PowerShell 技能连载 - 从注册表中读取已安装的软件

以下是查看已安装的软件的快速方法。Get-Software 函数读取所有用户的 32 位和 64 位软件的安装地址。

#requires -Version 1

function Get-Software
{
    param
    (
        [string]
        $DisplayName='*',

        [string]
        $UninstallString='*'
    )

    $keys = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
            'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'

    Get-ItemProperty -Path $keys |
      Where-Object { $_.DisplayName } |
      Select-Object -Property DisplayName, DisplayVersion, UninstallString |
      Where-Object { $_.DisplayName -like $DisplayName } |
      Where-Object { $_.UninstallString -like $UninstallString }
}

它甚至包含了过滤参数,所以您可以当您指定 -DisplayName-UninstallString(或两者)时,您可以轻松地过滤结果,仅显示您期望的软件产品。两个参数都支持通配符。

以下是一个调用的示例,显示所有的 Office 组件到一个网格视图窗口中:

Get-Software -DisplayName *Office* | Out-GridView

PowerShell 技能连载 - 显示消息对话框

PowerShell 是基于控制台的,但有些时候加入一些简单的对话框也很不错。以下是一个称为 Show-MessageBox 的函数,可以显示所有标准消息框,并支持智能显示参数:

#requires -Version 2

Add-Type -AssemblyName PresentationFramework
function Show-MessageBox
{
    param
    (
        [Parameter(Mandatory=$true)]
        $Prompt,

        $Title = 'Windows PowerShell',

        [Windows.MessageBoxButton]
        $Buttons = 'YesNo',

        [Windows.MessageBoxImage]
        $Icon = 'Information'
    )

    [System.Windows.MessageBox]::Show($Prompt, $Title, $Buttons, $Icon)
}


$result = Show-MessageBox -Prompt 'Rebooting.' -Buttons OKCancel -Icon Exclamation

if ($result -eq 'OK')
{
  Restart-Computer -Force -WhatIf
}

PowerShell 技能连载 - 尽可能使用服务端过滤

当您跨网络获取信息时,请注意只能在最后一步使用客户端技术,例如 Where-Object。服务端过滤技术更有效率。

例如,当您试图根据电子邮箱查找用户时,客户端的 Where-Object 语句将会将所有 AD 用户推到您的计算机上,并且通过本地的 Where-Object 来确认您需要的用户:

#requires -Version 1 -Modules ActiveDirectory

# inefficient client-side filter
Get-ADUser -Filter * | Where-Object { $_.mail -ne $null }

如您猜想的那样,当一个 cmdlet 有一个名为 -Filter 的参数时,它可以在传送数据到您的机器之前,在服务端过滤需要的元素。然而,Get-ADUser 命令的 -Filter 参数有的时候工作起来很困难,需要将类似 PowerShell 的语法转换为 Active Directory 所需的 LDAP 查询。

所以更常见的是,在第一处使用 LDAP 查询字符串更自然。这两条语句将会快速地找出所有包含(和不包含)邮箱地址的用户账户:

#requires -Version 1 -Modules ActiveDirectory

# any user with a mail address
Get-ADUser -LDAPFilter '(mail=*)'

# any user with NO mail address
Get-ADUser -LDAPFilter '(!mail=*)'

PowerShell 技能连载 - 将数字列表转换为有用的列表

PowerShell 将 “..“ 操作符的功能定义为生成一个数字列表。通过 -join 操作符,您可以将这些数字转换为几乎您想要的所有东西,例如逗号分隔的值。

当您希望将数字转换为字符时,您也可以将 ASCII 码转换为字母。

用管道将它们输出到 ForEach-Object,您就可以将它进一步处理成驱动器号。

或者使用 -f 操作符来创建服务器列表。以下是示例代码:

#requires -Version 1


1..10 -join ','

[Char[]][Byte[]](65..90) -join ','

