Skip to content
Snippets Groups Projects
Commit b77c7c35 authored by Aleš Hegedüs's avatar Aleš Hegedüs
Browse files

BLRecoveryKey_Backup

parent 96cfc285
No related branches found
No related tags found
No related merge requests found
<#
.SYNOPSIS
Backup Bitlocker recovery Keys from Entra to Local SQL database.
.DESCRIPTION
Script will update attribute LastContactWithEntra on DB records and download bitlocker recovery keys, which are not in DB.
SQLServer module is required and backup of recovery Keys is possible only if script is executed with user interactive Graph sign in.
.NOTES
2024/11/21
https://www.muni.cz/lide/253297-ales-vasko
#>
#Requires -Version 7.0
[CmdletBinding(SupportsShouldProcess)]
Param ()
try {
#Start time of Script
$startDate = Get-Date
#Function for sending queries to DB
function Send-SqlQuery($sqlQuery) {
$result = Invoke-Sqlcmd -ServerInstance $dbConfig.ServerName -Database $dbConfig.DatabaseName -Query $sqlQuery -Username $dbCredential.UserName -Password $dbPassword -EncryptConnection
return $result
}
#Object for error log
$processedObject = $null
#DB Information
$dbConfigPath = "$PSScriptRoot\config_Backup-EntraIDBitlockerKeys.json"
$dbConfig = Get-Content -Raw -Path $dbConfigPath | ConvertFrom-Json
#Credentials for Database connection
$dbCredential = $host.ui.PromptForCredential("Database Credentials", "Please enter password for database account.", "", "")
$dbPassword = $($dbCredential.GetNetworkCredential().password)
#Modules
Import-Module Microsoft.Graph.Authentication
Import-Module -Name SqlServer
#Connection to MS Graph
Connect-MgGraph -Scopes "Device.Read.All", "BitLockerKey.ReadBasic.All", "BitLockerKey.Read.All" -NoWelcome
#Load all Database Records
Write-Host "Downloading Recovery Keys from DB ..." -ForegroundColor Yellow
$queryLoadAllBLRKRecords = "SELECT * FROM $($dbConfig.TableName)"
$blKeysDB = Send-SqlQuery($queryLoadAllBLRKRecords) | Group-Object -Property BitLockerId -AsHashTable
Write-Host "Downloaded $($blKeysDB.Keys.Count) Recovery Keys from DB." -ForegroundColor Green
#Download all device records from Entra
Write-Host "Downloading All Entra ID Devices ..." -ForegroundColor Yellow
$entraDeviceProperties = @("ApproximateLastSignInDateTime", "Id", "DeviceId", "DisplayName")
$allEntraDevices = Get-MgDevice -All -Property $entraDeviceProperties | Select-Object $entraDeviceProperties | Group-Object -Property DeviceId -AsHashTable
Write-Host "Downloaded $($allEntraDevices.Keys.Count) Devices from Entra ID." -ForegroundColor Green
#[PART 1] - Update Attribute LastContactWithEntra for records in DB with records from Entra
$updatedDBrecordsCount = 0
$index = 0
$numberOfBLKeysInDB = $blKeysDB.Keys.Count
foreach ($encryptionID in $blKeysDB.GetEnumerator()) {
#Progress bar
$index++
$progress = $index * 100 / $numberOfBLKeysInDB
$progress = [Math]::Ceiling($progress)
Write-Progress -Activity "Updating attribute Last Contact With Entra for DB Records" -Status "$progress% Complete:" -PercentComplete $progress
$processedObject = $encryptionID.Value.Id
$dbRecord = $encryptionID.Value
$entraRecord = $allEntraDevices["$($dbRecord.DeviceId)"]
if ($($entraRecord -ne $null) -and $([datetime]$dbRecord.LastContactWithEntra -lt [datetime]$entraRecord.ApproximateLastSignInDateTime)) {
$updatedDBrecordsCount ++
if ($PSCmdlet.ShouldProcess("$($dbRecord.DeviceId)", "DB Record Update - LastContactWithEntra")) {
$updateDateQuery = "UPDATE $($dbConfig.TableName) SET LastContactWithEntra='$($entraRecord.ApproximateLastSignInDateTime)' WHERE DeviceId='$($encryptionID.Value.DeviceId)'"
$null = Send-SqlQuery($updateDateQuery)
}
}
}
Write-Progress -Completed -Activity "Updating attribute Last Contact With Entra for DB Records"
Write-Host "Updated Last Contact With Entra ID for $updatedDBrecordsCount records in DB." -ForegroundColor Green
#[PART 2] - Backup missing recovery Keys to SQL DB
#Load All Bitlocker IDs from Entra
Write-Host "Downloading all encrypted devices from Entra ID ..." -ForegroundColor Yellow
$encryptedEntraDeviceProperties = @("DeviceId", "Id")
$allEntraBitLockerIDs = Get-MgInformationProtectionBitlockerRecoveryKey -All -Property $encryptedEntraDeviceProperties | Select-Object $encryptedEntraDeviceProperties
Write-Host "Downloaded all encrypted from Entra ID." -ForegroundColor Green
#Filter only keys which are not present in DB
Write-Host "Adding all missing BitLocker Recovery Keys from Entra to DB..." -ForegroundColor Yellow
$numberOfkeysToBeAddedtoDB = 0
$numberOfAllNewBLRK = $($allEntraBitLockerIDs | Where-Object { -not $($blKeysDB.ContainsKey($_.Id)) }).Count
$allEntraBitLockerIDs | Where-Object { -not $($blKeysDB.ContainsKey($_.Id)) } | ForEach-Object {
$numberOfkeysToBeAddedtoDB ++
$processedObject = $_.Id
#Progress bar
$progress = $numberOfkeysToBeAddedtoDB * 100 / $numberOfAllNewBLRK
$progress = [Math]::Ceiling($progress)
Write-Progress -Activity "Downloading new BitLocker Recovery Keys from Entra to DB" -Status "$progress% Complete:" -PercentComplete $progress
#Add created object to DB
if ($PSCmdlet.ShouldProcess("$($_.Id)", "Add BL Recovery Key to DB")) {
#Create object which will be added to DB
$entraDeviceRecord = $allEntraDevices[$_.DeviceId]
$recordOutput = [PSCustomObject]@{
DeviceName = $entraDeviceRecord.DisplayName
DeviceId = $entraDeviceRecord.DeviceId
BitLockerId = $_.Id
BitLockerRecoveryKey = Get-MgInformationProtectionBitlockerRecoveryKey -BitlockerRecoveryKeyId $($_.Id) -Property "Key" | Select-Object -ExpandProperty 'Key'
LastContactWithEntra = $entraDeviceRecord.ApproximateLastSignInDateTime
}
$addKeyRecordQuery = "INSERT INTO $($dbConfig.TableName)
(DeviceName, DeviceId, BitLockerId, BitLockerRecoveryKey, LastContactWithEntra) VALUES
('$($recordOutput.DeviceName)', '$($recordOutput.DeviceId)', '$($recordOutput.BitLockerId)', '$($recordOutput.BitLockerRecoveryKey)', '$($recordOutput.LastContactWithEntra)')"
$null = Send-SqlQuery($addKeyRecordQuery)
}
}
Write-Progress -Completed -Activity "Downloading new BitLocker Recovery Keys from Entra to DB"
Write-Host "Added $numberOfkeysToBeAddedtoDB BitLocker Recovery Keys from Entra to DB." -ForegroundColor Green
$endDate = Get-Date
$totalTime = $endDate - $startDate
Write-Host "Process Took $totalTime." -ForegroundColor Magenta
} catch {
$err = "[EntraDevices]:$processedObject [type]:$($_.Exception.gettype().fullname);[message]:$($_.Exception.Message);[invocationInfo]:$(($_.InvocationInfo | Select-Object ScriptName, ScriptLineNumber, PSScriptRoot, PSCommandPath, InvocationName) -join ',')"
Write-Host $err -ForegroundColor Red
}
\ No newline at end of file
{
"ServerName": "",
"DatabaseName": "",
"TableName": ""
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment