Worklet: Store Bitlocker Keys in Device Tags

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:

$apiKey = "INSERT API KEY HERE"
$apiUrl = "https://console.automox.com/api/servers/"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Bearer $apiKey")
#$headers.Add("Cookie", "ax_session=eyJpdiI6IlpqM3NxdU03Mk81dHg0RjBkOGZRQmc9PSIsInZhbHVlIjoiL0Z2QVljTVF3SkV2L0Jod0lKMUFHQ0dMalMxQVNNdkswNWRRb2hkN1NiTHBFcWk4S2pXempXU2hpQzhybHE4b3loREhXRUxKSHZPMDBmMHVHNERzVlU2enphQm1sTTA3U2FCSmNlU0lJSjdEKzdDRHRqZXBlNXFSUThWb01zNk5UdXZheXpUNlExeDJKRXdONlZBbFZsV0tYc1hVMkl1Sm1QMFBvcGxKSEZYMkJNS3FkOXpPSStVV1JwNGVEN3ZlYkl5dHhvZnNHNURzR1FjMEUvZCthVyt4S09ZQmt1R2xaQUFzOGJpTmozTVcrdWtMNVdNQUR1cUNwUi9lU0lDamJVVkoydm84UEdsR2NldEVENVQ2TTdweWVkeGJtdjJaeHp6MlVpSUZXUE92MXZqbU0vSjRFcG9CWDVjZkYzeGEycnN5RGZKbDJReFIvbzdKdXRoZ0VVRnEweXhGSHd1dWozWlhTSUhNMVNVMEVGV0Faakw3ZVVWUFI5NDRSSDJKR3BhdkZ5Yk9EeklkNGtPOEhLb1B0T3pJci9JMFpDMUk5dExXZmJINHZmSDk1c3c5QlcyTWwxZEs0V1orVlNmWjFYdVRUZTg1WVNFMVhsdG9STThYMmduWEc4T1A5VGpoU2d6WVRlWXY1N3ByVkFlRVlOcExqT1hxdnpIRHN1RzMiLCJtYWMiOiIzNzc3MzM2MWM0MmQxMTA4NjliZTk2MzEwOTg1NWQ5NWNmZTZhODBlZTQyZGQwMTM3YTI3YTJhMTgwYTg5NzcwIn0%3D")

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


$currentMachineName = $env:COMPUTERNAME;

foreach($server in $response){
	$name = $server.name;	
	if($currentMachineName -eq $name){
		$id = $server.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 = "https://console.automox.com/api/servers/$($id)?o=$($organization_id)"
				$body = "{
				    `"server_group_id`": $server_group_id,
				    `"tags`": [
				        `"RecoveryID: $recID`",
						`"RecoveryKey: $recKey`"
				    ]
				}"
				
				$body 
				$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
	
	}
}
2 Likes

Okay this is freaking awesome! Nicely done @JHagstrom! I married my modified bitlocker remediation from our previous post with the addition you provided. This is modified in the sense that it will check for both decrypted + encrypted drives and populate them properly in the tags field. Additionally, I removed any keys being stored on the local drive and only check for the C drive to be encrypted (We have a lot of users who put in external media that cannot be encrypted). Additionally, I also nuked the RecoveryID since it provides little value to us and takes up a tag slot.
Overall, This is an amazing idea and the way you parse through the API data is sweet! Let me know what you think of my additions.

Function Invoke-AutomoxAPI{
[cmdletbinding()]
Param()

$apiKey = "YOUR API KEY"
$apiUrl = "https://console.automox.com/api/servers/"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Bearer $apiKey")

#Get all devices in the org to parse
$response = Invoke-RestMethod $apiUrl -Method 'GET' -Headers $headers -Body $body
$response | ConvertTo-Json
$currentMachineName = $env:COMPUTERNAME;
#Perform loop to figure out what our deviceID is and populate variables
foreach($server in $response){
	$name = $server.name;	
	if($currentMachineName -eq $name){
		$id = $server.id
		$organization_id = $server.organization_id
        $server_group_id = $server.server_group_id

    	#Modify device through API
	    ## Now calling modify device API and set recKey in tags
		$headers.Add("Content-Type", "application/json")
		$apiUrl = "https://console.automox.com/api/servers/$($id)?o=$($organization_id)"
				$body = "{
				    `"server_group_id`": $server_group_id,
				    `"tags`": [
				        `"RecoveryKey: $recKey`"
				    ]
                }"
                $body 
				$response = Invoke-RestMethod $apiUrl -Method 'PUT' -Headers $headers -Body $body
				$response | ConvertTo-Json
        }
    }
}
$toEncrypt = Get-BitLockerVolume | Where-Object { $_.VolumeStatus -match 'FullyDecrypted' -and $_.MountPoint -match 'c:'}
$Encrypted = Get-BitLockerVolume | Where-Object { $_.VolumeStatus -match 'FullyEncrypted' -and $_.MountPoint -match 'c:'}
# Enable Bitlocker if its not already and Export the Recovery Key
foreach ( $drive in $toEncrypt ) {
        $driveLetter = $drive.MountPoint.Replace(':','')
     try {
        #Enable Bitlocker
        Enable-BitLocker -MountPoint 'C:' -EncryptionMethod Aes256 -SkipHardwareTest -UsedSpaceOnly -RecoveryPasswordProtector | Out-Null        
        #Save Key into variable to push to AutoMox
        $recKey = (Get-BitLockerVolume -MountPoint $driveLetter).KeyProtector.RecoveryPassword
        Invoke-AutomoxAPI
         } catch {
            Write-Output "Unable to encrypt drive"
         }
    }
#Find already bitlockered volume and export the recovery key
foreach ( $drive in $Encrypted ) {
        $driveLetter = $drive.MountPoint.Replace(':','')
        try {            
            #Save Key into variable to push to AutoMox
            $recKey = (Get-BitLockerVolume -MountPoint $driveLetter).KeyProtector.RecoveryPassword
            Invoke-AutomoxAPI
        } catch {
            Write-Output "Unable to get already encrypted drive"
        }
      }
3 Likes

I tested both scripts but got no results, just a lot of data in the the activity log report details column. Any suggestions? Do you mean for this workflow to display the keyID and keycode here: image ?

Hey @cfrieberg, Yeah thats where we have the keys end up in the tags field. the first things I would check are this:

1: Do you have a TPM chip on your machine? Can you bitlocker manually? Can you invoke this specific command
Enable-BitLocker -MountPoint 'C:' -EncryptionMethod Aes256 -SkipHardwareTest -UsedSpaceOnly -RecoveryPasswordProtector

2: Powershell - Get-BitlockerVolume and make sure you are either “FullyDecrypted” or “FullyEncrypted”? You can change that “Where-Object” status to whatever fits your needs

3: I like to use Microsoft Visual Code as my IDE and setup breakpoints throughout the script, and run in debug mode. That way I can step through each line of code and see exactly what its doing.

Feel free to PM me if you need any more assistance and we can debug :smiley:

2 Likes

Hello @cfrieberg !

For sure try out what rmatthews suggested. A few other things to check would be:

1- Make sure you have no group policies related to Bitlocker key storage that might force the keys to be stored in AD or anything related.

2- As @Mrichards suggeted in #3 you can try running the script in a local powershell IDE and see if it outputs any specific errors to get a better idea of whats going on.

2 Likes

Hey @Mrichards,

Great additions! I would suggest if anyone finding this to use this above as its a great adjustment to the original one I posted.

2 Likes