BitLocker Recovery Keys: Get Them from Active Directory
Retrieve BitLocker recovery keys from Active Directory by computer name or 8-character password ID. Uses Get-ADObject with the AD module.
by Emanuel De Almeida
TL;DR
- Retrieve any BitLocker recovery key escrowed in Active Directory using computer name or the 8-character password ID shown on the recovery screen
- Script uses the ActiveDirectory module with
Get-ADObjectinstead of legacy ADSI, cutting code length dramatically - Returns computer name, DN, TPM info presence, escrow date, password ID, and full recovery password
- Requires RSAT and delegated permissions to read
msFVE-RecoveryInformationobjects - Works with pipeline input from
Get-ADComputerto query entire OUs at once
Why Does Fast BitLocker Recovery Key Access Matter?
When a BitLocker-encrypted machine prompts for its recovery key, you need that key immediately. Downtime costs money. User frustration compounds. If your organization escrows BitLocker recovery keys to Active Directory, the data sits on the computer object, waiting for retrieval.
Ransomware appeared in 44% of all data breaches in 2025, up from 32% the previous year, making reliable recovery capabilities essential for any IT team according to Infosecurity Magazine. BitLocker protects against data theft from lost or stolen devices, but that protection becomes a liability when legitimate users get locked out.
This script solves that problem. It reads recovery keys back from AD by computer name or by the 8-character password ID displayed on the recovery screen.
What Does This Script Do?
The script queries Active Directory for BitLocker recovery information and returns structured data for each recovery object found. You get the computer name, distinguished name, TPM recovery presence, escrow date, password ID, and the full 48-digit recovery password.
Three lookup methods work out of the box:
- Named computer lookup — specify one or more computer names directly
- Pipeline input — pipe results from
Get-ADComputerto query an entire OU - Password ID search — enter the 8-character ID a user reads to you over the phone
Microsoft notes that BitLocker addresses threats of data theft or exposure from lost, stolen, or inappropriately decommissioned devices. This script ensures you can recover those protected systems when needed.
How Do I Use the Script?
Save the script as Get-ADBitLockerRecovery.ps1 and run it from any machine with the ActiveDirectory module installed. Here is the basic syntax for computer name lookup:
.\Get-ADBitLockerRecovery.ps1 -ComputerName "WORKSTATION01"To search by the password ID shown on a locked screen:
.\Get-ADBitLockerRecovery.ps1 -PasswordId "A1B2C3D4"For bulk queries across an organizational unit:
Get-ADComputer -Filter * -SearchBase "OU=Laptops,DC=contoso,DC=com" | .\Get-ADBitLockerRecovery.ps1The script supports the -Server parameter for targeting specific domain controllers. This proves useful in multi-domain environments or when troubleshooting replication issues. If you are dealing with Outlook password prompts from Exchange auth loops, similar AD connectivity troubleshooting applies.
What Did I Rebuild From the Original?
The original script was a lengthy raw-ADSI implementation. It juggled COM Pathname objects and DirectorySearcher by hand. Maintenance was painful. Readability suffered. I rebuilt it on the ActiveDirectory module for clarity and supportability.
Key changes in the new version:
Get-ADComputercombined withGet-ADObject -LDAPFilter '(objectClass=msFVE-RecoveryInformation)'replaces hand-rolled ADSI searchers- Native pipeline support via
ValueFromPipelineenables bulk operations -Serverparameter works natively for domain controller targeting[ValidatePattern]enforces correct password ID format before queries run- Password ID extraction uses clean
[Guid][Byte[]]casting frommsFVE-RecoveryGuid
The result is a fraction of the original length. Reading and modifying it takes minutes, not hours.
Aspect | Old ADSI Approach | New AD Module Approach |
|---|---|---|
Lines of code | ~150+ | ~40 |
Dependencies | None (bare domain-joined box) | RSAT / ActiveDirectory module |
Readability | Low (COM objects, manual binding) | High (native cmdlets, pipeline) |
Maintenance | Difficult | Straightforward |
Pipeline support | Manual implementation | Built-in via ValueFromPipeline |
Tradeoff: The new version requires RSAT or the AD module. The pure-ADSI original ran on any domain-joined box without additional tools. If you specifically need the no-RSAT version for deployment to machines without management tools, that variant remains available.
What Permissions Are Required to Read BitLocker Keys?
Reading recovery passwords is a privileged operation. Standard domain users cannot access this data by design. If RecoveryPassword returns empty in your results, your account can see the object but lacks permission to read the secret itself.
To resolve permission issues:
- Run the script as a Domain Admin or similarly privileged account
- Delegate explicit read permissions on
msFVE-RecoveryInformationobjects to a security group - Add your helpdesk or recovery team to that delegated group
The msFVE-RecoveryInformation object class stores all BitLocker recovery data in AD. Delegation at the OU level allows granular control. Your desktop support team might need access to workstation keys but not server keys.
Note that Microsoft MBAM is deprecated, with Entra ID and Intune now serving as the primary control plane for BitLocker recovery in modern environments. AD DS remains the fallback for on-premises or hybrid deployments.
Are There Security Considerations?
BitLocker recovery key access should be logged and audited. Anyone who retrieves a key can potentially access encrypted data on that device. Enable auditing on your BitLocker recovery containers in AD.
A BitLocker bypass vulnerability, CVE-2026-50507, affecting Windows 10, Windows 11, and Windows Server versions through 2025 was patched in June 2026 updates according to Cybersecurity News. Keep systems current. The June 2026 Patch Tuesday addressed three zero-days including this BitLocker flaw.
The global average cost of a data breach reached $4.44 million in 2025, with encryption listed among the top three factors reducing breach costs per IBM. Proper BitLocker key management supports both security and recovery objectives.
Does This Work Without RSAT Installed?
No. This rebuilt version requires the ActiveDirectory PowerShell module, which installs with RSAT. The module provides Get-ADComputer and Get-ADObject cmdlets that the script depends on.
If you need recovery key retrieval on machines without RSAT, two options exist:
- Install RSAT: On Windows 10/11, add it via Settings > Apps > Optional Features > RSAT: Active Directory tools
- Use the legacy ADSI version: The original script works on bare domain-joined machines without additional components
For environments managing Intune Secure Boot certificate errors, you likely already have RSAT deployed on admin workstations. The module dependency should not present obstacles.
Notes and Attribution
Save the script as Get-ADBitLockerRecovery.ps1 in your tools directory. Based on the well-known BitLocker AD recovery script by Bill Stewart, rebuilt for modern PowerShell practices.
Test in a lab environment before production use. Verify your delegation model works correctly and that results match expected recovery keys. The Windows 11 KB5094126 June 2026 update includes cumulative fixes that may affect AD communication in some configurations.
The script
#Requires -Version 5.1
#Requires -Modules ActiveDirectory
<#
.SYNOPSIS
Gets BitLocker recovery information escrowed in Active Directory, by computer
name or by the 8-character recovery password ID.
.DESCRIPTION
Reads msFVE-RecoveryInformation objects stored under AD computer accounts and
returns the recovery password, password ID, escrow date and whether TPM
recovery information is present. Look up named computers, pipe in
Get-ADComputer results for a whole OU, or search by the password ID a user
reads from the BitLocker recovery screen.
This is a refactor of the classic raw-ADSI script onto the ActiveDirectory
module: far less code, native pipeline and -Server support. (It therefore
needs RSAT / the AD module, unlike the pure-ADSI original.)
Reading recovery passwords is privileged. If RecoveryPassword comes back
empty, your account can see the object but not the secret: rerun as, or
delegate to, an account with the right to read msFVE-RecoveryInformation.
.PARAMETER Name
One or more computer names (no wildcards).
.PARAMETER PasswordID
The first 8 characters (0-9, A-F) of a recovery password ID.
.PARAMETER Server
A specific domain controller to query.
.EXAMPLE
.\Get-ADBitLockerRecovery.ps1 PC001,PC002
.EXAMPLE
Get-ADComputer -Filter * -SearchBase 'OU=Laptops,DC=corp,DC=local' | .\Get-ADBitLockerRecovery.ps1
.EXAMPLE
.\Get-ADBitLockerRecovery.ps1 -PasswordID 1A2B3C4D
.NOTES
Author : Emanuel De Almeida - https://www.navanem.com
Refactored from the BitLocker AD recovery script by Bill Stewart (windowsitpro).
#>
[CmdletBinding(DefaultParameterSetName = 'Name')]
param(
[Parameter(ParameterSetName = 'Name', Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[Alias('ComputerName')]
[string[]] $Name,
[Parameter(ParameterSetName = 'PasswordID', Mandatory)]
[ValidatePattern('^[0-9A-Fa-f]{8}$')]
[string] $PasswordID,
[string] $Server
)
begin {
$common = @{}
if ($Server) { $common['Server'] = $Server }
$fveProps = 'msFVE-RecoveryPassword', 'msFVE-RecoveryGuid', 'whenCreated'
function Get-PasswordIdFromGuid {
param($GuidBytes)
if (-not $GuidBytes) { return $null }
([Guid][Byte[]]$GuidBytes).Guid.Split('-')[0].ToUpper()
}
# Emits one row per recovery object found under a computer.
function Get-RecoveryForComputer {
param($Computer)
$tpm = [bool]($Computer.'msTPM-OwnerInformation' -or $Computer.'msTPM-TpmInformationForComputer')
$found = $false
Get-ADObject -SearchBase $Computer.DistinguishedName -SearchScope Subtree `
-LDAPFilter '(objectClass=msFVE-RecoveryInformation)' -Properties $fveProps @common |
ForEach-Object {
$found = $true
[pscustomobject]@{
Computer = $Computer.Name
DistinguishedName = $Computer.DistinguishedName
TPMRecoveryInformation = $tpm
Date = $_.whenCreated
PasswordID = Get-PasswordIdFromGuid $_.'msFVE-RecoveryGuid'
RecoveryPassword = $_.'msFVE-RecoveryPassword'
}
}
if (-not $found) {
[pscustomobject]@{
Computer = $Computer.Name
DistinguishedName = $Computer.DistinguishedName
TPMRecoveryInformation = $tpm
Date = $null
PasswordID = $null
RecoveryPassword = $null
}
}
}
}
process {
$tpmProps = 'msTPM-OwnerInformation', 'msTPM-TpmInformationForComputer'
if ($PSCmdlet.ParameterSetName -eq 'Name') {
foreach ($n in $Name) {
$c = Get-ADComputer -Identity $n -Properties $tpmProps @common -ErrorAction SilentlyContinue
if (-not $c) { Write-Error "Computer '$n' not found." -Category ObjectNotFound; continue }
Get-RecoveryForComputer -Computer $c
}
}
else {
# Search every recovery object whose ID starts with the supplied 8 chars.
$matches = Get-ADObject -LDAPFilter "(&(objectClass=msFVE-RecoveryInformation)(name=*{$PasswordID-*}))" -Properties $fveProps @common
foreach ($m in $matches) {
$parentDN = ($m.DistinguishedName -split ',', 2)[1]
$c = Get-ADComputer -Identity $parentDN -Properties $tpmProps @common -ErrorAction SilentlyContinue
if (-not $c) { continue }
$tpm = [bool]($c.'msTPM-OwnerInformation' -or $c.'msTPM-TpmInformationForComputer')
[pscustomobject]@{
Computer = $c.Name
DistinguishedName = $c.DistinguishedName
TPMRecoveryInformation = $tpm
Date = $m.whenCreated
PasswordID = Get-PasswordIdFromGuid $m.'msFVE-RecoveryGuid'
RecoveryPassword = $m.'msFVE-RecoveryPassword'
}
}
}
}
Review before running. Test in a non-production environment first.