Worklet: Install BitLocker and store keys in device tag

  • 22 September 2020
  • 37 replies

Userlevel 3

Hello everyone,

This is just a script that will store bitlocker recovery keys in the device tags for whatever device the script is run on. Thought this would be an easier way to manage any bitlocker keys for those who will want to install it through automox rather than manually exporting keys or storing them via AD.

Only thing that needs changing is the API Key. Currently there is a placeholder of just “INSERT API KEY HERE” and you must add in your own for it to work.

Remediation Code:

$apiUrl = ""
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Bearer $apiKey")

$response = Invoke-RestMethod $apiUrl -Method 'GET' -Headers $headers -Body $body
$response | ConvertTo-Json

$currentMachineName = $env:COMPUTERNAME;

foreach($server in $response){
$name = $;
if($currentMachineName -eq $name){
$id = $
$organization_id = $server.organization_id
$server_group_id = $server.server_group_id
#Bitlocker Start
$keyPath = 'C:\temp'
$toEncrypt = Get-BitLockerVolume | Where-Object { $_.VolumeStatus -match 'Decrypted' }

# Loop through each Unencrypted Drives
# Enable Bitlocker and Export their Recovery Keys
foreach ( $drive in $toEncrypt )
$driveLetter = $drive.MountPoint.Replace(':','')
try {
#Enable Bitlocker
Enable-BitLocker -MountPoint $driveLetter -EncryptionMethod Aes128 -RecoveryPasswordProtector -SkipHardwareTest | Out-Null

#Export Key and Key ID to a File
$recID = (Get-BitLockerVolume -MountPoint $driveLetter).KeyProtector.KeyProtectorID
$recKey = (Get-BitLockerVolume -MountPoint $driveLetter).KeyProtector.RecoveryPassword
$keyAndID = "Recovery Key: $recKey | and Recovery ID: $recID"
#Set-Content -Path "$keyPath\BitlockerRecoveryKey_$driveLetter.txt" -Force -Value "Recovery Key ID: $recID"
#Add-Content -Path "$keyPath\BitlockerRecoveryKey_$driveLetter.txt" -Value "Recovery Key: $recKey"

#Modify device through API
## Now calling modify device API and set recID,recKey in tags
$headers.Add("Content-Type", "application/json")
$apiUrl = "$($id)?o=$($organization_id)"
$body = "{
`"server_group_id`": $server_group_id,
`"tags`": [
`"RecoveryID: $recID`",
`"RecoveryKey: $recKey`"

$response = Invoke-RestMethod $apiUrl -Method 'PUT' -Headers $headers -Body $body
$response | ConvertTo-Json
#endregion here is modify device API code ends
$KeyProperties = @()
$KeyObj = @()
$Computer = $env:Computername
$Keys = Get-BitlockerVolume -MountPoint C:
$selected = $Keys | Select-Object -ExpandProperty KeyProtector
$Selected[1] | select-Object KeyprotectorID, RecoveryPassword
Foreach ($S in $Selected) {
$KeyProperties = [pscustomobject]@{
Computer = $Computer
KeyProtectorID = $S.KeyProtectorID
RecoveryPassword = $S.RecoveryPassword
$KeyObj += $KeyProperties
$KeyObj[1] | Export-CSV "C:\$($Computer)_Keys.csv" -NoTypeInformation
Write-host $keyAndID
} catch {
Write-Output "Unable to Encrypt $($drive.MountPoint)"
#end of bitlocker code


37 replies

Userlevel 3

That would be the Remediation code. For Evaluation you could do can do something has simple as:

exit 1

or if you want to verify the machine is encrypted you could try something like this for the Evaluation:

$BLinfo = Get-Bitlockervolume

if($blinfo.ProtectionStatus -eq 'On' -and $blinfo.EncryptionPercentage -eq '100'){
Write-Output "'$env:computername - '$($blinfo.MountPoint)' is encrypted."
exit 1
} else {
Write-Output "'$env:computername - '$($blinfo.MountPoint)' is not encrypted."
exit 0

You should also test this on a test group before running it on any production machines.


Sorry…just getting back to testing this as I have been testing other scripts. I put this remediation code in and just put {exit 1} for the evaluation, input our API and tested on a device that has bit locker configured. The activity log shows the device name but the details section is BLANK and there are no tags added in the device info. Is there something i am missing?

Just wanted to say I’m in the same boat.

Userlevel 4

Initial testing shows that maybe Automox changed the way they accept arguments in their API for this call. Looks like it broke in our environment as well. Using the API docs listed here; we are getting a “400 Bad request”

Userlevel 2

I did some testing earlier and it looks like there’s some issues with the $body parameter in the worklet. The string prefix and terminator characters are missing, and there are some backticks in there that probably shouldn’t be. The $body parameter should look something like this:

$body = @"
"server_group_id": $server_group_id,
"tags": [
"RecoveryID: $recID",
"RecoveryKey: $recKey"
Userlevel 4

I have been doing a ton of work on this as well, and agree the issue lies within the body parameter. However, I think the issue we are seeing is that “groupID” is a required parameter, instead of optional as the docs list (my hunch is that it used to be optional, but must have been changed on the backend of the API).

Userlevel 2

Yes, the server_group_id is a required parameter. I’m not sure exactly when this might have changed, however it is called out in the yaml file as required. I’ll go ahead and update the docs page.

Userlevel 4

Is there any way we can request GroupID to be investigated to go back to optional? Refactoring our scripts to include this would be another layer of complexity that isn’t desired, or required.

Userlevel 2

I’m looking into that. Will get back to you as soon as I have more information.

Userlevel 2

@Mrichards I ran it by our engineers, and it looks like the server_group_id has been a required body parameter for a long time. I’m not sure whether it would be possible in the future to make it optional, but they’re looking into it. It was only marked as optional on the docs page due to an oversight.

Currently, passing the PUT /servers/{id} API call without that parameter will result in a 400 error, as you’ve described.


Is this still working/resolved, or broken due to the server_group_ID at this point?

Bumping this old thread to recommend a  modification.

Instead of $env:COMPUTERNAME, use [System.Net.Dns]::GetHostName().

$env returns the BIOS name, whereas Automox stores the full hostname.  If your full hostname is over 15 characters in length, the matching could fail.