Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function Convert-WuaResultCodeToName {
- param( [Parameter(Mandatory=$true)]
- [int] $ResultCode
- )
- $Result = $ResultCode
- switch($ResultCode)
- {
- 0 { $Result = "Not Started" }
- 1 { $Result = "In Progress" }
- 2 { $Result = "Succeeded" }
- 3 { $Result = "Succeeded With Errors" }
- 4 { $Result = "Failed" }
- 5 { $Result = "Aborted" }
- }
- return $Result
- }
- Function Get-PendingReboot {
- <#
- .SYNOPSIS
- Gets the pending reboot status on a local computer. Return
- .DESCRIPTION
- Queries the registry and WMI to determine if the system waiting for a reboot, from:
- CBServicing = Component Based Servicing (Windows 2008)
- WindowsUpdate = Windows Update / Auto Update (Windows 2003 / 2008)
- CCMClientSDK = SCCM 2012 Clients only (DetermineIfRebootPending method) otherwise $null value
- PendFileRename = PendingFileRenameOperations (Windows 2003 / 2008)
- Returns hash table similar to this:
- Computer : MYCOMPUTERNAME
- LastBootUpTime : 01/12/2014 11:53:04 AM
- CBServicing : False
- WindowsUpdate : False
- CCMClientSDK : False
- PendFileRename : False
- PendFileRenVal :
- RebootPending : False
- ErrorMsg :
- NOTES:
- ErrorMsg only contains something if an error occured
- .EXAMPLE
- Get-PendingReboot
- .EXAMPLE
- $PRB=Get-PendingReboot
- $PRB.RebootPending
- .NOTES
- Based On: http://gallery.technet.microsoft.com/scriptcenter/Get-PendingReboot-Query-bdb79542
- #>
- Begin { }## End Begin Script Block
- Process {
- Try {
- ## Setting pending values to false to cut down on the number of else statements
- $CompPendRen,$PendFileRename,$Pending,$SCCM = $false,$false,$false,$false
- ## Setting CBSRebootPend to null since not all versions of Windows has this value
- $CBSRebootPend = $null
- ## Querying WMI for build version
- $WMI_OS = Get-WmiObject -Class Win32_OperatingSystem -Property BuildNumber, CSName -ErrorAction Stop
- ## Making registry connection to the local/remote computer
- $HKLM = [UInt32] "0x80000002"
- $WMI_Reg = Get-Wmiobject -list "StdRegProv" -namespace root\default
- ## If Vista/2008 & Above query the CBS Reg Key
- If ([Int32]$WMI_OS.BuildNumber -ge 6001) {
- $RegSubKeysCBS = $WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\")
- $CBSRebootPend = $RegSubKeysCBS.sNames -contains "RebootPending"
- }
- ## Query WUAU from the registry
- $RegWUAURebootReq = $WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\")
- $WUAURebootReq = $RegWUAURebootReq.sNames -contains "RebootRequired"
- ## Query PendingFileRenameOperations from the registry
- $RegSubKeySM = $WMI_Reg.GetMultiStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\","PendingFileRenameOperations")
- $RegValuePFRO = $RegSubKeySM.sValue
- ## Query ComputerName and ActiveComputerName from the registry
- $ActCompNm = $WMI_Reg.GetStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\","ComputerName")
- $CompNm = $WMI_Reg.GetStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\","ComputerName")
- If ($ActCompNm -ne $CompNm) {
- $CompPendRen = $true
- }
- ## If PendingFileRenameOperations has a value set $RegValuePFRO variable to $true
- If ($RegValuePFRO) {
- $PendFileRename = $true
- }
- ## Determine SCCM 2012 Client Reboot Pending Status
- ## To avoid nested 'if' statements and unneeded WMI calls to determine if the CCM_ClientUtilities class exist, setting EA = 0
- $CCMClientSDK = $null
- $CCMSplat = @{
- NameSpace='ROOT\ccm\ClientSDK'
- Class='CCM_ClientUtilities'
- Name='DetermineIfRebootPending'
- ErrorAction='Stop'
- }
- ## Try CCMClientSDK
- Try {
- $CCMClientSDK = Invoke-WmiMethod @CCMSplat
- }
- Catch [System.UnauthorizedAccessException] {
- $CcmStatus = Get-Service -Name CcmExec -ComputerName $Computer -ErrorAction SilentlyContinue
- If ($CcmStatus.Status -ne 'Running') {
- #Write-Warning "$Computer`: Error - CcmExec service is not running."
- $CCMClientSDK = $null
- }
- }
- Catch {
- $CCMClientSDK = $null
- }
- If ($CCMClientSDK) {
- If ($CCMClientSDK.ReturnValue -ne 0) {
- Write-Warning "Error: DetermineIfRebootPending returned error code $($CCMClientSDK.ReturnValue)"
- }
- If ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) {
- $SCCM = $true
- }
- }
- Else {
- $SCCM = $null
- }
- ## Creating Custom PSObject and Select-Object Splat
- $SelectSplat = @{
- Property=(
- 'Computer',
- 'CBServicing',
- 'WindowsUpdate',
- 'CCMClientSDK',
- 'PendComputerRename',
- 'PendFileRename',
- 'PendFileRenVal',
- 'RebootPending'
- )
- }
- $results = New-Object -TypeName PSObject -Property @{
- Computer=$WMI_OS.CSName
- CBServicing=$CBSRebootPend
- WindowsUpdate=$WUAURebootReq
- CCMClientSDK=$SCCM
- PendComputerRename=$CompPendRen
- PendFileRename=$PendFileRename
- PendFileRenVal=$RegValuePFRO
- RebootPending=($CompPendRen -or $CBSRebootPend -or $WUAURebootReq -or $SCCM -or $PendFileRename)
- } | Select-Object @SelectSplat
- if ($debugging) {$results}
- elseIf ($results.rebootpending -eq $true) {
- Return "Pending Reboot"
- }
- elseif ($results.rebootpending -eq $false) {
- #Return "$results"
- Return "No"
- }
- else {
- Return "Unknown"
- }
- } # Outer Try Loop
- Catch {
- #Write-Warning "$Computer`: $_"
- Return $_
- }
- } ## End Process
- End { }## End End
- }## End Function Get-PendingReboot
- function Convert-Product {
- return $_.Categories | Where-Object {$_.Type -eq 'Product'} | Select-Object -First 1 -ExpandProperty Name
- }
- function Get-WuaHistory {
- # Get a WUA Session
- $session = (New-Object -ComObject 'Microsoft.Update.Session')
- # Query the latest 50 History starting with the first recordp
- $history = $session.QueryHistory("",0,50) |
- ForEach-Object {
- $Result = Convert-WuaResultCodeToName -ResultCode $_.ResultCode
- $product = Convert-Product $_.Categories
- # Make the properties hidden in com properties visible.
- $_ | Add-Member -MemberType NoteProperty -Value $Result -Name Result
- $_ | Add-Member -MemberType NoteProperty -Value $_.UpdateIdentity.UpdateId -Name UpdateId
- $_ | Add-Member -MemberType NoteProperty -Value $_.UpdateIdentity.RevisionNumber -Name RevisionNumber
- $_ | Add-Member -MemberType NoteProperty -Value $Product -Name Product
- Write-Output $_
- }
- #Remove null records and only return the fields we want
- $history |
- Where-Object {![String]::IsNullOrWhiteSpace($_.title)} |
- Select-Object Result, Date, Title, SupportUrl, Product, UpdateId, RevisionNumber
- }
- function Get-PendingUpdates {
- # Get a WUA Session
- $UpdateSession = (New-Object -ComObject 'Microsoft.Update.Session')
- $UpdateSearcher = $UpdateSession.CreateupdateSearcher()
- $HasSilverlight = Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -like "*Silverlight*"}
- if ($HasSilverlight) {
- Log "Has-Silverlight = Yes"
- $Updates = @($UpdateSearcher.Search("IsHidden=0 and IsInstalled=0").Updates) `
- | Select-Object Title | Out-String
- }
- else {
- Log "Has-Silverlight = No"
- $Updates = @($UpdateSearcher.Search("IsHidden=0 and IsInstalled=0").Updates) `
- | Where-Object {$_.Title -notlike "*Silverlight*"} `
- | Select-Object Title | Out-String
- }
- return $Updates
- }
- function Get-ComponentCleanupHistory {
- # Event filter for the initial query for all "Start" events in the last 90 days
- $EventFilter = @{
- LogName = 'Microsoft-Windows-TaskScheduler/Operational'
- Id = 100
- StartTime = [datetime]::Now.AddDays(-90)
- }
- # PropertySelector for the Correlation id (the InstanceId) and task name
- [string[]]$PropertyQueries = @(
- 'Event/EventData/Data[@Name="InstanceId"]'
- 'Event/EventData/Data[@Name="TaskName"]'
- )
- $PropertySelector = New-Object System.Diagnostics.Eventing.Reader.EventLogPropertySelector @(,$PropertyQueries)
- # Loop through the start events
- $TaskInvocations = foreach($StartEvent in Get-WinEvent -FilterHashtable $EventFilter) {
- # Grab the InstanceId and Task Name from the start event
- $InstanceId,$TaskName = $StartEvent.GetPropertyValues($PropertySelector)
- if ($TaskName -ne "\Microsoft\Windows\Servicing\StartComponentCleanup") {continue}
- # Create custom object with the name and start event, query end event by InstanceId
- [pscustomobject]@{
- TaskName = $TaskName
- StartTime = $StartEvent.TimeCreated
- EndTime = $(Get-WinEvent -FilterXPath "*[System[(EventID=102)] and EventData[Data[@Name=""InstanceId""] and Data=""{$InstanceId}""]]" -LogName 'Microsoft-Windows-TaskScheduler/Operational' -ErrorAction SilentlyContinue).TimeCreated
- }
- } # TaskInvocations
- return $TaskInvocations | Out-String
- } # Get-ComponentCleanupHistory
- function Get-ProcessOutput {
- Param (
- [Parameter(Mandatory=$true)]$FileName,
- $Args
- )
- $process = New-Object System.Diagnostics.Process
- $process.StartInfo.UseShellExecute = $false
- $process.StartInfo.RedirectStandardOutput = $true
- $process.StartInfo.RedirectStandardError = $true
- $process.StartInfo.FileName = $FileName
- if($Args) { $process.StartInfo.Arguments = $Args }
- $out = $process.Start()
- $StandardError = $process.StandardError.ReadToEnd()
- $StandardOutput = $process.StandardOutput.ReadToEnd()
- $output = New-Object PSObject
- $output | Add-Member -type NoteProperty -name StandardOutput -Value $StandardOutput
- $output | Add-Member -type NoteProperty -name StandardError -Value $StandardError
- return $output
- # just return the STDIN string
- #return $StandardOutput
- }
- Function Log {
- param(
- [Parameter(Mandatory=$true)][String]$msg
- )
- $now = Get-Date -UFormat "%Y/%m/%d %R"
- Add-Content $logfile "$now - $env:computername - $msg"
- }
- ###
- ### Define variables
- ###
- $SxSDir = "C:\Windows\WinSxS"
- #$SxSDir = "." # for testing
- $logfile = "C:\Windows\Logs\WindowsUpdate\WinSxS-stats.txt"
- $sep = "#" * 132
- $crlf = "`r`n"
- ###
- ### Main
- ###
- #
- # Header
- #
- Log ("collect-sxs-info - starting" + $crlf)
- #
- # O/S Status
- #
- Log "Is a Reboot Pending?: $(Get-PendingReboot)"
- Log "Pending Updates $crlf $(Get-PendingUpdates)"
- #
- # O/S Config
- #
- Log "Last StartComponentCleanup: $crlf $(Get-ComponentCleanupHistory)"
- Log "Scheduled Maintenance Tasks: $(Get-ScheduledTask | ? {$_.Settings.MaintenanceSettings} | Format-Table | Out-String)"
- #
- # Disk Usage
- #
- Log "Free Space on C: $(Get-PSDrive C | Select-Object -Property @{E={"{0:N2} GB" -f ($_.Free /1GB)}} | Format-Wide | Out-String)"
- #
- # WinSxS Folder Usage
- #
- if ($env:computername -eq "DH3TMR2") {
- $duargs = "/c C:\Users\Administrator.CORP\du64.exe -accepteula -nobanner $SxSDir"
- }
- else {
- $duargs = "/c C:\Users\Administrator\du64.exe -accepteula -nobanner $SxSDir"
- }
- $retval = Get-ProcessOutput -FileName "cmd.exe" -Args $duargs
- $output = "$SxSDir Folder Usage" + "$crlf$crlf" + $retval.StandardError + $retval.StandardOutput
- Log $output
- #
- # History
- #
- Log "Update History $crlf$crlf $(Get-WuaHistory | ConvertTo-Csv -NoType | Out-String)"
- #
- # Diagnostics
- #
- # Resource Checker (sfc) quick verify ( no changes )
- #
- if (0) { # 0 means 'never run', because I don't want to automate this part without realtime runtime monitoring.
- $args = "/c sfc /verifyonly"
- $retval = Get-ProcessOutput -FileName "cmd.exe" -Args $args
- $output = "Resource Checker (sfc) quick verify" + "$crlf$crlf" + $retval.StandardError + $retval.StandardOutput
- Log $output
- }
- else {
- Log "Resource Checker (sfc) quick verify is disabled"
- }
- Log "$crlf$sep$crlf$crlf"
Add Comment
Please, Sign In to add comment