Working with shutdown reason code

I’m probably not the only one who ever wondered how to translate the error code in event ID 1074 to something meaningful.

The following blog post sheds some lights on this topic: https://blogs.msdn.microsoft.com/oldnewthing/20100831-00/?p=12993

Far from being the brightest code I’ve ever produced, here’s a function that tries to convert the shutdown reason code to something meaningful 😀

Function Convert-ShutdownReason {
[CmdletBinding()]
Param(
    [Parameter(Mandatory,ValueFromPipeLine)]
    $InputObject
)
Begin {}
Process {
    $InputObject | ForEach-Object {
        $test = $_
        
        $Planned = $major = $reasonMajor = $minor = $reasonMinor = $null
        switch ($_) {
            { ($_ -band 0x80000000) -eq 0x80000000 } {
                $Planned = $true # system defined
                $major = $_ -bxor 0x80000000
                break
            }
            { ($_ -band 0x40000000) -eq 0x40000000 } {
                $Planned = $true # custom user defined
                $major = $_ -bxor 0x40000000
                break
            }
            default {
                $Planned = $false # flag not set
                $major = $_
            }
        }
        switch ($major) {
            { ($_ -band 0x70000) -eq 0x70000 } {
                $reasonMajor = 'LEGACY_API'
                $minor = $_ -bxor 0x70000
                break
            }
            { ($_ -band 0x60000) -eq 0x60000 } {
                $reasonMajor ='POWER'
                $minor = $_ -bxor 0x60000
                break
            }
            { ($_ -band 0x50000) -eq 0x50000 } {
                $reasonMajor ='SYSTEM'
                $minor = $_ -bxor 0x50000
                break
            }
            { ($_ -band 0x40000) -eq 0x40000 } {
                $reasonMajor ='APPLICATION'
                $minor = $_ -bxor 0x40000
                break
            }
            { ($_ -band 0x30000) -eq 0x30000 } {
                $minor = $_ -bxor 0x30000
                $reasonMajor ='SOFTWARE'
                break
            }
            { ($_ -band 0x20000) -eq 0x20000 } {
                $reasonMajor ='OPERATINGSYSTEM'
                $minor = $_ -bxor 0x20000
                break
            }
            { ($_ -band 0x10000) -eq 0x10000 } {
                $reasonMajor ='HARDWARE'
                $minor = $_ -bxor 0x10000
                break
            }
            default {
                $reasonMajor ='OTHER'
                $minor = $_ -bxor 0x0
            }
        }

        switch ($minor) {
            { ($_ -band 0xff) -eq 0xff } {
                $reasonMinor = 'NONE'
                break    
            }
            { ($_ -band 0x22) -eq 0x22 } {
                $reasonMinor = 'DC_DEMOTION'
                break    
            }
            { ($_ -band 0x21) -eq 0x21 } {
                $reasonMinor = 'DC_PROMOTION'
                break    
            }
            { ($_ -band 0x20) -eq 0x20 } {
                $reasonMinor = 'TERMSRV'
                break    
            }
            { ($_ -band 0x19) -eq 0x19} {
                $reasonMinor ='MMC'
                break
            }
            { ($_ -band 0x18) -eq 0x18 } {
                $reasonMinor ='SECURITYFIX_UNINSTALL'
                break
            }
            { ($_ -band 0x17) -eq 0x17 } {
                $reasonMinor ='HOTFIX_UNINSTALL'
                break
            }
            { ($_ -band 0x16) -eq 0x16 } {
                $reasonMinor ='SERVICEPACK_UNINSTALL'
                break
            }
            { ($_ -band 0x15) -eq 0x15 } {
                $reasonMinor ='WMI'
                break
            }
            { ($_ -band 0x14) -eq 0x14 } {
                $reasonMinor ='NETWORK_CONNECTIVITY'
                break
            }
            { ($_ -band 0x13) -eq 0x13 } {
                $reasonMinor ='SECURITY'
                break
            }
            { ($_ -band 0x12) -eq 0x12 } {
                $reasonMinor ='SECURITYFIX'
                break
            }
            { ($_ -band 0x11) -eq 0x11} {
                $reasonMinor ='HOTFIX'
                break
            }
            { ($_ -band 0x10) -eq 0x10 } {
                $reasonMinor ='SERVICEPACK'
                break
            }
            { ($_ -band 0xf) -eq 0xf } {
                $reasonMinor ='BLUESCREEN'
                break
            }
            { ($_ -band 0xe) -eq 0xe } {
                $reasonMinor ='OTHERDRIVER'
                break
            }
            { ($_ -band 0xd) -eq 0xd } {
                $reasonMinor ='HARDWARE_DRIVER'
                break
            }
            { ($_ -band 0xc) -eq 0xc } {
                $reasonMinor ='ENVIRONMENT'
                break
            }
            { ($_ -band 0xb) -eq 0xb } {
                $reasonMinor ='CORDUNPLUGGED'
                break
            }
            { ($_ -band 0xa) -eq 0xa } {
                $reasonMinor ='POWER_SUPPLY'
                break
            }
            { ($_ -band 0x9) -eq 0x9 } {
                $reasonMinor ='NETWORKCARD'
                break
            }
            { ($_ -band 0x8) -eq 0x8 } {
                $reasonMinor ='PROCESSOR'
                break
            }
            { ($_ -band 0x7) -eq 0x7 } {
                $reasonMinor ='DISK'
                break
            }
            { ($_ -band 0x6) -eq 0x6 } {
                $reasonMinor ='UNSTABLE'
                break
            }
            { ($_ -band 0x5) -eq 0x5 } {
                $reasonMinor ='HUNG'
                break
            }
            { ($_ -band 0x4) -eq 0x4 } {
                $reasonMinor ='RECONFIG'
                break
            }
            { ($_ -band 0x3) -eq 0x3 } {
                $reasonMinor ='UPGRADE'
                break
            }
            { ($_ -band 0x2) -eq 0x2 } {
                $reasonMinor ='INSTALLATION'
                break
            }
            { ($_ -band 0x1) -eq 0x1 } {
                $reasonMinor ='MAINTENANCE'
                break
            }
            { ($_ -band 0x0) -eq 0x0 } {
                $reasonMinor ='OTHER'
                break
            }
            default {
            }
        }

        [PSCustomObject]@{
            Reason = '0x{0:X}' -f $test
            Text = '{0}: {1}' -f $reasonMajor,$reasonMinor
            Planned = $Planned
        }
    }
}
End {}
}

