As an IT admin, ensuring the security of your organization's devices is paramount. One critical aspect is managing BitLocker recovery keys. But manually tracking these keys can be a daunting task. Fortunately, with the help of Microsoft Graph API and PowerShell, you can automate this process efficiently. In this article, we'll delve into a detailed script that not only tracks these keys but also alerts you when keys are missing. 🚀
Why Automate BitLocker Key Tracking?
Manually monitoring BitLocker keys for all managed devices can lead to human error, resulting in compromised security. Automation reduces the workload, ensures accuracy, and provides timely alerts for potential risks.
🔧 Prerequisites
- Microsoft 365 and Intune configured for your organization.
- Appropriate permissions to access the Microsoft Graph API.
- PowerShell 5.1 or newer with the Microsoft.Graph module installed.
- Connectivity to your SharePoint tenant.
🌐 Connecting to Microsoft Graph API
Using a Managed Identity simplifies the process, eliminating the need for stored credentials. Here's how you connect:
Connect-MgGraph -Identity -NoWelcome
Pro Tip: Use managed identities in Azure to connect securely without hardcoding credentials.
🏷️ Fetching Windows Devices
We begin by retrieving all Windows devices managed in your environment:
$devices = Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=operatingSystem eq 'Windows'" -Method GET
🔑 Checking for BitLocker Keys
For each device, we verify if a BitLocker recovery key is available:
foreach ($device in $devices.value) {
$keyUri = "https://graph.microsoft.com/beta/informationProtection/bitlocker/recoveryKeys?`$filter=deviceId eq '$($device.azureADDeviceId)'"
$keyResult = Invoke-MgGraphRequest -Uri $keyUri -Method GET
$hasKey = $keyResult.value.Count -gt 0
$AllResults += [PSCustomObject]{
DeviceName = $device.deviceName
SerialNumber = $device.serialNumber
AzureADDeviceId = $device.azureADDeviceId
ComplianceState = $device.complianceState
LastSync = $device.lastSyncDateTime
HasBitlockerKey = $hasKey
DateChecked = (Get-Date)
}
}
Worth knowing: This script checks the existence of keys in real-time, ensuring you always have the latest status.
📊 Exporting Results to Excel
We categorize the devices based on the availability of BitLocker keys and export the results to Excel files:
$Available | Export-Excel -Path $AvailablePath -WorksheetName "AvailableKeys" -AutoSize -ClearSheet $Missing | Export-Excel -Path $MissingPath -WorksheetName "MissingKeys" -AutoSize -ClearSheet
🔄 Uploading to SharePoint
Store your reports where your team can access them by uploading these files to a SharePoint folder:
function Upload-FileToSP {
param ($FilePath, $FileName)
$FileBytes = [System.IO.File]::ReadAllBytes($FilePath)
$UploadUri = "https://graph.microsoft.com/v1.0/sites/$SiteId/drives/$DriveId/root:/$FolderPath/$FileName:/content"
Invoke-MgGraphRequest -Uri $UploadUri -Method PUT -Body $FileBytes -ContentType "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
Upload-FileToSP -FilePath $AvailablePath -FileName $AvailableFile
Upload-FileToSP -FilePath $MissingPath -FileName $MissingFile
Pro Tip: Use folder structures in SharePoint to keep your reports organized by date.
📧 Alerting Your Team
If new devices are found without BitLocker keys, send an email alert:
if ($NewMissing.Count -gt 0) {
$MailBody = {
message = {
subject = "ALERT - New Devices Missing BitLocker Keys"
body = {
contentType = "Text"
content = "New devices missing BitLocker keys detected..."
}
toRecipients = @({ emailAddress = { address = "it@alphatecspine.com" }})
}
saveToSentItems = "false"
}
Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/users/it@alphatecspine.com/sendMail" -Method POST -Body ($MailBody | ConvertTo-Json -Depth 6)
}
💬 Notifying Through Teams
Additionally, you can notify your team directly in a Teams channel:
if ($NewMissing.Count -gt 0) {
$PostBody = {
body = {
contentType = "html"
content = "🚨 **New Devices Missing BitLocker Keys**..."
}
}
Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/teams/<TEAM_ID>/channels/<CHANNEL_ID>/messages" -Method POST -Body ($PostBody | ConvertTo-Json -Depth 5)
}
🔄 Azure Runbook Script
Automate the full process by setting up an Azure Runbook:
# Azure Automation Runbook Script
param()
# Authenticate to Azure
Connect-AzAccount -Identity
# Connect to Microsoft Graph
Connect-MgGraph -Identity
# Fetch devices
$devices = Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$filter=operatingSystem eq 'Windows'" -Method GET
# Check for BitLocker keys
foreach ($device in $devices.value) {
$keyUri = "https://graph.microsoft.com/beta/informationProtection/bitlocker/recoveryKeys?`$filter=deviceId eq '$($device.azureADDeviceId)'"
$keyResult = Invoke-MgGraphRequest -Uri $keyUri -Method GET
$hasKey = $keyResult.value.Count -gt 0
$AllResults += [PSCustomObject]{
DeviceName = $device.deviceName
SerialNumber = $device.serialNumber
AzureADDeviceId = $device.azureADDeviceId
ComplianceState = $device.complianceState
LastSync = $device.lastSyncDateTime
HasBitlockerKey = $hasKey
DateChecked = (Get-Date)
}
}
# Export results
$Available | Export-Excel -Path $AvailablePath -WorksheetName "AvailableKeys" -AutoSize -ClearSheet
$Missing | Export-Excel -Path $MissingPath -WorksheetName "MissingKeys" -AutoSize -ClearSheet
# Upload to SharePoint function here
function Upload-FileToSP {
param ($FilePath, $FileName)
$FileBytes = [System.IO.File]::ReadAllBytes($FilePath)
$UploadUri = "https://graph.microsoft.com/v1.0/sites/$SiteId/drives/$DriveId/root:/$FolderPath/$FileName:/content"
Invoke-MgGraphRequest -Uri $UploadUri -Method PUT -Body $FileBytes -ContentType "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
Upload-FileToSP -FilePath $AvailablePath -FileName $AvailableFile
Upload-FileToSP -FilePath $MissingPath -FileName $MissingFile
# Send alert through email
if ($NewMissing.Count -gt 0) {
$MailBody = {
message = {
subject = "ALERT - New Devices Missing BitLocker Keys"
body = {
contentType = "Text"
content = "New devices missing BitLocker keys detected..."
}
toRecipients = @({ emailAddress = { address = "it@alphatecspine.com" }})
}
saveToSentItems = "false"
}
Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/users/it@alphatecspine.com/sendMail" -Method POST -Body ($MailBody | ConvertTo-Json -Depth 6)
}
# Notify through Teams
if ($NewMissing.Count -gt 0) {
$PostBody = {
body = {
contentType = "html"
content = "🚨 **New Devices Missing BitLocker Keys**..."
}
}
Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/teams/<TEAM_ID>/channels/<CHANNEL_ID>/messages" -Method POST -Body ($PostBody | ConvertTo-Json -Depth 5)
}
🔍 Security & Performance Review
- Avoid hardcoding credentials. Use secure methods like Managed Identities.
- When processing large data sets, consider using pagination with the Graph API to prevent timeouts or memory issues.
- Ensure your scripts are running in a secure environment.
🔑 Conclusion
With this automated solution, tracking BitLocker keys becomes a streamlined process, minimizing the risk of unmanaged devices or misplaced encryption keys. By leveraging Microsoft Graph API and PowerShell, you not only enhance security but also maintain compliance effortlessly. Remember, in IT, the only thing better than fixing a problem is preventing it. 😊
Keep these automation insights at hand to ensure your corporate endpoints are always protected!