[英]Checking if windows security patches are installed on multiple servers
我正在尝试检查在变量列表中设置的指定KB#是否与服务器上已安装的KB修补程序的完整列表匹配。 如果匹配,它将显示已安装补丁,否则将显示未安装。
下面的代码似乎不起作用,因为它显示为未安装,但实际上已经安装了。
[CmdletBinding()]
param ( [Parameter(Mandatory=$true)][string] $EnvRegion )
if ($EnvRegion -eq "kofax"){
[array]$Computers = "wprdkofx105",
"wprdkofx106",
"wprdkofx107",
$KBList = "KB4507448",
"KB4507457",
"KB4504418"
}
elseif ($EnvRegion -eq "citrix"){
[array]$Computers = "wprdctxw124",
"wprdctxw125",
$KBList = "KB4503276",
"KB4503290",
"KB4503259",
"KB4503308"
}
### Checks LastBootUpTime for each server
function uptime {
gwmi win32_operatingsystem | Select
@{LABEL='LastBootUpTime';EXPRESSION=
{$_.ConverttoDateTime($_.lastbootuptime)}} | ft -AutoSize
}
### Main script starts here. Loops through all servers to check if
### hotfixes have been installed and server last reboot time
foreach ($c in $Computers) {
Write-Host "Server $c" -ForegroundColor Cyan
### Checks KB Installed Patches for CSIRT to see if patches have been
### installed on each server
foreach ($elem in $KBList) {
$InstalledKBList = Get-Wmiobject -class Win32_QuickFixEngineering -
namespace "root\cimv2" | where-object{$_.HotFixID -eq $elem} |
select-object -Property HotFixID | Out-String
if ($InstalledKBList -match $elem) {
Write-Host "$elem is installed" -ForegroundColor Green
}
else {
Write-Host "$elem is not installed" -ForegroundColor Red
}
}
Write-Host "-------------------------------------------"
Invoke-Command -ComputerName $c -ScriptBlock ${Function:uptime}
}
Read-Host -Prompt "Press any key to exit..."
我想说的是,关于从Win32_QuickFixEngineering WMI类获取有关所有已安装修补程序的信息的能力显然存在误解。 甚至官方文档也指出:
Microsoft Windows Installer(MSI)或Windows更新站点( https://update.microsoft.com )提供的更新不会由Win32_QuickFixEngineering返回。
看来,Win32_QuickFixEngineering是使用WUA像老式的做法,应重新更换使用Windows Update代理API来枚举所有更新安装- https://docs.microsoft.com/en-us/windows/win32/wua_sdk/using -the-Windows的更新代理API
另外,请掠夺这篇好文章-https: //support.infrasightlabs.com/article/what-does-the-different-windows-update-patch-dates-stand-for/
通过按“ Microsoft.Update.Session”一词搜索,您将找到很多代码示例。
如Kostia所述, Win32_QuickFixEngineering
不会检索所有更新和补丁。 为了获得这些,我将使用一个辅助函数,该函数还将获取Windows Updates并将它们全部返回为字符串数组,如下所示:
function Get-UpdateId {
[CmdletBinding()]
Param (
[string]$ComputerName = $env:COMPUTERNAME
)
# First get the Windows HotFix history as array of 'KB' id's
Write-Verbose "Retrieving Windows HotFix history on '$ComputerName'.."
$result = Get-HotFix -ComputerName $ComputerName | Select-Object -ExpandProperty HotFixID
# or use:
# $hotfix = Get-WmiobjectGet-WmiObject -Namespace 'root\cimv2' -Class Win32_QuickFixEngineering -ComputerName $ComputerName | Select-Object -ExpandProperty HotFixID
# Next get the Windows Update history
Write-Verbose "Retrieving Windows Update history on '$ComputerName'.."
if ($ComputerName -eq $env:COMPUTERNAME) {
# Local computer
$updateSession = New-Object -ComObject Microsoft.Update.Session
}
else {
# Remote computer (the last parameter $true enables exception being thrown if an error occurs while loading the type)
$updateSession = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session", $ComputerName, $true))
}
$updateSearcher = $updateSession.CreateUpdateSearcher()
$historyCount = $updateSearcher.GetTotalHistoryCount()
if ($historyCount -gt 0) {
$result += ($updateSearcher.QueryHistory(0, $historyCount) | ForEach-Object { [regex]::match($_.Title,'(KB\d+)').Value })
}
# release the Microsoft.Update.Session COM object
try {
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($updateSession) | Out-Null
Remove-Variable updateSession
}
catch {}
# remove empty items from the combined $result array, uniquify and return the results
$result | Where-Object { $_ -match '\S' } | Sort-Object -Unique
}
另外,我将您的uptime
函数重写为:
function Get-LastBootTime {
[CmdletBinding()]
Param (
[string]$ComputerName = $env:COMPUTERNAME
)
try {
$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ComputerName
$os.ConvertToDateTime($os.LastBootupTime)
}
catch {
Write-Error $_.Exception.Message
}
}
具备两个功能后,您可以执行
$Computers | ForEach-Object {
$updates = Get-UpdateId -ComputerName $_ -Verbose
# Now check each KBid in your list to see if it is installed or not
foreach ($item in $KBList) {
[PSCustomObject] @{
'Computer' = $_
'LastBootupTime' = Get-LastBootTime -ComputerName $_
'UpdateID' = $item
'Installed' = if ($updates -contains $item) { 'Yes' } else { 'No' }
}
}
}
输出将是这样的:
Computer LastBootupTime UpdateID Installed -------- -------------- -------- --------- wprdkofx105 10-8-2019 6:40:54 KB4507448 Yes wprdkofx105 10-8-2019 6:40:54 KB4507457 No wprdkofx105 10-8-2019 6:40:54 KB4504418 No wprdkofx106 23-1-2019 6:40:54 KB4507448 No wprdkofx106 23-1-2019 6:40:54 KB4507457 Yes wprdkofx106 23-1-2019 6:40:54 KB4504418 Yes wprdkofx107 12-4-2019 6:40:54 KB4507448 No wprdkofx107 12-4-2019 6:40:54 KB4507457 No wprdkofx107 12-4-2019 6:40:54 KB4504418 Yes
注意:我在荷兰计算机上,因此此处显示的默认日期格式为“ dd-M-yyyy H:mm:ss”
为了能够在日期范围内进行选择,还需要更改代码,以便函数Get-UpdateId
返回一个对象数组,而不是上面的字符串数组。
function Get-UpdateId { [CmdletBinding()] Param ( [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true , Position = 0)] [string]$ComputerName = $env:COMPUTERNAME ) # First get the Windows HotFix history as array objects with 3 properties: 'Type', 'UpdateId' and 'InstalledOn' Write-Verbose "Retrieving Windows HotFix history on '$ComputerName'.." $result = Get-HotFix -ComputerName $ComputerName | Select-Object @{Name = 'Type'; Expression = {'HotFix'}}, @{Name = 'UpdateId'; Expression = { $_.HotFixID }}, InstalledOn # or use: # $result = Get-WmiobjectGet-WmiObject -Namespace 'root\\cimv2' -Class Win32_QuickFixEngineering -ComputerName $ComputerName | # Select-Object @{Name = 'Type'; Expression = {'HotFix'}}, # @{Name = 'UpdateId'; Expression = { $_.HotFixID }}, # InstalledOn # Next get the Windows Update history Write-Verbose "Retrieving Windows Update history on '$ComputerName'.." if ($ComputerName -eq $env:COMPUTERNAME) { # Local computer $updateSession = New-Object -ComObject Microsoft.Update.Session } else { # Remote computer (the last parameter $true enables exception being thrown if an error occurs while loading the type) $updateSession = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session", $ComputerName, $true)) } $updateSearcher = $updateSession.CreateUpdateSearcher() $historyCount = $updateSearcher.GetTotalHistoryCount() if ($historyCount -gt 0) { $result += ($updateSearcher.QueryHistory(0, $historyCount) | ForEach-Object { [PsCustomObject]@{ 'Type' = 'Windows Update' 'UpdateId' = [regex]::match($_.Title,'(KB\\d+)').Value 'InstalledOn' = ([DateTime]($_.Date)).ToLocalTime() } }) } # release the Microsoft.Update.Session COM object try { [System.Runtime.Interopservices.Marshal]::ReleaseComObject($updateSession) | Out-Null Remove-Variable updateSession } catch {} # remove empty items from the combined $result array and return the results $result | Where-Object { $_.UpdateId -match '\\S' } }
Get-LastBootTime
函数不需要更改,因此我让您从答案的第一部分中进行复制。
通过其UpdateId
属性检查已安装的更新
$Computers | ForEach-Object { $updates = Get-UpdateId -ComputerName $_ -Verbose $updateIds = $updates | Select-Object -ExpandProperty UpdateId # Now check each KBid in your list to see if it is installed or not foreach ($item in $KBList) { $update = $updates | Where-Object { $_.UpdateID -eq $item } [PSCustomObject] @{ 'Computer' = $_ 'LastBootupTime' = Get-LastBootTime -ComputerName $_ 'Type' = $update.Type 'UpdateID' = $item 'IsInstalled' = if ($updateIds -contains $item) { 'Yes' } else { 'No' } 'InstalledOn' = $update.InstalledOn } } }
输出(类似)
Computer : wprdkofx105 LastBootupTime : 10-8-2019 20:01:47 Type : Windows Update UpdateID : KB4507448 IsInstalled : Yes InstalledOn : 12-6-2019 6:10:11 Computer : wprdkofx105 LastBootupTime : 10-8-2019 20:01:47 Type : UpdateID : KB4507457 IsInstalled : No InstalledOn :
要获取在开始日期和结束日期内安装的修补程序和更新
$StartDate = (Get-Date).AddDays(-14) $EndDate = Get-Date foreach ($computer in $Computers) { Get-UpdateId -ComputerName $computer | Where-Object { $_.InstalledOn -ge $StartDate -and $_.InstalledOn -le $EndDate } | Select-Object @{Name = 'Computer'; Expression = {$computer}}, @{Name = 'LastBootupTime'; Expression = {Get-LastBootTime -ComputerName $computer}}, * }
输出(类似)
Computer : wprdkofx105 LastBootupTime : 20-8-2019 20:01:47 Type : HotFix UpdateId : KB4474419 InstalledOn : 14-8-2019 0:00:00 Computer : wprdkofx107 LastBootupTime : 20-8-2019 20:01:47 Type : Windows Update UpdateId : KB2310138 InstalledOn : 8-8-2019 15:39:00
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.