Update Ensure-RealBitLockerKey.ps1
This commit is contained in:
@@ -1,35 +1,3 @@
|
|||||||
<##
|
|
||||||
.SYNOPSIS
|
|
||||||
Ensures a valid BitLocker recovery key is present for one or all volumes, optionally re-encrypting and auditing.
|
|
||||||
.DESCRIPTION
|
|
||||||
Advanced cmdlet to manage BitLocker recovery keys. Supports:
|
|
||||||
• Targeting system drive only (default) or all fixed disks with -AllDisks
|
|
||||||
• Adding a fresh RecoveryPassword protector (fast path)
|
|
||||||
• Full decrypt-and-reencrypt cycle (clean-slate path)
|
|
||||||
• Persisting audit output to registry or RMM UDF fields
|
|
||||||
Supports ShouldProcess for safe execution and returns a PSObject detailing actions.
|
|
||||||
.PARAMETER MountPoint
|
|
||||||
Drive letter (e.g. 'C:') to target. Ignored when -AllDisks is used.
|
|
||||||
.PARAMETER AllDisks
|
|
||||||
Switch to target all fixed disk volumes instead of a single MountPoint.
|
|
||||||
.PARAMETER FullReencrypt
|
|
||||||
Switch to perform a full decrypt-and-re-encrypt cycle.
|
|
||||||
.PARAMETER PersistToRegistry
|
|
||||||
Switch to persist the new recovery key and audit string to registry/UDF.
|
|
||||||
.PARAMETER UDFNumber
|
|
||||||
RMM UDF index to write audit string when PersistToRegistry is used.
|
|
||||||
.PARAMETER RegistryBasePath
|
|
||||||
Registry path for persisting keys. Defaults to HKLM:\SOFTWARE\CentraStage.
|
|
||||||
.EXAMPLE
|
|
||||||
# System drive only (default)
|
|
||||||
Ensure-RealBitLockerKey
|
|
||||||
.EXAMPLE
|
|
||||||
# All fixed disks
|
|
||||||
Ensure-RealBitLockerKey -AllDisks
|
|
||||||
.EXAMPLE
|
|
||||||
# Full reencrypt on all disks and write audit to UDF2
|
|
||||||
Ensure-RealBitLockerKey -AllDisks -FullReencrypt -PersistToRegistry -UDFNumber 2
|
|
||||||
#>
|
|
||||||
function Ensure-RealBitLockerKey {
|
function Ensure-RealBitLockerKey {
|
||||||
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='Medium')]
|
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='Medium')]
|
||||||
param(
|
param(
|
||||||
@@ -53,13 +21,16 @@ function Ensure-RealBitLockerKey {
|
|||||||
if ($AllDisks) {
|
if ($AllDisks) {
|
||||||
$targets = Get-WmiObject -Query "SELECT DeviceID FROM Win32_LogicalDisk WHERE DriveType=3" |
|
$targets = Get-WmiObject -Query "SELECT DeviceID FROM Win32_LogicalDisk WHERE DriveType=3" |
|
||||||
Select-Object -ExpandProperty DeviceID
|
Select-Object -ExpandProperty DeviceID
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
$targets = @($MountPoint)
|
$targets = @($MountPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
$results = @()
|
$results = @()
|
||||||
foreach ($d in $targets) {
|
foreach ($d in $targets) {
|
||||||
if (-not $PSCmdlet.ShouldProcess("Volume $d","Ensure recovery key")) { continue }
|
if (-not $PSCmdlet.ShouldProcess("Volume $d","Ensure recovery key")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
# Key regex
|
# Key regex
|
||||||
$keyPattern = '^\d{6}(-\d{6}){7}$'
|
$keyPattern = '^\d{6}(-\d{6}){7}$'
|
||||||
@@ -69,67 +40,109 @@ function Ensure-RealBitLockerKey {
|
|||||||
Select-Object -Last 1 -ExpandProperty RecoveryPassword
|
Select-Object -Last 1 -ExpandProperty RecoveryPassword
|
||||||
|
|
||||||
if ($curKey -match $keyPattern) {
|
if ($curKey -match $keyPattern) {
|
||||||
$results += [PSCustomObject]@{MountPoint=$d;Action='None';RecoveryKey=$curKey;AuditString=$null}
|
$results += [PSCustomObject]@{
|
||||||
|
MountPoint = $d
|
||||||
|
Action = 'None'
|
||||||
|
RecoveryKey = $curKey
|
||||||
|
AuditString = $null
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
# Provision new key
|
# Provision new key
|
||||||
if ($FullReencrypt) {
|
if ($FullReencrypt) {
|
||||||
Disable-BitLocker -MountPoint $d -ErrorAction Stop
|
Disable-BitLocker -MountPoint $d -ErrorAction Stop
|
||||||
while ((Get-BitLockerVolume -MountPoint $d).VolumeStatus -ne 'FullyDecrypted') { Start-Sleep 15 }
|
while ((Get-BitLockerVolume -MountPoint $d).VolumeStatus -ne 'FullyDecrypted') {
|
||||||
Enable-BitLocker -MountPoint $d -UsedSpaceOnly -SkipHardwareTest -TpmProtector -RecoveryPasswordProtector -ErrorAction Stop
|
Start-Sleep 15
|
||||||
|
}
|
||||||
|
Enable-BitLocker `
|
||||||
|
-MountPoint $d `
|
||||||
|
-UsedSpaceOnly `
|
||||||
|
-SkipHardwareTest `
|
||||||
|
-TpmProtector `
|
||||||
|
-RecoveryPasswordProtector `
|
||||||
|
-ErrorAction Stop
|
||||||
$action = 'FullReencrypt'
|
$action = 'FullReencrypt'
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
$vol.KeyProtector |
|
$vol.KeyProtector |
|
||||||
Where KeyProtectorType -eq 'RecoveryPassword' |
|
Where-Object KeyProtectorType -eq 'RecoveryPassword' |
|
||||||
ForEach-Object { Remove-BitLockerKeyProtector -MountPoint $d -KeyProtectorId $_.KeyProtectorId }
|
ForEach-Object { Remove-BitLockerKeyProtector -MountPoint $d -KeyProtectorId $_.KeyProtectorId }
|
||||||
Add-BitLockerKeyProtector -MountPoint $d -RecoveryPasswordProtector -ErrorAction Stop
|
Add-BitLockerKeyProtector -MountPoint $d -RecoveryPasswordProtector -ErrorAction Stop
|
||||||
$action = 'AddProtector'
|
$action = 'AddProtector'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get new key
|
# Grab the newly provisioned key
|
||||||
$newKey = (Get-BitLockerVolume -MountPoint $d).KeyProtector |
|
$newKey = (Get-BitLockerVolume -MountPoint $d).KeyProtector |
|
||||||
Where-Object KeyProtectorType -eq 'RecoveryPassword' |
|
Where-Object KeyProtectorType -eq 'RecoveryPassword' |
|
||||||
Select-Object -Last 1 -ExpandProperty RecoveryPassword
|
Select-Object -Last 1 -ExpandProperty RecoveryPassword
|
||||||
|
|
||||||
$auditString = $null
|
$auditString = $null
|
||||||
if ($PersistToRegistry) {
|
if ($PersistToRegistry) {
|
||||||
# Build audit
|
|
||||||
# Powershell 7
|
|
||||||
#$alert = $env:usrAlert -match 'true' ? 'Notice' : 'Status'
|
|
||||||
|
|
||||||
# powershell 5
|
# -- Replace PowerShell 7 ternary with if/else --
|
||||||
if ($env:usrAlert -match 'true') {
|
if ($env:usrAlert -match 'true') {
|
||||||
$alert = 'Notice'
|
$alert = 'Notice'
|
||||||
} else {
|
}
|
||||||
$alert = 'Status ...'
|
else {
|
||||||
|
$alert = 'Status'
|
||||||
}
|
}
|
||||||
|
|
||||||
$t = Get-Tpm; $mask = (if ($t.TpmPresent) { 1 } else { 0 }) + (if ($t.TpmReady) { 6 } else { 0 })# PoSH 7 $mask = ($t.TpmPresent?1:0) + ($t.TpmReady?6:0)
|
# -- Build TPM mask --
|
||||||
|
$t = Get-Tpm
|
||||||
|
$mask = (if ($t.TpmPresent) { 1 } else { 0 }) + `
|
||||||
|
(if ($t.TpmReady) { 6 } else { 0 })
|
||||||
|
|
||||||
|
# Capture and discard the switch output
|
||||||
|
switch ($mask) {
|
||||||
|
0 { $state = 'Absent'; break }
|
||||||
|
1 { $state = 'Disabled'; break }
|
||||||
|
3 { $state = 'Deactivated'; break }
|
||||||
|
7 { $state = 'Active'; break }
|
||||||
|
Default { $state = 'Error' }
|
||||||
|
}
|
||||||
|
$null = $state
|
||||||
|
|
||||||
switch ($mask) {0{'Absent'};1{'Disabled'};3{'Deactivated'};7{'Active'};default{'Error'}} | Out-Null
|
# -- Replace PowerShell 7 “? :” for drives list --
|
||||||
$drives=$AllDisks?($targets):(,$d)
|
if ($AllDisks) {
|
||||||
$diskStatus=''
|
$drives = $targets
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$drives = ,$d
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build disk-status string
|
||||||
|
$diskStatus = ''
|
||||||
foreach ($x in $drives) {
|
foreach ($x in $drives) {
|
||||||
$stat=(Get-BitLockerVolume -MountPoint $x).VolumeStatus
|
$stat = (Get-BitLockerVolume -MountPoint $x).VolumeStatus
|
||||||
switch ($stat) {
|
switch ($stat) {
|
||||||
'FullyEncrypted' {$code='ENCPASS'}
|
'FullyEncrypted' { $code = 'ENCPASS'; break }
|
||||||
'EncryptionInProgress' {$code='ENCPASS'}
|
'EncryptionInProgress' { $code = 'ENCPASS'; break }
|
||||||
'DecryptionInProgress' {$code='ENCFAIL'}
|
'DecryptionInProgress' { $code = 'ENCFAIL'; break }
|
||||||
'EncryptionSuspended' {$code='ENCFAIL'}
|
'EncryptionSuspended' { $code = 'ENCFAIL'; break }
|
||||||
'DecryptionSuspended' {$code='ENCFAIL'}
|
'DecryptionSuspended' { $code = 'ENCFAIL'; break }
|
||||||
'EncryptingWipeInProgress'{$code='ENCFAIL'}
|
'EncryptingWipeInProgress' { $code = 'ENCFAIL'; break }
|
||||||
default {$code='ENCFAIL'}
|
Default { $code = 'ENCFAIL' }
|
||||||
}
|
}
|
||||||
$diskStatus += "/$x`$code"
|
$diskStatus += "/$x`$$code"
|
||||||
}
|
}
|
||||||
$diskStatus = $diskStatus.TrimStart('/')
|
$diskStatus = $diskStatus.TrimStart('/')
|
||||||
$auditString = "TPM: $mask | DISKS: $diskStatus | RECOVERY: $newKey"
|
$auditString = "TPM: $mask | DISKS: $diskStatus | RECOVERY: $newKey"
|
||||||
New-ItemProperty -Path $RegistryBasePath -Name "Custom$UDFNumber" -Value $auditString -Force | Out-Null
|
|
||||||
|
# Persist to registry/UDF
|
||||||
|
New-ItemProperty `
|
||||||
|
-Path $RegistryBasePath `
|
||||||
|
-Name "Custom$UDFNumber" `
|
||||||
|
-Value $auditString `
|
||||||
|
-Force | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
$results += [PSCustomObject]@{MountPoint=$d;Action=$action;RecoveryKey=$newKey;AuditString=$auditString}
|
$results += [PSCustomObject]@{
|
||||||
|
MountPoint = $d
|
||||||
|
Action = $action
|
||||||
|
RecoveryKey = $newKey
|
||||||
|
AuditString = $auditString
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $results
|
return $results
|
||||||
|
|||||||
Reference in New Issue
Block a user