powershell Reporte de Actualizaciones WSUS

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了powershell Reporte de Actualizaciones WSUS相关的知识,希望对你有一定的参考价值。

<#
    WSUS Report
    
    ** Requires WSUS Administrator Console Installed or UpdateServices Module available **        
    
    TO DO:
        - SUSDB Size
        - Computers in Active Directory but not in WSUS (OPTIONAL)
#>

#region User Specified WSUS Information
$WSUSServer = 'XXXX'

#Accepted values are "80","443","8530" and "8531"
$Port = 8530 
$UseSSL = $False

#Specify when a computer is considered stale
$DaysComputerStale = 50 

#Send email of report
[bool]$SendEmail = $FALSE
#Display HTML file
[bool]$ShowFile = $FALSE
#endregion User Specified WSUS Information

#region User Specified Email Information
$EmailParams = @{
    To = 'user@domain.local'
    From = 'WSUSReport@domain.local'    
    Subject = "$WSUSServer WSUS Report"
    SMTPServer = 'exchange.domain.local'
    BodyAsHtml = $True
}
#endregion User Specified Email Information

#region Helper Functions
Function Set-AlternatingCSSClass {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
        [string]$HTMLFragment,
        [Parameter(Mandatory=$True)]
        [string]$CSSEvenClass,
        [Parameter(Mandatory=$True)]
        [string]$CssOddClass
    )
    [xml]$xml = $HTMLFragment
    $table = $xml.SelectSingleNode('table')
    $classname = $CSSOddClass
    foreach ($tr in $table.tr) {
        if ($classname -eq $CSSEvenClass) {
            $classname = $CssOddClass
        } else {
            $classname = $CSSEvenClass
        }
        $class = $xml.CreateAttribute('class')
        $class.value = $classname
        $tr.attributes.append($class) | Out-null
    }
    $xml.innerxml | out-string
}
Function Convert-Size {

    [cmdletbinding()]
    Param (
        [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
        [Alias("Length")]
        [int64]$Size
    )
    Begin {
        If (-Not $ConvertSize) {
            Write-Verbose ("Creating signature from Win32API")
            $Signature =  @"
                 [DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
                 public static extern long StrFormatByteSize( long fileSize, System.Text.StringBuilder buffer, int bufferSize );
"@
            $Global:ConvertSize = Add-Type -Name SizeConverter -MemberDefinition $Signature -PassThru
        }
        Write-Verbose ("Building buffer for string")
        $stringBuilder = New-Object Text.StringBuilder 1024
    }
    Process {
        Write-Verbose ("Converting {0} to upper most size" -f $Size)
        $ConvertSize::StrFormatByteSize( $Size, $stringBuilder, $stringBuilder.Capacity ) | Out-Null
        $stringBuilder.ToString()
    }
}
#endregion Helper Functions

#region Load WSUS Required Assembly
If (-Not (Get-Module -ListAvailable -Name UpdateServices)) {
    #Add-Type "$Env:ProgramFiles\Update Services\Api\Microsoft.UpdateServices.Administration.dll"
    $Null = [reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
} Else {
    Import-Module -Name UpdateServices
}
#endregion Load WSUS Required Assembly

#region CSS Layout
$head=@"
    <style> 
        h1 {
            text-align:center;
            border-bottom:1px solid #666666;
            color:#009933;
        }
		TABLE {
			TABLE-LAYOUT: auto; 
			FONT-SIZE: 100%; 
			WIDTH: 100%
		}
		* {
			margin:0
		}

		.pageholder {
			margin: 0px auto;
		}
					
		td {
			VERTICAL-ALIGN: TOP; 
			FONT-FAMILY: Tahoma
		}
					
		th {
			VERTICAL-ALIGN: TOP; 
			COLOR: #018AC0; 
			TEXT-ALIGN: left;
            background-color:DarkGrey;
            color:Black;
		}
        body {
            text-align:left;
            font-smoothing:always;
            width:100%;
        }
        .odd { background-color:#ffffff; }
        .even { background-color:#dddddd; }               
    </style>
"@
#endregion CSS Layout

#region Initial WSUS Connection
$ErrorActionPreference = 'Stop'
Try {
    $Wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WSUSServer,$UseSSL,$Port)
} Catch {
    Write-warning "$($WSUSServer)<$($Port)>: $($_)"
    Break
}
$ErrorActionPreference = 'Continue'
#endregion Initial WSUS Connection

#region Pre-Stage -- Used in more than one location
$htmlFragment = ''
$WSUSConfig = $Wsus.GetConfiguration()
$WSUSStats = $Wsus.GetStatus()
$TargetGroups = $Wsus.GetComputerTargetGroups()
$EmptyTargetGroups = $TargetGroups | Where {
    $_.GetComputerTargets().Count -eq 0 -AND $_.Name -ne 'Unassigned Computers'
}

#Stale Computers
$computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
$computerscope.ToLastReportedStatusTime = (Get-Date).AddDays(-$DaysComputerStale)
$StaleComputers = $wsus.GetComputerTargets($computerscope) | ForEach {
    [pscustomobject]@{
        "Nombre del Equipo" = $_.FullDomainName
        IP = $_.IPAddress
        "Ultimo Contacto" = $_.LastReportedStatusTime
        "Ultima Sincronizacion" = $_.LastSyncTime
        Grupo = ($_.GetComputerTargetGroups() | Where-Object {$_.Name -ne "Todos los Equipos"} | Select -Expand Name) -join ', '
    }
}

#Pending Reboots
$updateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
$updateScope.IncludedInstallationStates = 'InstalledPendingReboot'
$computerScope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
$computerScope.IncludedInstallationStates = 'InstalledPendingReboot'
$GroupRebootHash=@{}
$ComputerPendingReboot = $wsus.GetComputerTargets($computerScope) | ForEach {
    $Update = ($_.GetUpdateInstallationInfoPerUpdate($updateScope) | ForEach {
        $Update = $_.GetUpdate()
        $Update.title
    }) -join ', '
    If ($Update) {
        $TempTargetGroups = ($_.GetComputerTargetGroups() | Where-Object {$_.Name -ne "Todos los Equipos"} | Select -Expand Name) -join ', '
        $TempTargetGroups | ForEach {
            $GroupRebootHash[$_]++
        }
        [pscustomobject] @{
            "Nombre del equipo" = $_.FullDomainName
            IP = $_.IPAddress
            Grupo = $TempTargetGroups -join ', '
            #Updates = $Update
        }
    }
} | Sort Computername


#NotInstalled
$updateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
$updateScope.IncludedInstallationStates = 'NotInstalled'
$computerScope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
$computerScope.IncludedInstallationStates = 'NotInstalled'
$GroupNotInstalledHash=@{}
$ComputerHash = @{}
$UpdateHash = @{}
$ComputerNotInstall = $wsus.GetComputerTargets($computerScope) | ForEach {
    $Computername = $_.FullDomainName
    $Update = ($_.GetUpdateInstallationInfoPerUpdate($updateScope) | ForEach {
        $Update = $_.GetUpdate()
        $Update.title
        $ComputerHash[$Computername] += ,$Update.title
        $UpdateHash[$Update.title] += ,$Computername
    }) -join ', '
    If ($Update) {
        $TempTargetGroups = ($_.GetComputerTargetGroups() | Where-Object {$_.Name -ne "Todos los Equipos"} | Select -Expand Name) -join ', '
        $TempTargetGroups | ForEach {
            $GroupNotInstalledHash[$_]++
        }
        [pscustomobject] @{
            "Nombre del Equipo" = $_.FullDomainName
            IP = $_.IPAddress
            Grupo = $TempTargetGroups -join ', '
            Actualizaciones = $Update
        }
    }
} | Sort Computername



#Failed Installations
$updateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
$updateScope.IncludedInstallationStates = 'Failed'
$computerScope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
$computerScope.IncludedInstallationStates = 'Failed'
$GroupFailHash=@{}
$ComputerHash = @{}
$UpdateHash = @{}
$ComputerFailInstall = $wsus.GetComputerTargets($computerScope) | ForEach {
    $Computername = $_.FullDomainName
    $Update = ($_.GetUpdateInstallationInfoPerUpdate($updateScope) | ForEach {
        $Update = $_.GetUpdate()
        $Update.title
        $ComputerHash[$Computername] += ,$Update.title
        $UpdateHash[$Update.title] += ,$Computername
    }) -join ', '
    If ($Update) {
        $TempTargetGroups = ($_.GetComputerTargetGroups() | Where-Object {$_.Name -ne "Todos los Equipos"} | Select -Expand Name) -join ', '
        $TempTargetGroups | ForEach {
            $GroupFailHash[$_]++
        }
        [pscustomobject] @{
            "Nombre del Equipo" = $_.FullDomainName
            IP = $_.IPAddress
            Grupo = $TempTargetGroups -join ', '
            Actualizaciones = $Update
        }
    }
} | Sort Computername
#endregion Pre-Stage -- Used in more than one location

#region WSUS SERVER INFORMATION
$Pre = @"
<div style='margin: 0px auto; BACKGROUND-COLOR:Blue;Color:White;font-weight:bold;FONT-SIZE: 16pt;'>
    Informacion del servidor WSUS
</div>
"@
    #region WSUS Version
                    $WSUSVersion = [pscustomobject]@{
    Servidor = $WSUS.ServerName
    Version = $Wsus.Version
    Puerto = $Wsus.PortNumber
    "Protocolo de Version del Servidor" = $Wsus.ServerProtocolVersion
    }
    $Pre += @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Informacion del Servicio WSUS
        </div>

"@
    $Body = $WSUSVersion | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion WSUS Version

    #region WSUS Server Content
    $drive = $WSUSConfig.LocalContentCachePath.Substring(0,2)
    $Data = Get-CIMInstance -ComputerName $WSUSServer -ClassName Win32_LogicalDisk -Filter "DeviceID='$drive'"
    $UsedSpace = $data.Size - $data.Freespace
    $PercentFree = "{0:P}" -f ($Data.Freespace / $Data.Size)
    $Pre = @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Informacion del almacenamiento de WSUS
        </div>

"@
    $WSUSDrive = [pscustomobject]@{
        "Ruta de archivos" = $WSUSConfig.LocalContentCachePath
        "Espacio total" = $data.Size | Convert-Size
        "Espacio Utilizado" = $UsedSpace | Convert-Size
        "Espacio Libre" = $Data.freespace | Convert-Size
        "% libre" = $PercentFree
    }
    $Body = $WSUSDrive | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion WSUS Server Content

    #region Last Synchronization
    $synch = $wsus.GetSubscription()
    $SynchHistory = $Synch.GetSynchronizationHistory()[0]
    $WSUSSynch = [pscustomobject]@{
        Automatica = $synch.SynchronizeAutomatically
        "Hora Programada" = $synch.SynchronizeAutomaticallyTimeOfDay
        "Ultima Sincronizacion" = $synch.LastSynchronizationTime
        Resultado = $SynchHistory.Result
    }
    If ($SynchHistory.Result -eq 'Failed') {
        $WSUSSynch = $WSUSSynch | Add-Member -MemberType NoteProperty -Name ErrorType -Value $SynchHistory.Error -PassThru |
        Add-Member -MemberType NoteProperty -Name ErrorText -Value $SynchHistory.ErrorText -PassThru
    }
    $Pre = @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Ultima sincronizacion del servidor
        </div>

"@
    $Body = $WSUSSynch | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion Last Synchronization

#endregion WSUS SERVER INFORMATION

#region CLIENT INFORMATION
$Pre = @"
<div style='margin: 0px auto; BACKGROUND-COLOR:Blue;Color:White;font-weight:bold;FONT-SIZE: 16pt;'>
    Informacion de Equipos
</div>
"@
    #region Computer Statistics
    $WSUSComputerStats = [pscustomobject]@{
        "Total equipos" = [int]$WSUSStats.ComputerTargetCount    
        "Stale($DaysComputerStale Days)" = ($StaleComputers | Measure-Object).count
        "Equipos pendientes de actualizar" = [int]$WSUSStats.ComputerTargetsNeedingUpdatesCount
        "Instalaciones con errores" = [int]$WSUSStats.ComputerTargetsWithUpdateErrorsCount
        "Pendientes de reiniciar" = ($ComputerPendingReboot | Measure-Object).Count
    }

    $Pre += @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Estadisticas de Equipos
        </div>

"@
    $Body = $WSUSComputerStats | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion Computer Statistics

    #region Operating System
    $Pre = @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Contador de equipos por Sistema Operativo
        </div>

"@
    $Body = $wsus.GetComputerTargets() | Group OSDescription |
    Select @{L='Sistema Operativo';E={$_.Name}}, Count  | 
    ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'Odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post    
    #endregion Operating System

    #region Stale Computers
    $Pre = @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Equipos sin comunicacion ($DaysComputerStale dias)
        </div>

"@
    $Body = $StaleComputers | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion Stale Computers

    #region Unassigned Computers
    $Unassigned = ($TargetGroups | Where {
        $_.Name -eq 'Equipos sin Asignar'
    }).GetComputerTargets() | ForEach {
        [pscustomobject]@{
            Equipo = $_.FullDomainName
            "Sistema Operativo" = $_.OSDescription
            IP = $_.IPAddress
            "Ultimo Contacto" = $_.LastReportedStatusTime
            "Ultima Sincronizacion" = $_.LastSyncTime
        }    
    }
    $Pre = @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Equipos sin Asignar
        </div>

"@
    $Body = $Unassigned | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion Unassigned Computers

    #region Failed Update Install
    $Pre = @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Equipos con errores de instalacion
        </div>

"@
    $Body = $ComputerFailInstall | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion Failed Update Install

    #region Pending Reboot 
    $Pre = @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Equipos pendientes de reiniciar
        </div>

"@
    $Body = $ComputerPendingReboot | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion Pending Reboot

    #region Not Installed 
    $Pre = @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Equipos con actualizaciones pendientes
        </div>

"@
    $Body = $ComputerNotInstall | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion Not Installed






#endregion CLIENT INFORMATION

#region UPDATE INFORMATION
$Pre = @"
<div style='margin: 0px auto; BACKGROUND-COLOR:Blue;Color:White;font-weight:bold;FONT-SIZE: 16pt;'>
    Informacion de Actualizaciones
</div>
"@
    #region Update Statistics
    $WSUSUpdateStats = [pscustomobject]@{
        Totales = [int]$WSUSStats.UpdateCount    
        Necesarias = [int]$WSUSStats.UpdatesNeededByComputersCount
        Aprobadas = [int]$WSUSStats.ApprovedUpdateCount
        Rechazadas = [int]$WSUSStats.DeclinedUpdateCount
        "Necesitan Ficheros" = [int]$WSUSStats.ExpiredUpdateCount 
        "Pendientes de Aprobar" = [int]$WSUSStats.NotApprovedUpdateCount   
    }
    $Pre += @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Estadisticas de Actualizaciones
        </div>

"@
    $Body = $WSUSUpdateStats | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion Update Statistics

    #region Failed Update Installations
    $FailedUpdateInstall = $UpdateHash.GetEnumerator() | ForEach {
        [pscustomobject]@{
            Actualizacion = $_.Name
            "Nombre del Equipo" = ($_.Value) -join ', '
        }
    }
    $Pre = @"
        <div style='margin: 0px auto; BACKGROUND-COLOR:LightBlue;Color:Black;font-weight:bold;FONT-SIZE: 14pt;'>
            Instalaciones fallidas por actualizacion
        </div>

"@
    $Body = $FailedUpdateInstall | ConvertTo-Html -Fragment | Out-String | Set-AlternatingCSSClass -CSSEvenClass 'even' -CssOddClass 'odd'
    $Post = "<br>"
    $htmlFragment += $Pre,$Body,$Post
    #endregion Failed Update Installations

#endregion UPDATE INFORMATION


#region Compile HTML Report
$HTMLParams = @{
    Head = $Head
    Title = "WSUS Report for $WSUSServer"
    PreContent = "<H1><font color='white'>Please view in html!</font><br>$WSUSServer WSUS Report</H1>"
    PostContent = "$($htmlFragment)<i>Report generated on $((Get-Date).ToString())</i>" 
    
}
$Report = ConvertTo-Html @HTMLParams | Out-File -FilePath c:\WSUS.html
#endregion Compile HTML Report

If ($ShowFile) {
    $Report | Out-File WSUSReport.html
    Invoke-Item WSUSReport.html
}

#region Send Email
If ($SendEmail) {
    $EmailParams.Body = $Report
    Send-MailMessage @EmailParams
}
#endregion Send Email

以上是关于powershell Reporte de Actualizaciones WSUS的主要内容,如果未能解决你的问题,请参考以下文章

powershell Comandos de docker

powershell 抑制de lignesvidesaprèsunsplit

powershell 实用程序de PARAMETER

powershell Listado de usuarios en VPN

powershell Funciónparaescritura de logs en PWS

poj1655 Balancing Act