Aprovações de relatório do WSUS para um grupo

9

Estou tentando encontrar uma maneira de criar um relatório do WSUS de atualizações que foram aprovadas para o grupo de computadores A que não foram aprovadas para um ou mais outros grupos. Como alternativa, um relatório tabular que lista o status de aprovação de cada atualização e cada grupo, para que possa ser processado para extrair o que eu preciso. Parece não haver um relatório desse tipo no WSUS, ou pelo menos nenhum que eu possa encontrar; portanto, um script para produzir esse relatório seria bem-vindo.

John Gardeniers
fonte
Em qual versão do Windows o seu WSUS está sendo executado?
Nate
@Nate, é o WSUS 3.2.7600.226 em execução em uma máquina Server 2008 R2 Standard de 64 bits.
John Gardeniers
Acho que tenho uma solução para você, dê-me um pouco e eu vou confirmar
Nate

Respostas:

8

Esse script do PowerShell faz exatamente qual foi sua solicitação inicial. Examine um computerGroup e encontre atualizações não aprovadas para um ou vários outros grupos de computadores.

Nota Você precisará executá-lo em um servidor WSUS ou em uma máquina com as ferramentas de administração do WSUS instaladas.

Configuração

Defina $targetComputerGroupcomo o Grupo de computadores que você deseja usar como linha de base. Defina $CheckForMissingos nomes dos grupos para os quais você deseja ver se eles foram aprovados. Nota: Para fazer múltiplos, coma apenas em 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
            }
        }
    }
}

Quando concluído, você terá uma saída como: insira a descrição da imagem aqui

Se, em vez de enviar para a tela, você deseja exportar a lista para um CSV, substitua a parte inferior pelo seguinte 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
fonte
Funciona! Você sabe como impedir que a saída seja truncada? Aliás, não posso conceder a recompensa por mais 9 horas.
John Gardeniers
1
O truncamento é uma função de como o PowerShell é formatado para a tela. Atualizei a resposta com um exemplo de saída para arquivo CSV para que você possa ter os valores completos.
Nate
Excelente, pois o CSV é muito adequado para minhas necessidades. A partir daqui, posso alimentá-lo com Perl, onde pelo menos sei o que estou fazendo. Muito apreciado.
precisa saber é o seguinte
7

Pode-se "simplesmente" conectar-se ao banco de dados do WSUS e executar consultas nele:

  1. Inicie o SQL Management Studio com privilégios elevados.
  2. Conecte-se \\.\pipe\MSSQL$MICROSOFT##SSEE\sql\queryusando a autenticação do Windows .

Estas tabelas parecem ser interessantes em relação à sua pergunta:

  • tbUpdate
    Contém informações sobre atualizações únicas

  • tbTargetGroup
    Contém informações sobre todos os grupos de computadores

  • tbDeployment
    Contém informações sobre quais atualizações foram aprovadas para quais grupos de computadores

No entanto, parece benéfico utilizar a visualização já existente vUpdateApprovalpara recuperar a maioria das informações que você procura, pois essa visualização já traduz a ActionIDcoluna tbDeploymententre outras coisas.

A vUpdateApprovalexibição, no entanto, não inclui títulos de fácil leitura para atualizações. Os títulos são geralmente lidos tbLocalizedProperty. Para tornar mais fácil para nós, há um outro ponto de vista: vUpdate.

Eu realmente não tenho os dados adequados em nosso banco de dados do WSUS para construir a consulta adequada que se encaixaria na sua primeira solicitação (e não tenho confiança suficiente para construí-la às cegas). Então, aqui está uma abordagem para sua solicitação secundária. Se eu não errei, ele produzirá uma lista de todas as atualizações e o estado de aprovação de todos os 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
;

O que produz essa saída no nosso SBS alemão:

insira a descrição da imagem aqui

Para o nosso SBS com seus 5 grupos padrão, isso produz 121558 linhas de resultado em ~ 26s. Portanto, se você quiser brincar com a consulta, pode ser aconselhável alterar a primeira linha para SELECT TOP 1000durante o teste.

Também reservei um tempo para agrupar tudo em um script do 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

Observe que este script inclui a SELECT TOP 10limitação para evitar inundar seu shell durante o teste.

Der Hochstapler
fonte
Certamente é algo para investigar. Talvez haja um módulo Perl para interagir com o MS SQL Server.
John Gardeniers
@ JohnGardeniers: adicionei um script do PowerShell que executa a consulta. Infelizmente, meu conhecimento Perl é ainda pior :)
Der Hochstapler
Esse é um bom ponto de partida, mas terei que descobrir como impedir que a saída seja truncada.
John Gardeniers
@JohnGardeniers: é assim que o PowerShell exibe os objetos retornados por padrão. Você pode executar o script myscript.ps1 | flpara obter uma saída diferente (não truncada).
Der Hochstapler
Decidi recompensá-lo por seu esforço, mas você terá que esperar 24 horas. O sistema não me permitirá conceder uma recompensa imediatamente.
John Gardeniers