Skip to content

Van PowerShell tot Smart Home

Van PowerShell tot Smart Home

Primary Menu
  • Algemeen
  • Fotografie
  • Home Assistant
  • Microsoft
  • Azure
  • Powershell
Light/Dark Button
  • Home
  • Powershell – 🔐 BitLocker automatisch controleren en inschakelen met PowerShell
  • Intune
  • Powershell

Powershell – 🔐 BitLocker automatisch controleren en inschakelen met PowerShell

Vincent van Unen 2026-03-11 (Last updated: 2026-03-13) 10 minutes read
ChatGPT Image Mar 11, 2026, 01_55_02 PM

Beveiliging van endpoints is tegenwoordig geen luxe meer, maar een noodzaak. Gelukkig helpt Microsoft BitLocker daarbij door schijven te versleutelen. Maar wat als BitLocker nog niet actief is op een apparaat? Of als de recovery key niet goed is opgeslagen?

Met dit PowerShell-script wordt dat automatisch gecontroleerd én opgelost. 🚀

Het script controleert of BitLocker correct is ingesteld op een Windows-apparaat en voert waar nodig automatisch herstelacties uit. Ideaal voor beheer via Intune, beheerplatformen of handmatige deployments.


⚙️ Wat doet het script precies?

Het script voert meerdere controles uit om te garanderen dat BitLocker correct en veilig is geconfigureerd.

🔍 Controle op TPM

Het script controleert eerst of er een TPM-chip aanwezig en klaar voor gebruik is. Zonder TPM kan BitLocker namelijk niet op de standaard veilige manier worden ingezet.

🔐 BitLocker status controleren

Daarna wordt gecontroleerd of BitLocker al actief is op de systeemschijf.

Is BitLocker nog niet ingeschakeld?
Dan wordt de versleuteling automatisch gestart met XTS-AES-256 encryptie.

🗝 Recovery key controleren

Een recovery key is essentieel wanneer toegang tot het systeem verloren dreigt te gaan. Het script controleert daarom of een Recovery Password Protector aanwezig is.

Ontbreekt deze? Dan wordt hij automatisch toegevoegd.

☁️ Backup naar Entra ID / Azure AD

Voor centraal beheer wordt de recovery key automatisch geback-upt naar Entra ID (Azure AD). Hierdoor kunnen beheerders de sleutel altijd terugvinden wanneer dat nodig is.

📝 Logging en troubleshooting

Het script maakt uitgebreide logs met onder andere:

  • uitvoerende gebruiker
  • apparaatnaam
  • IP-adressen
  • encryptiestatus
  • foutmeldingen

Daarnaast wordt een transcriptbestand aangemaakt dat automatisch wordt gekopieerd naar de Intune Management Extension logs. Zo blijft troubleshooting eenvoudig.


💡 Waarom dit handig is

In grotere omgevingen komt het regelmatig voor dat:

  • BitLocker niet is ingeschakeld
  • Recovery keys ontbreken
  • Keys niet naar Entra ID zijn geüpload
  • TPM nog niet correct is geïnitialiseerd

Dit script lost die problemen automatisch op en zorgt voor een consistente beveiligingsconfiguratie op alle apparaten.

Perfect dus voor gebruik als:

  • Intune remediation script
  • compliance fix
  • deployment controle
  • endpoint security automatisering

🖥 Ondersteunde systemen

Het script werkt op:

  • Windows 10 Pro
  • Windows 10 Enterprise
  • Windows 10 Education
  • Windows 11 Pro
  • Windows 11 Enterprise
  • Windows 11 Education

Uitvoering moet plaatsvinden als Administrator of SYSTEM.


💻 Het PowerShell-script

param ([switch]$Silent)
<#
.NOTES
===========================================================================
Created on: 2025-06-21
Updated on: 2026-03-12
Created by: Vincent van Unen
Filename: SCA_BitlockercheckenFix.ps1
Version: 1.3.1
===========================================================================
.DESCRIPTION
Remediation - BitLocker inschakelen en recovery key back-uppen
- Controleert of TPM aanwezig en gereed is
- Controleert of BitLocker al actief is, zo niet, dan wordt het ingeschakeld
- Controleert of een Recovery Password protector aanwezig is, zo niet, dan wordt deze toegevoegd
- Back-upt de recovery key naar Entra ID/Azure AD (indien cmdlet beschikbaar)
- Hard Block: stopt veilig als TPM reset/herinitialisatie nodig lijkt
- Pending reboot guard: voorkomt FVE_E_REBOOT_REQUIRED tijdens run
- Geschikt voor Windows 10/11 Pro, Enterprise en Education
- Uitvoeren als administrator / SYSTEM

.CHANGELOG
[1.3.1] 2026-03-12 - FIX: bij bestaande TPM-protector eerst
'manage-bde -protectors -enable' en daarna 'manage-bde -on'
(anders start encryptie niet ondanks aanwezige protectors)
[1.3] 2026-03-12 - Duplication-safe enable (manage-bde fallback), Hard Block bij TPM not-ready,
verbeterde foutbranching (0x80310031/0x8031004E), logging aangescherpt
[1.2] 2026-03-12 - Correct parameterset (-TpmProtector), pending reboot guard, extra logging
[1.1] 2026-03-09 - Opschoning, robuustere logging, betere foutafhandeling
[1.0] 2025-06-21 - Eerste versie
#>

#region Script metadata
$ScriptAuthor = "Vincent van Unen"
$ScriptVersion = "1.3.1"
$ScriptChangeDate = "2026-03-12"
$ScriptCurrentUser = $env:UserName
$ScriptRunningDevice = $env:COMPUTERNAME
$CurrentDate = Get-Date -Format "yyyy-MM-dd"
$LogName = "SCA_CheckenFix_BitLocker"
#endregion Script metadata

#region Configuration
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$MaximumFunctionCount = 16384
$MaximumVariableCount = 16384

$TempDirs = @("C:\Temp","C:\Tmp","C:\Log")

$LogDirectory = "C:\Log"
$LogFile = Join-Path $LogDirectory "$LogName $CurrentDate.log"
$TranscriptFile = Join-Path $LogDirectory "${CurrentDate}_${LogName}_Transcript.log"
$IntuneLogFolder = "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs"

$TranscriptStarted = $false
$ExitCode = 1

$OSDrive = $env:SystemDrive
#endregion Configuration

#region Functions
function Write-Log {
[CmdletBinding()]
param (
[ValidateSet("INFO","WARN","ERROR","FATAL","DEBUG")]
[string]$Level = "INFO",
[Parameter(Mandatory = $true)][string]$Message,
[string]$Path = $LogFile
)
try {
$timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss.fff")
Add-Content -Path $Path -Value "[$timestamp] [$Level] $Message" -ErrorAction Stop
} catch {
Write-Warning "Logging mislukt: $($_.Exception.Message)"
}
}

function Write-ConsoleAndLog {
param (
[Parameter(Mandatory = $true)][string]$Message,
[ValidateSet("INFO","WARN","ERROR","FATAL","DEBUG")]
[string]$Level = "INFO"
)
if (-not $Silent) { Write-Output $Message }
Write-Log -Level $Level -Message $Message
}

function Test-IsAdministrator {
try {
if ($env:USERNAME -eq 'SYSTEM') { return $true }
$currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentIdentity)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
} catch { return $false }
}

function Get-PublicIP {
try { return (Invoke-RestMethod -Uri "https://ifconfig.me/ip" -TimeoutSec 10 -ErrorAction Stop).Trim() }
catch { return "Onbekend" }
}

function Get-PrivateIP {
try {
$ip = Get-NetIPAddress -AddressFamily IPv4 -ErrorAction Stop |
Where-Object { $_.IPAddress -notlike "169.254.*" -and $_.IPAddress -ne "127.0.0.1" -and $_.PrefixOrigin -ne "WellKnown" } |
Sort-Object InterfaceMetric | Select-Object -First 1 -ExpandProperty IPAddress
if ([string]::IsNullOrWhiteSpace($ip)) { return "Onbekend" }
return $ip
} catch { return "Onbekend" }
}

function Test-PendingReboot {
<# Detecteert veelvoorkomende reboot-triggers (CBS, pendmoves, WU, naamwijziging) #>
try {
if (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending' -ErrorAction SilentlyContinue) { return $true }
$pn = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' -Name 'PendingFileRenameOperations' -ErrorAction SilentlyContinue
if ($pn -and $pn.PendingFileRenameOperations) { return $true }
if (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired' -ErrorAction SilentlyContinue) { return $true }
$nm = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName' -ErrorAction SilentlyContinue
$an = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName' -ErrorAction SilentlyContinue
if ($nm -and $an -and $nm.ComputerName -ne $an.ComputerName) { return $true }
return $false
} catch {
Write-ConsoleAndLog -Level "WARN" -Message "Pending reboot check mislukt: $($_.Exception.Message)"
return $false
}
}
#endregion Functions

#region Preparation
foreach ($dir in $TempDirs) {
if (-not (Test-Path -Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
}

Write-Log -Message "Current Date = $CurrentDate"
Write-Log -Message "Script Author = $ScriptAuthor"
Write-Log -Message "Script Version = $ScriptVersion"
Write-Log -Message "Script ChangeDate = $ScriptChangeDate"
Write-Log -Message "Current User Running this script = $ScriptCurrentUser"
Write-Log -Message "Current Device Running this script = $ScriptRunningDevice"
Write-Log -Message "Current Public IP = $(Get-PublicIP)"
Write-Log -Message "Current Private IP = $(Get-PrivateIP)"

try {
Start-Transcript -Path $TranscriptFile -Force -ErrorAction Stop | Out-Null
$TranscriptStarted = $true
Write-Log -Message "Transcript gestart: $TranscriptFile"
} catch {
Write-Log -Level "WARN" -Message "Transcript kon niet worden gestart: $($_.Exception.Message)"
}
#endregion Preparation

try {
Write-ConsoleAndLog -Message "Start controle op TPM en BitLocker."

if (-not (Test-IsAdministrator)) { throw "Dit script moet worden uitgevoerd als administrator of SYSTEM." }

# Pending reboot guard – voorkomt FVE_E_REBOOT_REQUIRED (0x8031004E)
if (Test-PendingReboot) {
throw "Herstart vereist voordat BitLocker kan worden ingeschakeld (FVE_E_REBOOT_REQUIRED, 0x8031004E)."
}

# Cmdlets beschikbaar?
if (-not (Get-Command Get-BitLockerVolume -ErrorAction SilentlyContinue)) {
throw "De BitLocker PowerShell-cmdlets zijn niet beschikbaar op dit systeem."
}
if (-not (Get-Command Get-Tpm -ErrorAction SilentlyContinue)) {
throw "De TPM PowerShell-cmdlets zijn niet beschikbaar op dit systeem."
}

$BitLockerVolume = Get-BitLockerVolume -MountPoint $OSDrive -ErrorAction Stop
$TPM = Get-Tpm -ErrorAction Stop

Write-ConsoleAndLog -Message "Controle van TPM en BitLocker gestart op $OSDrive."

# Hard Block: TPM aanwezig maar niet gereed → mogelijke TPM reset nodig (runbook)
if ($TPM.TpmPresent -and -not $TPM.TpmReady) {
Write-ConsoleAndLog -Level "ERROR" -Message "HARD BLOCK: TPM is niet gereed. Remediation stopt. Volg het runbook 'TPM reset + BitLocker herstel'."
$ExitCode = 1
exit $ExitCode
}

if (-not $TPM.TpmPresent) { throw "TPM is niet aanwezig. BitLocker kan niet met TPM worden geconfigureerd." }
if (-not $TPM.TpmEnabled) { throw "TPM is uitgeschakeld. Schakel TPM in BIOS/UEFI in." }
if (-not $TPM.TpmActivated) { throw "TPM is niet geactiveerd. Activeer TPM in BIOS/UEFI." }

# Protectors inventariseren
$RecoveryProtectors = $BitLockerVolume.KeyProtector | Where-Object { $_.KeyProtectorType -eq "RecoveryPassword" }
$TpmProtectors = $BitLockerVolume.KeyProtector | Where-Object { $_.KeyProtectorType -eq "Tpm" }
$HasTpmProtector = [bool]$TpmProtectors

# Recovery Password protector verplicht (voor backup naar Entra ID)
if (-not $RecoveryProtectors) {
Write-ConsoleAndLog -Message "Recovery password protector ontbreekt. Deze wordt toegevoegd."
Add-BitLockerKeyProtector -MountPoint $OSDrive -RecoveryPasswordProtector -ErrorAction Stop | Out-Null
$BitLockerVolume = Get-BitLockerVolume -MountPoint $OSDrive -ErrorAction Stop
$RecoveryProtectors = $BitLockerVolume.KeyProtector | Where-Object { $_.KeyProtectorType -eq "RecoveryPassword" }
}

# TPM protector toevoegen als nog niet aanwezig
if (-not $HasTpmProtector) {
Write-ConsoleAndLog -Message "TPM protector ontbreekt. Deze wordt toegevoegd."
Add-BitLockerKeyProtector -MountPoint $OSDrive -TpmProtector -ErrorAction Stop | Out-Null
$BitLockerVolume = Get-BitLockerVolume -MountPoint $OSDrive -ErrorAction Stop
$TpmProtectors = $BitLockerVolume.KeyProtector | Where-Object { $_.KeyProtectorType -eq "Tpm" }
$HasTpmProtector = [bool]$TpmProtectors
}

# BitLocker inschakelen (duplication-safe, met enable-protectors bij bestaande TPM)
if ($BitLockerVolume.VolumeStatus -eq "FullyDecrypted" -or $BitLockerVolume.ProtectionStatus -eq "Off") {
Write-ConsoleAndLog -Message "BitLocker is niet actief. Inschakelen wordt gestart."

# Protectors vóór enable (debug)
$preKP = $BitLockerVolume.KeyProtector | Select-Object KeyProtectorId, KeyProtectorType
Write-ConsoleAndLog -Level "DEBUG" -Message ("Protectors vóór Enable-BitLocker:`n" + ($preKP | Out-String))

try {
if ($HasTpmProtector) {
# TPM protector bestaat al → eerst protectors activeren, dan encryptie starten
$manageBde = (Get-Command manage-bde.exe -ErrorAction SilentlyContinue)
if ($manageBde) {
Write-ConsoleAndLog -Message "TPM‑protector aanwezig → protectors activeren en encryptie starten via manage-bde."
& $manageBde.Source -protectors -enable $OSDrive | Out-Null
& $manageBde.Source -on $OSDrive -method xts_aes256 -usedspaceonly -skiphardwaretest | Out-Null
} else {
# Fallback: pure PowerShell (zonder extra protector en zonder -SkipHardwareTest om AmbiguousParameterSet te vermijden)
Write-ConsoleAndLog -Level "WARN" -Message "manage-bde niet gevonden. Fallback naar PowerShell‑enable zonder extra protector (reboot kan vereist zijn)."
Enable-BitLocker -MountPoint $OSDrive -EncryptionMethod XtsAes256 -UsedSpaceOnly -ErrorAction Stop | Out-Null
}
}
else {
# TPM protector zojuist toegevoegd → correct parameterset met -TpmProtector (OS‑volume + SkipHardwareTest)
Write-ConsoleAndLog -Message "TPM‑protector toegevoegd → Enable‑BitLocker via -TpmProtector (SkipHardwareTest)."
Enable-BitLocker `
-MountPoint $OSDrive `
-TpmProtector `
-EncryptionMethod XtsAes256 `
-UsedSpaceOnly `
-SkipHardwareTest `
-ErrorAction Stop | Out-Null
}

Write-ConsoleAndLog -Message "Enable‑fase afgerond; status ophalen…"
Start-Sleep -Seconds 10
$BitLockerVolume = Get-BitLockerVolume -MountPoint $OSDrive -ErrorAction Stop

# Protectors ná enable
$postKP = $BitLockerVolume.KeyProtector | Select-Object KeyProtectorId, KeyProtectorType
Write-ConsoleAndLog -Level "DEBUG" -Message ("Protectors ná Enable‑BitLocker:`n" + ($postKP | Out-String))
Write-ConsoleAndLog -Message ("Huidige status: VolumeStatus={0}, ProtectionStatus={1}, EncryptionPercent={2}" -f `
$BitLockerVolume.VolumeStatus, $BitLockerVolume.ProtectionStatus, $BitLockerVolume.EncryptionPercentage)
}
catch {
$global:LastBitLockerError = $_.Exception.Message
$msg = $global:LastBitLockerError

if ($msg -match '0x80310031' -or $msg -match 'FVE_E_PROTECTOR_EXISTS') {
Write-ConsoleAndLog -Level "ERROR" -Message "0x80310031 (FVE_E_PROTECTOR_EXISTS): er bestaat al een protector van dit type. Gebruik de duplication-safe flow (protectors enable + manage-bde -on)."
}
elseif ($msg -match '0x8031004E' -or $msg -match 'FVE_E_REBOOT_REQUIRED') {
Write-ConsoleAndLog -Level "ERROR" -Message "0x8031004E (FVE_E_REBOOT_REQUIRED): herstart vereist voordat BitLocker kan doorgaan."
}
else {
Write-ConsoleAndLog -Level "ERROR" -Message "Enable‑BitLocker mislukt: $msg"
}
throw
}
}
else {
Write-ConsoleAndLog -Message "BitLocker is al actief of de versleuteling is al gestart."
}

# Valideer RecoveryPassword protectors
$BitLockerVolume = Get-BitLockerVolume -MountPoint $OSDrive -ErrorAction Stop
$RecoveryProtectors = $BitLockerVolume.KeyProtector | Where-Object { $_.KeyProtectorType -eq "RecoveryPassword" }
if (-not $RecoveryProtectors) { throw "Recovery password protector ontbreekt nog steeds na herstelpoging." }

# Backup recovery keys naar Entra ID (indien cmdlet beschikbaar)
if (Get-Command BackupToAAD-BitLockerKeyProtector -ErrorAction SilentlyContinue) {
foreach ($Protector in $RecoveryProtectors) {
try {
BackupToAAD-BitLockerKeyProtector -MountPoint $OSDrive -KeyProtectorId $Protector.KeyProtectorId -ErrorAction Stop
Write-ConsoleAndLog -Message "Recovery key succesvol geback-upt naar Entra ID."
} catch {
Write-ConsoleAndLog -Level "WARN" -Message "Backup naar Entra ID is niet gelukt: $($_.Exception.Message)"
}
}
} else {
Write-ConsoleAndLog -Level "WARN" -Message "Cmdlet BackupToAAD-BitLockerKeyProtector is niet beschikbaar. Backup naar Entra ID is overgeslagen."
}

# Eindstatus
$FinalStatus = Get-BitLockerVolume -MountPoint $OSDrive -ErrorAction Stop

Write-ConsoleAndLog -Message "Eindstatus:"
Write-ConsoleAndLog -Message "VolumeStatus : $($FinalStatus.VolumeStatus)"
Write-ConsoleAndLog -Message "ProtectionStatus : $($FinalStatus.ProtectionStatus)"
Write-ConsoleAndLog -Message "EncryptionPercent : $($FinalStatus.EncryptionPercentage)"

if ($FinalStatus.ProtectionStatus -eq "On" -or $FinalStatus.VolumeStatus -in @("EncryptionInProgress", "FullyEncrypted")) {
Write-ConsoleAndLog -Message "BitLocker-remediation is succesvol gestart of voltooid."
$ExitCode = 0
} else {
throw "BitLocker-remediation is niet succesvol."
}
}
catch {
Write-ConsoleAndLog -Level "ERROR" -Message "Remediation mislukt: $($_.Exception.Message)"
$ExitCode = 1
}
finally {
if ($TranscriptStarted) {
try {
Stop-Transcript | Out-Null
Write-Log -Message "Transcript gestopt."
} catch {
Write-Log -Level "WARN" -Message "Stop-Transcript mislukt: $($_.Exception.Message)"
}
}

try {
if (Test-Path -Path $IntuneLogFolder) {
Copy-Item -Path $TranscriptFile -Destination $IntuneLogFolder -Force -ErrorAction Stop
Write-Log -Message "Transcript gekopieerd naar $IntuneLogFolder"
} else {
Write-Log -Level "WARN" -Message "Intune-logmap bestaat niet: $IntuneLogFolder"
}
} catch {
Write-Log -Level "WARN" -Message "Kopiëren van transcript is mislukt: $($_.Exception.Message)"
}

exit $ExitCode
}

🚀 Samenvatting

Met dit script zorg je ervoor dat:

✅ BitLocker automatisch wordt ingeschakeld
✅ TPM wordt gecontroleerd
✅ Recovery keys automatisch worden aangemaakt
✅ Recovery keys veilig in Entra ID worden opgeslagen
✅ Uitgebreide logging beschikbaar is

Een krachtige manier om endpoint-beveiliging automatisch af te dwingen binnen je organisatie.

Post navigation

Previous: Home Assistant Automation – Ochtendroutine met muziek ☀️🎶
Next: Powershell – 🔥 Windows Firewall automatisch herstellen met Intune Proactive Remediation

Related Stories

989d48b8-2fde-4ec9-b87a-58c777d68ede
  • Azure
  • Powershell

Volledig inzicht in Entra applicaties — zonder handmatig geklik

Vincent van Unen 2026-04-21
ChatGPT Image Mar 18, 2026, 11_44_05 AM
  • Powershell

Een PowerShell bootstrap voor modules, logging en minder irritatie

Vincent van Unen 2026-03-19
ChatGPT Image Mar 17, 2026, 01_17_55 PM
  • Powershell

🔧 Je netwerk echt meten met PowerShell

Vincent van Unen 2026-03-17

Recent Posts

  • Volledig inzicht in Entra applicaties — zonder handmatig geklik
  • Van “even het rolluik bedienen” naar een dashboard dat wél logisch voelt
  • Home Assistant op z’n strakst: mijn dashboard in kiosk-modus (zonder gedoe)
  • Een PowerShell bootstrap voor modules, logging en minder irritatie
  • 🔧 Je netwerk echt meten met PowerShell

Recent Comments

No comments to show.

You May Have Missed

989d48b8-2fde-4ec9-b87a-58c777d68ede
  • Azure
  • Powershell

Volledig inzicht in Entra applicaties — zonder handmatig geklik

Vincent van Unen 2026-04-21
ChatGPT Image Apr 16, 2026, 08_29_17 AM
  • Home Assistant

Van “even het rolluik bedienen” naar een dashboard dat wél logisch voelt

Vincent van Unen 2026-04-16
ChatGPT Image Mar 29, 2026, 01_06_58 PM
  • Home Assistant

Home Assistant op z’n strakst: mijn dashboard in kiosk-modus (zonder gedoe)

Vincent van Unen 2026-03-29
ChatGPT Image Mar 18, 2026, 11_44_05 AM
  • Powershell

Een PowerShell bootstrap voor modules, logging en minder irritatie

Vincent van Unen 2026-03-19
  • Algemeen
  • Fotografie
  • Home Assistant
  • Microsoft
  • Azure
  • Powershell
  • Algemeen
  • Fotografie
  • Home Assistant
  • Microsoft
  • Azure
  • Powershell
Copyright © 2026 All rights reserved. | ReviewNews by AF themes.