Lock on green wall or fence, zoomed in

Overview

This PowerShell script automates the process of enabling and managing BitLocker encryption on a Windows system, ensuring that recovery keys are safely stored in Microsoft Azure Active Directory (Azure AD) via Microsoft Entra. The script performs several critical checks and operations, including verifying the system’s readiness for BitLocker and securing the recovery key.

Features of the Script

  1. Checks for BitLocker and TPM Availability
    • Ensures that BitLocker is installed and that a TPM chip is present, ready, and enabled.
    • Verifies if the system already has BitLocker protection with recovery and TPM key protectors.
  2. BitLocker Recovery Key Management
    • Creates a recovery key if one does not exist.
    • Uploads the recovery key to Azure AD for added security.
  3. BitLocker Activation
    • Activates BitLocker on the C:\ drive using the system’s TPM module if it is not already enabled.
    • Confirms encryption status and informs the user if a system restart is required.
  4. Test Mode and Confirmation
    • Runs in test mode by default to simulate actions without making changes. Use the -run switch to execute changes.
    • Offers optional -force mode to bypass confirmation prompts.

Prerequisites

Before running the script, ensure the following:

  1. Run as administrator
    • The script needs to be run in an administrator PowerShell session or by right-clicking it and selection “Run as administrator
  2. Azure AD Sync
    • Your computers should be synced with Azure AD using Microsoft Entra Connect. While the script works without syncing, recovery keys uploaded to Azure before syncing might be lost when the sync is eventually established. Syncing your systems beforehand prevents this issue.
  3. BitLocker Installed
    • Verify that BitLocker is installed on your system, it should come by default on (at least) Windows 10 and 11
  4. TPM Chip Enabled
    • Ensure the TPM module is active and ready. If TPM is disabled in BIOS, refer to your computer or motherboard manual for instructions.

How to Use the Script

  1. Download and Review the Script
    Copy the script provided below into a .ps1 file. Open the file in a text editor to review and understand the code.
  2. Run in Test Mode (Default)
    Test mode simulates the script’s operations without making changes
.\YourScriptName.ps1
PowerShell
  1. Run in Execution Mode
    Use the -run switch to apply changes and actually run the script’s commands
.\YourScriptName.ps1 -run
PowerShell
  1. Force Execution Without Prompts
    Include the -force switch to skip the prompt confirming if you want to encrypt the drive once a TPM has been identified
.\YourScriptName.ps1 -run -force
PowerShell

Key Checks Performed by the Script

  1. BitLocker Status
    • Ensures BitLocker is installed.
    • Checks if the drive is fully encrypted with TPM and a recovery key already configured.
  2. TPM Module Validation
    • Confirms the TPM module is present, enabled, and ready.
    • Provides guidance if TPM is disabled or missing.
  3. Recovery Key
    • Ensures a recovery key exists and uploads it to Azure AD.
  4. BitLocker Encryption
    • Activates BitLocker if protection is not already enabled.

Notes on Usage

  • Running as SYSTEM
    If certain commands fail due to permission issues, consider running the script as the SYSTEM user. Tools like PsExec can help achieve this. Search online for guides on using PsExec for running scripts as SYSTEM.
  • Test the Script
    Always test the script in a non-production environment to ensure it works as expected for your setup.
  • Understand the Script
    Modify the script as necessary to suit your needs. Ensure you understand its operation before running it in production.

Disclaimer

This script was created for personal use and might not be perfect. While every effort has been made to ensure it works as intended and to take into account as many encryption scenarios as possible, I cannot be held responsible for any issues that arise from its use. Please thoroughly test and validate the script before applying it to critical systems.


The Script

param (
    [switch]$run,
    [switch]$force
)

if (!$run) {
    Write-Host "`nThe script is running in ""test"" mode. Use the -run argument to execute the script for real.`n To run the script without confirmation after checking for the presence of a TPM, use the -force argument."
}

# Checking for the presence of BitLocker
if (-not (Get-Command -Name "Get-BitLockerVolume" -ErrorAction SilentlyContinue)) {
    Write-Host "BitLocker is not installed on this system. Please ensure that BitLocker is available before proceeding."
    exit
}

write-host "`n"
write-host "#################################################"
write-host "#    Initial checks for BitLocker activation    #"
write-host "#################################################"
Write-Host "This checks if BitLocker is already activated and configured, if so, the BitLocker key will be uploaded to Azure as a precaution, and the script will exit`n"

