Private/Get-EFControlState.ps1
|
function Get-EFControlState { [CmdletBinding()] param( [Parameter(Mandatory)] [object]$Control ) $type = [string](Get-EFPropertyValue -InputObject $Control -Name 'Type') $desiredValue = Get-EFPropertyValue -InputObject $Control -Name 'DesiredValue' try { switch ($type) { 'Registry' { $path = [string](Get-EFPropertyValue -InputObject $Control -Name 'Path') $valueName = [string](Get-EFPropertyValue -InputObject $Control -Name 'ValueName') if (-not (Test-Path -LiteralPath $path)) { return New-EFControlResult -Control $Control -Status NonCompliant -ActualValue $null ` -DesiredValue $desiredValue -Message "Registry path '$path' does not exist." } $item = Get-ItemProperty -LiteralPath $path -ErrorAction Stop $property = $item.PSObject.Properties[$valueName] if ($null -eq $property) { return New-EFControlResult -Control $Control -Status NonCompliant -ActualValue $null ` -DesiredValue $desiredValue -Message "Registry value '$valueName' does not exist." } $actual = $property.Value $isMatch = Test-EFValueEqual -Actual $actual -Desired $desiredValue $status = if ($isMatch) { 'Compliant' } else { 'NonCompliant' } return New-EFControlResult -Control $Control -Status $status -ActualValue $actual ` -DesiredValue $desiredValue -Message "Registry value '$path\$valueName' evaluated." } 'Service' { $name = [string](Get-EFPropertyValue -InputObject $Control -Name 'Name') $service = Get-Service -Name $name -ErrorAction SilentlyContinue if ($null -eq $service) { return New-EFControlResult -Control $Control -Status NotApplicable -ActualValue $null ` -DesiredValue $desiredValue -Message "Service '$name' is not installed." } $startupType = Get-EFPropertyValue -InputObject $service -Name 'StartType' if ($null -eq $startupType) { $escapedName = $name.Replace("'", "''") $cimService = Get-CimInstance -ClassName Win32_Service -Filter "Name='$escapedName'" -ErrorAction Stop $startupType = switch ([string]$cimService.StartMode) { 'Auto' { 'Automatic' } default { [string]$cimService.StartMode } } } $desiredStartupType = [string](Get-EFPropertyValue -InputObject $Control -Name 'StartupType') $desiredStatus = [string](Get-EFPropertyValue -InputObject $Control -Name 'Status') $startupMatches = [string]::IsNullOrWhiteSpace($desiredStartupType) -or (Test-EFValueEqual -Actual ([string]$startupType) -Desired $desiredStartupType) $statusMatches = [string]::IsNullOrWhiteSpace($desiredStatus) -or (Test-EFValueEqual -Actual ([string]$service.Status) -Desired $desiredStatus) $actual = [ordered]@{ StartupType = [string]$startupType Status = [string]$service.Status } $desired = [ordered]@{ StartupType = $desiredStartupType Status = $desiredStatus } $resultStatus = if ($startupMatches -and $statusMatches) { 'Compliant' } else { 'NonCompliant' } return New-EFControlResult -Control $Control -Status $resultStatus -ActualValue $actual ` -DesiredValue $desired -Message "Service '$name' evaluated." } 'FirewallProfile' { if ($null -eq (Get-Command -Name Get-NetFirewallProfile -ErrorAction SilentlyContinue)) { return New-EFControlResult -Control $Control -Status NotApplicable -ActualValue $null ` -DesiredValue $desiredValue -Message 'Windows Firewall cmdlets are unavailable.' } $name = [string](Get-EFPropertyValue -InputObject $Control -Name 'Name') $firewallProfile = Get-NetFirewallProfile -Name $name -ErrorAction Stop $actual = [bool]$firewallProfile.Enabled $isMatch = Test-EFValueEqual -Actual $actual -Desired $desiredValue $status = if ($isMatch) { 'Compliant' } else { 'NonCompliant' } return New-EFControlResult -Control $Control -Status $status -ActualValue $actual ` -DesiredValue $desiredValue -Message "Firewall profile '$name' evaluated." } 'Defender' { if ($null -eq (Get-Command -Name Get-MpComputerStatus -ErrorAction SilentlyContinue)) { return New-EFControlResult -Control $Control -Status NotApplicable -ActualValue $null ` -DesiredValue $desiredValue -Message 'Microsoft Defender cmdlets are unavailable.' } $propertyName = [string](Get-EFPropertyValue -InputObject $Control -Name 'Property') $defender = Get-MpComputerStatus -ErrorAction Stop $property = $defender.PSObject.Properties[$propertyName] if ($null -eq $property) { throw "Microsoft Defender does not expose property '$propertyName'." } $actual = $property.Value $isMatch = Test-EFValueEqual -Actual $actual -Desired $desiredValue $status = if ($isMatch) { 'Compliant' } else { 'NonCompliant' } return New-EFControlResult -Control $Control -Status $status -ActualValue $actual ` -DesiredValue $desiredValue -Message "Microsoft Defender property '$propertyName' evaluated." } 'WindowsOptionalFeature' { if ($null -eq (Get-Command -Name Get-WindowsOptionalFeature -ErrorAction SilentlyContinue)) { return New-EFControlResult -Control $Control -Status NotApplicable -ActualValue $null ` -DesiredValue $desiredValue -Message 'Windows optional feature cmdlets are unavailable.' } $name = [string](Get-EFPropertyValue -InputObject $Control -Name 'Name') $feature = Get-WindowsOptionalFeature -Online -FeatureName $name -ErrorAction SilentlyContinue if ($null -eq $feature) { return New-EFControlResult -Control $Control -Status NotApplicable -ActualValue $null ` -DesiredValue $desiredValue -Message "Windows optional feature '$name' is unavailable." } $actual = [string]$feature.State $isMatch = Test-EFValueEqual -Actual $actual -Desired $desiredValue $status = if ($isMatch) { 'Compliant' } else { 'NonCompliant' } return New-EFControlResult -Control $Control -Status $status -ActualValue $actual ` -DesiredValue $desiredValue -Message "Windows optional feature '$name' evaluated." } 'BitLocker' { if ($null -eq (Get-Command -Name Get-BitLockerVolume -ErrorAction SilentlyContinue)) { return New-EFControlResult -Control $Control -Status NotApplicable -ActualValue $null ` -DesiredValue $desiredValue -Message 'BitLocker cmdlets are unavailable.' } $mountPoint = [Environment]::ExpandEnvironmentVariables( [string](Get-EFPropertyValue -InputObject $Control -Name 'MountPoint' -Default '%SystemDrive%') ) $volume = Get-BitLockerVolume -MountPoint $mountPoint -ErrorAction Stop $actual = [string]$volume.ProtectionStatus $isMatch = Test-EFValueEqual -Actual $actual -Desired $desiredValue $status = if ($isMatch) { 'Compliant' } else { 'NonCompliant' } return New-EFControlResult -Control $Control -Status $status -ActualValue $actual ` -DesiredValue $desiredValue -Message "BitLocker volume '$mountPoint' evaluated." } 'SecureBoot' { if ($null -eq (Get-Command -Name Confirm-SecureBootUEFI -ErrorAction SilentlyContinue)) { return New-EFControlResult -Control $Control -Status NotApplicable -ActualValue $null ` -DesiredValue $desiredValue -Message 'Secure Boot cmdlets are unavailable.' } try { $actual = [bool](Confirm-SecureBootUEFI -ErrorAction Stop) } catch { $secureBootMessage = $_.Exception.Message $secureBootStatus = if ($secureBootMessage -match 'not supported|not available|not implemented') { 'NotApplicable' } else { 'Error' } return New-EFControlResult -Control $Control -Status $secureBootStatus -ActualValue $null ` -DesiredValue $desiredValue -Message "Secure Boot cannot be queried on this device: $secureBootMessage" } $isMatch = Test-EFValueEqual -Actual $actual -Desired $desiredValue $status = if ($isMatch) { 'Compliant' } else { 'NonCompliant' } return New-EFControlResult -Control $Control -Status $status -ActualValue $actual ` -DesiredValue $desiredValue -Message 'Secure Boot evaluated.' } 'Tpm' { if ($null -eq (Get-Command -Name Get-Tpm -ErrorAction SilentlyContinue)) { return New-EFControlResult -Control $Control -Status NotApplicable -ActualValue $null ` -DesiredValue $desiredValue -Message 'TPM cmdlets are unavailable.' } $tpm = Get-Tpm -ErrorAction Stop if (-not (Test-EFPropertyPresent -InputObject $tpm -Name 'TpmPresent') -or -not (Test-EFPropertyPresent -InputObject $tpm -Name 'TpmReady')) { throw 'TPM status was not returned. Run PowerShell as Administrator to evaluate this control.' } $actual = [ordered]@{ TpmPresent = [bool](Get-EFPropertyValue -InputObject $tpm -Name 'TpmPresent') TpmReady = [bool](Get-EFPropertyValue -InputObject $tpm -Name 'TpmReady') } $expectedPresent = [bool](Get-EFPropertyValue -InputObject $desiredValue -Name 'TpmPresent' -Default $true) $expectedReady = [bool](Get-EFPropertyValue -InputObject $desiredValue -Name 'TpmReady' -Default $true) $isMatch = $actual.TpmPresent -eq $expectedPresent -and $actual.TpmReady -eq $expectedReady $status = if ($isMatch) { 'Compliant' } else { 'NonCompliant' } return New-EFControlResult -Control $Control -Status $status -ActualValue $actual ` -DesiredValue $desiredValue -Message 'Trusted Platform Module state evaluated.' } default { throw "Unsupported baseline control type '$type'." } } } catch { return New-EFControlResult -Control $Control -Status Error -ActualValue $null ` -DesiredValue $desiredValue -Message $_.Exception.Message } } |