PowerShell 技能连载 - 用 Group-Object 来创建哈希表

适用于所有 PowerShell 版本

Group-Object 能把对象输送到管道中,然后在一个管道中把属性相同的对象排在一起。

这个功能十分有用,特别是当您用 Group-Object 来返回哈希表时。它将生成一个按服务状态分组的哈希表:

$hash = Get-Service |
  Group-Object -Property Status -AsHashTable -AsString

您现在可以通过这种方式获取所有正在运行(或已停止的)服务:

$hash.Running
$hash.Stopped

可以用任何想要的属性来分组。这个例子将用三个组来分组文件:一组为小文件,一个组为中等文件,另一个组位大文件。

$code =
{
  if ($_.Length -gt 1MB)
  {'huge'}
  elseif ($_.Length -gt 10KB)
  {'average'}
  else
  {'tiny'}
}

$hash = Get-ChildItem -Path c:\windows |
  Group-Object -Property $code -AsHashTable -AsString


#$hash.Tiny
$hash.Huge

PowerShell 技能连载 - 用 PowerShell 来励志

适用于所有 PowerShell 版本

编写 PowerShell 代码是十分带劲的,但是某些时候会令人感到沮丧。这是一个用 PowerShell 来励志的函数。只需要打开音箱,PowerShell 会在您执行每一条命令之后鼓励你。

function prompt
{
  $text = 'You are great!', 'Hero!', 'What a checker you are.', 'Champ, well done!', 'Man, you are good!', 'Guru stuff I would say.', 'You are magic!'
  'PS> '
  $host.UI.RawUI.WindowTitle = Get-Location
  (New-Object -ComObject Sapi.SpVoice).Speak(($text | Get-Random))
}

PowerShell 技能连载 - 记录脚本做了什么事

适用于所有 PowerShell 版本

您应该知道在 PowerShell 控制台(不是 ISE 编辑器)中,您可以打开记录功能:

PS> Start-Transcript

这将会把所有键入的命令以及所有的命令执行结果都记录到一个文件中。不幸的是,当您运行一个脚本的时候,作用就受限了,因为您无法看到实际的脚本命令。

以下是一个激进的技巧,能够记录包括所有脚本中执行的命令。在您尝试这个技巧之前,请注意这将增加您的日志文件大小并且会导致脚本执行变慢,因为在循环体中,每一次循环都会被记录下来。

只要执行这行代码就可以打开脚本命令记录了:

PS> Set-PSDebug -Trace 1

PowerShell 技能连载 - 有趣的声音提示

适用于所有 PowerShell 版本

如果您的计算机装有声卡,那么这段代码可以让您的同事们吓一跳:

function prompt
{
  1..3 | ForEach-Object {
    $frequency = Get-Random -Minimum 400 -Maximum 10000
    $duration = Get-Random -Minimum 100 -Maximum 400
    [Console]::Beep($frequency, $duration)
  }
  'PS> '
  $host.ui.RawUI.WindowTitle = Get-Location
}

这段代码将会缩短您的 PowerShell 提示符,并且在标题栏上显示当前的路径。这还算是有益的功能。搞破坏的部分是每次执行一条命令,都会发出随机频率的刺耳的三连音:)。

PowerShell 技能连载 - 产生多个返回值

适用于所有 PowerShell 版本

如果一个 PowerShell 函数需要产生多个返回信息,最佳的实践方式是返回多个对象,然后将信息分别存储在对象的各个属性中。

以下是一个有趣的例外情况,它在某些场景中较为适用。尽管返回多个信息就可以了,并且要确保将结果赋值给多个变量:

function Get-MultipleData
{
  Get-Date
  'Hello'
  1+4
}

$date, $text, $result = Get-MultipleData

"The date is $date"
"The text was $text"
"The result is $result"

这个测试函数产生 3 段信息,然后将结果存储在 3 个不同的变量中。

PowerShell 技能连载 - 编辑“hosts”文件

适用于所有 PowerShell 版本

如果您常常需要修改“hosts”文件,那么手工用提升权限的记事本实例来打开文件是相当乏味的事情。这是因为该文件只能被 Administrators 用户修改,所以普通的记事本实例无法修改它。

以下是一段您可以直接使用,或者调整一下用来打开任何需要提升权限的程序的脚本。

