diff --git a/Misc/xBitlockerCommon.psm1 b/Misc/xBitlockerCommon.psm1 index ac234e2..a0825ab 100644 --- a/Misc/xBitlockerCommon.psm1 +++ b/Misc/xBitlockerCommon.psm1 @@ -425,7 +425,7 @@ function CheckForPreReqs Write-Error "The RSAT-Feature-Tools-BitLocker feature needs to be installed before the xBitlocker module can be used" } - if ($blAdminToolsRemoteFeature.InstallState -ne "Installed") + if ($blAdminToolsRemoteFeature.InstallState -ne 'Installed' -and (Get-OSEdition) -notmatch 'Core') { $hasAllPreReqs = $false @@ -518,4 +518,14 @@ function RemoveParameters } } +<# +.SYNOPSIS +Returns the OS edtion we currently running on +#> +function Get-OSEdition +{ + (Get-ItemProperty -Path 'HKLM:/software/microsoft/windows nt/currentversion' -Name InstallationType).InstallationType +} + + Export-ModuleMember -Function * diff --git a/README.md b/README.md index ac630ab..052afe6 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,8 @@ Defaults to false. * Fixed issue which caused Test to incorrectly succeed on fully decrypted volumes when correct Key Protectors were present ([issue #13](https://github.com/PowerShell/xBitlocker/issues/13)) * Fixed issue which caused xBLAutoBitlocker to incorrectly detect Fixed vs Removable volumes. ([issue #11](https://github.com/PowerShell/xBitlocker/issues/11)) * Fixed issue which made xBLAutoBitlocker unable to encrypt volumes with drive letters assigned. ([issue #10](https://github.com/PowerShell/xBitlocker/issues/10)) +* Fixed an issue in CheckForPreReqs function where on Server Core the installation of the non existing Windows Feature 'RSAT-Feature-Tools-BitLocker-RemoteAdminTool' was erroneously checked. ([issue #8](https://github.com/PowerShell/xBitlocker/issues/8)) + ### 1.1.0.0 diff --git a/Tests/Unit/xBitlockerCommon.tests.ps1 b/Tests/Unit/xBitlockerCommon.tests.ps1 index 566e93a..608e1e9 100644 --- a/Tests/Unit/xBitlockerCommon.tests.ps1 +++ b/Tests/Unit/xBitlockerCommon.tests.ps1 @@ -4,7 +4,7 @@ Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -P # Begin Testing try { - InModuleScope "xBitlockerCommon" { + InModuleScope 'xBitlockerCommon' { function Get-BitlockerVolume { @@ -16,25 +16,25 @@ try ) } - Describe "xBitlockerCommon\TestBitlocker" { + Describe 'xBitlockerCommon\TestBitlocker' { Context 'When OS Volume is not Encrypted and No Key Protectors Assigned' { Mock ` -CommandName Get-BitlockerVolume ` -ModuleName 'xBitlockerCommon' ` -MockWith { - # Decrypted with no Key Protectors - return @{ - VolumeType = 'OperatingSystem' - MountPoint = $MountPoint - CapacityGB = 500 - VolumeStatus = 'FullyDecrypted' - EncryptionPercentage = 0 - KeyProtector = @() - AutoUnlockEnabled = $null - ProtectionStatus = 'Off' - } + # Decrypted with no Key Protectors + return @{ + VolumeType = 'OperatingSystem' + MountPoint = $MountPoint + CapacityGB = 500 + VolumeStatus = 'FullyDecrypted' + EncryptionPercentage = 0 + KeyProtector = @() + AutoUnlockEnabled = $null + ProtectionStatus = 'Off' } + } It 'Should Fail The Test (TPM and RecoveryPassword Protectors)' { TestBitlocker -MountPoint 'C:' -PrimaryProtector 'TPMProtector' -RecoveryPasswordProtector $true | Should -Be $false @@ -46,25 +46,25 @@ try -CommandName Get-BitlockerVolume ` -ModuleName 'xBitlockerCommon' ` -MockWith { - # Encrypted with TPM and Recovery Password Key Protectors - return @{ - VolumeType = 'OperatingSystem' - MountPoint = $MountPoint - CapacityGB = 500 - VolumeStatus = 'FullyEncrypted' - EncryptionPercentage = 100 - KeyProtector = @( - @{ - KeyProtectorType = 'Tpm' - }, - @{ - KeyProtectorType = 'RecoveryPassword' - } - ) - AutoUnlockEnabled = $null - ProtectionStatus = 'On' - } + # Encrypted with TPM and Recovery Password Key Protectors + return @{ + VolumeType = 'OperatingSystem' + MountPoint = $MountPoint + CapacityGB = 500 + VolumeStatus = 'FullyEncrypted' + EncryptionPercentage = 100 + KeyProtector = @( + @{ + KeyProtectorType = 'Tpm' + }, + @{ + KeyProtectorType = 'RecoveryPassword' + } + ) + AutoUnlockEnabled = $null + ProtectionStatus = 'On' } + } It 'Should Pass The Test (TPM and RecoveryPassword Protectors)' { TestBitlocker -MountPoint 'C:' -PrimaryProtector 'TPMProtector' -RecoveryPasswordProtector $true -verbose | Should -Be $true @@ -76,31 +76,252 @@ try -CommandName Get-BitlockerVolume ` -ModuleName 'xBitlockerCommon' ` -MockWith { - # Encrypted with TPM and Recovery Password Key Protectors - return @{ - VolumeType = 'OperatingSystem' - MountPoint = $MountPoint - CapacityGB = 500 - VolumeStatus = 'FullyDecrypted' - EncryptionPercentage = 0 - KeyProtector = @( - @{ - KeyProtectorType = 'Tpm' - }, - @{ - KeyProtectorType = 'RecoveryPassword' - } - ) - AutoUnlockEnabled = $null - ProtectionStatus = 'Off' - } + # Encrypted with TPM and Recovery Password Key Protectors + return @{ + VolumeType = 'OperatingSystem' + MountPoint = $MountPoint + CapacityGB = 500 + VolumeStatus = 'FullyDecrypted' + EncryptionPercentage = 0 + KeyProtector = @( + @{ + KeyProtectorType = 'Tpm' + }, + @{ + KeyProtectorType = 'RecoveryPassword' + } + ) + AutoUnlockEnabled = $null + ProtectionStatus = 'Off' } + } It 'Should Fail The Test (TPM and RecoveryPassword Protectors)' { TestBitlocker -MountPoint 'C:' -PrimaryProtector 'TPMProtector' -RecoveryPasswordProtector $true | Should -Be $false } } } + + Describe 'xBitlockerCommon\CheckForPreReqs' { + function Get-WindowsFeature + { + param + ( + [string] + $FeatureName + ) + } + + function Get-OSEdition + { + + } + + Context 'When OS is Server Core and all required features are installed' { + Mock -CommandName Get-OSEdition -MockWith { + 'Server Core' + } + + Mock -CommandName Get-WindowsFeature -MockWith { + if ($FeatureName -eq 'RSAT-Feature-Tools-BitLocker-RemoteAdminTool') + { + return $null + } + else + { + return @{ + DisplayName = $FeatureName + Name = $FeatureName + InstallState = 'Installed' + } + } + } + + It 'Should not generate any error messages' { + Mock -CommandName Write-Error + CheckForPreReqs + Assert-MockCalled -Command Write-Error -Exactly -Times 0 -Scope It + } + + It 'Should run the CheckForPreReqs function without exceptions' { + {CheckForPreReqs} | Should -Not -Throw + } + } + + Context 'When OS is Full Server and all required features are installed' { + Mock -CommandName Get-OSEdition -MockWith { + return 'Server' + } + + Mock -CommandName Get-WindowsFeature -MockWith { + param + ( + [string] + $FeatureName + ) + + return @{ + DisplayName = $FeatureName + Name = $FeatureName + InstallState = 'Installed' + } + } + + It 'Should not generate any error messages' { + Mock -CommandName Write-Error + CheckForPreReqs + Assert-MockCalled -Command Write-Error -Exactly -Times 0 -Scope It + } + + It 'Should run the CheckForPreReqs function without exceptions' { + {CheckForPreReqs} | Should -Not -Throw + } + } + + Context 'When OS is Full Server without the required features installed' { + Mock -CommandName Get-OSEdition -MockWith { + return 'Server' + } + + Mock -CommandName Get-WindowsFeature -MockWith { + return @{ + DisplayName = $FeatureName + Name = $FeatureName + InstallState = 'Available' + } + } + + Mock -CommandName Write-Error + + It 'Should give an error that Bitlocker Windows Feature needs to be installed' { + {CheckForPreReqs} | Should -Throw + Assert-MockCalled -Command Write-Error -Exactly -Times 1 -Scope It -ParameterFilter { + $Message -eq 'The Bitlocker feature needs to be installed before the xBitlocker module can be used' + } + } + + It 'Should give an error that RSAT-Feature-Tools-BitLocker Windows Feature needs to be installed' { + {CheckForPreReqs} | Should -Throw + Assert-MockCalled -Command Write-Error -Exactly -Times 1 -Scope It -ParameterFilter { + $Message -eq 'The RSAT-Feature-Tools-BitLocker feature needs to be installed before the xBitlocker module can be used' + } + } + + It 'Should give an error that RSAT-Feature-Tools-BitLocker-RemoteAdminTool Windows Feature needs to be installed' { + {CheckForPreReqs} | Should -Throw + Assert-MockCalled -Command Write-Error -Exactly -Times 1 -Scope It -ParameterFilter { + $Message -eq 'The RSAT-Feature-Tools-BitLocker-RemoteAdminTool feature needs to be installed before the xBitlocker module can be used' + } + } + + It 'The CheckForPreReqs function should throw an exceptions about missing required Windows Features' { + {CheckForPreReqs} | Should -Throw 'Required Bitlocker features need to be installed before xBitlocker can be used' + } + } + + Context 'When OS is Server Core without the required features installed' { + Mock -CommandName Get-OSEdition -MockWith { + return 'Server Core' + } + + Mock -CommandName Get-WindowsFeature -MockWith { + param + ( + [string] + $FeatureName + ) + + if ($FeatureName -eq 'RSAT-Feature-Tools-BitLocker-RemoteAdminTool') + { + return $null + } + else + { + + return @{ + DisplayName = $FeatureName + Name = $FeatureName + InstallState = 'Available' + } + } + } + + Mock -CommandName Write-Error + + It 'Should give an error that Bitlocker Windows Feature needs to be installed' { + {CheckForPreReqs} | Should -Throw + Assert-MockCalled -Command Write-Error -Exactly -Times 1 -Scope It -ParameterFilter { + $Message -eq 'The Bitlocker feature needs to be installed before the xBitlocker module can be used' + } + } + + It 'Should give an error that RSAT-Feature-Tools-BitLocker Windows Feature needs to be installed' { + {CheckForPreReqs} | Should -Throw + Assert-MockCalled -Command Write-Error -Exactly -Times 1 -Scope It -ParameterFilter { + $Message -eq 'The RSAT-Feature-Tools-BitLocker feature needs to be installed before the xBitlocker module can be used' + } + } + + It 'Should not give an error that RSAT-Feature-Tools-BitLocker-RemoteAdminTool Windows Feature needs to be installed as this Windows Features is not available on Server Core.' { + {CheckForPreReqs} | Should -Throw + Assert-MockCalled -Command Write-Error -Exactly -Times 0 -Scope It -ParameterFilter { + $Message -eq 'The RSAT-Feature-Tools-BitLocker-RemoteAdminTool feature needs to be installed before the xBitlocker module can be used' + } + } + + It 'The CheckForPreReqs function should throw an exceptions about missing required Windows Features' { + {CheckForPreReqs} | Should -Throw 'Required Bitlocker features need to be installed before xBitlocker can be used' + } + } + } + + Describe 'xBitLockerCommon\Get-OSEdition' { + It 'Should return "Server Core" if the OS is Windows Server Core' { + Mock -CommandName Get-ItemProperty -MockWith { + [PSCustomObject]@{ + InstallationType = 'Server Core' + PSPath = 'Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\microsoft\windows nt\currentversion' + PSParentPath = 'Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\microsoft\windows nt' + PSChildName = 'currentversion' + PSDrive = 'HKLM' + PSProvider = 'Microsoft.PowerShell.Core\Registry' + } + } + + $OSVersion = Get-OSEdition + $OSVersion | Should -Be 'Server Core' + } + + It 'Should return "Server" if the OS is Full Windows Server' { + Mock -CommandName Get-ItemProperty -MockWith { + [PSCustomObject]@{ + InstallationType = 'Server' + PSPath = 'Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\microsoft\windows nt\currentversion' + PSParentPath = 'Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\microsoft\windows nt' + PSChildName = 'currentversion' + PSDrive = 'HKLM' + PSProvider = 'Microsoft.PowerShell.Core\Registry' + } + } + + $OSVersion = Get-OSEdition + $OSVersion | Should -Be 'Server' + } + + It 'Should run without exceptions' { + Mock -CommandName Get-ItemProperty -MockWith { + [PSCustomObject]@{ + InstallationType = 'Some other os' + PSPath = 'Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\microsoft\windows nt\currentversion' + PSParentPath = 'Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\microsoft\windows nt' + PSChildName = 'currentversion' + PSDrive = 'HKLM' + PSProvider = 'Microsoft.PowerShell.Core\Registry' + } + } + {Get-OSEdition} | Should -Not -Throw + } + } } } finally diff --git a/xBitlocker.psd1 b/xBitlocker.psd1 index a2aeb8f..b3078e9 100644 --- a/xBitlocker.psd1 +++ b/xBitlocker.psd1 @@ -36,7 +36,7 @@ PowerShellVersion = '4.0' # DotNetFrameworkVersion = '' # Minimum version of the common language runtime (CLR) required by this module -# CLRVersion = '' +CLRVersion = '4.0' # Processor architecture (None, X86, Amd64) required by this module # ProcessorArchitecture = ''