HelperFunctions.psm1
$AuditHash = @{ "0cce9210-69ae-11d9-bed3-505054503030" = "Audit_System_SecurityStateChange"; "0cce9211-69ae-11d9-bed3-505054503030" = "Audit_System_SecuritySubsystemExtension"; "0cce9212-69ae-11d9-bed3-505054503030" = "Audit_System_Integrity"; "0cce9213-69ae-11d9-bed3-505054503030" = "Audit_System_IPSecDriverEvents"; "0cce9214-69ae-11d9-bed3-505054503030" = "Audit_System_Others"; "0cce9215-69ae-11d9-bed3-505054503030" = "Audit_Logon_Logon"; "0cce9216-69ae-11d9-bed3-505054503030" = "Audit_Logon_Logoff"; "0cce9217-69ae-11d9-bed3-505054503030" = "Audit_Logon_AccountLockout"; "0cce9218-69ae-11d9-bed3-505054503030" = "Audit_Logon_IPSecMainMode"; "0cce9219-69ae-11d9-bed3-505054503030" = "Audit_Logon_IPSecQuickMode"; "0cce921a-69ae-11d9-bed3-505054503030" = "Audit_Logon_IPSecUserMode"; "0cce921b-69ae-11d9-bed3-505054503030" = "Audit_Logon_SpecialLogon"; "0cce921c-69ae-11d9-bed3-505054503030" = "Audit_Logon_Others"; "0cce921d-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_FileSystem"; "0cce921e-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_Registry"; "0cce921f-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_Kernel"; "0cce9220-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_Sam"; "0cce9221-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_CertificationServices"; "0cce9222-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_ApplicationGenerated"; "0cce9223-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_Handle"; "0cce9224-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_Share"; "0cce9225-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_FirewallPacketDrops"; "0cce9226-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_FirewallConnection"; "0cce9227-69ae-11d9-bed3-505054503030" = "Audit_ObjectAccess_Other"; "0cce9228-69ae-11d9-bed3-505054503030" = "Audit_PrivilegeUse_Sensitive"; "0cce9229-69ae-11d9-bed3-505054503030" = "Audit_PrivilegeUse_NonSensitive"; "0cce922a-69ae-11d9-bed3-505054503030" = "Audit_PrivilegeUse_Others"; "0cce922b-69ae-11d9-bed3-505054503030" = "Audit_DetailedTracking_ProcessCreation"; "0cce922c-69ae-11d9-bed3-505054503030" = "Audit_DetailedTracking_ProcessTermination"; "0cce922d-69ae-11d9-bed3-505054503030" = "Audit_DetailedTracking_DpapiActivity"; "0cce922e-69ae-11d9-bed3-505054503030" = "Audit_DetailedTracking_RpcCall"; "0cce922f-69ae-11d9-bed3-505054503030" = "Audit_PolicyChange_AuditPolicy"; "0cce9230-69ae-11d9-bed3-505054503030" = "Audit_PolicyChange_AuthenticationPolicy"; "0cce9231-69ae-11d9-bed3-505054503030" = "Audit_PolicyChange_AuthorizationPolicy"; "0cce9232-69ae-11d9-bed3-505054503030" = "Audit_PolicyChange_MpsscvRulePolicy"; "0cce9233-69ae-11d9-bed3-505054503030" = "Audit_PolicyChange_WfpIPSecPolicy"; "0cce9234-69ae-11d9-bed3-505054503030" = "Audit_PolicyChange_Others"; "0cce9235-69ae-11d9-bed3-505054503030" = "Audit_AccountManagement_UserAccount"; "0cce9236-69ae-11d9-bed3-505054503030" = "Audit_AccountManagement_ComputerAccount"; "0cce9237-69ae-11d9-bed3-505054503030" = "Audit_AccountManagement_SecurityGroup"; "0cce9238-69ae-11d9-bed3-505054503030" = "Audit_AccountManagement_DistributionGroup"; "0cce9239-69ae-11d9-bed3-505054503030" = "Audit_AccountManagement_ApplicationGroup"; "0cce923a-69ae-11d9-bed3-505054503030" = "Audit_AccountManagement_Others"; "0cce923b-69ae-11d9-bed3-505054503030" = "Audit_DSAccess_DSAccess"; "0cce923c-69ae-11d9-bed3-505054503030" = "Audit_DsAccess_AdAuditChanges"; "0cce923d-69ae-11d9-bed3-505054503030" = "Audit_Ds_Replication"; "0CCE9244-69AE-11D9-BED3-505054503030" = "Detailed File Share"; "0cce923e-69ae-11d9-bed3-505054503030" = "Audit_Ds_DetailedReplication"; "0cce923f-69ae-11d9-bed3-505054503030" = "Audit_AccountLogon_CredentialValidation"; "0cce9240-69ae-11d9-bed3-505054503030" = "Audit_AccountLogon_Kerberos"; "0cce9241-69ae-11d9-bed3-505054503030" = "Audit_AccountLogon_Others"; "0cce9242-69ae-11d9-bed3-505054503030" = "Audit_AccountLogon_KerbCredentialValidation"; "0cce9243-69ae-11d9-bed3-505054503030" = "Audit_Logon_NPS"; } $AuditCategoryHash = @{ "0CCE9211-69AE-11D9-BED3-505054503030" = "Security System Extension"; "0CCE9212-69AE-11D9-BED3-505054503030" = "System Integrity"; "0CCE9213-69AE-11D9-BED3-505054503030" = "IPsec Driver"; "0CCE9214-69AE-11D9-BED3-505054503030" = "Other System Events"; "0CCE9210-69AE-11D9-BED3-505054503030" = "Security State Change"; "0CCE9215-69AE-11D9-BED3-505054503030" = "Logon"; "0CCE9216-69AE-11D9-BED3-505054503030" = "Logoff"; "0CCE9217-69AE-11D9-BED3-505054503030" = "Account Lockout" "0CCE9218-69AE-11D9-BED3-505054503030" = "IPsec Main Mode"; "0CCE9219-69AE-11D9-BED3-505054503030" = "IPsec Quick Mode"; "0CCE921A-69AE-11D9-BED3-505054503030" = "IPsec Extended Mode"; "0CCE921B-69AE-11D9-BED3-505054503030" = "Special Logon"; "0CCE921C-69AE-11D9-BED3-505054503030" = "Other Logon/Logoff Events"; "0CCE9243-69AE-11D9-BED3-505054503030" = "Network Policy Server"; "0cce9247-69ae-11d9-bed3-505054503030" = "User / Device Claims"; "0cce9249-69ae-11d9-bed3-505054503030" = "Group Membership"; "0CCE921D-69AE-11D9-BED3-505054503030" = "File System"; "0CCE921E-69AE-11D9-BED3-505054503030" = "Registry"; "0CCE921F-69AE-11D9-BED3-505054503030" = "Kernel Object"; "0CCE9220-69AE-11D9-BED3-505054503030" = "SAM"; "0CCE9221-69AE-11D9-BED3-505054503030" = "Certification Services"; "0CCE9222-69AE-11D9-BED3-505054503030" = "Application Generated"; "0CCE9223-69AE-11D9-BED3-505054503030" = "Handle Manipulation"; "0CCE9224-69AE-11D9-BED3-505054503030" = "File Share"; "0CCE9225-69AE-11D9-BED3-505054503030" = "Filtering Platform Packet Drop"; "0CCE9226-69AE-11D9-BED3-505054503030" = "Filtering Platform Connection"; "0CCE9227-69AE-11D9-BED3-505054503030" = "Other Object Access Events"; "0CCE9244-69AE-11D9-BED3-505054503030" = "Detailed File Share"; "0CCE9245-69AE-11D9-BED3-505054503030" = "Removable Storage"; "0CCE9246-69AE-11D9-BED3-505054503030" = "Central Policy Staging"; "0CCE9229-69AE-11D9-BED3-505054503030" = "Non Sensitive Privilege Use"; "0CCE922A-69AE-11D9-BED3-505054503030" = "Other Privilege Use Events"; "0CCE9228-69AE-11D9-BED3-505054503030" = "Sensitive Privilege Use"; "0CCE922B-69AE-11D9-BED3-505054503030" = "Process Creation"; "0CCE922C-69AE-11D9-BED3-505054503030" = "Process Termination"; "0CCE922D-69AE-11D9-BED3-505054503030" = "DPAPI Activity"; "0CCE922E-69AE-11D9-BED3-505054503030" = "RPC Events"; "0cce9248-69ae-11d9-bed3-505054503030" = "Plug and Play Events"; "0CCE9230-69AE-11D9-BED3-505054503030" = "Authentication Policy Change"; "0CCE9231-69AE-11D9-BED3-505054503030" = "Authorization Policy Change"; "0CCE9232-69AE-11D9-BED3-505054503030" = "MPSSVC Rule-Level Policy Change"; "0CCE9233-69AE-11D9-BED3-505054503030" = "Filtering Platform Policy Change"; "0CCE9234-69AE-11D9-BED3-505054503030" = "Other Policy Change Events"; "0CCE922F-69AE-11D9-BED3-505054503030" = "Audit Policy Change"; "0CCE9235-69AE-11D9-BED3-505054503030" = "User Account Management"; "0CCE9236-69AE-11D9-BED3-505054503030" = "Computer Account Management"; "0CCE9237-69AE-11D9-BED3-505054503030" = "Security Group Management"; "0CCE9238-69AE-11D9-BED3-505054503030" = "Distribution Group Management"; "0CCE9239-69AE-11D9-BED3-505054503030" = "Application Group Management"; "0CCE923A-69AE-11D9-BED3-505054503030" = "Other Account Management Events"; "0CCE923C-69AE-11D9-BED3-505054503030" = "Directory Service Changes"; "0CCE923D-69AE-11D9-BED3-505054503030" = "Directory Service Replication"; "0CCE923E-69AE-11D9-BED3-505054503030" = "Detailed Directory Service Replication"; "0CCE923B-69AE-11D9-BED3-505054503030" = "Directory Service Access"; "0CCE9240-69AE-11D9-BED3-505054503030" = "Kerberos Service Ticket Operations"; "0CCE9241-69AE-11D9-BED3-505054503030" = "Other Account Logon Events"; "0CCE9242-69AE-11D9-BED3-505054503030" = "Kerberos Authentication Service"; "0CCE923F-69AE-11D9-BED3-505054503030" = "Credential Validation"; } $UserRightsHash = @{ "SeTrustedCredManAccessPrivilege" = "Access_Credential_Manager_as_a_trusted_caller" "SeNetworkLogonRight" = "Access_this_computer_from_the_network" "SeTcbPrivilege" = "Act_as_part_of_the_operating_system" "SeMachineAccountPrivilege" = "Add_workstations_to_domain" "SeIncreaseQuotaPrivilege" = "Adjust_memory_quotas_for_a_process" "SeInteractiveLogonRight" = "Allow_log_on_locally" "SeRemoteInteractiveLogonRight" = "Allow_log_on_through_Remote_Desktop_Services" "SeBackupPrivilege" = "Back_up_files_and_directories" "SeChangeNotifyPrivilege" = "Bypass_traverse_checking" "SeSystemtimePrivilege" = "Change_the_system_time" "SeTimeZonePrivilege" = "Change_the_time_zone" "SeCreatePagefilePrivilege" = "Create_a_pagefile" "SeCreateTokenPrivilege" = "Create_a_token_object" "SeCreateGlobalPrivilege" = "Create_global_objects" "SeCreatePermanentPrivilege" = "Create_permanent_shared_objects" "SeCreateSymbolicLinkPrivilege" = "Create_symbolic_links" "SeDebugPrivilege" = "Debug_programs" "SeDenyNetworkLogonRight" = "Deny_access_to_this_computer_from_the_network" "SeDenyBatchLogonRight" = "Deny_log_on_as_a_batch_job" "SeDenyServiceLogonRight" = "Deny_log_on_as_a_service" "SeDenyInteractiveLogonRight" = "Deny_log_on_locally" "SeDenyRemoteInteractiveLogonRight" = "Deny_log_on_through_Remote_Desktop_Services" "SeEnableDelegationPrivilege" = "Enable_computer_and_user_accounts_to_be_trusted_for_delegation" "SeRemoteShutdownPrivilege" = "Force_shutdown_from_a_remote_system" "SeAuditPrivilege" = "Generate_security_audits" "SeImpersonatePrivilege" = "Impersonate_a_client_after_authentication" "SeIncreaseWorkingSetPrivilege" = "Increase_a_process_working_set" "SeIncreaseBasePriorityPrivilege" = "Increase_scheduling_priority" "SeLoadDriverPrivilege" = "Load_and_unload_device_drivers" "SeLockMemoryPrivilege" = "Lock_pages_in_memory" "SeBatchLogonRight" = "Log_on_as_a_batch_job" "SeServiceLogonRight" = "Log_on_as_a_service" "SeSecurityPrivilege" = "Manage_auditing_and_security_log" "SeRelabelPrivilege" = "Modify_an_object_label" "SeSystemEnvironmentPrivilege" = "Modify_firmware_environment_values" "SeManageVolumePrivilege" = "Perform_volume_maintenance_tasks" "SeProfileSingleProcessPrivilege" = "Profile_single_process" "SeSystemProfilePrivilege" = "Profile_system_performance" "SeUndockPrivilege" = "Remove_computer_from_docking_station" "SeAssignPrimaryTokenPrivilege" = "Replace_a_process_level_token" "SeRestorePrivilege" = "Restore_files_and_directories" "SeShutdownPrivilege" = "Shut_down_the_system" "SeSyncAgentPrivilege" = "Synchronize_directory_service_data" "SeTakeOwnershipPrivilege" = "Take_ownership_of_files_or_other_objects" } $SecuritySettings = "MinimumPasswordAge","MaximumPasswordAge","MinimumPasswordLength","PasswordComplexity","PasswordHistorySize","LockoutBadCount","ForceLogoffWhenHourExpire","NewAdministratorName","NewGuestName","ClearTextPassword","LSAAnonymousNameLookup","EnableAdminAccount","EnableGuestAccount","ResetLockoutCount","LockoutDuration","MaxServiceAge","MaxTicketAge","MaxRenewAge","MaxClockSkew","TicketValidateClient" # Create a variable so we can detect conflicts in the Configuration. New-Variable -Name GlobalConflictEngine -Value @{} -Option AllScope -Scope Script -Force $GlobalConflictEngine = @{} # Create a variable to track every resource processed for Summary Data. New-Variable -Name ProcessingHistory -Value @{} -Option AllScope -Scope Script -Force $ProcessingHistory = @{} # This is the function that makes it all go. It has a variety of parameter sets which can be tricky to use. # Each of the Switches tell the function what type of Code block it is creating. # The additional parameters to the set are what determine the contents of the block. # This Function takes the input and properly formats it with Tabs and Newlines so it looks properly formatted. # It also has a built in Conflict detection engine. # If it detects that a Resource with the Same REQUIRED values was already processed it will COMMENT OUT subsequent resource blocks with the same values. # The Function also has logic to arbitrarily comment out a resource block if necessary (like disabled resources). # The function also provides functionality to comment Code Blocks if comments are available. Function Write-DSCString { [CmdletBinding()] [OutputType([String])] param ( # Configuration Block [Parameter(Mandatory=$true, ParameterSetName="Configuration")] [switch]$Configuration, # Resource Block [Parameter(Mandatory=$true, ParameterSetName="Resource")] [switch]$Resource, # Import-Module line. [Parameter(Mandatory=$true, ParameterSetName="ModuleImport")] [switch]$ModuleImport, # Node Block. [Parameter(Mandatory=$true, ParameterSetName="Node")] [switch]$Node, # Close out the configuration block. [Parameter(ParameterSetName="CloseConfigurationBlock")] [switch]$CloseConfigurationBlock, # Close the Node Block. [Parameter(ParameterSetName="CloseNodeBlock")] [switch]$CloseNodeBlock, # Invoke the Configuration (to create the MOF). [Parameter(Mandatory=$true, ParameterSetName="InvokeConfiguration")] [switch]$InvokeConfiguration, # This will be the Name of the Configuration Block or Node block or Resource Block. [Parameter(Mandatory=$true, ParameterSetName="Configuration")] [Parameter(Mandatory=$true, ParameterSetName="InvokeConfiguration")] [Parameter(Mandatory=$true, ParameterSetName="Node")] [Parameter(Mandatory=$true, ParameterSetName="Resource")] [string]$Name, # This is the TYPE to be used with Resource Blocks (Regisry, Service, etc.). [Parameter(Mandatory=$true, ParameterSetName="Resource")] [string]$Type, # This is an Array of ModuleNames to import. [Parameter(Mandatory=$true, ParameterSetName="ModuleImport")] [string[]]$ModuleName, # This is a hashtable of Keys/Values for a Resource Block. [Parameter(Mandatory=$true, ParameterSetName="Resource")] [hashtable]$Parameters, # This determines whether or not to comment out a resource block. [switch]$CommentOUT = $false, # This allows comments to be added to various code blocks. [string]$Comment, # This Output Path is for the Configuration Block, not this function. [Parameter(ParameterSetName="InvokeConfiguration")] [string]$OutputPath = $(Join-Path -Path $PSScriptRoot -ChildPath "Output") ) $DSCString = "" switch ($PSCmdlet.ParameterSetName) { "Configuration" { # Add comments if there are comments. if ($PSBoundParameters.ContainsKey("Comment")) { $Comment = "`n<#`n$Comment`n#>" } else { $Comment = "" } # Output the DSC String. $DSCString = @" $Comment Configuration $Name`n{`n`n`t "@ } "ModuleImport" { # Use this block to reset our Conflict Engine. $Script:GlobalConflictEngine = @{} # Loop through each module. foreach ($m in $ModuleName) { if (!(Get-command Get-DscResource -ErrorAction SilentlyContinue)) { Import-module PSDesiredStateConfiguration -Force } # Use Get-DSCResource to determine REQUIRED parameters to resource. $resources = Get-DscResource -Module $m -ErrorAction SilentlyContinue # Loop through every resource in the module. foreach ($r in $resources) { # Add a blank entry for the Resource Block with Required Parameters. $Script:GlobalConflictEngine[$r.Name] = @() $tmpHash = @{} $r.Properties.Where({$_.IsMandatory}) | % { $tmpHash[$_.Name] = ""} $Script:GlobalConflictEngine[$r.Name] += $tmpHash } } # Output our Import-Module string. $DSCString = "Import-DSCResource -ModuleName $(($ModuleName | %{"'$_'"}) -join ", ")`n`t" } "Node" { $DSCString = "Node $Name`n`t{`n" } "InvokeConfiguration" { $DSCString = "$Name -OutputPath '$($OutputPath)'" } "CloseNodeBlock" { $DSCString = "`t}" } "CloseConfigurationBlock" { $DSCString = "`n}`n" } "Resource" { # Variables to be used for commeting out resource if necessary. $CommentStart = "" $CommentEnd = "" # Set our conflict variables up. $GlobalConflict = $false $Conflict = @() $Checked = @() # Determine if we have already processed a Resource Block of this type. if ($Script:GlobalConflictEngine.ContainsKey($Type)) { # Loop through every Resource definition of this type. foreach ($hashtable in $Script:GlobalConflictEngine[$Type]) { $Conflict = @() $Checked = @() # Loop through every Key/Value Pair in the Resource definition to see if they match the current one. foreach ($KeyPair in $hashtable.GetEnumerator()) { # Add the test result to our Conflict Array. $Conflict += $KeyPair.Value -eq $Parameters[$KeyPair.Name] # Need to store which Key/Value Pairs we checked. $Checked += $KeyPair.Name } # If we found a conflict. if ($Checked.Count -gt 0 -and $Conflict -notcontains $false) { Write-Verbose "Detecting Potential Conflict in $Name. Commenting Out Block" $GlobalConflict = $true break } } } # If we do not have a processing history entry for this type, set it to a blank array. # Have to do this here, because they may have forgotten do import the module so we cannot assume only Resources specified in the Import-Module. if (!$ProcessingHistory.ContainsKey($Type)) { $ProcessingHistory[$Type] = @() } # Add this resource to the processing history. $ProcessingHistory[$Type] += @{Name=$Name;Conflict=$GlobalConflict;Disabled=$CommentOut} # If we have a conflict, comment the block out. if ($GlobalConflict) { $CommentOUT = $true } else # Add this Resources Key/Value pairs to the collective. { $tmpHash = @{} foreach ($Check in $Checked) { $tmpHash[$check] = $Parameters[$Check] } $Script:GlobalConflictEngine[$Type] += $tmpHash } # If we are commenting this block out, then set up our comment characters. if ($CommentOut) { $CommentStart = "<#" $CommentEnd = "#>" } # If they passed a comment FOR the block, add it above the block. if ($PSBoundParameters.ContainsKey("Comment")) { $tmpComment = "<#`n" $Comment -split "`n" | %{ $tmpComment += "`t`t$_`n"} $tmpComment += "`t`t#>`n`t`t" $Comment = $tmpComment } else { $Comment = "" } # Start the Resource Block with Comment and CommentOut characters if necessary. $DSCString = "`t`t$Comment$($CommentStart)$Type '$($Name)'`n`t`t{" foreach ($key in $Parameters.Keys) { # This was extremely tricky. Have to determine the type of object passed so we can format it properly. # MOF files are picky with their Types so a BOOl has to be $True/$False not "True"/"False" or "$True"/"$False" # Arrays have to be separated and individually contained in quotes. # Numbers have to have no quotes so they are not processed as strings. if ($Parameters[$key] -is [Array]) { $item = $Parameters[$key] $DSCString += "`n`t`t`t$($key) = " for ($i = 0; $i -lt $item.Count;$i++) { if ($item[$i] -is [String]) { Try { Invoke-Expression $("`$variable = '" + $item[$i] + "'") | Out-Null $DSCString += "'$($item[$i].Trim("'").TrimEnd("'").Trim('"').TrimEnd('"').Trim())'" } catch { $DSCString += "@'`n$($item[$i].Trim("'").TrimEnd("'").Trim('"').TrimEnd('"').Trim())`n'@" } } else { $DSCString += "$($item[$i])" } if (($item.Count - $i) -gt 1) { $DSCString += ", " } } } elseif($Parameters[$key] -is [System.String]) { Try { Invoke-Expression $("`$variable = '" + $Parameters[$Key] + "'") | Out-Null $DSCString += "`n`t`t`t$($key) = '$([string]::new($Parameters[$key].Trim("'").TrimEnd("'").Trim('"').TrimEnd('"').Trim()))'" } Catch { # Parsing Error $DSCString += "`n`t`t`t$($key) = @'`n$($Parameters[$key].Trim("'").TrimEnd("'").Trim('"').TrimEnd('"').Trim())`n'@" } } elseif($Parameters[$key] -is [System.Boolean]) { $DSCString += "`n`t`t`t$($key) = `$$([string]([bool]$Parameters[$key]))" } else { $DSCString += "`n`t`t`t$($key) = $($Parameters[$key])" } } # Output our Resource Block String $DSCString += "`n`n`t`t}$CommentEnd`n`n" } } Write-Verbose $DSCString # Return our DSCstring. return $DSCString } # XML helper function to grab Node comments from SCMXML and put them into easily convertable stringdata. Function Get-NodeComments { [CmdletBinding()] [OutputType([string])] param ( [Parameter(Mandatory=$true)] [System.XML.XmlElement]$Node ) # Grab all of the comments. $Setting = "../.." $ProductInfo = $node.SelectNodes($Setting).Content.ProductInfo $Comments = $ProductInfo | Out-String $Comments = $Comments -replace ": ProductRef", ": $($ProductInfo.ProductRef.product_ref)" $Comments = ($Comments -replace "ManualTestProcedure :", "") -replace "ValueRange : ValueRange", "" $Comments = $Comments -replace ": CCEID-50", ": $($ProductInfo.'CCEID-50'.ID)" $Comments = $Comments.Trim() <# This is how to get string data into object format. (((($Comments -replace ": ", "= '") -replace "(`n)([A-Z])", ("'`$1" + '$2')) + '"') -replace "`n[^A-Z]", "") -replace "\\", "\\" | ConvertFrom-StringData #> return $Comments } # Reverse function to get StringData Object from Comments String output of Get-NodeComments. Function Get-NodeDataFromComments { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [String]$Comments ) Try { $comments = $comments -replace "[^\u0000-\u007F]", "" $comments = ((((($Comments -replace "(?m)^([^ ]*)\s*:\s?", "`$1 = '") -replace "(?m)^[^A-Z]*`$`n", "") -replace "(?m)`$(`n)([A-Z])", ("'`$1" + '$2')) + '"')) -replace "\\", "\\" $tmpComments = $Comments -split "'`n" $Comments = ($tmpComments | %{ (($_ -replace "`n", "") + "'") -replace "'", "" }) -join "`n" $object = $comments | ConvertFrom-StringData } Catch { Write-Error "Cannot convert COMMENT Data" } return $object } # Helper function to convert INI into hashtable. function Get-IniContent { [CmdletBinding()] param ( [Parameter(Mandatory=$true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName=$true)] [ValidateScript({Test-Path $_})] [string]$Path ) $ini = @{} switch -regex -file $Path { “^\[(.+)\]” # Section { $section = $matches[1] $ini[$section] = @{} $CommentCount = 0 } “^(;.*)$” # Comment { $value = $matches[1] $CommentCount = $CommentCount + 1 $name = “Comment” + $CommentCount $ini[$section][$name] = $value continue } “(.+?)\s*=(.*)” # Key { $name,$value = $matches[1..2] $ini[$section][$name] = $value # Need to replace double quotes with `" continue } "\`"(.*)`",(.*)$" { $name, $value = $matches[1..2] $ini[$section][$name] = $value continue } } return $ini } Function Write-CSVAuditData { [CmdletBinding()] [OutputType([string])] param ( [Parameter(Mandatory=$true)] [System.Object]$Entry ) $retHash = @{} $retHash.Name = $Entry.SubCategory switch -regex ($Entry.InclusionSetting) { "Success and Failure" { $retHash.Ensure = "Present" $retHash.AuditFlag = "Success" Write-DSCString -Resource -Name "$Name (Success) - Inclusion" -Type AuditPolicySubcategory -Parameters $retHash $retHash.AuditFlag = "Failure" Write-DSCString -Resource -Name "$Name (Failure) - Inclusion" -Type AuditPolicySubcategory -Parameters $retHash } "No Auditing" { $retHash.Ensure = "Absent" $retHash.AuditFlag = "Success" Write-DSCString -Resource -Name "$Name (Success) - Inclusion" -Type AuditPolicySubcategory -Parameters $retHash $retHash.AuditFlag = "Failure" Write-DSCString -Resource -Name "$Name (Failure) - Inclusion" -Type AuditPolicySubcategory -Parameters $retHash } "^(Success|Failure)$" { $retHash.Ensure = "Present" $retHash.AuditFlag = $Entry.InclusionSetting Write-DSCString -Resource -Name "$Name - Inclusion" -Type AuditPolicySubcategory -Parameters $retHash } } $retHash.Ensure = "Absent" switch -regex ($Entry.ExclusionSetting) { "Success and Failure" { $retHash.Ensure = "Absent" $retHash.AuditFlag = "Success" Write-DSCString -Resource -Name "$Name (Success) - Exclusion" -Type AuditPolicySubcategory -Parameters $retHash $retHash.AuditFlag = "Failure" Write-DSCString -Resource -Name "$Name (Failure) - Exclusion" -Type AuditPolicySubcategory -Parameters $retHash } "No Auditing" { # I am not sure how to make sure that "No Auditing" is Excluded or ABSENT. What should it be set to then? } "^(Success|Failure)$" { $retHash.Ensure = "Absent" $retHash.AuditFlag = $Entry.ExclusionSetting Write-DSCString -Resource -Name "$Name - Exclusion" -Type AuditPolicySubcategory -Parameters $retHash } } } Function Write-GPORegistryXMLData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$XML ) $regHash = @{} $regHash.ValueType = "None" $regHash.ValueName = "" $regHash.ValueData = "" $regHash.Key = "" $Properties = $XML.Properties $ValueData = 1 if (!([int]::TryParse($Properties.Value, [ref]$ValueData))) { $ValueData = "'$($Properties.ValueData)'" -replace "[^\u0020-\u007E]", "" } $regHash.ValueData = $ValueData $regHash.ValueName = $Properties.name -replace "[^\u0020-\u007E]", "" switch ($Properties.hive) { "HKEY_LOCAL_MACHINE" { $regHash.Key = "HKLM:\" } } $regHash.Key = Join-Path -Path $regHash.Key -ChildPath $Properties.Key switch ($Properties.type) { "REG_SZ" { $reghash.ValueType = "String" } "REG_NONE" { $reghash.ValueType = "None" } "REG_EXPAND_SZ" { $reghash.ValueType = "ExpandString" } "REG_DWORD" { $reghash.ValueType = "DWORD" } "REG_QWORD" { $reghash.ValueType = "QWORD" } "REG_BINARY" { $reghash.ValueType = "Binary" } "REG_MULTI_SZ" { $reghash.ValueType = "MultiString" } Default { $regHash.ValueType = "None" } } if ($regHash.ValueType -eq "DWORD" -and ($ValueData -match "(Disabled|Enabled|Not Defined|True|False)" -or $ValueData -eq "''")) { # This is supposed to be an INT and it's a String [int]$regHash.ValueData = @{"Disabled"=0;"Enabled"=1;"Not Defined"=0;"True"=1;"False"=0;''=0}.$ValueData } elseif ($regHash.ValueType -eq "String" -or $regHash.ValueType -eq "MultiString") { [string]$regHash.ValueData = [string]$ValueData } $CommentOUT = $false If ([string]::IsNullOrEmpty($regHash.ValueName)-or [string]::IsNullOrEmpty([string]$regHash.ValueData)-or $regHash.ValueType -eq "None") { # Comment these out! $CommentOUT = $true } Write-DSCString -Resource -Name "XML_$(Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName)" -Type Registry -Parameters $regHash -CommentOUT:$CommentOUT } Function Write-POLRegistryData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [psobject]$Data ) $regHash = @{} $regHash.ValueType = "None" $regHash.ValueName = "" $regHash.ValueData = "" $regHash.Key = "HKLM:\" $regHash.Key = Join-Path -Path $regHash.Key -ChildPath $Data.KeyName $ValueData = 1 if (!([int]::TryParse($Data.ValueData, [ref]$ValueData))) { $ValueData = "'$($Data.ValueData)'" -replace "[^\u0020-\u007E]", "" } $regHash.ValueName = $Data.ValueName -replace "[^\u0020-\u007E]", "" $regHash.ValueData = $ValueData switch ($Data.ValueType) { "REG_SZ" { $reghash.ValueType = "String" } "REG_NONE" { $reghash.ValueType = "None" } "REG_EXPAND_SZ" { $reghash.ValueType = "ExpandString" } "REG_DWORD" { $reghash.ValueType = "DWORD" } "REG_QWORD" { $reghash.ValueType = "QWORD" } "REG_BINARY" { $reghash.ValueType = "Binary" } "REG_MULTI_SZ" { $reghash.ValueType = "MultiString" } Default { $regHash.ValueType = "None" } } if ($regHash.ValueType -eq "DWORD" -and ($ValueData -match "(Disabled|Enabled|Not Defined|True|False)" -or $ValueData -eq "''")) { # This is supposed to be an INT and it's a String [int]$regHash.ValueData = @{"Disabled"=0;"Enabled"=1;"Not Defined"=0;"True"=1;"False"=0;''=0}.$ValueData } elseif ($regHash.ValueType -eq "String" -or $regHash.ValueType -eq "MultiString") { [string]$regHash.ValueData = [string]$ValueData } $CommmentOUT = $false If ([string]::IsNullOrEmpty($regHash.ValueName)-or [string]::IsNullOrEmpty([string]$regHash.ValueData)-or $regHash.ValueType -eq "None") { $CommentOUT = $true } Write-DSCString -Resource -Name (Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName) -Type Registry -Parameters $regHash -CommentOUT:$CommentOUT } Function Write-INFRegistryData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Key, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$ValueData ) $regHash = @{} $regHash.ValueType = "None" $regHash.ValueName = "" $regHash.ValueData = "" $regHash.Key = "" $values = $ValueData -split "," $KeyPath = $Key $ValueName = Split-Path -Leaf $KeyPath $regHash.ValueName = $ValueName -replace "[^\u0020-\u007E]", "" $regHash.Key = Split-Path -Parent $KeyPath $regHash.Key = $regHash.Key -replace "MACHINE\\", "HKLM:\" $values[1] = $values[1..$values.count] -join "," switch ($values[0]) { "1" { # Not sure what type the legal caption is. Is it an array of strings? $regHash.ValueData = "'$($values[1])'" -replace "[^\u0020-\u007E]", "" $regHash.ValueType = "String" } "7" { $regHash.ValueData = @" $($values[1]) "@ -replace "[^\u0020-\u007E]", "" $regHash.ValueType = "MultiString" } "4" { $tmpValueData = 1 if (!([int]::TryParse($values[1], [ref]$tmpValueData))) { Write-Error "Cannot Parse Value for $ValueData at key $KeyData, setting value to 0" $tmpValueData = 0 } $regHash.ValueData = $tmpValueData $regHash.ValueType = "DWORD" } "3" { $hexified = $values[1] -split "," | % { "0x$_"} $regHash.ValueData = [byte[]]$hexified $regHash.ValueType = "Binary" } Default { Write-Warning "Cannot parse RegistryINF Data" return "" } } if ($regHash.ValueType -eq "DWORD" -and ($regHash.ValueData -match "(Disabled|Enabled|Not Defined|True|False)" -or $regHash.ValueData -eq "''")) { # This is supposed to be an INT and it's a String [int]$regHash.ValueData = @{"Disabled"=0;"Enabled"=1;"Not Defined"=0;"True"=1;"False"=0;''=0}.$regHash.ValueData } elseif ($regHash.ValueType -eq "String" -or $regHash.ValueType -eq "MultiString") { [string]$regHash.ValueData = [string]$regHash.ValueData } $CommentOUT = $false if ([string]::IsNullOrEmpty($regHash.ValueData)) { $CommentOUT = $true } Write-DSCString -Resource -Name "INF_$(Join-Path -Path $regHash.Key -ChildPath $regHash.ValueName)" -Type Registry -Parameters $regHash -CommentOUT:$CommentOUT } Function Write-INFServiceData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [string]$Service, [Parameter(Mandatory = $true)] [string]$ServiceData ) $serviceHash = @{} $serviceHash.Name = "" $serviceHash.State = "" $values = $ServiceData -split "," $serviceHash.Name = $Service switch ($values[0]) { "2" { $serviceHash.State = "Running" } "4" { $serviceHash.State = "Stopped" } "3" { $serviceHash.StartupType = "Manual" $serviceHash.Remove("State") } } # Does the Second (if present) value determine starttype? Write-DSCString -Resource -Name "INF_$($serviceHash.Name)" -Type Service -Parameters $serviceHash } Function Write-INFFileSecurityData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$ACLData ) $aclHash = @{} $aclHash.Path = "" $aclHash.DACLString = "" # These are DACLS $aclHash.Path = ((($Path -replace "^%", "`env:") -replace "%\\", "\") -replace "%", "") if ($aclData -match "[0-9],(.*)$") { $aclHash.DACLString = $Matches[1] } else { Write-Error "Cannot Parse $ACLData for $Path" return "" } Write-DSCString -Resource -Name "INF_$($ACLhash.Path)_ACL" -Type xACL -Parameters $aclHash } Function Write-INFPrivilegeData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Privilege, [Parameter(Mandatory = $true)] [AllowEmptyString()] [string]$PrivilegeData ) $privilegeHash = @{} $privilegeHash.Policy = "" $privilegeHash.Identity = "" # These are UserRights if ($UserRightsHash.ContainsKey($Privilege)) { $privilegeHash.Policy = $UserRightsHash[$Privilege] } else { Write-Error "Cannot find $Privilege" return "" } $privilegeHash.Identity = $PrivilegeData Write-DSCString -Resource -Name "INF_$($privilegeHash.Policy)" -Type UserRightsAssignment -Parameters $privilegeHash } Function Write-INFRegistryACLData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [string]$Path, [Parameter(Mandatory = $true)] [string]$ACLData ) $regHash = @{} $regHash.Path = "" $regHash.DACLString = "" $regHash.Path = $Path -replace "MACHINE\\", "HKLM:\" if ($ACLData -match "[0-9],(.*)$") { $regHash.DACLString = $Matches[1] } else { Write-Error "Cannot parse $ACLData for $Key" return "" } Write-DSCString -Resource -Name "INF_$($regHash.Path)_ACL" -Type xACL -Parameters $regHash } Function Write-INFSecuritySettingData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [string]$Key, [Parameter(Mandatory = $true)] [string]$SecurityData ) $regHash = @{} $SecurityData = $SecurityData.Trim() [int]$ValueData = 1 if (![int]::TryParse($SecurityData, [ref]$ValueData)) { [string]$ValueData = $SecurityData } $params = @{$key = $ValueData;Name = $Key} Write-DSCString -Resource -Name "INF_$Key" -Type SecuritySetting -Parameters $params } Function Complete-Configuration { [CmdletBinding()] [OutputType([bool])] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string]$ConfigString, [Parameter()] [string]$OutputPath = $(Join-Path -Path $pwd.path -ChildPath "Output") ) if ($ConfigString -match "(?m)Configuration (?<Name>.*)$") { $CallingFunction = $Matches.Name } else { $CallingFunction = (Get-PSCallStack)[1].Command } if (!(Test-Path $OutputPath)) { mkdir $OutputPath } $scriptblock = [scriptblock]::Create($ConfigString) if (!$?) { # Somehow CallingFunction, defined above, is not useable right here. Not sure why $Path = $(Join-Path -Path $OutputPath -ChildPath "$($CallingFunction).ps1.error") $ConfigString > $Path Write-Error "Could not CREATE ScriptBlock from configuration. Creating PS1 Error File: $Path. Please rename error file to PS1 and open for further inspection. Errors are listed below" return $false } $output = Invoke-Command -ScriptBlock $scriptblock if (!$?) { $Path = $(Join-Path -Path $OutputPath -ChildPath "$($CallingFunction).ps1.error") $scriptblock.ToString() > $Path Write-Error "Could not COMPILE cofiguration. Storing ScriptBlock: $Path. Please rename error file to PS1 and open for further inspection. Errors are listed below" foreach ($e in $output) { Write-Error $e } return $false } return $true } Function Write-XMLRegistryData { [CmdletBinding()] [OutputType([string])] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$DiscoveryData, [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$ValueData ) # Grab the ExistensialRule and Validation Rule. $ExistensialRule = $valueData.SelectNodes("..").ExistentialRule $ValidationRules = $valueData.SelectNodes("..").ValidationRules $Comments = Get-NodeComments -Node $DiscoveryData $Name = $DiscoveryData.SelectNodes("../..").Name $Name = "$((Get-NodeDataFromComments -Comments $Comments).'CCEID-50'): $Name" # This means that there is Policy Data if ($DiscoveryData.ChildNodes.name -notcontains "RegistryDiscoveryInfo") { $PolicyData = $DiscoveryData.SelectNodes("../..").Policy $Hive = switch ($DiscoveryData.Scope) { "Machine" { "HKLM" } } $Settings = "" switch ($PolicyData.Elements) { {$_.Enum} { $Settings = "Enum"} {$_.Boolean} { $Settings = "Boolean" } {$_.Text} { $Settings = "Text" } {$_.Decimal} {$Settings = "Decimal" } Default { Write-Error "Cannot find Proper Policy Value for $Name"; return "" } } foreach ($Setting in $PolicyData.Elements."$Settings") { $retHash = @{} $retHash.ValueName = $Setting.ValueName $retHash.Key = Join-Path -Path "$($Hive):" -ChildPath $Setting.Key $value = 1 [psobject]$TmpValue = ($ValidationRules.OptionRule | ?{$_.Id -eq $Setting.Id}).Value.ValueA if ($TmpValue -match '$\(string') { $TmpValue = $Settings.Item | ?{$_.DisplayName -match $TmpValue} } switch -Regex ($TmpValue) { {[string]::IsNullOrEmpty($_)} { Write-Error "Cannot Parse Data for $Name"; return ""} "(Disabled|Enabled|Not Defined|True|False)" { [int]$TmpValue = @{"Disabled"=0;"Enabled"=1;"Not Defined"=0;"True"=1;"False"=0;''=0}.$Value; $retHash.ValueType = "DWORD"; break } "''" { [int]$TmpValue = @{"Disabled"=0;"Enabled"=1;"Not Defined"=0;"True"=1;"False"=0;''=0}.$Value; $retHash.ValueType = "DWORD"; break } {[int]::TryParse($TmpValue, [ref]$value)} { [int]$TmpValue = $Value; $retHash.ValueType = "DWORD";break} Default { [string]$TmpValue = $TmpValue -replace "[^\u0020-\u007E]", ""; $retHash.ValueType = "String"} } $retHash.ValueData = $TmpValue Write-DSCString -Resource -Name "$($Name): $($setting.Id)" -Type Registry -Parameters $retHash -Comment $Comments } } else { $retHash = @{} $retHash.Key = "" $retHash.ValueName = "" $retHash.ValueData = "" # Grab the Value and Operator $TempValue = $ValidationRules.SettingRule.Value.ValueA $Operator = $ValidationRules.SettingRule.Operator if ($DiscoveryData.RegistryDiscoveryInfo.Hive -is [System.XML.XMLElement]) { $Hive = switch ($DiscoveryData.RegistryDiscoveryInfo.Hive."#text") { "HKEY_LOCAL_MACHINE" { "HKLM" } } $ValueType = $DiscoveryData.RegistryDiscoveryInfo.DataType."#text" $KeyPath = $DiscoveryData.RegistryDiscoveryInfo.KeyPath."#text" $ValueName = $DiscoveryData.RegistryDiscoveryInfo.ValueName."#text" } else { $Hive = switch ($DiscoveryData.RegistryDiscoveryInfo.Hive) { "HKEY_LOCAL_MACHINE" { "HKLM" } } $ValueType = $DiscoveryData.RegistryDiscoveryInfo.DataType $KeyPath = $DiscoveryData.RegistryDiscoveryInfo.KeyPath $ValueName = $DiscoveryData.RegistryDiscoveryInfo.ValueName } $retHash.Key = Join-Path -Path "$($Hive):" -ChildPath $KeyPath $retHash.ValueName = $ValueName $Value = 1 if (!([int]::TryParse($TempValue, [ref]$Value))) { $Value = "'$($TempValue)'" -replace "[^\u0020-\u007E]", "" } switch ($ValueType) { "REG_SZ" { $ValueType = "String" } "REG_NONE" { $ValueType = "None" } "REG_EXPAND_SZ" { $ValueType = "ExpandString" } "REG_DWORD" { $ValueType = "DWORD" } "REG_QWORD" { $ValueType = "QWORD" } "REG_BINARY" { $ValueType = "Binary" } "REG_MULTI_SZ" { $ValueType = "MultiString" } Default { $ValueType = "None" } } if ($ValueType -eq "DWORD" -and ($Value -match "(Disabled|Enabled|Not Defined|True|False)" -or $ValueData -eq "''")) { # This is supposed to be an INT and it's a String [int]$Value = @{"Disabled"=0;"Enabled"=1;"Not Defined"=0;"True"=1;"False"=0;''=0}.$Value } elseif ($ValueType -eq "String" -or $ValueType -eq "MultiString") { [string]$Value = [string]$Value } If ($ValueName -eq "" -or $Value -eq $null -or $ValueType -eq "None") { Write-Error "Cannot parse `$ValueData ($Value) and `$ValueType ($ValueType) for $($retHash.Key)" return "" } $retHash.ValueType = $ValueType $retHash.ValueData = $Value Write-DSCString -Resource -Name $Name -Type Registry -Parameters $retHash -Comment $Comments } } Function Write-XMLAuditData { [CmdletBinding()] [OutputType([hashtable])] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$DiscoveryData, [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$ValueData ) # Grab the ExistensialRule and Validation Rule. $ExistensialRule = $valueData.SelectNodes("..").ExistentialRule $ValidationRules = $valueData.SelectNodes("..").ValidationRules $Comments = Get-NodeComments -Node $DiscoveryData $Name = $DiscoveryData.SelectNodes("../..").Name $Name = "$((Get-NodeDataFromComments -Comments $Comments).'CCEID-50'): $Name" # Grab the Value and Operator $TempValue = $ValidationRules.SettingRule.Value.ValueA $Operator = $ValidationRules.SettingRule.Operator $retHash = @{} $retHash.AuditFlag = "" $retHash.Name = "" $AuditFlag = ((("$($TempValue)" -replace "[^\u0020-\u007E]", "") -replace "Success And Failure", "SuccessAndFailure") -replace "No Auditing", "NoAuditing") $AuditID = $DiscoveryData.AdvancedAuditDiscoveryInfo.advancedauditsettingid.Trim("{").TrimEnd("}") if ($AuditCategoryHash.ContainsKey($AuditID)) { $retHash.Name = $AuditCategoryHash["$AuditID"] } else { Write-Error "Cannot parse Subcategory for $AuditID with AuditFlag ($AuditFlag)" return "" } if (![string]::IsNullOrEmpty($AuditFlag)) { $retHash.AuditFlag = $AuditFlag } switch ($retHash.AuditFlag) { "SuccessAndFailure" { $retHash.AuditFlag = "Success" Write-DSCString -Resource -Name "$Name (Success)" -Type AuditPolicySubcategory -Parameters $retHash -Comment $Comments $retHash.AuditFlag = "Failure" Write-DSCString -Resource -Name "$Name (Failure)" -Type AuditPolicySubcategory -Parameters $retHash -Comment $Comments } "NoAuditing" { $retHash.Ensure = "Absent" $retHash.AuditFlag = "Success" Write-DSCString -Resource -Name "$Name (Success)" -Type AuditPolicySubcategory -Parameters $retHash -Comment $Comments $retHash.AuditFlag = "Failure" Write-DSCString -Resource -Name "$Name (Failure)" -Type AuditPolicySubcategory -Parameters $retHash -Comment $Comments } Default { Write-DSCString -Resource -Name $Name -Type AuditPolicySubcategory -Parameters $retHash -Comment $Comments } } } Function Write-XMLPrivilegeData { [CmdletBinding()] [OutputType([hashtable])] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$DiscoveryData, [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$ValueData ) # Grab the ExistensialRule and Validation Rule. $ExistensialRule = $valueData.SelectNodes("..").ExistentialRule $ValidationRules = $valueData.SelectNodes("..").ValidationRules $Comments = Get-NodeComments -Node $DiscoveryData $Name = $DiscoveryData.SelectNodes("../..").Name $Name = "$((Get-NodeDataFromComments -Comments $Comments).'CCEID-50'): $Name" # Grab the Value and Operator $TempValue = $ValidationRules.SettingRule.Value.ValueA $Operator = $ValidationRules.SettingRule.Operator $retHash = @{} $retHash.Identity = @() $retHash.Policy = "" if ($DiscoveryData.WmiDiscoveryInfo.Where -match "UserRight='(?<Policy>.*)'.*") { if ($UserRightsHash.ContainsKey($Matches.Policy)) { $retHash.Policy = $UserRightsHash[$Matches.Policy] $retHash.Identity = $TempValue -split "," } else { Write-Error "Cannot find matching User Right for Privilege ($($Matches.Privilege))" return "" } } else { Write-Error "Privilege String is not formatted correctly ($($DiscoveryData.WMIDiscoveryInfo.Where))" return "" } Write-DSCString -Resource -Name $Name -Type UserRightsAssignment -Parameters $retHash -Comment $Comments } Function Write-XMLScriptData { [CmdletBinding()] [OutputType([hashtable])] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$DiscoveryData, [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$ValueData ) $retHash = @{} return "" } Function Write-XMLWMIData { [CmdletBinding()] [OutputType([hashtable])] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$DiscoveryData, [Parameter(Mandatory=$true)] [System.Xml.XmlElement]$ValueData ) $Comments = Get-NodeComments -Node $DiscoveryData $Name = $DiscoveryData.SelectNodes("../..").Name $Name = "$((Get-NodeDataFromComments -Comments $Comments).'CCEID-50'): $Name" # Grab the ExistensialRule and Validation Rule. $ExistensialRule = $valueData.SelectNodes("..").ExistentialRule $ValidationRules = $valueData.SelectNodes("..").ValidationRules $Comments = Get-NodeComments -Node $DiscoveryData $Name = $DiscoveryData.SelectNodes("../..").Name $Name = "$((Get-NodeDataFromComments -Comments $Comments).'CCEID-50'): $Name" # Grab the Value and Operator $TempValue = $ValidationRules.SettingRule.Value.ValueA $parseValue = $false if ([bool]::TryParse($TempValue, [ref]$parseValue)) { [int]$TempValue = [bool]$parseValue } $Operator = $ValidationRules.SettingRule.Operator $retHash = @{} $Where = switch ($DiscoveryData.WMIDiscoveryInfo.Where) { {$_."#text"} {$_."#text"} Default { $_ } } $KeyName = "" if ($Where -match "KeyName.*'(?<Name>[A-Z]*)'.*") { $KeyName = $Matches.Name } else { Write-Error "Cannot extract Name from $Where" return "" } Write-DSCString -Resource -Name $Name -Type SecuritySetting -Parameters @{$KeyName = $TempValue;Name = $KeyName} -Comment $Comments } Function Write-JSONRegistryData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] $RegistryData ) $ValueData = -1 if ($RegistryData.RegValueType -eq "Int") { if (!([int]::TryParse($RegistryData.ExpectedValue, [ref]$ValueData))) { Write-Warning "Could not parse Policy ($($RegistryData.Name)) with ExpectedValue ($($RegistryData.ExpectedValue)) as ($($RegistryData.RegValueType))" continue } else { $ValueType = "DWORD" } } else { $ValueData = $RegistryData.ExpectedValue.ToString() $ValueType = "String" } switch ($RegistryData.Hive) { "LocalMachine" { $RegistryData.Hive = "HKLM:" } } if ($ValueType -eq "DWORD" -and ($Value -match "(Disabled|Enabled|Not Defined|True|False)" -or $ValueData -eq "''")) { # This is supposed to be an INT and it's a String [int]$Value = @{"Disabled"=0;"Enabled"=1;"Not Defined"=0;"True"=1;"False"=0;''=0}.$Value } elseif ($ValueType -eq "String" -or $ValueType -eq "MultiString") { [String]$valueData = $ValueData } $commentOUT = $false If ([string]::IsNullOrEmpty($RegistryData.Hive) -or [string]::IsNullOrEmpty($RegistryData.ValueName) -or [string]::IsNullOrEmpty($RegistryData.KeyPath)) { $CommentOUT = $true } $policyHash = @{} $policyHash.Key = $([string]$RegistryData.Hive, [string]$RegistryData.KeyPath -join "\" ) $policyHash.ValueName = $RegistryData.ValueName $policyHash.ValueType = $ValueType $policyHash.ValueData = $ValueData return Write-DSCString -Resource -Type Registry -Name "$($RegistryData.CCEID): $($RegistryData.Name)" -Parameters $policyHash -CommentOUT:(!$RegistryData.Enabled) } Function Write-JSONAuditData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] $AuditData ) if (!$AuditCategoryHash.ContainsKey($AuditData.AuditPolicyID)) { Write-Warning "Cannot find Audit Policy for ($($AuditData.AuditPolicyID)) from ($($AuditData.Name))" return "" } else { $Category = $AuditCategoryHash[$AuditData.AuditPolicyID] $Ensure = "Absent", "Present" $AuditData.ExpectedValue = ($AuditData.ExpectedValue -replace "Success And Failure", "SuccessAndFailure") -replace "No Auditing", "NoAuditing" $policyHash = @{} $policyHash.AuditFlag = $AuditData.ExpectedValue $policyHash.Name = $Category switch ($policyHash.AuditFlag) { "SuccessAndFailure" { $policyHash.AuditFlag = "Success" Write-DSCString -Resource -Type AuditPolicySubCategory -Name "$($AuditData.CCEID): $($AuditData.Name) (Success)" -Parameters $policyHash -CommentOUT:(!$AuditData.Enabled) $policyHash.AuditFlag = "Failure" Write-DSCString -Resource -Type AuditPolicySubCategory -Name "$($AuditData.CCEID): $($AuditData.Name) (Failure)" -Parameters $policyHash -CommentOUT:(!$AuditData.Enabled) } "NoAuditing" { $policyHash.Ensure = "Absent" $policyHash.AuditFlag = "Success" Write-DSCString -Resource -Type AuditPolicySubcategory -Name "$($AuditData.CCEID): $($AuditData.Name) (Success)" -Parameters $policyHash -CommentOUT:(!$AuditData.Enabled) $policyHash.AuditFlag = "Failure" Write-DSCString -Resource -Type AuditPolicySubcategory -Name "$($AuditData.CCEID): $($AuditData.Name) (Failure)" -Parameters $policyHash -CommentOUT:(!$AuditData.Enabled) } Default { Write-DSCString -Resource -Type AuditPolicySubcategory -Name "$($AuditData.CCEID): $($AuditData.Name)" -Parameters $policyHash -CommentOUT:(!$AuditData.Enabled) } } } } Function Write-JSONPrivilegeData { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] $PrivilegeData ) $Privilege = $PrivilegeData.SettingName if ($UserRightsHash.ContainsKey($Privilege)) { $Privilege = $UserRightsHash[$PrivilegeData.SettingName] } else { Write-Error "Cannot find privilege $Privilege" return "" } $Accounts = @() switch (($PrivilegeData.ExpectedValue -split ", ")) { "No One" { $Accounts = ""; break } "SERVICE" { $Accounts += "NT AUTHORITY\SERVICE" } "NEW_VALUE" { } "LOCAL SERVICE" { $Accounts += "NT AUTHORITY\LOCAL SERVICE" } "AUTHENTICATED USERS" { $Accounts += "NT AUTHORITY\AUTHENTICATED USERS" } "Administrators" { $Accounts += "BUILTIN\Administrators" } "NETWORK SERVICE" { $Accounts += "NT AUTHORITY\NETWORK SERVICE" } "NT AUTHORITY\Local account and member of Administrators group" { $Accounts += "[Local Account|Administrator]" } "NT AUTHORITY\Local account" { $Accounts += "[Local Account]"} "Guests" { $Accounts += "BUILTIN\Guests"} Default { Write-Warning "Found a new Account Value for JSONPrivilege: $_" } } $policyHash = @{} if ([string]::IsNullOrEmpty($Accounts)) { $policyHash.Force = $true } $policyHash.Policy = $Privilege $policyHash.Identity = $Accounts return Write-DSCString -Resource -Name "$($PrivilegeData.CCEID): $($PrivilegeData.Name)" -Type UserRightsAssignment -Parameters $policyHash -CommentOUT:(!$PrivilegeData.Enabled) } # Clear our processing history on each Configuration Creation. Function Clear-ProcessingHistory { $ProcessingHistory.Clear() } # Write out summary data and output proper files based on success/failure. Function Write-ProcessingHistory { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [bool]$Pass, [Parameter()] [string]$OutputPath = $(Join-Path -Path $pwd.path -ChildPath "Output") ) if (!(Test-Path $OutputPath)) { mkdir $OutputPath | Out-Null } if (((Get-Module -ListAvailable).name -contains "Pester")) { Import-Module Pester } elseif (!((Get-Module).name -contains "Pester")) { Write-ProcessingHistory_NonPester -Pass $Pass Write-ProcessingHistory_NonPester -Pass $Pass *> $(Join-Path -Path $OutputPath -ChildPath "Summary.log") return } $Tests = @() New-Variable -Name successes -Option AllScope -Force New-Variable -Name disabled -Option AllScope -Force New-Variable -Name conflict -Option AllScope -Force $successes = $disabled = $conflict = 0 $History = Get-Variable ProcessingHistory foreach($KeyPair in $History.Value.GetEnumerator()) { $old_success = $successes $old_disabled = $disabled $old_conflict = $conflict $Describe = "Parsing Summary: $((Get-PsCallStack)[1].Command) - $(@("FAILED", "SUCCEEDED")[[int]$Pass])`n`t$($KeyPair.Key.ToUpper()) Resources" Describe $Describe { foreach ($Resource in $KeyPair.Value.Where({($_.Disabled -eq $false) -and ($_.Conflict -eq $false)})) { It "Parsed: $($Resource.Name)" { $Resource.Disabled | Should Be $false } $successes++ } foreach ($Resource in $KeyPair.Value.Where({$_.Disabled})) { It "Disabled: $($Resource.Name)" { $Resource.Disabled | Should Be $true } $disabled++ } foreach ($Resource in $KeyPair.Value.Where({$_.Conflict})) { It "Found Conflicts: $($Resource.Name)" { $Resource.Conflict | Should Be $true } $conflict++ } } *>> $(Join-Path -Path $OutputPath -ChildPath "Summary.log") $successes = $old_success $disabled = $old_disabled $conflict = $old_conflict Describe $Describe { foreach ($Resource in $KeyPair.Value.Where({($_.Disabled -eq $false) -and ($_.Conflict -eq $false)})) { It "Parsed: $($Resource.Name)" { $Resource.Disabled | Should Be $false } $successes++ } foreach ($Resource in $KeyPair.Value.Where({$_.Disabled})) { It "Disabled: $($Resource.Name)" { $Resource.Disabled | Should Be $true } $disabled++ } foreach ($Resource in $KeyPair.Value.Where({$_.Conflict})) { It "Found Conflicts: $($Resource.Name)" { $Resource.Conflict | Should Be $true } $conflict++ } } } $tmpBlock = { Write-Host "TOTALS" -ForegroundColor White Write-Host "------" -ForegroundColor White Write-Host "SUCCESSES: $successes" -ForegroundColor Green Write-Host "DISABLED: $disabled" -ForegroundColor Gray Write-Host "CONFLICTS: $conflict" -ForegroundColor Red Write-Host "______________________" -ForegroundColor White Write-Host "TOTAL: $($successes + $disabled + $conflict)" -ForegroundColor White } $tmpBlock.Invoke() *>> $(Join-Path -Path $OutputPath -ChildPath "Summary.log") $tmpBlock.Invoke() } Function Write-ProcessingHistory_NonPester { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [bool]$Pass ) Write-Host "Parsing Summary: $((Get-PsCallStack)[1].Command) - $(@("FAILED", "SUCCEEDED")[[int]$Pass])" -ForegroundColor @("RED", "GREEN")[[int]$Pass] Write-Host "---------------" -ForegroundColor White $History = Get-Variable ProcessingHistory $successes = $disabled = $conflict = 0 foreach($KeyPair in $History.Value.GetEnumerator()) { foreach ($Resource in $KeyPair.Value.Where({($_.Disabled -eq $false) -and ($_.Conflict -eq $false)})) { Write-Host "Parsed: $($Resource.Name)" -ForegroundColor Green $successes++ } foreach ($Resource in $KeyPair.Value.Where({$_.Disabled})) { Write-Host "Disabled: $($Resource.Name)" -ForegroundColor Gray $disabled++ } foreach ($Resource in $KeyPair.Value.Where({$_.Conflict})) { Write-Host "Found Conflicts: $($Resource.Name)" -ForegroundColor Red $conflict++ } } Write-Host "TOTALS" -ForegroundColor White Write-Host "------" -ForegroundColor White Write-Host "SUCCESSES: $successes" -ForegroundColor Green Write-Host "DISABLED: $disabled" -ForegroundColor Gray Write-Host "CONFLICTS: $conflict" -ForegroundColor Red Write-Host "______________________" -ForegroundColor White Write-Host "TOTAL: $($successes + $disabled + $conflict)" -ForegroundColor White } Export-ModuleMember -Cmdlet * -Function * -Variable * |