Я пытаюсь найти способ создать отчет WSUS об обновлениях, одобренных для группы компьютеров A, но не одобренных для одной или нескольких других групп. Как вариант, табличный отчет, в котором перечислены статусы утверждения для каждого обновления и каждой группы, чтобы его можно было обработать для извлечения того, что мне нужно. Похоже, что в самом WSUS такого отчета нет, или, по крайней мере, я не могу его найти, поэтому сценарий для создания такого отчета был бы весьма кстати.
Этот сценарий PowerShell делает именно то, что было вашим первоначальным запросом. Изучите одну группу компьютеров и найдите обновления, не утвержденные для одной или нескольких других групп компьютеров.
Примечание. Вам нужно будет запустить это либо на сервере WSUS, либо на машине, на которой установлены инструменты администрирования WSUS.
Конфигурация
Устанавливать $targetComputerGroup
в группу компьютеров, которую вы хотите использовать в качестве базового набора $CheckForMissing
к именам группы или групп, для которых вы хотите узнать, утверждены ли они. Примечание. Чтобы выполнить кратное повторение, просто разделите запятую ("Группа1, Группа2")
$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
}
}
}
}
По завершении вы получите следующий результат:
Если вместо вывода на экран вы хотите экспортировать список в 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"
Можно "просто" подключиться к базе данных WSUS и запустим к нему запросы:
\\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query
с помощью Проверка подлинности Windows.Эти таблицы представляются интересными в отношении вашего вопроса:
tbUpdate
Содержит информацию об отдельных обновлениях
tbTargetGroup
Содержит информацию обо всех группах компьютеров
tbDeployment
Содержит информацию о том, какие обновления были утверждены для каких групп компьютеров.
Однако кажется полезным использовать уже существующее представление vUpdateApproval
для получения большей части информации, которая вам нужна, поскольку это представление уже переводит ActionID
столбец из tbDeployment
среди прочего.
В vUpdateApproval
view, однако, не содержит легко читаемых заголовков обновлений. Заголовки обычно читаются из 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
;
Что производит этот вывод на нашем немецком SBS:
Для нашего SBS с его 5 группами по умолчанию это дает 121558 строк результатов за ~ 26 секунд. Итак, если вы хотите поэкспериментировать с запросом, может быть целесообразно изменить первую строку на 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
Обратите внимание, что этот сценарий включает SELECT TOP 10
ограничение, чтобы избежать переполнения вашей оболочки во время тестирования.