Auditing/Bitlocker.ps1

function Get-CSBitlockerKeyProtector {
<#
.SYNOPSIS
 
Obtains Bitlocker volume key material.
 
Author: Matthew Graeber (@mattifestation)
Inspiration/Motivation: Jared Atkinson (@jaredcatkinson), Brian Reitz (@brian_psu)
License: BSD 3-Clause
 
.DESCRIPTION
 
Get-CSBitlockerKeyProtector retrieves key material for BitLocker volumes. This function is used for the purposes of remotely decrypting and mounting Bitlocker volumes. Depending on the Bitlocker key protector used, Get-CSBitlockerKeyProtector will return any combination of the NumericalPassword, ExternalKey, KeyPackage, or Certificate.
 
.PARAMETER DriveLetter
 
Specifies the drive letter for the volume you want to obtain key Bitlocker key material from. If DriveLetter is not specified, key material for all encryptable volumes will be returned.
 
.PARAMETER CimSession
 
Specifies the CIM session to use for this cmdlet. Enter a variable that contains the CIM session or a command that creates or gets the CIM session, such as the New-CimSession or Get-CimSession cmdlets. For more information, see about_CimSessions.
 
.EXAMPLE
 
Get-CSBitlockerKeyProtector
 
List all recoverable Bitlocker key material for each encryptable volume.
 
.EXAMPLE
 
Get-CSBitlockerKeyProtector -DriveLetter C:
 
List all recoverable Bitlocker key material for the C: volume.
 
.OUTPUTS
 
CimSweep.BitlockerKeyProtector
 
Outputs objects representing Bitlocker volume key material.
#>


    [CmdletBinding()]
    [OutputType('CimSweep.BitlockerKeyProtector')]
    param(
        [ValidatePattern('^[A-Z]:?$')]
        [String]
        $DriveLetter,

        [Alias('Session')]
        [ValidateNotNullOrEmpty()]
        [Microsoft.Management.Infrastructure.CimSession[]]
        $CimSession
    )

    BEGIN {
        # If a CIM session is not provided, trick the function into thinking there is one.
        if (-not $PSBoundParameters['CimSession']) {
            $CimSession = ''
            $CIMSessionCount = 1
        } else {
            $CIMSessionCount = $CimSession.Count
        }

        $CurrentCIMSession = 0

        $KeyProtectorTypes = @{
            0 = 'Unknown or other protector type'
            1 = 'Trusted Platform Module (TPM)'
            2 = 'External key'
            3 = 'Numerical password'
            4 = 'TPM And PIN'
            5 = 'TPM And Startup Key'
            6 = 'TPM And PIN And Startup Key'
            7 = 'Public Key'
            8 = 'Passphrase'
            9 = 'TPM Certificate'
            10 = 'CryptoAPI Next Generation (CNG) Protector'
        }
    }

    PROCESS {
        foreach ($Session in $CimSession) {
            $ComputerName = $Session.ComputerName
            if (-not $Session.ComputerName) { $ComputerName = 'localhost' }

            # Display a progress activity for each CIM session
            Write-Progress -Id 1 -Activity 'CimSweep - Bitlocker key protector sweep' -Status "($($CurrentCIMSession+1)/$($CIMSessionCount)) Current computer: $ComputerName" -PercentComplete (($CurrentCIMSession / $CIMSessionCount) * 100)
            $CurrentCIMSession++

            $CommonArgs = @{}
            if ($Session.Id) { $CommonArgs['CimSession'] = $Session }
            if ($OperationTimeoutSec) { $CommonArgs['OperationTimeoutSec'] = $OperationTimeoutSec }

            $VolumeArgs = @{
                Namespace = 'root/cimv2/security/microsoftvolumeencryption'
                ClassName = 'Win32_EncryptableVolume'
                Property = 'ProtectionStatus', 'DriveLetter', 'DeviceID'
            }

            if ($DriveLetter) { $VolumeArgs['Filter'] = "DriveLetter='$($DriveLetter[0]):'" }

            $Volumes = @(Get-CimInstance @CommonArgs @VolumeArgs)

            $VolCount = 0

            foreach ($CurrentVolume in $Volumes) {
                Write-Progress -Id 2 -ParentId 1 -Activity "Current volume:" -Status "($($VolCount+1)/$($Volumes.Count)) $($CurrentVolume.DriveLetter)" -PercentComplete (($VolCount / $Volumes.Count) * 100)
                $VolCount++

                if ($CurrentVolume.ProtectionStatus -ne 1) {
                    Write-Warning "[$ComputerName] Drive letter $($CurrentVolume.DriveLetter) is not Bitlocker protected."
                    continue
                }

                $Result = Invoke-CimMethod -CimInstance $CurrentVolume -MethodName GetKeyProtectors @CommonArgs

                if ($Result.ReturnValue) {
                    Write-Error "[$ComputerName] Unable to obtain key protectors from drive letter: $($CurrentVolume.DriveLetter)"
                    continue
                }

                $ProtectorCount = 0
                $KeyProtectorIDs = @($Result.VolumeKeyProtectorID)

                foreach ($ProtectorID in $KeyProtectorIDs) {
                    Write-Progress -Id 3 -ParentId 2 -Activity "Current key protector ID:" -Status "($($ProtectorCount+1)/$($KeyProtectorIDs.Count)) $ProtectorID" -PercentComplete (($ProtectorCount / $KeyProtectorIDs.Count) * 100)
                    $ProtectorCount++

                    $MethodArgs = @{
                        CimInstance = $CurrentVolume
                        Arguments = @{ VolumeKeyProtectorID = $ProtectorID }
                    }

                    $Result = Invoke-CimMethod -MethodName GetKeyProtectorType @CommonArgs @MethodArgs

                    if ($Result.ReturnValue) {
                        Write-Error "[$ComputerName] Unable to obtain key protector type for drive letter: $($CurrentVolume.DriveLetter), VolumeKeyProtectorID: $ProtectorID"
                        continue
                    }

                    $KeyProtectorFriendlyName = $KeyProtectorTypes[[Int] $Result.KeyProtectorType]

                    $ExternalKeyFileName = $null
                    $ExternalKeyBytes = $null
                    $NumericalPassword = $null
                    $KeyPackage = $null
                    $KeyProtectorCertificate = $null

                    $ErrorTemplate = "for drive letter: $($CurrentVolume.DriveLetter), VolumeKeyProtectorID: $ProtectorID"

                    switch ($KeyProtectorFriendlyName) {
                        'External key' {
                            $Result = Invoke-CimMethod -MethodName GetExternalKeyFileName @CommonArgs @MethodArgs
                            
                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain external key file name $ErrorTemplate"
                                continue
                            }

                            $ExternalKeyFileName = $Result.FileName

                            $Result = Invoke-CimMethod -MethodName GetKeyProtectorExternalKey @CommonArgs @MethodArgs

                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain external key bytes $ErrorTemplate"
                                continue
                            }

                            $ExternalKeyBytes = $Result.ExternalKey

                            $Result = Invoke-CimMethod -MethodName GetKeyPackage @CommonArgs @MethodArgs

                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain key package $ErrorTemplate"
                                continue
                            }

                            $KeyPackage = $Result.KeyPackage
                        }

                        'Numerical password' {
                            $Result = Invoke-CimMethod -MethodName GetKeyProtectorNumericalPassword @CommonArgs @MethodArgs

                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain numerical password $ErrorTemplate"
                                continue
                            }

                            $NumericalPassword = $Result.NumericalPassword

                            $Result = Invoke-CimMethod -MethodName GetKeyPackage @CommonArgs @MethodArgs

                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain key package $ErrorTemplate"
                                continue
                            }

                            $KeyPackage = $Result.KeyPackage
                        }

                        'TPM And Startup Key' {
                            $Result = Invoke-CimMethod -MethodName GetExternalKeyFileName @CommonArgs @MethodArgs

                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain external key file name $ErrorTemplate"
                                continue
                            }
        
                            $ExternalKeyFileName = $Result.FileName

                            $Result = Invoke-CimMethod -MethodName GetKeyProtectorExternalKey @CommonArgs @MethodArgs

                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain external key bytes $ErrorTemplate"
                                continue
                            }

                            $ExternalKeyBytes = $Result.ExternalKey
                        }

                        'TPM And PIN And Startup Key' {
                            $Result = Invoke-CimMethod -MethodName GetExternalKeyFileName @CommonArgs @MethodArgs

                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain external key file name $ErrorTemplate"
                                continue
                            }
        
                            $ExternalKeyFileName = $Result.FileName

                            $Result = Invoke-CimMethod -MethodName GetKeyProtectorExternalKey @CommonArgs @MethodArgs

                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain external key bytes $ErrorTemplate"
                                continue
                            }

                            $ExternalKeyBytes = $Result.ExternalKey
                        }

                        'Public Key' {
                            $Result = Invoke-CimMethod -CimInstance $CurrentVolume -MethodName GetKeyProtectorCertificate -Arguments @{ VolumeKeyProtectorID = $ProtectorID } @CommonArgs
        
                            if ($Result.ReturnValue) {
                                Write-Error "[$ComputerName] Unable to obtain protector certificate $ErrorTemplate"
                                continue
                            }

                            $KeyProtectorCertificate = [PSCustomObject] @{
                                PSTypeName = 'CimSweep.KeyProtector.BitlockerKeyProtector'
                                PublicKey = $Result.PublicKey
                                CertThumbprint = $Result.CertThumbprint
                                CertType = if ($Result.CertType -eq 1) { 'DataRecoveryAgent' } else { 'UserCertificate' }
                            }
                        }
                    }

                    $ProtectorProperties = [Ordered] @{
                        PSTypeName = 'CimSweep.BitlockerKeyProtector'
                        DriveLetter = $CurrentVolume.DriveLetter
                        DeviceID = $CurrentVolume.DeviceID
                        KeyProtectorID = $ProtectorID
                        KeyProtectorFriendlyName = $KeyProtectorFriendlyName
                        NumericalPassword = $NumericalPassword
                        ExternalKeyFileName = $ExternalKeyFileName
                        ExternalKeyBytes = $ExternalKeyBytes
                        KeyPackage = $KeyPackage
                        Certificate = $KeyProtectorCertificate
                    }

                    if ($CurrentVolume.PSComputerName) { $ProtectorProperties['PSComputerName'] = $CurrentVolume.PSComputerName }

                    [PSCustomObject] $ProtectorProperties
                }
            }
        }
    }
}

Export-ModuleMember -Function Get-CSBitlockerKeyProtector