PowerShell 技能连载 - 获取 MAC 地址

适用于 PowerShell 所有版本

在 PowerShell 中获取网卡的 MAC 地址十分简单。以下是众多方法中的一个:

PS> getmac /FO CSV | ConvertFrom-Csv

Physical Address                        Transport Name
----------------                        --------------
5C-51-4F-62-F2-7D                       \Device\Tcpip_{FF034A81-CBFE-4B11-9D...
5C-51-4F-62-F2-81                       Media disconnected

有挑战性的地方在于实际的列名是本地化的,不同语言文化的值差异很大。由于原始信息是来自于 getmac.exe 生成的 CSV 数据,所以有一个简单的技巧:跳过首行(包含 CSV 头部),然后传入自定义的统一列名,以达到对列重命名的效果。

getmac.exe /FO CSV |
  Select-Object -Skip 1 |
  ConvertFrom-Csv -Header MAC, Transport

这将总是产生“_MAC_”和“_Transport_”的列。

当然,也有面向对象的解决方案,例如通过 WMI 查询或者使用 Windows 8.1 或 Server 2012/2012 R2。不过,我们认为所演示的方法是一个有趣的选择并且展示了如何将原始的 CSV 数据转换为真正有用的和语言文化无关的信息。

PowerShell 技能连载 - 高级文本分隔

适用于 PowerShell 所有版本

当您用 -split 操作符来分隔文本时,分隔符本身会被忽略掉:

PS> 'Hello, this is a text, and it has commas' -split ','
Hello
 this is a text
 and it has commas

如您所见,结果中的逗号被忽略掉了。

分隔符有可能多于一个字符。以下代码将以逗号 + 一个空格作为分隔符:

PS> 'Hello, this is a text, and it has commas' -split ', '
Hello
this is a text
and it has commas

由于 -split 接受的操作数是一个正则表达式,所以以下代码将以逗号 + 至少一个空格作为分隔符:

PS> 'Hello,    this is a    text, and it has commas' -split ',\s{1,}'
Hello
this is a    text
and it has commas

如果您需要的话,可以用 (?=…) 把分隔符包裹起来,以在结果中保留分隔符:

PS> 'Hello,    this is a    text, and it has commas' -split '(?=,\s{1,})'
Hello
,    this is a    text
, and it has commas

PowerShell 技能连载 - 分隔文本

适用于 PowerShell 所有版本

我们可以用 -split 操作符按指定的分隔符来分隔文本。这个操作符接受一个正则表达式作为操作数,所以如果您只是希望用纯文本的表达式来作为分隔的操作数,那么您需要将该纯文本转义一下。

以下是用反斜杠来分隔路径的例子:

$originalText = 'c:\windows\test\file.txt'
$splitText = [RegEx]::Escape('\')

$originalText -split $splitText

结果类似如下,并且它是一个数组:

PS> $originalText -split $splitText
c:
windows
test
file.txt

我们可以将它保存到一个变量中,然后存取单个的数组元素。

PS> $parts = $originalText -split $splitText

PS> $parts[0]
c:

PS> $parts[-1]
file.txt

PowerShell 技能连载 - 替换重复的空格

适用于 PowerShell 所有版本

要删除重复的空格,请使用这个正则表达式:

PS> '[  Man, it    works!   ]' -replace '\s{2,}', ' '
[ Man, it works! ]

您也可以用这种方式将固定宽度的文本表格转成 CSV 数据:

PS> (qprocess) -replace '\s{2,}', ','
>tobias,console,1,3876,taskhostex.exe
>tobias,console,1,3844,explorer.exe
>tobias,console,1,4292,tabtip.exe

当得到 CSV 数据之后,您可以用 ConvertFrom-Csv 将文本数据转换为对象:

PS> (qprocess) -replace '\s{2,}', ',' | ConvertFrom-Csv -Header Name, Session, ID, Pid, Process


Name    : >tobias
Session : console
ID      : 1
Pid     : 3876
Process : taskhostex.exe

Name    : >tobias
Session : console
ID      : 1
Pid     : 3844
Process : explorer.exe

Name    : >tobias
Session : console
ID      : 1
Pid     : 4292
Process : tabtip.exe
(...)

PowerShell 技能连载 - 创建短网址

适用于 PowerShell 所有版本

您也许听说过长网址的缩短服务。有许多这类免费的服务。以下是一个将任何网址转化为短网址的脚本:

$OriginalURL = 'http://www.powertheshell.com/isesteroids2'

$url = "http://tinyurl.com/api-create.php?url=$OriginalURL"
$webclient = New-Object -TypeName System.Net.WebClient
$webclient.DownloadString($url)

只需要将需要缩短的网址赋给 $OriginalURL,运行脚本。它将返回对应的短网址。

PowerShell 技能连载 - 查找 PowerShell 函数

适用于 PowerShell 3.0 或更高版本

要快速扫描您的 PowerShell 脚本仓库并在其中查找某个函数,请使用以下过滤器:

filter Find-Function
{
   $path = $_.FullName
   $lastwrite = $_.LastWriteTime
   $text = Get-Content -Path $path

   if ($text.Length -gt 0)
   {

      $token = $null
      $errors = $null
      $ast = [System.Management.Automation.Language.Parser]::ParseInput($text, [ref] $token, [ref] $errors)
      $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true) |
      Select-Object -Property Name, Path, LastWriteTime |
      ForEach-Object {
         $_.Path = $path
         $_.LastWriteTime = $lastwrite
         $_
      }
   }
}

以下是扫描您的用户配置文件中所有定义了函数的 PowerShell 脚本的方法:

PS> dir $home -Filter *.ps1 -Recurse -Exclude *.ps1xml | Find-Function

  Name                       Path                       LastWriteTime
  ----                       ----                       -------------
  Inject-LogonCredentials    C:\Users\Tobias\Desktop... 06.01.2014 02:43:00
  Test-Command               C:\Users\Tobias\Desktop... 06.03.2014 10:17:02
  Test                       C:\Users\Tobias\Desktop... 30.01.2014 09:32:20
  Get-WebPictureOriginal     C:\Users\Tobias\Desktop... 11.12.2013 11:37:53
  Get-ConnectionString       C:\Users\Tobias\Documen... 23.05.2014 10:49:09
  Convert-SID2User           C:\Users\Tobias\Documen... 23.05.2014 15:33:06
  Lock-Screen                C:\Users\Tobias\Documen... 19.03.2014 12:51:54
  Show-OpenFileDialog        C:\Users\Tobias\Documen... 16.05.2014 13:42:16
  Show-UniversalData         C:\Users\Tobias\Documen... 16.05.2014 13:23:20
  Start-TimebombMemory       C:\Users\Tobias\Documen... 23.05.2014 09:12:28
  Stop-TimebombMemory        C:\Users\Tobias\Documen... 23.05.2014 09:12:28
  (...)

只需要将结果通过管道输出到 Out-GridView 就能查看完整的信息。

PowerShell 技能连载 - 导出服务状态信息

适用于 PowerShell 所有版本

如果您想将一个 PowerShell 命令的结果保存到磁盘上,以便传到另一台机器上,以下是简单的实现方法:

$Path = "$env:temp\mylist.xml"

Get-Service |
  Add-Member -MemberType NoteProperty -Name ComputerName -Value $env:COMPUTERNAME -PassThru |
  Export-Clixml -Depth 1 -Path $Path

explorer.exe "/select,$Path"

这段代码用 Get-Service 获取所有的服务。结果添加了一个“ComputerName”字段,用于保存生成的数据所在的计算机名。

然后,得到的结果被序列化成 XML 并保存到磁盘上。接着在目标文件夹打开资源管理器,并且选中创建的 XML 文件。这样您就可以方便地将它拷到 U 盘中随身带走。

要将结果反序列化成真实的对象,使用以下代码:

$Path = "$env:temp\mylist.xml"

Import-Clixml -Path $Path

PowerShell 技能连载 - 比较服务配置

适用于 PowerShell 3.0 或更高版本

假设您在两台服务器上启用了 PowerShell 远程服务,那么下面这个简单的脚本演示了如何从每台服务器上获取所有服务的状态并且计算两台服务器之间的差异。

$Server1 = 'myServer1'
$Server2 = 'someOtherServer'

$services1 = Invoke-Command { Get-Service } -ComputerName $Server1 |
  Sort-Object -Property Name, Status

$services2 = Invoke-Command { Get-Service } -ComputerName $Server2 |
  Sort-Object -Property Name, Status

Compare-Object -ReferenceObject $services1 -DifferenceObject $services2 -Property Name, Status -PassThru |
  Sort-Object -Property Name

得到的结果是服务配置差异的清单。

PowerShell 技能连载 - 下载 PowerShell 语言规范

适用于 PowerShell 所有版本

在 PowerShell 中,从 Internet 中下载文件十分方便。以下这段代码能够自动将 PowerShell 语言规范——包含 PowerShell 精华和内核知识的很棒的 Word 文档——下载到您的机器上。

$link = 'http://download.microsoft.com/download/3/2/6/326DF7A1-EE5B-491B-9130-F9AA9C23C29A/PowerShell%202%200%20Language%20Specification.docx'

$outfile = "$env:temp\languageref.docx"

Invoke-WebRequest -Uri $link -OutFile $outfile

Invoke-Item -Path $outfile

PowerShell 技能连载 - 等待按键

适用于 PowerShell 所有版本,仅适用于 PowerShell 控制台

若希望脚本执行结束时,保持 PowerShell 控制台程序为打开状态,您也许希望增加一句“按任意键继续”语句。以下是实现方式:

Write-Host 'Press Any Key!' -NoNewline
$null = [Console]::ReadKey('?')

这段代码仅适用于真实的 PowerShell 控制台。它在 ISE 编辑器或其它未使用真实互操作键盘缓冲区的控制台程序中并不适用。