Get the full reboot history for troubleshooting

  • The context

I’ve had some weird issues with my USB wireless audio headset causing a BSoD (Blue Screen of Death) 0x9f when I put the computer into sleep mode.
I’ve solved the issue by installing the following hotfix: A Windows 7-based computer does not enter sleep mode after you play audio files through a USB headset or a USB audio device http://support.microsoft.com/kb/2619331

BSoD 0x9f usbaudio.sys

When troubleshooting the issue, I used the Reliability control panel item to quickly summarize the issue.

control panel reliability monitor

Visually speaking it’s a very good built-in tool that relies on the RAC task.

RAC task

However it’s partially turned off by default on servers. Here’s a screenshot of Windows 2008 R2 SP1:
RAC task on 2008 R2

So, my idea was to get something between the Reliability monitor and the custom filtered view of the logs called ‘Administrative events’.

  • About the approach

This tip on Powershell Magazine presents how to quickly track the reboot history of a computer when things run correctly http://www.powershellmagazine.com/2012/10/15/pstip-get-your-reboot-history/

Of course, there will be a 6005 event logged after a BSoD and the hard reboot of the computer. But that doesn’t help much troubleshooting why the computer has been restarted.

I tried to gather more relevant information about the reboot history using the following command:

Get-EventLog -LogName System -Source 'Microsoft-Windows-Kernel-General',            
'Microsoft-Windows-Kernel-Power','Microsoft-Windows-Power-Troubleshooter',            
'Eventlog','User32' | Out-ExcelReport

NB: the Out-ExcelReport function can be found on http://powershell.com/cs/blogs/tips/archive/2012/12/20/sending-results-to-excel.aspx

Get-Eventlog reboot history

As you can see in the above image certain Message properties cannot be “interpreted” 😦

I’ve got the following message for example:

The description for Event ID ‘1’ in Source ‘Microsoft-Windows-Kernel-General’ cannot be found.
The local computer may not have the necessary registry information or message DLL files to display the message, or you may not have permission to access them.
The following information is part of the event:’2012-12-16T08:29:52.500000000Z’, ‘2012-12-15T19:39:38.905000000Z’

I’ve got a second problem, a DLL file needs probably to be registered with regsrv32. I’ve found an ugly way to workaround this issue. Anyway, I’ll prefer to present below a solution that work when you don’t have the above issue.

  • My solution version 1.0

Function Out-ExcelReport {
param(
        $Path = "$env:temp\$(Get-Random).csv"
)
    $Input | Export-Csv -Path $Path -Encoding UTF8 -NoTypeInformation -UseCulture
    Invoke-Item -Path $Path
}


Function Get-EventsHelper {
[CmdletBinding()]
Param(
 $HashTable,
 [string]$Provider,
 [string]$LogName,
 [int32[]]$EventID
)
Begin{
}
Process {
    $SuperHT = @{}
    $SuperHT += @{LogName = $LogName}
    if ($EventID) { $SuperHT += @{ID = $EventID} }
    if ($Provider) { $SuperHT += @{ProviderName = $Provider} }
    try {
        Get-WinEvent -FilterHashtable $SuperHT @HashTable
    } catch {
        Write-Warning -Message "Failed to get events from computer $Computer because $($_.Exception.Message)"
        if ( ($_.Exception.Message -eq "The RPC server is unavailable") -or ($_.CategoryInfo.Reason -eq 'UnauthorizedAccessException')) { 
            return
        }
    }
}
End {}
}

Function Get-RebootHistory {
 Param(            
    [CmdletBinding()]            
        [parameter(ValueFromPipeline = $True,ValueFromPipeLineByPropertyName = $True)]            
        [Alias('CN','__Server','IPAddress','Server')]            
        [string[]]$Computername = $Env:Computername,            
                    
        [parameter()]            
        [Alias('RunAs')]            
        [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty                   
    )            
Begin            
{            
    # Make sure we run as admin            
    $usercontext = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()            
    $IsAdmin = $usercontext.IsInRole(544)                                                       
    if (-not($IsAdmin))            
    {            
        Write-Warning "Must run powerShell as Administrator to perform these actions"            
        return            
    }             
    $results = @()
}             
Process             
{            
    $ComputerName | ForEach-Object -Process {            
        $allevents = @()
        $Computer = $_            
        # Prepare HT            
        $HT = @{}
        # Supplied Alternate Credentials?                        
        If ($PSBoundParameters['Credential'])  {                        
            $HT.credential = $Credential                        
        }            
        If ($Computer -eq $Env:Computername) {            
            $HT.remove('Credential')            
        } Else {            
            $HT += @{Computername = $Computer}            
        }     
        Write-Verbose -Message "Targeting computer $Computer"       
        $HT += @{ ErrorAction = 'Stop'}

        $allevents += Get-EventsHelper -Hashtable $HT -LogName "System" -Provider "User32"
        $allevents += Get-EventsHelper -Hashtable $HT -LogName "System" -Provider "Microsoft-Windows-WER-SystemErrorReporting" -EventID 1001,1018
        $allevents += Get-EventsHelper -Hashtable $HT -LogName "System" -Provider "Microsoft-Windows-Kernel-General" -EventID 1,12,13
        $allevents += Get-EventsHelper -Hashtable $HT -LogName "System" -Provider "Microsoft-Windows-Kernel-Power" -EventID 42,41,109
        $allevents += Get-EventsHelper -Hashtable $HT -LogName "System" -Provider "Microsoft-Windows-Power-Troubleshooter" -EventID 1
        $allevents += Get-EventsHelper -Hashtable $HT -LogName "System" -Provider "Eventlog" -EventID 6005,6006,6008,6013
        $results += ($allevents | ForEach-Object -Process {
                $_ | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer
                $_
        } |  Sort-Object -Descending -Property RecordId)
    } # end of Foreach-Object process
    $results            
}
End {}
} # end of function

Here is how to use the above code 😎

# Store credentials being used for remote computers            
$cred = Get-Credential            
            
# Get the reboot history and store in the $r variable            
$r =  Get-RebootHistory -Computername 'localhost',"PC2",$env:computername,"PC1","V-PC739" -Verbose -Credential $cred            
            
# Display on console            
$r | Select -Property  ComputerName,TimeCreated,Id,RecordId,Message | ft -AutoSize -Property ComputerName,TimeCreated,Id,Message            
            
# Read the results in Excel            
$r | Select -Property  ComputerName,TimeCreated,Id,RecordId,Message | Out-ExcelReport

Here you can see the result in Excel: Reboot history in Excel

  • Improvements for version 2.0
  • Bonus: other useful links
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s