$bitlockerStatus = Get-BitLockerVolume -MountPoint "C:"
$recoveryPasswordExists = $bitlockerStatus.KeyProtector | Where-Object { $_.KeyProtectorType -eq 'RecoveryPassword' }
$tpmProtectorExists = $bitlockerStatus.KeyProtector | Where-Object { $_.KeyProtectorType -eq 'Tpm' }
if ($bitlockerStatus.VolumeStatus -eq "FullyEncrypted" -and $bitlockerStatus.EncryptionPercentage -eq 100 -and $bitlockerStatus.ProtectionStatus -eq "on" -and $recoveryPasswordExists -and $tpmProtectorExists)
{
    Write-Host "BitLocker is active, the drive is fully encrypted, a ""RecoveryPassword"" exists, and the drive is protected by TPM. The script will abort. However, the password will still be backed up to Azure under the computer account as a precaution. The upload will not change anything if the key already exists on Azure"
    if (!$run)
    {
        Write-Host "The following command would be executed to back up the BitLocker key to Azure: BackupToAAD-BitLockerKeyProtector -MountPoint $env:SystemDrive -KeyProtectorId $($keyProtectorId.KeyProtectorId)"
        pause
        exit
    }
    else
    {
        $keyProtectorId = (Get-BitLockerVolume -MountPoint $env:SystemDrive).KeyProtector | Where-Object { $_.KeyProtectorType -eq 'RecoveryPassword' } | Select-Object -First 1
        BackupToAAD-BitLockerKeyProtector -MountPoint $env:SystemDrive -KeyProtectorId $($keyProtectorId.KeyProtectorId)
        pause
        exit
    }
    
}

write-host "`n"
write-host "#################################################"
write-host "#    Checking for the presence of a TPM chip    #"
write-host "#################################################"

# Checking for the presence of a TPM chip on the PC
try {
    $tpm = Get-Tpm
    if ($tpm.TpmPresent -eq $false) {
        throw "No TPM chip found. Please ensure the PC has a TPM chip before proceeding. It might also be disabled in the BIOS, refer to your computer/motherboard manufacturer"
    } elseif ($tpm.TpmReady -eq $false -or $tpm.TpmEnabled -eq $false) {
        throw "The TPM chip is not ready or not enabled. Please ensure the TPM chip is ready and enabled before proceeding."
    } elseif ($tpm.TpmPresent -eq $true -and $tpm.TpmReady -eq $true -and $tpm.TpmEnabled -eq $true -and $force -eq $true){
        Write-Host "TPM found, ready, and active. Skipping confirmation since the ""-force"" argument was used.`nStarting BitLocker encryption."
    } else {
        Write-Host "TPM found, ready, and active. Do you want to proceed with enabling BitLocker? (Y/N)"
        $confirmation = Read-Host "Enter Y to continue or N to cancel"
        if ($confirmation -ne "Y") {
            throw "Operation canceled by the user."
        }
    }
} catch {
    Write-Host $_
    Read-Host "Press Enter to exit"
    exit
}

write-host "`n"
write-host "####################################################################"
write-host "#    Checking for the presence of a BitLocker recovery password    #"
write-host "####################################################################"
# Checking if a recovery key exists
Try {
if (-not $recoveryPasswordExists) {
    Write-Host "A Bitlocker recovery password was not found on this drive. Creating one..."
    if (!$run) {
        Write-Host "The following command would be executed: Add-BitLockerKeyProtector -MountPoint C: -RecoveryPasswordProtector"
    } else {
        Add-BitLockerKeyProtector -MountPoint C: -RecoveryPasswordProtector | Out-Null
        $recoveryPasswordExists = $true
        Write-Host "A BitLocker recovery password has been added."
    }
} else {
    Write-Host "A recovery password already exists. No need to add a new recovery key."
}
} catch {
    Write-Host "Failed to create the recovery password or confirm its existence: $_"
    exit
}

write-host "`n"
write-host "#################################################################"
write-host "#    Saving the BitLocker recovery password to AzureAD/Entra    #"
write-host "#################################################################"
# Backing up the key to Azure
try {
    $keyProtectorId = (Get-BitLockerVolume -MountPoint $env:SystemDrive).KeyProtector | Where-Object { $_.KeyProtectorType -eq 'RecoveryPassword' } | Select-Object -First 1
    Write-Host "Backing up Bitlocker recovery key to Microsoft Azure..."
    if (!$run) {
        Write-Host "The following command would be executed to back up the key to Azure as a precaution: BackupToAAD-BitLockerKeyProtector -MountPoint $env:SystemDrive -KeyProtectorId $($keyProtectorId.KeyProtectorId)"
    } else {
        BackupToAAD-BitLockerKeyProtector -MountPoint $env:SystemDrive -KeyProtectorId $($keyProtectorId.KeyProtectorId)
        Write-Host "The BitLocker recovery key has been backed up to Azure."
    }
} catch {
    Write-Host "Failed to back up the key to Azure: $_"
    exit
}


