Public/Functions/BitLocker.ps1
|
function Backup-MyBitLockerKeys { <# .SYNOPSIS Saves available BitLocker key materials to one or more folders. .DESCRIPTION Calls helper functions to export external keys, key packages, and recovery passwords for BitLocker-protected volumes. .PARAMETER Path One or more destination folders used to store exported key materials. .EXAMPLE Backup-MyBitLockerKeys -Path 'D:\BitLockerBackup' Exports BitLocker key materials to D:\BitLockerBackup. .LINK https://github.com/OSDeploy/OSD/tree/master/docs .NOTES Author: David Segura - Recast Software 2026-07-11 - Added comment-based help #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName)] [string[]]$Path ) begin { if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Elevated Administrator rights are required" } #================================================= # Get-Command Get-BitLockerVolume #================================================= if (-not (Get-Command -Name Get-BitLockerVolume -ErrorAction Ignore)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] requires Get-BitLockerVolume, which is not present on this system" } #================================================= } process { Save-MyBitLockerExternalKey -Path $Path Save-MyBitLockerKeyPackage -Path $Path Save-MyBitLockerRecoveryPassword -Path $Path } end {} } function Get-MyBitLockerKeyProtectors { <# .SYNOPSIS Returns BitLocker key protector details for encrypted volumes. .DESCRIPTION Enumerates BitLocker volumes and returns protector metadata, with optional inclusion of recovery password values. .PARAMETER ShowRecoveryPassword Includes recovery password values in the output when specified. .EXAMPLE Get-MyBitLockerKeyProtectors Lists key protector details without recovery password values. .EXAMPLE Get-MyBitLockerKeyProtectors -ShowRecoveryPassword Lists key protector details including recovery password values. .LINK https://github.com/OSDeploy/OSD/tree/master/docs .NOTES Author: David Segura - Recast Software 2026-07-11 - Added comment-based help #> [CmdletBinding()] param ( [Parameter(Position = 0, ValueFromPipelineByPropertyName)] [System.Management.Automation.SwitchParameter]$ShowRecoveryPassword ) begin { #================================================= # Require Admin Rights #================================================= if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Elevated Administrator rights are required" } #================================================= # Get-Command Get-BitLockerVolume #================================================= if (-not (Get-Command -Name Get-BitLockerVolume -ErrorAction Ignore)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] requires Get-BitLockerVolume, which is not present on this system" } #================================================= # Get-BitLockerVolume #================================================= #$BitLockerVolumes = Get-BitLockerVolume | Sort-Object -Property MountPoint | Where-Object {$_.VolumeStatus -eq 'FullyEncrypted'} | Where-Object {$_.LockStatus -eq 'Unlocked'} $BitLockerVolumes = Get-BitLockerVolume | Sort-Object -Property MountPoint | Where-Object { $_.EncryptionMethod -ne '' } #================================================= } process { $Results = foreach ($BitLockerVolume in $BitLockerVolumes) { $ExternalKeyMatches = @($BitLockerVolume.KeyProtector | Where-Object { $_.KeyProtectorType -eq 'ExternalKey' }).Count if ($ExternalKeyMatches -eq 0) { Write-Warning "Mountpoint $($BitLockerVolume.Mountpoint) does not contain an ExternalKey" } if ($ExternalKeyMatches -gt 1) { Write-Warning "Mountpoint $($BitLockerVolume.Mountpoint) contains $ExternalKeyMatches ExternalKeys. Ideally, this should be 1" } $RecoveryPasswordMatches = @($BitLockerVolume.KeyProtector | Where-Object { $_.KeyProtectorType -eq 'RecoveryPassword' }).Count if ($RecoveryPasswordMatches -eq 0) { Write-Warning "Mountpoint $($BitLockerVolume.Mountpoint) does not contain an RecoveryPassword" } if ($RecoveryPasswordMatches -gt 1) { Write-Warning "Mountpoint $($BitLockerVolume.Mountpoint) contains $RecoveryPasswordMatches RecoveryPassword. Ideally, this should be 1" } foreach ($item in $BitLockerVolume.KeyProtector) { if ($ShowRecoveryPassword) { [PSCustomObject] @{ ComputerName = $BitLockerVolume.ComputerName MountPoint = $BitLockerVolume.MountPoint #VolumeStatus = $BitLockerVolume.VolumeStatus #ProtectionStatus = $BitLockerVolume.ProtectionStatus LockStatus = $BitLockerVolume.LockStatus #EncryptionPercentage = $BitLockerVolume.EncryptionPercentage #WipePercentage = $BitLockerVolume.WipePercentage VolumeType = $BitLockerVolume.VolumeType #CapacityGB = $BitLockerVolume.CapacityGB KeyProtectorId = $item.KeyProtectorId KeyProtectorType = $item.KeyProtectorType RecoveryPassword = $item.RecoveryPassword AutoUnlockProtector = $item.AutoUnlockProtector KeyFileName = $item.KeyFileName } } else { [PSCustomObject] @{ ComputerName = $BitLockerVolume.ComputerName MountPoint = $BitLockerVolume.MountPoint #VolumeStatus = $BitLockerVolume.VolumeStatus #ProtectionStatus = $BitLockerVolume.ProtectionStatus LockStatus = $BitLockerVolume.LockStatus #EncryptionPercentage = $BitLockerVolume.EncryptionPercentage #WipePercentage = $BitLockerVolume.WipePercentage VolumeType = $BitLockerVolume.VolumeType #CapacityGB = $BitLockerVolume.CapacityGB KeyProtectorId = $item.KeyProtectorId KeyProtectorType = $item.KeyProtectorType #RecoveryPassword = $item.RecoveryPassword AutoUnlockProtector = $item.AutoUnlockProtector KeyFileName = $item.KeyFileName } } } } Return $Results } end {} } function Save-MyBitLockerExternalKey { <# .SYNOPSIS Saves BitLocker external key protectors (.BEK) to destination folders. .DESCRIPTION Finds unlocked volumes with external key protectors and exports their external key files to one or more target paths. .PARAMETER Path One or more destination folders used to store exported external keys. .EXAMPLE Save-MyBitLockerExternalKey -Path 'D:\BitLockerBackup' Exports external key files to D:\BitLockerBackup. .LINK https://github.com/OSDeploy/OSD/tree/master/docs .NOTES Author: David Segura - Recast Software 2026-07-11 - Added comment-based help #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName)] [string[]]$Path ) begin { #================================================= # Require Admin Rights #================================================= if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Elevated Administrator rights are required" } #================================================= # Get-Command Get-BitLockerVolume #================================================= if (-not (Get-Command -Name Get-BitLockerVolume -ErrorAction Ignore)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] requires Get-BitLockerVolume, which is not present on this system" } #================================================= # Test-Path #================================================= foreach ($Item in $Path) { if (-NOT (Test-Path -LiteralPath $Item)) { New-Item $Item -ItemType Directory -Force -ErrorAction Stop | Out-Null } } #================================================= # Get-BitLockerKeyProtectors #================================================= $BitLockerKeyProtectors = Get-MyBitLockerKeyProtectors | Sort-Object -Property MountPoint | Where-Object { $_.LockStatus -eq 'Unlocked' -and $_.KeyProtectorType -eq 'ExternalKey' } #================================================= } process { foreach ($BitLockerKeyProtector in $BitLockerKeyProtectors) { foreach ($Item in $Path) { manage-bde.exe -protectors -get $BitLockerKeyProtector.MountPoint -Type ExternalKey -SaveExternalKey $Item } } } end {} } function Save-MyBitLockerKeyPackage { <# .SYNOPSIS Saves BitLocker key packages to destination folders. .DESCRIPTION Enumerates unlocked BitLocker volumes and exports key package data for each non-TPM protector to one or more target paths. .PARAMETER Path One or more destination folders used to store exported key packages. .EXAMPLE Save-MyBitLockerKeyPackage -Path 'D:\BitLockerBackup' Exports key package files to D:\BitLockerBackup. .LINK https://github.com/OSDeploy/OSD/tree/master/docs .NOTES Author: David Segura - Recast Software 2026-07-11 - Added comment-based help #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName)] [string[]]$Path ) begin { #================================================= # Require Admin Rights #================================================= if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Elevated Administrator rights are required" } #================================================= # Get-Command Get-BitLockerVolume #================================================= if (-not (Get-Command -Name Get-BitLockerVolume -ErrorAction Ignore)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] requires Get-BitLockerVolume, which is not present on this system" } #================================================= # Test-Path #================================================= foreach ($Item in $Path) { if (-NOT (Test-Path -LiteralPath $Item)) { New-Item $Item -ItemType Directory -Force -ErrorAction Stop | Out-Null } } #================================================= # Get-BitLockerKeyProtectors #================================================= $BitLockerKeyProtectors = Get-MyBitLockerKeyProtectors -ShowRecoveryPassword | Sort-Object -Property MountPoint | Where-Object { $_.LockStatus -eq 'Unlocked' -and $_.KeyProtectorType -ne 'Tpm' } #================================================= } process { foreach ($BitLockerKeyProtector in $BitLockerKeyProtectors) { foreach ($Item in $Path) { manage-bde.exe -KeyPackage $BitLockerKeyProtector.MountPoint -id $BitLockerKeyProtector.KeyProtectorId -Path $Item } } } end {} } function Save-MyBitLockerRecoveryPassword { <# .SYNOPSIS Saves BitLocker recovery passwords to text files. .DESCRIPTION Exports recovery password protector values from unlocked volumes and writes them as recovery key text files in one or more destination folders. .PARAMETER Path One or more destination folders used to store recovery password files. .EXAMPLE Save-MyBitLockerRecoveryPassword -Path 'D:\BitLockerBackup' Exports recovery password text files to D:\BitLockerBackup. .LINK https://github.com/OSDeploy/OSD/tree/master/docs .NOTES Author: David Segura - Recast Software 2026-07-11 - Added comment-based help #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName)] [string[]]$Path ) begin { #================================================= # Require Admin Rights #================================================= if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Elevated Administrator rights are required" } #================================================= # Get-Command Get-BitLockerVolume #================================================= if (-not (Get-Command -Name Get-BitLockerVolume -ErrorAction Ignore)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] requires Get-BitLockerVolume, which is not present on this system" } #================================================= # Test-Path #================================================= foreach ($Item in $Path) { if (-NOT (Test-Path -LiteralPath $Item)) { New-Item $Item -ItemType Directory -Force -ErrorAction Stop | Out-Null } } #================================================= # Get-BitLockerKeyProtectors #================================================= $BitLockerKeyProtectors = Get-MyBitLockerKeyProtectors -ShowRecoveryPassword | Sort-Object -Property MountPoint | Where-Object { $_.LockStatus -eq 'Unlocked' -and $_.KeyProtectorType -eq 'RecoveryPassword' } #================================================= } process { foreach ($BitLockerKeyProtector in $BitLockerKeyProtectors) { foreach ($Item in $Path) { $ComputerName = $BitLockerKeyProtector.ComputerName $MountPoint = $BitLockerKeyProtector.MountPoint -replace ":" $KeyProtectorId = $BitLockerKeyProtector.KeyProtectorId -replace "{" -replace "}" $RecoveryPassword = $BitLockerKeyProtector.RecoveryPassword $TextContent = @" BitLocker Drive Encryption recovery key To verify that this is the correct recovery key, compare the start of the following identifier with the identifier value displayed on your PC. Identifier: $KeyProtectorId If the above identifier matches the one displayed by your PC, then use the following key to unlock your drive. Recovery Key: $RecoveryPassword If the above identifier doesn't match the one displayed by your PC, then this isn't the right key to unlock your drive. Try another recovery key, or refer to https://go.microsoft.com/fwlink/?LinkID=260589 for additional assistance. "@ New-Item -Path "$Item\$ComputerName MountPoint $MountPoint $KeyProtectorId.TXT" -Force $TextContent | Set-Content "$Item\$ComputerName MountPoint $MountPoint $KeyProtectorId.TXT" -Force } } } end {} } function Unlock-MyBitLockerExternalKey { <# .SYNOPSIS Unlocks BitLocker volumes using external key files. .DESCRIPTION Searches one or more paths for matching .BEK files and unlocks locked BitLocker volumes that use external key protectors. .PARAMETER Path One or more folders to search for matching .BEK external key files. .PARAMETER Recurse Searches subdirectories under each path for matching key files. .EXAMPLE Unlock-MyBitLockerExternalKey -Path 'D:\BitLockerBackup' Unlocks volumes using matching .BEK files in the specified folder. .EXAMPLE Unlock-MyBitLockerExternalKey -Path 'D:\BitLockerBackup' -Recurse Unlocks volumes using matching .BEK files found recursively. .LINK https://github.com/OSDeploy/OSD/tree/master/docs .NOTES Author: David Segura - Recast Software 2026-07-11 - Added comment-based help #> [CmdletBinding()] param ( [Parameter(Position = 0, ValueFromPipelineByPropertyName)] [string[]]$Path, [Parameter(Position = 1, ValueFromPipelineByPropertyName)] [System.Management.Automation.SwitchParameter]$Recurse ) begin { #================================================= # Require Admin Rights #================================================= if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Elevated Administrator rights are required" } #================================================= # Get-Command Get-BitLockerVolume #================================================= if (-not (Get-Command -Name Get-BitLockerVolume -ErrorAction Ignore)) { throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] requires Get-BitLockerVolume, which is not present on this system" } #================================================= # Test-Path #================================================= foreach ($Item in $Path) { if (-NOT (Test-Path -LiteralPath $Item)) { Write-Warning "Unable to validate Path at $Item" Break } } #================================================= # Get-MyBitLockerKeyProtectors #================================================= $BitLockerKeyProtectors = Get-MyBitLockerKeyProtectors | Sort-Object -Property MountPoint | Where-Object { $_.LockStatus -eq 'Locked' -and $_.KeyProtectorType -eq 'ExternalKey' } $BitLockerKeyProtectors if (-NOT $BitLockerKeyProtectors) { Write-Warning "No BitLocker Volumes with a LockStatus of Locked could be found" Break } #================================================= } process { foreach ($BitLockerKeyProtector in $BitLockerKeyProtectors) { $ExternalKeyName = (($BitLockerKeyProtector).KeyProtectorId -replace "{" -replace "}") + ".BEK" if ($Recurse) { $RecoveryKeyPath = Get-ChildItem -Path $Path -Force -Recurse -File -Filter $ExternalKeyName -ErrorAction Ignore | Select-Object -ExpandProperty FullName -First 1 } else { $RecoveryKeyPath = Get-ChildItem -Path $Path -Force -File -Filter $ExternalKeyName -ErrorAction Ignore | Select-Object -ExpandProperty FullName -First 1 } if ($RecoveryKeyPath) { Write-Verbose "MountPoint: $($BitLockerKeyProtector.MountPoint)" -Verbose Write-Verbose "RecoveryKeyPath: $RecoveryKeyPath" -Verbose Unlock-BitLocker -MountPoint $BitLockerKeyProtector.MountPoint -RecoveryKeyPath $RecoveryKeyPath } else { Write-Warning "Unable to find a ExternalKey $ExternalKeyName" } } } end {} } |