Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions powershell/Maester.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@
'Test-MtAppleVolumePurchaseProgramToken',
'Test-MtCertificateConnectors', 'Test-MtFeatureUpdatePolicy',
'Test-MtIntuneDiagnosticSettings', 'Test-MtIntuneRbacGroupsProtected',
'Test-MtBitLockerFullDiskEncryption',
'Test-MtMdmAuthority', 'Test-MtMobileThreatDefenseConnectors',
'Test-MtTenantCustomization', 'Test-MtWindowsDataProcessor',
'Test-MtXspmCriticalCredsOnDevicesWithNonCriticalAccounts',
Expand Down
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%
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
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 }
}
}
}
}
}
}

# Check Fixed drive encryption type (FixedDrivesEncryptionType)
if ($defId -eq $fixedEncryptionTypeId) {
$policyDetail.IsBitLockerPolicy = $true
$parentVal = $setting.settingInstance.choiceSettingValue.value
if ($parentVal -like '*_1') {
$children = $setting.settingInstance.choiceSettingValue.children
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) {
$policyDetail.IsBitLockerPolicy = $true
$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
}
}
7 changes: 7 additions & 0 deletions tests/Maester/Intune/Test-MtIntunePlatform.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,11 @@ Describe "Maester/Intune" -Tag "Maester", "Intune" {
$result | Should -Be $true -Because "MDM Authority is set to Intune."
}
}

It "MT.1123: Ensure BitLocker full disk encryption is configured" -Tag "MT.1123" {
$result = Test-MtBitLockerFullDiskEncryption
if ($null -ne $result) {
$result | Should -Be $true -Because "at least one Intune Endpoint Security Disk encryption policy enforces BitLocker full disk encryption."
}
}
}
5 changes: 5 additions & 0 deletions tests/maester-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,11 @@
"Severity": "Medium",
"Title": "AI agents should not have orphaned ownership"
},
{
"Id": "MT.1123",
"Severity": "High",
"Title": "Ensure BitLocker full disk encryption is configured via Intune"
},
{
"Id": "ORCA.100",
"Severity": "Medium",
Expand Down
Loading
Loading