BitLocker and Self-Immolation
My primary device is corporate-owned, and contains a lot of corporate data. Policy says to have it secured by BitLocker, so I’ll have it secured by BitLocker. Perfectly reasonable, no?
However, I suspect something is wrong with this laptop’s TPM chip. Every so often, it decides that it won’t accept my BitLocker PIN, and requires I have the recovery passcode, all 48 digits of it. I save it to my SkyDrive (so I can read it via my phone if/when I need it), but sometimes I forget to do so. Both as an academic exercise, and as a way making it possible for me to schedule it as a task, I wrote the script below.
The two key takeaways are:
- Get-BitLockerVolume gives the BitLocker recovery data
- Start-Process PowerShell.exe –Verb RunAs escalates permissions
<# .Synopsis
Save the bitlocker recovery key.
.Description
Save the bitlocker recovery key for the specified drive, elevating itself to Administrator if possible.
.Notes
The self-elevation is brittle as hell. This script must be placed in a path that does not have special characters. Specifically '$home\Skydrive @ Microsoft\foo' does NOT work.
#>
param (
[string]$Path = "$home\SkyDrive\BitlockerRecovery\$env:ComputerName-$(Get-Date -Format 'yyyy-MM-dd').txt",
[string]$Drive = "c"
);
function Get-BitLockerRecoveryKey {
param (
[string]$Path = "$home\SkyDrive\BitlockerRecovery\$env:ComputerName-$(Get-Date -Format 'yyyy-MM-dd').txt",
[string]$Drive = "c"
);
# move existing key
if (Test-Path -Path $path) { mv $path ("$path-$(Get-Date -Format yyyyMMddhhmmss).txt"); }
# attempt to create destination folder if it doesn't exist
$pathDirName = Split-Path -Parent -Path $Path;
if (!(Test-Path -Path $pathDirName)) { New-Item -ItemType Directory -Path $path -ErrorAction SilentlyContinue | Out-null; }
if (Test-Path -Path $pathDirName) {
# If the folder exists, perform the heavy lifting
$scriptBlock = {
param (
[string]$Path = "$home\SkyDrive\BitlockerRecovery\$env:ComputerName-$(Get-Date -Format 'yyyy-MM-dd').txt",
[string]$Drive = "c"
);
$KeyProtector = (Get-BitLockerVolume -ErrorAction SilentlyContinue -MountPoint $Drive).KeyProtector | ? { $_.KeyProtectorType -eq 'RecoveryPassword'; }
if ($keyProtector) { "ID: $($KeyProtector.KeyProtectorId -replace '[{}]')`n`nKey: $($KeyProtector.RecoveryPassword)" | Out-File -FilePath $Path; }
} # $scriptBlock =
Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $Path, $Drive;
if (Test-Path -path $Path) {
# if the file exists, this worked (but that's normally not the case)
$Path;
} else {
# if the file doesn't exist, elevate itself.
Start-Process PowerShell.Exe -WindowStyle Hidden -Verb RunAs -ArgumentList "-NoProfile -File $($MyInvocation.ScriptName) -Drive $Drive -Path $Path" -Wait;
if (Test-Path -Path $Path) {
# if the file exists, this worked
$Path;
} else {
# otherwise, carp and exit
Write-Warning "Unable to save BitLocker recovery key for drive ${drive}:";
} # if (Test-Path -Path $Path)
} # if (Test-Path $Path)
} else {
# if output folder doesn't exist, carp and exit
Write-Warning "Unable to find nor create $pathDirName";
} # if (Test-Path -Path $pathDirName)
} # function
# run it.
Get-BitLockerRecoveryKey -Path $Path -Drive $Drive;