Enforce BitLocker startup PIN on Windows with Intune
The purpose of this blog post is to inform you how to enforce a BitLocker startup Pin for standard users. I was inspired by the solution of Oliver Kieselbach, but his solution was user-driven and not enforced so I decided to change some settings, make a proactive remediation script, and create a custom Compliance check to enforce the BitLocker startup pin.
Requirements:
Original solution
By default, a standard user is not able to set a BitLocker startup pin. Only a local admin can set the pin code, so there must be another method. I did some research, and I found the solution of Oliver Kieselbach. You can find his blog and the original content here.
Enforced solution
The solution did not force the user to set the startup pin, but I wanted to enforce it, so I decided to modify his solution. I change some settings in his code, so the user cannot close the pin code diagram anymore. Created the Win32 app and set it as a required install so everything was on the device. The last piece of the puzzle was to enforce it with a proactive remediation script and a custom compliance policy.
What did I change?
File: popup.ps1
Line: 1
Original:
# Author: Oliver Kieselbach (oliverkieselbach.com)
Changed to:
# Author: Oliver Kieselbach (oliverkieselbach.com) & Rene Laas (endpointcave.com)
File: popup.ps1
Line: 12
Add:
# - 02/23/2022 Added simple PIN i.e. 000000 check # added by Rene Laas - Endpointcave.com
File: popup.ps1
Line: 66
Add:
# Test of all numbers in array are the same
# Function Added by Rene Laas Endpointcave.com
function Test-Number
{
param (
[String]
$NumberString
)
$array = $NumberString.ToCharArray()
If ( @($array | Select -Unique).Count -eq 1 )
{
return $true
}
Else
{
return $false
}
}
if(!(Test-Path $PSScriptRoot\BitLockerRunning.txt))
{
File: popup.ps1
Line: 113
Original:
$language = Get-Content language.json -Encoding UTF8 | ConvertFrom-Json
Changed to:
$language = Get-Content "C:\progra~2\BitLockerPINDialog\language.json" -Encoding UTF8 | ConvertFrom-Json # Modified by Rene Laas Endpointcave - Change json location
File: popup.ps1
Line: 176
Original:
$pathPINFile = $(Join-Path -Path "$env:SystemRoot\tracing" -ChildPath "168ba6df825678e4da1a.tmp")
Changed to:
#$pathPINFile = $(Join-Path -Path "$env:SystemRoot\tracing" -ChildPath "168ba6df825678e4da1a.tmp")
$pathPINFile = "C:\PinTemp\PIN-prompted.txt" # Modified by Rene Laas Endpointcave.com
File: popup.ps1
Line: 183
Add:
Remove-Item -Path $PSScriptRoot\BitLockerRunning.txt -Force # Added by Rene Laas Endpointcave.com
File: popup.ps1
Line: 241
Original:
$formBitLockerStartupPIN.ClientSize = '445, 271'
Changed to:
$formBitLockerStartupPIN.ClientSize = '445, 305' # Modified by Rene Laas Endpointcave - change 271 to 305
File: popup.ps1
Line: 1783
Add:
$formBitLockerStartupPIN.ControlBox = $False # Added by Rene Laas Endpointcave
File: popup.ps1
Line: 1794
Original:
$labelPINIsNotEqual.Location = '275, 181'
Changed to:
$labelPINIsNotEqual.Location = '275, 210' # Modified by Rene Laas Endpointcave - from 181 to 210
File: popup.ps1
Line: 1805
Original:
$labelRetypePIN.Location = '26, 146'
Changed to:
$labelRetypePIN.Location = '26, 186' # Modified by Rene Laas Endpointcave - from 146 to 186
File: popup.ps1
Line: 1815
Original:
$labelNewPIN.Location = '26, 105'
Changed to:
$labelNewPIN.Location = '26, 145' # Modified by Rene Laas Endpointcave - from 105 to 145
File: popup.ps1
Line: 1834
Original:
$panelBottom.Controls.Add($buttonCancel)
Changed to:
#$panelBottom.Controls.Add($buttonCancel) # Disabled by Rene Laas Endpointcave
File: popup.ps1
Line: 1837
Original:
$panelBottom.Location = '-1, 209'
Changed to:
$panelBottom.Location = '-1, 243' # Modified by Rene Laas Endpointcave - from 209 to 243
File: popup.ps1
Line: 1855
Original:
$buttonSetPIN.Location = '225, 17'
Changed to:
$buttonSetPIN.Location = '320, 17' # Modified by Rene Laas Endpointcave - from 225 to 320
File: popup.ps1
Line: 1877
Original:
$textboxRetypedPin.Location = '140, 143'
Changed to:
$textboxRetypedPin.Location = '180, 183' # Modified by Rene Laas Endpointcave - from 140 to 180 and 143 to 183
File: popup.ps1
Line: 1886
Original:
$textboxNewPin.Location = '140, 102'
Changed to:
$textboxNewPin.Location = '180, 142' # Modified by Rene Laas Endpointcave - from 140 to 180 and 102 to 142
File: popup.ps1
Line: 1901
Add:
}
Else
{
# Check if file is older/newer
$lastWrite = (get-item $PSScriptRoot\BitLockerRunning.txt).LastWriteTime
$timespan = new-timespan -days 1
if (((get-date) - $lastWrite) -ge $timespan)
{
Write-Output "BitLockerRunning.txt is created more than 1 day ago, deleting file and waiting for next cycle."
Remove-Item -Path $PSScriptRoot\BitLockerRunning.txt -ForceRemove-Item -Path $PSScriptRoot\BitLockerRunning.txt -Force
}
else
{
Write-Output "BitLockerRunning.txt is created less than 1 day ago."
}
}
File: Setbitlockerpin.ps1
Line: 13
Original:
.\ServiceUI.exe -process:Explorer.exe "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -WindowStyle Hidden -Ex bypass -file "$PSScriptRoot\Popup.ps1"
Changed to:
C:\progra~2\BitLockerPINDialog\ServiceUI.exe -process:Explorer.exe "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -WindowStyle Hidden -Ex bypass -file "C:\progra~2\BitLockerPINDialog\Popup.ps1" # Modified by Rene Laas Endpointcave - Path modified
File: Setbitlockerpin.ps1
Line: 19
Original:
$pathPINFile = $(Join-Path -Path "$env:SystemRoot\tracing" -ChildPath "168ba6df825678e4da1a.tmp")
Changed to:
#$pathPINFile = $(Join-Path -Path "$env:SystemRoot\tracing" -ChildPath "168ba6df825678e4da1a.tmp")
$pathPINFile = "C:\PINtemp\PIN-prompted.txt" # Modified by Rene Laas Endpointcave
Add install/uninstall script to the source?
For the correct working of the script, some files must be present on the device. I have added therefore a PowerShell installation and an uninstallation script that will make sure the needed files are in the required subdirectory of the program files directory or can be deleted.
Install.ps1:
New-Item -ItemType Directory -Force -Path C:\progra~2\BitLockerPINDialog\
Move-Item -Path .\*.* -Destination C:\progra~2\BitLockerPINDialog\
Uninstall.ps1:
Remove-Item -Path C:\progra~2\BitLockerPINDialog -Recurse
How to configure the BitLocker settings
- Open Microsoft Endpoint manager
- In the menu select Endpoint security
- Under Manage, select Disk encryption
Or use the following link Disk encryption – Microsoft Endpoint Manager admin center - Click on + Create Policy
- Select Windows 10 and later as the platform and BitLocker as the profile
- Click on create
- Set a name and optionally the description and click on Next
- Configure the following settings
BitLocker – Base settings
Setting | Value |
---|---|
Enable full disk encryption for OS and fixed data drives | Yes |
Require storage cards to be encrypted (mobile only) | Not configured |
Hide prompt about third-party encryption | Yes |
Allow standard users to enable encryption during Autopilot | Yes |
Configure client-driven recovery password rotation | Enable rotation on Azure AD and Hybrid-joined devices |
Bitlocker OS Drive Settings
Setting | Value |
---|---|
BitLocker system drive policy | Configure |
Startup authentication required | Yes |
Compatible TPM startup | Allowed |
Compatible TPM startup PIN | Allowed |
Compatible TPM startup key | Blocked |
Compatible TPM startup key and PIN | Blocked |
Disable BitLocker on devices where TPM is incompatible | Not configure |
Enable preboot recovery message and URL | Not configure |
System drive recovery | Configure |
Recovery key file creation | Allowed |
Configure BitLocker recovery package | Password and key |
Require device to back up recovery information to Azure AD | Yes |
Recovery password creation | Allowed |
Hide recovery options during BitLocker setup | Yes |
Enable BitLocker after recovery information to store | Yes |
Block the use of certificate-based data recovery agent (DRA) | Not configure |
Minimum PIN length | 6 |
Configure encryption method for Operating System drives | AES 256bit XTS |
Note. I recommended to configure BitLocker – Fixed Drive Settings and BitLocker – Removable Drive Settings as well, but both are not required for the BitLocker Startup Pin
How to create the BitLocker Startup Pin package
- Download the SetBitLockerPin files of Oliver his Github page.
Link: Intune/Win32/SetBitLockerPin at master · okieselbach/Intune · GitHub - Copy the SetBitLockerPin files to an empty folder
- Modify the files that are mentioned in the paragraph What did I change?
- Create the .intunewin package with the Intune content preparation tool with the following command:
{directory of WinappUtil}\IntuneWinAppUtil.exe -c { directory of SetBitLockerPin files } -s install.ps1 -o .\ -q
Or
- Download the modified SetBitLockerPin files from my Github page
Link: EndpointCave.com/BitLockerStartupPin at main · Renelaas/EndpointCave.com · GitHub - Copy the SetBitLockerPin files to an empty folder
- Create the .intunewin package with the Intune content preparation tool with the following command:
{directory of WinappUtil}\IntuneWinAppUtil.exe -c {directory of SetBitLockerPin files} -s install.ps1 -o .\ -q
Or
- Download the .intunewin package here
How to install BitLocker solution
- Open Microsoft Endpoint manager
- In the menu select Apps
- Under Apps, select Windows
Or use the following link Windows Apps – Microsoft Endpoint Manager admin center - Click on + Add
- Select the App Type Windows App (Win32) and click on Select
- Click on the Select app package file and click on the blue directory icon
- The file explorer will open and browse to the .Intunewin file that you have created.
- Click on OK
- Set a name, description, and publisher of the app
- Click on Next
- Set the following Install and uninstall commands
Install:
powershell.exe -executionpolicy bypass -file ".\install.ps1"
Uninstall:
powershell.exe -executionpolicy bypass -file ".\uninstall.ps1"
- Select 64-bit as the operating system architecture
- Select Windows 10 20H2 as the minimum Operating system
- Select Manually configure detection rules as the rules format
- Click on + Add and configure the following detection rule
Setting | Value |
---|---|
Rule Type | File |
Path | C:\progra~2\BitLockerPINDialog\ |
File or folder | ServiceUI.exe |
Detection method | File or folder exists |
Associated with a 32-bit app on 64-bit clients | No |
- Click on Next and on the Dependencies and Supersedence section click also next
- Set the assignment to require for all devices
- Click on next. Check the app configuration and click on Create.
- The app will be created and uploaded
Proactive Remediation Scripts that need to be uploaded to Intune
Detection Script:
$pin = (Get-BitLockerVolume -MountPoint $env:SystemDrive).KeyProtector | Where { $_.KeyProtectorType -eq 'TpmPin' }
if (((Get-BitLockerVolume -MountPoint $env:SystemDrive).VolumeStatus) -ne "FullyDecrypted")
{
Write-Output "Encryption enabled"
if ($pin -ne $null)
{
Write-Output "TPM Pin set"
Exit 0
}
else
{
Write-Output "TPM Pin is not set"
Exit 1
}
}
else
{
Write-Output "Encryption not yet started"
Exit 0
}
Remediation Script:
#Author: Oliver Kieselbach (oliverkieselbach.com) & Rene Laas (endpointcave.com)
# Date: 08/01/2019
# Description: Starts the Windows Forms Dialog for BitLocker PIN entry and receives the PIN via exit code to set the additional key protector
# - 10/21/2019 changed PIN handover
# - 02/10/2020 added content length check
# - 09/30/2021 changed PIN handover to AES encryption/decryption via DPAPI and shared key
# added simple PIN check for incrementing and decrementing numbers e.g. 123456 and 654321
# language support (see language.json), default is always en-US
# changed temp storage location and temp file name
# The script is provided "AS IS" with no warranties.
# Added by Rene Laas endpoincave
if (!(Test-Path "C:\PINtemp"))
{
New-Item -Path 'C:\PINtemp' -ItemType Directory
Write-output "Temp directory created"
}
else
{
Write-output "Temp directory already exist"
}
# Added by Rene Laas Endpointcave
# Pin temp file
$PathPINtemp = "C:\PINtemp\"
$pathPINFile = $PathPINtemp + "PIN-prompted.txt"
#######################
C:\progra~2\BitLockerPINDialog\ServiceUI.exe -process:Explorer.exe "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -WindowStyle Hidden -Ex bypass -file "C:\progra~2\BitLockerPINDialog\SetBitLockerPin.ps1" # Modified by Rene Laas Endpointcave
$exitCode = $LASTEXITCODE
# ASR rules can block the write access to public documents, so we use a writeable path for users and system
# Check with sysinternals tool: accesschk.exe users -wus c:\windows\*
# "c:\windows\tracing" should be fine as temp storage
#$pathPINFile = $(Join-Path -Path "$env:SystemRoot\tracing" -ChildPath "168ba6df825678e4da1a.tmp")
# Alternativly use public documents, but keep in mind the ASR rules!
#$pathPINFile = $(Join-Path -Path $([Environment]::GetFolderPath("CommonDocuments")) -ChildPath "168ba6df825678e4da1a.tmp")
If ($exitCode -eq 0 -And (Test-Path -Path $pathPINFile)) {
$encodedText = Get-Content -Path $pathPINFile
if ($encodedText.Length -gt 0) {
# Using DPAPI with a random generated shared 256-bit key to decrypt the PIN
$key = (43,155,164,59,21,127,28,43,81,18,198,145,127,51,72,55,39,23,228,166,146,237,41,131,176,14,4,67,230,81,212,214)
$secure = ConvertTo-SecureString $encodedText -Key $key
# Code for PS7+
#$PIN = ConvertFrom-SecureString -SecureString $secure -AsPlainText
# Code for PS5
$PIN = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure))
Add-BitLockerKeyProtector -MountPoint $env:SystemDrive -Pin $(ConvertTo-SecureString $PIN -AsPlainText -Force) -TpmAndPinProtector
}
}
# Cleanup ###
# Modified by Rene Laas Endpointcave
if((Test-Path $pathPINFile))
{
Remove-Item -Path $pathPINFile -Force -Recurse
Write-output "Encrypted Pin file deleted"
}
if((Test-Path $PathPINtemp))
{
Remove-Item -Path $PathPINtemp -Force -Recurse
Write-Output "Deleted temp folder"
}
How to enforce BitLocker Startup pin via Intune with Proactive Remediation Scripts
- Open Microsoft endpoint manager
- In the menu select Reports
- Click on Endpoint analytics in the menu under Analytics
- Click on Proactive remediations
Or use the following link Endpoint analytics – Microsoft Endpoint Manager admin center - Click on Create script package
- Provide a Name script name
- Set a description, so that everyone with access to the portal knows the purpose of the script
- Click on Next
- Upload the Detection scripts and Remediation scripts.
- Configure the following PowerShell script settings
Setting | Value |
---|---|
Run this script using the logged on credentials | No |
Enforce script signature check | No |
Run script in 64-bit PowerShell Host | Yes |
- Click on Nextand on the Scope tags section click on Next
- Assign remediation script to All User
- Change the schedule via the 3 bullets and Click on Edit
- Click on the dropdown list and change the frequency from Daily to Hourly and click on Next
- Check on the review + create page if all settings are configured correctly and click on Create
Result:
Create a Custom Compliance check
- Open Microsoft endpoint manager
- In the menu select Devices
- Click on Compliance Policies under Policy in the new menu
- In the menu click on Scripts
or use the following link: Compliance policies – Microsoft Endpoint Manager admin center - Click on + Add and select Windows 10 and later
- Fill in the following settings
Setting | Value |
---|---|
Name | BitLockerPin |
Description | Custom compliance check for BitLocker Startup Ping |
Publisher | Endpointcave.com |
- Click on next
- Configure the following Custom script settings
Detection script Script
$BLinfo = (Get-BitLockerVolume -MountPoint $env:SystemDrive).KeyProtector | Where { $_.KeyProtectorType -eq 'TpmPin' }
$hash = @{KeyProtectorType = $BLinfo.KeyProtectorType}
return $hash | ConvertTo-Json -Compress
Setting | Value |
---|---|
Run this script using the logged on credentials | No |
Enforce script signature check | No |
Run script in 64-bit PowerShell Host | Yes |
- Click on Next, review the configuration, and click on Create
- The next step is to open an existing compliance policy
- In the menu click on policies
- Open an existing compliance policy to enforce BitLocker startup Pin
- Click on Properties under Manage
- Edit the compliance settings via the edit button
- Open the Custom Compliance section
- Configure the following Custom Compliance settings
Setting | Value |
---|---|
Custom compliance | Required |
Select your discovery script | BitlockerPin |
JSON
{
"Rules":[
{
"SettingName":"KeyProtectorType",
"Operator":"IsEquals",
"DataType":"Int64",
"Operand":"4",
"MoreInfoUrl":"https://endpointcave.com",
"RemediationStrings":[
{
"Language":"en_US",
"Title":"Bitlocker Startup Pin must be set",
"Description": " Bitlocker Startup Pin must be set "
}
]
}
]
}
Result:
I use this sollution and it works like a charm, but for some reason device become non compliant and when i look at the device it is the bitlockerpin compliance that failed and so the device become non compliant. can i remove the custom compliance script? The remediation script will take care of the enforce bitlocker pin set so i think i can remove it or do i miss something?
Hi Andre,
The custom compliance script is an Add-on, but if you remove it you cannot guarantee that your users are using the PIN. But it is not required.
What you could do is check why the compliance script is reporting non compliant
Hi Rene,
This walk through worked flawlessly for me. Appreciate the write up on this – very helpful.
Hi,
I don’t find any “Proactive remediations” in Intune: Reports -> Endpoint analytics -> ?
Hi Hedi,
With the latest update of Microsoft Intune the location of the proactive remediation scripts has been moved.
You can find it now here.
Devices -> Under the section Policy (submenu) -> Remediations
That is because they (Microsoft) moved the section to Devices-> Remediations
Hi,
This is really great, just what I’m looking for. It works really well to make users set a PIN and only runs if they haven’t done it.
I am having a problem though and am fairly new to compliance policies & limited PowerShell exposure so far. The problem I have is that when a PIN is not set, rather than marking the device not-compliant it shows that an error has been detected, when I look deeper I see the following in the “State Details” column for the KeyProtector Type setting:
“65010(Invalid datatype for the discovered setting)”.
I assume this is because when the detection script doesn’t find a TpmPin config present only TPM & Recovery Password and therefore returns a null. As I said, fairly new to this and any help to overcome this would be really appreciated.
Thanks
Hi Craig,
Can you run manually the detection script on your device where you have set the pin and on a device where the pin is not set?
Can you share me the results,
Kind Regards,
Rene
The PIN registration pop-up appears for the user; however, if they close the pop-up using the task manager or the taskbar, the pop-up does not appear again. Does anyone know how to resolve this?
Hi Kauan,
It should pop-up after a day again, The script checks for the txt file and will remove the txt file if it older than a day
Kind regards,
Rene
Hi, I am receiving an error message ‘65010’(invalid datatype for the discovered settings). Could you help me to solve the issue.
It shows error in compliance policy check- KeyProtectorType- error- 65010(invalid Datatype for the discovered settings).
Thanks,
Rani
Another interesting I just noted that after pressing ALT+F4 on the PIN prompt, it got vanished and is not appearing backe even after I rebooted the machine multiple times. Any suggestions?
First of all, thank you very much Rene for this extended version of the procedure what Oliver Kieselbach has developed. I went through step-by-step as you described in this blog and it works wonder for me in my test lab. However when I decrypted the drive and got it re-encrypted silently again by performing MDM refresh/sync again, I don’t see the PIN prompt unless I rebooted by test machine. Is there any workaround for this?
Hi Rene,
i actually found that by pressing alt-f4 or closing the window from taskbar makes it disappear, but what is strange is that the request to insert the PIN is not appearing anymore.
any suggestions?
Sounds awesome but I found some issues here,
I did manage to get the popup but after setting pin nothing really happens, box just disappears and according to manage-bde, pin is not set, Key Protectors stands as TPM + numerical password. Whenever I restart the device I do not see an Enter Pin screen also. I used the ready Intune package + added scripts/descriptions by copy-paste
Hi Andrew, after you enter the pin, can you check if an temp pin txt file will be created and is still on the location. Other question how is your bitlocker configuration. Do you use an antivirus solution what can cause the issue?