Modules/GuestConfigurationPolicy/GuestConfigurationPolicy.psm1
#Region './prefix.ps1' 0 Set-StrictMode -Version latest $ErrorActionPreference = 'Stop' #EndRegion './prefix.ps1' 3 #Region './Private/Convert-FileToUnixLineEndings.ps1' 0 function Convert-FileToUnixLineEndings { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $FilePath ) $fileContent = Get-Content -Path $FilePath -Raw $fileContentWithLinuxLineEndings = $fileContent.Replace("`r`n", "`n") $null = Set-Content -Path $FilePath -Value $fileContentWithLinuxLineEndings -Force -NoNewline Write-Verbose -Message "Converted the file '$FilePath' to Unix line endings." } #EndRegion './Private/Convert-FileToUnixLineEndings.ps1' 16 #Region './Private/Format-Json.ps1' 0 function Format-Json { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [String] $Json ) $indent = 0 $jsonLines = $Json -Split '\n' $formattedLines = @() $previousLine = '' foreach ($line in $jsonLines) { $skipAddingLine = $false if ($line -match '^\s*\}\s*' -or $line -match '^\s*\]\s*') { # This line contains ] or }, decrement the indentation level $indent-- } $formattedLine = (' ' * $indent * 4) + $line.TrimStart().Replace(': ', ': ') if ($line -match '\s*".*"\s*:\s*\[' -or $line -match '\s*".*"\s*:\s*\{' -or $line -match '^\s*\{\s*' -or $line -match '^\s*\[\s*') { # This line contains [ or {, increment the indentation level $indent++ } if ($previousLine.Trim().EndsWith("{")) { if ($formattedLine.Trim() -in @("}", "},")) { $newLine = "$($previousLine.TrimEnd())$($formattedLine.Trim())" #Write-Verbose -Message "FOUND SHORTENED LINE: $newLine" $formattedLines[($formattedLines.Count - 1)] = $newLine $previousLine = $newLine $skipAddingLine = $true } } if ($previousLine.Trim().EndsWith("[")) { if ($formattedLine.Trim() -in @("]", "],")) { $newLine = "$($previousLine.TrimEnd())$($formattedLine.Trim())" #Write-Verbose -Message "FOUND SHORTENED LINE: $newLine" $formattedLines[($formattedLines.Count - 1)] = $newLine $previousLine = $newLine $skipAddingLine = $true } } if (-not $skipAddingLine -and -not [String]::IsNullOrWhiteSpace($formattedLine)) { $previousLine = $formattedLine $formattedLines += $formattedLine } } $formattedJson = $formattedLines -join "`n" return $formattedJson } #EndRegion './Private/Format-Json.ps1' 68 #Region './Private/Get-GuestConfigurationAssignmentParameterName.ps1' 0 <# .SYNOPSIS Retrieves the name of a Guest Configuration Assignment parameter correctly formatted to be passed to the Guest Configuration Assignment. .PARAMETER ParameterInfo A single hashtable indicating the necessary parameter info from which to retrieve the parameter name. .EXAMPLE Get-GuestConfigurationAssignmentParameterName -ParameterInfo $currentParameterInfo #> function Get-GuestConfigurationAssignmentParameterName { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter()] [Hashtable] $ParameterInfo ) $assignmentParameterName = "$($ParameterInfo.MofResourceReference);$($ParameterInfo.MofParameterName)" return $assignmentParameterName } #EndRegion './Private/Get-GuestConfigurationAssignmentParameterName.ps1' 22 #Region './Private/Get-GuestConfigurationAssignmentParametersExistenceConditionSection.ps1' 0 <# .SYNOPSIS Retrieves a policy section check for the existence of a Guest Configuration Assignment with the specified parameters. .PARAMETER ParameterInfo A list of hashtables indicating the necessary info for parameters that need to be passed into this Guest Configuration Assignment. .EXAMPLE Get-GuestConfigurationAssignmentParametersExistenceConditionSection -ParameterInfo $parameterInfo #> function Get-GuestConfigurationAssignmentParametersExistenceConditionSection { [CmdletBinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [Hashtable[]] $ParameterInfo ) $parameterValueConceatenatedStringList = @() foreach ($currentParameterInfo in $ParameterInfo) { $assignmentParameterName = Get-GuestConfigurationAssignmentParameterName -ParameterInfo $currentParameterInfo $assignmentParameterStringValue = Get-GuestConfigurationAssignmentParameterStringValue -ParameterInfo $currentParameterInfo $currentParameterValueConcatenatedString = "'$assignmentParameterName', '=', $assignmentParameterStringValue" $parameterValueConceatenatedStringList += $currentParameterValueConcatenatedString } $allParameterValueConcantenatedString = $parameterValueConceatenatedStringList -join ", ',', " $parameterExistenceConditionEqualsValue = "[base64(concat($allParameterValueConcantenatedString))]" $existenceConditionHashtable = [Ordered]@{ field = 'Microsoft.GuestConfiguration/guestConfigurationAssignments/parameterHash' equals = $parameterExistenceConditionEqualsValue } return $existenceConditionHashtable } #EndRegion './Private/Get-GuestConfigurationAssignmentParametersExistenceConditionSection.ps1' 40 #Region './Private/Get-GuestConfigurationAssignmentParameterStringValue.ps1' 0 <# .SYNOPSIS Retrieves the string value of a Guest Configuration Assignment parameter correctly formatted to be passed to the Guest Configuration Assignment as part of the parameter hash. .PARAMETER ParameterInfo A single hashtable indicating the necessary parameter info from which to retrieve the parameter string value. .EXAMPLE Get-GuestConfigurationAssignmentParameterStringValue -ParameterInfo $currentParameterInfo #> function Get-GuestConfigurationAssignmentParameterStringValue { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter()] [Hashtable] $ParameterInfo ) if ($ParameterInfo.ContainsKey('ConfigurationValue')) { if ($ParameterInfo.ConfigurationValue.StartsWith('[') -and $ParameterInfo.ConfigurationValue.EndsWith(']')) { $assignmentParameterStringValue = $ParameterInfo.ConfigurationValue.Substring(1, $ParameterInfo.ConfigurationValue.Length - 2) } else { $assignmentParameterStringValue = "'$($ParameterInfo.ConfigurationValue)'" } } else { $assignmentParameterStringValue = "parameters('$($ParameterInfo.ReferenceName)')" } return $assignmentParameterStringValue } #EndRegion './Private/Get-GuestConfigurationAssignmentParameterStringValue.ps1' 38 #Region './Private/Get-GuestConfigurationMofContent.ps1' 0 function Get-GuestConfigurationMofContent { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $Name, [Parameter(Mandatory = $true)] [String] $Path ) Write-Verbose "Parsing Configuration document '$Path'" $resourcesInMofDocument = [Microsoft.PowerShell.DesiredStateConfiguration.Internal.DscClassCache]::ImportInstances($Path, 4) # Set the profile path for Chef resource $resourcesInMofDocument | ForEach-Object { if ($_.CimClass.CimClassName -eq 'MSFT_ChefInSpecResource') { $profilePath = "$Name/Modules/$($_.Name)" $item = $_.CimInstanceProperties.Item('GithubPath') if ($null -eq $item) { $item = [Microsoft.Management.Infrastructure.CimProperty]::Create('GithubPath', $profilePath, [Microsoft.Management.Infrastructure.CimFlags]::Property) $_.CimInstanceProperties.Add($item) } else { $item.Value = $profilePath } } } return $resourcesInMofDocument } #EndRegion './Private/Get-GuestConfigurationMofContent.ps1' 39 #Region './Private/Get-ParameterDefinition.ps1' 0 <# .SYNOPSIS Define the parmameters of a policy for Audit or Deploy. .PARAMETER ParameterInfo A list of hashtables indicating the necessary info for parameters that need to be passed into this Guest Configuration Assignment. #> function Get-ParameterDefinition { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [Hashtable[]]$ParameterInfo ) $paramDefinition = [Ordered]@{} foreach ($item in $ParameterInfo) { $paramDefinition[$($item.ReferenceName)] = @{ type = $item.Type metadata = [Ordered]@{ displayName = $item.DisplayName description = $item.Description } } if ($item.ContainsKey('AllowedValues')) { $paramDefinition[$($item.ReferenceName)]['allowedValues'] = $item.AllowedValues } if ($item.ContainsKey('DefaultValue')) { $paramDefinition[$($item.ReferenceName)]['defaultValue'] = $item.DefaultValue } } return $paramDefinition } #EndRegion './Private/Get-ParameterDefinition.ps1' 40 #Region './Private/Get-ParameterMappingForAINE.ps1' 0 <# .SYNOPSIS Define the policy parameter mapping to the parameters of the MOF file. .PARAMETER ParameterInfo A list of hashtables indicating the necessary info for parameters that need to be passed into this Guest Configuration Assignment. #> function Get-ParameterMappingForAINE { [CmdletBinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] param ( [Parameter(Mandatory = $true)] [array] $ParameterInfo ) $paramMapping = @{} foreach ($item in $ParameterInfo) { $paramMapping[$item.ReferenceName] = ("{0};{1}" -f $item.MofResourceReference, $item.MofParameterName) } return $paramMapping } #EndRegion './Private/Get-ParameterMappingForAINE.ps1' 28 #Region './Private/Get-ParameterMappingForDINE.ps1' 0 <# .SYNOPSIS Define the policy parameter mapping to the parameters of the MOF file. Expected output should follow the following format: { "name": "[MyFile]createFoobarTestFile;path", "value": "[parameters('path')]" }, { "name": "[MyFile]createFoobarTestFile;ensure", "value": "[parameters('ensure')]" }, { "name": "[MyFile]createFoobarTestFile;content", "value": "[parameters('content')]" } .PARAMETER ParameterInfo A list of hashtables indicating the necessary info for parameters that need to be passed into this Guest Configuration Assignment. #> function Get-ParameterMappingForDINE { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [array] $ParameterInfo ) $paramMapping = @() foreach ($item in $ParameterInfo) { $parameterPair = @{ "name" = ("{0};{1}" -f $item.MofResourceReference, $item.MofParameterName) "value" = ("[parameters('{0}')]" -f $item.ReferenceName) } $paramMapping += $parameterPair } return $paramMapping } #EndRegion './Private/Get-ParameterMappingForDINE.ps1' 45 #Region './Private/New-GuestConfigurationAuditPolicyDefinition.ps1' 0 <# .SYNOPSIS Creates a new audit policy definition for a guest configuration policy. #> function New-GuestConfigurationAuditPolicyDefinition { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $FileName, [Parameter(Mandatory = $true)] [String] $FolderPath, [Parameter(Mandatory = $true)] [String] $DisplayName, [Parameter(Mandatory = $true)] [String] $Description, [Parameter(Mandatory = $true)] [String] $ConfigurationName, [Parameter(Mandatory = $true)] [String] $ConfigurationVersion, [Parameter(Mandatory = $true)] [String] $ReferenceId, [Parameter()] [Hashtable[]] $ParameterInfo, [Parameter()] [String] $ContentUri, [Parameter()] [String] $ContentHash, [AssignmentType] $AssignmentType, [Parameter()] [bool] $UseCertificateValidation = $false, [Parameter()] [String] $Category = 'Guest Configuration', [Parameter(Mandatory = $true)] [ValidateNotNull()] [String] $Guid, [Parameter(Mandatory = $true)] [ValidateSet('Windows', 'Linux')] [String] $Platform, [Parameter()] [Hashtable[]] $Tag ) $filePath = Join-Path -Path $FolderPath -ChildPath $FileName Write-Verbose -Message "Creating Guest Configuration Audit Policy Definition to '$filePath'." $auditPolicyGuid = $Guid $ParameterMapping = @{ } $ParameterDefinitions = @{ } $auditPolicyContentHashtable = [Ordered]@{ } if ($null -ne $ParameterInfo) { $ParameterMapping = Get-ParameterMappingForAINE -ParameterInfo $ParameterInfo $ParameterDefinitions = Get-ParameterDefinition -ParameterInfo $ParameterInfo } $ParameterDefinitions['IncludeArcMachines'] += [Ordered]@{ type = "string" metadata = [Ordered]@{ displayName = 'Include Arc connected servers' description = 'By selecting this option, you agree to be charged monthly per Arc connected machine.' } allowedValues = @('True', 'False') defaultValue = 'False' } $auditPolicyContentHashtable = [Ordered]@{ properties = [Ordered]@{ displayName = $DisplayName policyType = 'Custom' mode = 'All' description = $Description metadata = [Ordered]@{ category = $Category guestConfiguration = [Ordered]@{ name = $ConfigurationName version = $ConfigurationVersion contentType = "Custom" contentUri = $ContentUri contentHash = $ContentHash configurationParameter = $ParameterMapping } } parameters = $ParameterDefinitions } id = "/providers/Microsoft.Authorization/policyDefinitions/$auditPolicyGuid" name = $auditPolicyGuid } $policyRuleHashtable = [Ordered]@{ if = [Ordered]@{ anyOf = @( [Ordered]@{ allOf = @( [Ordered]@{ field = 'type' equals = "Microsoft.Compute/virtualMachines" } ) }, [Ordered]@{ allOf = @( [Ordered]@{ value = "[parameters('IncludeArcMachines')]" equals = "true" }, [Ordered]@{ field = "type" equals = "Microsoft.HybridCompute/machines" } ) } ) } then = [Ordered]@{ effect = 'auditIfNotExists' details = [Ordered]@{ type = 'Microsoft.GuestConfiguration/guestConfigurationAssignments' name = $ConfigurationName } } } if ($Platform -ieq 'Windows') { $policyRuleHashtable['if']['anyOf'][0]['allOf'] += @( [Ordered]@{ anyOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" in = @( 'esri', 'incredibuild', 'MicrosoftDynamicsAX', 'MicrosoftSharepoint', 'MicrosoftVisualStudio', 'MicrosoftWindowsDesktop', 'MicrosoftWindowsServerHPCPack' ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'MicrosoftWindowsServer' }, [Ordered]@{ field = "Microsoft.Compute/imageSKU" notLike = '2008*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'MicrosoftSQLServer' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" notLike = 'SQL2008*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'microsoft-dsvm' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" equals = 'dsvm-windows' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'microsoft-ads' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" in = @( 'standard-data-science-vm', 'windows-data-science-vm' ) } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'batch' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" equals = 'rendering-windows2016' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'center-for-internet-security-inc' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" like = 'cis-windows-server-201*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'pivotal' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" like = 'bosh-windows-server*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'cloud-infrastructure-services' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" like = 'ad*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ anyOf = @( [Ordered]@{ field = "Microsoft.Compute/virtualMachines/osProfile.windowsConfiguration" exists = 'true' }, [Ordered]@{ field = "Microsoft.Compute/virtualMachines/storageProfile.osDisk.osType" like = 'Windows*' } ) }, [Ordered]@{ anyOf = @( [Ordered]@{ field = "Microsoft.Compute/imageSKU" exists = 'false' }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imageSKU" notLike = '2008*' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" notLike = 'SQL2008*' } ) } ) } ) } ) } ) $policyRuleHashtable['if']['anyOf'][1]['allOf'] += @( [Ordered]@{ field = "Microsoft.HybridCompute/imageOffer" like = "windows*" } ) } elseif ($Platform -ieq 'Linux') { $policyRuleHashtable['if']['anyOf'][0]['allOf'] += @( [Ordered]@{ anyOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" in = @( 'microsoft-aks', 'qubole-inc', 'datastax', 'couchbase', 'scalegrid', 'checkpoint', 'paloaltonetworks' ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'OpenLogic' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" like = 'CentOS*' }, [Ordered]@{ field = "Microsoft.Compute/imageSKU" notLike = '6*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" equals = 'Oracle' }, [Ordered]@{ field = "Microsoft.Compute/imageOffer" equals = 'Oracle-Linux' }, [Ordered]@{ field = "Microsoft.Compute/imageSKU" notLike = '6*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'RedHat' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' in = @( 'RHEL', 'RHEL-HA' 'RHEL-SAP', 'RHEL-SAP-APPS', 'RHEL-SAP-HA', 'RHEL-SAP-HANA' ) }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '6*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'RedHat' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' in = @( 'osa', 'rhel-byos' ) } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'center-for-internet-security-inc' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' in = @( 'cis-centos-7-l1', 'cis-centos-7-v2-1-1-l1' 'cis-centos-8-l1', 'cis-debian-linux-8-l1', 'cis-debian-linux-9-l1', 'cis-nginx-centos-7-v1-1-0-l1', 'cis-oracle-linux-7-v2-0-0-l1', 'cis-oracle-linux-8-l1', 'cis-postgresql-11-centos-linux-7-level-1', 'cis-rhel-7-l2', 'cis-rhel-7-v2-2-0-l1', 'cis-rhel-8-l1', 'cis-suse-linux-12-v2-0-0-l1', 'cis-ubuntu-linux-1604-v1-0-0-l1', 'cis-ubuntu-linux-1804-l1' ) } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'credativ' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'Debian' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '7*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'Suse' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' like = 'SLES*' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '11*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'Canonical' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'UbuntuServer' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '12*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'microsoft-dsvm' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' in = @( 'linux-data-science-vm-ubuntu', 'azureml' ) } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'cloudera' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'cloudera-centos-os' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '6*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'cloudera' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'cloudera-altus-centos-os' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'microsoft-ads' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' like = 'linux*' } ) } ) } ) $policyRuleHashtable['if']['anyOf'][1]['allOf'] += @( [Ordered]@{ field = "Microsoft.HybridCompute/imageOffer" like = "linux*" } ) $policyRuleHashtable['if']['anyOf'][1]['allOf'] += @( [Ordered]@{ field = 'Microsoft.HybridCompute/imageOffer' like = 'linux*' } ) $policyRuleHashtable['if']['anyOf'][1]['allOf'] += @( [Ordered]@{ field = "Microsoft.HybridCompute/imageOffer" like = "linux*" } ) } else { throw "The specified platform '$Platform' is not currently supported by this script." } # if there is atleast one tag if ($PSBoundParameters.ContainsKey('Tag') -AND $null -ne $Tag) { # capture existing 'anyOf' section $anyOf = $policyRuleHashtable['if'] # replace with new 'allOf' at top order $policyRuleHashtable['if'] = [Ordered]@{ allOf = @( ) } # add tags section under new 'allOf' $policyRuleHashtable['if']['allOf'] += [Ordered]@{ allOf = @( ) } # re-insert 'anyOf' under new 'allOf' after tags 'allOf' $policyRuleHashtable['if']['allOf'] += $anyOf # add each tag individually to tags 'allOf' for ($i = 0; $i -lt $Tag.count; $i++) { # if there is atleast one tag if (-not [string]::IsNullOrEmpty($Tag[$i].Keys)) { $policyRuleHashtable['if']['allOf'][0]['allOf'] += [Ordered]@{ field = "tags.$($Tag[$i].Keys)" equals = "$($Tag[$i].Values)" } } } } $existenceConditionList = [Ordered]@{ allOf = [System.Collections.ArrayList]@() } $existenceConditionList['allOf'].Add([Ordered]@{ field = 'Microsoft.GuestConfiguration/guestConfigurationAssignments/complianceStatus' equals = 'Compliant' }) if ($null -ne $ParameterInfo) { $parametersExistenceCondition = Get-GuestConfigurationAssignmentParametersExistenceConditionSection -ParameterInfo $ParameterInfo $existenceConditionList['allOf'].Add($parametersExistenceCondition) } $policyRuleHashtable['then']['details']['existenceCondition'] = $existenceConditionList $auditPolicyContentHashtable['properties']['policyRule'] = $policyRuleHashtable $auditPolicyContent = ConvertTo-Json -InputObject $auditPolicyContentHashtable -Depth 100 | ForEach-Object { [System.Text.RegularExpressions.Regex]::Unescape($_) } $formattedAuditPolicyContent = Format-Json -Json $auditPolicyContent if (Test-Path -Path $filePath) { Write-Error -Message "A file at the policy destination path '$filePath' already exists. Please remove this file or specify a different destination path." } else { $null = New-Item -Path $filePath -ItemType 'File' -Value $formattedAuditPolicyContent } return $auditPolicyGuid } #EndRegion './Private/New-GuestConfigurationAuditPolicyDefinition.ps1' 636 #Region './Public/New-CustomGuestConfigPolicy.ps1' 0 function New-CustomGuestConfigPolicy { [CmdletBinding()] [OutputType([String])] param ( [Parameter(Mandatory = $true)] [String] $PolicyFolderPath, [Parameter(Mandatory = $true)] [Hashtable] $PolicyInfo ) Write-Verbose -Message "Getting Policy Definitions from Current Context." $existingPolicies = Get-AzPolicyDefinition # policy.name is actually the policy id $existingAuditPolicy = $existingPolicies | Where-Object -FilterScript { ($_.name -eq $PolicyInfo.guid) } if ($null -ne $existingAuditPolicy) { Write-Verbose -Message "Policy with specified guid '$($existingAuditPolicy.Name)' already exists. Overwriting: '$($existingAuditPolicy.Properties.displayName)' ..." } New-GuestConfigurationPolicyDefinition @PSBoundParameters } #EndRegion './Public/New-CustomGuestConfigPolicy.ps1' 32 #Region './Public/New-GuestConfigurationDeployPolicyDefinition.ps1' 0 function New-GuestConfigurationDeployPolicyDefinition { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $FileName, [Parameter(Mandatory = $true)] [String] $FolderPath, [Parameter(Mandatory = $true)] [String] $DisplayName, [Parameter(Mandatory = $true)] [String] $Description, [Parameter(Mandatory = $true)] [String] $ConfigurationName, [Parameter(Mandatory = $true)] [String] $ConfigurationVersion, [Parameter(Mandatory = $true)] [String] $ContentUri, [Parameter(Mandatory = $true)] [String] $ContentHash, [Parameter()] [AssignmentType] $AssignmentType, [Parameter(Mandatory = $true)] [String] $ReferenceId, [Parameter()] [Hashtable[]] $ParameterInfo, [Parameter(Mandatory = $true)] [ValidateNotNull()] [String] $Guid, [Parameter(Mandatory = $true)] [ValidateSet('Windows', 'Linux')] [String] $Platform, [Parameter()] [bool] $UseCertificateValidation = $false, [Parameter()] [String] $Category = 'Guest Configuration', [Parameter()] [Hashtable[]] $Tag ) $filePath = Join-Path -Path $FolderPath -ChildPath $FileName Write-Verbose -Message "Creating Guest Configuration Deploy Policy Definition to '$filePath'." $deployPolicyGuid = $Guid $ParameterMapping = @() $ParameterDefinitions = @{} $PolicyContentHashtable = [Ordered]@{} $existenceConditionList = [Ordered]@{ allOf = [System.Collections.ArrayList]@() } $MetadataParameterMapping = @{} if ($null -ne $ParameterInfo) { $ParameterMapping += Get-ParameterMappingForDINE -ParameterInfo $ParameterInfo $ParameterDefinitions = Get-ParameterDefinition -ParameterInfo $ParameterInfo $MetadataParameterMapping = Get-ParameterMappingForAINE -ParameterInfo $ParameterInfo } $ParameterDefinitions['IncludeArcMachines'] += [Ordered]@{ type = "string" metadata = [Ordered]@{ displayName = 'Include Arc connected servers' description = 'By selecting this option, you agree to be charged monthly per Arc connected machine.' } allowedValues = @('True', 'False') defaultValue = 'False' } $deployPolicyContentHashtable = [Ordered]@{ properties = [Ordered]@{ displayName = $DisplayName policyType = 'Custom' mode = 'Indexed' description = $Description metadata = [Ordered]@{ version = $ConfigurationVersion category = $Category guestConfiguration = [Ordered]@{ name = $ConfigurationName version = $ConfigurationVersion contentType = "Custom" contentUri = $ContentUri contentHash = $ContentHash configurationParameter = $MetadataParameterMapping } requiredProviders = @( 'Microsoft.GuestConfiguration' ) } parameters = $ParameterDefinitions } } $policyRuleHashtable = [Ordered]@{ if = [Ordered]@{ anyOf = @( [Ordered]@{ allOf = @( [Ordered]@{ field = 'type' equals = "Microsoft.Compute/virtualMachines" } ) }, [Ordered]@{ allOf = @( [Ordered]@{ value = "[parameters('IncludeArcMachines')]" equals = "true" }, [Ordered]@{ field = "type" equals = "Microsoft.HybridCompute/machines" } ) } ) } then = [Ordered]@{ effect = 'deployIfNotExists' details = [Ordered]@{ type = 'Microsoft.GuestConfiguration/guestConfigurationAssignments' name = $ConfigurationName roleDefinitionIds = @('/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c') } } } $deploymentHashtable = [Ordered]@{ properties = [Ordered]@{ mode = 'incremental' parameters = [Ordered]@{ vmName = [Ordered]@{ value = "[field('name')]" } location = [Ordered]@{ value = "[field('location')]" } type = [Ordered]@{ value = "[field('type')]" } configurationName = [Ordered]@{ value = $ConfigurationName } contentUri = [Ordered]@{ value = $ContentUri } contentHash = [Ordered]@{ value = $ContentHash } } template = [Ordered]@{ '$schema' = 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#' contentVersion = '1.0.0.0' parameters = [Ordered]@{ vmName = [Ordered]@{ type = 'string' } location = [Ordered]@{ type = 'string' } type = [Ordered]@{ type = 'string' } configurationName = [Ordered]@{ type = 'string' } contentUri = [Ordered]@{ type = 'string' } contentHash = [Ordered]@{ type = 'string' } } resources = @() } } } $guestConfigurationAssignmentHashtable = @( # Compute [Ordered]@{ condition = "[equals(toLower(parameters('type')), toLower('Microsoft.Compute/virtualMachines'))]" apiVersion = '2018-11-20' type = 'Microsoft.Compute/virtualMachines/providers/guestConfigurationAssignments' name = "[concat(parameters('vmName'), '/Microsoft.GuestConfiguration/', parameters('configurationName'))]" location = "[parameters('location')]" properties = [Ordered]@{ guestConfiguration = [Ordered]@{ name = "[parameters('configurationName')]" version = $ConfigurationVersion contentUri = "[parameters('contentUri')]" contentHash = "[parameters('contentHash')]" assignmentType = "$AssignmentType" configurationParameter = $ParameterMapping } } } # Hybrid Compute [Ordered]@{ condition = "[equals(toLower(parameters('type')), toLower('microsoft.hybridcompute/machines'))]" apiVersion = '2018-11-20' type = 'Microsoft.HybridCompute/machines/providers/guestConfigurationAssignments' name = "[concat(parameters('vmName'), '/Microsoft.GuestConfiguration/', parameters('configurationName'))]" location = "[parameters('location')]" properties = [Ordered]@{ guestConfiguration = [Ordered]@{ name = "[parameters('configurationName')]" contentUri = "[parameters('contentUri')]" contentHash = "[parameters('contentHash')]" assignmentType = "$AssignmentType" version = $ConfigurationVersion configurationParameter = $ParameterMapping } } } ) if ($Platform -ieq 'Windows') { $policyRuleHashtable['if']['anyOf'][0]['allOf'] += @( [Ordered]@{ anyOf = @( [Ordered]@{ field = "Microsoft.Compute/imagePublisher" in = @( 'esri', 'incredibuild', 'MicrosoftDynamicsAX', 'MicrosoftSharepoint', 'MicrosoftVisualStudio', 'MicrosoftWindowsDesktop', 'MicrosoftWindowsServerHPCPack' ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'MicrosoftWindowsServer' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '2008*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'MicrosoftSQLServer' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' notLike = 'SQL2008*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'microsoft-dsvm' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'dsvm-windows' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'microsoft-ads' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' in = @( 'standard-data-science-vm', 'windows-data-science-vm' ) } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'batch' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'rendering-windows2016' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'center-for-internet-security-inc' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' like = 'cis-windows-server-201*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'pivotal' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' like = 'bosh-windows-server*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'cloud-infrastructure-services' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' like = 'ad*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ anyOf = @( [Ordered]@{ field = 'Microsoft.Compute/virtualMachines/osProfile.windowsConfiguration' exists = 'true' }, [Ordered]@{ field = 'Microsoft.Compute/virtualMachines/storageProfile.osDisk.osType' like = 'Windows*' } ) }, [Ordered]@{ anyOf = @( [Ordered]@{ field = 'Microsoft.Compute/imageSKU' exists = 'false' }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '2008*' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' notLike = 'SQL2008*' } ) } ) } ) } ) } ) $policyRuleHashtable['if']['anyOf'][1]['allOf'] += @( [Ordered]@{ field = 'Microsoft.HybridCompute/imageOffer' like = 'windows*' } ) } elseif ($Platform -ieq 'Linux') { $policyRuleHashtable['if']['anyOf'][0]['allOf'] += @( [Ordered]@{ anyOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' in = @( 'microsoft-aks', 'qubole-inc', 'datastax', 'couchbase', 'scalegrid', 'checkpoint', 'paloaltonetworks' ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'OpenLogic' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' like = 'CentOS*' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '6*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'Oracle' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'Oracle-Linux' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '6*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'RedHat' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' in = @( 'RHEL', 'RHEL-HA' 'RHEL-SAP', 'RHEL-SAP-APPS', 'RHEL-SAP-HA', 'RHEL-SAP-HANA' ) }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '6*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'RedHat' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' in = @( 'osa', 'rhel-byos' ) } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'center-for-internet-security-inc' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' in = @( 'cis-centos-7-l1', 'cis-centos-7-v2-1-1-l1' 'cis-centos-8-l1', 'cis-debian-linux-8-l1', 'cis-debian-linux-9-l1', 'cis-nginx-centos-7-v1-1-0-l1', 'cis-oracle-linux-7-v2-0-0-l1', 'cis-oracle-linux-8-l1', 'cis-postgresql-11-centos-linux-7-level-1', 'cis-rhel-7-l2', 'cis-rhel-7-v2-2-0-l1', 'cis-rhel-8-l1', 'cis-suse-linux-12-v2-0-0-l1', 'cis-ubuntu-linux-1604-v1-0-0-l1', 'cis-ubuntu-linux-1804-l1' ) } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'credativ' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'Debian' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '7*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'Suse' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' like = 'SLES*' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '11*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'Canonical' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'UbuntuServer' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '12*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'microsoft-dsvm' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' in = @( 'linux-data-science-vm-ubuntu', 'azureml' ) } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'cloudera' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'cloudera-centos-os' }, [Ordered]@{ field = 'Microsoft.Compute/imageSKU' notLike = '6*' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'cloudera' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' equals = 'cloudera-altus-centos-os' } ) }, [Ordered]@{ allOf = @( [Ordered]@{ field = 'Microsoft.Compute/imagePublisher' equals = 'microsoft-ads' }, [Ordered]@{ field = 'Microsoft.Compute/imageOffer' like = 'linux*' } ) } ) } ) $policyRuleHashtable['if']['anyOf'][1]['allOf'] += @( [Ordered]@{ field = "Microsoft.HybridCompute/imageOffer" like = "linux*" } ) $policyRuleHashtable['if']['anyOf'][1]['allOf'] += @( [Ordered]@{ field = 'Microsoft.HybridCompute/imageOffer' like = 'linux*' } ) } else { throw "The specified platform '$Platform' is not currently supported by this script." } # If there is at least one tag if ($PSBoundParameters.ContainsKey('Tag') -AND $null -ne $Tag) { # Capture existing 'anyOf' section $anyOf = $policyRuleHashtable['if'] # Replace with new 'allOf' at top order $policyRuleHashtable['if'] = [Ordered]@{ allOf = @( ) } # Add tags section under new 'allOf' $policyRuleHashtable['if']['allOf'] += [Ordered]@{ allOf = @( ) } # Re-insert 'anyOf' under new 'allOf' after tags 'allOf' $policyRuleHashtable['if']['allOf'] += $anyOf # Add each tag individually to tags 'allOf' for ($i = 0; $i -lt $Tag.count; $i++) { # If there is at least one tag if (-not [string]::IsNullOrEmpty($Tag[$i].Keys)) { $policyRuleHashtable['if']['allOf'][0]['allOf'] += [Ordered]@{ field = "tags.$($Tag[$i].Keys)" equals = "$($Tag[$i].Values)" } } } } # Handle adding parameters if needed if ($null -ne $ParameterInfo -and $ParameterInfo.Count -gt 0) { $parameterValueConceatenatedStringList = @() if (-not $deployPolicyContentHashtable['properties'].Contains('parameters')) { $deployPolicyContentHashtable['properties']['parameters'] = [Ordered]@{ } } foreach ($guestConfigurationAssignment in $guestConfigurationAssignmentHashtable) { if (-not $guestConfigurationAssignment['properties']['guestConfiguration'].Contains('configurationParameter')) { $guestConfigurationAssignment['properties']['guestConfiguration']['configurationParameter'] = @() } } # Parameter Hash Section $parameterValueConceatenatedStringList = @() foreach ($parameterPair in $ParameterMapping) { $name = $parameterPair.name $value = $parameterPair.value -replace "[][]","" $currentParameterValueConcatenatedString = "'$name', '=', $value" $parameterValueConceatenatedStringList += $currentParameterValueConcatenatedString } $allParameterValueConcantenatedString = $parameterValueConceatenatedStringList -join ", ',', " $parameterExistenceConditionEqualsValue = "[base64(concat($allParameterValueConcantenatedString))]" $existenceConditionList['allOf'].Add([Ordered]@{ field = 'Microsoft.GuestConfiguration/guestConfigurationAssignments/parameterHash' equals = $parameterExistenceConditionEqualsValue }) # Adding parameters into the deploymentHashTable foreach ($currentParameterInfo in $parameterInfo) { # Add values in Deployment > Properties > Parameter section if ($currentParameterInfo.ContainsKey('DeploymentValue')) { $deploymentHashtable['properties']['parameters'] += [Ordered]@{ $currentParameterInfo.ReferenceName = [Ordered]@{ value = $currentParameterInfo.DeploymentValue } } } else { $deploymentHashtable['properties']['parameters'] += [Ordered]@{ $currentParameterInfo.ReferenceName = [Ordered]@{ value = "[parameters('$($currentParameterInfo.ReferenceName)')]" } } } # Add Type to Deployment > Properties > Template > Parameters section $deploymentHashtable['properties']['template']['parameters'] += [Ordered]@{ $currentParameterInfo.ReferenceName = [Ordered]@{ type = $currentParameterInfo.Type } } } } # Existence Condition section $existenceConditionList['allOf'].Add([Ordered]@{ field = 'Microsoft.GuestConfiguration/guestConfigurationAssignments/contentHash' equals = "$ContentHash" }) $existenceConditionList['allOf'].Add([Ordered]@{ field = 'Microsoft.GuestConfiguration/guestConfigurationAssignments/complianceStatus' equals = 'Compliant' }) $policyRuleHashtable['then']['details']['existenceCondition'] = $existenceConditionList # Deployment Section $policyRuleHashtable['then']['details']['deployment'] = $deploymentHashtable $policyRuleHashtable['then']['details']['deployment']['properties']['template']['resources'] += $guestConfigurationAssignmentHashtable $deployPolicyContentHashtable['properties']['policyRule'] = $policyRuleHashtable $deployPolicyContentHashtable += [Ordered]@{ id = "/providers/Microsoft.Authorization/policyDefinitions/$deployPolicyGuid" type = "Microsoft.Authorization/policyDefinitions" name = $deployPolicyGuid } $deployPolicyContent = ConvertTo-Json -InputObject $deployPolicyContentHashtable -Depth 100 | ForEach-Object { [System.Text.RegularExpressions.Regex]::Unescape($_) } $formattedDeployPolicyContent = Format-Json -Json $deployPolicyContent if (Test-Path -Path $filePath) { Write-Error -Message "A file at the policy destination path '$filePath' already exists. Please remove this file or specify a different destination path." } else { $null = New-Item -Path $filePath -ItemType 'File' -Value $formattedDeployPolicyContent } return $deployPolicyGuid } #EndRegion './Public/New-GuestConfigurationDeployPolicyDefinition.ps1' 795 #Region './Public/New-GuestConfigurationPolicyDefinition.ps1' 0 <# .SYNOPSIS Creates a new policy for guest configuration. .PARAMETER PolicyFolderPath Folder where policy exists. .PARAMETER PolicyInfo Policy information. .EXAMPLE $PolicyInfo = @{ FileName = $FileName DisplayName = $DisplayName Description = $Description Platform = $Platform ConfigurationName = $policyName ConfigurationVersion = $Version ContentUri = $ContentUri ContentHash = $contentHash AssignmentType = $Mode ReferenceId = "Deploy_$policyName" ParameterInfo = $ParameterInfo UseCertificateValidation = $packageIsSigned Category = $Category Tag = $Tag } New-GuestConfigurationPolicyDefinition -PolicyFolderPath $policyDefinitionsPath -PolicyInfo $PolicyInfo #> function New-GuestConfigurationPolicyDefinition { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $PolicyFolderPath, [Parameter(Mandatory = $true)] [Hashtable] $PolicyInfo ) Write-Verbose -Message "Creating new Guest Configuration Policy to '$PolicyFolderPath'." if (Test-Path -Path $PolicyFolderPath) { $null = Remove-Item -Path $PolicyFolderPath -Force -Recurse -ErrorAction 'SilentlyContinue' } $null = New-Item -Path $PolicyFolderPath -ItemType 'Directory' if ($PolicyInfo.FileName -eq 'DeployIfNotExists.json') { foreach ($currentDeployPolicyInfo in $PolicyInfo) { $currentDeployPolicyInfo['FolderPath'] = $PolicyFolderPath New-GuestConfigurationDeployPolicyDefinition @currentDeployPolicyInfo } } else { foreach ($currentAuditPolicyInfo in $PolicyInfo) { $currentAuditPolicyInfo['FolderPath'] = $PolicyFolderPath New-GuestConfigurationAuditPolicyDefinition @currentAuditPolicyInfo } } } #EndRegion './Public/New-GuestConfigurationPolicyDefinition.ps1' 72 #Region './Public/Save-GuestConfigurationMofDocument.ps1' 0 function Save-GuestConfigurationMofDocument { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $Name, [Parameter(Mandatory = $true)] [String] $SourcePath, [Parameter(Mandatory = $true)] [String] $DestinationPath ) $resourcesInMofDocument = Get-GuestConfigurationMofContent -Name $Name -Path $SourcePath # if mof contains Chef resource if ($resourcesInMofDocument.CimSystemProperties.ClassName -contains 'MSFT_ChefInSpecResource') { Write-Verbose -Message "Serialize DSC document to $DestinationPath path ..." $content = '' for ($i = 0; $i -lt $resourcesInMofDocument.Count; $i++) { $resourceClassName = $resourcesInMofDocument[$i].CimSystemProperties.ClassName $content += "instance of $resourceClassName" if ($resourceClassName -ne 'OMI_ConfigurationDocument') { $content += ' as $' + "$resourceClassName$i" } $content += "`n{`n" $resourcesInMofDocument[$i].CimInstanceProperties | ForEach-Object { $content += " $($_.Name)" if ($_.CimType -eq 'StringArray') { $content += " = {""$($_.Value -replace '[""\\]','\$&')""}; `n" } else { $content += " = ""$($_.Value -replace '[""\\]','\$&')""; `n" } } $content += "};`n" ; } $content | Out-File $DestinationPath } else { Write-Verbose "Copy DSC document to $DestinationPath path ..." Copy-Item $SourcePath $DestinationPath } } #EndRegion './Public/Save-GuestConfigurationMofDocument.ps1' 60 #Region './Public/Test-GuestConfigurationMofResourceDependencies.ps1' 0 function Test-GuestConfigurationMofResourceDependencies { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $Path ) $resourcesInMofDocument = [Microsoft.PowerShell.DesiredStateConfiguration.Internal.DscClassCache]::ImportInstances($Path, 4) for ($i = 0; $i -lt $resourcesInMofDocument.Count; $i++) { if ($resourcesInMofDocument[$i].CimInstanceProperties.Name -contains 'ModuleName' -and $resourcesInMofDocument[$i].ModuleName -ne 'GuestConfiguration') { if ($resourcesInMofDocument[$i].ModuleName -ieq 'PsDesiredStateConfiguration') { throw "'PsDesiredStateConfiguration' module is not supported by GuestConfiguration. Please use 'PSDSCResources' module instead of 'PsDesiredStateConfiguration' module in DSC configuration." } $configurationName = $resourcesInMofDocument[$i].ConfigurationName Write-Warning -Message "The configuration '$configurationName' is using one or more resources outside of the GuestConfiguration module. Please make sure these resources work with PowerShell Core" break } } } #EndRegion './Public/Test-GuestConfigurationMofResourceDependencies.ps1' 28 #Region './Public/Update-MofDocumentParameters.ps1' 0 function Update-MofDocumentParameters { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $Path, [Parameter()] [Hashtable[]] $Parameter ) if ($Parameter.Count -eq 0) { return } $resourcesInMofDocument = [Microsoft.PowerShell.DesiredStateConfiguration.Internal.DscClassCache]::ImportInstances($Path, 4) foreach ($parmInfo in $Parameter) { if (-not $parmInfo.Contains('ResourceType')) { throw "Policy parameter is missing a mandatory property 'ResourceType'. Please make sure that configuration resource type is specified in configuration parameter." } if (-not $parmInfo.Contains('ResourceId')) { throw "Policy parameter is missing a mandatory property 'ResourceId'. Please make sure that configuration resource Id is specified in configuration parameter." } if (-not $parmInfo.Contains('ResourcePropertyName')) { throw "Policy parameter is missing a mandatory property 'ResourcePropertyName'. Please make sure that configuration resource property name is specified in configuration parameter." } if (-not $parmInfo.Contains('ResourcePropertyValue')) { throw "Policy parameter is missing a mandatory property 'ResourcePropertyValue'. Please make sure that configuration resource property value is specified in configuration parameter." } $resourceId = "[$($parmInfo.ResourceType)]$($parmInfo.ResourceId)" if ($null -eq ( $resourcesInMofDocument | Where-Object { ($_.CimInstanceProperties.Name -contains 'ResourceID') -and ($_.CimInstanceProperties['ResourceID'].Value -eq $resourceId) -and ($_.CimInstanceProperties.Name -contains $parmInfo.ResourcePropertyName) }) ) { throw "Failed to find parameter reference in the configuration '$Path'. Please make sure parameter with ResourceType:'$($parmInfo.ResourceType)', ResourceId:'$($parmInfo.ResourceId)' and ResourcePropertyName:'$($parmInfo.ResourcePropertyName)' exist in the configuration." } Write-Verbose "Updating configuration parameter for $resourceId ..." $resourcesInMofDocument | ForEach-Object { if (($_.CimInstanceProperties.Name -contains 'ResourceID') -and ($_.CimInstanceProperties['ResourceID'].Value -eq $resourceId)) { $item = $_.CimInstanceProperties.Item($parmInfo.ResourcePropertyName) $item.Value = $parmInfo.ResourcePropertyValue } } } Write-Verbose "Saving configuration file '$Path' with updated parameters ..." $content = "" for ($i = 0; $i -lt $resourcesInMofDocument.Count; $i++) { $resourceClassName = $resourcesInMofDocument[$i].CimSystemProperties.ClassName $content += "instance of $resourceClassName" if ($resourceClassName -ne 'OMI_ConfigurationDocument') { $content += ' as $' + "$resourceClassName$i" } $content += "`n{`n" $resourcesInMofDocument[$i].CimInstanceProperties | ForEach-Object { $content += " $($_.Name)" if ($_.CimType -eq 'StringArray') { $content += " = {""$($_.Value -replace '[""\\]','\$&')""}; `n" } else { $content += " = ""$($_.Value -replace '[""\\]','\$&')""; `n" } } $content += "};`n" ; } $content | Out-File $Path } #EndRegion './Public/Update-MofDocumentParameters.ps1' 96 #Region './Public/Update-PolicyParameter.ps1' 0 function Update-PolicyParameter { [CmdletBinding()] param ( [Parameter()] [Hashtable[]] $parameter ) $updatedParameterInfo = @() foreach ($parmInfo in $Parameter) { $param = @{ } $param['Type'] = 'string' if ($parmInfo.Contains('Name')) { $param['ReferenceName'] = $parmInfo.Name } else { throw "Policy parameter is missing a mandatory property 'Name'. Please make sure that parameter name is specified in Policy parameter." } if ($parmInfo.Contains('DisplayName')) { $param['DisplayName'] = $parmInfo.DisplayName } else { throw "Policy parameter is missing a mandatory property 'DisplayName'. Please make sure that parameter display name is specified in Policy parameter." } if ($parmInfo.Contains('Description')) { $param['Description'] = $parmInfo.Description } if (-not $parmInfo.Contains('ResourceType')) { throw "Policy parameter is missing a mandatory property 'ResourceType'. Please make sure that configuration resource type is specified in Policy parameter." } elseif (-not $parmInfo.Contains('ResourceId')) { throw "Policy parameter is missing a mandatory property 'ResourceId'. Please make sure that configuration resource Id is specified in Policy parameter." } else { $param['MofResourceReference'] = "[$($parmInfo.ResourceType)]$($parmInfo.ResourceId)" } if ($parmInfo.Contains('ResourcePropertyName')) { $param['MofParameterName'] = $parmInfo.ResourcePropertyName } else { throw "Policy parameter is missing a mandatory property 'ResourcePropertyName'. Please make sure that configuration resource property name is specified in Policy parameter." } if ($parmInfo.Contains('DefaultValue')) { $param['DefaultValue'] = $parmInfo.DefaultValue } if ($parmInfo.Contains('AllowedValues')) { $param['AllowedValues'] = $parmInfo.AllowedValues } $updatedParameterInfo += $param; } return $updatedParameterInfo } #EndRegion './Public/Update-PolicyParameter.ps1' 78 # SIG # Begin signature block # MIIjhQYJKoZIhvcNAQcCoIIjdjCCI3ICAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDv7JoeVwC2xVDU # cq7w1O+j3Yvat2vgJLtf8cmYZka+IqCCDYEwggX/MIID56ADAgECAhMzAAACUosz # qviV8znbAAAAAAJSMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjEwOTAyMTgzMjU5WhcNMjIwOTAxMTgzMjU5WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDQ5M+Ps/X7BNuv5B/0I6uoDwj0NJOo1KrVQqO7ggRXccklyTrWL4xMShjIou2I # sbYnF67wXzVAq5Om4oe+LfzSDOzjcb6ms00gBo0OQaqwQ1BijyJ7NvDf80I1fW9O # L76Kt0Wpc2zrGhzcHdb7upPrvxvSNNUvxK3sgw7YTt31410vpEp8yfBEl/hd8ZzA # v47DCgJ5j1zm295s1RVZHNp6MoiQFVOECm4AwK2l28i+YER1JO4IplTH44uvzX9o # RnJHaMvWzZEpozPy4jNO2DDqbcNs4zh7AWMhE1PWFVA+CHI/En5nASvCvLmuR/t8 # q4bc8XR8QIZJQSp+2U6m2ldNAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUNZJaEUGL2Guwt7ZOAu4efEYXedEw # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDY3NTk3MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAFkk3 # uSxkTEBh1NtAl7BivIEsAWdgX1qZ+EdZMYbQKasY6IhSLXRMxF1B3OKdR9K/kccp # kvNcGl8D7YyYS4mhCUMBR+VLrg3f8PUj38A9V5aiY2/Jok7WZFOAmjPRNNGnyeg7 # l0lTiThFqE+2aOs6+heegqAdelGgNJKRHLWRuhGKuLIw5lkgx9Ky+QvZrn/Ddi8u # TIgWKp+MGG8xY6PBvvjgt9jQShlnPrZ3UY8Bvwy6rynhXBaV0V0TTL0gEx7eh/K1 # o8Miaru6s/7FyqOLeUS4vTHh9TgBL5DtxCYurXbSBVtL1Fj44+Od/6cmC9mmvrti # yG709Y3Rd3YdJj2f3GJq7Y7KdWq0QYhatKhBeg4fxjhg0yut2g6aM1mxjNPrE48z # 6HWCNGu9gMK5ZudldRw4a45Z06Aoktof0CqOyTErvq0YjoE4Xpa0+87T/PVUXNqf # 7Y+qSU7+9LtLQuMYR4w3cSPjuNusvLf9gBnch5RqM7kaDtYWDgLyB42EfsxeMqwK # WwA+TVi0HrWRqfSx2olbE56hJcEkMjOSKz3sRuupFCX3UroyYf52L+2iVTrda8XW # esPG62Mnn3T8AuLfzeJFuAbfOSERx7IFZO92UPoXE1uEjL5skl1yTZB3MubgOA4F # 8KoRNhviFAEST+nG8c8uIsbZeb08SeYQMqjVEmkwggd6MIIFYqADAgECAgphDpDS # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVWjCCFVYCAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAlKLM6r4lfM52wAAAAACUjAN # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgKClL4boa # BkYFs6VgMxdgwoIJ9aD4bHzbhrV/WeCdVq0wQgYKKwYBBAGCNwIBDDE0MDKgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN # BgkqhkiG9w0BAQEFAASCAQC0U2pjaYLNrrmlUHmTh7AkRI14B60aqIANB0ZoBXe9 # EigsmV2SN7OPNcLHjXb1ZKkNGOE8EYczvTZ8JKffkePcUotduh6+Oyf4E+TEfDZo # zwipb2/oct9GDgetemyB6bf8dVxfgxRQBBMyIJWuqYEflObftKd7Y3tKgw/rZRsD # qnE5vt3BegDN69SkHjiWDagr9NAVRIrjkxwLXiyHgqGEbLLr4nw6PCw87JaEGC37 # lnLmf4jNi3FiqTwb3YD5RkHyLGzAUnny5NEA5HPFSaCwHryXVxldbgdYhHISh6Sc # 2Ey4opuZpdf4GOCX3OrqMIVQfXBHdc9pAqWAyo3zbMbNoYIS5DCCEuAGCisGAQQB # gjcDAwExghLQMIISzAYJKoZIhvcNAQcCoIISvTCCErkCAQMxDzANBglghkgBZQME # AgEFADCCAVAGCyqGSIb3DQEJEAEEoIIBPwSCATswggE3AgEBBgorBgEEAYRZCgMB # MDEwDQYJYIZIAWUDBAIBBQAEIKpmQdbsaypdEEVanbsbuJ6yI4MLSvX2FbPFCP+A # znZoAgZhwM+avWkYEjIwMjIwMTEyMTg0MDU3Ljc4WjAEgAIB9KCB0KSBzTCByjEL # MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v # bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWlj # cm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEmMCQGA1UECxMdVGhhbGVzIFRTUyBF # U046OEE4Mi1FMzRGLTlEREExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1w # IFNlcnZpY2Wggg48MIIE8TCCA9mgAwIBAgITMwAAAUtPsqZI1eTCUQAAAAABSzAN # BgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0y # MDExMTIxODI1NTlaFw0yMjAyMTExODI1NTlaMIHKMQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBP # cGVyYXRpb25zMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo4QTgyLUUzNEYtOURE # QTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCASIwDQYJ # KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKE2elDHdi4mv+K+hs+gu2lD16BQWXxM # d1ZnpIAogl20/cvbgPf93reiaaaNmMLKtCb6P/W0cMDCNAa47Bi+fv15w8JB8AH3 # UmcSn/A/gEwXZJfIx/yT1HzhG2Eh18Yc9dNarOkIJ81aiVURxRWbwB3+vUuuKRE7 # 7goqjqyUNAkqyAoCl8FT/0ntG52+HDWsRDDQ2TUFEZaOsinv+5ahQh9HityXpTW6 # 06JgiicLzs8+kAlBcZGwN0qdUUXg2la8yLJ66Syfm3863DPzawaWd78c1CmYzOKB # Hxxnx5cQMkk0hnGi/1YAcePbyBQTb0PyK8BPvTqKHG9O/nRljxbnW7ECAwEAAaOC # ARswggEXMB0GA1UdDgQWBBRSqmp+0BKW57orct4+VNOfTUrrxjAfBgNVHSMEGDAW # gBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8v # Y3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNUaW1TdGFQQ0Ff # MjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRw # Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0YVBDQV8yMDEw # LTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0G # CSqGSIb3DQEBCwUAA4IBAQAW2rnVlz87UB8kri0QHY2vxsYRUPmpDyXyBchAysxl # i110cf5waKqAX/gaa+Y9+XkUBiH6B//xh3erj+IPb4rgu0luz/e/qanIGXWZDi+6 # wrrl0DKlaaJPVbcWJeOyYIiSNIMOwosUFgfnIYWc0U4QyAv47u7iiwfjZ/zSdzZZ # 2dlXr469bTflc9Xpm21QF8VYd0htSR04bU7afjImbXQ59pwi1nTx/OAwyoT5/9JO # BVY0IdtHYRipNZrKsY/r2MzC1UP0EYZNa2LVeOm8TrIp07wf2e5GLcv4LqNie19o # SYFNudMURX6RHHUI1ylJv2izzoIBR6FlTVpHNDoJD+mPMIIGcTCCBFmgAwIBAgIK # YQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm # aWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcNMjUwNzAxMjE0 # NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD # VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIwDQYJKoZIhvcN # AQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0VBDVpQoAgoX7 # 7XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEwRA/xYIiEVEMM # 1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQedGFnkV+BVLHP # k0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKxXf13Hz3wV3Ws # vYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4GkbaICDXoeByw # 6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEAAaOCAeYwggHi # MBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7fEYbxTNoWoVt # VTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0T # AQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNV # HR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9w # cm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEE # TjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2Nl # cnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0gAQH/BIGVMIGS # MIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93d3cubWljcm9z # b2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYBBQUHAgIwNB4y # IB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUAbQBlAG4AdAAu # IB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOhIW+z66bM9TG+ # zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS+7lTjMz0YBKK # dsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlKkVIArzgPF/Uv # eYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon/VWvL/625Y4z # u2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOiPPp/fZZqkHim # bdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/fmNZJQ96LjlX # dqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCIIYdqwUB5vvfHh # AN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0cs0d9LiFAR6A # +xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7aKLixqduWsqdC # osnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQcdeh0sVV42ne # V8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+NR4Iuto229Nf # j950iEkSoYICzjCCAjcCAQEwgfihgdCkgc0wgcoxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9w # ZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjhBODItRTM0Ri05RERB # MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYF # Kw4DAhoDFQCROjP3t+x4fE05RJDk79sFVIX57qCBgzCBgKR+MHwxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU # aW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUAAgUA5Yj3KjAiGA8yMDIy # MDExMjE0NDM1NFoYDzIwMjIwMTEzMTQ0MzU0WjB3MD0GCisGAQQBhFkKBAExLzAt # MAoCBQDliPcqAgEAMAoCAQACAiDFAgH/MAcCAQACAhBgMAoCBQDlikiqAgEAMDYG # CisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEA # AgMBhqAwDQYJKoZIhvcNAQEFBQADgYEAR0qgK9ymyx2heWWgFKA7013wUXIvYIEn # epG4kiZVmb7Iv+6kBmAkTBBqJ1umkWO+pgQbL0T5HjYW8eV5ts5OAIziPCPloFrx # aBW0/MX4kxGWodvkUPj1w7mt/ATFPMdcdXQ9UCf7OTM6IObsGryr0uu3/Kkv2yoX # OxYZ4ki1ORMxggMNMIIDCQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg # MjAxMAITMwAAAUtPsqZI1eTCUQAAAAABSzANBglghkgBZQMEAgEFAKCCAUowGgYJ # KoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCBViycoJUOs # 79RnhF3m3lmkS/iIpim8GvhVMLLYg3mpOTCB+gYLKoZIhvcNAQkQAi8xgeowgecw # geQwgb0EIGv27oQieexlgS2z8WP+sgW/RhlbXKeFco4/aFU9RTkjMIGYMIGApH4w # fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl # ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMd # TWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAFLT7KmSNXkwlEAAAAA # AUswIgQgRvc1tuu6GqnfnUKME1+ZnRReJDlVaTORRVkd2MgIA24wDQYJKoZIhvcN # AQELBQAEggEAbwEk59dwQXed7umI7lp/78jTKaOuadIDxUNS1oA+0Vknp2u00Gxh # dh0o2i2bQfpMJosw6x9cuqP8pxIYyVfV9wGhf7NCgqhthsM0A2umsF5p9On80Qvn # L7oGSv+oYlqVufhQS3gkA2a6o5Re1SLnJyDUbMYDl1mIO9n2vW8vWxxcBnK4kd9y # VHAHABy/izIDhvzX1k4eInh37sKTzQqolc36rH23Erk+LoU3Sy8OQOVLPGm1EbIJ # cGNGUsFgLI6p3DdxFoecLmKG5TULaGzBq1Dz9hiDdKsKWHkHWADq/jd4B4oHEmS2 # bfMtsg3ZEyEgAFXOhiLsRTe2aBv1vUbYUQ== # SIG # End signature block |