A powershell script to enforce bitlocker on remote laptops should run locally through endpoint management, verify that a TPM is ready, encrypt the operating-system drive with XTS-AES 256, create a recovery-password protector, and confirm that the recovery key is escrowed in Microsoft Entra ID. This approach gives a compliance team repeatable technical evidence for ISO 27001 control 6.7, while routing unsupported devices and key-escrow failures into an exception workflow rather than silently marking them compliant.
For an enterprise deal, the useful question is not whether BitLocker exists somewhere in a policy document. The buyer will want proof that remote devices protecting company information are encrypted, recoverable, monitored, and handled when enforcement fails. ISO 27001 practice 6.7 requires security measures for personnel working remotely to protect information accessed, processed, or stored outside organizational premises.[1] Device encryption is not the entire remote-working control, but it is a concrete and auditable safeguard.
What can a powershell script to enforce bitlocker on remote laptops automate, and what still needs governance?
Automation can make encryption status measurable across a distributed Windows fleet. It can also reduce the risky gap between a laptop being issued and a security team discovering months later that its disk is unencrypted. For remote endpoints, deploy the script through Microsoft Intune Remediations, an RMM platform, or another device-management agent that executes locally as SYSTEM. Do not depend on WinRM access to home networks or on a user being connected to the corporate VPN.
| Automated activity | What the endpoint process does | Evidence retained |
|---|---|---|
| Eligibility validation | Checks Windows edition, OS volume, TPM presence, and TPM readiness. | Script output and Intune remediation status. |
| Encryption enforcement | Enables BitLocker with XTS-AES 256 and a TPM protector on C:. | Get-BitLockerVolume status and protector inventory. |
| Recovery preparation | Adds a recovery-password protector and backs it up to Microsoft Entra ID. | Recovery-key escrow record and device identifier. |
| Drift correction | Resumes suspended protection and adds missing protectors. | Remediation result and follow-up compliance state. |
| Exception handling | Returns a failure code for no TPM, unavailable escrow, or unsupported configuration. | Ticket, approved risk acceptance, or replacement-device record. |
Automation cannot decide whether a user has a legitimate business need for an exception, whether an executive can keep an unsupported personal device, or whether recovery-key access is appropriately restricted. Your ISO 27001 evidence package should therefore pair technical results with a documented remote-working policy, an exception approval process, and periodic review of who can retrieve recovery keys.
How do you deploy the BitLocker remote-laptop enforcement script?
The following PowerShell is intended for Microsoft Entra ID-joined Windows 10 or Windows 11 devices managed by Intune. It deliberately requires a TPM and Entra recovery-key escrow; those are sensible baseline conditions for corporate remote laptops. Test it first against a pilot ring of IT-owned devices, including an already encrypted laptop, a freshly provisioned laptop, and a device with a suspended protector.
#requires -RunAsAdministrator
# Run as SYSTEM through Microsoft Intune Remediations or an RMM agent.
# Enforces BitLocker on C: and escrows recovery-password protectors in Entra ID.
$ErrorActionPreference = 'Stop'
$MountPoint = 'C:'
$LogDirectory = 'C:\ProgramData\Company\Security'
$LogFile = Join-Path $LogDirectory 'BitLocker-Enforcement.log'
New-Item -Path $LogDirectory -ItemType Directory -Force | Out-Null
function Write-RunLog {
param([string]$Message)
$line = '{0} {1}' -f (Get-Date -Format 'yyyy-MM-ddTHH:mm:ssK'), $Message
$line | Tee-Object -FilePath $LogFile -Append
}
try {
$tpm = Get-Tpm
if (-not $tpm.TpmPresent) {
throw 'TPM is not present. Route this device to the approved exception workflow.'
}
if (-not $tpm.TpmReady) {
throw 'TPM is present but not ready. TPM ownership or firmware remediation is required.'
}
$dsreg = (& dsregcmd.exe /status | Out-String)
if ($dsreg -notmatch 'AzureAdJoined\s*:\s*YES') {
throw 'Device is not Microsoft Entra ID joined; recovery-key escrow cannot be verified.'
}
$volume = Get-BitLockerVolume -MountPoint $MountPoint
if ($volume.VolumeStatus -eq 'FullyDecrypted') {
Write-RunLog 'C: is unencrypted. Starting BitLocker with XTS-AES 256 and TPM protector.'
Enable-BitLocker -MountPoint $MountPoint `
-EncryptionMethod XtsAes256 `
-UsedSpaceOnly `
-TpmProtector `
-SkipHardwareTest
$volume = Get-BitLockerVolume -MountPoint $MountPoint
}
if ($volume.ProtectionStatus -ne 'On') {
Write-RunLog 'BitLocker protection is suspended. Resuming protection.'
Resume-BitLocker -MountPoint $MountPoint
$volume = Get-BitLockerVolume -MountPoint $MountPoint
}
$tpmProtector = @($volume.KeyProtector | Where-Object {
$_.KeyProtectorType -eq 'Tpm'
})
if ($tpmProtector.Count -eq 0) {
Write-RunLog 'TPM protector is missing. Adding TPM protector.'
Add-BitLockerKeyProtector -MountPoint $MountPoint -TpmProtector | Out-Null
$volume = Get-BitLockerVolume -MountPoint $MountPoint
}
$recoveryProtector = @($volume.KeyProtector | Where-Object {
$_.KeyProtectorType -eq 'RecoveryPassword'
})
if ($recoveryProtector.Count -eq 0) {
Write-RunLog 'Recovery-password protector is missing. Creating one.'
Add-BitLockerKeyProtector -MountPoint $MountPoint -RecoveryPasswordProtector | Out-Null
$volume = Get-BitLockerVolume -MountPoint $MountPoint
$recoveryProtector = @($volume.KeyProtector | Where-Object {
$_.KeyProtectorType -eq 'RecoveryPassword'
})
}
foreach ($protector in $recoveryProtector) {
BackupToAAD-BitLockerKeyProtector `
-MountPoint $MountPoint `
-KeyProtectorId $protector.KeyProtectorId
}
$finalVolume = Get-BitLockerVolume -MountPoint $MountPoint
$result = [ordered]@{
ComputerName = $env:COMPUTERNAME
MountPoint = $MountPoint
VolumeStatus = $finalVolume.VolumeStatus.ToString()
ProtectionStatus = $finalVolume.ProtectionStatus.ToString()
EncryptionMethod = $finalVolume.EncryptionMethod.ToString()
RecoveryProtectors = @($finalVolume.KeyProtector | Where-Object {
$_.KeyProtectorType -eq 'RecoveryPassword'
}).Count
Result = 'CompliantOrEncrypting'
} | ConvertTo-Json -Compress
Write-RunLog $result
Write-Output $result
exit 0
}
catch {
$failure = [ordered]@{
ComputerName = $env:COMPUTERNAME
Result = 'Failed'
Error = $_.Exception.Message
} | ConvertTo-Json -Compress
Write-RunLog $failure
Write-Error $failure
exit 1
}
This remote BitLocker enforcement script uses -UsedSpaceOnly because it is appropriate for newly provisioned corporate devices and typically completes sooner. For laptops already in service, confirm with counsel, your security architect, and your disk-reuse policy whether full-disk encryption is required instead. Encryption in progress is an expected transitional status; protection must remain enabled and be reassessed at the next scheduled run.
How should the script be integrated into scheduled jobs and CI/CD?
For a mid-market organization closing an ISO 27001-driven deal, Intune Remediations is usually the cleanest operational route: use a detection script to identify devices whose OS volume is not fully encrypted, whose protection is off, or whose recovery protector is missing; use the remediation script above to correct the condition. Assign it to a dynamic group containing corporate Windows laptops, run it daily, and retain the remediation export with your control evidence.
Keep the production script in source control even if Intune is the execution platform. A small GitHub Actions workflow prevents an unreviewed syntax error or unsafe edit from reaching hundreds of remote devices.
name: Validate BitLocker Remediation Script
on:
pull_request:
paths:
- 'scripts/Enforce-BitLocker.ps1'
jobs:
powershell-quality-check:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Install PSScriptAnalyzer
shell: pwsh
run: Install-Module PSScriptAnalyzer -Force -Scope CurrentUser
- name: Fail on PowerShell quality findings
shell: pwsh
run: |
$results = Invoke-ScriptAnalyzer `
-Path scripts/Enforce-BitLocker.ps1 `
-Severity Error,Warning
if ($results) {
$results | Format-Table -AutoSize
throw "PSScriptAnalyzer reported findings."
}
- name: Confirm script parses
shell: pwsh
run: |
[void][scriptblock]::Create(
(Get-Content scripts/Enforce-BitLocker.ps1 -Raw)
)
Require security approval for pull requests that change encryption method, key protector types, exit codes, or escrow behavior. That review record is valuable evidence that the control is managed rather than merely configured once.
What monitoring and alerting hooks prove remote-device encryption is working?
The endpoint output alone is not enough. Monitor fleet state in Intune, verify that recovery keys appear in Microsoft Entra ID, and create alerts around failed remediation rather than alerting only when a laptop is visibly unencrypted.
| Signal | Alert threshold | Compliance response |
|---|---|---|
| Intune remediation failure | Any failure on an assigned corporate laptop | Create a service ticket within one business day. |
| BitLocker protection suspended | Protection remains off after the next daily run | Escalate to endpoint engineering and restrict access if unresolved. |
| Recovery key not escrowed | Zero Entra recovery keys after successful encryption | Mark device noncompliant and investigate join or permissions state. |
| Encryption still in progress | More than 72 hours after remediation began | Check disk health, power availability, and user connectivity. |
Export a monthly report showing device name, primary user, encryption method, protection status, recovery-key presence, last remediation date, and exception reference. This creates practical evidence for ISO 27001 6.7 without exposing actual recovery passwords in tickets, spreadsheets, or audit folders.
How should failure modes be handled without creating remote-work exceptions by accident?
A reliable PowerShell BitLocker deployment treats failure as a workflow trigger, not as a reason to weaken the control. The script should never print recovery passwords, disable encryption to “fix” a problem, or substitute a user-created password protector without an approved recovery process.
- No TPM or TPM not ready: send the device to hardware support or a documented exception path; do not silently continue with an unmanaged protector.
- Device is not Entra joined: verify whether it is an approved AD DS-managed device with a separate escrow policy, or block it from the managed remote-work population.
- Encryption is paused or slow: resume protection, preserve the device’s existing encryption state, and investigate battery, disk, firmware, or endpoint-agent issues.
- Recovery escrow fails: retain encryption if it is already active, but classify the device as noncompliant until a recoverable key is confirmed.
- User is offline: let the local management agent retry on the next check-in; avoid attempting direct remote administration over consumer networks.
Before sharing your ISO 27001 evidence with the prospective customer, pilot this automation, document the exception owner and remediation SLA, and export a current report proving that every in-scope remote laptop is encrypted, protected, and recoverable.