我目前正在使用以下PS脚本来检查系统上是否安装了MS补丁。该脚本设置为检查$env:COMPUTERNAME.mbsa
和Patch_NA.txt
文件,并将结果发送到$env:COMPUTERNAME.csv
文件。
我现在需要修改此脚本,以便从同一位置(POS
)的其他C:\Users\Cambridge\SecurityScans
设备提取信息,并将结果发送到$env:COMPUTERNAME.csv file
。
POS
设备列出如下:
172.26.210.1.mbsa
172.26.210.2.mbsa
172.26.210.3.mbsa
等等。
我们所有位置(最后一个八位字节)的IP
范围是1 - 60
。关于如何设置它的任何想法?
脚本:
$logname = "C:\temp\PatchVerify\$env:COMPUTERNAME.csv"
[xml]$x=type "C:\Users\Cambridge\SecurityScans\$env:COMPUTERNAME.mbsa"
#This list is created based on a text file that is provided.
$montlyPatches = type "C:\Temp\PatchVerify\Patches_NA.txt"|
foreach{if ($_ -mat"-KB(? <KB>\d+)"){$matches.KB}}
$patchesNotInstalled=$x.SecScan.check | where {$_.id -eq 500} |foreach{`
$_.detail.updatedata|where {$_.isinstalled -eq "false"}}|Select -expandProperty KBID
$patchesInstalled =$x.SecScan.check | where {$_.id -eq 500} |foreach{`
$_.detail.updatedata|where {$_.isinstalled -eq "true"}}|Select -expandProperty KBID
"Store,Patch,Present"> $logname
$store = "$env:COMPUTERNAME"
foreach ($patch in $montlyPatches)
{
$result = "Unknown"
if ( $patchesInstalled -contains $patch)
{
$result = "YES"
}
if ( $patchesNotInstalled -contains $patch)
{
$result = "NO"
}
"$store,KB$($patch),$result" >>$logname
}
答案 0 :(得分:0)
您可以在网上找到有关创建功能的大量信息,但一个简单的例子是:
Function Check-Patches{
Param($FileName)
$logname = "C:\temp\PatchVerify\$FileName.csv"
[xml]$x=type "C:\Users\Cambridge\SecurityScans\$FileName.mbsa"
The rest of your existing code goes here...
}
Check-Patches "$env:ComputerName"
For($i=1;$i -le 60;$i++){
Check-Patches "172.26.210.$i"
}
如果你需要我打破任何事情,让我知道,我会进一步解释,但从你已经拥有它看起来你对PowerShell理论有一个很好的把握,只需要知道什么资源可用。
编辑:我更新了我的示例以更好地适应您的脚本,让它接受文件名,然后将该文件名应用于函数中的$ logname和$ x变量。
分解......
首先我们声明我们正在使用Function
关键字创建一个Function。接下来是您稍后将用它来调用它的函数的名称,以及一个用于启动构成实际函数的scriptblock的开始大括号。
接下来是Param行,在这种情况下非常简单,只将一个变量声明为输入。这也可以作为Function Check-Patches ($FileName){
来完成,但是当你开始进入更高级的功能时只会让人感到困惑,所以我的建议是坚持将参数放在函数的scriptblock中。在大多数情况下,这是您在函数内部首先要做的事情,不包括您为函数编写的任何帮助。
然后我们更新了$logname
和[xml]$x
的行,这些行使用函数获取的$ FileName作为输入。
之后会出现解析补丁日志,输出到CSV以及结束scriptblock的结束大括号和函数的所有代码。
然后我们将它称为ComputerName,并运行For循环。 For循环运行1到60之间的所有内容,对于每个循环,它使用该数字作为文件名的最后一个八位字节,以输入函数并检查这些文件。
对其余代码的一些评论。 $monthlypatches =
可以更改为= type | ?{$_ -match "-KB(? <KB>\d+)"}|%{$matches.KB}
,以便在ForEach循环之前过滤结果,这可能会缩短一段时间。
在$ patchesInstalled和$ patchesNotInstalled行中,您不需要该行末尾的反引号。在脚本块开始之后,对于ForEach循环,您自然会有一个换行符。有了它,如果脚本中断,以后会很难看到,如果后面有任何内容(包括空格),脚本可能会破坏并抛出难以追踪的错误。
最后,你循环$ x两次,然后$ monthlyPatches一次,并对日志文件进行大量的单独写入。我建议创建一个数组,用自定义对象填充它有3个属性(Store,Patch和Present),然后在函数末尾输出。这会稍微改变一下,但是你的函数会输出一个对象,你可以将其输出到Export-CSV,或者稍后你可能希望它做其他的事情,但至少你可以拥有它。为此,我通过一个开关运行$ x来查看是否已经安装了东西,然后通过将该阵列中尚未包含的所有月份补丁设置为“未知”来清除阵列。那会是这样的:
Function Check-Patches{
Param($FileName)
$logname = "C:\temp\PatchVerify\$FileName.csv"
[xml]$x=type "C:\Users\Cambridge\SecurityScans\$FileName.mbsa"
$PatchStatus = @()
#This list is created based on a text file that is provided.
$monthlyPatches = GC "C:\Temp\PatchVerify\Patches_NA.txt"|?{$_ -match "-KB(? <KB>\d+)"} | %{$matches.KB}
#Create objects for all the patches in the updatelog that were in the monthly list.
Switch($x.SecScan.Check|?{$_.KBID -in $monthlyPatches -and $_.id -eq 500}){
{$_.detail.updatedata.isinstalled -eq "true"}{$PatchStatus+=[PSCustomObject][Ordered]@{Store=$FileName;Patch=$_.KBID;Present="YES"};Continue}
{$_.detail.updatedata.isinstalled -eq "false"}{$PatchStatus+=[PSCustomObject][Ordered]@{Store=$FileName;Patch=$_.KBID;Present="NO"};Continue}
}
#Populate all of the monthly patches that weren't found on the machine as installed or failed
$monthlyPatches | ?{$_ -notin $PatchStatus.Patch} | %{$PatchStatus += [PSCustomObject][Ordered]@{Store=$FileName;Patch=$_;Present="Unknown"}}
#Output results
$PatchStatus
}
#Check patches on current computer
Check-Patches "$env:ComputerName"|Export-Csv "C:\temp\PatchVerify\$env:ComputerName.csv" -NoTypeInformation
#Check patches on POS Devices
For($i=1;$i -le 60;$i++){
Check-Patches "172.26.210.$i"|Export-Csv "C:\temp\PatchVerify\172.26.210.$i.csv" -NoTypeInformation
}