我正在尝试找到一种方法来创建 WSUS 报告,其中包含已批准用于计算机组 A 但尚未批准用于一个或多个其他组的更新。或者,列出每个更新和每个组的批准状态的表格报告,以便可以对其进行处理以提取我需要的内容。WSUS 本身似乎没有这样的报告,或者至少我找不到这样的报告,因此非常欢迎生成此类报告的脚本。
此 powershell 脚本完全符合您的初始请求。检查一个 computerGroup 并查找未批准用于一个或多个其他计算机组的更新。
注意您需要在 WSUS 服务器或安装了 WSUS 管理工具的计算机上运行它。
配置
设置$targetComputerGroup为您要用作基准的计算机组 设置$CheckForMissing为您想查看它们是否已获批准的一个或多个组的名称。注意:要做倍数只是昏迷分开(“Group1,Group2”)
$serverName="localhost"
$targetComputerGroup="BaselineGroup"
$checkForMissing="MissingGroup1,MissingGroup2"
[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
$wsus=[Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($serverName,$false)
$computerGroup=$wsus.GetComputerTargetGroups()|ForEach-Object -Process {if ($_.Name -eq $targetComputerGroup) {$_}}
$UpdateScope=New-Object Microsoft.UpdateServices.Administration.UpdateScope
$UpdateScope.ApprovedStates="Any"
$updateScope.ApprovedComputerTargetGroups.Add($computerGroup)
$Approvals = $wsus.GetUpdateApprovals($UpdateScope)
#At this point we have all of the updates assigned to the $targetComputerGroup
$report= @()
write-host "Querying for all Updates approved for $targetComputerGroup"
foreach ($Approval in $approvals) {
$record=""|Select-Object ComputerGroup,UpdateName, UpdateID
$record.ComputerGroup=$wsus.GetComputerTargetGroup($Approval.ComputerTargetGroupID).Name
$record.UpdateName=$wsus.GetUpdate($Approval.UpdateID).Title
$record.UpdateID=$wsus.GetUpdate($Approval.UpdateID).ID.UpdateID
$report +=$record
}
#Now group the results by UpdateName
$GR=$report|group -Property UpdateName
$CheckForMissing=$CheckForMissing.Split(",")
foreach ($entry in $gr) {
$groups=@()
foreach ($g in $entry.Group) {
$groups += $g.ComputerGroup
}
foreach ($missing in $checkForMissing) {
if ($groups -Contains $missing) {}
else{
New-Object PSObject -Property @{
Name = $entry.Name
UpdateID = $entry.Group[0].UpdateID
GroupMissing = $missing
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
完成后,您将输出如下输出:

如果不是输出到屏幕,而是要将列表导出为 CSV,请使用以下代码替换底部部分:
$CheckForMissing=$CheckForMissing.Split(",")
$CSVdata=@()
foreach ($entry in $gr) {
$groups=@()
foreach ($g in $entry.Group) {
$groups += $g.ComputerGroup
}
foreach ($missing in $checkForMissing) {
if ($groups -Contains $missing) {}
else{
$CSVdata += New-Object PSObject -Property @{
Name = $entry.Name
UpdateID = $entry.Group[0].UpdateID
GroupMissing = $missing
}
}
}
}
$CSVdata|Export-Csv "FILENAME.CSV"
Run Code Online (Sandbox Code Playgroud)
人们可以“简单地”连接到 WSUS 数据库并对其运行查询:
\\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query使用Windows 身份验证连接。这些表格似乎对您的问题感兴趣:
tbUpdate
保存有关单个更新的信息
tbTargetGroup
保存有关所有计算机组的信息
tbDeployment
保存有关哪些计算机组已批准哪些更新的信息
但是,利用现有视图vUpdateApproval来检索您需要的大部分信息似乎是有益的,因为该视图已经ActionID从tbDeployment其他内容中转换了列。
vUpdateApproval但是,该视图不包含任何易于阅读的更新标题。标题通常是从tbLocalizedProperty. 为了方便我们,还有另一种观点:vUpdate.
我的 WSUS 数据库中确实没有正确的数据来构建适合您的第一个请求的正确查询(而且我没有足够的信心盲目地构建它)。所以这是您的次要请求的一种方法。如果我没有搞砸,它会生成所有更新的列表和所有组的批准状态。
SELECT
aUpdate.UpdateId,
aUpdate.DefaultTitle,
aGroup.Name as GroupName,
aApproval.Action as Action
FROM
PUBLIC_VIEWS.vUpdate AS aUpdate INNER JOIN
PUBLIC_VIEWS.vUpdateApproval AS aApproval ON aUpdate.UpdateId = aApproval.UpdateId LEFT JOIN
dbo.tbTargetGroup as aGroup ON aGroup.TargetGroupID = aApproval.ComputerTargetGroupId
;
Run Code Online (Sandbox Code Playgroud)
在我们的德国 SBS 上产生此输出:

对于具有 5 个默认组的 SBS,这会在大约 26 秒内产生 121558 个结果行。因此,如果您想处理查询,建议SELECT TOP 1000在测试时将第一行更改为。
我还花时间将其全部打包到一个 PowerShell 脚本中:
# Where to connect to
$dataSource = "\\.\pipe\MSSQL`$MICROSOFT##SSEE\sql\query"
$connectionTimeout = 30
# The query we want to perform against the WSUS database
$query = @"
SELECT TOP 10
aUpdate.UpdateId,
aUpdate.DefaultTitle,
aGroup.Name as GroupName,
aApproval.Action as Action
FROM
PUBLIC_VIEWS.vUpdate AS aUpdate INNER JOIN
PUBLIC_VIEWS.vUpdateApproval AS aApproval ON aUpdate.UpdateId = aApproval.UpdateId LEFT JOIN
dbo.tbTargetGroup as aGroup ON aGroup.TargetGroupID = aApproval.ComputerTargetGroupId
"@
$queryTimeout = 120
# Construct the connection string
$connectionString = "Data Source={0};Integrated Security=True;Connect Timeout={1};Database=SUSDB" -f $dataSource,$connectionTimeout
# Open the connection to the SQL server
$connection = New-Object System.Data.SqlClient.SQLConnection
$connection.ConnectionString = $connectionString
$connection.Open()
# Construct our SQL command
$sqlCommand = New-Object system.Data.SqlClient.SqlCommand( $query, $connection )
$sqlCommand.CommandTimeout = $queryTimeout
# Retrieve the data from the server
$dataSet = New-Object system.Data.DataSet
$dataAdapter = New-Object system.Data.SqlClient.SqlDataAdapter( $sqlCommand )
[void]$dataAdapter.fill( $dataSet )
# Clean up
$connection.Close()
# Output result
$dataSet.Tables
Run Code Online (Sandbox Code Playgroud)
请注意,此脚本包含SELECT TOP 10避免在测试期间淹没您的 shell的限制。
