Public/SecurityOption.ps1

<#
.SYNOPSIS
    Test a Security Option.
.DESCRIPTION
    Test the setting of a particular security option.
.PARAMETER Target
    Specifies the category of the security option.
.PARAMETER Should
    A Script Block defining a Pester Assertion.
.EXAMPLE
    SecurityOption 'Accounts: Administrator account status' { Should -Be Disabled }
.EXAMPLE
    SecurityOption 'Domain member: Maximum machine account password age' { Should -Be 30 }
.EXAMPLE
    SecurityOption 'Accounts: Block Microsoft accounts' { Should -Be $null }
.NOTES
    Assertions: Be, BeExactly, Match, MatchExactly
#>

 
function SecurityOption {
    [CmdletBinding(DefaultParameterSetName = "Default")]
    param(
        [Parameter(Mandatory, Position = 1)]
        [Alias("Category")]
        [ValidateSet(
            "Accounts: Administrator account status",
            "Accounts: Block Microsoft accounts",
            "Accounts: Guest account status",
            "Accounts: Limit local account use of blank passwords to console logon only",
            "Accounts: Rename administrator account",
            "Accounts: Rename guest account",
            "Audit: Audit the access of global system objects",
            "Audit: Audit the use of Backup and Restore privilege",
            "Audit: Force audit policy subcategory settings Windows Vista or later to override audit policy category settings",
            "Audit: Shut down system immediately if unable to log security audits",
            "DCOM: Machine Access Restrictions in Security Descriptor Definition Language SDDL syntax",
            "DCOM: Machine Launch Restrictions in Security Descriptor Definition Language SDDL syntax",
            "Devices: Allow undock without having to log on",
            "Devices: Allowed to format and eject removable media",
            "Devices: Prevent users from installing printer drivers",
            "Devices: Restrict CD ROM access to locally logged on user only",
            "Devices: Restrict floppy access to locally logged on user only",
            "Domain controller: Allow server operators to schedule tasks",
            "Domain controller: LDAP server signing requirements",
            "Domain controller: Refuse machine account password changes",
            "Domain member: Digitally encrypt or sign secure channel data always",
            "Domain member: Digitally encrypt secure channel data when possible",
            "Domain member: Digitally sign secure channel data when possible",
            "Domain member: Disable machine account password changes",
            "Domain member: Maximum machine account password age",
            "Domain member: Require strong Windows 2000 or later session key",
            "Interactive logon: Display user information when the session is locked",
            "Interactive logon: Do not display last user name",
            "Interactive logon: Do not require CTRL ALT DEL",
            "Interactive logon: Machine account lockout threshold",
            "Interactive logon: Machine inactivity limit",
            "Interactive logon: Message text for users attempting to log on",
            "Interactive logon: Message title for users attempting to log on",
            "Interactive logon: Number of previous logons to cache in case domain controller is not available",
            "Interactive logon: Prompt user to change password before expiration",
            "Interactive logon: Require Domain Controller authentication to unlock workstation",
            "Interactive logon: Require smart card",
            "Interactive logon: Smart card removal behavior",
            "Microsoft network client: Digitally sign communications always",
            "Microsoft network client: Digitally sign communications if server agrees",
            "Microsoft network client: Send unencrypted password to third party SMB servers",
            "Microsoft network server: Amount of idle time required before suspending session",
            "Microsoft network server: Attempt S4U2Self to obtain claim information",
            "Microsoft network server: Digitally sign communications always",
            "Microsoft network server: Digitally sign communications if client agrees",
            "Microsoft network server: Disconnect clients when logon hours expire",
            "Microsoft network server: Server SPN target name validation level",
            "Network access: Allow anonymous SID Name translation",
            "Network access: Do not allow anonymous enumeration of SAM accounts",
            "Network access: Do not allow anonymous enumeration of SAM accounts and shares",
            "Network access: Do not allow storage of passwords and credentials for network authentication",
            "Network access: Let Everyone permissions apply to anonymous users",
            "Network access: Named Pipes that can be accessed anonymously",
            "Network access: Remotely accessible registry paths",
            "Network access: Remotely accessible registry paths and subpaths",
            "Network access: Restrict anonymous access to Named Pipes and Shares",
            "Network access: Restrict clients allowed to make remote calls to SAM",
            "Network access: Shares that can be accessed anonymously",
            "Network access: Sharing and security model for local accounts",
            "Network security: Allow Local System to use computer identity for NTLM",
            "Network security: Allow LocalSystem NULL session fallback",
            "Network Security: Allow PKU2U authentication requests to this computer to use online identities",
            "Network security: Configure encryption types allowed for Kerberos",
            "Network security: Do not store LAN Manager hash value on next password change",
            "Network security: Force logoff when logon hours expire",
            "Network security: LAN Manager authentication level",
            "Network security: LDAP client signing requirements",
            "Network security: Minimum session security for NTLM SSP based including secure RPC clients",
            "Network security: Minimum session security for NTLM SSP based including secure RPC servers",
            "Network security: Restrict NTLM Add remote server exceptions for NTLM authentication",
            "Network security: Restrict NTLM Add server exceptions in this domain",
            "Network Security: Restrict NTLM Incoming NTLM Traffic",
            "Network Security: Restrict NTLM NTLM authentication in this domain",
            "Network Security: Restrict NTLM Outgoing NTLM traffic to remote servers",
            "Network Security: Restrict NTLM Audit Incoming NTLM Traffic",
            "Network Security: Restrict NTLM Audit NTLM authentication in this domain",
            "Recovery console: Allow automatic administrative logon",
            "Recovery console: Allow floppy copy and access to all drives and folders",
            "Shutdown: Allow system to be shut down without having to log on",
            "Shutdown: Clear virtual memory pagefile",
            "System cryptography: Force strong key protection for user keys stored on the computer",
            "System cryptography: Use FIPS compliant algorithms for encryption hashing and signing",
            "System objects: Require case insensitivity for non Windows subsystems",
            "System objects: Strengthen default permissions of internal system objects eg Symbolic Links",
            "System settings: Optional subsystems",
            "System settings: Use Certificate Rules on Windows Executables for Software Restriction Policies",
            "User Account Control: Admin Approval Mode for the Built in Administrator account",
            "User Account Control: Allow UIAccess applications to prompt for elevation without using the secure desktop",
            "User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode",
            "User Account Control: Behavior of the elevation prompt for standard users",
            "User Account Control: Detect application installations and prompt for elevation",
            "User Account Control: Only elevate executables that are signed and validated",
            "User Account Control: Only elevate UIAccess applications that are installed in secure locations",
            "User Account Control: Run all administrators in Admin Approval Mode",
            "User Account Control: Switch to the secure desktop when prompting for elevation",
            "User Account Control: Virtualize file and registry write failures to per user locations"
        )]
        [string]
        $Target,
        
        [Parameter(Mandatory, Position = 2)]
        [scriptblock]
        $Should
    )
    function GetSecurityPolicy([string]$Category) {

        function Get-PolicyOptionData {
            [OutputType([hashtable])]
            [CmdletBinding()]
            Param
            (
                [Parameter(Mandatory = $true)]
                [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformation()]
                [hashtable]
                $FilePath
            )
            return $FilePath
        }

        $securityOptionData = Get-PolicyOptionData -FilePath $("$PSScriptRoot\SecurityOptionData.psd1").Normalize()
        
        $SecurityOption = $securityOptionData[$Category]

        If ($SecurityOption) {

            $SecurityPolicyFilePath = Join-Path -Path $env:temp -ChildPath 'SecurityPolicy.inf'
            secedit.exe /export /cfg $SecurityPolicyFilePath /areas 'SECURITYPOLICY' | Out-Null
    
            $policyConfiguration = @{ }

            switch -regex -file $SecurityPolicyFilePath {
                "^\[(.+)\]" {
                    # Section
                    $section = $matches[1]
                    $policyConfiguration[$section] = @{ }
                }
                "(.+?)\s*=(.*)" {
                    # Key
                    $name, $value = $matches[1..2] -replace "\*"
                    $policyConfiguration[$section][$name] = $value.Trim()
                }
            }

            $soSection = $SecurityOption.Section
            $soOptions = $SecurityOption.Option
            $soValue = $SecurityOption.Value                

            $soResultValue = $policyConfiguration.$soSection.$soValue

            If ($soResultValue) {

                If ($soOptions.GetEnumerator().Name -ne 'String') {
                    $soResult = ($soOptions.GetEnumerator() | Where-Object { $_.Value -eq $soResultValue }).Name
                } 
                Else {
                    $soOptionsValue = ($soOptions.GetEnumerator() | Where-Object { $_.Name -eq 'String' }).Value
                    $soResult = $soResultValue -Replace "^$soOptionsValue", ''
                }
            }
            Else {
                $soResult = $null
            }

            Return $soResult
        }
        Else {
            Throw "The security option $Category was not found."
        }
    }

    # Modify the target string to match what is in the SecurityOptionData.psd1 file
    $Category = $Target.Replace(':','').Replace(' ','_')

    $Expression = { GetSecurityPolicy -Category '$Category' }
    $Params = Get-PoshspecParam -TestName SecurityOption -TestExpression $Expression @PSBoundParameters

    Invoke-PoshspecExpression @Params
}