Tests/Unit/MSFT_xBLAutoBitlocker.tests.ps1

#region HEADER
$script:DSCModuleName = 'xBitlocker'
$script:DSCResourceName = 'MSFT_xBLAutoBitlocker'

# Unit Test Template Version: 1.2.4
$script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or `
     (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) )
{
    & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath 'DscResource.Tests'))
}

Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force

$TestEnvironment = Initialize-TestEnvironment `
    -DSCModuleName $script:DSCModuleName `
    -DSCResourceName $script:DSCResourceName `
    -ResourceType 'Mof' `
    -TestType Unit

#endregion HEADER

function Invoke-TestSetup
{

}

function Invoke-TestCleanup
{
    Restore-TestEnvironment -TestEnvironment $TestEnvironment
}

# Begin Testing
try
{
    InModuleScope 'MSFT_xBLAutoBitlocker' {
        # Override Bitlocker functions
        function Get-BitLockerVolume {
            param
            (
                [Parameter()]
                [System.String[]]
                $MountPoint
            )
        }

        # Override Helper functions
        function Assert-HasPrereqsForBitlocker {}
        function Remove-FromPSBoundParametersUsingHashtable {}
        function Add-ToPSBoundParametersFromHashtable {}
        function Test-BitlockerEnabled {}
        function Enable-BitlockerInternal {}

        Describe 'MSFT_xBLAutoBitlocker\Get-TargetResource' -Tag 'Get' {
            AfterEach {
                Assert-VerifiableMock
            }

            $testDriveType = 'Fixed'
            $testPrimaryProtector = 'TpmProtector'

            Mock -CommandName Import-Module -Verifiable
            Mock -CommandName Assert-HasPrereqsForBitlocker -Verifiable

            Context 'When Get-TargetResource is called and Assert-HasPrereqsForBitlocker succeeds' {
                It 'Should return a Hashtable with the input resource DriveType' {
                    $getResult = Get-TargetResource -DriveType $testDriveType -PrimaryProtector $testPrimaryProtector
                    $getResult | Should -Be -Not $null
                    $getResult.DriveType | Should -Be $testDriveType
                }
            }
        }

        Describe 'MSFT_xBLAutoBitlocker\Set-TargetResource' -Tag 'Set' {
            AfterEach {
                Assert-VerifiableMock
            }

            $testDriveType = 'Fixed'
            $testPrimaryProtector = 'TpmProtector'

            Mock -CommandName Import-Module -Verifiable
            Mock -CommandName Assert-HasPrereqsForBitlocker -Verifiable

            Context 'When Set-TargetResource is called, Assert-HasPrereqsForBitlocker succeeds, and Get-AutoBitlockerStatus returns null' {
                Mock -CommandName Get-AutoBitlockerStatus -Verifiable

                It 'Should throw an exception' {
                    { Set-TargetResource -DriveType $testDriveType -PrimaryProtector $testPrimaryProtector } | Should -Throw -ExpectedMessage 'No Auto Bitlocker volumes were found'
                }
            }

            Context 'When Set-TargetResource is called, Assert-HasPrereqsForBitlocker succeeds, Get-AutoBitlockerStatus returns a valid hashtable, and Test-BitlockerEnabled returns False' {
                Mock -CommandName Get-AutoBitlockerStatus -Verifiable -MockWith {
                    return @{
                        Keys = @('Volume1')
                    }
                }
                Mock -CommandName Remove-FromPSBoundParametersUsingHashtable -Verifiable
                Mock -CommandName Add-ToPSBoundParametersFromHashtable -Verifiable
                Mock -CommandName Test-BitlockerEnabled -Verifiable -MockWith { return $false }
                Mock -CommandName Enable-BitlockerInternal -Verifiable

                It 'Should enable Bitlocker' {
                    Set-TargetResource -DriveType $testDriveType -PrimaryProtector $testPrimaryProtector
                }
            }

            Context 'When Set-TargetResource is called, Assert-HasPrereqsForBitlocker succeeds, Get-AutoBitlockerStatus returns a valid hashtable, and Test-BitlockerEnabled returns True' {
                Mock -CommandName Get-AutoBitlockerStatus -Verifiable -MockWith {
                    return @{
                        Keys = @('Volume1')
                    }
                }
                Mock -CommandName Remove-FromPSBoundParametersUsingHashtable -Verifiable
                Mock -CommandName Add-ToPSBoundParametersFromHashtable -Verifiable
                Mock -CommandName Test-BitlockerEnabled -Verifiable -MockWith { return $true }
                Mock -CommandName Enable-BitlockerInternal

                It 'Should not enable Bitlocker' {
                    Set-TargetResource -DriveType $testDriveType -PrimaryProtector $testPrimaryProtector

                    Assert-MockCalled -CommandName Enable-BitlockerInternal -Times 0
                }
            }
        }

        Describe 'MSFT_xBLAutoBitlocker\Test-TargetResource' -Tag 'Test' {
            AfterEach {
                Assert-VerifiableMock
            }

            $testDriveType = 'Fixed'
            $testPrimaryProtector = 'TpmProtector'

            Mock -CommandName Import-Module -Verifiable
            Mock -CommandName Assert-HasPrereqsForBitlocker -Verifiable

            Context 'When Test-TargetResource is called, Assert-HasPrereqsForBitlocker succeeds, and Get-AutoBitlockerStatus returns null' {
                Mock -CommandName Get-AutoBitlockerStatus -Verifiable
                Mock -CommandName Write-Error -Verifiable

                It 'Should write an error and return false' {
                    Test-TargetResource -DriveType $testDriveType -PrimaryProtector $testPrimaryProtector | Should -Be $false
                }
            }

            Context 'When Test-TargetResource is called, Assert-HasPrereqsForBitlocker succeeds, Get-AutoBitlockerStatus returns a valid hashtable, and Test-BitlockerEnabled returns False' {
                Mock -CommandName Get-AutoBitlockerStatus -Verifiable -MockWith {
                    return @{
                        Keys = @('Volume1')
                    }
                }
                Mock -CommandName Remove-FromPSBoundParametersUsingHashtable -Verifiable
                Mock -CommandName Add-ToPSBoundParametersFromHashtable -Verifiable
                Mock -CommandName Test-BitlockerEnabled -Verifiable -MockWith { return $false }

                It 'Should return False' {
                    Test-TargetResource -DriveType $testDriveType -PrimaryProtector $testPrimaryProtector | Should -Be $false
                }
            }

            Context 'When Test-TargetResource is called, Assert-HasPrereqsForBitlocker succeeds, Get-AutoBitlockerStatus returns a valid hashtable, and Test-BitlockerEnabled returns True' {
                Mock -CommandName Get-AutoBitlockerStatus -Verifiable -MockWith {
                    return @{
                        Keys = @('Volume1')
                    }
                }
                Mock -CommandName Remove-FromPSBoundParametersUsingHashtable -Verifiable
                Mock -CommandName Add-ToPSBoundParametersFromHashtable -Verifiable
                Mock -CommandName Test-BitlockerEnabled -Verifiable -MockWith { return $true }

                It 'Should return True' {
                    Test-TargetResource -DriveType $testDriveType -PrimaryProtector $testPrimaryProtector | Should -Be $true
                }
            }
        }

        Describe 'MSFT_xBLAutoBitlocker\Get-AutoBitlockerStatus' {
        # Get-BitlockerVolume is used to obtain list of volumes in the system and their current encryption status
            Mock `
                -CommandName Get-BitlockerVolume `
                -ModuleName 'MSFT_xBLAutoBitlocker' `
                -MockWith {
                    # Returns a collection of OS/Fixed/Removable disks with correct/incorrect removable status
                    return @(
                        @{
                            # C: is OS drive
                            VolumeType = 'OperatingSystem'
                            MountPoint = 'C:'
                            CapacityGB = 500
                            VolumeStatus = 'FullyEncrypted'
                            EncryptionPercentage = 100
                            KeyProtector = @(
                                @{
                                    KeyProtectorType = 'Tpm'
                                },
                                @{
                                    KeyProtectorType = 'RecoveryPassword'
                                }
                            )
                            AutoUnlockEnabled = $null
                            ProtectionStatus = 'On'
                        },
                        @{
                            # D: is Fixed drive, incorrectly reporting as Removable to Bitlocker
                            VolumeType = 'Data'
                            MountPoint = 'D:'
                            CapacityGB = 500
                            VolumeStatus = 'FullyDecrypted'
                            EncryptionPercentage = 0
                            KeyProtector = @(
                            )
                            AutoUnlockEnabled = $null
                            ProtectionStatus = 'Off'
                        },
                        @{
                            # E: is Fixed drive, correctly reporting as Fixed to Bitlocker
                            VolumeType = 'Data'
                            MountPoint = 'E:'
                            CapacityGB = 50
                            VolumeStatus = 'FullyDecrypted'
                            EncryptionPercentage = 0
                            KeyProtector = @(
                            )
                            AutoUnlockEnabled = $null
                            ProtectionStatus = 'Off'
                        }
                        @{
                            # F: is a Removable drive thumb drive, correctly reporting as Removable to Bitlocker
                            VolumeType = 'Data'
                            MountPoint = 'F:'
                            CapacityGB = 500
                            VolumeStatus = 'FullyDecrypted'
                            EncryptionPercentage = 0
                            KeyProtector = @(
                            )
                            AutoUnlockEnabled = $null
                            ProtectionStatus = 'Off'
                        },
                        @{
                            # 1 is Fixed drive, incorrectly reporting as Removable to Bitlocker
                            VolumeType = 'Data'
                            MountPoint = '\\?\Volume{00000000-0000-0000-0000-000000000001}\'
                            CapacityGB = 500
                            VolumeStatus = 'FullyDecrypted'
                            EncryptionPercentage = 0
                            KeyProtector = @(
                            )
                            AutoUnlockEnabled = $null
                            ProtectionStatus = 'Off'
                        },
                        @{
                            # 2 is Fixed drive, correctly reporting as Fixed to Bitlocker
                            VolumeType = 'Data'
                            MountPoint = '\\?\Volume{00000000-0000-0000-0000-000000000002}\'
                            CapacityGB = 500
                            VolumeStatus = 'FullyDecrypted'
                            EncryptionPercentage = 0
                            KeyProtector = @(
                            )
                            AutoUnlockEnabled = $null
                            ProtectionStatus = 'Off'
                        }
                        @{
                            # 3 is a Removable drive thumb drive, correctly reporting as Removable to Bitlocker
                            VolumeType = 'Data'
                            MountPoint = '\\?\Volume{00000000-0000-0000-0000-000000000003}\'
                            CapacityGB = 50
                            VolumeStatus = 'FullyDecrypted'
                            EncryptionPercentage = 0
                            KeyProtector = @(
                            )
                            AutoUnlockEnabled = $null
                            ProtectionStatus = 'Off'
                        }
                    )
                }

            # Get-Volume evaluates volume removable status correctly
            # This was used in broken version of the module, replaced in Issue #11 by Win32_EncryptableVolume class
            Mock `
                -CommandName Get-Volume `
                -ModuleName 'MSFT_xBLAutoBitlocker' `
                -MockWith {
                    # Returns a collection of OS/Fixed/Removable disks with correct/incorrect removable status

                    switch ($Path)
                    {
                        '\\?\Volume{00000000-0000-0000-0000-000000000001}\'
                        {
                            return @{
                                # D: is Fixed drive, incorrectly reporting as Removable to Bitlocker
                                DriveLetter = ''
                                Path = '\\?\Volume{00000000-0000-0000-0000-000000000001}\'
                                DriveType = 'Fixed'
                            }
                        }
                        '\\?\Volume{00000000-0000-0000-0000-000000000002}\'
                        {
                            return @{
                                # 2 is Fixed drive, correctly reporting as Fixed to Bitlocker
                                DriveLetter = ''
                                Path = '\\?\Volume{00000000-0000-0000-0000-000000000002}\'
                                DriveType = 'Fixed'
                            }
                        }
                        '\\?\Volume{00000000-0000-0000-0000-000000000003}\'
                        {
                            return @{
                                # 3 is a Removable drive, correctly reporting as Fixed to Bitlocker
                                DriveLetter = ''
                                Path = '\\?\Volume{00000000-0000-0000-0000-000000000003}\'
                                DriveType = 'Removable'
                            }
                        }
                        default
                        {
                            throw "No MSFT_Volume objects found with property 'Path' equal to '$Path'. Verify the value of the property and retry."
                        }
                    }
                }

            Mock `
                -CommandName Get-CimInstance `
                -ModuleName 'MSFT_xBLAutoBitlocker' `
                -MockWith {
                    # Returns a collection of OS/Fixed/Removable disks with correct/incorrect removable status
                    return @(
                        @{
                            # C: is OS drive
                            DriveLetter = 'C:'
                            VolumeType=0
                            DeviceID='\\?\Volume{00000000-0000-0000-0000-000000000000}\'

                        },
                        @{
                            # D: is Fixed drive, incorrectly reporting as Removable to Bitlocker
                            DriveLetter = 'D:'
                            VolumeType=2
                            DeviceID='\\?\Volume{00000000-0000-0000-0000-000000000004}\'

                        },
                        @{
                            # E: is Fixed drive, correctly reporting as Fixed to Bitlocker
                            DriveLetter = 'E:'
                            VolumeType=1
                            DeviceID='\\?\Volume{00000000-0000-0000-0000-000000000005}\'

                        },
                        @{
                            # F: is a Removable drive, correctly reporting as Fixed to Bitlocker
                            DriveLetter = 'F:'
                            VolumeType=2
                            DeviceID='\\?\Volume{00000000-0000-0000-0000-000000000006}\'
                        },
                        @{
                            # 1 is Fixed drive, incorrectly reporting as Removable to Bitlocker
                            DriveLetter = ''
                            VolumeType=2
                            DeviceID='\\?\Volume{00000000-0000-0000-0000-000000000001}\'
                        },
                        @{
                            # 2 is Fixed drive, correctly reporting as Fixed to Bitlocker
                            DriveLetter = ''
                            VolumeType=1
                            DeviceID='\\?\Volume{00000000-0000-0000-0000-000000000002}\'
                        },
                        @{
                            # 3 is a Removable drive, correctly reporting as Fixed to Bitlocker
                            DriveLetter = ''
                            VolumeType=2
                            DeviceID='\\?\Volume{00000000-0000-0000-0000-000000000003}\'
                        }

                    )
                }

            Context 'When Volume C: Reports as OS Volume' {

                It 'Should Not Be In The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector TpmProtector|Select-Object -ExpandProperty Keys)|Should -Not -Contain 'C:'
                }

                It 'Should Not Be In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector TpmProtector|Select-Object -ExpandProperty Keys)|Should -Not -Contain 'C:'
                }
            }

            Context 'When Volume D: Reports Fixed to OS, but Removable to Bitlocker' {

                It 'Should Not Be In The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Not -Contain 'D:'
                }

                It 'Should Be In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain 'D:'
                }
            }

            Context 'When Volume E: Reports Fixed to OS and Bitlocker' {

                It 'Should Be In The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain 'E:'
                }

                It 'Should Not Be In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Not -Contain 'E:'
                }
            }

            Context 'When Volume F: Reports as Removable to OS and Bitlocker' {

                It 'Should Not Be In The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Not -Contain 'F:'
                }

                It 'Should Be In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain 'F:'
                }
            }

            Context 'When Volume \\?\Volume{00000000-0000-0000-0000-000000000001}\ Reports Fixed to OS, but Removable to Bitlocker' {

                It 'Should Not Be In The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Not -Contain '\\?\Volume{00000000-0000-0000-0000-000000000001}\'
                }

                It 'Should Be In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain '\\?\Volume{00000000-0000-0000-0000-000000000001}\'
                }
            }

            Context 'When Volume \\?\Volume{00000000-0000-0000-0000-000000000002}\ Reports Fixed to OS and Bitlocker' {

                It 'Should Be In The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain '\\?\Volume{00000000-0000-0000-0000-000000000002}\'
                }

                It 'Should Not Be In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Not -Contain '\\?\Volume{00000000-0000-0000-0000-000000000002}\'
                }
            }

            Context 'When Volume \\?\Volume{00000000-0000-0000-0000-000000000003}\ Reports as Removable to OS and Bitlocker' {

                It 'Should Not Be In The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Not -Contain '\\?\Volume{00000000-0000-0000-0000-000000000003}\'
                }

                It 'Should Be In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain '\\?\Volume{00000000-0000-0000-0000-000000000003}\'
                }
            }

            Context 'When MinDiskCapacity Parameter is Defined at 100 GB for Fixed Disks' {

                It 'Should Exclude E: from The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector -MinDiskCapacityGB 100|Select-Object -ExpandProperty Keys)|Should -Not -Contain 'E:'
                }

                It 'Should Include Volume \\?\Volume{00000000-0000-0000-0000-000000000002}\ In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector -MinDiskCapacityGB 100|Select-Object -ExpandProperty Keys)|Should -Contain '\\?\Volume{00000000-0000-0000-0000-000000000002}\'
                }
            }

            Context 'When MinDiskCapacity Parameter is Not Defined for Fixed Disks' {

                It 'Should Include E: In The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain 'E:'
                }

                It 'Should Include Volume \\?\Volume{00000000-0000-0000-0000-000000000002}\ In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Fixed' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain '\\?\Volume{00000000-0000-0000-0000-000000000002}\'
                }
            }

            Context 'When MinDiskCapacity Parameter is Defined at 100 GB for Removable Disks' {

                It 'Should Exclude \\?\Volume{00000000-0000-0000-0000-000000000003}\ from The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector -MinDiskCapacityGB 100|Select-Object -ExpandProperty Keys)|Should -Not -Contain '\\?\Volume{00000000-0000-0000-0000-000000000003}\'
                }

                It 'Should Include F: In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector -MinDiskCapacityGB 100|Select-Object -ExpandProperty Keys)|Should -Contain 'F:'
                }
            }

            Context 'When MinDiskCapacity Parameter is Not Defined for Fixed Disks' {

                It 'Should Include \\?\Volume{00000000-0000-0000-0000-000000000003}\ In The List of Eligible Fixed Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain '\\?\Volume{00000000-0000-0000-0000-000000000003}\'
                }

                It 'Should Include F: In The List of Eligible Removable Volumes' {
                    (Get-AutoBitlockerStatus -DriveType 'Removable' -PrimaryProtector RecoveryPasswordProtector|Select-Object -ExpandProperty Keys)|Should -Contain 'F:'
                }
            }
        }
    }
}
finally
{
    Invoke-TestCleanup
}