([Char[]][Byte[]](65..90) | ForEach-Object { $_ + ':\' })  -join ','

1..10 | ForEach-Object { 'Server{0:0000}' -f $_ }

PowerShell 技能连载 - 和 Powershell 对话

今日的技能是当您键入一个未知的命令时,使用可编程的 CommandNotFoundHandler 让 PowerShell 和您对话:

$ExecutionContext.InvokeCommand.CommandNotFoundAction =
{
  param(
    [string]
    $commandName,

    [System.Management.Automation.CommandLookupEventArgs]
    $eventArgs
  )

  $Sapi = New-Object -ComObject Sapi.SpVoice
  $null = $Sapi.Speak("I don't know $commandName, stupid.")
}

当您运行这段代码(并且打开您的声音)后,当用户输入一个未知的命令时,PowerShell 将会开口说话,并且抱怨它不知道您的命令。您可能会听到该声音两次:如果该命令不以 “get-“ 开头,PowerShell 首先会试图查找一个以 “get-“ 开头,并以您键入的名字结尾的命令。

PowerShell 技能连载 - 查看操作系统版本

一个最简单的查看操作系统版本号的方法是这一行代码:

PS> [Environment]::OSVersion

Platform ServicePack        Version             VersionString
-------- -----------        -------             -------------
 Win32NT Service Pack 1     6.1.7601.65536      Microsoft Windows N...

Environment”类型提供了您计算机很多方面的信息。例如,操作系统核心的个数:

PS> [Environment]::ProcessorCount
4

要查看该类型能做什么,请在 PowerShell ISE 中,键入:

[Environment]::

当您按下第二个冒号时,智能提示将打开一个菜单,里面包含了该类型的所有静态属性和方法。

PowerShell 技能连载 - 为什么捕获不到某些错误

当您在 PowerShell 中收到一条红色的错误信息时,您总是可以用一个 try..catch 代码块将代码包裹起来,然后自行处理该错误:

try
{
  1/0
}
catch
{
  Write-Warning "Something crazy happened: $_"
}

然而,一些错误,特别是来自 cmdlet 的,并不能被处理。当那些情况发生时,说明缺失的错误是被 cmdlet 内部的错误处理器处理了,并且您可以通过 -ErrorAction 通用参数来控制 cmdlet 的错误处理器。

当您设置 ErrorAction 的值为 Stop 时,您实际上告知 cmdlet 抛出一个异常,该以上可以被您的异常处理器捕获。

要让所有 cmdlet 发出异常,而不是内部处理,您可以用 $ErrorActionPreference = 'Stop' 语句,该语句将设置所有 cmdlet 的缺省错误动作为“停止”。

请注意它的副作用:当您告知一个 cmdlet 的错误处理器要在某些错误发生时抛出异常,则该 cmdlet 将会在发生第一个错误的地方抛出异常,并且不会继续执行。

PowerShell 技能连载 - 在命令提示符中显示路径

缺省的 PowerShell 提示符显示当前的位置。当您在很深的嵌套文件夹中时,这将占用您的输入空间,而且会导致需要滚动才能看清。

有很多方法可以解决这个问题。以下是针对这个题的两个 prompt 的替代函数。

第一个是保持在当前提示符中显示当前路径,但实际的输入是在下面一行,所以您的输入总是可见。

function prompt
{
  Write-Host("PS: $pwd>")
}

另一种方式是在窗体的标题栏显示当前的路径:

function prompt
{
  $host.UI.RawUI.WindowTitle = Get-Location
  'PS> '
}

如果您想用这些方法,请将它们放在自启动脚本中(缺省情况下可能不存在)。它的路径可以通过 $profile 变量找到。

PowerShell 技能连载 - 帮助 PowerShell 做得更好!

与其批评不正常的功能,或是缺少的功能,不如一起参与建设!PowerShell 团队做了很大努力来改进和扩展 PowerShell。现在只需要您的反馈意见。

这是一站式服务地址:https://connect.microsoft.com/PowerShell

当您打开那个网页时,您可以一键提交 bug、发送反馈,或是为新的功能投票。您需要用一个免费的微软账号登录。

PowerShell 技能连载 - 试试 CTRL+SPACE!

在 PowerShell ISE 中,有两个键盘快捷键可能对您有用。按下 TAB 键的功能就像在控制台中一样,并且每次您按下 TAB,您会得到一个 Tab 展开的结果。

CTRL + SPACE 是另一个重要的键盘快捷键。它将打开智能感知菜单。由于大多数情况下 ISE 自动打开这些菜单,所以大多数用户从来没有注意过 CTRL + SPACE,但它重打开一个错过的智能感知菜单功能十分有用。

从 PowerShell 5.0 开始,CTRL + SPACE 变得更为重要,特别是当您在书写 DSC(所需状态配置)配置脚本时。PowerShell ISE 提供了针对 DSC 的扩展智能感知帮助,但在许多情况下并不会自动弹出智能感知菜单。仅当按下 CTRL + SPACE 时才能获得智能感知帮助。