function Show-HostsFile
{
  $Path = "$env:windir\system32\drivers\etc\hosts"
  Start-Process -FilePath notepad -ArgumentList $Path -Verb runas
}

PowerShell 技能连载 - 请注意 UNC 路径!

适用于所有 PowerShell 版本

许多 cmdlet 可以处理 UNC 路径,但是使用 UNC 路径会导致很多古怪的情况。请看以下:

PS> Test-Path -Path \\127.0.0.1\c$
True

这段代码返回了 true,该 UNC 路径存在。现在将当前驱动器变为一个非文件系统驱动器,然后再次实验:

PS> cd hkcu:\

PS> Test-Path -Path \\127.0.0.1\c$
False

同样的路径现在返回了 false。这是因为 UNC 路径并不包含驱动器号,而 PowerShell 需要驱动器号来指定正确的提供器。如果一个路径不包含驱动器号,那么 PowerShell 假设使用当前驱动器的提供器。所以如果您将当前的目录改为注册表,PowerShell 尝试在那儿查找 UNC 路径,那么就会失败。

更糟糕的是,出于某些未知的原因,但您用 net use 来映射驱动器时,PowerShell 在使用 cmdlet 来访问驱动器时可能会也可能不会产生混淆。

解决方案十分简单:当您用 cmdlet 访问 UNC 时,始终在 UNC 路径前面加上正确的提供器名称。这将消除该问题:

PS> Test-Path -Path FileSystem::\\127.0.0.1\c$
True

PS> cd hkcu:\

PS> Test-Path -Path \\127.0.0.1\c$
False

PS> Test-Path -Path FileSystem::\\127.0.0.1\c$
True

如果您遇到了 net use 产生的问题,也可以使用同样的办法,在路径前面加上 “FileSystem::。该问题可以立刻得到解决。

PowerShell 技能连载 - 查找 AD 用户

适用于所有 PowerShell 版本

假如您已登录到了一个活动目录域中,那么只需要执行一些简单的命令就可以搜索活动目录。在前一个技巧中我们演示了最基本的脚本。以下是一个扩展,它能够定义一个搜索的根(搜索的起点),就像一个扁平的搜索一样(相对于在容器中递归而言)。

它也演示了如何将活动目录的搜索结果转换成实际的用户对象:

$SAMAccountName = 'tobias'
$SearchRoot = 'LDAP://OU=customer,DC=company,DC=com'
$SearchScope = 'OneLevel'

$ldap = "(&(objectClass=user)(samAccountName=*$SAMAccountName*))"
$searcher = [adsisearcher]$ldap
$searcher.SearchRoot = $SearchRoot
$searcher.PageSize = 999
$searcher.SearchScope = $SearchScope

$searcher.FindAll() |
  ForEach-Object { $_.GetDirectoryEntry()  } |
  Select-Object -Property *

PowerShell 技能连载 - 查找并提取注册表键的路径

适用于所有 PowerShell 版本

在前一个技巧中,我们演示了如何将一个 PowerShell 内部的路径格式转换为一个真实的路径。以下是一个用力。这段代码递归地搜索 HKEY_CURRENT_USER 键,并且找出所有包含单词“_powershell_”的注册表键(您可以将搜索关键字换成任何别的):

Get-ChildItem -Path HKCU:\ -Include *PowerShell* -Recurse -ErrorAction SilentlyContinue |
  Select-Object -Property *Path* |
  Out-GridView

这段代码输出所有名称中包含“Path_”的属性。如您所见,注册表键中有两个属性包含该关键字:_PSPath 和 _PSParentPath_。两者都是 PowerShell 内置的路径格式。

要提取所有满足搜索条件的注册表键的路径,请使用以下代码:

Get-ChildItem -Path HKCU:\ -Include *PowerShell* -Recurse -ErrorAction SilentlyContinue |
  ForEach-Object {
    Convert-Path -Path $_.PSPath
  }

PowerShell 技能连载 - 修正 PowerShell 中的路径

适用于所有 PowerShell 版本

有些时候,您会为某些奇怪的路径格式感到困惑,比如这个:

Microsoft.PowerShell.Core\FileSystem::C:\windows\explorer.exe

这是一个完整的 PowerShell 路径名,路径中包含了了模块名和提供器名。要得到一个纯的路径名,请使用以下代码:

Convert-Path -Path Microsoft.PowerShell.Core\FileSystem::C:\windows\explorer.exe