DSCResources/ResourceController/ResourceController.psm1
# Suppress Global Vars PSSA Error because $global:DSCMachineStatus must be allowed [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] param() function Get-TargetResource { [CmdletBinding()] [OutputType([Hashtable])] Param ( [Parameter(Mandatory = $true)] [string] $InstanceName, [Parameter(Mandatory = $true)] [System.String] $ResourceName, [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $Properties, [Parameter()] [Boolean] $SupressReboot, [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $MaintenanceWindow, [Parameter(Mandatory = $true)] [System.String] $ResourceVersion ) $functionName = "Get-TargetResource" $PropertiesHashTable = @{} foreach($prop in $Properties) { $PropertiesHashTable.Add($prop.Key, $prop.Value) } $dscResource = (Get-DscResource -Name $ResourceName).Where({$_.Version -eq $ResourceVersion})[0] Import-Module $dscResource.Path -Function $functionName -Prefix $ResourceName try { Test-ParameterValidation -Name $functionName.Replace("-","-$ResourceName") -Values $PropertiesHashTable } catch { throw $_.Exception.Message } Write-Verbose "Parameters passed in have validated succesfully." $splatProperties = Get-ValidParameter -Name $functionName.Replace("-","-$ResourceName") -Values $PropertiesHashTable Write-Verbose "Calling Get-TargetResource" $get = & "Get-${ResourceName}TargetResource" @splatProperties $CimGetResults = New-Object -TypeName 'System.Collections.ObjectModel.Collection`1[Microsoft.Management.Infrastructure.CimInstance]' foreach($row in $get.Keys.GetEnumerator()) { $value = $get.$row $CimProperties = @{ Namespace = 'root/Microsoft/Windows/DesiredStateConfiguration' ClassName = "MSFT_KeyValuePair" Property = @{ Key = "$row" Value = "$value" } } $CimGetResults += New-CimInstance -ClientOnly @CimProperties } $returnValue = @{ InstanceName = $InstanceName ResourceName = $ResourceName Properties = $Properties Result = $CimGetResults SupressReboot = $SupressReboot MaintenanceWindow = $MaintenanceWindow } return $returnValue } function Test-TargetResource { [OutputType([Boolean])] [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [string] $InstanceName, [Parameter(Mandatory = $true)] [string] $ResourceName, [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $Properties, [Parameter()] [Boolean] $SupressReboot, [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $MaintenanceWindow, [Parameter(Mandatory = $true)] [System.String] $ResourceVersion ) $functionName = "Test-TargetResource" $PropertiesHashTable = @{} foreach($prop in $Properties) { $PropertiesHashTable.Add($prop.Key, $prop.Value) } $dscResource = (Get-DscResource -Name $ResourceName).Where({$_.Version -eq $ResourceVersion})[0] Import-Module $dscResource.Path -Function $functionName -Prefix $ResourceName try { $null = Test-ParameterValidation -Name $functionName.Replace("-","-$ResourceName") -Values $PropertiesHashTable } catch { throw $_.Exception.Message } Write-Verbose "Parameters passed in have validated succesfully." $splatProperties = Get-ValidParameter -Name $functionName.Replace("-","-$ResourceName") -Values $PropertiesHashTable Write-Verbose "Calling Test-TargetResource" $result = &"Test-${ResourceName}TargetResource" @splatProperties return $result } function Set-TargetResource { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [string] $InstanceName, [Parameter(Mandatory = $true)] [string] $ResourceName, [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $Properties, [Parameter()] [Boolean] $SupressReboot, [Parameter()] [Microsoft.Management.Infrastructure.CimInstance[]] $MaintenanceWindow, [Parameter(Mandatory = $true)] [System.String] $ResourceVersion ) $inMaintenanceWindow = $false foreach($window in $MaintenanceWindow) { $maintenanceWindowProperties = @{} $params = @("Frequency", "StartTime", "EndTime", "DaysofWeek", "Week", "Days", "StartDate", "EndDate") foreach($param in $params) { if($window.$param) { $maintenanceWindowProperties.Add($param, $window.$param) } } if($(Test-MaintenanceWindow @maintenanceWindowProperties)) { $inMaintenanceWindow = $true } } if(-not $inMaintenanceWindow -and $MaintenanceWindow) { Write-Verbose "You are outside the maintenance window. No changes will be made." return } if(-not $inMaintenanceWindow -and $MaintenanceWindow) { Write-Verbose "You are outside the maintenance window. No changes will be made." return } $functionName = "Set-TargetResource" $PropertiesHashTable = @{} foreach($prop in $Properties) { $PropertiesHashTable.Add($prop.Key, $prop.Value) } $dscResource = (Get-DscResource -Name $ResourceName).Where({$_.Version -eq $ResourceVersion})[0] Import-Module $dscResource.Path -Function $functionName -Prefix $ResourceName try { Test-ParameterValidation -Name $functionName.Replace("-","-$ResourceName") -Values $PropertiesHashTable } catch { throw $_.Exception.Message } Write-Verbose "Parameters passed in have validated succesfully." $splatProperties = Get-ValidParameter -Name $functionName.Replace("-","-$ResourceName") -Values $PropertiesHashTable Write-Verbose "Calling Set-TargetResource." &"Set-${ResourceName}TargetResource" @splatProperties -Verbose if($SupressReboot -and $global:DSCMachineStatus -ne 0) { $global:DSCMachineStatus = 0 } } function Test-MaintenanceWindow { param( [Parameter(Mandatory = $true)] [string] $Frequency, [Parameter()] [Nullable[DateTime]] $StartTime, [Parameter()] [Nullable[DateTime]] $EndTime, [Parameter()] [string[]] $DaysOfWeek, [Parameter()] [int[]] $Week, [Parameter()] [int[]] $Days, [Parameter()] [Nullable[DateTime]] $StartDate, [Parameter()] [Nullable[DateTime]] $EndDate ) $now = Get-Date if($StartDate) { if($now.Date -lt $StartDate.Date) { return $false } } if($EndDate) { if($now.Date -gt $EndDate.Date) { return $false } } if($StartTime) { if($now.TimeOfDay -lt $StartTime.TimeOfDay) { return $false } } if($EndTime) { if($now.TimeOfDay -gt $EndTime.TimeOfDay) { return $false } } switch ($Frequency) { 'Daily' { if(-not $DaysOfWeek) { throw "Error" } if(-not ($DaysOfWeek -Contains $now.DayOfWeek)) { return $false } } 'Weekly' { if(-not $DaysOfWeek -or -not $Week) { throw "Error" } if(-not ($DaysOfWeek -Contains $now.DayOfWeek)) { return $false } $dow = $now.DayOfWeek $WorkingDate = Get-Date -Year $now.Year -Month $now.Month -Day 1 $weekCount = 0 for($i = 1; $i -le $now.Day; $i++) { if($WorkingDate.DayOfWeek -eq $dow) { $weekCount++ } $WorkingDate = $WorkingDate.AddDays(1) } if(-not ($Week -contains $weekCount)) { #check if last day if($Week -contains 0) { $WorkingDate = Get-Date -Year $now.Year -Month $now.Month -Day $([DateTime]::DaysInMonth($now.Year,$now.Month)) while($dow -ne $WorkingDate.DayOfWeek) { $WorkingDate = $WorkingDate.AddDays(-1) } if($WorkingDate.Day -ne $now.Day) { return $false } } else { return $false } } } 'Monthly' { if(-not $Days) { throw "error" } if(-not ($Days -contains $now.Day)) { if($Days -contains 0) { $lastDayofMonth = $([DateTime]::DaysInMonth($now.Year,$now.Month)) if($lastDayofMonth -ne $now.Day) { return $false } } else { return $false } } } } return $true } function Assert-Validation { param( [Parameter(Mandatory = $true)] $element, [Parameter(Mandatory = $true)] [psobject] $ParameterMetadata ) $BindingFlags = 'static','nonpublic','instance' $errorMessage = @() foreach($attribute in $ParameterMetadata.Attributes) { try { $Method = $attribute.GetType().GetMethod('ValidateElement',$BindingFlags) if($Method) { $Method.Invoke($attribute,@($element)) } } catch { $errorMessage += "Error on parameter $($ParameterMetadata.Name): $($_.Exception.InnerException.Message)" } } if($errorMessage.Count -gt 0) { throw $errorMessage -join "`n" } } function Test-ParameterValidation { param( [Parameter(Mandatory = $true)] [string] $Name, [Parameter(Mandatory = $true)] [Hashtable] $Values ) $ignoreResourceParameters = [System.Management.Automation.Cmdlet]::CommonParameters + [System.Management.Automation.Cmdlet]::OptionalCommonParameters $errorMessage = @() $command = Get-Command -Name $name $parameterNames = $command.Parameters foreach($name in $parameterNames.Keys) { if($ignoreResourceParameters -notcontains $name) { $metadata = $command.Parameters.$($name) if($Values.$($name)) { try { Assert-Validation -element $Values.$($name) -ParameterMetadata $metadata } catch { $errorMessage += $_.Exception.Message } } elseif($($metadata.Attributes | Where-Object {$_.TypeId.Name -eq "ParameterAttribute"}).Mandatory) { $errorMessage += "Parameter '$name' is mandatory." } } } if($errorMessage.Count -gt 0) { throw $errorMessage -join "`n" } } function Get-ValidParameter { param( [Parameter(Mandatory = $true)] [string] $Name, [Parameter(Mandatory = $true)] [Hashtable] $Values ) $ignoreResourceParameters = [System.Management.Automation.Cmdlet]::CommonParameters + [System.Management.Automation.Cmdlet]::OptionalCommonParameters $command = Get-Command -Name $name $parameterNames = $command.Parameters $properties = @{} foreach($name in $parameterNames.Keys) { if($ignoreResourceParameters -notcontains $name) { if($Values.ContainsKey($name)) { $properties.Add($Name, $Values.$name) } } } return $properties } Export-ModuleMember -Function *-TargetResource |