Aprobaciones de informes de WSUS para un grupo

9

Estoy tratando de encontrar una manera de crear un informe WSUS de actualizaciones que se hayan aprobado para el grupo de computadoras A que no se hayan aprobado para uno o más grupos. Alternativamente, un informe tabular que enumera el estado de aprobación para cada actualización y cada grupo, de modo que pueda procesarse para extraer lo que necesito. No parece haber tal informe en el propio WSUS, o al menos no puedo encontrar uno, por lo que un guión para producir dicho informe sería muy bienvenido.

John Gardeniers
fuente
¿En qué versión de Windows se está ejecutando su WSUS?
Nate
@Nate, es WSUS 3.2.7600.226 ejecutándose en una máquina Server 2008 R2 Standard de 64 bits.
John Gardeniers
Creo que tengo una solución para usted, dame unos y voy a confirmar
Nate

Respuestas:

8

Este script de PowerShell hace exactamente lo que fue su solicitud inicial. Examine un grupo de computadoras y encuentre actualizaciones no aprobadas para uno o varios otros grupos de computadoras.

Nota Deberá ejecutar esto en un servidor WSUS o en una máquina que tenga instaladas las herramientas de administración de WSUS.

Configuración

Establezca $targetComputerGroupel grupo de computadoras que desea usar como línea de base Establezca $CheckForMissinglos nombres del grupo o grupos para los que desea ver si han sido aprobados. Nota: Para hacer múltiplos solo coma separado ("Grupo1, Grupo2")

$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
            }
        }
    }
}

Cuando termine, obtendrá una salida como: ingrese la descripción de la imagen aquí

Si en lugar de enviar a la pantalla desea exportar la lista a un CSV, reemplace la parte inferior con el siguiente código:

   $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"
Nate
fuente
¡Funciona! ¿Sabes cómo evitar que la salida se trunca? Por cierto, no puedo otorgar la recompensa por otras 9 horas.
John Gardeniers
1
El truncamiento es una función de cómo los formatos de PowerShell para la pantalla. Actualicé la respuesta con un ejemplo de salida a un archivo CSV para que pueda tener los valores completos.
Nate
Excelente, ya que CSV es muy adecuado para mis necesidades. Desde aquí puedo alimentarlo a Perl, donde al menos sé lo que estoy haciendo. Muy apreciado.
John Gardeniers
7

Uno puede "simplemente" conectarse a la base de datos WSUS y ejecutar consultas en su contra:

  1. Inicie SQL Management Studio con privilegios elevados.
  2. Conéctese \\.\pipe\MSSQL$MICROSOFT##SSEE\sql\querycon la autenticación de Windows .

Estas tablas parecen ser de interés con respecto a su pregunta:

  • tbUpdate
    Contiene información sobre actualizaciones individuales

  • tbTargetGroup
    Contiene información sobre todos los grupos de computadoras

  • tbDeployment
    Contiene información sobre qué actualizaciones se han aprobado para qué grupos de computadoras

Sin embargo, parece beneficioso utilizar la vista ya existente vUpdateApprovalpara recuperar la mayor parte de la información que busca, ya que esta vista ya traduce la ActionIDcolumna tbDeploymententre otras cosas.

La vUpdateApprovalvista, sin embargo, no incluye ningún título fácil de leer para las actualizaciones. Los títulos generalmente se leen tbLocalizedProperty. Para que sea más fácil para nosotros, hay otro punto de vista: vUpdate.

Realmente no tengo los datos adecuados en nuestra base de datos WSUS para construir la consulta adecuada que se ajuste a su primera solicitud (y no tengo la confianza suficiente para construirla a ciegas). Así que aquí hay un enfoque para su solicitud secundaria. Si no me equivoqué, produce una lista de todas las actualizaciones y el estado de aprobación para todos los grupos.

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
;

Lo que produce esta salida en nuestro SBS alemán:

ingrese la descripción de la imagen aquí

Para nuestro SBS con sus 5 grupos predeterminados, esto produce 121558 filas de resultados en ~ 26s. Por lo tanto, si desea jugar con la consulta, puede ser recomendable cambiar la primera línea SELECT TOP 1000durante la prueba.

También me tomé el tiempo para envolverlo todo en un script de 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

Tenga en cuenta que este script incluye la SELECT TOP 10limitación para evitar inundar su shell durante las pruebas.

Der Hochstapler
fuente
Ciertamente es algo para investigar. Quizás haya un módulo Perl para interactuar con MS SQL Server.
John Gardeniers
@JohnGardeniers: agregué un script de PowerShell que realiza la consulta. Lamentablemente, mi conocimiento de Perl es aún peor :)
Der Hochstapler
Ese es un buen punto de partida, pero tendré que averiguar cómo detener el truncamiento de la salida.
John Gardeniers
@JohnGardeniers: así es como PowerShell muestra los objetos devueltos de forma predeterminada. Puede ejecutar el script myscript.ps1 | flpara obtener un resultado diferente (no truncado).
Der Hochstapler
He decidido recompensarlo por su esfuerzo, pero tendrá que esperar 24 horas. El sistema no me permitirá otorgar una recompensa de inmediato.
John Gardeniers