PowerShell 技能连载 - 解析纯文本(第一部分)

有些时候,您可能希望从纯文本结果中提取一些有用的信息。一个简单的办法是使用 Select-String 命令。这个例子只提取包含“IPv4”的文本行:

1
2
3
PS C:\> ipconfig | Select-String 'IPv4'

IPv4 Address. . . . . . . . . . . : 192.168.2.112

如果您只对实际的 IP 地址感兴趣,您可以改进这个结果,用正则表达式来提取您感兴趣的部分:

1
2
3
4
PS C:\> $data = ipconfig | select-string 'IPv4'
PS C:\> [regex]::Matches($data,"\b(?:\d{1,3}\.){3}\d{1,3}\b") | Select-Object -ExpandProperty Value

192.168.2.112

[Regex]::Matches() 输入原始数据和正则表达式 pattern,后者描述了您感兴趣的部分。符合该 pattern 的内容可以在“Value”属性中找到。

PowerShell 技能连载 - 调整简单界面

在前一个技能中您学到了如何使用 Show-Command 为基于文本的命令创建简单的 UI:

1
2
3
4
5
6
7
8
#requires -Version 3.0

function Send-MailMessageUI
{
Show-Command -Name Send-MailMessage
}

Send-MailMessageUI

如果您想调整 UI 中显示的参数的个数,只需要编写您自己的函数即可。

在下面的例子中,Send-MailMessage 被包裹在一个自定义的函数中,并只暴露其中的某些属性,然后在内部初始化其它的属性(例如 SMTP 服务器和凭据)。

以下是一个非常简单的 email 发送函数,只显示发送 email 的文本框:

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
41
#requires -Version 3.0

function Send-MailMessageCustomized
{
param
(
[Parameter(Mandatory)]
[string]
$From,

[Parameter(Mandatory)]
[string]
$To,

[Parameter(Mandatory)]
[string]
$Subject,

[Parameter(Mandatory)]
[string]
$building,

[switch]
$BodyAsHTML
)
$username = 'mymailusername'
$password = 'mymailpassword' # Dangerous, never hardcode! Consider using Get-Credential instead.
$myServer = 'mail.mymailserver.mycompany.com'

$passwordSecure = $password | ConvertTo-SecureString -AsPlainText -Force
$myCred = New-Object -TypeName PSCredential($username, $passwordSecure)

Send-MailMessage -From $From -To $To -Subject $Subject -building $building -BodyAsHtml:$BodyAsHTML -SmtpServer $myServer -Encoding UTF8 -Credential $myCred
}

function Send-MailMessageUI
{
Show-Command -Name Send-MailMessageCustomized
}

Send-MailMessageUI

PowerShell 技能连载 - 创建简单的 UI

函数和 cmdlet 参数是 PowerShell 提供的基础功能,这些文本界面可以轻松地转换成图形界面。

如果您想发送一条消息,您可以使用 Send-MailMessage 并通过文本参数的方式提交细节信息。或者,您可以创建一个图形界面,并将它命名为 Send-MailMessageUI

1
2
3
4
5
6
7
8
#requires -Version 3.0

function Send-MailMessageUI
{
Show-Command -Name Send-MailMessage
}

Send-MailMessageUI

现在,您可以运行 Send-MailMessageUI,所有参数都将变成文本框和复选框。甚至不会脚本开发的人现在也能填写这个表单,然后点击“运行”来执行命令。

PowerShell 技能连载 - 扩展 Robocopy

PowerShell 可以向原有的命令(例如 robocopy)添加值。请看以下的函数——它用 robocopy 来拷贝文件,并且当拷贝完成时,增加了“扁平拷贝”选项来打开目标文件夹:

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
41
42
43
#requires -Version 3.0

function Copy-FileWithRobocopy
{
param
(
[Parameter(Mandatory)]
[string]$Source,

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

[string]$Filter = '*',

[int]$RetryCount = 0,

[string]$ExcludeDirectory = '',

[switch]$Open,

[switch]$FlatCopy,

[switch]$NoRecurse
)

$Recurse = '/S'
if ($NoRecurse) { $Recurse = '' }

robocopy.exe $Source $Destination $Filter /R:$RetryCount $Recurse /XD $ExcludeDirectory

if ($FlatCopy)
{
Get-ChildItem -Path $Destination -Recurse -Filter $Filter |
Move-Item -Destination $Destination -Force
Get-ChildItem -Path $Destination -Directory |
Remove-Item -Recurse -Force
}

if ($Open)
{
explorer $Destination
}
}

这将会把 Windows 文件夹下所有子文件夹中的 log 文件拷贝到名为 c:\\logs 的新文件夹,并且执行扁平化拷贝:

1
PS>  Copy-FileWithRobocopy -Source $env:windir -Destination c:\logs -Filter *.log -FlatCopy -Open

当您在生产系统使用这段代码之前,请观察 -FlatCopy 是如何工作的:它只是在目标文件夹中查找匹配指定的过滤器,然后将它们移到根目录,最后删除所有文件夹。

所以重复的文件将会被覆盖,而且如果目标文件夹的子文件夹中有其他数据,也会被删除。这是一个很简单的操作,适用于许多情况,但也有很多改进空间。

PowerShell 技能连载 - 复制着色过的代码

当您在 PowerShell ISE 中选中一段代码并复制到剪贴板时,它是以 RTF 格式复制的并且保留了所有颜色代码和字体信息。您可以将它粘贴到支持 RTF 的应用程序,例如 Word 中,就可以看到格式化并着色好的 PowerShell 代码。

要调节字体大小,您不能用 PowerShell ISE 右下角的滑块。这个滑块只是改变 PowerShell ISE 中的字体大小,并不会影响复制的代码字体大小。

正确的方法是,在 PowerShell ISE 中,选择工具/选项,然后在选项对话框中调节字体大小。

PowerShell 技能连载 - 在 PowerShell 中创建 WinForms GUI 界面

虽然建议使用更现代的 WPF 技术来创建 PowerShell 用户界面,但您在某些时候仍然会希望使用更早的 WinForms 技术。特别是要在没有安装 .NET framework 3.51 及以上版本的机器上运行时。WinForms 用户界面需要很多代码,而且不是那么直观。

所以这里提供一个免费的 PowerShell 在线图形设计器,可以快速地创建代码: http://www.poshgui.com/

PowerShell 技能连载 - 使用“Exit”和 Linux 通信

当一个 PowerShell 脚本结束时,您可以使用“Exit”命令来返回一个数值。这在 Windows 世界中是一个很好的实践。它能够设置“Error Level”值,并能够被调用者(例如一个批处理文件或是定时任务管理器)读取到。

1
exit 99

既然 PowerShell 在 Linux 上也可以运行,它也可以用来报告调用 Linux 进程的状态值。

PowerShell 技能连载 - 捕获 Linux 输出

如果您在 Linux 上运行 PowerShell,您可以混合使用 Linux 命令和 PowerShell 命令。要将 Linux 命令的输出赋值给 PowerShell 变量,请像这样写:

1
$content = (ls)

请注意“ls”在 Windows 系统上是一个别名,但在 Linux 系统上指向的是原始的 ls 命令。

PowerShell 技能连载 - 检测文件或文件夹

Test-Path 可以检测一个文件或文件夹是否存在。如果您添加了 -PathType 来指定叶子节点(文件),或 -Container(文件夹),结果会更具体:

$path = 'c:\windows'

Test-Path -Path $path
Test-Path -Path $path -PathType Leaf
Test-Path -Path $path -PathType Container

PowerShell 技能连载 - 系统内存、单位和四舍五入

有些时候,您可能会需要不同的度量单位。例如整个系统的内存是以字节计算的。以下是一些将字节转换为 GB 并且仍然保证可读性的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$memory = Get-WmiObject -Class Win32_ComputerSystem |
Select-Object -ExpandProperty TotalPhysicalMemory

$memoryGB = $memory/1GB

# raw result in bytes
$memoryGB

# rounding
[Int]$memoryGB
[Math]::Round($memoryGB)
[Math]::Round($memoryGB, 1)

# string formatting
'{0:n1} GB' -f $memoryGB

结果看起来类似如下:

15.8744087219238
16
16
15.9
15.9 GB