PowerShell 技能连载 - Saving PowerShell User Defaults

我们将要进入的“色彩之周”将带来许多改变 PowerShell ISE 编辑器和控制台颜色的技能。多数应用到 PowerShell 的改变并没有保存。PowerShell ISE 并不会保存一些颜色设置,但一个更健壮的方法是在 PowerShell 的一个描述脚本中改变您的自定义设置。

任何一个 PowerShell 宿主(控制台或 PowerShell ISE 或其它支持 PowerShell 的程序)都会执行的脚本如下:

1
2
PS C:\> $profile.CurrentUserAllHosts
C:\Users\Tobias\Documents\WindowsPowerShell\profile.ps1

Anything that applies to a specific host like the console only, or the PowerShell ISE only, goes here:

任何一个特定的 PowerShell 宿主,例如特指控制台或特指 PowerShell ISE 启动执行的脚本如下:

1
2
PS C:\>  $profile.CurrentUserCurrentHost
C:\Users\Tobias\Documents\WindowsPowerShell\XXXXXXXXXXXXXX_profile.ps1

请注意路径中的 “XXX”。需要在指定的宿主内运行上面的代码才有效。根据不同的宿主,这行代码会返回不同的路径。

另外请注意这些调用只是返回描述脚本的路径。它缺省情况下并不存在。您可能需要自己创建它,包括 “WindowsPowerShell” 文件夹。当描述脚本存在时,PowerShell 宿主启动的时候就会执行它。

请注意需要打开脚本执行功能。所以您可能需要一次性地允许脚本执行,比如:

1
PS> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force

PowerShell 技能连载 - 查看 ASCII 码

这是一种查看任何字符 ASCII 码的简单办法。字符可能截取自网站或者来自从 internet 上下载的脚本。

只需要打开 PowerShell 然后输入以下代码:

1
2
3
4
5
6
7
8
9
10
11
# paste character(s)  inside the quotes

$text = ''

foreach($char in [char[]]$text)

{

'Character {0,-3} Decimal {1,-5} Hex {1,-4:X}' -f $char, [int]$char

}

下一步,将字符(可以多个)粘贴在引号内,然后运行代码。为了测试,可以在 PowerShell 中运行以下代码:

1
PS C:\> charmap

这将打开字符映射表。您可以在其中选择一种字体,例如 DingBats,以及一个或多个字符。将它们复制到剪贴板,然后将它们粘贴到上面的 PowerShell 代码中。当您运行代码时,它将以十进制和十进制两种方式返回所选字符的 ASCII 码值。它们应该和字符映射表工具状态栏显示的值相同。

PowerShell 技能连载 - 检查(本地和远程的)硬盘容量

WMI 可以提供硬盘的容量和剩余空间。PowerShell 会用返回这样的友好信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PS C:\> # local
PS C:\> Get-HardDriveSize

DriveLetter Free(GB) Size(GB) Percent
----------- -------- -------- -------
C: 823,7 942,3 87,4


PS C:\> # remote
PS C:\> Get-HardDriveSize -ComputerName server2 -Credential server2\Tobias

DriveLetter Free(GB) Size(GB) Percent
----------- -------- -------- -------
C: 87,3 436,9 20
D: 5,3 25 21,3

以下是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function Get-HardDriveSize
{
param
(
$ComputerName,

$Credential
)

# get calculated properties:
$prop1 = @{
Name = 'DriveLetter'
Expression = { $_.DeviceID }
}

$prop2 = @{
Name = 'Free(GB)'
Expression = { [Math]::Round(($_.FreeSpace / 1GB),1) }
}

$prop3 = @{
Name = 'Size(GB)'
Expression = { [Math]::Round(($_.Size / 1GB),1) }
}

$prop4 = @{
Name = 'Percent'
Expression = { [Math]::Round(($_.Freespace * 100 / $_.Size),1) }
}

# get all hard drives
Get-CimInstance -ClassName Win32_LogicalDisk @PSBoundParameters -Filter "DriveType=3" |
Select-Object -Property $prop1, $prop2, $prop3, $prop4
}

PowerShell 技能连载 - 启用远程管理

支持 PowerShell 2 以上版本

许多早先基于 DCOM 的命令需要打开“远程管理防火墙例外”,才能访问远程系统。其中包含 Get-WmiObject 等 Cmdlet。

一个启用该功能的简单办法是在管理员权限下运行以下命令:

1
netsh firewall set service remoteadmin enable

虽然该命令已经准备淘汰,不过它仍然能用,而且是配置防火墙的最简单方法。

PowerShell 技能连载 - 查找自启动项

支持 PowerShell 3 以上版本

If you’d like to know which programs start automatically on your machine, WMI may help:

如果您想了解有多少个程序随着您的机器自动启动,WMI 也许能帮上忙:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
PS C:\> Get-CimInstance -ClassName Win32_StartupCommand | Select-Object -Property Name, Location, User, Command, Description

Name : OneDrive
Location : HKU\S-1-5-21-2012478179-265285931-690539891-1001\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
User : DESKTOP-7AAMJLF\tobwe
Command : "C:\Users\tobwe\AppData\Local\Microsoft\OneDrive\OneDrive.exe" /background
Description : OneDrive

Name : Bluetooth
Location : Common Startup
User : Public
Command : C:\PROGRA~1\WIDCOMM\BLUETO~1\BTTray.exe
Description : Bluetooth

Name : Snagit 12
Location : Common Startup
User : Public
Command : C:\PROGRA~2\TECHSM~1\SNAGIT~1\Snagit32.exe
Description : Snagit 12

Name : RTHDVCPL
Location : HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
User : Public
Command : "C:\Program Files\Realtek\Audio\HDA\RtkNGUI64.exe" -s
Description : RTHDVCPL

...

PowerShell 技能连载 - 替换 CSV 文件列名

支持 PowerShell 2 以上版本

当读取 CSV 数据的时候,可能会希望重命名 CSV 的列名,以下是一个简单的实现:只需要一行一行地读取文本,并跳过第一行(第一行包括 CSV 的列名)。然后,将表头替换成一个自定义的列名:

1
2
3
4
5
$header = ‘NewHeader1’, 'NewHeader2', 'NewHeader3'

Get-Content N:\somepathtofile\userlist.csv -Encoding Default |
Select-Object -Skip 1 |
ConvertFrom-CSV -UseCulture -Header $header

PowerShell 技能连载 - 通过管道输入数据

在前一个技能里我们演示了 Convert-Umlaut 如何转换一个字符串中的特殊字符。这在一个函数接受管道输入的时候更有用。让我们来看看增加这种特性所需要做的改变。

在不支持管道的情况下,该函数大概长这个样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#requires -Version 3

function Convert-Umlaut
{
param
(
[Parameter(Mandatory)]
$Text
)

$output = $Text.Replace('ö','oe').Replace('ä','ae').Replace('ü','ue').Replace('ß','ss').Replace('Ö','Oe').Replace('Ü','Ue').Replace('Ä','Ae')
$isCapitalLetter = $Text -ceq $Text.toUpper()
if ($isCapitalLetter)
{
$output = $output.toUpper()
}
$output
}

可以通过这种方式执行:

1
2
PS C:\> Convert-Umlaut -Text "Mößler, Christiansön"
Moessler, Christiansoen

然而,它不能像这样执行:

1
PS C:\> "Mößler, Christiansön" | Convert-Umlaut

要增加管道功能,需要做两件事:

  1. 参数需要标记为支持管道数据。
  2. 在迭代中对每个输入的元素进行处理的代码需要放置在 “process“ 代码块中。

以下是改变后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#requires -Version 3

function Convert-Umlaut
{
param
(
[Parameter(Mandatory, ValueFromPipeline)]
$Text
)

process
{
$output = $Text.Replace('ö','oe').Replace('ä','ae').Replace('ü','ue').Replace('ß','ss').Replace('Ö','Oe').Replace('Ü','Ue').Replace('Ä','Ae')
$isCapitalLetter = $Text -ceq $Text.toUpper()
if ($isCapitalLetter)
{
$output = $output.toUpper()
}
$output
}
}

现在,也可以通过管道传输数据了:

1
2
PS C:\> "Mößler, Christiansön" | Convert-Umlaut
Moessler, Christiansoen

PowerShell 技能连载 - 替换类似 “Umlauts” 的特殊字符

支持 PowerShell 2.0 以上版本

有些时候我们需要将一些字符替换,例如德语的 “Umlauts”,来适应用户名或邮箱地址。

以下是一个演示如何实现这个功能的小函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#requires -Version 3

function Convert-Umlaut
{
param
(
[Parameter(Mandatory)]
$Text
)

$output = $Text.Replace('ö','oe').Replace('ä','ae').Replace('ü','ue').Replace('ß','ss').Replace('Ö','Oe').Replace('Ü','Ue').Replace('Ä','Ae')
$isCapitalLetter = $Text -ceq $Text.toUpper()
if ($isCapitalLetter)
{
$output = $output.toUpper()
}
$output
}

要转换一个字符串,请这样使用:

1
2
PS C:\> Convert-Umlaut -Text "Mößler, Christiansön"
Moessler, Christiansoen

PowerShell 技能连载 - 友好地使用 Robocopy

支持 PowerShell 2.0 以上版本

Robocopy 是一个用于拷贝文件的工具,它在 PowerShell 里的功能也是一样。然而您可以用 PowerShell 将 robocopy 封装在一个对用户友好的 PowerShell 函数中。通过这种方式,您不再需要记忆 robocopy 别扭的命令行选项。取而代之的是 PowerShell 参数和智能提示功能。

一次 robocopy 的调用可能看起来如下:

1
PS C:\> Invoke-Robocopy -Source $env:windir -Destination c:\logs -Filter *.log -Recurse -Open

以下是封装函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#requires -Version 3

function Invoke-Robocopy
{
param
(
[String]
[Parameter(Mandatory)]
$Source,

[String]
[Parameter(Mandatory)]
$Destination,

[String]
$Filter = '*',

[Switch]
$Recurse,

[Switch]
$Open
)

if ($Recurse)
{
$DoRecurse = '/S'
}
else
{
$DoRecurse = ''
}

robocopy $Source $Destination $Filter $DoRecurse /R:0

if ($Open)
{
explorer.exe $Destination
}
}

PowerShell 技能连载 - 直接使用 .NET 类型

Cmdlet 内含了纯 .NET 代码,所以感谢 cmdlet,我们通常无需接触 .NET 代码。不过,如果您需要的话仍然可以使用。以下是一系列调用示例,演示了如何调用 .NET 方法:

#requires -Version 2
[System.Convert]::ToString(687687687, 2)

[Math]::Round(4.6)

[Guid]::NewGuid()

[System.IO.Path]::ChangeExtension('c:\test.txt', 'bak')

[System.Net.DNS]::GetHostByName('dell1')
[System.Net.DNS]::GetHostByAddress('192.168.1.124')

[Environment]::SetEnvironmentVariable()

# dangerous, save your work first
[Environment]::FailFast('Oops')

Add-Type -AssemblyName PresentationFramework
$dialog = New-Object Microsoft.Win32.OpenFileDialog
$dialog.ShowDialog()
$dialog.FileName