Windows PowerShell:通过命令而不是脚本完成操作
08/17/2016
本文内容
不要被“编写脚本”这个术语吓倒,因为您可以通过 Windows PowerShell 使用简单的命令完成许多操作。
Don Jones
在 Windows PowerShell 争取得到管理员接受方面,认知一向是我们所面临的最大问题。长期以来,管理员对该 shell 的认知是,它与 VBScript 一样都是“脚本编写语言”。虽然由于脚本编写语言可被用于完成大量操作而深受许多管理员喜爱,但由于其复杂性和陡峭的学习曲线,也使很多管理员望而却步。
这令人感到非常可惜。该 shell 支持基于脚本的强大功能,但同样也支持更简单的、以命令为导向的功能。该 shell 的真正吸引人之处在于您可以使用上述任何一种方法来完成大量同样的工作。
仅仅是一个脚本
下列函数将从命令行处以字符串或输入对象的“ComputerName”属性的方式接受计算机名称;它还会使用 Windows Management Instrumentation (WMI) 从每台计算机检索 BIOS 和 OS 信息。
function Get-Inventory
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[string] $computername
)
Process {
$os = gwmi win32_operatingsystem -computername $computername
$bios = gwmi win32_bios -computername $computername
$obj = new-object psobject
$obj | add-member noteproperty ComputerName $computername
$obj | add-member noteproperty OSBuild ($os.buildnumber)
$obj | add-member noteproperty SPVersion ($os.servicepackmajorversion)
$obj | add-member noteproperty BIOSSerial ($bios.serialnumber)
Write-output $obj
}
}
请注意,圆括号会强制 shell 执行表达式(例如从 $os 变量的对象中获取 BuildNumber 属性),并将该表达式的结果作为 Add-Member 的第三个参数值返回。
我也可以通过管道输入静态计算机名称来运行此函数:
'localhost','server2' | Get-Inventory
或者,通过发送每行包含一个计算机名称的文本文件的内容来运行此函数。
Get-Content names.txt | Get-Inventory
或者甚至是通过从 Active Directory 检索计算机对象、将“名称”属性更改为 ComputerName,并通过管道传输下列内容:
Import-Module ActiveDirectory
Get-ADComputer –filter * | Select-Object @{Label='ComputerName';Expression={$_.Name}} | Get-Inventory
另外,我使用括号来封装可执行代码。$_ 占位符代表通过管道输入 Select-Object cmdlet 的对象。上述操作的结果均为格式简洁的表,包含四列。我可以轻松地将上述输出重定向至文件、打印机或网格,或者甚至是在显示结果之前对其进行筛选和排序。例如,
Get-Content names.txt | Get-Inventory | Where { $_.BuildNumber –eq 7600 } | Sort ComputerName
再次重申,括号封装一个可执行代码块,即我希望筛选的表达式,而 $_ 占位符代表通过管道传入的对象。
命令性能
类似那样的脚本并没有错误,但是需要处理大量工作。对于这种脚本编写人员或者说程序员式方法,许多管理员都认为任务过于繁重。通过一个稍微复杂的命令也可以完成同样的任务。打起精神来:
Get-WmiObject Win32_OperatingSystem -computername (get-content names.txt) |
Select-object @{Label="ComputerName";Expression={$_.__SERVER}},
@{Label="OSBuild";Expression={$_.BuildNumber}},
@{Label="SPVersion";Expression={$_.ServicePackMajorVersion}},
@{Label="BIOSSerial";Expression={(gwmi win32_bios -comp $_.__server).serialnumber}}
这里要完成许多操作。下面是操作详解:
首先,运行 Get-WmiObject,从特定的计算机名称中检索 Win32_OperatingSystem 对象。如果您定期阅读此专栏,您就可能知道 Get-WmiObject 所返回的对象始终包括一个 __SERVER 属性,该属性包含 WMI 对象的来源计算机名称。
WMI 对象通过管道传输到 Select-Object。我使用四个散列表来定义四个属性:ComputerName、OSBuild、SPVersion 和 BIOSSerial。每个散列表都会指定一个标签和一个表达式,其中标签将随后用作输出的列标题。该散列表通过使用 @ 数组运算符后跟包含在括号内的标签/表达式定义构成。这些括号封装定义散列表表达式部分的可执行代码。
对于前三列,该表达式只是指该对象的现有属性;我只不过更改了属性名称。
对于第四列,我的表达式实际上是在同一台服务器上执行第二次 WMI 查询。它会从 __SERVER 属性中提取计算机名称。查看整个 WMI 调用是如何封装在圆括号内的?这会强制先执行该表达式。该表达式所得到的任何对象都将代替圆括号内部分插入。右括号后面的句点使我能够访问得到的对象的属性,因此我可从第四列访问其 SerialNumber 属性。
在某种程度上,此语法比我所启动的脚本更难读。它比较紧凑,并使用了大量标点符号。您可以将其用作模板,并根据您的需要进行修改。如果您不明白为什么它无法工作,请在我的 ConcentratedTech.com 博客上提问,我会为您解答。
不要将它称为脚本
我的意思是我们不必将 Windows PowerShell 作为脚本语言使用。我演示的命令可能复杂,但也不会比我所见到的管理员为旧式 Cmd.exe shell 编写的冗长命令更复杂。虽然需要进行一些训练,但熟悉其语法之后,与编写完整的脚本或函数相比,该命令要简单的多。
因此,请不要看到“脚本语言”便不愿采用该 shell。您可以选择使用脚本编写较为简单的功能。
Don Jones是 Concentrated Technology 的创始人,他会在 ConcentratedTech.com 解答有关 Windows PowerShell 和其他技术的问题。他也是 Nexus.Realtimepublishers.com 的撰稿人,他的许多著作还在他的网站上以电子版的形式提供。
相关内容