Approbations du rapport WSUS pour un groupe

9

J'essaie de trouver un moyen de créer un rapport WSUS des mises à jour qui ont été approuvées pour le groupe d'ordinateurs A qui n'ont pas été approuvées pour un ou plusieurs autres groupes. Alternativement, un rapport tabulaire qui répertorie l'état d'approbation pour chaque mise à jour et chaque groupe, afin qu'il puisse être traité pour extraire ce dont j'ai besoin. Il ne semble pas y avoir un tel rapport dans WSUS lui-même, ou du moins pas un que je puisse trouver, donc un script pour produire un tel rapport serait le bienvenu.

John Gardeniers
la source
Sur quelle version de Windows votre WSUS fonctionne-t-il?
Nate
@Nate, c'est WSUS 3.2.7600.226 fonctionnant sur une machine 64 bits Server 2008 R2 Standard.
John Gardeniers
Je pense que j'ai une solution pour vous, donnez-m'en quelques-unes et je confirmerai
Nate

Réponses:

8

Ce script PowerShell fait exactement votre demande initiale. Examinez un groupe d'ordinateurs et recherchez les mises à jour non approuvées pour un ou plusieurs autres groupes d'ordinateurs.

Remarque Vous devrez l'exécuter sur un serveur WSUS ou sur une machine sur laquelle les outils d'administration WSUS sont installés.

Configuration

Définissez $targetComputerGrouple groupe d'ordinateurs que vous souhaitez utiliser comme ligne de base Définissez $CheckForMissingles noms du ou des groupes pour lesquels vous souhaitez voir s'ils ont été approuvés. Remarque: Pour faire des multiples juste un coma séparés ("Groupe1, Groupe2")

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

Une fois terminé, vous aurez une sortie comme: entrez la description de l'image ici

Si au lieu de sortir à l'écran, vous souhaitez exporter la liste vers un fichier CSV, remplacez la partie inférieure par le code suivant:

   $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
la source
Ça marche! Savez-vous comment empêcher la sortie d'être tronquée? BTW, je ne peux pas attribuer la prime pendant encore 9 heures.
John Gardeniers
1
La troncature est fonction de la façon dont les formats PowerShell pour l'écran. J'ai mis à jour la réponse avec un exemple de sortie vers un fichier CSV afin que vous puissiez avoir les valeurs complètes.
Nate
Excellent, car CSV est très adapté à mes besoins. De là, je peux le transmettre à Perl, où au moins je sais ce que je fais. Très appréciée.
John Gardeniers
7

On peut "simplement" se connecter à la base de données WSUS et exécuter des requêtes sur celle-ci:

  1. Démarrez SQL Management Studio avec des privilèges élevés.
  2. Connectez-vous à l' \\.\pipe\MSSQL$MICROSOFT##SSEE\sql\queryaide de l' authentification Windows .

Ces tableaux semblent intéresser votre question:

  • tbUpdate
    Contient des informations sur les mises à jour uniques

  • tbTargetGroup
    Contient des informations sur tous les groupes d'ordinateurs

  • tbDeployment
    Contient des informations sur les mises à jour approuvées pour quels groupes d'ordinateurs

Cependant, il semble avantageux d'utiliser la vue déjà existante vUpdateApprovalpour récupérer la plupart des informations que vous recherchez, car cette vue traduit déjà la ActionIDcolonne tbDeploymententre autres choses.

La vUpdateApprovalvue, cependant, ne comprend aucun titre facilement lisible pour les mises à jour. Les titres sont généralement lus tbLocalizedProperty. Pour le rendre plus facile pour nous, il y a une autre vue: vUpdate.

Je n'ai pas vraiment les données appropriées dans notre base de données WSUS pour construire la requête appropriée qui conviendrait à votre première demande (et je ne suis pas assez confiant pour la construire aveuglément). Voici donc une approche pour votre demande secondaire. Si je ne me trompe pas, il produit une liste de toutes les mises à jour et l'état d'approbation pour tous les groupes.

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
;

Ce qui produit cette sortie sur notre SBS allemand:

entrez la description de l'image ici

Pour notre SBS avec ses 5 groupes par défaut, cela produit 121558 lignes de résultats en ~ 26s. Donc, si vous voulez jouer avec la requête, il peut être conseillé de changer la première ligne en SELECT TOP 1000pendant le test.

J'ai également pris le temps de tout résumer dans un script 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

Veuillez noter que ce script inclut la SELECT TOP 10limitation pour éviter d'inonder votre shell pendant les tests.

Der Hochstapler
la source
C'est certainement quelque chose à enquêter. Il existe peut-être un module Perl pour interagir avec MS SQL Server.
John Gardeniers
@JohnGardeniers: J'ai ajouté un script PowerShell qui exécute la requête. Malheureusement, mes connaissances en Perl sont encore pires :)
Der Hochstapler
C'est un bon point de départ mais je devrai trouver comment arrêter la sortie tronquée.
John Gardeniers
@JohnGardeniers: C'est exactement ainsi que PowerShell affiche les objets retournés par défaut. Vous pouvez exécuter le script comme myscript.ps1 | flpour obtenir une sortie différente (non tronquée).
Der Hochstapler
J'ai décidé de vous récompenser pour vos efforts mais vous devrez attendre 24 heures. Le système ne me permettra pas d'accorder une prime immédiatement.
John Gardeniers