PowerShell 技能连载 - WMI 搜索工具

适用于 PowerShell 所有版本

WMI 是一个很棒很强大的技术:只需要指定一个 WMI 类名,您就可以获取该类的所有实体。

PS> Get-WmiObject -Class Win32_BIOS


SMBIOSBIOSVersion : 76CN27WW
Manufacturer      : LENOVO
Name              : 76CN27WW
SerialNumber      : 1006250300406
Version           : LENOVO - 1

那么如何知道有哪些 WMI 类呢?以下是一个搜索工具函数:

function Find-WMIClass
{
   param
   (
      [Parameter(Mandatory=$true)]
      $SearchTerm = 'Resolution'
   )

   Get-WmiObject -Class * -List |
   Where-Object { $_.Properties.Count -ge 3 } |
   Where-Object { $_.Name -notlike 'Win32_Perf*'  } |
   Where-Object {
      $ListOfNames = $_.Properties | Select-Object -ExpandProperty Name
      ($ListOfNames -like "*$SearchTerm*") -ne $null
   } |
   Sort-Object -Property Name
}

只需要指定一个搜索条件。该函数将会查找所有属性名中包含搜索条件的 WMI 类(可以用通配符来扩大搜索范围)。

这段代码能搜索属性以“resolution”结尾的 WMI 类:

PS> Find-WMIClass -SearchTerm *resolution


   NameSpace: ROOT\cimv2

Name                                Methods              Properties
----                                -------              ----------
CIM_CacheMemory                     {SetPowerState, R... {Access, AdditionalErr...
CIM_CurrentSensor                   {SetPowerState, R... {Accuracy, Availabilit...
CIM_FlatPanel                       {SetPowerState, R... {Availability, Caption...
CIM_Memory                          {SetPowerState, R... {Access, AdditionalErr...
CIM_MonitorResolution               {}                   {Caption, Description,...
CIM_NonVolatileStorage              {SetPowerState, R... {Access, AdditionalErr...
CIM_NumericSensor                   {SetPowerState, R... {Accuracy, Availabilit...
CIM_PCVideoController               {SetPowerState, R... {AcceleratorCapabiliti...
CIM_PointingDevice                  {SetPowerState, R... {Availability, Caption...
CIM_Printer                         {SetPowerState, R... {Availability, Availab...
CIM_Tachometer                      {SetPowerState, R... {Accuracy, Availabilit...
CIM_TemperatureSensor               {SetPowerState, R... {Accuracy, Availabilit...
CIM_VideoController                 {SetPowerState, R... {AcceleratorCapabiliti...
CIM_VideoControllerResolution       {}                   {Caption, Description,...
CIM_VolatileStorage                 {SetPowerState, R... {Access, AdditionalErr...
CIM_VoltageSensor                   {SetPowerState, R... {Accuracy, Availabilit...
Win32_CacheMemory                   {SetPowerState, R... {Access, AdditionalErr...
Win32_CurrentProbe                  {SetPowerState, R... {Accuracy, Availabilit...
Win32_DisplayControllerConfigura... {}                   {BitsPerPixel, Caption...
Win32_MemoryArray                   {SetPowerState, R... {Access, AdditionalErr...
Win32_MemoryDevice                  {SetPowerState, R... {Access, AdditionalErr...
Win32_NetworkAdapterConfiguration   {EnableDHCP, Rene... {ArpAlwaysSourceRoute,...
Win32_PointingDevice                {SetPowerState, R... {Availability, Caption...
Win32_Printer                       {SetPowerState, R... {Attributes, Availabil...
Win32_PrinterConfiguration          {}                   {BitsPerPel, Caption, ...
Win32_SMBIOSMemory                  {SetPowerState, R... {Access, AdditionalErr...
Win32_TemperatureProbe              {SetPowerState, R... {Accuracy, Availabilit...
Win32_VideoConfiguration            {}                   {ActualColorResolution...
Win32_VideoController               {SetPowerState, R... {AcceleratorCapabiliti...
Win32_VoltageProbe                  {SetPowerState, R... {Accuracy, Availabilit...

下一步,选择一个类名并观察它的实际数据:

PS> Get-WmiObject -Class CIM_CacheMemory | Select-Object -Property *

PowerShell 技能连载 - 列出所有信息

适用于 PowerShell 所有版本

大多数时候,PowerShell 不会显示从 cmdlet 中返回的所有信息。相反地,PowerShell 限制了只显示信息中最常见的部分。

PS> Get-WmiObject -Class CIM_CacheMemory


BlockSize      : 1024
CacheSpeed     :
CacheType      : 4
DeviceID       : Cache Memory 0
InstalledSize  : 32
Level          : 3
MaxCacheSize   : 32
NumberOfBlocks : 32
Status         : OK

(...)

要看到完整的信息,请像这样加一句 Select-Object 语句:

PS> Get-WmiObject -Class CIM_CacheMemory | Select-Object -Property *


PSComputerName              : TOBI2
DeviceID                    : Cache Memory 0
ErrorCorrectType            : 5
Availability                : 3
Status                      : OK
StatusInfo                  : 3
BlockSize                   : 1024
CacheSpeed                  :
CacheType                   : 4
InstalledSize               : 32
Level                       : 3
MaxCacheSize                : 32
NumberOfBlocks              : 32
WritePolicy                 : 3
__GENUS                     : 2
__CLASS                     : Win32_CacheMemory
__SUPERCLASS                : CIM_CacheMemory
__DYNASTY                   : CIM_ManagedSystemElement
__RELPATH                   : Win32_CacheMemory.DeviceID="Cache Memory 0"
__PROPERTY_COUNT            : 53
__DERIVATION                : {CIM_CacheMemory, CIM_Memory, CIM_StorageExtent,
                              CIM_LogicalDevice...}
__SERVER                    : TOBI2
__NAMESPACE                 : root\cimv2
__PATH                      : \\TOBI2\root\cimv2:Win32_CacheMemory.DeviceID="Cache
                               Memory 0"
Access                      :
AdditionalErrorData         :
Associativity               : 7
Caption                     : Cache Memory
ConfigManagerErrorCode      :
ConfigManagerUserConfig     :
CorrectableError            :
CreationClassName           : Win32_CacheMemory
CurrentSRAM                 : {5}
Description                 : Cache Memory
EndingAddress               :
ErrorAccess                 :
ErrorAddress                :
ErrorCleared                :
ErrorData                   :
ErrorDataOrder              :
ErrorDescription            :
ErrorInfo                   :
ErrorMethodology            :
ErrorResolution             :
ErrorTime                   :
ErrorTransferSize           :
FlushTimer                  :
InstallDate                 :
LastErrorCode               :
LineSize                    :
Location                    : 0
Name                        : Cache Memory
OtherErrorDescription       :
PNPDeviceID                 :
PowerManagementCapabilities :
PowerManagementSupported    :
Purpose                     : L1 Cache
ReadPolicy                  :
ReplacementPolicy           :
StartingAddress             :
SupportedSRAM               : {5}
SystemCreationClassName     : Win32_ComputerSystem
SystemLevelAddress          :
SystemName                  : TOBI2
Scope                       : System.Management.ManagementScope
Path                        : \\TOBI2\root\cimv2:Win32_CacheMemory.DeviceID="Cache
                               Memory 0"
Options                     : System.Management.ObjectGetOptions
ClassPath                   : \\TOBI2\root\cimv2:Win32_CacheMemory
Properties                  : {Access, AdditionalErrorData, Associativity,
                              Availability...}
SystemProperties            : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...}
Qualifiers                  : {dynamic, Locale, provider, UUID}
Site                        :
Container                   :

(...)

PowerShell 技能连载 - 获取美国邮政编码

适用于 PowerShell 所有版本

是否曾需要查找某个(美国)城市的邮政编码,或者反过来通过邮政编码查找城市的名称?

只需要简单地用 PowerShell 连接到一个免费的 Web Service 就可以获得这些信息:

$webservice = New-WebServiceProxy -Uri 'http://www.webservicex.net/uszip.asmx?WSDL'
$webservice.GetInfoByCity('New York').Table
$webservice.GetInfoByZIP('10286').Table

PowerShell 技能连载 - 获取包含数据类型信息在内的注册表键值

适用于 PowerShell 所有版本

读取所有注册表信息时,如果您不需要数据类型信息,那么十分简单:只需要用 Get-ItemProperty 即可:

Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

如果您确实需要数据类新信息,那么需要做点额外的事情:

$key = Get-Item -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

$key.GetValueNames() |
  ForEach-Object {
    $ValueName = $_

    $rv = 1 | Select-Object -Property Name, Type, Value
    $rv.Name = $ValueName
    $rv.Type = $key.GetValueKind($ValueName)
    $rv.Value = $key.GetValue($ValueName)
    $rv
  }

PowerShell 技能连载 - 查找文件以及错误信息

适用于 PowerShell 所有版本

当您使用 Get-ChildItem 在目录中递归查找文件时,您有时候会遇到一些权限不足的文件夹。为了禁止错误信息,您可能会使用 -ErrorAction SilentlyContinue 的方法。

这是个不错的实践,但是您也许还希望得到一份权限不足的文件夹的清单。

以下是一段在 Windows 文件夹中搜索所有 PowerShell 脚本的脚本。它将这些文件保存在 $PSScripts 变量中。同时,它将所有的错误信息记录在 $ErrorList 变量中,并列出所有不可存取的文件夹。

$PSScripts = Get-ChildItem -Path c:\windows -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue -ErrorVariable ErrorList

$ErrorList | ForEach-Object {
  Write-Warning ('Access denied: ' + $_.CategoryInfo.TargetName)
}

PowerShell 技能连载 - 查找可改变的属性

适用于 PowerShell 所有版本

当您从 PowerShell cmdlet 中获取结果时,返回的结果都是包含属性的对象。有些属性是可改变的,另一些是只读的。

以下是一个获取可改变的属性的简单技巧。这段代码是以当前 PowerShell 宿主的进程对象为例,但您可以用任意的 cmdlet 结果。

$myProcess = Get-Process -Id $Pid

$myProcess |
  Get-Member -MemberType Properties |
  Out-String -Stream |
  Where-Object { $_ -like '*set;*' }

结果类似如下:

EnableRaisingEvents        Property       bool EnableRaisingEvents {get;set;}
MaxWorkingSet              Property       System.IntPtr MaxWorkingSet  {get;set;}
MinWorkingSet              Property       System.IntPtr MinWorkingSet  {get;set;}
PriorityBoostEnabled       Property       bool PriorityBoostEnabled  {get;set;}

PowerShell 技能连载 - 获取变量详细清单

适用于 PowerShell ISE 3 或更高版本

出于写文档等目的,您可能需要获得一份 PowerShell 脚本用到的所有变量的清单。

以下是一个名为 Get-Variable 的函数:

function Get-Variable
{

  $token = $null
  $errors = $null

  $ast = [System.Management.Automation.Language.Parser]::ParseInput($psise.CurrentFile.Editor.Text, [ref] $token, [ref] $errors)

  # not complete, add variables you want to exclude from the list:
  $systemVariables = '_', 'null', 'psitem', 'true', 'false', 'args', 'host'

  $null = $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.CommandAst] }, $true)
  $token |
    Where-Object { $_.Kind -eq 'Variable'} |
    Select-Object -ExpandProperty Name |
    Where-Object { $systemVariables -notcontains $_ } |
    Sort-Object -Unique
}

只需要用系统自带的 ISE 编辑器打开这个脚本,然后在交互式控制台中运行 Get-Variable

您将会得到一个排序过的列表,内容是当前打开的脚本用到的所有变量。

如果您将“$psise.CurrentFile.Editor.Text”替换成一个包含脚本代码的变量,那么您可以在 ISE 编辑器之外运行这个函数。只需要用 Get-Content 将任意脚本的内容读取进一个变量,然后就可以在上述代码中使用这个变量。

PowerShell 技能连载 - 重命名变量

适用于 PowerShell ISE 3 或更高版本

以下是一个简单的变量重命名函数,您可以在 PowerShell 3.0 及以上版本的 ISE 编辑器中使用它

它将识别某个变量的所有实例,然后将它重命名为一个新的名字。

function Rename-Variable
{
  param
  (
    [Parameter(Mandatory=$true)]
    $OldName,

    [Parameter(Mandatory=$true)]
    $NewName
  )

  $InputText = $psise.CurrentFile.Editor.Text
  $token = $null
  $errors = $null

  $ast = [System.Management.Automation.Language.Parser]::ParseInput($InputText, [ref] $token, [ref] $errors)

  $token |
  Where-Object { $_.Kind -eq 'Variable'} |
  Where-Object { $_.Name -eq $OldName } |
  Sort-Object { $_.Extent.StartOffset } -Descending |
  ForEach-Object {
    $start = $_.Extent.StartOffset + 1
    $end = $_.Extent.EndOffset
    $InputText = $InputText.Remove($start, $end-$start).Insert($start, $NewName)
  }

  $psise.CurrentFile.Editor.Text = $InputText
}

运行这个函数之后,您将得到一个名为 Rename-Variable 的新命令。

下一步,在 ISE 编辑器中打开一个脚本,然后在控制台面板中,键入以下内容(当然,需要将旧的变量名“_oldVariableName_”改为您当前所打开的 ISE 脚本中实际存在的变量名)。

PS> Rename-Variable -OldName oldVariableName -NewName theNEWname

立刻,旧变量的所有出现的地方都被替换成新的变量名。

注意:这是一个非常简易的变量重命名函数。一定要记得备份您的脚本。它还不能算是一个能用在生产环境的重构方案。

当您重命名变量时,您脚本的许多别处地方也可能需要更新。例如,当一个变量是函数参数时,所有调用该函数的地方都得修改它们的参数名。

PowerShell 技能连载 - 格式化行尾符

适用于 PowerShell 所有版本

当您从 Internet 中下载了文件之后,您也许会遇到文件无法在编辑器中正常打开的情况。最常见的是,由于非正常行尾符导致的。

以下是这个问题的一个例子。在前一个技能里我们演示了如何下载一份 MAC 地址的厂家清单。当下载完成后用记事本打开它时,换行都消失了:

$url = 'http://standards.ieee.org/develop/regauth/oui/oui.txt'
$outfile = "$home\vendorlist.txt"

Invoke-WebRequest -Uri $url -OutFile $outfile

Invoke-Item -Path $outfile

要修复这个文件,只需要使用这段代码:

$OldFile = "$home\vendorlist.txt"
$NewFile = "$home\vendorlistGood.txt"

Get-Content $OldFile | Set-Content -Path $NewFile

notepad $NewFile

Get-Content 能够检测非标准的行尾符,所以结果是各行的字符串数组。当您将这些行写入一个新文件时,一切都会变正常,因为 Set-Content 会使用缺省的行尾符。

PowerShell 技能连载 - 通过 MAC 地址识别网卡厂家

适用于 PowerShell 所有版本

每个 MAC 地址唯一标识了一个网络设备。MAC 地址是由网络设备厂家分配的。所以您可以通过任何一个 MAC 地址反查出厂家信息。

您所需的只是一份大约 2MB 大小的 IEEE 厂家清单。以下是下载该清单的脚本:

$url = 'http://standards.ieee.org/develop/regauth/oui/oui.txt'
$outfile = "$home\vendorlist.txt"

Invoke-WebRequest -Uri $url -OutFile $outfile

下一步,您可以使用该清单来识别厂家信息。首先获取 MAC 地址,例如:

PS> getmac

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

取 MAC 地址的前 3 个 8 进制字符,例如 _5c-51-4f_,然后用它在下载的文件中查询:

PS> Get-Content -Path $outfile | Select-String 5c-51-4f -Context 0,6

>   5C-51-4F   (hex)        Intel Corporate
    5C514F     (base 16)        Intel Corporate
                    Lot 8, Jalan Hi-Tech 2/3
                  Kulim Hi-Tech Park
                  Kulim Kedah 09000
                  MALAYSIA

您不仅可以获取厂家名称(这个例子中是 Intel),而且还可以获取厂家的地址和所在区域。