Files
DistractADD cfddd4fad2 Added Files
2021-07-06 13:16:46 +10:00

965 lines
39 KiB
PowerShell

#requires -Version 5.0 -RunAsAdministrator
<#
.SYNOPSIS
Enable BitLocker with both TPM and recovery password key protectors on Windows 10 devices.
.DESCRIPTION
Enable BitLocker with both TPM and recovery password key protectors on Windows 10 devices.
.PARAMETER EncryptionMethod
Define the encryption method to be used when enabling BitLocker.
.PARAMETER OperationalMode
Set the operational mode of this script.
.PARAMETER CompanyName
Set the company name to be used as registry root when running in Backup mode.
.NOTES
Version 1.0.1
Adopted version of Enable-BitLockerEncryption.ps1 from Nickolaj Andersen (@NickolajA)
#>
[CmdletBinding(SupportsShouldProcess)]
param (
[ValidateNotNullOrEmpty()]
[ValidateSet('Aes128', 'Aes256', 'XtsAes128', 'XtsAes256')]
[string]
$EncryptionMethod = 'XtsAes256',
[ValidateNotNullOrEmpty()]
[ValidateSet('Encrypt', 'Backup')]
[string]
$OperationalMode = 'Encrypt',
[ValidateNotNullOrEmpty()]
[string]
$CompanyName = 'enabling Technology'
)
begin
{
Write-Output -InputObject 'Enable BitLocker with both TPM and recovery password key protectors'
#region
$STP = 'Stop'
$SCT = 'SilentlyContinue'
#endregion
if (Get-Command -Name 'Set-MpPreference' -ErrorAction $SCT)
{
$null = (Set-MpPreference -EnableControlledFolderAccess Disabled -Force -ErrorAction $SCT)
}
#region
function Write-LogEntry
{
<#
.SYNOPSIS
Describe purpose of "Write-LogEntry" in 1-2 sentences.
.DESCRIPTION
Add a more complete description of what the function does.
.PARAMETER Value
Describe parameter -Value.
.PARAMETER Severity
Describe parameter -Severity.
.EXAMPLE
Write-LogEntry -Value Value -Severity Value
Describe what this call does
.NOTES
Place additional notes here.
.LINK
URLs to related sites
The first link is opened by Get-Help -Online Write-LogEntry
.INPUTS
List of input types that are accepted by this function.
.OUTPUTS
List of output types produced by this function.
#>
param (
[parameter(Mandatory, HelpMessage = 'Value added to the log file.')]
[ValidateNotNullOrEmpty()]
[string]
$Value,
[parameter(Mandatory, HelpMessage = 'Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.')]
[ValidateNotNullOrEmpty()]
[ValidateSet('1', '2', '3')]
[string]
$Severity
)
begin
{
$SCT = 'SilentlyContinue'
}
process
{
# Determine log file location
$paramJoinPath = @{
Path = (Join-Path -Path $env:windir -ChildPath 'Temp' -ErrorAction $SCT)
ChildPath = 'Enable-BitLockerEncryption.log'
ErrorAction = $SCT
}
$LogFilePath = (Join-Path @paramJoinPath)
# Construct time stamp for log entry
$paramTestPath = @{
Path = 'variable:global:TimezoneBias'
ErrorAction = $SCT
}
if (-not (Test-Path @paramTestPath))
{
[string]$global:TimezoneBias = [TimeZoneInfo]::Local.GetUtcOffset((Get-Date)).TotalMinutes
if ($TimezoneBias -match '^-')
{
$TimezoneBias = $TimezoneBias.Replace('-', '+')
}
else
{
$TimezoneBias = '-' + $TimezoneBias
}
}
$Time = -join @((Get-Date -Format 'HH:mm:ss.fff'), $TimezoneBias)
# Construct date for log entry
$Date = (Get-Date -Format 'MM-dd-yyyy')
# Construct context for log entry
$Context = $([Security.Principal.WindowsIdentity]::GetCurrent().Name)
# Construct final log entry
$LogText = "<![LOG[$($Value)]LOG]!><time=""$($Time)"" date=""$($Date)"" component=""BitLockerEncryption"" context=""$($Context)"" type=""$($Severity)"" thread=""$($PID)"" file="""">"
# Add value to log file
try
{
$paramOutFile = @{
Append = $true
NoClobber = $true
Encoding = 'Default'
FilePath = $LogFilePath
ErrorAction = 'Stop'
}
$null = ($LogText | Out-File @paramOutFile)
}
catch
{
Write-Warning -Message "Unable to append log entry to Enable-BitLockerEncryption.log file. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)"
}
}
}
function Invoke-Executable
{
<#
.SYNOPSIS
Describe purpose of "Invoke-Executable" in 1-2 sentences.
.DESCRIPTION
Add a more complete description of what the function does.
.PARAMETER FilePath
Describe parameter -FilePath.
.PARAMETER Arguments
Describe parameter -Arguments.
.EXAMPLE
Invoke-Executable -FilePath Value -Arguments Value
Describe what this call does
.NOTES
Place additional notes here.
.LINK
URLs to related sites
The first link is opened by Get-Help -Online Invoke-Executable
.INPUTS
List of input types that are accepted by this function.
.OUTPUTS
List of output types produced by this function.
#>
param (
[parameter(Mandatory, HelpMessage = 'Specify the file name or path of the executable to be invoked, including the extension')]
[ValidateNotNullOrEmpty()]
[string]
$FilePath,
[ValidateNotNull()]
[string]
$Arguments
)
process
{
# Construct a hash-table for default parameter splatting
$SplatArgs = @{
FilePath = $FilePath
NoNewWindow = $true
Passthru = $true
RedirectStandardOutput = 'null.txt'
ErrorAction = 'Stop'
}
# Add ArgumentList param if present
if (-not ([string]::IsNullOrEmpty($Arguments)))
{
$SplatArgs.Add('ArgumentList', $Arguments)
}
# Invoke executable and wait for process to exit
try
{
$Invocation = (Start-Process @SplatArgs)
$Handle = $Invocation.Handle
$Invocation.WaitForExit()
# Remove redirected output file
$paramRemoveItem = @{
Path = (Join-Path -Path $PSScriptRoot -ChildPath 'null.txt' -ErrorAction Continue)
Force = $true
}
$null = (Remove-Item @paramRemoveItem)
}
catch
{
Write-Warning -Message $_.Exception.Message
break
}
return $Invocation.ExitCode
}
}
function Test-RegistryValue
{
<#
.SYNOPSIS
Describe purpose of "Test-RegistryValue" in 1-2 sentences.
.DESCRIPTION
Add a more complete description of what the function does.
.PARAMETER Path
Describe parameter -Path.
.PARAMETER Name
Describe parameter -Name.
.EXAMPLE
Test-RegistryValue -Path Value -Name Value
Describe what this call does
.NOTES
Place additional notes here.
.LINK
URLs to related sites
The first link is opened by Get-Help -Online Test-RegistryValue
.INPUTS
List of input types that are accepted by this function.
.OUTPUTS
List of output types produced by this function.
#>
param (
[parameter(Mandatory, HelpMessage = 'Add help message for user')]
[ValidateNotNullOrEmpty()]
[string]
$Path,
[ValidateNotNullOrEmpty()]
[string]
$Name
)
begin
{
# If item property value exists return True, else catch the failure and return False
$STP = 'Stop'
}
process
{
try
{
if ($PSBoundParameters['Name'])
{
$paramGetItemProperty = @{
Path = $Path
ErrorAction = $STP
}
$Existence = (Get-ItemProperty @paramGetItemProperty | Select-Object -ExpandProperty $Name -ErrorAction $STP)
}
else
{
$paramGetItemProperty = @{
Path = $Path
ErrorAction = $STP
}
$Existence = (Get-ItemProperty @paramGetItemProperty)
}
if ($Existence)
{
return $true
}
}
catch
{
return $false
}
}
}
function Set-RegistryValue
{
<#
.SYNOPSIS
Describe purpose of "Set-RegistryValue" in 1-2 sentences.
.DESCRIPTION
Add a more complete description of what the function does.
.PARAMETER Path
Describe parameter -Path.
.PARAMETER Name
Describe parameter -Name.
.PARAMETER Value
Describe parameter -Value.
.EXAMPLE
Set-RegistryValue -Path Value -Name Value -Value Value
Describe what this call does
.NOTES
Place additional notes here.
.LINK
URLs to related sites
The first link is opened by Get-Help -Online Set-RegistryValue
.INPUTS
List of input types that are accepted by this function.
.OUTPUTS
List of output types produced by this function.
#>
param (
[parameter(Mandatory, HelpMessage = 'Add help message for user')]
[ValidateNotNullOrEmpty()]
[string]
$Path,
[parameter(Mandatory, HelpMessage = 'Add help message for user')]
[ValidateNotNullOrEmpty()]
[string]
$Name,
[parameter(Mandatory, HelpMessage = 'Add help message for user')]
[ValidateNotNullOrEmpty()]
[string]
$Value
)
begin
{
$SCT = 'SilentlyContinue'
$STP = 'Stop'
}
process
{
try
{
$paramGetItemProperty = @{
Path = $Path
Name = $Name
ErrorAction = $SCT
}
$RegistryValue = (Get-ItemProperty @paramGetItemProperty)
if ($RegistryValue)
{
$paramSetItemProperty = @{
Path = $Path
Name = $Name
Value = $Value
Force = $true
ErrorAction = $STP
}
$null = (Set-ItemProperty @paramSetItemProperty)
}
else
{
$paramNewItemProperty = @{
Path = $Path
Name = $Name
PropertyType = 'String'
Value = $Value
Force = $true
ErrorAction = $STP
}
$null = (New-ItemProperty @paramNewItemProperty)
}
}
catch
{
Write-LogEntry -Value "Failed to create or update registry value '$($Name)' in '$($Path)'. Error message: $($_.Exception.Message)" -Severity 3
}
}
}
#endregion
}
process
{
# Check if we're running as a 64-bit process or not
if (-not [Environment]::Is64BitProcess)
{
# Get the sysnative path for powershell.exe
$paramJoinPath = @{
Path = ($PSHOME.ToLower().Replace('syswow64', 'sysnative'))
ChildPath = 'powershell.exe'
}
$SysNativePowerShell = (Join-Path @paramJoinPath)
# Construct new ProcessStartInfo object to restart powershell.exe as a 64-bit process and re-run scipt
$ProcessStartInfo = (New-Object -TypeName System.Diagnostics.ProcessStartInfo)
$ProcessStartInfo.FileName = $SysNativePowerShell
$ProcessStartInfo.Arguments = "-ExecutionPolicy Bypass -File ""$($PSCommandPath)"""
$ProcessStartInfo.RedirectStandardOutput = $true
$ProcessStartInfo.RedirectStandardError = $true
$ProcessStartInfo.UseShellExecute = $false
$ProcessStartInfo.WindowStyle = 'Hidden'
$ProcessStartInfo.CreateNoWindow = $true
# Instatiate the new 64-bit process
$Process = [Diagnostics.Process]::Start($ProcessStartInfo)
# Read standard error output to determine if the 64-bit script process somehow failed
$ErrorOutput = $Process.StandardError.ReadToEnd()
if ($ErrorOutput)
{
Write-Error -Message $ErrorOutput
}
}
else
{
try
{
# Define the company registry root key
$RegistryRootPath = "HKLM:\SOFTWARE\$($CompanyName)"
if (-not (Test-RegistryValue -Path $RegistryRootPath))
{
Write-LogEntry -Value 'Attempting to create registry root path for recovery password escrow results' -Severity 1
$paramNewItem = @{
Path = $RegistryRootPath
ItemType = 'Directory'
Force = $true
ErrorAction = $STP
}
$null = (New-Item @paramNewItem)
}
}
catch
{
Write-LogEntry -Value "An error occurred while creating registry root item '$($RegistryRootPath)'. Error message: $($_.Exception.Message)" -Severity 3
}
# Switch execution context depending on selected operational mode for the script as parameter input
switch ($OperationalMode)
{
'Encrypt'
{
Write-LogEntry -Value "Current operational mode for script: $($OperationalMode)" -Severity 1
try
{
try
{
# Check if TPM chip is currently owned, if not take ownership
$paramGetWmiObject = @{
Namespace = 'root\cimv2\Security\MicrosoftTPM'
Class = 'Win32_TPM'
}
$TPMClass = (Get-WmiObject @paramGetWmiObject)
$IsTPMOwned = $TPMClass.IsOwned().IsOwned
if ($IsTPMOwned -eq $false)
{
Write-LogEntry -Value "TPM chip is currently not owned, value from WMI class method 'IsOwned' was: $($IsTPMOwned)" -Severity 1
# Generate a random pass phrase to be used when taking ownership of TPM chip
$NewPassPhrase = (New-Guid).Guid.Replace('-', '').SubString(0, 14)
# Construct owner auth encoded string
$NewOwnerAuth = $TPMClass.ConvertToOwnerAuth($NewPassPhrase).OwnerAuth
# Attempt to take ownership of TPM chip
$Invocation = $TPMClass.TakeOwnership($NewOwnerAuth)
if ($Invocation.ReturnValue -eq 0)
{
Write-LogEntry -Value 'TPM chip ownership was successfully taken' -Severity 1
}
else
{
Write-LogEntry -Value "Failed to take ownership of TPM chip, return value from invocation: $($Invocation.ReturnValue)" -Severity 3
}
}
else
{
Write-LogEntry -Value 'TPM chip is currently owned, will not attempt to take ownership' -Severity 1
}
}
catch
{
Write-LogEntry -Value "An error occurred while taking ownership of TPM chip. Error message: $($_.Exception.Message)" -Severity 3
}
try
{
# Retrieve the current encryption status of the operating system drive
Write-LogEntry -Value 'Attempting to retrieve the current encryption status of the operating system drive' -Severity 1
$paramGetBitLockerVolume = @{
MountPoint = $env:SystemRoot
ErrorAction = $STP
}
$BitLockerOSVolume = (Get-BitLockerVolume @paramGetBitLockerVolume)
if ($BitLockerOSVolume)
{
# Determine whether BitLocker is turned on or off
if (($BitLockerOSVolume.VolumeStatus -like 'FullyDecrypted') -or ($BitLockerOSVolume.KeyProtector.Count -eq 0))
{
Write-LogEntry -Value "Current encryption status of the operating system drive was detected as: $($BitLockerOSVolume.VolumeStatus)" -Severity 1
try
{
# Enable BitLocker with TPM key protector
Write-LogEntry -Value "Attempting to enable BitLocker protection with TPM key protector for mount point: $($env:SystemRoot)" -Severity 1
$paramEnableBitLocker = @{
MountPoint = $BitLockerOSVolume.MountPoint
TpmProtector = $true
UsedSpaceOnly = $true
EncryptionMethod = $EncryptionMethod
SkipHardwareTest = $true
ErrorAction = $STP
}
$null = (Enable-BitLocker @paramEnableBitLocker)
}
catch
{
Write-LogEntry -Value "An error occurred while enabling BitLocker with TPM key protector for mount point '$($env:SystemRoot)'. Error message: $($_.Exception.Message)" -Severity 3
}
try
{
# Enable BitLocker with recovery password key protector
Write-LogEntry -Value "Attempting to enable BitLocker protection with recovery password key protector for mount point: $($env:SystemRoot)" -Severity 1
$paramEnableBitLocker = @{
MountPoint = $BitLockerOSVolume.MountPoint
RecoveryPasswordProtector = $true
UsedSpaceOnly = $true
EncryptionMethod = $EncryptionMethod
SkipHardwareTest = $true
ErrorAction = $STP
}
$null = (Enable-BitLocker @paramEnableBitLocker)
}
catch
{
Write-LogEntry -Value "An error occurred while enabling BitLocker with recovery password key protector for mount point '$($env:SystemRoot)'. Error message: $($_.Exception.Message)" -Severity 3
}
}
elseif (($BitLockerOSVolume.VolumeStatus -like 'FullyEncrypted') -or ($BitLockerOSVolume.VolumeStatus -like 'UsedSpaceOnly'))
{
Write-LogEntry -Value "Current encryption status of the operating system drive was detected as: $($BitLockerOSVolume.VolumeStatus)" -Severity 1
Write-LogEntry -Value 'Validating that all desired key protectors are enabled' -Severity 1
# Validate that not only the TPM protector is enabled, add recovery password protector
if ($BitLockerOSVolume.KeyProtector.Count -lt 2)
{
if ($BitLockerOSVolume.KeyProtector.KeyProtectorType -like 'Tpm')
{
Write-LogEntry -Value 'Recovery password key protector is not present' -Severity 1
try
{
# Enable BitLocker with TPM key protector
Write-LogEntry -Value "Attempting to enable BitLocker protection with recovery password key protector for mount point: $($env:SystemRoot)" -Severity 1
$paramEnableBitLocker = @{
MountPoint = $BitLockerOSVolume.MountPoint
RecoveryPasswordProtector = $true
UsedSpaceOnly = $true
EncryptionMethod = $EncryptionMethod
SkipHardwareTest = $true
ErrorAction = $STP
}
$null = (Enable-BitLocker @paramEnableBitLocker)
}
catch
{
Write-LogEntry -Value "An error occurred while enabling BitLocker with TPM key protector for mount point '$($env:SystemRoot)'. Error message: $($_.Exception.Message)" -Severity 3
}
}
if ($BitLockerOSVolume.KeyProtector.KeyProtectorType -like 'RecoveryPassword')
{
Write-LogEntry -Value 'TPM key protector is not present' -Severity 1
try
{
# Add BitLocker recovery password key protector
Write-LogEntry -Value "Attempting to enable BitLocker protection with TPM key protector for mount point: $($env:SystemRoot)" -Severity 1
$paramEnableBitLocker = @{
MountPoint = $BitLockerOSVolume.MountPoint
TpmProtector = $true
UsedSpaceOnly = $true
EncryptionMethod = $EncryptionMethod
SkipHardwareTest = $true
ErrorAction = $STP
}
$null = (Enable-BitLocker @paramEnableBitLocker)
}
catch
{
Write-LogEntry -Value "An error occurred while enabling BitLocker with recovery password key protector for mount point '$($env:SystemRoot)'. Error message: $($_.Exception.Message)" -Severity 3
}
}
}
else
{
# BitLocker is in wait state
Invoke-Executable -FilePath 'manage-bde.exe' -Arguments "-On $($BitLockerOSVolume.MountPoint) -UsedSpaceOnly"
}
}
else
{
Write-LogEntry -Value "Current encryption status of the operating system drive was detected as: $($BitLockerOSVolume.VolumeStatus)" -Severity 1
}
# Validate that previous configuration was successful and all key protectors have been enabled and encryption is on
$paramGetBitLockerVolume = @{
MountPoint = $env:SystemRoot
}
$BitLockerOSVolume = (Get-BitLockerVolume @paramGetBitLockerVolume)
# Wait for encryption to complete
if ($BitLockerOSVolume.VolumeStatus -like 'EncryptionInProgress')
{
do
{
$paramGetBitLockerVolume = @{
MountPoint = $env:SystemRoot
}
$BitLockerOSVolume = (Get-BitLockerVolume @paramGetBitLockerVolume)
Write-LogEntry -Value "Current encryption percentage progress: $($BitLockerOSVolume.EncryptionPercentage)" -Severity 1
Write-LogEntry -Value 'Waiting for BitLocker encryption progress to complete, sleeping for 15 seconds' -Severity 1
Start-Sleep -Seconds 15
}
until ($BitLockerOSVolume.EncryptionPercentage -eq 100)
Write-LogEntry -Value 'Encryption of operating system drive has now completed' -Severity 1
}
if (($BitLockerOSVolume.VolumeStatus -like 'FullyEncrypted') -and ($BitLockerOSVolume.KeyProtector.Count -eq 2))
{
try
{
# Attempt to backup recovery password to Azure AD device object
Write-LogEntry -Value 'Attempting to backup recovery password to Azure AD device object' -Severity 1
$RecoveryPasswordKeyProtector = $BitLockerOSVolume.KeyProtector | Where-Object {
$_.KeyProtectorType -like 'RecoveryPassword'
}
if ($RecoveryPasswordKeyProtector)
{
$paramBackupToAADBitLockerKeyProtector = @{
MountPoint = $BitLockerOSVolume.MountPoint
KeyProtectorId = $RecoveryPasswordKeyProtector.KeyProtectorId
ErrorAction = $STP
}
$null = (BackupToAAD-BitLockerKeyProtector @paramBackupToAADBitLockerKeyProtector)
Write-LogEntry -Value 'Successfully backed up recovery password details' -Severity 1
}
else
{
Write-LogEntry -Value 'Unable to determine proper recovery password key protector for backing up of recovery password details' -Severity 2
}
}
catch
{
Write-LogEntry -Value "An error occurred while attempting to backup recovery password to Azure AD. Error message: $($_.Exception.Message)" -Severity 3
# Copy executing script to system temporary directory
Write-LogEntry -Value 'Attempting to copy executing script to system temporary directory' -Severity 1
$paramJoinPath = @{
Path = $env:SystemRoot
ChildPath = 'Temp'
}
$SystemTemp = (Join-Path @paramJoinPath)
$paramTestPath = @{
Path = (Join-Path -Path $SystemTemp -ChildPath "$($MyInvocation.MyCommand.Name)")
PathType = 'Leaf'
}
if (-not (Test-Path @paramTestPath))
{
try
{
# Copy executing script
Write-LogEntry -Value 'Copying executing script to staging folder for scheduled task usage' -Severity 1
$paramCopyItem = @{
Path = $MyInvocation.MyCommand.Definition
Destination = $SystemTemp
ErrorAction = $STP
}
$null = (Copy-Item @paramCopyItem)
try
{
# Create escrow scheduled task to backup recovery password to Azure AD at a later time
$paramNewScheduledTaskAction = @{
Execute = 'powershell.exe'
Argument = "-ExecutionPolicy Bypass -NoProfile -File $($SystemTemp)\$($MyInvocation.MyCommand.Name) -OperationalMode Backup"
ErrorAction = $STP
}
$TaskAction = (New-ScheduledTaskAction @paramNewScheduledTaskAction)
$paramNewScheduledTaskTrigger = @{
AtLogOn = $true
ErrorAction = $STP
}
$TaskTrigger = (New-ScheduledTaskTrigger @paramNewScheduledTaskTrigger)
$paramNewScheduledTaskSettingsSet = @{
AllowStartIfOnBatteries = $true
Hidden = $true
DontStopIfGoingOnBatteries = $true
Compatibility = 'Win8'
RunOnlyIfNetworkAvailable = $true
MultipleInstances = 'IgnoreNew'
ErrorAction = $STP
}
$TaskSettings = (New-ScheduledTaskSettingsSet @paramNewScheduledTaskSettingsSet)
$paramNewScheduledTaskPrincipal = @{
UserId = 'NT AUTHORITY\SYSTEM'
LogonType = 'ServiceAccount'
RunLevel = 'Highest'
ErrorAction = $STP
}
$TaskPrincipal = (New-ScheduledTaskPrincipal @paramNewScheduledTaskPrincipal)
$paramNewScheduledTask = @{
Action = $TaskAction
Principal = $TaskPrincipal
Settings = $TaskSettings
Trigger = $TaskTrigger
ErrorAction = $STP
}
$ScheduledTask = (New-ScheduledTask @paramNewScheduledTask)
$paramRegisterScheduledTask = @{
InputObject = $ScheduledTask
TaskName = 'Backup BitLocker Recovery Password to Azure AD'
TaskPath = '\Microsoft'
ErrorAction = $STP
}
$null = (Register-ScheduledTask @paramRegisterScheduledTask)
try
{
# Attempt to create BitLocker recovery password escrow registry value
$paramTestRegistryValue = @{
Path = $RegistryRootPath
Name = 'BitLockerEscrowResult'
}
if (-not (Test-RegistryValue @paramTestRegistryValue))
{
Write-LogEntry -Value "Setting initial 'BitLockerEscrowResult' registry value to: None" -Severity 1
$paramSetRegistryValue = @{
Path = $RegistryRootPath
Name = 'BitLockerEscrowResult'
Value = 'None'
}
$null = (Set-RegistryValue @paramSetRegistryValue)
}
}
catch
{
Write-LogEntry -Value "Unable to register scheduled task for backup of recovery password. Error message: $($_.Exception.Message)" -Severity 3
}
}
catch
{
Write-LogEntry -Value "Unable to register scheduled task for backup of recovery password. Error message: $($_.Exception.Message)" -Severity 3
}
}
catch
{
Write-LogEntry -Value "Unable to stage script in system temporary directory for scheduled task. Error message: $($_.Exception.Message)" -Severity 3
}
}
}
}
else
{
Write-LogEntry -Value 'Validation of current encryption status for operating system drive was not successful' -Severity 2
Write-LogEntry -Value "Current volume status for mount point '$($BitLockerOSVolume.MountPoint)': $($BitLockerOSVolume.VolumeStatus)" -Severity 2
Write-LogEntry -Value "Count of enabled key protectors for volume: $($BitLockerOSVolume.KeyProtector.Count)" -Severity 2
}
}
else
{
Write-LogEntry -Value 'Current encryption status query returned an empty result, this was not expected at this point' -Severity 2
}
}
catch
{
Write-LogEntry -Value "An error occurred while retrieving the current encryption status of operating system drive. Error message: $($_.Exception.Message)" -Severity 3
}
}
catch
{
Write-LogEntry -Value "An error occurred while importing the BitLocker module. Error message: $($_.Exception.Message)" -Severity 3
}
}
'Backup'
{
Write-LogEntry -Value "Current operational mode for script: $($OperationalMode)" -Severity 1
# Retrieve the current encryption status of the operating system drive
$paramGetBitLockerVolume = @{
MountPoint = $env:SystemRoot
}
$BitLockerOSVolume = (Get-BitLockerVolume @paramGetBitLockerVolume)
# Attempt to backup recovery password to Azure AD device object if volume is encrypted
if (($BitLockerOSVolume.VolumeStatus -like 'FullyEncrypted') -and ($BitLockerOSVolume.KeyProtector.Count -eq 2))
{
try
{
$paramGetItemPropertyValue = @{
Path = $RegistryRootPath
Name = 'BitLockerEscrowResult'
ErrorAction = $STP
}
$BitLockerEscrowResultsValue = (Get-ItemPropertyValue @paramGetItemPropertyValue)
if ($BitLockerEscrowResultsValue -match 'None|False')
{
try
{
Write-LogEntry -Value 'Attempting to backup recovery password to Azure AD device object' -Severity 1
$RecoveryPasswordKeyProtector = $BitLockerOSVolume.KeyProtector | Where-Object {
$_.KeyProtectorType -like 'RecoveryPassword'
}
if ($RecoveryPasswordKeyProtector)
{
$paramBackupToAADBitLockerKeyProtector = @{
MountPoint = $BitLockerOSVolume.MountPoint
KeyProtectorId = $RecoveryPasswordKeyProtector.KeyProtectorId
ErrorAction = $STP
}
$null = (BackupToAAD-BitLockerKeyProtector @paramBackupToAADBitLockerKeyProtector)
$paramSetRegistryValue = @{
Path = $RegistryRootPath
Name = 'BitLockerEscrowResult'
Value = 'True'
}
$null = (Set-RegistryValue @paramSetRegistryValue)
Write-LogEntry -Value 'Successfully backed up recovery password details' -Severity 1
}
else
{
Write-LogEntry -Value 'Unable to determine proper recovery password key protector for backing up of recovery password details' -Severity 2
}
}
catch
{
Write-LogEntry -Value "An error occurred while attempting to backup recovery password to Azure AD. Error message: $($_.Exception.Message)" -Severity 3
$paramSetRegistryValue = @{
Path = $RegistryRootPath
Name = 'BitLockerEscrowResult'
Value = 'False'
}
$null = (Set-RegistryValue @paramSetRegistryValue)
}
}
else
{
Write-LogEntry -Value "Value for 'BitLockerEscrowResults' was '$($BitLockerEscrowResultsValue)', will not attempt to backup recovery password once more" -Severity 1
try
{
# Disable scheduled task
$paramGetScheduledTask = @{
TaskName = 'Backup BitLocker Recovery Password to Azure AD'
ErrorAction = $STP
}
$ScheduledTask = (Get-ScheduledTask @paramGetScheduledTask)
$paramDisableScheduledTask = @{
InputObject = $ScheduledTask
ErrorAction = $STP
}
$null = (Disable-ScheduledTask @paramDisableScheduledTask)
Write-LogEntry -Value "Successfully disabled scheduled task named 'Backup BitLocker Recovery Password to Azure AD'" -Severity 1
}
catch
{
Write-LogEntry -Value "An error occurred while disabling scheduled task to backup recovery password. Error message: $($_.Exception.Message)" -Severity 3
}
}
}
catch
{
Write-LogEntry -Value "An error occurred while reading 'BitLockerEscrowResults' registry value. Error message: $($_.Exception.Message)" -Severity 3
}
}
}
}
}
}
end
{
if (Get-Command -Name 'Set-MpPreference' -ErrorAction $SCT)
{
$null = (Set-MpPreference -EnableControlledFolderAccess Enabled -Force -ErrorAction $SCT)
}
}