NAVANEM
BitLocker & Encryption[PowerShell]medium6 min read · jun 13, 2026 · 05:12 utc

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-ADObject instead 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-RecoveryInformation objects
  • Works with pipeline input from Get-ADComputer to 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:

  1. Named computer lookup — specify one or more computer names directly
  2. Pipeline input — pipe results from Get-ADComputer to query an entire OU
  3. 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:

powershell
.\Get-ADBitLockerRecovery.ps1 -ComputerName "WORKSTATION01"

To search by the password ID shown on a locked screen:

powershell
.\Get-ADBitLockerRecovery.ps1 -PasswordId "A1B2C3D4"

For bulk queries across an organizational unit:

powershell
Get-ADComputer -Filter * -SearchBase "OU=Laptops,DC=contoso,DC=com" | .\Get-ADBitLockerRecovery.ps1

The 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-ADComputer combined with Get-ADObject -LDAPFilter '(objectClass=msFVE-RecoveryInformation)' replaces hand-rolled ADSI searchers
  • Native pipeline support via ValueFromPipeline enables bulk operations
  • -Server parameter works natively for domain controller targeting
  • [ValidatePattern] enforces correct password ID format before queries run
  • Password ID extraction uses clean [Guid][Byte[]] casting from msFVE-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:

  1. Run the script as a Domain Admin or similarly privileged account
  2. Delegate explicit read permissions on msFVE-RecoveryInformation objects to a security group
  3. 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

powershell-get-ad-bitlocker-recovery.ps1
#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.

#PowerShell#Active Directory#windows#Security#Automation

Related topics