-
Notifications
You must be signed in to change notification settings - Fork 232
Add MT.1123 - BitLocker Full Disk Encryption Check #1583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
OfirGavish
wants to merge
5
commits into
maester365:main
Choose a base branch
from
OfirGavish:feature/mt-1123-bitlocker-encryption-policy
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5fc3818
feat: Add MT.1123 - BitLocker encryption policy check (#intune)
OfirGavish 83750b8
Address Copilot review: array normalization, 401/403 handling, descri…
OfirGavish f76920c
Address Copilot review round 2: filter non-BitLocker policies, fix la…
OfirGavish 479ff0f
Set IsBitLockerPolicy flag in all BitLocker CSP setting blocks
OfirGavish ef07579
Save as UTF-8 with BOM, replace em dashes with ASCII dashes
OfirGavish File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
powershell/public/maester/intune/Test-MtBitLockerFullDiskEncryption.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| Ensure at least one Intune Disk Encryption policy enforces BitLocker with **full disk encryption type**. | ||
|
|
||
| BitLocker Drive Encryption protects data on Windows devices by encrypting the disk. | ||
| However, BitLocker supports two encryption types that have very different security implications: | ||
|
|
||
| - **Full disk encryption** — encrypts the entire drive including free space. This is the recommended and secure option. | ||
| - **Used space only encryption** — only encrypts sectors currently holding data. **This is dangerous on drives that previously contained unencrypted data**, because previously deleted files remain as raw data in unencrypted free space. This data can be recovered using commonly available data recovery software (e.g., Recuva, PhotoRec, or forensic imaging tools). NTFS marks deleted file sectors as "free" but does not zero them out — the original bytes stay on disk until overwritten by new data. | ||
|
|
||
| **Bottom line:** If BitLocker is enabled with "Used space only" on a drive that already had data on it before encryption was turned on, that pre-existing deleted data is fully recoverable. Only "Full disk encryption" guarantees that the entire drive surface is protected. | ||
|
|
||
| This test queries the Intune **Endpoint Security > Disk Encryption** policies via the `configurationPolicies` Graph API and inspects the BitLocker CSP settings to verify that **Enforce drive encryption type** is set to **Full encryption** for OS drives. | ||
|
|
||
| #### Remediation action: | ||
|
|
||
| 1. Navigate to [Microsoft Intune admin center](https://intune.microsoft.com). | ||
| 2. Go to **Endpoint security** > **Disk encryption**. | ||
| 3. Click **+ Create policy**. | ||
| 4. Set **Platform** to **Windows 10 and later** and **Profile** to **BitLocker**. | ||
| 5. Enter a policy name (e.g., "BitLocker - Full Disk Encryption"). | ||
| 6. Configure the following settings: | ||
| - **Require Device Encryption**: **Enabled** | ||
| - **Allow Warning For Other Disk Encryption**: **Disabled** (enables silent encryption) | ||
| - **Allow Standard User Encryption**: **Enabled** | ||
| - **Enforce drive encryption type on operating system drives**: **Enabled**, set to **Full encryption** | ||
| - **Enforce drive encryption type on fixed data drives**: **Enabled**, set to **Full encryption** | ||
| - **Choose drive encryption method and cipher strength**: **Enabled** | ||
| - OS drives: **XTS-AES 256-bit** | ||
| - Fixed data drives: **XTS-AES 256-bit** | ||
| - Removable data drives: **AES-CBC 256-bit** | ||
| - **Require additional authentication at startup**: **Enabled**, with **Require TPM** | ||
| - **Choose how BitLocker-protected OS drives can be recovered**: **Enabled**, with backup to Entra ID | ||
| 7. Assign the policy to your device groups and click **Create**. | ||
|
|
||
| #### Related links | ||
|
|
||
| - [Microsoft Intune - Endpoint Security Disk Encryption](https://intune.microsoft.com/#view/Microsoft_Intune_Workflows/SecurityManagementMenu/~/diskEncryption) | ||
| - [Microsoft Learn - Encrypt devices with BitLocker in Intune](https://learn.microsoft.com/en-us/mem/intune/protect/encrypt-devices) | ||
| - [Microsoft Learn - BitLocker CSP reference](https://learn.microsoft.com/en-us/windows/client-management/mdm/bitlocker-csp) | ||
| - [CIS Benchmark - Ensure BitLocker is enabled on all Windows devices](https://www.cisecurity.org/benchmark/microsoft_intune_for_windows) | ||
|
|
||
| <!--- Results ---> | ||
| %TestResult% |
222 changes: 222 additions & 0 deletions
222
powershell/public/maester/intune/Test-MtBitLockerFullDiskEncryption.ps1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,222 @@ | ||
| function Test-MtBitLockerFullDiskEncryption { | ||
| <# | ||
| .SYNOPSIS | ||
| Ensure at least one Intune Disk Encryption policy enforces BitLocker with full disk encryption type. | ||
|
|
||
| .DESCRIPTION | ||
| Checks Intune Endpoint Security Disk Encryption policies (configurationPolicies API) for BitLocker | ||
| profiles that enforce full disk encryption rather than "Used space only" encryption. | ||
|
|
||
| BitLocker supports two encryption types with very different security implications: | ||
| - "Full disk encryption" — encrypts the entire drive including free space. This is the secure option. | ||
| - "Used space only encryption" — only encrypts sectors currently holding data. Previously deleted | ||
| files that were written before encryption was enabled remain in unencrypted free space and can be | ||
| recovered using data recovery software (e.g., Recuva, PhotoRec, or forensic tools). This is because | ||
| NTFS marks sectors as free but does not zero them out — the raw data stays on disk until overwritten. | ||
|
|
||
| This test queries the configurationPolicies Graph API (used by Endpoint Security > Disk Encryption) | ||
| which exposes the actual BitLocker CSP settings including: | ||
| - SystemDrivesEncryptionType (OS drive encryption type: full vs used space only) | ||
| - FixedDrivesEncryptionType (fixed drive encryption type: full vs used space only) | ||
| - RequireDeviceEncryption (require BitLocker encryption) | ||
| - EncryptionMethodByDriveType (cipher strength: XTS-AES 128/256, AES-CBC 128/256) | ||
|
|
||
| The test passes only if at least one BitLocker Disk Encryption policy has the OS drive encryption | ||
| type set to "Full encryption". It fails if no policies exist, if encryption type is set to | ||
| "Used space only", or if the encryption type setting is not configured. | ||
|
|
||
| .EXAMPLE | ||
| Test-MtBitLockerFullDiskEncryption | ||
|
|
||
| Returns true if at least one Disk Encryption policy enforces full disk encryption for OS drives. | ||
|
|
||
| .LINK | ||
| https://maester.dev/docs/commands/Test-MtBitLockerFullDiskEncryption | ||
| #> | ||
| [CmdletBinding()] | ||
| [OutputType([bool])] | ||
| param() | ||
|
|
||
| if (-not (Get-MtLicenseInformation -Product Intune)) { | ||
| Add-MtTestResultDetail -SkippedBecause NotLicensedIntune | ||
| return $null | ||
| } | ||
|
|
||
| try { | ||
| # Query Endpoint Security Disk Encryption policies (server-side filter). | ||
| # This template family can include non-BitLocker templates (e.g., Personal Data Encryption); | ||
| # BitLocker-specific settings are evaluated per-policy below. | ||
| $diskEncryptionPolicies = @(Invoke-MtGraphRequest -RelativeUri "deviceManagement/configurationPolicies?`$filter=templateReference/templateFamily eq 'endpointSecurityDiskEncryption'&`$select=id,name,description,templateReference" -ApiVersion beta) | ||
|
|
||
| if ($diskEncryptionPolicies.Count -eq 0) { | ||
| $testResultMarkdown = "No Endpoint Security Disk Encryption policies found in Intune.`n`n" | ||
| $testResultMarkdown += "Create a Disk Encryption policy under **Endpoint Security > Disk Encryption** with " | ||
| $testResultMarkdown += "**Enforce drive encryption type** set to **Full encryption** for OS and fixed data drives." | ||
| Add-MtTestResultDetail -Result $testResultMarkdown | ||
| return $false | ||
| } | ||
|
|
||
| # Setting definition IDs for BitLocker CSP settings | ||
| $osEncryptionTypeId = 'device_vendor_msft_bitlocker_systemdrivesencryptiontype' | ||
| $osEncryptionTypeDropdownId = 'device_vendor_msft_bitlocker_systemdrivesencryptiontype_osencryptiontypedropdown_name' | ||
| $fixedEncryptionTypeId = 'device_vendor_msft_bitlocker_fixeddrivesencryptiontype' | ||
| $fixedEncryptionTypeDropdownId = 'device_vendor_msft_bitlocker_fixeddrivesencryptiontype_fdeencryptiontypedropdown_name' | ||
| $requireEncryptionId = 'device_vendor_msft_bitlocker_requiredeviceencryption' | ||
| $encryptionMethodId = 'device_vendor_msft_bitlocker_encryptionmethodbydrivetype' | ||
| $osEncryptionMethodDropdownId = 'device_vendor_msft_bitlocker_encryptionmethodbydrivetype_encryptionmethodwithxtsosdropdown_name' | ||
|
|
||
| # Encryption type value suffixes: _0 = Allow user to choose, _1 = Full encryption, _2 = Used Space Only | ||
| $encryptionTypeLabels = @{ | ||
| '_0' = 'Allow user to choose' | ||
| '_1' = 'Full encryption' | ||
| '_2' = 'Used Space Only' | ||
| } | ||
|
|
||
| # Encryption method value suffixes: _3=AES-CBC 128, _4=AES-CBC 256, _6=XTS-AES 128, _7=XTS-AES 256 | ||
| $encryptionMethodLabels = @{ | ||
| '_3' = 'AES-CBC 128-bit' | ||
| '_4' = 'AES-CBC 256-bit' | ||
| '_6' = 'XTS-AES 128-bit' | ||
| '_7' = 'XTS-AES 256-bit' | ||
| } | ||
|
|
||
| $policyResults = [System.Collections.Generic.List[hashtable]]::new() | ||
| $hasFullEncryption = $false | ||
|
|
||
| foreach ($policy in $diskEncryptionPolicies) { | ||
| # Fetch settings for this policy with definitions expanded | ||
| $settingsUri = "deviceManagement/configurationPolicies('$($policy.id)')/settings?`$expand=settingDefinitions&`$top=1000" | ||
| $settingsResponse = @(Invoke-MtGraphRequest -RelativeUri $settingsUri -ApiVersion beta) | ||
|
|
||
| $policyDetail = @{ | ||
| Name = $policy.name | ||
| RequireEncryption = 'Not configured' | ||
| OsEncryptionType = 'Not configured' | ||
| FixedEncryptionType = 'Not configured' | ||
| OsEncryptionMethod = 'Not configured' | ||
| IsBitLockerPolicy = $false | ||
| } | ||
|
|
||
| foreach ($setting in $settingsResponse) { | ||
| $defId = $setting.settingInstance.settingDefinitionId | ||
|
|
||
| # Check RequireDeviceEncryption | ||
| if ($defId -eq $requireEncryptionId) { | ||
| $policyDetail.IsBitLockerPolicy = $true | ||
| $val = $setting.settingInstance.choiceSettingValue.value | ||
| if ($val -like '*_1') { | ||
| $policyDetail.RequireEncryption = 'Enabled' | ||
| } else { | ||
| $policyDetail.RequireEncryption = 'Disabled' | ||
| } | ||
| } | ||
|
|
||
| # Check OS drive encryption type (SystemDrivesEncryptionType) | ||
| if ($defId -eq $osEncryptionTypeId) { | ||
| $policyDetail.IsBitLockerPolicy = $true | ||
| $parentVal = $setting.settingInstance.choiceSettingValue.value | ||
| if ($parentVal -like '*_1') { | ||
| # Enabled — check the child dropdown for the actual encryption type | ||
| $children = $setting.settingInstance.choiceSettingValue.children | ||
| foreach ($child in $children) { | ||
| if ($child.settingDefinitionId -eq $osEncryptionTypeDropdownId) { | ||
| $dropdownVal = $child.choiceSettingValue.value | ||
| foreach ($suffix in $encryptionTypeLabels.Keys) { | ||
| if ($dropdownVal.EndsWith($suffix)) { | ||
| $policyDetail.OsEncryptionType = $encryptionTypeLabels[$suffix] | ||
| if ($suffix -eq '_1') { $hasFullEncryption = $true } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
OfirGavish marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| # Check Fixed drive encryption type (FixedDrivesEncryptionType) | ||
| if ($defId -eq $fixedEncryptionTypeId) { | ||
| $parentVal = $setting.settingInstance.choiceSettingValue.value | ||
| if ($parentVal -like '*_1') { | ||
| $children = $setting.settingInstance.choiceSettingValue.children | ||
OfirGavish marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| foreach ($child in $children) { | ||
| if ($child.settingDefinitionId -eq $fixedEncryptionTypeDropdownId) { | ||
| $dropdownVal = $child.choiceSettingValue.value | ||
| foreach ($suffix in $encryptionTypeLabels.Keys) { | ||
| if ($dropdownVal.EndsWith($suffix)) { | ||
| $policyDetail.FixedEncryptionType = $encryptionTypeLabels[$suffix] | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| # Check encryption method (cipher strength) | ||
| if ($defId -eq $encryptionMethodId) { | ||
OfirGavish marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| $parentVal = $setting.settingInstance.choiceSettingValue.value | ||
| if ($parentVal -like '*_1') { | ||
| $children = $setting.settingInstance.choiceSettingValue.children | ||
| foreach ($child in $children) { | ||
| if ($child.settingDefinitionId -eq $osEncryptionMethodDropdownId) { | ||
| $methodVal = $child.choiceSettingValue.value | ||
| foreach ($suffix in $encryptionMethodLabels.Keys) { | ||
| if ($methodVal.EndsWith($suffix)) { | ||
| $policyDetail.OsEncryptionMethod = $encryptionMethodLabels[$suffix] | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| $policyResults.Add($policyDetail) | ||
| } | ||
|
|
||
| # Filter to only BitLocker policies (those with BitLocker CSP settings) | ||
| $bitLockerPolicies = @($policyResults | Where-Object { $_.IsBitLockerPolicy }) | ||
|
|
||
| if ($bitLockerPolicies.Count -eq 0) { | ||
| $testResultMarkdown = "Found $($diskEncryptionPolicies.Count) Disk Encryption policy/policies in Intune, but none are BitLocker policies.`n`n" | ||
| $testResultMarkdown += "Create a BitLocker policy under **Endpoint Security > Disk Encryption** with " | ||
| $testResultMarkdown += "**Enforce drive encryption type** set to **Full encryption** for OS and fixed data drives." | ||
| Add-MtTestResultDetail -Result $testResultMarkdown | ||
| return $false | ||
| } | ||
|
|
||
| # Build result markdown (only BitLocker policies) | ||
| $testResultMarkdown = "Found $($bitLockerPolicies.Count) BitLocker Disk Encryption policy/policies in Intune.`n`n" | ||
| $testResultMarkdown += "| Policy | Require Encryption | OS Encryption Type | Fixed Encryption Type | OS Cipher |`n" | ||
| $testResultMarkdown += "| --- | --- | --- | --- | --- |`n" | ||
| foreach ($p in $bitLockerPolicies) { | ||
| $testResultMarkdown += "| $($p.Name) | $($p.RequireEncryption) | $($p.OsEncryptionType) | $($p.FixedEncryptionType) | $($p.OsEncryptionMethod) |`n" | ||
| } | ||
|
|
||
| if ($hasFullEncryption) { | ||
| $testResultMarkdown += "`n**Result:** At least one BitLocker policy enforces **Full encryption** for OS drives." | ||
|
|
||
| # Warn if any policy uses Used Space Only | ||
| $usedSpaceOnly = @($bitLockerPolicies | Where-Object { $_.OsEncryptionType -eq 'Used Space Only' }) | ||
| if ($usedSpaceOnly.Count -gt 0) { | ||
| $testResultMarkdown += "`n`n> **Warning:** $($usedSpaceOnly.Count) policy/policies use **Used Space Only** encryption. " | ||
| $testResultMarkdown += "Previously deleted data remains recoverable from unencrypted free space on those devices." | ||
| } | ||
|
|
||
| Add-MtTestResultDetail -Result $testResultMarkdown | ||
| return $true | ||
| } else { | ||
| $testResultMarkdown += "`n**Result:** No BitLocker policy enforces **Full encryption** for OS drives.`n`n" | ||
| $testResultMarkdown += "> **Risk:** If 'Used space only' encryption is configured (or encryption type is not enforced), " | ||
| $testResultMarkdown += "data written to the disk before BitLocker was enabled remains as raw unencrypted data in free space " | ||
| $testResultMarkdown += "and can be recovered using commonly available data recovery tools (Recuva, PhotoRec, forensic imaging)." | ||
| Add-MtTestResultDetail -Result $testResultMarkdown | ||
| return $false | ||
| } | ||
| } catch { | ||
| if ($_.Exception.Response -and $_.Exception.Response.StatusCode -in @(401, 403)) { | ||
| Add-MtTestResultDetail -SkippedBecause NotAuthorized | ||
| } else { | ||
| Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ | ||
| } | ||
| return $null | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
website/versioned_docs/version-2.0.0/tests/maester/MT.1123.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| --- | ||
| title: MT.1123 - Ensure BitLocker full disk encryption is configured via Intune | ||
| description: Checks if at least one Intune Endpoint Security Disk encryption policy enforces BitLocker full disk encryption for OS drives. | ||
| slug: /tests/MT.1123 | ||
OfirGavish marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| sidebar_class_name: hidden | ||
| --- | ||
|
|
||
| # Ensure BitLocker full disk encryption is configured via Intune | ||
|
|
||
| ## Description | ||
|
|
||
| BitLocker Drive Encryption protects data on Windows devices, but the **encryption type** setting is critical: | ||
|
|
||
| - **Full disk encryption** — encrypts the entire drive including free space. This is the secure option. | ||
| - **Used space only encryption** — only encrypts sectors currently holding data. Previously deleted files that existed before encryption was enabled remain as raw data in unencrypted free space and **can be recovered using data recovery software** (e.g., Recuva, PhotoRec, forensic imaging tools). This happens because NTFS marks deleted sectors as "free" but does not zero them — the original bytes persist on disk until overwritten. | ||
|
|
||
| This test queries the `configurationPolicies` Graph API (the same API used by the Intune admin center's **Endpoint Security > Disk Encryption** blade). It reads the BitLocker CSP settings — specifically `SystemDrivesEncryptionType` and `FixedDrivesEncryptionType` — to verify that at least one Disk Encryption policy enforces **Full encryption** for OS drives. It also reports `RequireDeviceEncryption` status and cipher strength (`EncryptionMethodByDriveType`) for each policy. | ||
|
|
||
| The test **passes** only if at least one BitLocker Disk Encryption policy has the OS drive encryption type set to "Full encryption". It **fails** if no policies exist, or if all policies use "Used space only" or "Allow user to choose". | ||
|
|
||
| ## How to fix | ||
|
|
||
| 1. Navigate to [Microsoft Intune admin center](https://intune.microsoft.com). | ||
| 2. Go to **Endpoint security** > **Disk encryption**. | ||
| 3. Click **Create Policy**. | ||
| 4. Set **Platform** to **Windows 10 and later**. | ||
| 5. Set **Profile** to **BitLocker**. | ||
| 6. Under the BitLocker settings, configure: | ||
| - **Enforce drive encryption type on operating system drives**: **Full encryption** (`SystemDrivesEncryptionType`) | ||
| - **Enforce drive encryption type on fixed data drives**: **Full encryption** (`FixedDrivesEncryptionType`) | ||
| - **Require Device Encryption**: **Enabled** | ||
| - **Choose drive encryption method and cipher strength**: **Enabled** | ||
| - OS drives: **XTS-AES 256-bit** | ||
| - Fixed data drives: **XTS-AES 256-bit** | ||
| - Removable data drives: **AES-CBC 256-bit** | ||
| 7. Assign the policy to your device groups. | ||
|
|
||
| ## Learn more | ||
|
|
||
| - [Microsoft Intune - Endpoint Security Disk Encryption](https://intune.microsoft.com/#view/Microsoft_Intune_Workflows/SecurityManagementMenu/~/diskEncryption) | ||
| - [Microsoft Learn - Encrypt devices with BitLocker in Intune](https://learn.microsoft.com/en-us/mem/intune/protect/encrypt-devices) | ||
| - [Microsoft Learn - BitLocker CSP reference](https://learn.microsoft.com/en-us/windows/client-management/mdm/bitlocker-csp) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.