您的位置:首页 > 运维架构 > Shell

实战:使用PowerShell建立自己的软件清单工具

2009-07-30 18:07 525 查看
[align=center]使用PowerShell 建立自己的软件清单工具[/align]
Don Jones
《原文章发布在2008年11期的TechNet杂志上
地址:http://technet.microsoft.com/en-us/magazine/2008.11.windowspowershell.aspx

<刚刚发现,TechNet杂志上已经有该文章的翻译,地址是:http://technet.microsoft.com/zh-cn/magazine/2008.11.windowspowershell.aspx,我对比了下,我的译文和原译文差别不大,大家可自行选择。〉

在这期的Windows Powershell专栏里,我要向大家演示一种非常实用的Powershell用法。

我的目标是:
对公司内电脑,建立一个工具来检查操作系统的版本号(这是确定操作系统版本的最好方法)和补丁包(Service Pack)版本号。
但是这次我不会直接给出最后的解决方案,而是逐步的演示我是如何开发出这个脚本的。
尽管最后的工具是很好用,但是我认为开发出这脚本的步骤更重要。一旦你知道怎么开发并且把它用到自己的工作中,你的Powershell就可以真正的解决系统管理问题了。(古人云,授之以鱼,不如授之以渔)

找到信息

这是第一步,通常也是最难的,到底从哪里可以找出操作系统和补丁包版本号信息呢。你可能想到了注册表,注册表确实可以解决这方面的问题。但是这一般都是我最后的法宝,因为注册表处理起来总是很麻烦。
“收集”和“信息”让我马上想到了一个方法可能可行, Windows Management Instrumentation (WMI),另一个让我想到WMI的关键词是“远程”。因为在Windows Powershell第一版中,WMI是唯一的能够执行任何远程信息查找或管理的唯一选择。
遗憾的是,大多数的Windows系统都有成千上万的WMI类别,所以能难找到你所要找的信息。我一般会从Web搜索开始,,输入类似“wmi service pack version number”之类的关键词。你可能需要输入较长的关键词才可以得到比较准确的结果。
你甚至还需要尝试一些变化的搜索关键词,不过不要去尝试“wmi SP version”,一般不会返回有用的结果。请考虑替代的关键词,比如,你可能称为“Patches 补丁”,而有些人称为“hotfixes”,但是还有些时候会是“Quick fix engineering 快速修复工程”或“qfe patch (qfe补丁)”。你可能需要把这些都试完才可以拿到正确的结果。
如果你要找那些和电脑硬件或者Windows OS核心相关的信息,你可以在搜索关键词内加入“Win32”,因为大部分相关的WMI类别都是以“Win32_”开头。
搜索关键词,加入 “Win32”达到最佳结果,,我看到有些结果显示“Win32_OperatingSystem”,这是WMI类别的名称。
这里还有个技巧,就是避免点击搜索结果(这种方法可能会让人混乱)。我首先会找到对于这个类的正式说明网页,因此我以类别的名称开始了新的搜索。这样做的结果,头几条搜索结果通常会连接到msdn.microsoft.com,而这就应该会把你引向类别说明文档
【图1】显示了该文档的部分内容,我卷动到该页面中特别重要的表格,就是列出来了该类别使用的操作系统。我记不清多少次我费尽心血,结果到头来才发现我要做的动作在那些Windows版本根本不适用。所以我现在养成了先检查这个表格的习惯。



【图1】查找WMI类别的相关信息
仔细查看该页面,我看到了两个感兴趣的属性:BuildNumber和ServicePackMajorVersion, 事实上,ServicePackMinorVersion可能也很有用。但是我从来都没有见过微软有2.1版本的补丁包。但是,无论如何,这个属性也值得我们一起查看。



设计原型


在确认这些确实是我要的属性之前,我不想贸然行事。Windows Powershell让这个工作做起来很简单。我首先在我的电脑上面检查这些信息。

Get-WmiObject Win32_OperatingSystem | Select BuildNumber,ServicePackMajorVersion,ServicePack-MinorVersion




好了,次要版本是零,和我预期的一样,那我就不管他了。其他信息也像我想象的那样---我的Windows Server 2008电脑版本号是 6001,补丁包版本号是1.
(我的计算机是Windows XP SP2, 版本号是2600, 主版本号是2)
现在我要在远程电脑上(也就是我需要管理的那台电脑)上执行相似的测试

Get-WmiObject Win32_OperatingSystem –computer Server2 | Select BuildNumber,ServicePackMajorVersion




如果测试不通,我需要停下来找出原因才可以继续,可能是和网络连接、防火墙、权限有关,这些都超出了Windows Powershell的范围。一旦我把这些事情都搞定,我就可以继续问题的下一步:从文件里拿到一串计算机名称。

读取计算机名称

假设我的电脑名称清单保存在一个文本文件里面,每一行都有一个计算机名,最简单的办法使用Get-Content Cmdlet (如果你的计算机名称不在这文本文件或不是逐行列出也不用太担心,后续的文章里我会来介绍)
每个名字都以独立的字符串的方式返回。Get-Wmiobjectcmdlet有一个功能很方便,就是他的-computername参数,这个参数可以接受计算机名称集合,所以我们可以这样做

$names = Get-Content c:\computernames.txt
Get-WmiObject Win32_OperatingSystem –comp $names | Select
BuildNumber,ServicePackMajorVersion





现在的问题在于,我列出的是一份数字清单,没有显示那个数字是那台电脑的。幸运的是,Win32_OperatingSystem类别里正好有一个属性CSName,里面就包含计算机名。因此我可以把该属性加入代码这样我就得到了一个不错的结果

$names = Get-Content c:\computernames.txt
Get-WmiObject Win32_OperatingSystem –comp $names | Select
CSName,BuildNumber,ServicePackMajorVersion








模块化


上面对于缺少经验的技术人员来说可能有点难,因此最后一步就是把这些步骤组成一个函数。一个办法就是写一个函数可以接受文件名,然后让该函数做所有的工作。

Function Get-SPInventory ([string]$filename) {
$names = Get-Content $filename
Get-WmiObject Win32_OperatingSystem –comp  $names | Select   CSName,BuildNumber,ServicePackMajorVersion
}





我们把整个代码编写成一个名为Get-SPInventory的函数, 我使用了名为$filename的输入参数来定义。所以我们可以使用下面方法来使用该函数

Get-SPInventory c:\computernames.txt





还可以采用标准的Powershell命令,将这些结果也可以输出到一个CSV文件,或转换成HTML,或采用其他不同的格式。

Get-SPInventory c:\computernames.txt |
Export-CSV SPInventory.csv





但这个函数还不完美,如果某天我还想查没有包含在Win32_OperatingSystem类别的某些信息(比如每台电脑的BIOS序列号),那该怎么办?许多配置管理数据库(Configuration Management Databases, CMDBs)都使用BIOS作为计算机的唯一标识码,这些信息就很有用了。
我还想希望函数的输出更灵活,可以让我很轻松的排序或者过滤结果。比如,我可以选择在在最终的输出中只包含老版本补丁包的Windows Server 2003电脑。

管道函数

那我现在就要修改函数,让他在Windows Powershell管道中作用更大。更具体的点,我希望函数直接的接受来自管道的电脑名称,这样我就可以决定每次我使用函数是从哪里拿到计算机名称。计算机名称可以在一个文件里,或者在AD(Active Directory)里,我希望函数在两种情况下都可以运行。
下面就是针对管道改写的函数。

Function Get-SPInventory {
PROCESS {
$wmi = Get-WmiObject Win32_OperatingSystem       –comp $_ | Select     CSName,BuildNumber,ServicePackMajorVersion
Write-Output $wmi
}
}





这种特殊的函数类型是使用Process脚本模块,他会针对我输送到函数的每个管道对象执行一次(可以参考我在2008年7月份有关Process脚本模块的文章,网址是technet.microsoft.com/magazine/cc644947.aspx)这个特殊的$_变量会自动填入管道的输入;只要我们输入的是计算机名,他就能顺利执行。新函数使用起来如下

Get-Content c:\computernames.txt | Get-SPInventory






正如你所见,从不同的地方拿到计算机名称能够提供更多的弹性,我只是将命令的Get-content部分换成了其他的可以取得计算机名称的命令。请注意,通过查询不同的WMI类别(或其他的数据源),我也把它设置成更加强健的输出。
讨论还没结束,下个月我会把这个函数扩展到加入BIOS序列号在输出结果里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: