我正试着写一个powershell脚本来查询几个服务器并检查它们是否有任何待处理的更新。
基本上,我使用“MSCatalog”模块来查询更新如下:
$Search = (Get-Date -Format "yyyy-MM")
$Updates = (Get-MSCatalogUpdate -Search $Search -AllPages ) | Where-Object { ($_.Title -like "*Server*") -OR ($_.Products -like "*Server*") }
我最感兴趣的是新的每月更新,所以我只是使用获取日期查询这个月的更新。当然,我过滤了服务器的标题或产品列表。
现在我的服务器都是全面的。我们有一些遗留服务器2008,2012,2012 R2,2016和2019。
我试图找出一个好的方法来检查,看看是否有任何更新丢失。要获得当前的服务器更新,我运行下面的命令:
$ServerKBs = (((Get-HotFix -ComputerName $($FilteredServerResult.ServerName)) | Select-Object HotFixID,InstalledOn) | Where-Object {($_.InstalledOn -like "$ServerUpdateSearch" )}).HotFixID
我坚持的部分是我试图只比较与服务器相关的更新。例如,我不关心2016或2012 r2服务器的2019更新。我只希望特定于该服务器的更新显示。现在我明白了,我可以通过列名过滤它,并将其与服务器上的操作系统进行比较,以确保它匹配。例如,要获取操作系统的数字版本,我可以使用以下命令:
$ServerOSString = (($FilteredServerResult.OS) -replace '\D+(\d+)\D+','$1')
例如,输出将是2016而不是“Windows Server 2016 Standard”,然后我可以这样做:
if(($Update.Products -match $ServerOSString) -eq $True )
{
#Do Stuff
}
这是我卡住的部分,因为假设这一切都对齐,现在我将服务器上安装的KB与我从Microsoft Windows Catalog中查询的内容进行比较......可能有一些更新匹配,其他更新可能不匹配。我想只关注那些具有与服务器不匹配的挂起更新的更新。我如何才能进行这样的操作?
我使用poshrs-job在多个服务器上运行它,所以它更快,所以我想尽可能高效地完成这一任务,并希望输出一个简单的服务器列表,这些服务器仍然需要使用KB &\或标题进行修补。
下面是我正在尝试做的一个例子:
CLS
#Main Variables
#The Search will always be the year-month when you run the script
$Search = (Get-Date -Format "yyyy-MM")
#Formatting is different one servers than on Windows update catalog
$ServerUpdateSearch = (Get-Date -Format "*MM*yyyy*")
#------------- MSCatalog (For Querying Windows Catalog)
if((Get-Module -ListAvailable -Name "MSCatalog") -or (Get-Module -Name "MSCatalog"))
{
Import-Module MSCatalog
}
else
{
Install-Module -Name MSCatalog -Scope CurrentUser -Force -Confirm:$False
Import-Module MSCatalog
}
#------------- PoshRSJob (multitasking)
if((Get-Module -ListAvailable -Name "PoshRSJob") -or (Get-Module -Name "PoshRSJob"))
{
Import-Module PoshRSJob
}
else
{
Install-Module -Name PoshRSJob -Scope CurrentUser -Force -Confirm:$False
Import-Module PoshRSJob
}
#------------- ImportExcel Module
if((Get-Module -ListAvailable -Name "ImportExcel") -or (Get-Module -Name "ImportExcel"))
{
Import-Module ImportExcel
}
else
{
#Install NuGet (Prerequisite) first
Install-PackageProvider -Name NuGet -Scope CurrentUser -Force -Confirm:$False
Install-Module -Name ImportExcel -Scope CurrentUser -Force -Confirm:$False
Import-Module ImportExcel
}
#Clear screen again
CLS
#----------------------------------------------------------------------------------------------------------------
#Start Timestamp
$Start = Get-Date
#Global Variables
$Path = (Split-Path $script:MyInvocation.MyCommand.Path)
$ErrorFile = (Split-Path $script:MyInvocation.MyCommand.Path) + "\ERROR.csv"
#------------------------------------ Setup Excel Variables
#The file we will be reading from
$ExcelFile = (Get-ChildItem -Path "$Path\*.xlsx").FullName
#Worksheet we are working on (by default this is the 1st tab)
$worksheet = (((New-Object -TypeName OfficeOpenXml.ExcelPackage -ArgumentList (New-Object -TypeName System.IO.FileStream -ArgumentList $ExcelFile,'Open','Read','ReadWrite')).Workbook).Worksheets[1]).Name
$ExcelServers = Import-Excel -Path $ExcelFile -WorkSheetname $worksheet -StartRow 1
#------------------------------------ Populate our variable with data from spreadsheet
$ExcelServersList = foreach($ExcelServer in $ExcelServers) {
$ExcelServer | Select-Object @{Name="ServerName";Expression={$_.Child}}, "Primary", @{Name="PatchWindow";Expression={$_."Patch Window"}}, @{Name="TestServer";Expression={$_."Test Server"}}, "DMZ", @{Name="OS";Expression={$_."Operating System"}}
}
#------------------------------------ Remove Duplicate entries
$SortedExcelServersList = ($ExcelServersList | Sort-Object -Property ServerName -Unique)
#------------------------------------ Seperate Servers from DMZ Servers
$FilteredServers = ForEach($SortedExcelServerList in $SortedExcelServersList) {
if($($SortedExcelServerList.DMZ) -eq $true)
{
$SortedExcelServerList.ServerName = [System.String]::Concat("$($SortedExcelServerList.ServerName)",".DMZ.com")
}
$SortedExcelServerList
}
#------------------------------------ Grab all servers from AD so we can use to compare against our list - also trimany whitespaces from output
$Servers = (dsquery * -filter "(&(objectClass=Computer)(objectCategory=Computer)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(operatingSystem=*Server*))" -limit 0 -attr Name | sort).trim()
#------------------------------------ Compare our list to servers in AD and filter out appliances
$FilteredServersResult = $Null
$FilteredServersResult = ForEach ($Item in $FilteredServers)
{
If (($item.servername -in $Servers) -or ($item.DMZ -eq $True))
{
$Item
}
}
#---------------------------- Perform our search. In this case all Monthly Updates and filter it to only show updates for Servers
$Updates = (Get-MSCatalogUpdate -Search $Search -AllPages ) | Where-Object { ($_.Title -like "*Server*") -OR ($_.Products -like "*Server*") }
#------------------------------------ Multithreading Magic
$FilteredServersResult | Start-RSJob -Throttle 50 -Batch "Test" -ScriptBlock {
Param($Server)
#Ping servers to make sure they're responsive
if($NULL -ne (Get-CimInstance -ClassName Win32_PingStatus -Filter "Address='$($Server.servername)' AND Timeout=100").ResponseTime)
{
Try
{
$ServerKBs = (((Get-HotFix -ComputerName $($Server.servername)) | Select-Object HotFixID,InstalledOn) | Where-Object {($_.InstalledOn -like "$ServerUpdateSearch" )}).HotFixID
foreach($Update in $Updates)
{
If (($Server.OS -like "*2016*") -And $Update.Products -match "*2016*")
{
#Check if there are any missing Updates
#($Server | Add-Member -NotePropertyMembers @{"Missing Updates" = $Update} -PassThru)
}
If (($Server.OS -like "*2019*") -And $Update.Products -match "*2019*")
{
#Check if there are any missing Updates
#($Server | Add-Member -NotePropertyMembers @{"Missing Updates" = $Update} -PassThru)
}
}
}
Catch
{
($Server | Add-Member -NotePropertyMembers @{"Error" = [string]$Error} -PassThru) | Export-Csv -Path $using:ErrorFile -NoTypeInformation -Force -Append
}
#Get list of Updates for servers
}
} | Wait-RSJob -ShowProgress | Receive-RSJob | Export-Csv -Path "$Path\Results.csv" -NoTypeInformation -Force
$End = (Get-Date)
$End - $Start
1条答案
按热度按时间b91juud31#
我可以使用3个不同的模块来实现这一点。
我采取的高水平步骤如下:
1.从电子表格导入服务器信息
1.我做了一些过滤,将MZ服务器与普通服务器分开
1.我将电子表格与AD中的内容进行比较,以确保不包括已禁用的设备或其他服务器对象
1.接下来,我查询Windows更新目录以获取本月的最新更新,并将其过滤为仅显示服务器更新,而且我只对关键和安全更新感兴趣。
1.在多线程脚本块中,我检查服务器上安装了哪些最新更新,并将其与我从Windows Update目录中提取的更新进行比较。
下面是我使用的脚本: