繁体   English   中英

检查Windows安全修补程序是否已安装在多台服务器上

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM