AuditPolicy.psm1

function ConvertFrom-SID {
    <#
    .SYNOPSIS
    Small command that can resolve SID values
 
    .DESCRIPTION
    Small command that can resolve SID values
 
    .PARAMETER SID
    Value to resolve
 
    .PARAMETER OnlyWellKnown
    Only resolve SID when it's well know SID. Otherwise return $null
 
    .PARAMETER OnlyWellKnownAdministrative
    Only resolve SID when it's administrative well know SID. Otherwise return $null
 
    .PARAMETER DoNotResolve
    Uses only dicrionary values without querying AD
 
    .EXAMPLE
    ConvertFrom-SID -SID 'S-1-5-8', 'S-1-5-9', 'S-1-5-11', 'S-1-5-18', 'S-1-1-0' -DoNotResolve
 
    .NOTES
    General notes
    #>

    [cmdletbinding(DefaultParameterSetName = 'Standard')]
    param([Parameter(ParameterSetName = 'Standard')]
        [Parameter(ParameterSetName = 'OnlyWellKnown')]
        [Parameter(ParameterSetName = 'OnlyWellKnownAdministrative')]
        [string[]] $SID,
        [Parameter(ParameterSetName = 'OnlyWellKnown')][switch] $OnlyWellKnown,
        [Parameter(ParameterSetName = 'OnlyWellKnownAdministrative')][switch] $OnlyWellKnownAdministrative,
        [Parameter(ParameterSetName = 'Standard')][switch] $DoNotResolve)
    $WellKnownAdministrative = @{'S-1-5-18' = [PSCustomObject] @{Name = 'NT AUTHORITY\SYSTEM'
            SID                                                       = 'S-1-5-18'
            DomainName                                                = ''
            Type                                                      = 'WellKnownAdministrative'
            Error                                                     = ''
        }
        'S-1-5-32-544'                      = [PSCustomObject] @{Name = 'BUILTIN\Administrators'
            SID                                  = 'S-1-5-32-544'
            DomainName                           = ''
            Type                                 = 'WellKnownAdministrative'
            Error                                = ''
        }
    }
    $wellKnownSIDs = @{'S-1-0' = [PSCustomObject] @{Name = 'Null AUTHORITY'
            SID                                          = 'S-1-0'
            DomainName                                   = ''
            Type                                         = 'WellKnownGroup'
            Error                                        = ''
        }
        'S-1-0-0'              = [PSCustomObject] @{Name = 'NULL SID'
            SID                             = 'S-1-0-0'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-1'                = [PSCustomObject] @{Name = 'WORLD AUTHORITY'
            SID                           = 'S-1-1'
            DomainName                    = ''
            Type                          = 'WellKnownGroup'
            Error                         = ''
        }
        'S-1-1-0'              = [PSCustomObject] @{Name = 'Everyone'
            SID                             = 'S-1-1-0'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-2'                = [PSCustomObject] @{Name = 'LOCAL AUTHORITY'
            SID                           = 'S-1-2'
            DomainName                    = ''
            Type                          = 'WellKnownGroup'
            Error                         = ''
        }
        'S-1-2-0'              = [PSCustomObject] @{Name = 'LOCAL'
            SID                             = 'S-1-2-0'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-2-1'              = [PSCustomObject] @{Name = 'CONSOLE LOGON'
            SID                             = 'S-1-2-1'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-3'                = [PSCustomObject] @{Name = 'CREATOR AUTHORITY'
            SID                           = 'S-1-3'
            DomainName                    = ''
            Type                          = 'WellKnownGroup'
            Error                         = ''
        }
        'S-1-3-0'              = [PSCustomObject] @{Name = 'CREATOR OWNER'
            SID                             = 'S-1-3-0'
            DomainName                      = ''
            Type                            = 'WellKnownAdministrative'
            Error                           = ''
        }
        'S-1-3-1'              = [PSCustomObject] @{Name = 'CREATOR GROUP'
            SID                             = 'S-1-3-1'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-3-2'              = [PSCustomObject] @{Name = 'CREATOR OWNER SERVER'
            SID                             = 'S-1-3-2'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-3-3'              = [PSCustomObject] @{Name = 'CREATOR GROUP SERVER'
            SID                             = 'S-1-3-3'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-3-4'              = [PSCustomObject] @{Name = 'OWNER RIGHTS'
            SID                             = 'S-1-3-4'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-5-80-0'           = [PSCustomObject] @{Name = 'NT SERVICE\ALL SERVICES'
            SID                                = 'S-1-5-80-0'
            DomainName                         = ''
            Type                               = 'WellKnownGroup'
            Error                              = ''
        }
        'S-1-4'                = [PSCustomObject] @{Name = 'Non-unique Authority'
            SID                           = 'S-1-4'
            DomainName                    = ''
            Type                          = 'WellKnownGroup'
            Error                         = ''
        }
        'S-1-5'                = [PSCustomObject] @{Name = 'NT AUTHORITY'
            SID                           = 'S-1-5'
            DomainName                    = ''
            Type                          = 'WellKnownGroup'
            Error                         = ''
        }
        'S-1-5-1'              = [PSCustomObject] @{Name = 'NT AUTHORITY\DIALUP'
            SID                             = 'S-1-5-1'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-5-2'              = [PSCustomObject] @{Name = 'NT AUTHORITY\NETWORK'
            SID                             = 'S-1-5-2'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-5-3'              = [PSCustomObject] @{Name = 'NT AUTHORITY\BATCH'
            SID                             = 'S-1-5-3'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-5-4'              = [PSCustomObject] @{Name = 'NT AUTHORITY\INTERACTIVE'
            SID                             = 'S-1-5-4'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-5-6'              = [PSCustomObject] @{Name = 'NT AUTHORITY\SERVICE'
            SID                             = 'S-1-5-6'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-5-7'              = [PSCustomObject] @{Name = 'NT AUTHORITY\ANONYMOUS LOGON'
            SID                             = 'S-1-5-7'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-5-8'              = [PSCustomObject] @{Name = 'NT AUTHORITY\PROXY'
            SID                             = 'S-1-5-8'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-5-9'              = [PSCustomObject] @{Name = 'NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS'
            SID                             = 'S-1-5-9'
            DomainName                      = ''
            Type                            = 'WellKnownGroup'
            Error                           = ''
        }
        'S-1-5-10'             = [PSCustomObject] @{Name = 'NT AUTHORITY\SELF'
            SID                              = 'S-1-5-10'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-11'             = [PSCustomObject] @{Name = 'NT AUTHORITY\Authenticated Users'
            SID                              = 'S-1-5-11'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-12'             = [PSCustomObject] @{Name = 'NT AUTHORITY\RESTRICTED'
            SID                              = 'S-1-5-12'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-13'             = [PSCustomObject] @{Name = 'NT AUTHORITY\TERMINAL SERVER USER'
            SID                              = 'S-1-5-13'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-14'             = [PSCustomObject] @{Name = 'NT AUTHORITY\REMOTE INTERACTIVE LOGON'
            SID                              = 'S-1-5-14'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-15'             = [PSCustomObject] @{Name = 'NT AUTHORITY\This Organization'
            SID                              = 'S-1-5-15'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-17'             = [PSCustomObject] @{Name = 'NT AUTHORITY\IUSR'
            SID                              = 'S-1-5-17'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-18'             = [PSCustomObject] @{Name = 'NT AUTHORITY\SYSTEM'
            SID                              = 'S-1-5-18'
            DomainName                       = ''
            Type                             = 'WellKnownAdministrative'
            Error                            = ''
        }
        'S-1-5-19'             = [PSCustomObject] @{Name = 'NT AUTHORITY\NETWORK SERVICE'
            SID                              = 'S-1-5-19'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-20'             = [PSCustomObject] @{Name = 'NT AUTHORITY\NETWORK SERVICE'
            SID                              = 'S-1-5-20'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-32-544'         = [PSCustomObject] @{Name = 'BUILTIN\Administrators'
            SID                                  = 'S-1-5-32-544'
            DomainName                           = ''
            Type                                 = 'WellKnownAdministrative'
            Error                                = ''
        }
        'S-1-5-32-545'         = [PSCustomObject] @{Name = 'BUILTIN\Users'
            SID                                  = 'S-1-5-32-545'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-546'         = [PSCustomObject] @{Name = 'BUILTIN\Guests'
            SID                                  = 'S-1-5-32-546'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-547'         = [PSCustomObject] @{Name = 'BUILTIN\Power Users'
            SID                                  = 'S-1-5-32-547'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-548'         = [PSCustomObject] @{Name = 'BUILTIN\Account Operators'
            SID                                  = 'S-1-5-32-548'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-549'         = [PSCustomObject] @{Name = 'BUILTIN\Server Operators'
            SID                                  = 'S-1-5-32-549'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-550'         = [PSCustomObject] @{Name = 'BUILTIN\Print Operators'
            SID                                  = 'S-1-5-32-550'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-551'         = [PSCustomObject] @{Name = 'BUILTIN\Backup Operators'
            SID                                  = 'S-1-5-32-551'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-552'         = [PSCustomObject] @{Name = 'BUILTIN\Replicators'
            SID                                  = 'S-1-5-32-552'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-64-10'          = [PSCustomObject] @{Name = 'NT AUTHORITY\NTLM Authentication'
            SID                                 = 'S-1-5-64-10'
            DomainName                          = ''
            Type                                = 'WellKnownGroup'
            Error                               = ''
        }
        'S-1-5-64-14'          = [PSCustomObject] @{Name = 'NT AUTHORITY\SChannel Authentication'
            SID                                 = 'S-1-5-64-14'
            DomainName                          = ''
            Type                                = 'WellKnownGroup'
            Error                               = ''
        }
        'S-1-5-64-21'          = [PSCustomObject] @{Name = 'NT AUTHORITY\Digest Authentication'
            SID                                 = 'S-1-5-64-21'
            DomainName                          = ''
            Type                                = 'WellKnownGroup'
            Error                               = ''
        }
        'S-1-5-80'             = [PSCustomObject] @{Name = 'NT SERVICE'
            SID                              = 'S-1-5-80'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-5-83-0'           = [PSCustomObject] @{Name = 'NT VIRTUAL MACHINE\Virtual Machines'
            SID                                = 'S-1-5-83-0'
            DomainName                         = ''
            Type                               = 'WellKnownGroup'
            Error                              = ''
        }
        'S-1-16-0'             = [PSCustomObject] @{Name = 'Untrusted Mandatory Level'
            SID                              = 'S-1-16-0'
            DomainName                       = ''
            Type                             = 'WellKnownGroup'
            Error                            = ''
        }
        'S-1-16-4096'          = [PSCustomObject] @{Name = 'Low Mandatory Level'
            SID                                 = 'S-1-16-4096'
            DomainName                          = ''
            Type                                = 'WellKnownGroup'
            Error                               = ''
        }
        'S-1-16-8192'          = [PSCustomObject] @{Name = 'Medium Mandatory Level'
            SID                                 = 'S-1-16-8192'
            DomainName                          = ''
            Type                                = 'WellKnownGroup'
            Error                               = ''
        }
        'S-1-16-8448'          = [PSCustomObject] @{Name = 'Medium Plus Mandatory Level'
            SID                                 = 'S-1-16-8448'
            DomainName                          = ''
            Type                                = 'WellKnownGroup'
            Error                               = ''
        }
        'S-1-16-12288'         = [PSCustomObject] @{Name = 'High Mandatory Level'
            SID                                  = 'S-1-16-12288'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-16-16384'         = [PSCustomObject] @{Name = 'System Mandatory Level'
            SID                                  = 'S-1-16-16384'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-16-20480'         = [PSCustomObject] @{Name = 'Protected Process Mandatory Level'
            SID                                  = 'S-1-16-20480'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-16-28672'         = [PSCustomObject] @{Name = 'Secure Process Mandatory Level'
            SID                                  = 'S-1-16-28672'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-554'         = [PSCustomObject] @{Name = 'BUILTIN\Pre-Windows 2000 Compatible Access'
            SID                                  = 'S-1-5-32-554'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-555'         = [PSCustomObject] @{Name = 'BUILTIN\Remote Desktop Users'
            SID                                  = 'S-1-5-32-555'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-556'         = [PSCustomObject] @{Name = 'BUILTIN\Network Configuration Operators'
            SID                                  = 'S-1-5-32-556'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-557'         = [PSCustomObject] @{Name = 'BUILTIN\Incoming Forest Trust Builders'
            SID                                  = 'S-1-5-32-557'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-558'         = [PSCustomObject] @{Name = 'BUILTIN\Performance Monitor Users'
            SID                                  = 'S-1-5-32-558'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-559'         = [PSCustomObject] @{Name = 'BUILTIN\Performance Log Users'
            SID                                  = 'S-1-5-32-559'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-560'         = [PSCustomObject] @{Name = 'BUILTIN\Windows Authorization Access Group'
            SID                                  = 'S-1-5-32-560'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-561'         = [PSCustomObject] @{Name = 'BUILTIN\Terminal Server License Servers'
            SID                                  = 'S-1-5-32-561'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-562'         = [PSCustomObject] @{Name = 'BUILTIN\Distributed COM Users'
            SID                                  = 'S-1-5-32-562'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-569'         = [PSCustomObject] @{Name = 'BUILTIN\Cryptographic Operators'
            SID                                  = 'S-1-5-32-569'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-573'         = [PSCustomObject] @{Name = 'BUILTIN\Event Log Readers'
            SID                                  = 'S-1-5-32-573'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-574'         = [PSCustomObject] @{Name = 'BUILTIN\Certificate Service DCOM Access'
            SID                                  = 'S-1-5-32-574'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-575'         = [PSCustomObject] @{Name = 'BUILTIN\RDS Remote Access Servers'
            SID                                  = 'S-1-5-32-575'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-576'         = [PSCustomObject] @{Name = 'BUILTIN\RDS Endpoint Servers'
            SID                                  = 'S-1-5-32-576'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-577'         = [PSCustomObject] @{Name = 'BUILTIN\RDS Management Servers'
            SID                                  = 'S-1-5-32-577'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-578'         = [PSCustomObject] @{Name = 'BUILTIN\Hyper-V Administrators'
            SID                                  = 'S-1-5-32-578'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-579'         = [PSCustomObject] @{Name = 'BUILTIN\Access Control Assistance Operators'
            SID                                  = 'S-1-5-32-579'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
        'S-1-5-32-580'         = [PSCustomObject] @{Name = 'BUILTIN\Remote Management Users'
            SID                                  = 'S-1-5-32-580'
            DomainName                           = ''
            Type                                 = 'WellKnownGroup'
            Error                                = ''
        }
    }
    foreach ($S in $SID) {
        if ($OnlyWellKnownAdministrative) { if ($WellKnownAdministrative[$S]) { $WellKnownAdministrative[$S] } } elseif ($OnlyWellKnown) { if ($wellKnownSIDs[$S]) { $wellKnownSIDs[$S] } } else {
            if ($wellKnownSIDs[$S]) { $wellKnownSIDs[$S] } else {
                if ($DoNotResolve) {
                    if ($S -like "S-1-5-21-*-519" -or $S -like "S-1-5-21-*-512") {
                        [PSCustomObject] @{Name = $S
                            SID                 = $S
                            DomainName          = ''
                            Type                = 'Administrative'
                            Error               = ''
                        }
                    } else {
                        [PSCustomObject] @{Name = $S
                            SID                 = $S
                            DomainName          = ''
                            Error               = ''
                            Type                = 'NotAdministrative'
                        }
                    }
                } else {
                    try {
                        if ($S -like "S-1-5-21-*-519" -or $S -like "S-1-5-21-*-512") { $Type = 'Administrative' } else { $Type = 'NotAdministrative' }
                        $Name = (([System.Security.Principal.SecurityIdentifier]::new($S)).Translate([System.Security.Principal.NTAccount])).Value
                        [PSCustomObject] @{Name = $Name
                            SID                 = $S
                            DomainName          = (ConvertFrom-NetbiosName -Identity $Name).DomainName
                            Type                = $Type
                            Error               = ''
                        }
                    } catch {
                        [PSCustomObject] @{Name = $S
                            SID                 = $S
                            DomainName          = ''
                            Error               = $_.Exception.Message -replace [environment]::NewLine, ' '
                            Type                = 'Unknown'
                        }
                    }
                }
            }
        }
    }
}
function ConvertTo-JsonLiteral {
    <#
    .SYNOPSIS
    Converts an object to a JSON-formatted string.
 
    .DESCRIPTION
    The ConvertTo-Json cmdlet converts any object to a string in JavaScript Object Notation (JSON) format. The properties are converted to field names, the field values are converted to property values, and the methods are removed.
 
    .PARAMETER Object
    Specifies the objects to convert to JSON format. Enter a variable that contains the objects, or type a command or expression that gets the objects. You can also pipe an object to ConvertTo-JsonLiteral
 
    .PARAMETER Depth
    Specifies how many levels of contained objects are included in the JSON representation. The default value is 0.
 
    .PARAMETER AsArray
    Outputs the object in array brackets, even if the input is a single object.
 
    .PARAMETER DateTimeFormat
    Changes DateTime string format. Default "yyyy-MM-dd HH:mm:ss"
 
    .PARAMETER NumberAsString
    Provides an alternative serialization option that converts all numbers to their string representation.
 
    .PARAMETER BoolAsString
    Provides an alternative serialization option that converts all bool to their string representation.
 
    .PARAMETER PropertyName
    Uses PropertyNames provided by user (only works with Force)
 
    .PARAMETER NewLineFormat
    Provides a way to configure how new lines are converted for property names
 
    .PARAMETER NewLineFormatProperty
    Provides a way to configure how new lines are converted for values
 
    .PARAMETER PropertyName
    Allows passing property names to be used for custom objects (hashtables and alike are unaffected)
 
    .PARAMETER ArrayJoin
    Forces any array to be a string regardless of depth level
 
    .PARAMETER ArrayJoinString
    Uses defined string or char for array join. By default it uses comma with a space when used.
 
    .PARAMETER Force
    Forces using property names from first object or given thru PropertyName parameter
 
    .EXAMPLE
    Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral
 
    .EXAMPLE
    Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -Depth 3
 
    .EXAMPLE
    Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -NewLineFormat $NewLineFormat = @{
        NewLineCarriage = '\r\n'
        NewLine = "\n"
        Carriage = "\r"
    } -NumberAsString -BoolAsString
 
    .EXAMPLE
    Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -NumberAsString -BoolAsString -DateTimeFormat "yyyy-MM-dd HH:mm:ss"
 
    .EXAMPLE
    # Keep in mind this advanced replace will break ConvertFrom-Json, but it's sometimes useful for projects like PSWriteHTML
    Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -NewLineFormat $NewLineFormat = @{
        NewLineCarriage = '\r\n'
        NewLine = "\n"
        Carriage = "\r"
    } -NumberAsString -BoolAsString -AdvancedReplace @{ '.' = '\.'; '$' = '\$' }
 
    .NOTES
    General notes
    #>

    [cmdletBinding()]
    param([alias('InputObject')][Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0, Mandatory)][Array] $Object,
        [int] $Depth,
        [switch] $AsArray,
        [string] $DateTimeFormat = "yyyy-MM-dd HH:mm:ss",
        [switch] $NumberAsString,
        [switch] $BoolAsString,
        [System.Collections.IDictionary] $NewLineFormat = @{NewLineCarriage = '\r\n'
            NewLine                                                         = "\n"
            Carriage                                                        = "\r"
        },
        [System.Collections.IDictionary] $NewLineFormatProperty = @{NewLineCarriage = '\r\n'
            NewLine                                                                 = "\n"
            Carriage                                                                = "\r"
        },
        [System.Collections.IDictionary] $AdvancedReplace,
        [string] $ArrayJoinString,
        [switch] $ArrayJoin,
        [string[]]$PropertyName,
        [switch] $Force)
    Begin {
        $TextBuilder = [System.Text.StringBuilder]::new()
        $CountObjects = 0
        filter IsNumeric() { return $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] }
        filter IsOfType() { return $_ -is [bool] -or $_ -is [char] -or $_ -is [datetime] -or $_ -is [string] -or $_ -is [timespan] -or $_ -is [URI] -or $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] }
        [int] $MaxDepth = $Depth
        [int] $InitialDepth = 0
    }
    Process {
        for ($a = 0; $a -lt $Object.Count; $a++) {
            $CountObjects++
            if ($CountObjects -gt 1) { $null = $TextBuilder.Append(',') }
            if ($Object[$a] -is [System.Collections.IDictionary]) {
                $null = $TextBuilder.AppendLine("{")
                for ($i = 0; $i -lt ($Object[$a].Keys).Count; $i++) {
                    $Property = ([string[]]$Object[$a].Keys)[$i]
                    $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage)
                    $null = $TextBuilder.Append("`"$DisplayProperty`":")
                    $Value = ConvertTo-StringByType -Value $Object[$a][$Property] -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $InitialDepth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -NewLineFormat $NewLineFormat -NewLineFormatProperty $NewLineFormatProperty -Force:$Force -ArrayJoin:$ArrayJoin -ArrayJoinString $ArrayJoinString -AdvancedReplace $AdvancedReplace
                    $null = $TextBuilder.Append("$Value")
                    if ($i -ne ($Object[$a].Keys).Count - 1) { $null = $TextBuilder.AppendLine(',') }
                }
                $null = $TextBuilder.Append("}")
            } elseif ($Object[$a] | IsOfType) {
                $Value = ConvertTo-StringByType -Value $Object[$a] -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $InitialDepth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -NewLineFormat $NewLineFormat -NewLineFormatProperty $NewLineFormatProperty -Force:$Force -ArrayJoin:$ArrayJoin -ArrayJoinString $ArrayJoinString -AdvancedReplace $AdvancedReplace
                $null = $TextBuilder.Append($Value)
            } else {
                $null = $TextBuilder.AppendLine("{")
                if ($Force -and -not $PropertyName) { $PropertyName = $Object[0].PSObject.Properties.Name } elseif ($Force -and $PropertyName) {} else { $PropertyName = $Object[$a].PSObject.Properties.Name }
                $PropertyCount = 0
                foreach ($Property in $PropertyName) {
                    $PropertyCount++
                    $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage)
                    $null = $TextBuilder.Append("`"$DisplayProperty`":")
                    $Value = ConvertTo-StringByType -Value $Object[$a].$Property -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $InitialDepth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -NewLineFormat $NewLineFormat -NewLineFormatProperty $NewLineFormatProperty -Force:$Force -ArrayJoin:$ArrayJoin -ArrayJoinString $ArrayJoinString -AdvancedReplace $AdvancedReplace
                    $null = $TextBuilder.Append("$Value")
                    if ($PropertyCount -ne $PropertyName.Count) { $null = $TextBuilder.AppendLine(',') }
                }
                $null = $TextBuilder.Append("}")
            }
            $InitialDepth = 0
        }
    }
    End { if ($CountObjects -gt 1 -or $AsArray) { "[$($TextBuilder.ToString())]" } else { $TextBuilder.ToString() } }
}
function Get-ComputerOperatingSystem {
    [CmdletBinding()]
    param([string[]] $ComputerName = $Env:COMPUTERNAME,
        [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default',
        [switch] $All)
    [string] $Class = 'win32_operatingsystem'
    if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = 'Caption', 'Manufacturer', 'InstallDate', 'OSArchitecture', 'Version', 'SerialNumber', 'BootDevice', 'WindowsDirectory', 'CountryCode', 'OSLanguage', 'OSProductSuite', 'PSComputerName', 'LastBootUpTime', 'LocalDateTime' }
    $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties
    if ($All) { $Information } else {
        foreach ($Info in $Information) {
            foreach ($Data in $Info) {
                [PSCustomObject] @{ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME }
                    OperatingSystem             = $Data.Caption
                    OperatingSystemVersion      = ConvertTo-OperatingSystem -OperatingSystem $Data.Caption -OperatingSystemVersion $Data.Version
                    OperatingSystemBuild        = $Data.Version
                    Manufacturer                = $Data.Manufacturer
                    OSArchitecture              = $Data.OSArchitecture
                    OSLanguage                  = ConvertFrom-LanguageCode -LanguageCode $Data.OSLanguage
                    OSProductSuite              = [Microsoft.PowerShell.Commands.OSProductSuite] $($Data.OSProductSuite)
                    InstallDate                 = $Data.InstallDate
                    LastBootUpTime              = $Data.LastBootUpTime
                    LocalDateTime               = $Data.LocalDateTime
                    SerialNumber                = $Data.SerialNumber
                    BootDevice                  = $Data.BootDevice
                    WindowsDirectory            = $Data.WindowsDirectory
                    CountryCode                 = $Data.CountryCode
                }
            }
        }
    }
}
function Get-PSRegistry {
    <#
    .SYNOPSIS
    Get registry key values.
 
    .DESCRIPTION
    Get registry key values.
 
    .PARAMETER RegistryPath
    The registry path to get the values from.
 
    .PARAMETER ComputerName
    The computer to get the values from. If not specified, the local computer is used.
 
    .EXAMPLE
    Get-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters' -ComputerName AD1
 
    .EXAMPLE
    Get-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters'
 
    .EXAMPLE
    Get-PSRegistry -RegistryPath "HKLM\SYSTEM\CurrentControlSet\Services\DFSR\Parameters" -ComputerName AD1,AD2,AD3 | ft -AutoSize
 
    .EXAMPLE
    Get-PSRegistry -RegistryPath 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Directory Service'
 
    .EXAMPLE
    Get-PSRegistry -RegistryPath 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Windows PowerShell' | Format-Table -AutoSize
 
    .EXAMPLE
    Get-PSRegistry -RegistryPath 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Directory Service' -ComputerName AD1 -Advanced
 
    .EXAMPLE
    Get-PSRegistry -RegistryPath "HKLM:\Software\Microsoft\Powershell\1\Shellids\Microsoft.Powershell\"
 
    .EXAMPLE
    # Get default key and it's value
    Get-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests" -Key ""
 
    .EXAMPLE
    # Get default key and it's value (alternative)
o Get-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests" -DefaultKey
 
    .NOTES
    General notes
    #>

    [cmdletbinding()]
    param([alias('Path')][string[]] $RegistryPath,
        [string[]] $ComputerName = $Env:COMPUTERNAME,
        [string] $Key,
        [switch] $Advanced,
        [switch] $DefaultKey)
    Get-PSRegistryDictionaries
    $RegistryPath = Resolve-PrivateRegistry -RegistryPath $RegistryPath
    [Array] $Computers = Get-ComputerSplit -ComputerName $ComputerName
    [Array] $RegistryTranslated = Get-PSConvertSpecialRegistry -RegistryPath $RegistryPath -Computers $ComputerName -HiveDictionary $Script:HiveDictionary
    if ($PSBoundParameters.ContainsKey("Key") -or $DefaultKey) {
        [Array] $RegistryValues = Get-PSSubRegistryTranslated -RegistryPath $RegistryTranslated -HiveDictionary $Script:HiveDictionary -Key $Key
        foreach ($Computer in $Computers[0]) { foreach ($R in $RegistryValues) { Get-PSSubRegistry -Registry $R -ComputerName $Computer } }
        foreach ($Computer in $Computers[1]) { foreach ($R in $RegistryValues) { Get-PSSubRegistry -Registry $R -ComputerName $Computer -Remote } }
    } else {
        [Array] $RegistryValues = Get-PSSubRegistryTranslated -RegistryPath $RegistryTranslated -HiveDictionary $Script:HiveDictionary
        foreach ($Computer in $Computers[0]) { foreach ($R in $RegistryValues) { Get-PSSubRegistryComplete -Registry $R -ComputerName $Computer -Advanced:$Advanced } }
        foreach ($Computer in $Computers[1]) { foreach ($R in $RegistryValues) { Get-PSSubRegistryComplete -Registry $R -ComputerName $Computer -Remote -Advanced:$Advanced } }
    }
    if ($Script:DefaultRegistryMounted) {
        $null = Dismount-DefaultRegistryPath
        $Script:DefaultRegistryMounted = $null
    }
}
function Set-PSRegistry {
    <#
    .SYNOPSIS
    Sets/Updates registry entries locally and remotely using .NET methods.
 
    .DESCRIPTION
    Sets/Updates registry entries locally and remotely using .NET methods. If the registry path to key doesn't exists it will be created.
 
    .PARAMETER ComputerName
    The computer to run the command on. Defaults to local computer.
 
    .PARAMETER RegistryPath
    Registry Path to Update
 
    .PARAMETER Type
    Registry type to use. Options are: REG_SZ, REG_EXPAND_SZ, REG_BINARY, REG_DWORD, REG_MULTI_SZ, REG_QWORD, string, expandstring, binary, dword, multistring, qword
 
    .PARAMETER Key
    Registry key to set. If the path to registry key doesn't exists it will be created.
 
    .PARAMETER Value
    Registry value to set.
 
    .PARAMETER Suppress
    Suppresses the output of the command. By default the command outputs PSObject with the results of the operation.
 
    .EXAMPLE
    Set-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics' -Type REG_DWORD -Key "16 LDAP Interface Events" -Value 2 -ComputerName AD1
 
    .EXAMPLE
    Set-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics' -Type REG_SZ -Key "LDAP Interface Events" -Value 'test' -ComputerName AD1
 
    .EXAMPLE
    Set-PSRegistry -RegistryPath "HKCU:\\Tests" -Key "LimitBlankPass1wordUse" -Value "0" -Type REG_DWORD
 
    .EXAMPLE
    Set-PSRegistry -RegistryPath "HKCU:\\Tests\MoreTests\Tests1" -Key "LimitBlankPass1wordUse" -Value "0" -Type REG_DWORD
 
    .EXAMPLE
    # Setting default value
 
    $ValueData = [byte[]] @(
        0, 1, 0, 0, 9, 0, 0, 0, 128, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3,
        0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3,
        0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3,
        0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3,
        0, 3, 0, 0, 0, 5, 0, 10, 0, 14, 0, 3, 0, 5, 0, 6, 0, 6, 0, 4, 0, 4, 0
    )
    Set-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests" -Key '' -Value $ValueData -Type 'NONE'
 
    .NOTES
    General notes
    #>

    [cmdletbinding(SupportsShouldProcess)]
    param([string[]] $ComputerName = $Env:COMPUTERNAME,
        [Parameter(Mandatory)][string] $RegistryPath,
        [Parameter(Mandatory)][ValidateSet('REG_SZ', 'REG_NONE', 'None', 'REG_EXPAND_SZ', 'REG_BINARY', 'REG_DWORD', 'REG_MULTI_SZ', 'REG_QWORD', 'string', 'binary', 'dword', 'qword', 'multistring', 'expandstring')][string] $Type,
        [Parameter()][string] $Key,
        [Parameter(Mandatory)][object] $Value,
        [switch] $Suppress)
    Get-PSRegistryDictionaries
    [Array] $ComputersSplit = Get-ComputerSplit -ComputerName $ComputerName
    $RegistryPath = Resolve-PrivateRegistry -RegistryPath $RegistryPath
    [Array] $RegistryTranslated = Get-PSConvertSpecialRegistry -RegistryPath $RegistryPath -Computers $ComputerName -HiveDictionary $Script:HiveDictionary
    foreach ($Registry in $RegistryTranslated) {
        $RegistryValue = Get-PrivateRegistryTranslated -RegistryPath $Registry -HiveDictionary $Script:HiveDictionary -Key $Key -Value $Value -Type $Type -ReverseTypesDictionary $Script:ReverseTypesDictionary
        if ($RegistryValue.HiveKey) {
            foreach ($Computer in $ComputersSplit[0]) { Set-PrivateRegistry -RegistryValue $RegistryValue -Computer $Computer -Suppress:$Suppress.IsPresent -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference }
            foreach ($Computer in $ComputersSplit[1]) { Set-PrivateRegistry -RegistryValue $RegistryValue -Computer $Computer -Remote -Suppress:$Suppress.IsPresent -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference }
        } else {
            if ($PSBoundParameters.ErrorAction -eq 'Stop') {
                if ($Script:DefaultRegistryMounted) {
                    $null = Dismount-DefaultRegistryPath
                    $Script:DefaultRegistryMounted = $null
                }
                throw
            } else { Write-Warning "Set-PSRegistry - Setting registry to $Registry have failed. Couldn't translate HIVE." }
        }
    }
    if ($Script:DefaultRegistryMounted) {
        $null = Dismount-DefaultRegistryPath
        $Script:DefaultRegistryMounted = $null
    }
}
function ConvertFrom-LanguageCode {
    [cmdletBinding()]
    param([string] $LanguageCode)
    $LanguageCodeDictionary = @{'1' = "Arabic"
        '4'                         = "Chinese (Simplified)?? China"
        '9'                         = "English"
        '1025'                      = "Arabic (Saudi Arabia)"
        '1026'                      = "Bulgarian"
        '1027'                      = "Catalan"
        '1028'                      = "Chinese (Traditional) Taiwan"
        '1029'                      = "Czech"
        '1030'                      = "Danish"
        '1031'                      = "German (Germany)"
        '1032'                      = "Greek"
        '1033'                      = "English (United States)"
        '1034'                      = "Spanish (Traditional Sort)"
        '1035'                      = "Finnish"
        '1036'                      = "French (France)"
        '1037'                      = "Hebrew"
        '1038'                      = "Hungarian"
        '1039'                      = "Icelandic"
        '1040'                      = "Italian (Italy)"
        '1041'                      = "Japanese"
        '1042'                      = "Korean"
        '1043'                      = "Dutch (Netherlands)"
        '1044'                      = "Norwegian (Bokmal)"
        '1045'                      = "Polish"
        '1046'                      = "Portuguese (Brazil)"
        '1047'                      = "Rhaeto-Romanic"
        '1048'                      = "Romanian"
        '1049'                      = "Russian"
        '1050'                      = "Croatian"
        '1051'                      = "Slovak"
        '1052'                      = "Albanian"
        '1053'                      = "Swedish"
        '1054'                      = "Thai"
        '1055'                      = "Turkish"
        '1056'                      = "Urdu"
        '1057'                      = "Indonesian"
        '1058'                      = "Ukrainian"
        '1059'                      = "Belarusian"
        '1060'                      = "Slovenian"
        '1061'                      = "Estonian"
        '1062'                      = "Latvian"
        '1063'                      = "Lithuanian"
        '1065'                      = "Persian"
        '1066'                      = "Vietnamese"
        '1069'                      = "Basque (Basque)"
        '1070'                      = "Serbian"
        '1071'                      = "Macedonian (FYROM)"
        '1072'                      = "Sutu"
        '1073'                      = "Tsonga"
        '1074'                      = "Tswana"
        '1076'                      = "Xhosa"
        '1077'                      = "Zulu"
        '1078'                      = "Afrikaans"
        '1080'                      = "Faeroese"
        '1081'                      = "Hindi"
        '1082'                      = "Maltese"
        '1084'                      = "Scottish Gaelic (United Kingdom)"
        '1085'                      = "Yiddish"
        '1086'                      = "Malay (Malaysia)"
        '2049'                      = "Arabic (Iraq)"
        '2052'                      = "Chinese (Simplified) PRC"
        '2055'                      = "German (Switzerland)"
        '2057'                      = "English (United Kingdom)"
        '2058'                      = "Spanish (Mexico)"
        '2060'                      = "French (Belgium)"
        '2064'                      = "Italian (Switzerland)"
        '2067'                      = "Dutch (Belgium)"
        '2068'                      = "Norwegian (Nynorsk)"
        '2070'                      = "Portuguese (Portugal)"
        '2072'                      = "Romanian (Moldova)"
        '2073'                      = "Russian (Moldova)"
        '2074'                      = "Serbian (Latin)"
        '2077'                      = "Swedish (Finland)"
        '3073'                      = "Arabic (Egypt)"
        '3076'                      = "Chinese Traditional (Hong Kong SAR)"
        '3079'                      = "German (Austria)"
        '3081'                      = "English (Australia)"
        '3082'                      = "Spanish (International Sort)"
        '3084'                      = "French (Canada)"
        '3098'                      = "Serbian (Cyrillic)"
        '4097'                      = "Arabic (Libya)"
        '4100'                      = "Chinese Simplified (Singapore)"
        '4103'                      = "German (Luxembourg)"
        '4105'                      = "English (Canada)"
        '4106'                      = "Spanish (Guatemala)"
        '4108'                      = "French (Switzerland)"
        '5121'                      = "Arabic (Algeria)"
        '5127'                      = "German (Liechtenstein)"
        '5129'                      = "English (New Zealand)"
        '5130'                      = "Spanish (Costa Rica)"
        '5132'                      = "French (Luxembourg)"
        '6145'                      = "Arabic (Morocco)"
        '6153'                      = "English (Ireland)"
        '6154'                      = "Spanish (Panama)"
        '7169'                      = "Arabic (Tunisia)"
        '7177'                      = "English (South Africa)"
        '7178'                      = "Spanish (Dominican Republic)"
        '8193'                      = "Arabic (Oman)"
        '8201'                      = "English (Jamaica)"
        '8202'                      = "Spanish (Venezuela)"
        '9217'                      = "Arabic (Yemen)"
        '9226'                      = "Spanish (Colombia)"
        '10241'                     = "Arabic (Syria)"
        '10249'                     = "English (Belize)"
        '10250'                     = "Spanish (Peru)"
        '11265'                     = "Arabic (Jordan)"
        '11273'                     = "English (Trinidad)"
        '11274'                     = "Spanish (Argentina)"
        '12289'                     = "Arabic (Lebanon)"
        '12298'                     = "Spanish (Ecuador)"
        '13313'                     = "Arabic (Kuwait)"
        '13322'                     = "Spanish (Chile)"
        '14337'                     = "Arabic (U.A.E.)"
        '14346'                     = "Spanish (Uruguay)"
        '15361'                     = "Arabic (Bahrain)"
        '15370'                     = "Spanish (Paraguay)"
        '16385'                     = "Arabic (Qatar)"
        '16394'                     = "Spanish (Bolivia)"
        '17418'                     = "Spanish (El Salvador)"
        '18442'                     = "Spanish (Honduras)"
        '19466'                     = "Spanish (Nicaragua)"
        '20490'                     = "Spanish (Puerto Rico)"
    }
    $Output = $LanguageCodeDictionary[$LanguageCode]
    if ($Output) { $Output } else { "Unknown (Undocumented)" }
}
function ConvertFrom-NetbiosName {
    [cmdletBinding()]
    param([Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)]
        [string[]] $Identity)
    process {
        foreach ($Ident in $Identity) {
            if ($Ident -like '*\*') {
                $NetbiosWithObject = $Ident -split "\\"
                if ($NetbiosWithObject.Count -eq 2) {
                    $LDAPQuery = ([ADSI]"LDAP://$($NetbiosWithObject[0])")
                    $DomainName = ConvertFrom-DistinguishedName -DistinguishedName $LDAPQuery.distinguishedName -ToDomainCN
                    [PSCustomObject] @{DomainName = $DomainName
                        Name                      = $NetbiosWithObject[1]
                    }
                } else {
                    [PSCustomObject] @{DomainName = ''
                        Name                      = $Ident
                    }
                }
            } else {
                [PSCustomObject] @{DomainName = ''
                    Name                      = $Ident
                }
            }
        }
    }
}
function ConvertTo-OperatingSystem {
    <#
    .SYNOPSIS
    Allows easy conversion of OperatingSystem, Operating System Version to proper Windows 10 naming based on WMI or AD
 
    .DESCRIPTION
    Allows easy conversion of OperatingSystem, Operating System Version to proper Windows 10 naming based on WMI or AD
 
    .PARAMETER OperatingSystem
    Operating System as returned by Active Directory
 
    .PARAMETER OperatingSystemVersion
    Operating System Version as returned by Active Directory
 
    .EXAMPLE
    $Computers = Get-ADComputer -Filter * -Properties OperatingSystem, OperatingSystemVersion | ForEach-Object {
        $OPS = ConvertTo-OperatingSystem -OperatingSystem $_.OperatingSystem -OperatingSystemVersion $_.OperatingSystemVersion
        Add-Member -MemberType NoteProperty -Name 'OperatingSystemTranslated' -Value $OPS -InputObject $_ -Force
        $_
    }
    $Computers | Select-Object DNS*, Name, SamAccountName, Enabled, OperatingSystem*, DistinguishedName | Format-Table
 
    .EXAMPLE
    $Registry = Get-PSRegistry -ComputerName 'AD1' -RegistryPath 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
    ConvertTo-OperatingSystem -OperatingSystem $Registry.ProductName -OperatingSystemVersion $Registry.CurrentBuildNumber
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([string] $OperatingSystem,
        [string] $OperatingSystemVersion)
    if ($OperatingSystem -like 'Windows 10*' -or $OperatingSystem -like 'Windows 11*') {
        $Systems = @{'10.0 (22000)' = 'Windows 11 21H2'
            '10.0 (19043)'          = 'Windows 10 21H1'
            '10.0 (19042)'          = 'Windows 10 20H2'
            '10.0 (19041)'          = 'Windows 10 2004'
            '10.0 (18898)'          = 'Windows 10 Insider Preview'
            '10.0 (18363)'          = "Windows 10 1909"
            '10.0 (18362)'          = "Windows 10 1903"
            '10.0 (17763)'          = "Windows 10 1809"
            '10.0 (17134)'          = "Windows 10 1803"
            '10.0 (16299)'          = "Windows 10 1709"
            '10.0 (15063)'          = "Windows 10 1703"
            '10.0 (14393)'          = "Windows 10 1607"
            '10.0 (10586)'          = "Windows 10 1511"
            '10.0 (10240)'          = "Windows 10 1507"
            '10.0.22000'            = 'Windows 11 21H2'
            '10.0.19043'            = 'Windows 10 21H1'
            '10.0.19042'            = 'Windows 10 20H2'
            '10.0.19041'            = 'Windows 10 2004'
            '10.0.18898'            = 'Windows 10 Insider Preview'
            '10.0.18363'            = "Windows 10 1909"
            '10.0.18362'            = "Windows 10 1903"
            '10.0.17763'            = "Windows 10 1809"
            '10.0.17134'            = "Windows 10 1803"
            '10.0.16299'            = "Windows 10 1709"
            '10.0.15063'            = "Windows 10 1703"
            '10.0.14393'            = "Windows 10 1607"
            '10.0.10586'            = "Windows 10 1511"
            '10.0.10240'            = "Windows 10 1507"
            '22000'                 = 'Windows 11 21H2'
            '19043'                 = 'Windows 10 21H1'
            '19042'                 = 'Windows 10 20H2'
            '19041'                 = 'Windows 10 2004'
            '18898'                 = 'Windows 10 Insider Preview'
            '18363'                 = "Windows 10 1909"
            '18362'                 = "Windows 10 1903"
            '17763'                 = "Windows 10 1809"
            '17134'                 = "Windows 10 1803"
            '16299'                 = "Windows 10 1709"
            '15063'                 = "Windows 10 1703"
            '14393'                 = "Windows 10 1607"
            '10586'                 = "Windows 10 1511"
            '10240'                 = "Windows 10 1507"
        }
        $System = $Systems[$OperatingSystemVersion]
        if (-not $System) { $System = $OperatingSystem }
    } elseif ($OperatingSystem -like 'Windows Server*') {
        $Systems = @{'10.0 (20348)' = 'Windows Server 2022'
            '10.0 (19042)'          = 'Windows Server 2019 20H2'
            '10.0 (19041)'          = 'Windows Server 2019 2004'
            '10.0 (18363)'          = 'Windows Server 2019 1909'
            '10.0 (18362)'          = "Windows Server 2019 1903"
            '10.0 (17763)'          = "Windows Server 2019 1809"
            '10.0 (17134)'          = "Windows Server 2016 1803"
            '10.0 (14393)'          = "Windows Server 2016 1607"
            '6.3 (9600)'            = 'Windows Server 2012 R2'
            '6.1 (7601)'            = 'Windows Server 2008 R2'
            '5.2 (3790)'            = 'Windows Server 2003'
            '10.0.20348'            = 'Windows Server 2022'
            '10.0.19042'            = 'Windows Server 2019 20H2'
            '10.0.19041'            = 'Windows Server 2019 2004'
            '10.0.18363'            = 'Windows Server 2019 1909'
            '10.0.18362'            = "Windows Server 2019 1903"
            '10.0.17763'            = "Windows Server 2019 1809"
            '10.0.17134'            = "Windows Server 2016 1803"
            '10.0.14393'            = "Windows Server 2016 1607"
            '6.3.9600'              = 'Windows Server 2012 R2'
            '6.1.7601'              = 'Windows Server 2008 R2'
            '5.2.3790'              = 'Windows Server 2003'
            '20348'                 = 'Windows Server 2022'
            '19042'                 = 'Windows Server 2019 20H2'
            '19041'                 = 'Windows Server 2019 2004'
            '18363'                 = 'Windows Server 2019 1909'
            '18362'                 = "Windows Server 2019 1903"
            '17763'                 = "Windows Server 2019 1809"
            '17134'                 = "Windows Server 2016 1803"
            '14393'                 = "Windows Server 2016 1607"
            '9600'                  = 'Windows Server 2012 R2'
            '7601'                  = 'Windows Server 2008 R2'
            '3790'                  = 'Windows Server 2003'
        }
        $System = $Systems[$OperatingSystemVersion]
        if (-not $System) { $System = $OperatingSystem }
    } else { $System = $OperatingSystem }
    if ($System) { $System } else { 'Unknown' }
}
function ConvertTo-StringByType {
    <#
    .SYNOPSIS
    Private function to use within ConvertTo-JsonLiteral
 
    .DESCRIPTION
    Private function to use within ConvertTo-JsonLiteral
 
    .PARAMETER Value
    Value to convert to JsonValue
 
     .PARAMETER Depth
    Specifies how many levels of contained objects are included in the JSON representation. The default value is 0.
 
    .PARAMETER AsArray
    Outputs the object in array brackets, even if the input is a single object.
 
    .PARAMETER DateTimeFormat
    Changes DateTime string format. Default "yyyy-MM-dd HH:mm:ss"
 
    .PARAMETER NumberAsString
    Provides an alternative serialization option that converts all numbers to their string representation.
 
    .PARAMETER BoolAsString
    Provides an alternative serialization option that converts all bool to their string representation.
 
    .PARAMETER PropertyName
    Uses PropertyNames provided by user (only works with Force)
 
    .PARAMETER ArrayJoin
    Forces any array to be a string regardless of depth level
 
    .PARAMETER ArrayJoinString
    Uses defined string or char for array join. By default it uses comma with a space when used.
 
    .PARAMETER Force
    Forces using property names from first object or given thru PropertyName parameter
 
    .EXAMPLE
    $Value = ConvertTo-StringByType -Value $($Object[$a][$i]) -DateTimeFormat $DateTimeFormat
 
    .NOTES
    General notes
    #>

    [cmdletBinding()]
    param([Object] $Value,
        [int] $Depth,
        [int] $MaxDepth,
        [string] $DateTimeFormat,
        [switch] $NumberAsString,
        [switch] $BoolAsString,
        [System.Collections.IDictionary] $NewLineFormat = @{NewLineCarriage = '\r\n'
            NewLine                                                         = "\n"
            Carriage                                                        = "\r"
        },
        [System.Collections.IDictionary] $NewLineFormatProperty = @{NewLineCarriage = '\r\n'
            NewLine                                                                 = "\n"
            Carriage                                                                = "\r"
        },
        [System.Collections.IDictionary] $AdvancedReplace,
        [System.Text.StringBuilder] $TextBuilder,
        [string[]] $PropertyName,
        [switch] $ArrayJoin,
        [string] $ArrayJoinString,
        [switch] $Force)
    Process {
        if ($null -eq $Value) { "`"`"" } elseif ($Value -is [string]) {
            $Value = $Value.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormat.NewLineCarriage).Replace("`n", $NewLineFormat.NewLine).Replace("`r", $NewLineFormat.Carriage)
            foreach ($Key in $AdvancedReplace.Keys) { $Value = $Value.Replace($Key, $AdvancedReplace[$Key]) }
            "`"$Value`""
        } elseif ($Value -is [DateTime]) { "`"$($($Value).ToString($DateTimeFormat))`"" } elseif ($Value -is [bool]) { if ($BoolAsString) { "`"$($Value)`"" } else { $Value.ToString().ToLower() } } elseif ($Value -is [System.Collections.IDictionary]) {
            if ($MaxDepth -eq 0 -or $Depth -eq $MaxDepth) { "`"$($Value)`"" } else {
                $Depth++
                $null = $TextBuilder.AppendLine("{")
                for ($i = 0; $i -lt ($Value.Keys).Count; $i++) {
                    $Property = ([string[]]$Value.Keys)[$i]
                    $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage)
                    $null = $TextBuilder.Append("`"$DisplayProperty`":")
                    $OutputValue = ConvertTo-StringByType -Value $Value[$Property] -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $Depth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -Force:$Force -ArrayJoinString $ArrayJoinString
                    $null = $TextBuilder.Append("$OutputValue")
                    if ($i -ne ($Value.Keys).Count - 1) { $null = $TextBuilder.AppendLine(',') }
                }
                $null = $TextBuilder.Append("}")
            }
        } elseif ($Value -is [System.Collections.IList] -or $Value -is [System.Collections.ReadOnlyCollectionBase]) {
            if ($ArrayJoin) {
                $Value = $Value -join $ArrayJoinString
                $Value = "$Value".Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage)
                "`"$Value`""
            } else {
                if ($MaxDepth -eq 0 -or $Depth -eq $MaxDepth) {
                    $Value = "$Value".Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage)
                    "`"$Value`""
                } else {
                    $CountInternalObjects = 0
                    $null = $TextBuilder.Append("[")
                    foreach ($V in $Value) {
                        $CountInternalObjects++
                        if ($CountInternalObjects -gt 1) { $null = $TextBuilder.Append(',') }
                        if ($Force -and -not $PropertyName) { $PropertyName = $V.PSObject.Properties.Name } elseif ($Force -and $PropertyName) {} else { $PropertyName = $V.PSObject.Properties.Name }
                        $OutputValue = ConvertTo-StringByType -Value $V -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $Depth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -Force:$Force -PropertyName $PropertyName -ArrayJoinString $ArrayJoinString
                        $null = $TextBuilder.Append($OutputValue)
                    }
                    $null = $TextBuilder.Append("]")
                }
            }
        } elseif ($Value -is [System.Enum]) { "`"$($($Value).ToString())`"" } elseif (($Value | IsNumeric) -eq $true) {
            $Value = $($Value).ToString().Replace(',', '.')
            if ($NumberAsString) { "`"$Value`"" } else { $Value }
        } elseif ($Value -is [PSObject]) {
            if ($MaxDepth -eq 0 -or $Depth -eq $MaxDepth) { "`"$($Value)`"" } else {
                $Depth++
                $CountInternalObjects = 0
                $null = $TextBuilder.AppendLine("{")
                if ($Force -and -not $PropertyName) { $PropertyName = $Value.PSObject.Properties.Name } elseif ($Force -and $PropertyName) {} else { $PropertyName = $Value.PSObject.Properties.Name }
                foreach ($Property in $PropertyName) {
                    $CountInternalObjects++
                    if ($CountInternalObjects -gt 1) { $null = $TextBuilder.AppendLine(',') }
                    $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage)
                    $null = $TextBuilder.Append("`"$DisplayProperty`":")
                    $OutputValue = ConvertTo-StringByType -Value $Value.$Property -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $Depth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -Force:$Force -ArrayJoinString $ArrayJoinString
                    $null = $TextBuilder.Append("$OutputValue")
                }
                $null = $TextBuilder.Append("}")
            }
        } else {
            $Value = $Value.ToString().Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage)
            "`"$Value`""
        }
    }
}
function Dismount-DefaultRegistryPath {
    [CmdletBinding()]
    param([string] $MountPoint = "HKEY_USERS\.DEFAULT_USER")
    Dismount-PSRegistryPath -MountPoint $MountPoint
}
function Get-CimData {
    <#
    .SYNOPSIS
    Helper function for retreiving CIM data from local and remote computers
 
    .DESCRIPTION
    Helper function for retreiving CIM data from local and remote computers
 
    .PARAMETER ComputerName
    Specifies computer on which you want to run the CIM operation. You can specify a fully qualified domain name (FQDN), a NetBIOS name, or an IP address. If you do not specify this parameter, the cmdlet performs the operation on the local computer using Component Object Model (COM).
 
    .PARAMETER Protocol
    Specifies the protocol to use. The acceptable values for this parameter are: DCOM, Default, or Wsman.
 
    .PARAMETER Class
    Specifies the name of the CIM class for which to retrieve the CIM instances. You can use tab completion to browse the list of classes, because PowerShell gets a list of classes from the local WMI server to provide a list of class names.
 
    .PARAMETER Properties
    Specifies a set of instance properties to retrieve. Use this parameter when you need to reduce the size of the object returned, either in memory or over the network. The object returned also contains the key properties even if you have not listed them using the Property parameter. Other properties of the class are present but they are not populated.
 
    .EXAMPLE
    Get-CimData -Class 'win32_bios' -ComputerName AD1,EVOWIN
 
    Get-CimData -Class 'win32_bios'
 
    # Get-CimClass to get all classes
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([parameter(Mandatory)][string] $Class,
        [string] $NameSpace = 'root\cimv2',
        [string[]] $ComputerName = $Env:COMPUTERNAME,
        [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default',
        [string[]] $Properties = '*')
    $ExcludeProperties = 'CimClass', 'CimInstanceProperties', 'CimSystemProperties', 'SystemCreationClassName', 'CreationClassName'
    [Array] $ComputersSplit = Get-ComputerSplit -ComputerName $ComputerName
    $CimObject = @(# requires removal of this property for query
        [string[]] $PropertiesOnly = $Properties | Where-Object { $_ -ne 'PSComputerName' }
        $Computers = $ComputersSplit[1]
        if ($Computers.Count -gt 0) {
            if ($Protocol = 'Default') { Get-CimInstance -ClassName $Class -ComputerName $Computers -ErrorAction SilentlyContinue -Property $PropertiesOnly -Namespace $NameSpace -Verbose:$false -ErrorVariable ErrorsToProcess | Select-Object -Property $Properties -ExcludeProperty $ExcludeProperties } else {
                $Option = New-CimSessionOption -Protocol $Protocol
                $Session = New-CimSession -ComputerName $Computers -SessionOption $Option -ErrorAction SilentlyContinue
                $Info = Get-CimInstance -ClassName $Class -CimSession $Session -ErrorAction SilentlyContinue -Property $PropertiesOnly -Namespace $NameSpace -Verbose:$false -ErrorVariable ErrorsToProcess | Select-Object -Property $Properties -ExcludeProperty $ExcludeProperties
                $null = Remove-CimSession -CimSession $Session -ErrorAction SilentlyContinue
                $Info
            }
        }
        foreach ($E in $ErrorsToProcess) { Write-Warning -Message "Get-CimData - No data for computer $($E.OriginInfo.PSComputerName). Failed with errror: $($E.Exception.Message)" }
        $Computers = $ComputersSplit[0]
        if ($Computers.Count -gt 0) {
            $Info = Get-CimInstance -ClassName $Class -ErrorAction SilentlyContinue -Property $PropertiesOnly -Namespace $NameSpace -Verbose:$false -ErrorVariable ErrorsLocal | Select-Object -Property $Properties -ExcludeProperty $ExcludeProperties
            $Info | Add-Member -Name 'PSComputerName' -Value $Computers -MemberType NoteProperty -Force
            $Info
        }
        foreach ($E in $ErrorsLocal) { Write-Warning -Message "Get-CimData - No data for computer $($Env:COMPUTERNAME). Failed with errror: $($E.Exception.Message)" })
    $CimObject
}
function Get-ComputerSplit {
    [CmdletBinding()]
    param([string[]] $ComputerName)
    if ($null -eq $ComputerName) { $ComputerName = $Env:COMPUTERNAME }
    try { $LocalComputerDNSName = [System.Net.Dns]::GetHostByName($Env:COMPUTERNAME).HostName } catch { $LocalComputerDNSName = $Env:COMPUTERNAME }
    $ComputersLocal = $null
    [Array] $Computers = foreach ($Computer in $ComputerName) {
        if ($Computer -eq '' -or $null -eq $Computer) { $Computer = $Env:COMPUTERNAME }
        if ($Computer -ne $Env:COMPUTERNAME -and $Computer -ne $LocalComputerDNSName) { $Computer } else { $ComputersLocal = $Computer }
    }
    , @($ComputersLocal, $Computers)
}
function Get-PrivateRegistryTranslated {
    [cmdletBinding()]
    param([Array] $RegistryPath,
        [System.Collections.IDictionary] $HiveDictionary,
        [System.Collections.IDictionary] $ReverseTypesDictionary,
        [Parameter()][ValidateSet('REG_SZ', 'REG_NONE', 'None', 'REG_EXPAND_SZ', 'REG_BINARY', 'REG_DWORD', 'REG_MULTI_SZ', 'REG_QWORD', 'string', 'binary', 'dword', 'qword', 'multistring', 'expandstring')][string] $Type,
        [Parameter()][string] $Key,
        [Parameter()][object] $Value)
    foreach ($Registry in $RegistryPath) {
        if ($Registry -is [string]) { $Registry = $Registry.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") } else { $Registry.RegistryPath = $Registry.RegistryPath.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") }
        foreach ($Hive in $HiveDictionary.Keys) {
            if ($Registry -is [string] -and $Registry.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) {
                if ($Hive.Length -eq $Registry.Length) {
                    [ordered] @{HiveKey = $HiveDictionary[$Hive]
                        SubKeyName      = $null
                        ValueKind       = if ($Type) { [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) } else { $null }
                        Key             = $Key
                        Value           = $Value
                    }
                } else {
                    [ordered] @{HiveKey = $HiveDictionary[$Hive]
                        SubKeyName      = $Registry.substring($Hive.Length + 1)
                        ValueKind       = if ($Type) { [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) } else { $null }
                        Key             = $Key
                        Value           = $Value
                    }
                }
                break
            } elseif ($Registry -isnot [string] -and $Registry.RegistryPath.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) {
                if ($Hive.Length -eq $Registry.RegistryPath.Length) {
                    [ordered] @{ComputerName = $Registry.ComputerName
                        HiveKey              = $HiveDictionary[$Hive]
                        SubKeyName           = $null
                        ValueKind            = if ($Type) { [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) } else { $null }
                        Key                  = $Key
                        Value                = $Value
                    }
                } else {
                    [ordered] @{ComputerName = $Registry.ComputerName
                        HiveKey              = $HiveDictionary[$Hive]
                        SubKeyName           = $Registry.RegistryPath.substring($Hive.Length + 1)
                        ValueKind            = if ($Type) { [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) } else { $null }
                        Key                  = $Key
                        Value                = $Value
                    }
                }
                break
            }
        }
    }
}
function Get-PSConvertSpecialRegistry {
    [cmdletbinding()]
    param([Array] $RegistryPath,
        [Array] $Computers,
        [System.Collections.IDictionary] $HiveDictionary)
    $FixedPath = foreach ($R in $RegistryPath) {
        foreach ($DictionaryKey in $HiveDictionary.Keys) {
            if ($R.StartsWith($DictionaryKey, [System.StringComparison]::CurrentCultureIgnoreCase)) {
                if ($HiveDictionary[$DictionaryKey] -in 'All', 'All+Default', 'Default', 'AllDomain+Default', 'AllDomain') {
                    foreach ($Computer in $Computers) {
                        $SubKeys = Get-PSRegistry -RegistryPath "HKEY_USERS" -ComputerName $Computer
                        if ($SubKeys.PSSubKeys) {
                            $RegistryKeys = ConvertTo-HKeyUser -SubKeys ($SubKeys.PSSubKeys | Sort-Object) -HiveDictionary $HiveDictionary -DictionaryKey $DictionaryKey -RegistryPath $R
                            foreach ($S in $RegistryKeys) {
                                [PSCustomObject] @{ComputerName = $Computer
                                    RegistryPath                = $S
                                    Error                       = $null
                                    ErrorMessage                = $null
                                }
                            }
                        } else {
                            [PSCustomObject] @{ComputerName = $Computer
                                RegistryPath                = $R
                                Error                       = $true
                                ErrorMessage                = "Couldn't connect to $Computer to list HKEY_USERS"
                            }
                        }
                    }
                } else { $R }
                break
            }
        }
    }
    $FixedPath
}
function Get-PSRegistryDictionaries {
    [cmdletBinding()]
    param()
    if ($Script:Dictionary) { return }
    $Script:Dictionary = @{'HKUAD:' = 'HKEY_ALL_USERS_DEFAULT'
        'HKUA:'                     = 'HKEY_ALL_USERS'
        'HKUD:'                     = 'HKEY_DEFAULT_USER'
        'HKUDUD:'                   = 'HKEY_ALL_DOMAIN_USERS_DEFAULT'
        'HKUDU:'                    = 'HKEY_ALL_DOMAIN_USERS'
        'HKCR:'                     = 'HKEY_CLASSES_ROOT'
        'HKCU:'                     = 'HKEY_CURRENT_USER'
        'HKLM:'                     = 'HKEY_LOCAL_MACHINE'
        'HKU:'                      = 'HKEY_USERS'
        'HKCC:'                     = 'HKEY_CURRENT_CONFIG'
        'HKDD:'                     = 'HKEY_DYN_DATA'
        'HKPD:'                     = 'HKEY_PERFORMANCE_DATA'
    }
    $Script:HiveDictionary = [ordered] @{'HKEY_ALL_USERS_DEFAULT' = 'All+Default'
        'HKUAD'                                                   = 'All+Default'
        'HKEY_ALL_USERS'                                          = 'All'
        'HKUA'                                                    = 'All'
        'HKEY_ALL_DOMAIN_USERS_DEFAULT'                           = 'AllDomain+Default'
        'HKUDUD'                                                  = 'AllDomain+Default'
        'HKEY_ALL_DOMAIN_USERS'                                   = 'AllDomain'
        'HKUDU'                                                   = 'AllDomain'
        'HKEY_DEFAULT_USER'                                       = 'Default'
        'HKUD'                                                    = 'Default'
        'HKEY_CLASSES_ROOT'                                       = 'ClassesRoot'
        'HKCR'                                                    = 'ClassesRoot'
        'ClassesRoot'                                             = 'ClassesRoot'
        'HKCU'                                                    = 'CurrentUser'
        'HKEY_CURRENT_USER'                                       = 'CurrentUser'
        'CurrentUser'                                             = 'CurrentUser'
        'HKLM'                                                    = 'LocalMachine'
        'HKEY_LOCAL_MACHINE'                                      = 'LocalMachine'
        'LocalMachine'                                            = 'LocalMachine'
        'HKU'                                                     = 'Users'
        'HKEY_USERS'                                              = 'Users'
        'Users'                                                   = 'Users'
        'HKCC'                                                    = 'CurrentConfig'
        'HKEY_CURRENT_CONFIG'                                     = 'CurrentConfig'
        'CurrentConfig'                                           = 'CurrentConfig'
        'HKDD'                                                    = 'DynData'
        'HKEY_DYN_DATA'                                           = 'DynData'
        'DynData'                                                 = 'DynData'
        'HKPD'                                                    = 'PerformanceData'
        'HKEY_PERFORMANCE_DATA '                                  = 'PerformanceData'
        'PerformanceData'                                         = 'PerformanceData'
    }
    $Script:ReverseTypesDictionary = [ordered] @{'REG_SZ' = 'string'
        'REG_NONE'                                        = 'none'
        'REG_EXPAND_SZ'                                   = 'expandstring'
        'REG_BINARY'                                      = 'binary'
        'REG_DWORD'                                       = 'dword'
        'REG_MULTI_SZ'                                    = 'multistring'
        'REG_QWORD'                                       = 'qword'
        'string'                                          = 'string'
        'expandstring'                                    = 'expandstring'
        'binary'                                          = 'binary'
        'dword'                                           = 'dword'
        'multistring'                                     = 'multistring'
        'qword'                                           = 'qword'
        'none'                                            = 'none'
    }
}
function Get-PSSubRegistry {
    [cmdletBinding()]
    param([System.Collections.IDictionary] $Registry,
        [string] $ComputerName,
        [switch] $Remote)
    if ($Registry.ComputerName) { if ($Registry.ComputerName -ne $ComputerName) { return } }
    if (-not $Registry.Error) {
        try {
            if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Registry.HiveKey, $ComputerName, 0) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($Registry.HiveKey, 0) }
            $PSConnection = $true
            $PSError = $null
        } catch {
            $PSConnection = $false
            $PSError = $($_.Exception.Message)
        }
    } else {
        $PSConnection = $false
        $PSError = $($Registry.ErrorMessage)
    }
    if ($PSError) {
        [PSCustomObject] @{PSComputerName = $ComputerName
            PSConnection                  = $PSConnection
            PSError                       = $true
            PSErrorMessage                = $PSError
            PSPath                        = $Registry.Registry
            PSKey                         = $Registry.Key
            PSValue                       = $null
            PSType                        = $null
        }
    } else {
        try {
            $SubKey = $BaseHive.OpenSubKey($Registry.SubKeyName, $false)
            if ($null -ne $SubKey) {
                [PSCustomObject] @{PSComputerName = $ComputerName
                    PSConnection                  = $PSConnection
                    PSError                       = $false
                    PSErrorMessage                = $null
                    PSPath                        = $Registry.Registry
                    PSKey                         = $Registry.Key
                    PSValue                       = $SubKey.GetValue($Registry.Key)
                    PSType                        = $SubKey.GetValueKind($Registry.Key)
                }
            } else {
                [PSCustomObject] @{PSComputerName = $ComputerName
                    PSConnection                  = $PSConnection
                    PSError                       = $true
                    PSErrorMessage                = "Registry path $($Registry.Registry) doesn't exists."
                    PSPath                        = $Registry.Registry
                    PSKey                         = $Registry.Key
                    PSValue                       = $null
                    PSType                        = $null
                }
            }
        } catch {
            [PSCustomObject] @{PSComputerName = $ComputerName
                PSConnection                  = $PSConnection
                PSError                       = $true
                PSErrorMessage                = $_.Exception.Message
                PSPath                        = $Registry.Registry
                PSKey                         = $Registry.Key
                PSValue                       = $null
                PSType                        = $null
            }
        }
    }
    if ($null -ne $SubKey) {
        $SubKey.Close()
        $SubKey.Dispose()
    }
    if ($null -ne $BaseHive) {
        $BaseHive.Close()
        $BaseHive.Dispose()
    }
}
function Get-PSSubRegistryComplete {
    [cmdletBinding()]
    param([System.Collections.IDictionary] $Registry,
        [string] $ComputerName,
        [switch] $Remote,
        [switch] $Advanced)
    if ($Registry.ComputerName) { if ($Registry.ComputerName -ne $ComputerName) { return } }
    if (-not $Registry.Error) {
        try {
            if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Registry.HiveKey, $ComputerName, 0) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($Registry.HiveKey, 0) }
            $PSConnection = $true
            $PSError = $null
        } catch {
            $PSConnection = $false
            $PSError = $($_.Exception.Message)
        }
    } else {
        $PSConnection = $false
        $PSError = $($Registry.ErrorMessage)
    }
    if ($PSError) {
        [PSCustomObject] @{PSComputerName = $ComputerName
            PSConnection                  = $PSConnection
            PSError                       = $true
            PSErrorMessage                = $PSError
            PSSubKeys                     = $null
            PSPath                        = $Registry.Registry
            PSKey                         = $Registry.Key
        }
    } else {
        try {
            $SubKey = $BaseHive.OpenSubKey($Registry.SubKeyName, $false)
            if ($null -ne $SubKey) {
                $Object = [ordered] @{PSComputerName = $ComputerName
                    PSConnection                     = $PSConnection
                    PSError                          = $false
                    PSErrorMessage                   = $null
                    PSSubKeys                        = $SubKey.GetSubKeyNames()
                    PSPath                           = $Registry.Registry
                }
                $Keys = $SubKey.GetValueNames()
                foreach ($K in $Keys) {
                    if ($K -eq "") {
                        if ($Advanced) {
                            $Object['DefaultKey'] = [ordered] @{Value = $SubKey.GetValue($K)
                                Type                                  = $SubKey.GetValueKind($K)
                            }
                        } else { $Object['DefaultKey'] = $SubKey.GetValue($K) }
                    } else {
                        if ($Advanced) {
                            $Object[$K] = [ordered] @{Value = $SubKey.GetValue($K)
                                Type                        = $SubKey.GetValueKind($K)
                            }
                        } else { $Object[$K] = $SubKey.GetValue($K) }
                    }
                }
                [PSCustomObject] $Object
            } else {
                [PSCustomObject] @{PSComputerName = $ComputerName
                    PSConnection                  = $PSConnection
                    PSError                       = $true
                    PSErrorMessage                = "Registry path $($Registry.Registry) doesn't exists."
                    PSSubKeys                     = $null
                    PSPath                        = $Registry.Registry
                }
            }
        } catch {
            [PSCustomObject] @{PSComputerName = $ComputerName
                PSConnection                  = $PSConnection
                PSError                       = $true
                PSErrorMessage                = $_.Exception.Message
                PSSubKeys                     = $null
                PSPath                        = $Registry.Registry
            }
        }
    }
    if ($null -ne $SubKey) {
        $SubKey.Close()
        $SubKey.Dispose()
    }
    if ($null -ne $BaseHive) {
        $BaseHive.Close()
        $BaseHive.Dispose()
    }
}
function Get-PSSubRegistryTranslated {
    [cmdletBinding()]
    param([Array] $RegistryPath,
        [System.Collections.IDictionary] $HiveDictionary,
        [string] $Key)
    foreach ($Registry in $RegistryPath) {
        if ($Registry -is [string]) { $Registry = $Registry.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") } else { $Registry.RegistryPath = $Registry.RegistryPath.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") }
        foreach ($Hive in $HiveDictionary.Keys) {
            if ($Registry -is [string] -and $Registry.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) {
                if ($Hive.Length -eq $Registry.Length) {
                    [ordered] @{Registry = $Registry
                        HiveKey          = $HiveDictionary[$Hive]
                        SubKeyName       = $null
                        Key              = if ($Key -eq "") { $null } else { $Key }
                        Error            = $null
                        ErrorMessage     = $null
                    }
                } else {
                    [ordered] @{Registry = $Registry
                        HiveKey          = $HiveDictionary[$Hive]
                        SubKeyName       = $Registry.substring($Hive.Length + 1)
                        Key              = if ($Key -eq "") { $null } else { $Key }
                        Error            = $null
                        ErrorMessage     = $null
                    }
                }
                break
            } elseif ($Registry -isnot [string] -and $Registry.RegistryPath.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) {
                if ($Hive.Length -eq $Registry.RegistryPath.Length) {
                    [ordered] @{ComputerName = $Registry.ComputerName
                        Registry             = $Registry.RegistryPath
                        HiveKey              = $HiveDictionary[$Hive]
                        SubKeyName           = $null
                        Key                  = if ($Key -eq "") { $null } else { $Key }
                        Error                = $Registry.Error
                        ErrorMessage         = $Registry.ErrorMessage
                    }
                } else {
                    [ordered] @{ComputerName = $Registry.ComputerName
                        Registry             = $Registry.RegistryPath
                        HiveKey              = $HiveDictionary[$Hive]
                        SubKeyName           = $Registry.RegistryPath.substring($Hive.Length + 1)
                        Key                  = if ($Key -eq "") { $null } else { $Key }
                        Error                = $Registry.Error
                        ErrorMessage         = $Registry.ErrorMessage
                    }
                }
                break
            }
        }
    }
}
function Resolve-PrivateRegistry {
    [CmdletBinding()]
    param([alias('Path')][string[]] $RegistryPath)
    foreach ($R in $RegistryPath) {
        $R = $R.Replace("\\", "\").Replace("\\", "\")
        If ($R.StartsWith("Users\.DEFAULT_USER") -or $R.StartsWith('HKEY_USERS\.DEFAULT_USER')) {
            $R = $R.Replace("Users\.DEFAULT_USER", "HKUD")
            $R.Replace('HKEY_USERS\.DEFAULT_USER', "HKUD")
        } elseif ($R -like '*:*') {
            foreach ($DictionaryKey in $Script:Dictionary.Keys) {
                if ($R.StartsWith($DictionaryKey, [System.StringComparison]::CurrentCultureIgnoreCase)) {
                    $R -replace $DictionaryKey, $Script:Dictionary[$DictionaryKey]
                    break
                }
            }
        } else { $R }
    }
}
function Set-PrivateRegistry {
    [cmdletBinding(SupportsShouldProcess)]
    param([System.Collections.IDictionary] $RegistryValue,
        [string] $Computer,
        [switch] $Remote,
        [switch] $Suppress)
    if ($RegistryValue.ComputerName) { if ($RegistryValue.ComputerName -ne $Computer) { return } }
    try {
        if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RegistryValue.HiveKey, $Computer, 0) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($RegistryValue.HiveKey, 0) }
        $PSConnection = $true
        $PSError = $null
    } catch {
        $PSConnection = $false
        $PSError = $($_.Exception.Message)
        if ($PSBoundParameters.ErrorAction -eq 'Stop') {
            if ($null -ne $BaseHive) {
                $BaseHive.Close()
                $BaseHive.Dispose()
            }
            throw
        } else { Write-Warning "Set-PSRegistry - Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind) on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" }
    }
    if ($PSCmdlet.ShouldProcess($Computer, "Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind)")) {
        if ($PSError) {
            if (-not $Suppress) {
                [PSCustomObject] @{PSComputerName = $Computer
                    PSConnection                  = $PSConnection
                    PSError                       = $true
                    PSErrorMessage                = $PSError
                    Path                          = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)"
                    Key                           = $RegistryValue.Key
                    Value                         = $RegistryValue.Value
                    Type                          = $RegistryValue.ValueKind
                }
            }
        } else {
            try {
                $SubKey = $BaseHive.OpenSubKey($RegistryValue.SubKeyName, $true)
                if (-not $SubKey) {
                    $SubKeysSplit = $RegistryValue.SubKeyName.Split('\')
                    $SubKey = $BaseHive.OpenSubKey($SubKeysSplit[0], $true)
                    if (-not $SubKey) { $SubKey = $BaseHive.CreateSubKey($SubKeysSplit[0]) }
                    $SubKey = $BaseHive.OpenSubKey($SubKeysSplit[0], $true)
                    foreach ($S in $SubKeysSplit | Select-Object -Skip 1) { $SubKey = $SubKey.CreateSubKey($S) }
                }
                if ($RegistryValue.ValueKind -eq [Microsoft.Win32.RegistryValueKind]::MultiString) { $SubKey.SetValue($RegistryValue.Key, [string[]] $RegistryValue.Value, $RegistryValue.ValueKind) } elseif ($RegistryValue.ValueKind -in [Microsoft.Win32.RegistryValueKind]::None, [Microsoft.Win32.RegistryValueKind]::Binary) { $SubKey.SetValue($RegistryValue.Key, [byte[]] $RegistryValue.Value, $RegistryValue.ValueKind) } else { $SubKey.SetValue($RegistryValue.Key, $RegistryValue.Value, $RegistryValue.ValueKind) }
                if (-not $Suppress) {
                    [PSCustomObject] @{PSComputerName = $Computer
                        PSConnection                  = $PSConnection
                        PSError                       = $false
                        PSErrorMessage                = $null
                        Path                          = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)"
                        Key                           = $RegistryValue.Key
                        Value                         = $RegistryValue.Value
                        Type                          = $RegistryValue.ValueKind
                    }
                }
            } catch {
                if ($PSBoundParameters.ErrorAction -eq 'Stop') {
                    if ($null -ne $SubKey) {
                        $SubKey.Close()
                        $SubKey.Dispose()
                    }
                    if ($null -ne $BaseHive) {
                        $BaseHive.Close()
                        $BaseHive.Dispose()
                    }
                    throw
                } else { Write-Warning "Set-PSRegistry - Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind) on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" }
                if (-not $Suppress) {
                    [PSCustomObject] @{PSComputerName = $Computer
                        PSConnection                  = $PSConnection
                        PSError                       = $true
                        PSErrorMessage                = $_.Exception.Message
                        Path                          = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)"
                        Key                           = $RegistryValue.Key
                        Value                         = $RegistryValue.Value
                        Type                          = $RegistryValue.ValueKind
                    }
                }
            }
        }
    } else {
        if (-not $Suppress) {
            [PSCustomObject] @{PSComputerName = $Computer
                PSConnection                  = $PSConnection
                PSError                       = $true
                PSErrorMessage                = if ($PSError) { $PSError } else { "WhatIf used - skipping registry setting" }
                Path                          = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)"
                Key                           = $RegistryValue.Key
                Value                         = $RegistryValue.Value
                Type                          = $RegistryValue.ValueKind
            }
        }
    }
    if ($null -ne $SubKey) {
        $SubKey.Close()
        $SubKey.Dispose()
    }
    if ($null -ne $BaseHive) {
        $BaseHive.Close()
        $BaseHive.Dispose()
    }
}
function ConvertFrom-DistinguishedName {
    <#
    .SYNOPSIS
    Converts a Distinguished Name to CN, OU, Multiple OUs or DC
 
    .DESCRIPTION
    Converts a Distinguished Name to CN, OU, Multiple OUs or DC
 
    .PARAMETER DistinguishedName
    Distinguished Name to convert
 
    .PARAMETER ToOrganizationalUnit
    Converts DistinguishedName to Organizational Unit
 
    .PARAMETER ToDC
    Converts DistinguishedName to DC
 
    .PARAMETER ToDomainCN
    Converts DistinguishedName to Domain CN
 
    .EXAMPLE
    $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz'
    ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName -ToOrganizationalUnit
 
    Output:
    OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz
 
    .EXAMPLE
    $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz'
    ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName
 
    Output:
    Przemyslaw Klys
 
    .EXAMPLE
    ConvertFrom-DistinguishedName -DistinguishedName 'OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' -ToMultipleOrganizationalUnit -IncludeParent
 
    Output:
    OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz
    OU=Production,DC=ad,DC=evotec,DC=xyz
 
    .EXAMPLE
    ConvertFrom-DistinguishedName -DistinguishedName 'OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' -ToMultipleOrganizationalUnit
 
    Output:
    OU=Production,DC=ad,DC=evotec,DC=xyz
 
    .EXAMPLE
    $Con = @(
        'CN=Windows Authorization Access Group,CN=Builtin,DC=ad,DC=evotec,DC=xyz'
        'CN=Mmm,DC=elo,CN=nee,DC=RootDNSServers,CN=MicrosoftDNS,CN=System,DC=ad,DC=evotec,DC=xyz'
        'CN=e6d5fd00-385d-4e65-b02d-9da3493ed850,CN=Operations,CN=DomainUpdates,CN=System,DC=ad,DC=evotec,DC=xyz'
        'OU=Domain Controllers,DC=ad,DC=evotec,DC=pl'
        'OU=Microsoft Exchange Security Groups,DC=ad,DC=evotec,DC=xyz'
    )
 
    ConvertFrom-DistinguishedName -DistinguishedName $Con -ToLastName
 
    Output:
    Windows Authorization Access Group
    Mmm
    e6d5fd00-385d-4e65-b02d-9da3493ed850
    Domain Controllers
    Microsoft Exchange Security Groups
 
    .NOTES
    General notes
    #>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param([Parameter(ParameterSetName = 'ToOrganizationalUnit')]
        [Parameter(ParameterSetName = 'ToMultipleOrganizationalUnit')]
        [Parameter(ParameterSetName = 'ToDC')]
        [Parameter(ParameterSetName = 'ToDomainCN')]
        [Parameter(ParameterSetName = 'Default')]
        [Parameter(ParameterSetName = 'ToLastName')]
        [alias('Identity', 'DN')][Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)][string[]] $DistinguishedName,
        [Parameter(ParameterSetName = 'ToOrganizationalUnit')][switch] $ToOrganizationalUnit,
        [Parameter(ParameterSetName = 'ToMultipleOrganizationalUnit')][alias('ToMultipleOU')][switch] $ToMultipleOrganizationalUnit,
        [Parameter(ParameterSetName = 'ToMultipleOrganizationalUnit')][switch] $IncludeParent,
        [Parameter(ParameterSetName = 'ToDC')][switch] $ToDC,
        [Parameter(ParameterSetName = 'ToDomainCN')][switch] $ToDomainCN,
        [Parameter(ParameterSetName = 'ToLastName')][switch] $ToLastName)
    Process {
        foreach ($Distinguished in $DistinguishedName) {
            if ($ToDomainCN) {
                $DN = $Distinguished -replace '.*?((DC=[^=]+,)+DC=[^=]+)$', '$1'
                $CN = $DN -replace ',DC=', '.' -replace "DC="
                if ($CN) { $CN }
            } elseif ($ToOrganizationalUnit) {
                $Value = [Regex]::Match($Distinguished, '(?=OU=)(.*\n?)(?<=.)').Value
                if ($Value) { $Value }
            } elseif ($ToMultipleOrganizationalUnit) {
                if ($IncludeParent) { $Distinguished }
                while ($true) {
                    $Distinguished = $Distinguished -replace '^.+?,(?=..=)'
                    if ($Distinguished -match '^DC=') { break }
                    $Distinguished
                }
            } elseif ($ToDC) {
                $Value = $Distinguished -replace '.*?((DC=[^=]+,)+DC=[^=]+)$', '$1'
                if ($Value) { $Value }
            } elseif ($ToLastName) {
                $NewDN = $Distinguished -split ",DC="
                if ($NewDN[0].Contains(",OU=")) { [Array] $ChangedDN = $NewDN[0] -split ",OU=" } elseif ($NewDN[0].Contains(",CN=")) { [Array] $ChangedDN = $NewDN[0] -split ",CN=" } else { [Array] $ChangedDN = $NewDN[0] }
                if ($ChangedDN[0].StartsWith('CN=')) { $ChangedDN[0] -replace 'CN=', '' } else { $ChangedDN[0] -replace 'OU=', '' }
            } else {
                $Regex = '^CN=(?<cn>.+?)(?<!\\),(?<ou>(?:(?:OU|CN).+?(?<!\\),)+(?<dc>DC.+?))$'
                $Found = $Distinguished -match $Regex
                if ($Found) { $Matches.cn }
            }
        }
    }
}
function ConvertTo-HkeyUser {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $HiveDictionary,
        [Array] $SubKeys,
        [string] $DictionaryKey,
        [string] $RegistryPath)
    foreach ($Sub in $Subkeys) {
        if ($HiveDictionary[$DictionaryKey] -eq 'All') { if ($Sub -notlike "*_Classes*" -and $Sub -ne '.DEFAULT') { $RegistryPath.Replace($DictionaryKey, "Users\$Sub") } } elseif ($HiveDictionary[$DictionaryKey] -eq 'All+Default') {
            if ($Sub -notlike "*_Classes*") {
                if (-not $Script:DefaultRegistryMounted) { $Script:DefaultRegistryMounted = Mount-DefaultRegistryPath }
                if ($Sub -eq '.DEFAULT') { $RegistryPath.Replace($DictionaryKey, "Users\.DEFAULT_USER") } else { $RegistryPath.Replace($DictionaryKey, "Users\$Sub") }
            }
        } elseif ($HiveDictionary[$DictionaryKey] -eq 'Default') {
            if ($Sub -eq '.DEFAULT') {
                if (-not $Script:DefaultRegistryMounted) { $Script:DefaultRegistryMounted = Mount-DefaultRegistryPath }
                $RegistryPath.Replace($DictionaryKey, "Users\.DEFAULT_USER")
            }
        } elseif ($HiveDictionary[$DictionaryKey] -eq 'AllDomain+Default') {
            if (($Sub.StartsWith("S-1-5-21") -and $Sub -notlike "*_Classes*") -or $Sub -eq '.DEFAULT') {
                if (-not $Script:DefaultRegistryMounted) { $Script:DefaultRegistryMounted = Mount-DefaultRegistryPath }
                if ($Sub -eq '.DEFAULT') { $RegistryPath.Replace($DictionaryKey, "Users\.DEFAULT_USER") } else { $RegistryPath.Replace($DictionaryKey, "Users\$Sub") }
            }
        } elseif ($HiveDictionary[$DictionaryKey] -eq 'AllDomain') { if ($Sub.StartsWith("S-1-5-21") -and $Sub -notlike "*_Classes*") { $RegistryPath.Replace($DictionaryKey, "Users\$Sub") } }
    }
}
function Dismount-PSRegistryPath {
    [alias('Dismount-RegistryPath')]
    [cmdletbinding()]
    param([Parameter(Mandatory)][string] $MountPoint,
        [switch] $Suppress)
    [gc]::Collect()
    $pinfo = [System.Diagnostics.ProcessStartInfo]::new()
    $pinfo.FileName = "reg.exe"
    $pinfo.RedirectStandardError = $true
    $pinfo.RedirectStandardOutput = $true
    $pinfo.UseShellExecute = $false
    $pinfo.Arguments = " unload $MountPoint"
    $p = [System.Diagnostics.Process]::new()
    $p.StartInfo = $pinfo
    $p.Start() | Out-Null
    $p.WaitForExit()
    $Output = $p.StandardOutput.ReadToEnd()
    $Errors = $p.StandardError.ReadToEnd()
    if ($Errors) { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $Errors } else { Write-Warning -Message "Dismount-PSRegistryPath - Couldn't unmount $MountPoint. Error: $Errors" } } else { if ($Output -like "*operation completed*") { if (-not $Suppress) { return $true } } }
    if (-not $Suppress) { return $false }
}
function Mount-DefaultRegistryPath {
    [CmdletBinding()]
    param([string] $MountPoint = "HKEY_USERS\.DEFAULT_USER")
    $DefaultRegistryPath = Get-PSRegistry -RegistryPath 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' -Key 'Default'
    if ($PSError -ne $true) {
        $PathToNTUser = [io.path]::Combine($DefaultRegistryPath.PSValue, 'NTUSER.DAT')
        Mount-PSRegistryPath -MountPoint $MountPoint -FilePath $PathToNTUser
    } else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $PSErrorMessage } else { Write-Warning -Message "Import-DefaultRegistryPath - Couldn't execute. Error: $PSErrorMessage" } }
}
function Mount-PSRegistryPath {
    [alias('Mount-RegistryPath')]
    [cmdletbinding()]
    param([Parameter(Mandatory)][string] $MountPoint,
        [Parameter(Mandatory)][string] $FilePath)
    $pinfo = [System.Diagnostics.ProcessStartInfo]::new()
    $pinfo.FileName = "reg.exe"
    $pinfo.RedirectStandardError = $true
    $pinfo.RedirectStandardOutput = $true
    $pinfo.UseShellExecute = $false
    $pinfo.Arguments = " load $MountPoint $PathToNTUser"
    $p = [System.Diagnostics.Process]::new()
    $p.StartInfo = $pinfo
    $p.Start() | Out-Null
    $p.WaitForExit()
    $Output = $p.StandardOutput.ReadToEnd()
    $Errors = $p.StandardError.ReadToEnd()
    if ($Errors) { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $Errors } else { Write-Warning -Message "Mount-PSRegistryPath - Couldn't mount $MountPoint. Error: $Errors" } } else { if ($Output -like "*operation completed*") { if (-not $Suppress) { return $true } } }
    if (-not $Suppress) { return $false }
}
function Set-SystemAuditPolicyAuditpol {
    <#
    .SYNOPSIS
    This command is used to set the audit policy for the system using auditpol.exe
 
    .DESCRIPTION
    This command is used to set the audit policy for the system using auditpol.exe
 
    .PARAMETER Policies
    This parameter is used to specify the audit policy to be set.
 
    .PARAMETER Value
    This parameter is used to specify the value of the audit policy to be set. Options are: NotConfigured, Success, Failure, and SuccessAndFailure.
 
    .PARAMETER Suppress
    Suppresses the output of the command
 
    .EXAMPLE
    Set-SystemAuditPolicyLocalSecurity -AccountManagement 'Computer Account Management' -Value Failure -Verbose -WhatIf
 
    .EXAMPLE
    Set-SystemAuditPolicyLocalSecurity -AccountManagement 'Application Group Management' -Value Success -Verbose -WhatIf
 
    .NOTES
    General notes
    #>

    [cmdletBinding(SupportsShouldProcess)]
    param([parameter(Mandatory)][ValidateSet("Security System Extension",
            "System Integrity",
            "IPsec Driver",
            "Other System Events",
            "Security State Change",
            "Logon",
            "Logoff",
            "Account Lockout",
            "IPsec Main Mode",
            "IPsec Quick Mode",
            "IPsec Extended Mode",
            "Special Logon",
            "Other Logon/Logoff Events",
            "Network Policy Server",
            "User / Device Claims",
            "Group Membership",
            "File System",
            "Registry",
            "Kernel Object",
            "SAM",
            "Certification Services",
            "Application Generated",
            "Handle Manipulation",
            "File Share",
            "Filtering Platform Packet Drop",
            "Filtering Platform Connection",
            "Other Object Access Events",
            "Detailed File Share",
            "Removable Storage",
            "Central Policy Staging",
            "Non Sensitive Privilege Use",
            "Other Privilege Use Events",
            "Sensitive Privilege Use",
            "Process Creation",
            "Process Termination",
            "DPAPI Activity",
            "RPC Events",
            "Plug and Play Events",
            "Token Right Adjusted Events",
            "Audit Policy Change",
            "Authentication Policy Change",
            "Authorization Policy Change",
            "MPSSVC Rule-Level Policy Change",
            "Filtering Platform Policy Change",
            "Other Policy Change Events",
            "Computer Account Management",
            "Security Group Management",
            "Distribution Group Management",
            "Application Group Management",
            "Other Account Management Events",
            "User Account Management",
            "Directory Service Access",
            "Directory Service Changes",
            "Directory Service Replication",
            "Detailed Directory Service Replication",
            "Kerberos Service Ticket Operations",
            "Kerberos Service Ticket Operations",
            "Other Account Logon Events",
            "Kerberos Authentication Service",
            "Credential Validation")][string[]] $Policies,
        [parameter(Mandatory)][validateSet('NoAuditing', 'NotConfigured', 'Success', 'Failure', 'SuccessAndFailure')][string] $Value)
    if ($Value -in 'NotConfigured', 'NoAuditing') {
        $Success = 'disable'
        $Failure = 'disable'
    } elseif ($Value -eq 'Success') {
        $Success = 'enable'
        $Failure = 'disable'
    } elseif ($Value -eq 'Failure') {
        $Success = 'disable'
        $Failure = 'enable'
    } elseif ($Value -eq 'SuccessAndFailure') {
        $Success = 'enable'
        $Failure = 'enable'
    }
    foreach ($Policy in $Policies) {
        if ($PSCmdlet.ShouldProcess("SubCategory $Policy", "Setting $Value (Success: $Success / Failure: $Failure)")) {
            Write-Verbose -Message "Set-SystemAuditPolicyAuditpol - Executing: auditpol.exe /set /subcategory:$Policy /success:$Success /failure:$Failure"
            $pinfo = [System.Diagnostics.ProcessStartInfo]::new()
            $pinfo.FileName = "auditpol.exe"
            $pinfo.RedirectStandardError = $true
            $pinfo.RedirectStandardOutput = $true
            $pinfo.UseShellExecute = $false
            $pinfo.Arguments = " /set /subcategory:`"$Policy`" /success:`"$Success`" /failure:`"$Failure`""
            $p = [System.Diagnostics.Process]::new()
            $p.StartInfo = $pinfo
            $p.Start() | Out-Null
            $p.WaitForExit()
            $Output = $p.StandardOutput.ReadToEnd()
            $Errors = $p.StandardError.ReadToEnd()
            if ($Output -like "*The command was successfully*" -and -not $Errors) {
                if (-not $Suppress) {
                    [PSCustomObject] @{'Policy' = $Policy
                        'Value'                 = $Value
                        'Result'                = 'Success'
                        'Error'                 = ''
                    }
                }
            } else {
                if (-not $Suppress) {
                    $SplitErrors = ($Errors -split "\n").Trim() -join " "
                    [PSCustomObject] @{'Policy' = $Policy
                        'Value'                 = $Value
                        'Result'                = 'Failed'
                        'Error'                 = $SplitErrors
                    }
                }
            }
        } else {
            if (-not $Suppress) {
                [PSCustomObject] @{'Policy' = $Policy
                    'Value'                 = $Value
                    'Result'                = 'WhatIf'
                    'Error'                 = 'WhatIf in use.'
                }
            }
        }
    }
}
function Set-SystemAuditPolicyLocalSecurity {
    <#
    .SYNOPSIS
    This function will set the audit policy for the local machine using Local Security Policy (audit.csv)
 
    .DESCRIPTION
    This function will set the audit policy for the local machine using Local Security Policy (audit.csv)
    It's IMPORTANT to know that Local Security Policy doesn't apply until next GPO refresh
 
    .PARAMETER Policies
    This parameter is used to specify the audit policy to be set.
 
    .PARAMETER Value
    This parameter is used to specify the value of the audit policy to be set. Options are: NoAuditing, NotConfigured, Success, Failure, and SuccessAndFailure.
 
    .PARAMETER Suppress
    Suppresses the output of the command
 
    .EXAMPLE
    Set-SystemAuditPolicyLocalSecurity -AccountManagement 'Computer Account Management' -Value Failure -Verbose -WhatIf
 
    .EXAMPLE
    Set-SystemAuditPolicyLocalSecurity -AccountManagement 'Application Group Management' -Value Success -Verbose -WhatIf
 
    .NOTES
    General notes
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param([parameter(Mandatory)][ValidateSet("Security System Extension",
            "System Integrity",
            "IPsec Driver",
            "Other System Events",
            "Security State Change",
            "Logon",
            "Logoff",
            "Account Lockout",
            "IPsec Main Mode",
            "IPsec Quick Mode",
            "IPsec Extended Mode",
            "Special Logon",
            "Other Logon/Logoff Events",
            "Network Policy Server",
            "User / Device Claims",
            "Group Membership",
            "File System",
            "Registry",
            "Kernel Object",
            "SAM",
            "Certification Services",
            "Application Generated",
            "Handle Manipulation",
            "File Share",
            "Filtering Platform Packet Drop",
            "Filtering Platform Connection",
            "Other Object Access Events",
            "Detailed File Share",
            "Removable Storage",
            "Central Policy Staging",
            "Non Sensitive Privilege Use",
            "Other Privilege Use Events",
            "Sensitive Privilege Use",
            "Process Creation",
            "Process Termination",
            "DPAPI Activity",
            "RPC Events",
            "Plug and Play Events",
            "Token Right Adjusted Events",
            "Audit Policy Change",
            "Authentication Policy Change",
            "Authorization Policy Change",
            "MPSSVC Rule-Level Policy Change",
            "Filtering Platform Policy Change",
            "Other Policy Change Events",
            "Computer Account Management",
            "Security Group Management",
            "Distribution Group Management",
            "Application Group Management",
            "Other Account Management Events",
            "User Account Management",
            "Directory Service Access",
            "Directory Service Changes",
            "Directory Service Replication",
            "Detailed Directory Service Replication",
            "Kerberos Service Ticket Operations",
            "Other Account Logon Events",
            "Kerberos Authentication Service",
            "Credential Validation")][alias('Policies')][string] $Policy,
        [parameter(Mandatory)][validateSet('NotConfigured', 'Success', 'Failure', 'SuccessAndFailure', 'NoAuditing')][string] $Value)
    $AuditPoliciesGuids = [ordered] @{'IPsec Driver' = '{0CCE9213-69AE-11D9-BED3-505054503030}'
        'System Integrity'                           = '{0CCE9212-69AE-11D9-BED3-505054503030}'
        'Security System Extension'                  = '{0CCE9211-69AE-11D9-BED3-505054503030}'
        'Security State Change'                      = '{0CCE9210-69AE-11D9-BED3-505054503030}'
        'Other System Events'                        = '{0CCE9214-69AE-11D9-BED3-505054503030}'
        'Group Membership'                           = '{0CCE9249-69AE-11D9-BED3-505054503030}'
        'User / Device Claims'                       = '{0CCE9247-69AE-11D9-BED3-505054503030}'
        'Network Policy Server'                      = '{0CCE9243-69AE-11D9-BED3-505054503030}'
        'Other Logon/Logoff Events'                  = '{0CCE921C-69AE-11D9-BED3-505054503030}'
        'Special Logon'                              = '{0CCE921B-69AE-11D9-BED3-505054503030}'
        'IPsec Extended Mode'                        = '{0CCE921A-69AE-11D9-BED3-505054503030}'
        'IPsec Quick Mode'                           = '{0CCE9219-69AE-11D9-BED3-505054503030}'
        'IPsec Main Mode'                            = '{0CCE9218-69AE-11D9-BED3-505054503030}'
        'Account Lockout'                            = '{0CCE9217-69AE-11D9-BED3-505054503030}'
        'Logoff'                                     = '{0CCE9216-69AE-11D9-BED3-505054503030}'
        'Logon'                                      = '{0CCE9215-69AE-11D9-BED3-505054503030}'
        'Handle Manipulation'                        = '{0CCE9223-69AE-11D9-BED3-505054503030}'
        'Central Policy Staging'                     = '{0CCE9246-69AE-11D9-BED3-505054503030}'
        'Removable Storage'                          = '{0CCE9245-69AE-11D9-BED3-505054503030}'
        'Detailed File Share'                        = '{0CCE9244-69AE-11D9-BED3-505054503030}'
        'Other Object Access Events'                 = '{0CCE9227-69AE-11D9-BED3-505054503030}'
        'Filtering Platform Connection'              = '{0CCE9226-69AE-11D9-BED3-505054503030}'
        'Filtering Platform Packet Drop'             = '{0CCE9225-69AE-11D9-BED3-505054503030}'
        'File Share'                                 = '{0CCE9224-69AE-11D9-BED3-505054503030}'
        'Application Generated'                      = '{0CCE9222-69AE-11D9-BED3-505054503030}'
        'Certification Services'                     = '{0CCE9221-69AE-11D9-BED3-505054503030}'
        'SAM'                                        = '{0CCE9220-69AE-11D9-BED3-505054503030}'
        'Kernel Object'                              = '{0CCE921F-69AE-11D9-BED3-505054503030}'
        'Registry'                                   = '{0CCE921E-69AE-11D9-BED3-505054503030}'
        'File System'                                = '{0CCE921D-69AE-11D9-BED3-505054503030}'
        'Other Privilege Use Events'                 = '{0CCE922A-69AE-11D9-BED3-505054503030}'
        'Non Sensitive Privilege Use'                = '{0CCE9229-69AE-11D9-BED3-505054503030}'
        'Sensitive Privilege Use'                    = '{0CCE9228-69AE-11D9-BED3-505054503030}'
        'RPC Events'                                 = '{0CCE922E-69AE-11D9-BED3-505054503030}'
        'Token Right Adjusted Events'                = '{0CCE924A-69AE-11D9-BED3-505054503030}'
        'Process Creation'                           = '{0CCE922B-69AE-11D9-BED3-505054503030}'
        'Process Termination'                        = '{0CCE922C-69AE-11D9-BED3-505054503030}'
        'Plug and Play Events'                       = '{0CCE9248-69AE-11D9-BED3-505054503030}'
        'DPAPI Activity'                             = '{0CCE922D-69AE-11D9-BED3-505054503030}'
        'Other Policy Change Events'                 = '{0CCE9234-69AE-11D9-BED3-505054503030}'
        'Authentication Policy Change'               = '{0CCE9230-69AE-11D9-BED3-505054503030}'
        'Audit Policy Change'                        = '{0CCE922F-69AE-11D9-BED3-505054503030}'
        'Filtering Platform Policy Change'           = '{0CCE9233-69AE-11D9-BED3-505054503030}'
        'Authorization Policy Change'                = '{0CCE9231-69AE-11D9-BED3-505054503030}'
        'MPSSVC Rule-Level Policy Change'            = '{0CCE9232-69AE-11D9-BED3-505054503030}'
        'Other Account Management Events'            = '{0CCE923A-69AE-11D9-BED3-505054503030}'
        'Application Group Management'               = '{0CCE9239-69AE-11D9-BED3-505054503030}'
        'Distribution Group Management'              = '{0CCE9238-69AE-11D9-BED3-505054503030}'
        'Security Group Management'                  = '{0CCE9237-69AE-11D9-BED3-505054503030}'
        'Computer Account Management'                = '{0CCE9236-69AE-11D9-BED3-505054503030}'
        'User Account Management'                    = '{0CCE9235-69AE-11D9-BED3-505054503030}'
        'Directory Service Replication'              = '{0CCE923D-69AE-11D9-BED3-505054503030}'
        'Directory Service Access'                   = '{0CCE923B-69AE-11D9-BED3-505054503030}'
        'Detailed Directory Service Replication'     = '{0CCE923E-69AE-11D9-BED3-505054503030}'
        'Directory Service Changes'                  = '{0CCE923C-69AE-11D9-BED3-505054503030}'
        'Other Account Logon Events'                 = '{0CCE9241-69AE-11D9-BED3-505054503030}'
        'Kerberos Service Ticket Operations'         = '{0CCE9240-69AE-11D9-BED3-505054503030}'
        'Credential Validation'                      = '{0CCE923F-69AE-11D9-BED3-505054503030}'
        'Kerberos Authentication Service'            = '{0CCE9242-69AE-11D9-BED3-505054503030}'
    }
    $ListTranslated = @{'NoAuditing' = 'No Auditing'
        'NotConfigured'              = ''
        'Success'                    = 'Success'
        'Failure'                    = 'Failure'
        'SuccessAndFailure'          = 'Success and Failure'
    }
    $ValuesTranslated = @{'NoAuditing' = 0
        'NotConfigured'                = -1
        'Success'                      = 1
        'Failure'                      = 2
        'SuccessAndFailure'            = 3
    }
    $LocalSecurity = [ordered] @{}
    $LocalSecurityPolicyFolder = [io.path]::Combine($Env:SystemRoot, "System32", "GroupPolicy", "Machine", "Microsoft", "Windows NT", "Audit")
    $LocalSecurityPolicy = [io.path]::Combine($Env:SystemRoot, "System32", "GroupPolicy", "Machine", "Microsoft", "Windows NT", "Audit", 'Audit.csv')
    if (Test-Path -LiteralPath $LocalSecurityPolicy) {
        $CurrentCSV = Get-Content -LiteralPath $LocalSecurityPolicy -Raw | ConvertFrom-Csv
        foreach ($C in $CurrentCSV) { $LocalSecurity[$C.Subcategory] = $C }
    }
    if ($Value -eq 'NotConfigured') { $LocalSecurity.Remove($Policy) } else {
        $InputValue = [PScustomObject] @{'Machine Name' = ''
            'Policy Target'                             = 'System'
            'Subcategory'                               = $Policy
            'Subcategory GUID'                          = $AuditPoliciesGuids[$Policy]
            'Inclusion Setting'                         = $ListTranslated[$Value]
            'Exclusion Setting'                         = ''
            'Setting Value'                             = $ValuesTranslated[$Value]
        }
        $LocalSecurity[$Policy] = $InputValue
    }
    if ($PSCmdlet.ShouldProcess("SubCategory $Policy", "Setting $Value")) {
        try { if (-not (Test-Path -LiteralPath $LocalSecurityPolicyFolder -ErrorAction SilentlyContinue)) { $null = New-Item -ItemType Directory -Path $LocalSecurityPolicyFolder -Force } } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Set-SystemAuditPolicyLocalSecurityPolicy - Couldn't create folder $LocalSecurityPolicyFolder. Error: $($_.Exception.Message)" } }
        try {
            $LocalSecurity.Values | ConvertTo-Csv -NoTypeInformation -Delimiter "," | ForEach-Object { $_ -replace '"', '' } | Set-Content -LiteralPath $LocalSecurityPolicy -ErrorAction Stop
            $Message = ''
            $Result = 'Success'
        } catch {
            $Result = 'Failed'
            $Message = $($_.Exception.Message)
            if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Set-SystemAuditPolicyLocalSecurityPolicy - Audit policies couldn't be saved to $LocalSecurityPolicy. Error: $($_.Exception.Message)" }
        }
    } else {
        $Message = 'WhatIf in use.'
        $Result = 'WhatIf'
    }
    if (-not $Suppress) {
        [PSCustomObject] @{'Policy' = $Policy
            'Value'                 = $Value
            'Result'                = $Result
            'Error'                 = $Message
        }
    }
}
function Backup-SystemAuditPolicy {
    <#
    .SYNOPSIS
    Backups the current system audit policy to a file or json or as object
 
    .DESCRIPTION
    Backups the current system audit policy to a file or json or as object
 
    .PARAMETER ComputerName
    ComputerName for remote system to read audit policy from. Requires permissions on the destination.
 
    .PARAMETER FilePath
    FilePath to write the audit policy to. If not given will be returned as JSON
 
    .PARAMETER AsJson
    If true will return the audit policy as JSON
 
    .PARAMETER AsObject
    If true will return the audit policy as an object
 
    .PARAMETER Policy
    Returns the specified policy, and only that policy.
 
    .EXAMPLE
    Backup-SystemAuditPolicy | Out-File -FilePath $PSScriptRoot\Backups\AuditPolicy.json
 
    .NOTES
    General notes
    #>

    [cmdletBinding(DefaultParameterSetName = 'File')]
    param([string] $ComputerName,
        [parameter(ParameterSetName = 'File')] [string] $FilePath,
        [parameter(ParameterSetName = 'AsObject')][switch] $AsObject,
        [parameter(ParameterSetName = 'AsJson')][switch] $AsJson,
        [ValidateSet("Security System Extension",
            "System Integrity",
            "IPsec Driver",
            "Other System Events",
            "Security State Change",
            "Logon",
            "Logoff",
            "Account Lockout",
            "IPsec Main Mode",
            "IPsec Quick Mode",
            "IPsec Extended Mode",
            "Special Logon",
            "Other Logon/Logoff Events",
            "Network Policy Server",
            "User / Device Claims",
            "Group Membership",
            "File System",
            "Registry",
            "Kernel Object",
            "SAM",
            "Certification Services",
            "Application Generated",
            "Handle Manipulation",
            "File Share",
            "Filtering Platform Packet Drop",
            "Filtering Platform Connection",
            "Other Object Access Events",
            "Detailed File Share",
            "Removable Storage",
            "Central Policy Staging",
            "Non Sensitive Privilege Use",
            "Other Privilege Use Events",
            "Sensitive Privilege Use",
            "Process Creation",
            "Process Termination",
            "DPAPI Activity",
            "RPC Events",
            "Plug and Play Events",
            "Token Right Adjusted Events",
            "Audit Policy Change",
            "Authentication Policy Change",
            "Authorization Policy Change",
            "MPSSVC Rule-Level Policy Change",
            "Filtering Platform Policy Change",
            "Other Policy Change Events",
            "Computer Account Management",
            "Security Group Management",
            "Distribution Group Management",
            "Application Group Management",
            "Other Account Management Events",
            "User Account Management",
            "Directory Service Access",
            "Directory Service Changes",
            "Directory Service Replication",
            "Detailed Directory Service Replication",
            "Kerberos Service Ticket Operations",
            "Other Account Logon Events",
            "Kerberos Authentication Service",
            "Credential Validation")][alias('Policies')][string] $Policy)
    if ($Policy) { $AuditPolicy = Get-SystemAuditPolicy -ComputerName $ComputerName -Policy $Policy } else { $AuditPolicy = Get-SystemAuditPolicy -ComputerName $ComputerName }
    if ($FilePath) { $AuditPolicy | ConvertTo-JsonLiteral -Depth 5 | Out-File -LiteralPath $FilePath } elseif ($AsObject) { $AuditPolicy } else { $AuditPolicy | ConvertTo-JsonLiteral -Depth 5 }
}
function Clear-SystemAuditPolicy {
    <#
    .SYNOPSIS
    Clears all audit policies to their default values (Not Configured)
 
    .DESCRIPTION
    Clears all audit policies to their default values (Not Configured)
 
    .PARAMETER ComputerName
    ComputerName for remote system to clear audit policy from. Requires permissions on the destination.
 
    .EXAMPLE
    Clear-SystemAuditPolicy -WhatIf
 
    .NOTES
    General notes
    #>

    [cmdletBinding(SupportsShouldProcess)]
    param([string] $ComputerName)
    $CurrentPolicies = Get-SystemAuditPolicy -ComputerName $ComputerName
    foreach ($Policy in $CurrentPolicies.Keys) {
        $Value = $CurrentPolicies[$Policy]
        if ($Value -ne 'NotConfigured') {
            $setSystemAuditPolicySplat = @{Policy = $Policy
                ComputerName                      = $ComputerName
                WhatIf                            = $WhatIfPreference
                Value                             = 'NotConfigured'
            }
            $Success = Set-SystemAuditPolicy @setSystemAuditPolicySplat
            if ($Success.Result -in 'Success', 'Not Required') {} elseif ($Success.Result -eq 'WhatIf') {} else { Write-Warning -Message " Clear-SystemAuditPolicy - Failed to clear $Policy, status: $($Success.Result) error: $($Success.Error)" }
        }
    }
}
function Get-SystemAuditPolicy {
    <#
    .SYNOPSIS
    Small functions that reads Audit Policy (the same way as auditpol.exe) and returns a hashtable with the values.
 
    .DESCRIPTION
    Small functions that reads Audit Policy (the same way as auditpol.exe) and returns a hashtable with the values.
 
    .PARAMETER ComputerName
    ComputerName for remote system to read audit policy from. Requires permissions on the destination.
 
    .PARAMETER Policy
    Returns the specified policy, and only that policy.
 
    .PARAMETER Categories
    Forces display in category view
 
    .EXAMPLE
    $AuditPolicies = Get-SystemAuditPolicy
    $AuditPolicies | Format-Table
    $AuditPolicies.AccountLogon | Format-Table
    $AuditPolicies.AccountManagement | Format-Table
    $AuditPolicies.DetailedTracking | Format-Table
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([string] $ComputerName,
        [ValidateSet("Security System Extension",
            "System Integrity",
            "IPsec Driver",
            "Other System Events",
            "Security State Change",
            "Logon",
            "Logoff",
            "Account Lockout",
            "IPsec Main Mode",
            "IPsec Quick Mode",
            "IPsec Extended Mode",
            "Special Logon",
            "Other Logon/Logoff Events",
            "Network Policy Server",
            "User / Device Claims",
            "Group Membership",
            "File System",
            "Registry",
            "Kernel Object",
            "SAM",
            "Certification Services",
            "Application Generated",
            "Handle Manipulation",
            "File Share",
            "Filtering Platform Packet Drop",
            "Filtering Platform Connection",
            "Other Object Access Events",
            "Detailed File Share",
            "Removable Storage",
            "Central Policy Staging",
            "Non Sensitive Privilege Use",
            "Other Privilege Use Events",
            "Sensitive Privilege Use",
            "Process Creation",
            "Process Termination",
            "DPAPI Activity",
            "RPC Events",
            "Plug and Play Events",
            "Token Right Adjusted Events",
            "Audit Policy Change",
            "Authentication Policy Change",
            "Authorization Policy Change",
            "MPSSVC Rule-Level Policy Change",
            "Filtering Platform Policy Change",
            "Other Policy Change Events",
            "Computer Account Management",
            "Security Group Management",
            "Distribution Group Management",
            "Application Group Management",
            "Other Account Management Events",
            "User Account Management",
            "Directory Service Access",
            "Directory Service Changes",
            "Directory Service Replication",
            "Detailed Directory Service Replication",
            "Kerberos Service Ticket Operations",
            "Other Account Logon Events",
            "Kerberos Authentication Service",
            "Credential Validation")][alias('Policies')][string] $Policy,
        [switch] $Categories)
    Add-Type -TypeDefinition @"
        using System;
 
        namespace AuditPolicies
        {
            public enum Events {
                NotConfigured = 0,
                Success = 1,
                Failure = 2,
                SuccessAndFailure = 3
            }
        }
"@

    $IsSystem = [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem
    if (-not $IsSystem) {
        $SID = ConvertFrom-SID -SID "S-1-5-32-544"
        Set-SystemAuditPolicyPermissions -Identity $SID.Name -Permissions FullControl -WhatIf:$false -ComputerName $ComputerName
    }
    $Audit = Get-PSRegistry -RegistryPath "HKEY_LOCAL_MACHINE\SECURITY\Policy\PolAdtEv" -Key "" -ComputerName $ComputerName
    if (-not $IsSystem) {
        $SID = ConvertFrom-SID -SID "S-1-5-32-544"
        Remove-SystemAuditPolicyPermissions -Identity $SID.Name -Permissions FullControl -WhatIf:$false -ComputerName $ComputerName
    }
    if ($Audit.PSConnection -eq $true -and $Audit.PSError -eq $false) {
        $Data = $Audit.PSValue
        $OperatingSystem = Get-ComputerOperatingSystem -ComputerName $ComputerName
        $Version = [version]$OperatingSystem.OperatingSystemBuild
        if ($Version.Major -eq 6 -and $Version.Minor -eq 3) {
            Write-Verbose -Message "Get-SystemAuditPolicy for Windows 2012 R2"
            $AuditPolicies = [ordered] @{System = [ordered] @{'Security State Change' = [AuditPolicies.Events] $Data[12]
                    'Security System Extension'                                       = [AuditPolicies.Events] $Data[14]
                    'System Integrity'                                                = [AuditPolicies.Events] $Data[16]
                    'IPsec Driver'                                                    = [AuditPolicies.Events] $Data[18]
                    'Other System Events'                                             = [AuditPolicies.Events] $Data[20]
                }
                LogonLogoff                     = [ordered] @{'Logon' = [AuditPolicies.Events] $Data[22]
                    'Logoff'                      = [AuditPolicies.Events] $Data[24]
                    'Account Lockout'             = [AuditPolicies.Events] $Data[26]
                    'IPSec Main Mode'             = [AuditPolicies.Events] $Data[28]
                    'Special Logon'               = [AuditPolicies.Events] $Data[30]
                    'IPSec Quick Mode'            = [AuditPolicies.Events] $Data[32]
                    'IPSec Extended Mode'         = [AuditPolicies.Events] $Data[34]
                    'Other Logon/Logoff Events'   = [AuditPolicies.Events] $Data[36]
                    'Network Policy Server'       = [AuditPolicies.Events] $Data[38]
                    'User / Device Claims'        = [AuditPolicies.Events] $Data[40]
                }
                ObjectAccess                    = [ordered] @{'File System' = [AuditPolicies.Events] $Data[42]
                    'Registry'                           = [AuditPolicies.Events] $Data[44]
                    'Kernel Object'                      = [AuditPolicies.Events] $Data[46]
                    'SAM'                                = [AuditPolicies.Events] $Data[48]
                    'Other Object Access Events'         = [AuditPolicies.Events] $Data[50]
                    'Certification Services'             = [AuditPolicies.Events] $Data[52]
                    'Application Generated'              = [AuditPolicies.Events] $Data[54]
                    'Handle Manipulation'                = [AuditPolicies.Events] $Data[56]
                    'File Share'                         = [AuditPolicies.Events] $Data[58]
                    'Filtering Platform Packet Drop'     = [AuditPolicies.Events] $Data[60]
                    'Filtering Platform Connection'      = [AuditPolicies.Events] $Data[62]
                    'Detailed File Share'                = [AuditPolicies.Events] $Data[64]
                    'Removable Storage'                  = [AuditPolicies.Events] $Data[66]
                    'Central Policy Staging'             = [AuditPolicies.Events] $Data[68]
                }
                PrivilegeUse                    = [ordered] @{'Sensitive Privilege Use' = [AuditPolicies.Events] $Data[70]
                    'Non Sensitive Privilege Use'                    = [AuditPolicies.Events] $Data[72]
                    'Other Privilege Use Events'                     = [AuditPolicies.Events] $Data[74]
                }
                DetailedTracking                = [ordered] @{'Process Creation' = [AuditPolicies.Events] $Data[76]
                    'Process Termination'                         = [AuditPolicies.Events] $Data[78]
                    'DPAPI Activity'                              = [AuditPolicies.Events] $Data[80]
                    'RPC Events'                                  = [AuditPolicies.Events] $Data[82]
                    'Plug and Play Events'                        = [AuditPolicies.Events] $Data[84]
                }
                PolicyChange                    = [ordered] @{'Audit Policy Change' = [AuditPolicies.Events] $Data[86]
                    'Authentication Policy Change'               = [AuditPolicies.Events] $Data[88]
                    'Authorization Policy Change'                = [AuditPolicies.Events] $Data[90]
                    'MPSSVC Rule-Level Policy Change'            = [AuditPolicies.Events] $Data[92]
                    'Filtering Platform Policy Change'           = [AuditPolicies.Events] $Data[94]
                    'Other Policy Change Events'                 = [AuditPolicies.Events] $Data[96]
                }
                AccountManagement               = [ordered] @{'User Account Management' = [AuditPolicies.Events] $Data[98]
                    'Computer Account Management'                         = [AuditPolicies.Events] $Data[100]
                    'Security Group Management'                           = [AuditPolicies.Events] $Data[102]
                    'Distribution Group Management'                       = [AuditPolicies.Events] $Data[104]
                    'Application Group Management'                        = [AuditPolicies.Events] $Data[106]
                    'Other Account Management Events'                     = [AuditPolicies.Events] $Data[108]
                }
                DSAccess                        = [ordered] @{'Directory Service Access' = [AuditPolicies.Events] $Data[102]
                    'Directory Service Changes'                   = [AuditPolicies.Events] $Data[104]
                    'Directory Service Replication'               = [AuditPolicies.Events] $Data[106]
                    'Detailed Directory Service Replication'      = [AuditPolicies.Events] $Data[108]
                }
                AccountLogon                    = [ordered] @{'Credential Validation' = [AuditPolicies.Events] $Data[110]
                    'Kerberos Service Ticket Operations'           = [AuditPolicies.Events] $Data[112]
                    'Other Account Logon Events'                   = [AuditPolicies.Events] $Data[114]
                    'Kerberos Authentication Service'              = [AuditPolicies.Events] $Data[116]
                }
            }
        } elseif ($Version.Major -lt 6) {
            Write-Verbose -Message "Get-SystemAuditPolicy for Windows 2012 and earlier (not really tested)"
            $AuditPolicies = [ordered] @{System = [ordered] @{'Security State Change' = [AuditPolicies.Events] $Data[12]
                    'Security System Extension'                                       = [AuditPolicies.Events] $Data[14]
                    'System Integrity'                                                = [AuditPolicies.Events] $Data[16]
                    'IPsec Driver'                                                    = [AuditPolicies.Events] $Data[18]
                    'Other System Events'                                             = [AuditPolicies.Events] $Data[20]
                }
                LogonLogoff                     = [ordered] @{'Logon' = [AuditPolicies.Events] $Data[22]
                    'Logoff'                      = [AuditPolicies.Events] $Data[24]
                    'Account Lockout'             = [AuditPolicies.Events] $Data[26]
                    'IPSec Main Mode'             = [AuditPolicies.Events] $Data[28]
                    'Special Logon'               = [AuditPolicies.Events] $Data[30]
                    'IPSec Quick Mode'            = [AuditPolicies.Events] $Data[32]
                    'IPSec Extended Mode'         = [AuditPolicies.Events] $Data[34]
                    'Other Logon/Logoff Events'   = [AuditPolicies.Events] $Data[36]
                    'Network Policy Server'       = [AuditPolicies.Events] $Data[38]
                }
                ObjectAccess                    = [ordered] @{'File System' = [AuditPolicies.Events] $Data[40]
                    'Registry'                           = [AuditPolicies.Events] $Data[42]
                    'Kernel Object'                      = [AuditPolicies.Events] $Data[44]
                    'SAM'                                = [AuditPolicies.Events] $Data[46]
                    'Other Object Access Events'         = [AuditPolicies.Events] $Data[48]
                    'Certification Services'             = [AuditPolicies.Events] $Data[50]
                    'Application Generated'              = [AuditPolicies.Events] $Data[52]
                    'Handle Manipulation'                = [AuditPolicies.Events] $Data[54]
                    'File Share'                         = [AuditPolicies.Events] $Data[56]
                    'Filtering Platform Packet Drop'     = [AuditPolicies.Events] $Data[58]
                    'Filtering Platform Connection'      = [AuditPolicies.Events] $Data[60]
                    'Detailed File Share'                = [AuditPolicies.Events] $Data[62]
                }
                PrivilegeUse                    = [ordered] @{'Sensitive Privilege Use' = [AuditPolicies.Events] $Data[64]
                    'Non Sensitive Privilege Use'                    = [AuditPolicies.Events] $Data[66]
                    'Other Privilege Use Events'                     = [AuditPolicies.Events] $Data[68]
                }
                DetailedTracking                = [ordered] @{'Process Creation' = [AuditPolicies.Events] $Data[70]
                    'Process Termination'                         = [AuditPolicies.Events] $Data[72]
                    'DPAPI Activity'                              = [AuditPolicies.Events] $Data[74]
                    'RPC Events'                                  = [AuditPolicies.Events] $Data[76]
                }
                PolicyChange                    = [ordered] @{'Audit Policy Change' = [AuditPolicies.Events] $Data[78]
                    'Authentication Policy Change'               = [AuditPolicies.Events] $Data[80]
                    'Authorization Policy Change'                = [AuditPolicies.Events] $Data[82]
                    'MPSSVC Rule-Level Policy Change'            = [AuditPolicies.Events] $Data[84]
                    'Filtering Platform Policy Change'           = [AuditPolicies.Events] $Data[86]
                    'Other Policy Change Events'                 = [AuditPolicies.Events] $Data[88]
                }
                AccountManagement               = [ordered] @{'User Account Management' = [AuditPolicies.Events] $Data[90]
                    'Computer Account Management'                         = [AuditPolicies.Events] $Data[92]
                    'Security Group Management'                           = [AuditPolicies.Events] $Data[94]
                    'Distribution Group Management'                       = [AuditPolicies.Events] $Data[96]
                    'Application Group Management'                        = [AuditPolicies.Events] $Data[98]
                    'Other Account Management Events'                     = [AuditPolicies.Events] $Data[100]
                }
                DSAccess                        = [ordered] @{'Directory Service Access' = [AuditPolicies.Events] $Data[102]
                    'Directory Service Changes'                   = [AuditPolicies.Events] $Data[104]
                    'Directory Service Replication'               = [AuditPolicies.Events] $Data[106]
                    'Detailed Directory Service Replication'      = [AuditPolicies.Events] $Data[108]
                }
                AccountLogon                    = [ordered] @{'Credential Validation' = [AuditPolicies.Events] $Data[110]
                    'Kerberos Service Ticket Operations'           = [AuditPolicies.Events] $Data[112]
                    'Other Account Logon Events'                   = [AuditPolicies.Events] $Data[114]
                    'Kerberos Authentication Service'              = [AuditPolicies.Events] $Data[116]
                }
            }
        } else {
            Write-Verbose -Message "Get-SystemAuditPolicy for Windows 2016/Windows 10 and later"
            $AuditPolicies = [ordered] @{System = [ordered] @{'Security State Change' = [AuditPolicies.Events] $Data[12]
                    'Security System Extension'                                       = [AuditPolicies.Events] $Data[14]
                    'System Integrity'                                                = [AuditPolicies.Events] $Data[16]
                    'IPsec Driver'                                                    = [AuditPolicies.Events] $Data[18]
                    'Other System Events'                                             = [AuditPolicies.Events] $Data[20]
                }
                LogonLogoff                     = [ordered] @{'Logon' = [AuditPolicies.Events] $Data[22]
                    'Logoff'                      = [AuditPolicies.Events] $Data[24]
                    'Account Lockout'             = [AuditPolicies.Events] $Data[26]
                    'IPSec Main Mode'             = [AuditPolicies.Events] $Data[28]
                    'Special Logon'               = [AuditPolicies.Events] $Data[30]
                    'IPSec Quick Mode'            = [AuditPolicies.Events] $Data[32]
                    'IPSec Extended Mode'         = [AuditPolicies.Events] $Data[34]
                    'Other Logon/Logoff Events'   = [AuditPolicies.Events] $Data[36]
                    'Network Policy Server'       = [AuditPolicies.Events] $Data[38]
                    'User / Device Claims'        = [AuditPolicies.Events] $Data[40]
                    'Group Membership'            = [AuditPolicies.Events] $Data[42]
                }
                ObjectAccess                    = [ordered] @{'File System' = [AuditPolicies.Events] $Data[44]
                    'Registry'                           = [AuditPolicies.Events] $Data[46]
                    'Kernel Object'                      = [AuditPolicies.Events] $Data[48]
                    'SAM'                                = [AuditPolicies.Events] $Data[50]
                    'Other Object Access Events'         = [AuditPolicies.Events] $Data[52]
                    'Certification Services'             = [AuditPolicies.Events] $Data[54]
                    'Application Generated'              = [AuditPolicies.Events] $Data[56]
                    'Handle Manipulation'                = [AuditPolicies.Events] $Data[58]
                    'File Share'                         = [AuditPolicies.Events] $Data[60]
                    'Filtering Platform Packet Drop'     = [AuditPolicies.Events] $Data[62]
                    'Filtering Platform Connection'      = [AuditPolicies.Events] $Data[64]
                    'Detailed File Share'                = [AuditPolicies.Events] $Data[66]
                    'Removable Storage'                  = [AuditPolicies.Events] $Data[68]
                    'Central Policy Staging'             = [AuditPolicies.Events] $Data[70]
                }
                PrivilegeUse                    = [ordered] @{'Sensitive Privilege Use' = [AuditPolicies.Events] $Data[72]
                    'Non Sensitive Privilege Use'                    = [AuditPolicies.Events] $Data[74]
                    'Other Privilege Use Events'                     = [AuditPolicies.Events] $Data[76]
                }
                DetailedTracking                = [ordered] @{'Process Creation' = [AuditPolicies.Events] $Data[78]
                    'Process Termination'                         = [AuditPolicies.Events] $Data[80]
                    'DPAPI Activity'                              = [AuditPolicies.Events] $Data[82]
                    'RPC Events'                                  = [AuditPolicies.Events] $Data[84]
                    'Plug and Play Events'                        = [AuditPolicies.Events] $Data[86]
                    'Token Right Adjusted Events'                 = [AuditPolicies.Events] $Data[88]
                }
                PolicyChange                    = [ordered] @{'Audit Policy Change' = [AuditPolicies.Events] $Data[90]
                    'Authentication Policy Change'               = [AuditPolicies.Events] $Data[92]
                    'Authorization Policy Change'                = [AuditPolicies.Events] $Data[94]
                    'MPSSVC Rule-Level Policy Change'            = [AuditPolicies.Events] $Data[96]
                    'Filtering Platform Policy Change'           = [AuditPolicies.Events] $Data[98]
                    'Other Policy Change Events'                 = [AuditPolicies.Events] $Data[100]
                }
                AccountManagement               = [ordered] @{'User Account Management' = [AuditPolicies.Events] $Data[102]
                    'Computer Account Management'                         = [AuditPolicies.Events] $Data[104]
                    'Security Group Management'                           = [AuditPolicies.Events] $Data[106]
                    'Distribution Group Management'                       = [AuditPolicies.Events] $Data[108]
                    'Application Group Management'                        = [AuditPolicies.Events] $Data[110]
                    'Other Account Management Events'                     = [AuditPolicies.Events] $Data[112]
                }
                DSAccess                        = [ordered] @{'Directory Service Access' = [AuditPolicies.Events] $Data[114]
                    'Directory Service Changes'                   = [AuditPolicies.Events] $Data[116]
                    'Directory Service Replication'               = [AuditPolicies.Events] $Data[118]
                    'Detailed Directory Service Replication'      = [AuditPolicies.Events] $Data[120]
                }
                AccountLogon                    = [ordered] @{'Credential Validation' = [AuditPolicies.Events] $Data[122]
                    'Kerberos Service Ticket Operations'           = [AuditPolicies.Events] $Data[124]
                    'Other Account Logon Events'                   = [AuditPolicies.Events] $Data[126]
                    'Kerberos Authentication Service'              = [AuditPolicies.Events] $Data[128]
                }
            }
        }
        if ($Policy) {
            foreach ($Entry in $AuditPolicies.Keys) {
                foreach ($Key in $AuditPolicies[$Entry].Keys) {
                    if ($Policy -eq $Key) {
                        return [PSCustomObject] @{'Category' = $Entry
                            'Policy'                         = $Policy
                            'Value'                          = $AuditPolicies[$Entry][$Key]
                        }
                    }
                }
            }
        } else {
            if (-not $Categories) {
                $OutputObject = [ordered] @{}
                foreach ($Entry in $AuditPolicies.Keys) { foreach ($Key in $AuditPolicies[$Entry].Keys) { $OutputObject[$Key] = $AuditPolicies[$Entry][$Key] } }
                $OutputObject
            } else { $AuditPolicies }
        }
    } else { Write-Warning -Message "Get-SystemAuditPolicies - Audit policies couldn't be read: $($Audit.PSErrorMessage)" }
}
function Get-SystemAuditPolicyFromFile {
    <#
    .SYNOPSIS
    Get local security policy audit policies and group policies that contain audit policies in them (if cache is used).
 
    .DESCRIPTION
    Get local security policy audit policies and group policies that contain audit policies in them (if cache is used).
 
    .EXAMPLE
    An example
 
    .NOTES
    General notes
    #>

    [cmdletBinding()]
    param()
    $Output = [ordered] @{}
    $GPOPath = [io.path]::Combine($Env:SystemRoot, "System32", "GroupPolicy", 'DataStore')
    $GPOWithAudit = Get-ChildItem -LiteralPath $GPOPath -Filter "Audit.csv" -Recurse -Force -ErrorAction SilentlyContinue
    if ($GPOWithAudit) {
        foreach ($File in $GPOWithAudit) {
            $pattern = "Policies\\(.*?)\\Machine\\"
            $GUID = [regex]::Match($File.FullName, $pattern).Groups[1].Value
            if ($GUID) { $Output[$GUID] = Get-Content -LiteralPath $File.FullName -Raw | ConvertFrom-Csv }
        }
    }
    $LocalSecurityPolicy = [io.path]::Combine($Env:SystemRoot, "System32", "GroupPolicy", "Machine", "Microsoft", "Windows NT", "Audit", 'Audit.csv')
    if (Test-Path -LiteralPath $LocalSecurityPolicy) { $Output["LocalSecurityPolicy"] = Get-Content -LiteralPath $LocalSecurityPolicy -Raw | ConvertFrom-Csv }
    $Output
}
function Remove-SystemAuditPolicyPermissions {
    <#
    .SYNOPSIS
    Removes audit policy permissions from a user or group.
 
    .DESCRIPTION
    Removes audit policy permissions from a user or group.
    By default only SYSTEM account has any permissions.
    This command can be used to remove audit policy permissions from a user or group.
 
    .PARAMETER Identity
    Specifies the user or group to remove audit policy permissions from.
 
    .PARAMETER Permissions
    Specifies the audit policy permissions to remove. By default FullControl
 
    .EXAMPLE
    Remove-SystemAuditPolicyPermissions -Identity "przemyslaw.klys" -Verbose -WhatIf
 
    .NOTES
    General notes
    #>

    [cmdletBinding(SupportsShouldProcess)]
    param([parameter(Mandatory)][string] $Identity,
        [System.Security.AccessControl.RegistryRights] $Permissions = [System.Security.AccessControl.RegistryRights]::FullControl,
        [string] $ComputerName)
    try {
        if ($ComputerName) {
            $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LOCAL', $ComputerName, 0)
            $RegistryKeyControl = $BaseHive.OpenSubKey('SECURITY',
                [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
                [System.Security.AccessControl.RegistryRights]::ChangePermissions)
        } else {
            $RegistryKeyControl = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SECURITY',
                [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
                [System.Security.AccessControl.RegistryRights]::ChangePermissions)
        }
    } catch {
        if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Remove-SystemAuditPolicyPermissions - Opening registry failed $($_.Exception.Message)" }
        return
    }
    $AccessControlList = $RegistryKeyControl.GetAccessControl()
    $Account = [System.Security.Principal.NTAccount] $Identity
    $InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit'
    $PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None
    $AccessType = [System.Security.AccessControl.AccessControlType]::Allow
    $AccessRule = [System.Security.AccessControl.RegistryAccessRule]::new($Account,
        $Permissions,
        $InheritanceFlag,
        $PropagationFlag,
        $AccessType)
    if ($PSCmdlet.ShouldProcess("Registry HKLM\SECURITY", "Removing 'FullControl' access to $Identity for SECURITY subkey")) {
        try { $Output = $AccessControlList.RemoveAccessRule($AccessRule) } catch {
            if ($PSBoundParameters.ErrorAction -eq 'Stop') {
                if ($null -ne $BaseHive) {
                    $BaseHive.Close()
                    $BaseHive.Dispose()
                }
                throw
            } else { Write-Warning -Message "Remove-SystemAuditPolicyPermissions - Removing access rule failed $($_.Exception.Message)" }
        }
        if ($Output) { $RegistryKeyControl.SetAccessControl($AccessControlList) }
    }
    if ($null -ne $BaseHive) {
        $BaseHive.Close()
        $BaseHive.Dispose()
    }
}
function Restore-SystemAuditPolicy {
    <#
    .SYNOPSIS
    Restore the system audit policy to the one from backup.
 
    .DESCRIPTION
    Restore the system audit policy to the one from backup.
 
    .PARAMETER ComputerName
    ComputerName for remote system to restore audit policy on. Requires permissions on the destination.
 
    .PARAMETER Object
    Object to restore audit policy from
 
    .PARAMETER JSON
    JSON object to restore audit policy from
 
    .PARAMETER FilePath
    File path to restore audit policy from
 
    .PARAMETER Policy
    Pick policy/policies to restore from all policies provided
 
    .EXAMPLE
    $FilePath = "$PSScriptRoot\Backups\AuditPolicy.json"
    Restore-SystemAuditPolicy -FilePath $FilePath -Verbose -WhatIf
 
    .EXAMPLE
    $FilePath = "$PSScriptRoot\Backups\AuditPolicy.json"
    Restore-SystemAuditPolicy -FilePath $FilePath -Verbose -Policy 'Application Group Management'
 
    .NOTES
    General notes
    #>

    [cmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "File")]
    param([string] $ComputerName,
        [parameter(Mandatory, ParameterSetName = 'Object')][System.Collections.IDictionary] $Object,
        [parameter(Mandatory, ParameterSetName = 'JSON')][string] $JSON,
        [parameter(Mandatory, ParameterSetName = 'File')][string] $FilePath,
        [ValidateSet("Security System Extension",
            "System Integrity",
            "IPsec Driver",
            "Other System Events",
            "Security State Change",
            "Logon",
            "Logoff",
            "Account Lockout",
            "IPsec Main Mode",
            "IPsec Quick Mode",
            "IPsec Extended Mode",
            "Special Logon",
            "Other Logon/Logoff Events",
            "Network Policy Server",
            "User / Device Claims",
            "Group Membership",
            "File System",
            "Registry",
            "Kernel Object",
            "SAM",
            "Certification Services",
            "Application Generated",
            "Handle Manipulation",
            "File Share",
            "Filtering Platform Packet Drop",
            "Filtering Platform Connection",
            "Other Object Access Events",
            "Detailed File Share",
            "Removable Storage",
            "Central Policy Staging",
            "Non Sensitive Privilege Use",
            "Other Privilege Use Events",
            "Sensitive Privilege Use",
            "Process Creation",
            "Process Termination",
            "DPAPI Activity",
            "RPC Events",
            "Plug and Play Events",
            "Token Right Adjusted Events",
            "Audit Policy Change",
            "Authentication Policy Change",
            "Authorization Policy Change",
            "MPSSVC Rule-Level Policy Change",
            "Filtering Platform Policy Change",
            "Other Policy Change Events",
            "Computer Account Management",
            "Security Group Management",
            "Distribution Group Management",
            "Application Group Management",
            "Other Account Management Events",
            "User Account Management",
            "Directory Service Access",
            "Directory Service Changes",
            "Directory Service Replication",
            "Detailed Directory Service Replication",
            "Kerberos Service Ticket Operations",
            "Other Account Logon Events",
            "Kerberos Authentication Service",
            "Credential Validation")][alias('Policies')][string[]] $Policy)
    if ($PSBoundParameters.ContainsKey('FilePath')) {
        if ($FilePath -and (Test-Path -LiteralPath $FilePath)) {
            try {
                $FileContent = Get-Content -LiteralPath $FilePath -Raw -ErrorAction Stop
                $SystemPolicies = $FileContent | ConvertFrom-Json -ErrorAction Stop
            } catch { Write-Warning -Message "Restore-SystemAuditPolicy - JSON $JSON is not valid. Restore aborted. Error: $($_.Exception.Message)" }
        } else { Write-Warning -Message "Restore-SystemAuditPolicy - File $FilePath not found. Restore aborted." }
    } elseif ($PSBoundParameters.ContainsKey('Object')) { $SystemPolicies = $Object } elseif ($PSBoundParameters.ContainsKey('JSON')) {
        try { $SystemPolicies = $JSON | ConvertFrom-Json -ErrorAction Stop } catch {
            Write-Warning -Message "Restore-SystemAuditPolicy - JSON $JSON is not valid. Restore aborted. Error: $($_.Exception.Message)"
            return
        }
    } else {
        Write-Warning -Message "Restore-SystemAuditPolicy - No file or object specified. Restore aborted."
        return
    }
    if ($SystemPolicies) {
        $AuditPolicy = Get-SystemAuditPolicy -ComputerName $ComputerName
        if ($AuditPolicy) {
            if ($SystemPolicies -is [System.Collections.IDictionary]) {
                foreach ($CurrentPolicy in $SystemPolicies.Keys) {
                    if ($Policy) { if ($CurrentPolicy -notin $Policy) { continue } }
                    $Value = $SystemPolicies[$CurrentPolicy]
                    if ($Value -ne $AuditPolicy[$CurrentPolicy]) {
                        $setSystemAuditPolicySplat = @{Policy = $CurrentPolicy
                            ComputerName                      = $ComputerName
                            WhatIf                            = $WhatIfPreference
                            Value                             = $Value
                        }
                        $Success = Set-SystemAuditPolicy @setSystemAuditPolicySplat
                        $Success
                    } else {
                        [PSCustomObject] @{'Policy' = $CurrentPolicy
                            'Value'                 = $Value
                            'Result'                = 'Not required'
                            'Error'                 = ''
                        }
                    }
                }
            } else {
                foreach ($CurrentPolicy in $SystemPolicies.PSObject.Properties.Name) {
                    if ($Policy) { if ($CurrentPolicy -notin $Policy) { continue } }
                    $Value = $SystemPolicies.$CurrentPolicy
                    if ($Value -ne $AuditPolicy[$CurrentPolicy]) {
                        Write-Verbose -Message "Restore-SystemAuditPolicies - Current value for $CurrentPolicy is $($AuditPolicy[$CurrentPolicy]) to be replaced with $Value"
                        $setSystemAuditPolicySplat = @{Policy = $CurrentPolicy
                            ComputerName                      = $ComputerName
                            WhatIf                            = $WhatIfPreference
                            Value                             = $Value
                        }
                        $Success = Set-SystemAuditPolicy @setSystemAuditPolicySplat
                        $Success
                    } else {
                        [PSCustomObject] @{'Policy' = $CurrentPolicy
                            'Value'                 = $Value
                            'Result'                = 'Not required'
                            'Error'                 = ''
                        }
                        Write-Verbose -Message "Restore-SystemAuditPolicies - Current value for $CurrentPolicy is $($AuditPolicy[$CurrentPolicy]) is the same as requested $Value"
                    }
                }
            }
        }
    }
}
function Set-SystemAuditPolicy {
    <#
    .SYNOPSIS
    Sets the audit policy similary to what auditpol.exe does.
 
    .DESCRIPTION
    Sets the audit policy similary to what auditpol.exe does.
 
    .PARAMETER ComputerName
    ComputerName for remote system to clear audit policy from. Requires permissions on the destination.
 
    .PARAMETER Policy
    The policy to set from all categories
 
    .PARAMETER AccountLogon
    Choose one of the options for the AccountLogon parameter.
 
    .PARAMETER AccountManagement
    Choose one of the options for the AccountManagement parameter.
 
    .PARAMETER DetailedTracking
    Choose one of the options for the DetailedTracking parameter.
 
    .PARAMETER DSAccess
    Choose one of the options for the DSAccess parameter.
 
    .PARAMETER LogonLogoff
    Choose one of the options for the LogonLogoff parameter.
 
    .PARAMETER ObjectAccess
    Choose one of the options for the ObjectAccess parameter.
 
    .PARAMETER PolicyChange
    Choose one of the options for the PolicyChange parameter.
 
    .PARAMETER PrivilegeUse
    Choose one of the options for the PrivilegeUse parameter.
 
    .PARAMETER System
    Choose one of the options for the System parameter.
 
    .PARAMETER Value
    Choose one of the options for the Value parameter.
 
    .PARAMETER UseAuditPol
    Forces use of AuditPol.exe instead of registry approach
 
    .PARAMETER UseLocalSecurityPolicy
    Forces use of LocalSecurityPolicy (audit.csv) to instead of registry approach
    It's important to know that refresh of policies happens on next GPO refresh rather than being applied immediately.
 
    .PARAMETER Suppress
    Suppresses the output of the command
 
    .EXAMPLE
    $WhatIf = $false
 
    Set-SystemAuditPolicy -AccountLogon 'Kerberos Service Ticket Operations' -Value Failure -Verbose -WhatIf:$WhatIf
    Set-SystemAuditPolicy -AccountLogon 'Other AccountLogon Events' -Value Failure -Verbose -WhatIf:$WhatIf
    Set-SystemAuditPolicy -AccountLogon 'Kerberos Authentication Service' -Value SuccessAndFailure -Verbose -WhatIf:$WhatIf
    Set-SystemAuditPolicy -AccountLogon 'Credential Validation' -Value Success -Verbose -WhatIf:$WhatIf
 
    Set-SystemAuditPolicy -AccountManagement 'Computer Account Management' -Value Failure -Verbose -WhatIf:$WhatIf
    Set-SystemAuditPolicy -AccountManagement 'Application Group Management' -Value Success -Verbose -WhatIf:$WhatIf
    Set-SystemAuditPolicy -AccountManagement 'Distribution Group Management' -Value Failure -Verbose -WhatIf:$WhatIf
    Set-SystemAuditPolicy -AccountManagement 'Other Account ManagementEvents' -Value Failure -Verbose -WhatIf:$WhatIf
    Set-SystemAuditPolicy -AccountManagement 'Security Group Management' -Value Failure -Verbose -WhatIf:$WhatIf
    Set-SystemAuditPolicy -AccountManagement 'User Account Management' -Value Failure -Verbose -WhatIf:$WhatIf
 
    .EXAMPLE
    Set-SystemAuditPolicy -AccountManagement 'User Account Management' -Value Failure -Verbose -WhatIf -UseLocalSecurityPolicy
 
    .EXAMPLE
    Set-SystemAuditPolicy -AccountManagement 'User Account Management' -Value Failure -Verbose -WhatIf -UseAuditPol
 
    .NOTES
    General notes
    #>

    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'AllPolicies')]
    param([string] $ComputerName,
        [parameter(Mandatory, ParameterSetName = 'AllPolicies')]
        [ValidateSet("Security System Extension",
            "System Integrity",
            "IPsec Driver",
            "Other System Events",
            "Security State Change",
            "Logon",
            "Logoff",
            "Account Lockout",
            "IPsec Main Mode",
            "IPsec Quick Mode",
            "IPsec Extended Mode",
            "Special Logon",
            "Other Logon/Logoff Events",
            "Network Policy Server",
            "User / Device Claims",
            "Group Membership",
            "File System",
            "Registry",
            "Kernel Object",
            "SAM",
            "Certification Services",
            "Application Generated",
            "Handle Manipulation",
            "File Share",
            "Filtering Platform Packet Drop",
            "Filtering Platform Connection",
            "Other Object Access Events",
            "Detailed File Share",
            "Removable Storage",
            "Central Policy Staging",
            "Non Sensitive Privilege Use",
            "Other Privilege Use Events",
            "Sensitive Privilege Use",
            "Process Creation",
            "Process Termination",
            "DPAPI Activity",
            "RPC Events",
            "Plug and Play Events",
            "Token Right Adjusted Events",
            "Audit Policy Change",
            "Authentication Policy Change",
            "Authorization Policy Change",
            "MPSSVC Rule-Level Policy Change",
            "Filtering Platform Policy Change",
            "Other Policy Change Events",
            "Computer Account Management",
            "Security Group Management",
            "Distribution Group Management",
            "Application Group Management",
            "Other Account Management Events",
            "User Account Management",
            "Directory Service Access",
            "Directory Service Changes",
            "Directory Service Replication",
            "Detailed Directory Service Replication",
            "Kerberos Service Ticket Operations",
            "Other Account Logon Events",
            "Kerberos Authentication Service",
            "Credential Validation")][alias('Policies')][string] $Policy,
        [parameter(Mandatory, ParameterSetName = 'AccountLogon')][ValidateSet('Credential Validation',
            'Kerberos Service Ticket Operations',
            'Other Account Logon Events',
            'Kerberos Authentication Service')][string] $AccountLogon,
        [parameter(Mandatory, ParameterSetName = 'AccountManagement')][ValidateSet('User Account Management',
            'Computer Account Management',
            'Security Group Management',
            'Distribution Group Management',
            'Application Group Management',
            'Other Account Management Events')][string] $AccountManagement,
        [parameter(Mandatory, ParameterSetName = 'DetailedTracking')][ValidateSet('Process Creation',
            'Process Termination',
            'DPAPI Activity',
            'RPC Events',
            'Plug and Play Events',
            'Token Right Adjusted Events')][string] $DetailedTracking,
        [parameter(Mandatory, ParameterSetName = 'DSAccess')][ValidateSet('Directory Service Access',
            'Directory Service Changes',
            'Directory Service Replication',
            'Detailed Directory Service Replication')][string] $DSAccess,
        [parameter(Mandatory, ParameterSetName = 'LogonLogoff')][ValidateSet('Logon',
            'Logoff',
            'Account Lockout',
            'IPSec Main Mode',
            'Special Logon',
            'IPSec Quick Mode',
            'IPSec Extended Mode',
            'Other Logon/Logoff Events',
            'Network Policy Server',
            'User / Device Claims',
            'Group Membership')][string] $LogonLogoff,
        [parameter(Mandatory, ParameterSetName = 'ObjectAccess')][ValidateSet('File System',
            'Registry',
            'Kernel Object',
            'SAM',
            'Other Object Access Events',
            'Certification Services',
            'Application Generated',
            'Handle Manipulation',
            'File Share',
            'Filtering Platform Packet Drop',
            'Filtering Platform Connection',
            'Detailed File Share',
            'Removable Storage',
            'Central Policy Staging')][string] $ObjectAccess,
        [parameter(Mandatory, ParameterSetName = 'PolicyChange')][ValidateSet('Audit Policy Change',
            'Authentication Policy Change',
            'Authorization Policy Change',
            'MPSSVC Rule-Level Policy Change',
            'Filtering Platform Policy Change',
            'Other Policy Change Events')][string] $PolicyChange,
        [parameter(Mandatory, ParameterSetName = 'PrivilegeUse')][ValidateSet('Sensitive Privilege Use',
            'Non Sensitive Privilege Use',
            'Other Privilege Use Events')][string] $PrivilegeUse,
        [parameter(Mandatory, ParameterSetName = 'System')][ValidateSet('Security State Change',
            'Security System Extension',
            'System Integrity',
            'IPsec Driver',
            'Other System Events')][string] $System,
        [parameter(Mandatory)][validateSet('NoAuditing', 'NotConfigured', 'Success', 'Failure', 'SuccessAndFailure')][string] $Value,
        [switch] $UseAuditPol,
        [switch] $UseLocalSecurityPolicy,
        [switch] $Suppress)
    Add-Type -TypeDefinition @"
        using System;
 
        namespace AuditPolicies
        {
            public enum Events {
                NotConfigured = 0,
                Success = 1,
                Failure = 2,
                SuccessAndFailure = 3
            }
        }
"@

    $AuditValues = @{'NoAuditing' = 0
        'NotConfigured'           = 0
        'Success'                 = 1
        'Failure'                 = 2
        'SuccessAndFailure'       = 3
    }
    $OperatingSystem = Get-ComputerOperatingSystem -ComputerName $ComputerName
    $Version = [version]$OperatingSystem.OperatingSystemBuild
    if ($Version.Major -ge 10) {
        $AuditPoliciesByte = [ordered] @{AccountLogon = [ordered] @{'Credential Validation' = 122
                'Kerberos Service Ticket Operations'                                        = 124
                'Other Account Logon Events'                                                = 126
                'Kerberos Authentication Service'                                           = 128
            }
            AccountManagement                         = [ordered] @{'User Account Management' = 102
                'Computer Account Management'                         = 104
                'Security Group Management'                           = 106
                'Distribution Group Management'                       = 108
                'Application Group Management'                        = 110
                'Other Account Management Events'                     = 112
            }
            DetailedTracking                          = [ordered] @{'Process Creation' = 78
                'Process Termination'                         = 80
                'DPAPI Activity'                              = 82
                'RPC Events'                                  = 84
                'Plug and Play Events'                        = 86
                'Token Right Adjusted Events'                 = 88
            }
            DSAccess                                  = [ordered] @{'Directory Service Access' = 114
                'Directory Service Changes'                   = 116
                'Directory Service Replication'               = 118
                'Detailed Directory Service Replication'      = 120
            }
            LogonLogoff                               = [ordered] @{'Logon' = 22
                'Logoff'                      = 24
                'Account Lockout'             = 26
                'IPSec Main Mode'             = 28
                'Special Logon'               = 30
                'IPSec Quick Mode'            = 32
                'IPSec Extended Mode'         = 34
                'Other Logon/Logoff Events'   = 36
                'Network Policy Server'       = 38
                'User / Device Claims'        = 40
                'Group Membership'            = 42
            }
            ObjectAccess                              = [ordered] @{'File System' = 44
                'Registry'                           = 46
                'Kernel Object'                      = 48
                'SAM'                                = 50
                'Other Object Access Events'         = 52
                'Certification Services'             = 54
                'Application Generated'              = 56
                'Handle Manipulation'                = 58
                'File Share'                         = 60
                'Filtering Platform Packet Drop'     = 62
                'Filtering Platform Connection'      = 64
                'Detailed File Share'                = 66
                'Removable Storage'                  = 68
                'Central Policy Staging'             = 70
            }
            PolicyChange                              = [ordered] @{'Audit Policy Change' = 90
                'Authentication Policy Change'               = 92
                'Authorization Policy Change'                = 94
                'MPSSVC Rule-Level Policy Change'            = 96
                'Filtering Platform Policy Change'           = 98
                'Other Policy Change Events'                 = 100
            }
            PrivilegeUse                              = [ordered] @{'Sensitive Privilege Use' = 72
                'Non Sensitive Privilege Use'                    = 74
                'Other Privilege Use Events'                     = 76
            }
            System                                    = [ordered] @{'Security State Change' = 12
                'Security System Extension'              = 14
                'System Integrity'                       = 16
                'IPsec Driver'                           = 18
                'Other System Events'                    = 20
            }
        }
    } elseif ($Version.Major -eq 6 -and $Version.Minor -eq 3) {
        $AuditPoliciesByte = [ordered] @{AccountLogon = [ordered] @{'Credential Validation' = 118
                'Kerberos Service Ticket Operations'                                        = 120
                'Other Account Logon Events'                                                = 122
                'Kerberos Authentication Service'                                           = 124
            }
            AccountManagement                         = [ordered] @{'User Account Management' = 98
                'Computer Account Management'                         = 100
                'Security Group Management'                           = 102
                'Distribution Group Management'                       = 104
                'Application Group Management'                        = 106
                'Other Account Management Events'                     = 108
            }
            DetailedTracking                          = [ordered] @{'Process Creation' = 76
                'Process Termination'                         = 78
                'DPAPI Activity'                              = 80
                'RPC Events'                                  = 82
                'Plug and Play Events'                        = 84
            }
            DSAccess                                  = [ordered] @{'Directory Service Access' = 110
                'Directory Service Changes'                   = 112
                'Directory Service Replication'               = 114
                'Detailed Directory Service Replication'      = 116
            }
            LogonLogoff                               = [ordered] @{'Logon' = 22
                'Logoff'                      = 24
                'Account Lockout'             = 26
                'IPSec Main Mode'             = 28
                'Special Logon'               = 30
                'IPSec Quick Mode'            = 32
                'IPSec Extended Mode'         = 34
                'Other Logon/Logoff Events'   = 36
                'Network Policy Server'       = 38
                'User / Device Claims'        = 40
            }
            ObjectAccess                              = [ordered] @{'File System' = 42
                'Registry'                           = 44
                'Kernel Object'                      = 46
                'SAM'                                = 48
                'Other Object Access Events'         = 50
                'Certification Services'             = 52
                'Application Generated'              = 54
                'Handle Manipulation'                = 56
                'File Share'                         = 58
                'Filtering Platform Packet Drop'     = 60
                'Filtering Platform Connection'      = 62
                'Detailed File Share'                = 64
                'Removable Storage'                  = 66
                'Central Policy Staging'             = 68
            }
            PolicyChange                              = [ordered] @{'Audit Policy Change' = 86
                'Authentication Policy Change'               = 88
                'Authorization Policy Change'                = 90
                'MPSSVC Rule-Level Policy Change'            = 92
                'Filtering Platform Policy Change'           = 94
                'Other Policy Change Events'                 = 96
            }
            PrivilegeUse                              = [ordered] @{'Sensitive Privilege Use' = 70
                'Non Sensitive Privilege Use'                    = 72
                'Other Privilege Use Events'                     = 74
            }
            System                                    = [ordered] @{'Security State Change' = 12
                'Security System Extension'              = 14
                'System Integrity'                       = 16
                'IPsec Driver'                           = 18
                'Other System Events'                    = 20
            }
        }
    } else {
        $AuditPoliciesByte = [ordered] @{AccountLogon = [ordered] @{'Credential Validation' = 110
                'Kerberos Service Ticket Operations'                                        = 112
                'Other Account Logon Events'                                                = 114
                'Kerberos Authentication Service'                                           = 116
            }
            AccountManagement                         = [ordered] @{'User Account Management' = 90
                'Computer Account Management'                         = 92
                'Security Group Management'                           = 94
                'Distribution Group Management'                       = 96
                'Application Group Management'                        = 98
                'Other Account Management Events'                     = 100
            }
            DetailedTracking                          = [ordered] @{'Process Creation' = 70
                'Process Termination'                         = 72
                'DPAPI Activity'                              = 74
                'RPC Events'                                  = 76
            }
            DSAccess                                  = [ordered] @{'Directory Service Access' = 102
                'Directory Service Changes'                   = 104
                'Directory Service Replication'               = 106
                'Detailed Directory Service Replication'      = 108
            }
            LogonLogoff                               = [ordered] @{'Logon' = 22
                'Logoff'                      = 24
                'Account Lockout'             = 26
                'IPSec Main Mode'             = 28
                'Special Logon'               = 30
                'IPSec Quick Mode'            = 32
                'IPSec Extended Mode'         = 34
                'Other Logon/Logoff Events'   = 36
                'Network Policy Server'       = 38
            }
            ObjectAccess                              = [ordered] @{'File System' = 40
                'Registry'                           = 42
                'Kernel Object'                      = 44
                'SAM'                                = 46
                'Other Object Access Events'         = 48
                'Certification Services'             = 50
                'Application Generated'              = 52
                'Handle Manipulation'                = 54
                'File Share'                         = 56
                'Filtering Platform Packet Drop'     = 58
                'Filtering Platform Connection'      = 60
                'Detailed File Share'                = 62
            }
            PolicyChange                              = [ordered] @{'Audit Policy Change' = 78
                'Authentication Policy Change'               = 80
                'Authorization Policy Change'                = 82
                'MPSSVC Rule-Level Policy Change'            = 84
                'Filtering Platform Policy Change'           = 86
                'Other Policy Change Events'                 = 88
            }
            PrivilegeUse                              = [ordered] @{'Sensitive Privilege Use' = 64
                'Non Sensitive Privilege Use'                    = 66
                'Other Privilege Use Events'                     = 68
            }
            System                                    = [ordered] @{'Security State Change' = 12
                'Security System Extension'              = 14
                'System Integrity'                       = 16
                'IPsec Driver'                           = 18
                'Other System Events'                    = 20
            }
        }
    }
    $BoundParameters = $PSBoundParameters
    $CurrentParameterSet = $PsCmdlet.ParameterSetName
    $ChosenParameter = $BoundParameters.$CurrentParameterSet
    if ($UseAuditPol) { if ($Policy) { Set-SystemAuditPolicyAuditpol -Policies $Policy -Value $Value -WhatIf:$WhatIfPreference } elseif ($ChosenParameter) { Set-SystemAuditPolicyAuditpol -Policies $ChosenParameter -Value $Value -WhatIf:$WhatIfPreference } } elseif ($UseLocalSecurityPolicy) { if ($Policy) { Set-SystemAuditPolicyLocalSecurity -Policies $Policy -Value $Value -WhatIf:$WhatIfPreference } elseif ($ChosenParameter) { Set-SystemAuditPolicyLocalSecurity -Policies $ChosenParameter -Value $Value -WhatIf:$WhatIfPreference } } else {
        $IsSystem = [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem
        if (-not $IsSystem) {
            $SID = ConvertFrom-SID -SID "S-1-5-32-544"
            Set-SystemAuditPolicyPermissions -Identity $SID.Name -Permissions FullControl -WhatIf:$false -ComputerName $ComputerName
        }
        $Audit = Get-PSRegistry -RegistryPath "HKEY_LOCAL_MACHINE\SECURITY\Policy\PolAdtEv" -Key "" -ComputerName $ComputerName
        if ($Audit.PSConnection -eq $true -and $Audit.PSError -eq $false) {} else {
            if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $($Audit.PSErrorMessage) } else { Write-Warning -Message "Set-SystemAuditPolicy - Audit policies couldn't be read: $($Audit.PSErrorMessage)" }
            return
        }
        if ($CurrentParameterSet) {
            if ($CurrentParameterSet -eq 'AllPolicies') {
                foreach ($Key in $AuditPoliciesByte.Keys) {
                    if ($AuditPoliciesByte[$Key][$Policy]) {
                        $ByteNumber = $AuditPoliciesByte[$Key][$Policy]
                        $CurrentParameterSet = $Key
                        $ChosenParameter = $Policy
                        break
                    }
                }
            } else { $ByteNumber = $AuditPoliciesByte[$CurrentParameterSet][$ChosenParameter] }
            $ExpectedValue = $AuditValues[$Value]
            $ExpectedTranslatedValue = [AuditPolicies.Events] $ExpectedValue
            if (-not $ByteNumber) {
                if (-not $Suppress) {
                    if ($CurrentParameterSet -eq 'AllPolicies') { $ChosenParameter = $Policy } else { $ChosenParameter = $ChosenParameter }
                    return [PSCustomObject] @{'Policy' = $ChosenParameter
                        'Value'                        = $ExpectedTranslatedValue
                        'Result'                       = 'Failed'
                        'Error'                        = "Policy '$ChosenParameter' doesn't exist on this system version system. Please use a valid policy name."
                    }
                }
                return
            }
            $CurrentValue = $Audit.PSValue[$ByteNumber]
            $CurrentTranslatedValue = [AuditPolicies.Events] $CurrentValue
            Write-Verbose -Message "Set-SystemAuditPolicy - Current value for $CurrentParameterSet\$ChosenParameter is $CurrentTranslatedValue ($CurrentValue) to be replaced with $ExpectedTranslatedValue ($ExpectedValue)"
            if ($CurrentTranslatedValue -ne $ExpectedTranslatedValue) {
                $ValueToSet = $Audit.PSValue
                $ValueToSet[$ByteNumber] = $ExpectedValue
                if ($PSCmdlet.ShouldProcess("SubCategory $Policy", "Setting $Value on $Policy")) {
                    $AuditOutput = Set-PSRegistry -RegistryPath "HKEY_LOCAL_MACHINE\SECURITY\Policy\PolAdtEv" -Key "" -ComputerName $ComputerName -Type None -Value $ValueToSet -WhatIf:$WhatIfPreference
                    if ($AuditOutput.PSConnection -eq $true -and $AuditOutput.PSError -eq $false) {
                        $Result = 'Success'
                        $Message = ''
                    } else {
                        if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $($AuditOutput.PSErrorMessage) } else { Write-Warning -Message "Set-SystemAuditPolicy - Audit policies couldn't be set because: $($AuditOutput.PSErrorMessage)" }
                        $Result = 'Failed'
                        $Message = $($AuditOutput.PSErrorMessage)
                    }
                } else {
                    $Result = 'WhatIf'
                    $Message = 'WhatIf in use.'
                }
            } else {
                $Result = 'Not required'
                Write-Verbose -Message "Set-SystemAuditPolicy - Current value for $CurrentParameterSet\$ChosenParameter ($ByteNumber) is $CurrentTranslatedValue ($CurrentValue) - nothing to do."
            }
        }
        if (-not $IsSystem) {
            $SID = ConvertFrom-SID -SID "S-1-5-32-544"
            Remove-SystemAuditPolicyPermissions -Identity $SID.Name -Permissions FullControl -WhatIf:$false -ComputerName $ComputerName
        }
        if (-not $Suppress) {
            [PSCustomObject] @{'Policy' = $ChosenParameter
                'Value'                 = $ExpectedTranslatedValue
                'Result'                = $Result
                'Error'                 = $Message
            }
        }
    }
}
function Set-SystemAuditPolicyPermissions {
    <#
    .SYNOPSIS
    This function will set the audit policy permissions for the specified user or group to FullControl.
 
    .DESCRIPTION
    This function will set the audit policy permissions for the specified user or group to FullControl.
    By default only SYSTEM account has any permission.
    This command can be used to add audit policy permissions for the specified user or group.
 
    .PARAMETER Identity
    The identity of the user or group to set the audit policy permissions for
 
    .PARAMETER Permissions
    The permissions to set for the specified user or group. By default FullControl.
 
    .EXAMPLE
    Set-SystemAuditPolicyPermissions -Identity "przemyslaw.klys" -Verbose -WhatIf
 
    .NOTES
    General notes
    #>

    [cmdletBinding(SupportsShouldProcess)]
    param([parameter(Mandatory)][string] $Identity,
        [System.Security.AccessControl.RegistryRights] $Permissions = [System.Security.AccessControl.RegistryRights]::FullControl,
        [string] $ComputerName)
    try {
        if ($ComputerName) {
            $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LOCAL', $ComputerName, 0)
            $RegistryKeyControl = $BaseHive.OpenSubKey('SECURITY',
                [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
                [System.Security.AccessControl.RegistryRights]::ChangePermissions)
        } else {
            $RegistryKeyControl = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SECURITY',
                [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
                [System.Security.AccessControl.RegistryRights]::ChangePermissions)
        }
    } catch {
        if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Set-SystemAuditPolicyPermissions - Opening registry failed $($_.Exception.Message)" }
        return
    }
    $AccessControlList = $RegistryKeyControl.GetAccessControl()
    $Account = [System.Security.Principal.NTAccount] $Identity
    $InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit'
    $PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None
    $AccessType = [System.Security.AccessControl.AccessControlType]::Allow
    $AccessRule = [System.Security.AccessControl.RegistryAccessRule]::new($Account,
        $Permissions,
        $InheritanceFlag,
        $PropagationFlag,
        $AccessType)
    if ($PSCmdlet.ShouldProcess("Registry HKLM\Security", "Adding 'FullControl' access to $Identity for SECURITY subkey")) {
        try { $AccessControlList.AddAccessRule($AccessRule) } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Set-SystemAuditPolicyPermissions - Adding access rule failed $($_.Exception.Message)" } }
        $RegistryKeyControl.SetAccessControl($AccessControlList)
    }
}
Export-ModuleMember -Function @('Backup-SystemAuditPolicy', 'Clear-SystemAuditPolicy', 'Get-SystemAuditPolicy', 'Get-SystemAuditPolicyFromFile', 'Remove-SystemAuditPolicyPermissions', 'Restore-SystemAuditPolicy', 'Set-SystemAuditPolicy', 'Set-SystemAuditPolicyPermissions') -Alias @()
# SIG # Begin signature block
# MIInaAYJKoZIhvcNAQcCoIInWTCCJ1UCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBmGxh9sINJ/Crz
# qdJn8YTK/J8K91kZpfgnfPGLOtsfe6CCIWEwggO3MIICn6ADAgECAhAM5+DlF9hG
# /o/lYPwb8DA5MA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBa
# Fw0zMTExMTAwMDAwMDBaMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lD
# ZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
# AQoCggEBAK0OFc7kQ4BcsYfzt2D5cRKlrtwmlIiq9M71IDkoWGAM+IDaqRWVMmE8
# tbEohIqK3J8KDIMXeo+QrIrneVNcMYQq9g+YMjZ2zN7dPKii72r7IfJSYd+fINcf
# 4rHZ/hhk0hJbX/lYGDW8R82hNvlrf9SwOD7BG8OMM9nYLxj+KA+zp4PWw25EwGE1
# lhb+WZyLdm3X8aJLDSv/C3LanmDQjpA1xnhVhyChz+VtCshJfDGYM2wi6YfQMlqi
# uhOCEe05F52ZOnKh5vqk2dUXMXWuhX0irj8BRob2KHnIsdrkVxfEfhwOsLSSplaz
# vbKX7aqn8LfFqD+VFtD/oZbrCF8Yd08CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGG
# MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEXroq/0ksuCMS1Ri6enIZ3zbcgP
# MB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBBQUA
# A4IBAQCiDrzf4u3w43JzemSUv/dyZtgy5EJ1Yq6H6/LV2d5Ws5/MzhQouQ2XYFwS
# TFjk0z2DSUVYlzVpGqhH6lbGeasS2GeBhN9/CTyU5rgmLCC9PbMoifdf/yLil4Qf
# 6WXvh+DfwWdJs13rsgkq6ybteL59PyvztyY1bV+JAbZJW58BBZurPSXBzLZ/wvFv
# hsb6ZGjrgS2U60K3+owe3WLxvlBnt2y98/Efaww2BxZ/N3ypW2168RJGYIPXJwS+
# S86XvsNnKmgR34DnDDNmvxMNFG7zfx9jEB76jRslbWyPpbdhAbHSoyahEHGdreLD
# +cOZUbcrBwjOLuZQsqf6CkUvovDyMIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1
# b5VQCDANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln
# aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtE
# aWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgx
# MDIyMTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT
# SEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEF
# AAOCAQ8AMIIBCgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLX
# cep2nQUut4/6kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSR
# I5aQd4L5oYQjZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXi
# TWAYvqrEsq5wMWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5
# Ng2Q7+S1TqSp6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8
# vYWxYoNzQYIH5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYD
# VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYB
# BQUHAwMweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k
# aWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4
# oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJv
# b3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy
# dEFzc3VyZWRJRFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCow
# KAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZI
# AYb9bAMwHQYDVR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaA
# FEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPz
# ItEVyCx8JSl2qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRu
# pY5a4l4kgU4QpO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKN
# JK4kxscnKqEpKBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmif
# z0DLQESlE/DmZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN
# 3fYBIM6ZMWM9CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKy
# ZqHnGKSaZFHvMIIFPTCCBCWgAwIBAgIQBNXcH0jqydhSALrNmpsqpzANBgkqhkiG
# 9w0BAQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw
# FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEy
# IEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTIwMDYyNjAwMDAwMFoXDTIz
# MDcwNzEyMDAwMFowejELMAkGA1UEBhMCUEwxEjAQBgNVBAgMCcWabMSFc2tpZTER
# MA8GA1UEBxMIS2F0b3dpY2UxITAfBgNVBAoMGFByemVteXPFgmF3IEvFgnlzIEVW
# T1RFQzEhMB8GA1UEAwwYUHJ6ZW15c8WCYXcgS8WCeXMgRVZPVEVDMIIBIjANBgkq
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7KB3iyBrhkLUbbFe9qxhKKPBYqDBqln
# r3AtpZplkiVjpi9dMZCchSeT5ODsShPuZCIxJp5I86uf8ibo3vi2S9F9AlfFjVye
# 3dTz/9TmCuGH8JQt13ozf9niHecwKrstDVhVprgxi5v0XxY51c7zgMA2g1Ub+3ti
# i0vi/OpmKXdL2keNqJ2neQ5cYly/GsI8CREUEq9SZijbdA8VrRF3SoDdsWGf3tZZ
# zO6nWn3TLYKQ5/bw5U445u/V80QSoykszHRivTj+H4s8ABiforhi0i76beA6Ea41
# zcH4zJuAp48B4UhjgRDNuq8IzLWK4dlvqrqCBHKqsnrF6BmBrv+BXQIDAQABo4IB
# xTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYE
# FBixNSfoHFAgJk4JkDQLFLRNlJRmMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK
# BggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2Vy
# dC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQu
# ZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3
# BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu
# Y29tL0NQUzAIBgZngQwBBAEwgYQGCCsGAQUFBwEBBHgwdjAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME4GCCsGAQUFBzAChkJodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNzdXJlZElEQ29kZVNpZ25p
# bmdDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAmr1sz4ls
# LARi4wG1eg0B8fVJFowtect7SnJUrp6XRnUG0/GI1wXiLIeow1UPiI6uDMsRXPHU
# F/+xjJw8SfIbwava2eXu7UoZKNh6dfgshcJmo0QNAJ5PIyy02/3fXjbUREHINrTC
# vPVbPmV6kx4Kpd7KJrCo7ED18H/XTqWJHXa8va3MYLrbJetXpaEPpb6zk+l8Rj9y
# G4jBVRhenUBUUj3CLaWDSBpOA/+sx8/XB9W9opYfYGb+1TmbCkhUg7TB3gD6o6ES
# Jre+fcnZnPVAPESmstwsT17caZ0bn7zETKlNHbc1q+Em9kyBjaQRcEQoQQNpezQu
# g9ufqExx6lHYDjCCBbEwggSZoAMCAQICEAEkCvseOAuKFvFLcZ3008AwDQYJKoZI
# hvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
# MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNz
# dXJlZCBJRCBSb290IENBMB4XDTIyMDYwOTAwMDAwMFoXDTMxMTEwOTIzNTk1OVow
# YjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ
# d3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290
# IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjww
# IjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J5
# 8soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMH
# hOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6
# Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQ
# ecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4b
# A3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9
# WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCU
# tNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvo
# ZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/J
# vNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCP
# orF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCAV4wggFaMA8GA1UdEwEB/wQFMAMB
# Af8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXr
# oq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggr
# BgEFBQcDCDB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw
# LmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNl
# cnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqg
# OKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS
# b290Q0EuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkq
# hkiG9w0BAQwFAAOCAQEAmhYCpQHvgfsNtFiyeK2oIxnZczfaYJ5R18v4L0C5ox98
# QE4zPpA854kBdYXoYnsdVuBxut5exje8eVxiAE34SXpRTQYy88XSAConIOqJLhU5
# 4Cw++HV8LIJBYTUPI9DtNZXSiJUpQ8vgplgQfFOOn0XJIDcUwO0Zun53OdJUlsem
# Ed80M/Z1UkJLHJ2NltWVbEcSFCRfJkH6Gka93rDlkUcDrBgIy8vbZol/K5xlv743
# Tr4t851Kw8zMR17IlZWt0cu7KgYg+T9y6jbrRXKSeil7FAM8+03WSHF6EBGKCHTN
# bBsEXNKKlQN2UVBT1i73SkbDrhAscUywh7YnN0RgRDCCBq4wggSWoAMCAQICEAc2
# N7ckVHzYR6z9KGYqXlswDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTAT
# BgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEh
# MB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTIyMDMyMzAwMDAw
# MFoXDTM3MDMyMjIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD
# ZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYg
# U0hBMjU2IFRpbWVTdGFtcGluZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBAMaGNQZJs8E9cklRVcclA8TykTepl1Gh1tKD0Z5Mom2gsMyD+Vr2EaFE
# FUJfpIjzaPp985yJC3+dH54PMx9QEwsmc5Zt+FeoAn39Q7SE2hHxc7Gz7iuAhIoi
# GN/r2j3EF3+rGSs+QtxnjupRPfDWVtTnKC3r07G1decfBmWNlCnT2exp39mQh0YA
# e9tEQYncfGpXevA3eZ9drMvohGS0UvJ2R/dhgxndX7RUCyFobjchu0CsX7LeSn3O
# 9TkSZ+8OpWNs5KbFHc02DVzV5huowWR0QKfAcsW6Th+xtVhNef7Xj3OTrCw54qVI
# 1vCwMROpVymWJy71h6aPTnYVVSZwmCZ/oBpHIEPjQ2OAe3VuJyWQmDo4EbP29p7m
# O1vsgd4iFNmCKseSv6De4z6ic/rnH1pslPJSlRErWHRAKKtzQ87fSqEcazjFKfPK
# qpZzQmiftkaznTqj1QPgv/CiPMpC3BhIfxQ0z9JMq++bPf4OuGQq+nUoJEHtQr8F
# nGZJUlD0UfM2SU2LINIsVzV5K6jzRWC8I41Y99xh3pP+OcD5sjClTNfpmEpYPtMD
# iP6zj9NeS3YSUZPJjAw7W4oiqMEmCPkUEBIDfV8ju2TjY+Cm4T72wnSyPx4Jduyr
# XUZ14mCjWAkBKAAOhFTuzuldyF4wEr1GnrXTdrnSDmuZDNIztM2xAgMBAAGjggFd
# MIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS6FtltTYUvcyl2mi91
# jGogj57IbzAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8B
# Af8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQG
# CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKG
# NWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290
# RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQC
# MAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAfVmOwJO2b5ipRCIBfmbW
# 2CFC4bAYLhBNE88wU86/GPvHUF3iSyn7cIoNqilp/GnBzx0H6T5gyNgL5Vxb122H
# +oQgJTQxZ822EpZvxFBMYh0MCIKoFr2pVs8Vc40BIiXOlWk/R3f7cnQU1/+rT4os
# equFzUNf7WC2qk+RZp4snuCKrOX9jLxkJodskr2dfNBwCnzvqLx1T7pa96kQsl3p
# /yhUifDVinF2ZdrM8HKjI/rAJ4JErpknG6skHibBt94q6/aesXmZgaNWhqsKRcnf
# xI2g55j7+6adcq/Ex8HBanHZxhOACcS2n82HhyS7T6NJuXdmkfFynOlLAlKnN36T
# U6w7HQhJD5TNOXrd/yVjmScsPT9rp/Fmw0HNT7ZAmyEhQNC3EyTN3B14OuSereU0
# cZLXJmvkOHOrpgFPvT87eK1MrfvElXvtCl8zOYdBeHo46Zzh3SP9HSjTx/no8Zhf
# +yvYfvJGnXUsHicsJttvFXseGYs2uJPU5vIXmVnKcPA3v5gA3yAWTyf7YGcWoWa6
# 3VXAOimGsJigK+2VQbc61RWYMbRiCQ8KvYHZE/6/pNHzV9m8BPqC3jLfBInwAM1d
# wvnQI38AC+R2AibZ8GV2QqYphwlHK+Z/GqSFD/yYlvZVVCsfgPrA8g4r5db7qS9E
# FUrnEw4d2zc4GqEr9u3WfPwwggbGMIIErqADAgECAhAKekqInsmZQpAGYzhNhped
# MA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy
# dCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNI
# QTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjIwMzI5MDAwMDAwWhcNMzMwMzE0MjM1
# OTU5WjBMMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJDAi
# BgNVBAMTG0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIyIC0gMjCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBALkqliOmXLxf1knwFYIY9DPuzFxs4+AlLtIx5DxA
# rvurxON4XX5cNur1JY1Do4HrOGP5PIhp3jzSMFENMQe6Rm7po0tI6IlBfw2y1vmE
# 8Zg+C78KhBJxbKFiJgHTzsNs/aw7ftwqHKm9MMYW2Nq867Lxg9GfzQnFuUFqRUIj
# QVr4YNNlLD5+Xr2Wp/D8sfT0KM9CeR87x5MHaGjlRDRSXw9Q3tRZLER0wDJHGVvi
# mC6P0Mo//8ZnzzyTlU6E6XYYmJkRFMUrDKAz200kheiClOEvA+5/hQLJhuHVGBS3
# BEXz4Di9or16cZjsFef9LuzSmwCKrB2NO4Bo/tBZmCbO4O2ufyguwp7gC0vICNEy
# u4P6IzzZ/9KMu/dDI9/nw1oFYn5wLOUrsj1j6siugSBrQ4nIfl+wGt0ZvZ90QQqv
# uY4J03ShL7BUdsGQT5TshmH/2xEvkgMwzjC3iw9dRLNDHSNQzZHXL537/M2xwafE
# DsTvQD4ZOgLUMalpoEn5deGb6GjkagyP6+SxIXuGZ1h+fx/oK+QUshbWgaHK2jCQ
# a+5vdcCwNiayCDv/vb5/bBMY38ZtpHlJrYt/YYcFaPfUcONCleieu5tLsuK2QT3n
# r6caKMmtYbCgQRgZTu1Hm2GV7T4LYVrqPnqYklHNP8lE54CLKUJy93my3YTqJ+7+
# fXprAgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAW
# BgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglg
# hkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0O
# BBYEFI1kt4kh/lZYRIRhp+pvHDaP3a8NMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6
# Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEy
# NTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUF
# BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6
# Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZT
# SEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAA0tI3Sm
# 0fX46kuZPwHk9gzkrxad2bOMl4IpnENvAS2rOLVwEb+EGYs/XeWGT76TOt4qOVo5
# TtiEWaW8G5iq6Gzv0UhpGThbz4k5HXBw2U7fIyJs1d/2WcuhwupMdsqh3KErlrib
# Vakaa33R9QIJT4LWpXOIxJiA3+5JlbezzMWn7g7h7x44ip/vEckxSli23zh8y/pc
# 9+RTv24KfH7X3pjVKWWJD6KcwGX0ASJlx+pedKZbNZJQfPQXpodkTz5GiRZjIGvL
# 8nvQNeNKcEiptucdYL0EIhUlcAZyqUQ7aUcR0+7px6A+TxC5MDbk86ppCaiLfmSi
# ZZQR+24y8fW7OK3NwJMR1TJ4Sks3KkzzXNy2hcC7cDBVeNaY/lRtf3GpSBp43UZ3
# Lht6wDOK+EoojBKoc88t+dMj8p4Z4A2UKKDr2xpRoJWCjihrpM6ddt6pc6pIallD
# rl/q+A8GQp3fBmiW/iqgdFtjZt5rLLh4qk1wbfAs8QcVfjW05rUMopml1xVrNQ6F
# 1uAszOAMJLh8UgsemXzvyMjFjFhpr6s94c/MfRWuFL+Kcd/Kl7HYR+ocheBFThIc
# FClYzG/Tf8u+wQ5KbyCcrtlzMlkI5y2SoRoR/jKYpl0rl+CL05zMbbUNrkdjOEcX
# W28T2moQbh9Jt0RbtAgKh1pZBHYRoad3AhMcMYIFXTCCBVkCAQEwgYYwcjELMAkG
# A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp
# Z2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENv
# ZGUgU2lnbmluZyBDQQIQBNXcH0jqydhSALrNmpsqpzANBglghkgBZQMEAgEFAKCB
# hDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE
# AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJ
# BDEiBCAvWo+vxV40xHk+JZKVHH7CtZJM5i4Hh1csie3EMr0VvzANBgkqhkiG9w0B
# AQEFAASCAQB2WkYva5KXh1uPerF0fmDHtXEsbzLi9XFgRQCjYO2T80ImIGoKej+1
# J/9wn87XIBXAUZ5Kd3nFCjthmZ4gSE6M8B6gL3HasHES8Y/INifvkEs/xS3JO07G
# tU7xGjza0M1qgZTscBnodYhskTjsXRdGc2CdTMzmadKjokSd4ybolq1jYn8k2y3z
# zXwwAbYBv8bTSfIBVLMEYId7kaJXpMrrarjSz6ZbA3hYbRlxjPXHNxnJ4CJSGAf1
# Nos5qwF0uyD8GzGq3J74klc9sIjBq0wmYyKi4MC31gh6xDKjJZee8AdotMcHhmO/
# tiAJENRUbm6UHbb1wkeemJx3RiadXm+joYIDIDCCAxwGCSqGSIb3DQEJBjGCAw0w
# ggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu
# MTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRp
# bWVTdGFtcGluZyBDQQIQCnpKiJ7JmUKQBmM4TYaXnTANBglghkgBZQMEAgEFAKBp
# MBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIyMDcx
# ODIwMTM0OFowLwYJKoZIhvcNAQkEMSIEICGmiQf2p+Sjtk2cjDGE2n7lh6YW0Q/0
# hDBjzTC1GMDGMA0GCSqGSIb3DQEBAQUABIICAGHR+vhGwTo1dCgrFDsMHeudPdp1
# pXOMgQYHJqvg5plOO7sLuwLnyLOIGGCh4KpiTC6co6Evqe7W2+LpRXTqX6oS/+xb
# nLr8u2TAHAkBfjK9Fd6IzWXozQbEcMwLPV4wX7p07GLtTBVmUohbFc5qZJzV1JfJ
# l97wPAc32YTwIoF0f+fwpPE/bypHo4lM8/fcRAOZ1dET9xwg2HH7gtBqbQTAShk8
# Y2IIqDUZPkOYRun9Qch77NdZxvMSG6H0ehAURc6JV/ikYWrGlgaenBlHmMmykjYw
# Y+SCx/NOIY4J5v7J/c6wfFbrXMaetiH7PPRD9Elo+RpxO7cTapk8NauEXB8a2OrU
# zHP78hMtn1QwOv8oSNnuSrKkEQ4H/RthOQcAJKMoY28GeJqow8Upk9YKdKxjoRMQ
# MCvOSniIhbqTNHkmCp8ZY+APgFh0m4moS2CrQMDjOuu6fvIpKwYwHUYvu5vsbQ9g
# EAYuJTuRKMpNen4MTpkfsaiLMwGuiSdTzZJ0tsO30g7KOoOoUVnFGAyELT4wvp88
# ecALN2Kdxi7uiREs8g+yGdvC/VCWitq7O5qdeVXo4rzKe9uya0nXMVQu9bnM54Tf
# tqLaz9b+Zx1Q2JRoMhl24y/Oo/rYf46oIiGPPlmYSlM/nULW0xijj52oneRq1AsY
# 8AlRkHFpBximvEDl
# SIG # End signature block