# Enabling BitLocker using the PC's TPM for the C:\ drive
try {
    write-host "`n"
    write-host "#################################################"
    write-host "#    Enabling BitLocker using the TPM module    #"
    write-host "#################################################"
    if ($bitlockerStatus.ProtectionStatus -eq "Off" -and -not $tpmProtectorExists -and $recoveryPasswordExists) {
        Write-Host "Since Bitlocker is disabled, no TPM protector exists and a recovery password was configured, we can now enable it"
        if (!$run) {
            Write-Host "The script is running in test mode, the following command would be executed: Enable-BitLocker -MountPoint C: -TpmProtector"
        } else {
            Enable-BitLocker -MountPoint C: -TpmProtector | Out-Null
            Write-Host "BitLocker protection has been enabled and will be managed by the TPM module."
            $tpmProtectorExists = $true
            $bitlockerEnabled = $True
        }
    } else {
        Write-Host "BitLocker is already enabled with TPM and recovery password protectors or there was an error and no password was created during the execution of this script."
    }
} catch {
    Write-Host "Error enabling BitLocker with TPM: $_"
}

# Running the manage-bde.exe command after enabling BitLocker
try {
    if ($bitlockerStatus.VolumeStatus -eq "FullyEncrypted" -and $bitlockerStatus.EncryptionPercentage -eq 100) {
        write-host "`n"
        write-host "############################"
        write-host "#    Enabling BitLocker    #"
        write-host "############################"
        Write-Host "This step is only necessary for PCs where the drive was already encrypted with BitLocker but not fully enabled, which is the case here"
        if (!$run) {
            Write-Host "The following command would be executed: manage-bde.exe -on C: | Out-Null"
        } else {
            manage-bde.exe -on C: | Out-Null
            Write-Host "Finalization of BitLocker activation completed."
        }
    }
} catch {
    Write-Host "Error executing the manage-bde.exe command: $_"
}

write-host "`n"
write-host "###########################"
write-host "#    BitLocker status     #"
write-host "###########################"
# Displaying restart message if BitLocker was enabled by the script
if ($bitlockerEnabled -eq $true -and $bitlockerStatus.VolumeStatus -eq "FullyEncrypted" -and $bitlockerStatus.EncryptionPercentage -eq 100 -and "(Get-BitLockerVolume).ProtectionStatus") {
    Write-Host "BitLocker has been enabled; a restart is not required."
}  elseif (!$run) {
    Write-host "The script is in test mode. A message would now indicate if a restart is required."
}  elseif ($bitlockerEnabled) {
    Write-host "A restart will be required for encryption to start. The system will verify the integrity of BitLocker decryption keys."
} else {
    Write-Host "BitLocker was already enabled or there was an issue, the recovery key was backed up to Azure as a precaution, and nothing else was done."
}

write-host "`nPlease run the following command ""Get-BitLockerVolume"" to get the current drive encryption status.`nPlease keep in mind that if ""Protection Status"" currently indicates ""Off"", a reboot might be required for encryption to start.`nIf an encrpyion is in progress, its status can be checked using ""(Get-BitLockerVolume).EncryptionPercentage"".`nIf ""Encryption Percentage"" is currently at 100 and ""Protection Status"" is set to ""On"", a reboot is not required."

pause
PowerShell

Verifying BitLocker Recovery Keys in Microsoft Entra (Azure AD)

To confirm that the BitLocker recovery keys have been successfully backed up to Microsoft Entra (formerly Azure AD), follow these steps:

  1. Log in to the Microsoft Entra admin center with an account that has the necessary admin privileges.
  2. Navigate to Devices:
    • In the left-hand menu, go to Identity > Devices > All devices.
  3. Search for the device:
    • Use the search bar to find the computer by name (matching the hostname of the machine where the script was executed).
  4. Make sure the recovery key is present:
    • Click on the device to open its details page.
    • Look for the section labeled BitLocker Keys on the left.
    • Ensure that at least one recovery key is present. You can view the key’s details, including the key ID and its upload date.

If the recovery keys are not visible:

  • Confirm that the script ran successfully and that the BackupToAAD-BitLockerKeyProtector command completed without errors. You can try launching that command separately if needed.
$keyProtectorId = (Get-BitLockerVolume -MountPoint $env:SystemDrive).KeyProtector | Where-Object { $_.KeyProtectorType -eq 'RecoveryPassword' } | Select-Object -First 1
BackupToAAD-BitLockerKeyProtector -MountPoint $env:SystemDrive -KeyProtectorId $($keyProtectorId.KeyProtectorId)
PowerShell
  • Verify that the device is properly hybrid Azure AD-joined or Azure AD-joined. On the device’s “Properties” page on Entra, there should be an option named “Join type” for which the status will be “Microsoft Entra hybrid joined“.
  • Ensure the user account running the script has sufficient permissions to write to Azure AD.

This process ensures your recovery keys are securely stored in Azure AD and can be accessed in case of emergencies.


Final Thoughts

This script simplifies BitLocker setup and management, particularly for systems synced with Azure AD. While it was created for personal use, it can help others streamline their BitLocker deployment. If you encounter issues, remember that adjusting execution context (e.g., running as SYSTEM) and thorough testing are key to successful implementation.

By Don

Leave a Reply

Your email address will not be published. Required fields are marked *