Here a a the most frequent shutdown reason codes I’ve encountered:

0x80020010,0x80070015,0x500ff,0x0,0x80030002,0x80030003 | 
Convert-ShutdownReason

convert-shutdown-reason-01

The shutdown reason code can be extracted from the event logs and directly piped into the function like this:

(Get-WinEvent -FilterHashtable @{ LogName = 'system';ProviderName='User32' ; Id = 1074} -MaxEvents 100) | 
Select -First 2 | Foreach-Object {
 ($_.Properties[3].Value) -as [int32]
}| 
Convert-ShutdownReason

convert-shutdown-reason-02

Virtual Bitlocker Containers

A few days ago a post on the Sans.org diary caught my attention because of its title: Virtual Bitlocker Containers. Very nice idea 😀

But instead of going through the old school diskpart.exe hassle, you can actually bring more automation with PowerShell with the following oneliner:


# Define a hashtable for readability
$BLHT = @{
 EncryptionMethod  = 'XtsAes256';
 PasswordProtector = $true;
 Password = (ConvertTo-SecureString 12345678 -AsPlainText -Force);
 UsedSpaceOnly = $true;
}

# Here we go!
New-VHD -Path c:\container.vhdx -SizeBytes 128MB -Fixed | 
Mount-VHD -Passthru | 
Initialize-Disk -PassThru | 
New-Partition -UseMaximumSize -AssignDriveLetter | 
Format-Volume -FileSystem NTFS | 
Select @{l='MountPoint';e={"$($_.DriveLetter):"}} |
Enable-BitLocker @BLHT | 
Add-BitLockerKeyProtector -RecoveryPasswordProtector -WA 0

NB1: XTS-AES encryption method is introduced in Windows 10 version 1511.
NB2: WA is the alias of WarningAction and 0 means SilentlyContinue.
You can try the oneliner without it and the recovery key will be displayed in the warning stream.

So, don’t forget to

# save the recovery key displayed by this command, somewhere...
Get-BitLockerVolume d: | Select -Expand KeyProtector

Bitlocker-Container-OneLiner

Bonus: about XTS-AES
Bitlocker-New-XTS-AES

Decipher Windows Update error codes

