DscResources/DscLcmController/DscLcmController.schema.psm1
$dscLcmPostponeScript = @' $path = Join-Path -Path ([System.Environment]::GetFolderPath('CommonApplicationData')) -ChildPath 'Dsc\LcmController' Start-Transcript -Path "$path\LcmPostpone.log" -Append $currentLcmSettings = Get-DscLocalConfigurationManager $maxConsistencyCheckInterval = if ($currentLcmSettings.ConfigurationModeFrequencyMins -eq 30) #44640) { 44639 #value must be changed in order to reset the LCM timer } else { 44640 #minutes for 31 days } $maxRefreshInterval = if ($currentLcmSettings.RefreshFrequencyMins -eq 30) #44640) { 44639 #value must be changed in order to reset the LCM timer } else { 44640 #minutes for 31 days } $metaMofFolder = mkdir -Path "$path\MetaMof" -Force $mofFile = Copy-Item -Path C:\Windows\System32\Configuration\MetaConfig.mof -Destination "$path\MetaMof\localhost.meta.mof" -PassThru $content = Get-Content -Path $mofFile.FullName -Raw -Encoding Unicode $pattern = '(ConfigurationModeFrequencyMins +=)( +\d+)(;)' $content = $content -replace $pattern, ('$1 {0}$3' -f $maxConsistencyCheckInterval) $pattern = '(RefreshFrequencyMins +=)( +\d+)(;)' $content = $content -replace $pattern, ('$1 {0}$3' -f $maxRefreshInterval) $content | Out-File -FilePath $mofFile.FullName -Encoding unicode Set-DscLocalConfigurationManager -Path $metaMofFolder -Verbose "$(Get-Date) - Postponed LCM" | Add-Content -Path "$path\LcmSummery.log" Stop-Transcript '@ $dscLcmControlScript = @' $path = Join-Path -Path ([System.Environment]::GetFolderPath('CommonApplicationData')) -ChildPath 'Dsc\LcmController' Start-Transcript -Path "$path\LcmController.log" -Append $namespace = 'root/Microsoft/Windows/DesiredStateConfiguration' $className = 'MSFT_DSCLocalConfigurationManager' $configurationMode = (Get-DscLocalConfigurationManager).ConfigurationMode $doConsistencyCheck = $false $doRefresh = $false $inMaintenanceWindow = $false $currentTime = Get-Date $maintenanceWindows = Get-ChildItem -Path HKLM:\SOFTWARE\DscLcmControl\MaintenanceWindows $consistencyCheckIntervalOverride = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmControl -Name ConsistencyCheckIntervalOverride $refreshIntervalOverride = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmControl -Name RefreshIntervalOverride [datetime]$lastConsistencyCheck = try { Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmControl -Name LastConsistencyCheck } catch { Get-Date -Date 0 } [timespan]$consistencyCheckInterval = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmControl -Name ConsistencyCheckInterval [datetime]$lastRefresh = try { Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmControl -Name lastRefresh } catch { Get-Date -Date 0 } [timespan]$refreshInterval = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmControl -Name RefreshInterval $maintenanceWindowOverride = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmControl -Name MaintenanceWindowOverride if ($maintenanceWindows) { $inMaintenanceWindow = foreach ($maintenanceWindow in $maintenanceWindows) { Write-Host "Reading maintenance window '$($maintenanceWindow.PSChildName)'" [datetime]$maintenanceWindowStartTime = Get-ItemPropertyValue -Path $maintenanceWindow.PSPath -Name MaintenanceWindowStartTime [timespan]$maintenanceWindowTimespan = Get-ItemPropertyValue -Path $maintenanceWindow.PSPath -Name MaintenanceWindowTimespan [datetime]$maintenanceWindowEndTime = $maintenanceWindowStartTime + $maintenanceWindowTimespan Write-Host "Maintenance window: $($maintenanceWindowStartTime) - $($maintenanceWindowEndTime)." if ($currentTime -gt $maintenanceWindowStartTime -and $currentTime -lt $maintenanceWindowEndTime) { Write-Host "Current time '$currentTime' is in maintenance window '$($maintenanceWindow.PSChildName)'" Write-Host "IN MAINTENANCE WINDOW: Setting 'inMaintenanceWindow' to 'true' as the current time is in a maintanence windows." $true break } else { Write-Host "Current time '$currentTime' is not in maintenance window '$($maintenanceWindow.PSChildName)'" } } } else { Write-Host "No maintenance windows defined. Setting 'inMaintenanceWindow' to 'true'." $inMaintenanceWindow = $true } Write-Host if (-not $inMaintenanceWindow -and $maintenanceWindowOverride) { Write-Host "OVERRIDE: 'inMaintenanceWindow' is 'false' but 'maintenanceWindowOverride' is enabled, setting 'inMaintenanceWindow' to 'true'" $inMaintenanceWindow = $true } elseif (-not $inMaintenanceWindow) { Write-Host "NOT IN MAINTENANCE WINDOW: 'inMaintenanceWindow' is 'false'. The current time is not in any of the $($maintenanceWindows.Count) maintenance windows." } #always invoke the consistency check if in 'ApplyAndMonitor' but when in 'ApplyAndAutoCorrect' only if in maintenance window. if ($configurationMode -eq 'ApplyAndAutoCorrect' -and $inMaintenanceWindow) { $doConsistencyCheck = $true } elseif ($configurationMode -in 'ApplyAndMonitor', 'MonitorOnly') { $doConsistencyCheck = $true } $doRefresh = $inMaintenanceWindow #Consistency Check $nextConsistencyCheck = $lastConsistencyCheck + $consistencyCheckInterval Write-Host "" Write-Host "The previous consistency check was done on '$lastConsistencyCheck', the next one will not triggered before '$nextConsistencyCheck'. ConsistencyCheckInterval is $consistencyCheckInterval." if ($currentTime -gt $nextConsistencyCheck) { Write-Host 'It is time to trigger a consistency check per the defined interval.' $doConsistencyCheck = $doConsistencyCheck -band 1 } else { if ($consistencyCheckIntervalOverride) { Write-Host "OVERRIDE: It is NOT time to trigger a consistency check per the defined interval but 'ConsistencyCheckIntervalOverride' is enabled." $doConsistencyCheck = $doConsistencyCheck -band 1 } else { Write-Host 'It is NOT time to trigger a consistency check per the defined interval.' $doConsistencyCheck = $doConsistencyCheck -band 0 } } Write-Host #Refresh Check $nextRefresh = $lastRefresh + $refreshInterval Write-Host "" Write-Host "The previous refresh check was done on '$lastRefresh', the next one will not triggered before '$nextRefresh'. RefreshInterval is $refreshInterval." if ($currentTime -gt $nextRefresh) { Write-Host 'It is time to trigger a refresh check per the defined interval.' $doRefresh = $doRefresh -band 1 } else { if ($refreshIntervalOverride) { Write-Host "OVERRIDE: It is NOT time to trigger a consistency check per the defined interval but 'RefreshIntervalOverride' is enabled." $doRefresh = $doRefresh -band 1 } else { Write-Host 'It is NOT time to trigger a refresh per the defined interval.' $doRefresh = $doRefresh -band 0 } } Write-Host if ($doConsistencyCheck) { Write-Host "ACTION: Invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags '1' (Consistency Check)." try { Invoke-CimMethod -ClassName $className -Namespace $namespace -MethodName PerformRequiredConfigurationChecks -Arguments @{ Flags = [uint32]1 } -ErrorAction Stop $dscLcmControl = Get-Item -Path HKLM:\SOFTWARE\DscLcmControl Set-ItemProperty -Path $dscLcmControl.PSPath -Name LastConsistencyCheck -Value (Get-Date) -Type String -Force } catch { Write-Error "Error invoking 'PerformRequiredConfigurationChecks'. The message is: '$($_.Exception.Message)'" } } else { Write-Host "NO ACTION: 'doConsistencyCheck' is false, not invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags '1' (Consistency Check)." } if ($doRefresh) { Write-Host "ACTION: Invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags'5' (Pull and Consistency Check)." try { Invoke-CimMethod -ClassName $className -Namespace $namespace -MethodName PerformRequiredConfigurationChecks -Arguments @{ Flags = [uint32]5 } -ErrorAction Stop $dscLcmControl = Get-Item -Path HKLM:\SOFTWARE\DscLcmControl Set-ItemProperty -Path $dscLcmControl.PSPath -Name LastRefresh -Value (Get-Date) -Type String -Force } catch { Write-Error "Error invoking 'PerformRequiredConfigurationChecks'. The message is: '$($_.Exception.Message)'" } } else { Write-Host "NO ACTION: 'doRefresh' is false, not invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags '5' (Pull and Consistency Check)." } "$(Get-Date) - LcmController: doConsistencyCheck = '$doConsistencyCheck', doRefresh = '$doRefresh'" | Add-Content -Path "$path\LcmSummery.log" Stop-Transcript '@ Configuration DscLcmController { Param( [Parameter(Mandatory)] [timespan]$ConsistencyCheckInterval, [bool]$ConsistencyCheckIntervalOverride, [Parameter(Mandatory)] [timespan]$RefreshInterval, [bool]$RefreshIntervalOverride, [Parameter(Mandatory)] [timespan]$ControllerInterval, [bool]$MaintenanceWindowOverride ) Import-DscResource -ModuleName xPSDesiredStateConfiguration -ModuleVersion 8.6.0.0 Import-DscResource -ModuleName ComputerManagementDsc -ModuleVersion 6.3.0.0 Import-DscResource -ModuleName PSDesiredStateConfiguration xRegistry DscLcmControl_ConsistencyCheckInterval { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmControl' ValueName = 'ConsistencyCheckInterval' ValueData = $ConsistencyCheckInterval ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmControl_ConsistencyCheckIntervalOverride { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmControl' ValueName = 'ConsistencyCheckIntervalOverride' ValueData = [int]$ConsistencyCheckIntervalOverride ValueType = 'DWORD' Ensure = 'Present' Force = $true } xRegistry DscLcmControl_RefreshInterval { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmControl' ValueName = 'RefreshInterval' ValueData = $RefreshInterval ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmControl_RefreshIntervalOverride { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmControl' ValueName = 'RefreshIntervalOverride' ValueData = [int]$RefreshIntervalOverride ValueType = 'DWORD' Ensure = 'Present' Force = $true } xRegistry DscLcmControl_ControllerInterval { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmControl' ValueName = 'ControllerInterval' ValueData = $ControllerInterval ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmControl_MaintenanceWindowOverride { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmControl' ValueName = 'MaintenanceWindowOverride' ValueData = [int]$MaintenanceWindowOverride ValueType = 'DWORD' Ensure = 'Present' Force = $true } File DscLcmPostponeScript { Ensure = 'Present' Type = 'File' DestinationPath = 'C:\ProgramData\Dsc\LcmController\LcmPostpone.ps1' Contents = $dscLcmPostponeScript } ScheduledTask DscPostponeTask { DependsOn = '[File]DscLcmPostponeScript' TaskName = 'DscLcmPostpone' TaskPath = '\DscController' ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' ActionArguments = '-File C:\ProgramData\Dsc\LcmController\LcmPostpone.ps1' ScheduleType = 'Once' RepeatInterval = $ControllerInterval RepetitionDuration = 'Indefinitely' StartTime = (Get-Date) } File DscLcmControlScript { Ensure = 'Present' Type = 'File' DestinationPath = 'C:\ProgramData\Dsc\LcmController\LcmControl.ps1' Contents = $dscLcmControlScript } ScheduledTask DscControlTask { DependsOn = '[File]DscLcmControlScript' TaskName = 'DscLcmControl' TaskPath = '\DscController' ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' ActionArguments = '-File C:\ProgramData\Dsc\LcmController\LcmControl.ps1' ScheduleType = 'Once' RepeatInterval = $ControllerInterval RepetitionDuration = 'Indefinitely' StartTime = (Get-Date) } } |