On PM.org, people sometimes ask questions and only provide the error code in various forms.
Wu-error-question
This time, it was provided as a int64.

What I usually to understand this error is locate my Get-ErrorCode function on my own blog and then browse the kb938205 page where I look for the hexadecimal value returned by my Get-ErrorCode function. Then I try give more context on PM.org.
WU-error-reply

As I repeat the same task over time, I wanted to have the answer as quick as possible. I reused some of the code of my Get-ErrorCode function and created the following gist

#Requires -Version 3.0
Function Find-WUErrorCode {
<#
.SYNOPSIS
Deciphers an error code using KB938205.
.DESCRIPTION
Translates an error code to hexadecimal and locates its meaning on https://support.microsoft.com/en-us/kb/938205
.PARAMETER InputObject
It can be an array of string,int32,int64,hex based error codes
.EXAMPLE
Find-WUErrorCode '0x80240017'
.EXAMPLE
0x80240017| Find-WUErrorCode
.EXAMPLE
-2145124329 | Find-WUErrorCode
.EXAMPLE
0xf0800,0xf081C,0x80240006,0x80244005,0x8024400D,0x8024CFFF,0xFFFFFFFF | Find-WUErrorCode
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory,ValueFromPipeline)]
[System.Object[]]$InputObjet
) Begin {
# Get the content of the KB page
try {
$URL = 'https://support.microsoft.com/api/content/kb/938205&#39;
$pagecontent = (new-object Net.Webclient).DownloadString([system.Uri]$($URL))
} catch {
Write-Warning -Message "Failed to read web page content because $($_.Exception.Message)"
break
}
# Sort categories' titles and at what line they resides
$Titles = @()
$pagecontent -split "`n" -split '>' -split '<' | Select-String -Pattern "^H4\sclass=" -Context 0,1 | ForEach-Object {
$Titles += [PSCustomObject]@{
LineNumber = $_.LineNumber + 1
Line = ($_.Context | Select -Expand PostContext) -replace '</H4',''
}
}
}
Process {
$InputObjet | ForEach-Object {
$err = $TV = $Short = $Long = $hex = $int32 = $int64 = $Cat = $null ;
Write-Verbose "Dealing with $($_)"
# Convert input object based on its type
try {
Switch ($_) {
{$_ -is [string]} {
$hex = "{0:X0}" -f ([int32]$_)
$int64 = [Convert]::ToInt64($hex,16)
$int32 = $_
break
}
{$_ -is [int32]} {
$hex = "{0:X0}" -f ([int32]$_)
$int64 = [Convert]::ToInt64($hex,16)
$int32 = $_
break
}
{$_ -is [int64]} {
$hex = "{0:X0}" -f ([int64]$_)
$int64 = $_
$int32 = [Convert]::ToInt32($hex,16)
break
}
default {}
}
$err = [PSCustomObject]@{
Hexadecimal = "0x$hex"
Int32 = $int32
Int64 = $int64
}
} catch {
Write-Warning -Message "Failed to convert input because $($_.Exception.Message)"
}
if ($err.Hexadecimal -match '^0x[a-fA-F\d]{1,8}' ) {
# Get full line
$TV = ($pagecontent -split "`n" -split '>' -split '<') | Select-String -Pattern "^$($err.Hexadecimal)\s"
if ($TV) {
# Short and Long description
$null,$Short,$Long = ([regex]'^0x[a-fA-F\d]{1,8}\s(?<WUShortName>[A-Z_]+)\s(?<WUDesc>.*)').Matches($TV.Line) |
Select-Object -ExpandProperty Groups |
Select -Expand Value
# Category
$Cat = $Titles | Where LineNumber -lt $($TV.LineNumber) | Select -Last 1 -ExpandProperty Line
# Output
[PSCustomObject]@{
Hexadecimal = $err.Hexadecimal ;
Constant = $Short ;
Description = $Long -replace '&lt;','<' -replace '&gt;','>';
Category = $Cat ;
}
} else {
Write-Warning -Message "$($err.Hexadecimal) cannot be found on page https://support.microsoft.com/en-us/kb/938205&quot;
}
} else {
Write-Warning -Message "Don't have a hex value for $_"
}
}
}
End {}
}
view raw WUError.ps1 hosted with ❤ by GitHub

It works with the value supplied on the PM.org mailing list
Find-WUError-2

And you can also pass values from the pipeline 😀
Find-WUError