DSCResources/DscLcmController/DscLcmController.schema.psm1
$dscLcmControllerScript = @'
function Get-DscConfigurationVersionLocal { $hash = @{} $key = Get-Item HKLM:\SOFTWARE\DscTagging -ErrorAction SilentlyContinue if( $null -ne $key ) { foreach ($property in $key.Property) { $hash.Add($property, $key.GetValue($property)) } } else { $hash.Version = 'Unknown' } New-Object -TypeName PSObject -Property $hash } function Send-DscTaggingData { [CmdletBinding()] param() $pattern = 'http[s]?:\/\/(?<PullServer>([^\/:\.[:space:]]+(\.[^\/:\.[:space:]]+)*)|([0-9](\.[0-9]{3})))(:[0-9]+)?((\/[^?#[:space:]]+)(\?[^#[:space:]]+)?(\#.+)?)?' try { $lcm = Get-DscLocalConfigurationManager -ErrorAction Stop $pullServerUrl = $lcm.ConfigurationDownloadManagers.ServerURL $agentId = $lcm.AgentId Write-Host "PullServerUrl = '$pullServerUrl'" Write-Host "AgentId = '$agentId'" $found = $pullServerUrl -match $pattern if (-not $found) { Write-Error "Could not find pull server in Url '$pullServerUrl'" -ErrorAction Stop } } catch { Write-Error "Cannot get pull server name from 'Get-DscLocalConfigurationManager' output, the error was $($_.Exception.Message)" return } $versionData = Get-DscConfigurationVersionLocal if ($versionData.Layers.Count -gt 1) { $versionData.Layers = $versionData.Layers -join ', ' } Write-Host Write-Host "Sending the following DSC version data to JEA endpoint on pull server '$($Matches.PullServer)'" $versionData | Out-String | Write-Host Invoke-Command -ComputerName $Matches.PullServer -ConfigurationName DscData -ScriptBlock { Send-DscTaggingData -AgentId $args[0] -Data $args[1] } -ArgumentList $agentId, $versionData } function Set-LcmPostpone { $postponeInterval = 14 if ($lastLcmPostpone.AddDays($postponeInterval) -gt (Get-Date)) { Write-Host "Last LCM postpone was done at '$lastLcmPostpone'. Next one will not be triggered before '$($lastLcmPostpone.AddDays($postponeInterval))'" Write-Host return } else { Write-Host "Last LCM postpone was done at '$lastLcmPostpone'. Triggering LCM postone as the last time was more than $postponeInterval ago" Write-Host } $currentLcmSettings = Get-DscLocalConfigurationManager $maxConsistencyCheckInterval = if ($currentLcmSettings.ConfigurationModeFrequencyMins -eq 44640) { 44639 #value must be changed in order to reset the LCM timer } else { 44640 #minutes for 31 days } $maxRefreshInterval = if ($currentLcmSettings.RefreshFrequencyMins -eq 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 if (Test-Path -Path C:\Windows\System32\Configuration\MetaConfig.mof) { $mofFile = Copy-Item -Path C:\Windows\System32\Configuration\MetaConfig.mof -Destination "$path\MetaMof\localhost.meta.mof" -Force -PassThru } else { $mofFile = Get-Item -Path "$path\MetaMof\localhost.meta.mof" -ErrorAction Stop } $content = Get-Content -Path $mofFile.FullName -Raw -Encoding Unicode $pattern = '(ConfigurationModeFrequencyMins(\s+)?=(\s+)?)(\d+)(;)' $content = $content -replace $pattern, ('$1 {0}$5' -f $maxConsistencyCheckInterval) $pattern = '(RefreshFrequencyMins(\s+)?=(\s+)?)(\d+)(;)' $content = $content -replace $pattern, ('$1 {0}$5' -f $maxRefreshInterval) $content | Out-File -FilePath $mofFile.FullName -Encoding unicode Set-DscLocalConfigurationManager -Path $metaMofFolder "$(Get-Date) - Postponed LCM" | Add-Content -Path "$path\LcmPostponeSummary.log" Set-ItemProperty -Path $dscLcmController.PSPath -Name LastLcmPostpone -Value (Get-Date) -Type String -Force } function Test-InMaintenanceWindow { if ($maintenanceWindows) { $inMaintenanceWindow = foreach ($maintenanceWindow in $maintenanceWindows) { Write-Host "Reading maintenance window '$($maintenanceWindow.PSChildName)'" [datetime]$startTime = Get-ItemPropertyValue -Path $maintenanceWindow.PSPath -Name StartTime [timespan]$timespan = Get-ItemPropertyValue -Path $maintenanceWindow.PSPath -Name Timespan [datetime]$endTime = $startTime + $timespan [string]$dayOfWeek = try { Get-ItemPropertyValue -Path $maintenanceWindow.PSPath -Name DayOfWeek } catch { } [string]$on = try { Get-ItemPropertyValue -Path $maintenanceWindow.PSPath -Name On } catch { } if ($dayOfWeek) { if ((Get-Date).DayOfWeek -ne $dayOfWeek) { Write-Host "DayOfWeek is set to '$dayOfWeek'. Current day of week is '$((Get-Date).DayOfWeek)', maintenance window does not apply" continue } else { Write-Host "Maintenance Window is configured for week day '$dayOfWeek' which is the current day of week." } } if ($on) { if ($on -ne 'last') { $on = [int][string]$on[0] } $daysInMonth = [datetime]::DaysInMonth($now.Year, $now.Month) $daysInMonth = for ($i = 1; $i -le $daysInMonth; $i++) { Get-Date -Date $now -Day $i } $daysInMonth = $daysInMonth | Where-Object { $_.DayOfWeek -eq $dayOfWeek } $daysInMonth = if ($on -eq 'last') { $daysInMonth | Select-Object -Last 1 } else { $daysInMonth | Select-Object -Index ($on - 1) } if ($daysInMonth.ToShortDateString() -ne $now.ToShortDateString()) { Write-Host "Today is not the '$on' $dayOfWeek in the current month" continue } else { Write-Host "The LCM is supposed to run on the '$on' $dayOfWeek which applies to today" } } Write-Host "Maintenance window: $($startTime) - $($endTime)." if ($currentTime -gt $startTime -and $currentTime -lt $endTime) { 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 'false'." $false } Write-Host if (-not $inMaintenanceWindow -and $maintenanceWindowOverride) { Write-Host "OVERRIDE: 'inMaintenanceWindow' is 'false' but 'maintenanceWindowOverride' is enabled, setting 'inMaintenanceWindow' to 'true'" $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." $false } else { $inMaintenanceWindow } } function Set-LcmMode { param( [Parameter(Mandatory = $true)] [ValidateSet('ApplyAndAutoCorrect', 'ApplyAndMonitor')] [string]$Mode ) $metaMofFolder = mkdir -Path "$path\MetaMof" -Force if (Test-Path -Path C:\Windows\System32\Configuration\MetaConfig.mof) { $mofFile = Copy-Item -Path C:\Windows\System32\Configuration\MetaConfig.mof -Destination "$path\MetaMof\localhost.meta.mof" -Force -PassThru } else { $mofFile = Get-Item -Path "$path\MetaMof\localhost.meta.mof" -ErrorAction Stop } $content = Get-Content -Path $mofFile.FullName -Raw -Encoding Unicode $pattern = '(ConfigurationMode(\s+)?=(\s+)?)("\w+")(;)' $content = $content -replace $pattern, ('$1 "{0}"$5' -f $Mode) Write-Host "LCM put into '$Mode' mode" } function Set-LcmRebootNodeIfNeededMode { param( [Parameter(Mandatory = $true)] [bool] $RebootNodeIfNeeded ) $metaMofFolder = mkdir -Path "$path\MetaMof" -Force if (Test-Path -Path C:\Windows\System32\Configuration\MetaConfig.mof) { $mofFile = Copy-Item -Path C:\Windows\System32\Configuration\MetaConfig.mof -Destination "$path\MetaMof\localhost.meta.mof" -Force -PassThru } else { $mofFile = Get-Item -Path "$path\MetaMof\localhost.meta.mof" -ErrorAction Stop } $content = Get-Content -Path $mofFile.FullName -Raw -Encoding Unicode $patternRebootNodeIfNeeded = '(RebootNodeIfNeeded(\s+)?=(\s+)?)(true|false);' $content = $content -replace $patternRebootNodeIfNeeded, ('$1 {0};' -f $RebootNodeIfNeeded) $content | Out-File -FilePath $mofFile.FullName -Encoding unicode Set-DscLocalConfigurationManager -Path $metaMofFolder Write-Host "LCM RebootIfNeededValue is set to '$RebootNodeIfNeeded'" } function Test-StartDscAutoCorrect { if ($maintenanceWindowMode -eq 'AutoCorrect') { $nextAutoCorrect = $lastAutoCorrect + $autoCorrectInterval Write-Host "" Write-Host "The previous AutoCorrect was done on '$lastAutoCorrect', the next one will not be triggered before '$nextAutoCorrect'. AutoCorrectInterval is $autoCorrectInterval." if ($currentTime -gt $nextAutoCorrect) { Write-Host 'It is time to trigger an AutoCorrect per the defined interval.' $doAutoCorrect = $true } else { if ($autoCorrectIntervalOverride) { Write-Host "OVERRIDE: It is NOT time to trigger an AutoCorrect per the defined interval but 'AutoCorrectIntervalOverride' is enabled." $doAutoCorrect = $true } else { Write-Host 'It is NOT time to trigger an AutoCorrect per the defined interval.' $doAutoCorrect = $false } } $doAutoCorrect } else { $false } } function Test-StartDscRefresh { if ($maintenanceWindowMode -eq 'AutoCorrect') { $nextRefresh = $lastRefresh + $refreshInterval Write-Host "" Write-Host "The previous Refresh was done on '$lastRefresh', the next one will not be triggered before '$nextRefresh'. RefreshInterval is $refreshInterval." if ($currentTime -gt $nextRefresh) { Write-Host 'It is time to trigger a Refresh per the defined interval.' $doRefresh = $true } else { if ($refreshIntervalOverride) { Write-Host "OVERRIDE: It is NOT time to trigger a Refresh check per the defined interval but 'refreshIntervalOverride' is enabled." $doRefresh = $true } else { Write-Host 'It is NOT time to trigger a Refresh check per the defined interval.' $doRefresh = $false } } $doRefresh } else { $false } } function Start-AutoCorrect { Write-Host "ACTION: Invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags '1' (Consistency Check)." try { $script:lcmRuntime = Start-LcmRequiredConfigurationChecks -Mode AutoCorrect -MaxLcmRuntime $maxLcmRuntime -Flags 1 $dscLcmController = Get-Item -Path HKLM:\SOFTWARE\DscLcmController Set-ItemProperty -Path $dscLcmController.PSPath -Name LastAutoCorrect -Value (Get-Date) -Type String -Force } catch { Write-Error "Error invoking 'PerformRequiredConfigurationChecks'. The message is: '$($_.Exception.Message)'" $script:autoCorrectErrors = $true } } function Start-Monitor { Write-Host "ACTION: Invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags '1' (Consistency Check)." try { $script:lcmRuntime = Start-LcmRequiredConfigurationChecks -Mode Monitor -MaxLcmRuntime $maxLcmRuntime -Flags 1 $dscLcmController = Get-Item -Path HKLM:\SOFTWARE\DscLcmController Set-ItemProperty -Path $dscLcmController.PSPath -Name LastMonitor -Value (Get-Date) -Type String -Force } catch { Write-Error "Error invoking 'PerformRequiredConfigurationChecks'. The message is: '$($_.Exception.Message)'" $script:monitorErrors = $true } } function Start-Refresh { Write-Host "ACTION: Invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags'5' (Pull and Consistency Check)." try { $script:lcmRuntime = Start-LcmRequiredConfigurationChecks -Mode AutoCorrect -MaxLcmRuntime $maxLcmRuntime -Flags 5 $dscLcmController = Get-Item -Path HKLM:\SOFTWARE\DscLcmController Set-ItemProperty -Path $dscLcmController.PSPath -Name LastRefresh -Value (Get-Date) -Type String -Force if ($sendDscTaggingData) { try { Send-DscTaggingData -ErrorAction Stop } catch { $sendDscTaggingDataError = $true } } } catch { Write-Error "Error invoking 'PerformRequiredConfigurationChecks'. The message is: '$($_.Exception.Message)'" $script:refreshErrors = $true } } function Test-StartDscMonitor { $nextMonitor1 = $lastMonitor + $monitorInterval $nextMonitor2 = $lastAutoCorrect + $monitorInterval $nextMonitor = [datetime][math]::Max($nextMonitor1.Ticks, $nextMonitor2.Ticks) Write-Host '' Write-Host "The previous Monitor was done on '$lastMonitor', the next one will not be triggered before '$nextMonitor'. MonitorInterval is $monitorInterval." if ($currentTime -gt $nextMonitor) { Write-Host 'It is time to trigger a Monitor per the defined interval.' $doMonitor = $true } else { Write-Host 'It is NOT time to trigger a Monitor per the defined interval.' $doMonitor = $false } $doMonitor } function Start-LcmRequiredConfigurationChecks { param( [OutputType([timespan])] [Parameter()] [timespan]$MaxLcmRuntime = (New-TimeSpan -Days 2), [Parameter(Mandatory = $true)] [ValidateSet('Monitor', 'AutoCorrect')] [string]$Mode, [Parameter(Mandatory = $true)] [int]$Flags ) Write-Verbose "Entering 'Start-LcmRequiredConfigurationChecks'" $internalMaxLcmRuntime = $MaxLcmRuntime $j = Start-Job -ScriptBlock { param( [Parameter(Mandatory = $true)] [int]$Flags ) $params = @{ ClassName = 'MSFT_DSCLocalConfigurationManager' Namespace = 'root/Microsoft/Windows/DesiredStateConfiguration' MethodName = 'PerformRequiredConfigurationChecks' Arguments = @{ Flags = [uint32]$Flags } ErrorAction = 'Stop' } Write-Output "Calling 'Invoke-CimMethod' with the following parameters:" $params | ConvertTo-Json | Write-Output Invoke-CimMethod @params | Out-Null } -ArgumentList $Flags Write-Host "Waiting $MaxLcmRuntime for the background job to finish." while ($j.State -eq 'Running' -and $internalMaxLcmRuntime -gt 0) { $waitIntervalInSeconds = 5 Start-Sleep -Seconds $waitIntervalInSeconds $output = $j | Receive-Job | Out-String if ($output) { $output | Write-Host } $internalMaxLcmRuntime = $internalMaxLcmRuntime.Subtract((New-TimeSpan -Seconds $waitIntervalInSeconds)) } if ($j.State -eq 'Running') { Write-Host "LCM did not finish with the timeout of '$MaxLcmRuntime'" $j | Stop-Job #find the process that is hosting the DSC engine $dscProcess = Get-CimInstance -ClassName msft_providers | Where-Object { $_.Provider -like 'dsccore' } Write-Host "Shutting down LCM process with ID '$($dscProcess.HostProcessIdentifier)'" Get-Process -Id $dscProcess.HostProcessIdentifier | Stop-Process -Force if ($Mode -eq 'AutoCorrect') { Set-ItemProperty -Path $dscLcmController.PSPath -Name LastAutoCorrect -Value (Get-Date -Date 0) -Type String -Force } else { Set-ItemProperty -Path $dscLcmController.PSPath -Name LastMonitor -Value (Get-Date -Date 0) -Type String -Force } Write-Error -Message "LCM did run longer than '$MaxLcmRuntime'. Process was stopped." -ErrorAction Stop } $runtime = $j.PSEndTime - $j.PSBeginTime Write-Host "LCM runtime was '$runtime'" $runtime } $writeTranscripts = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name WriteTranscripts $path = Join-Path -Path ([System.Environment]::GetFolderPath('CommonApplicationData')) -ChildPath 'Dsc\LcmController' if ($writeTranscripts) { Start-Transcript -Path "$path\LcmController.log" -Append } #Disable DSC Timer $timer = Get-CimInstance -ClassName msft_providers | Where-Object { $_.Provider -like 'dsctimer' } $timer | Invoke-CimMethod -MethodName UnLoad $now = Get-Date $lcmConfiguration = Get-DscLocalConfigurationManager $currentConfigurationMode = $lcmConfiguration.ConfigurationMode $lcmModeChanged = '' $doConsistencyCheck = $false $doRefresh = $false $inMaintenanceWindow = $false $doAutoCorrect = $false $doRefresh = $false $doMonitor = $false $autoCorrectErrors = $false $refreshErrors = $false $monitorErrors = $false $currentTime = Get-Date $lcmRuntime = $null $sendDscTaggingData = $false $sendDscTaggingDataError = $false $dscLcmController = Get-Item -Path HKLM:\SOFTWARE\DscLcmController $maintenanceWindows = Get-ChildItem -Path HKLM:\SOFTWARE\DscLcmController\MaintenanceWindows [bool]$maintenanceWindowOverride = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name MaintenanceWindowOverride [timespan]$autoCorrectInterval = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name AutoCorrectInterval [bool]$autoCorrectIntervalOverride = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name AutoCorrectIntervalOverride [timespan]$monitorInterval = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name MonitorInterval [timespan]$refreshInterval = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name RefreshInterval [bool]$refreshIntervalOverride = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name RefreshIntervalOverride [timespan]$maxLcmRuntime = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name MaxLcmRuntime [timespan]$logHistoryTimeSpan = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name LogHistoryTimeSpan [bool]$sendDscTaggingData = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name SendDscTaggingData $maintenanceWindowMode = Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name MaintenanceWindowMode [datetime]$lastAutoCorrect = try { Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name LastAutoCorrect } catch { Get-Date -Date 0 } [datetime]$lastMonitor = try { Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name LastMonitor } catch { Get-Date -Date 0 } [datetime]$lastRefresh = try { Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name LastRefresh } catch { Get-Date -Date 0 } [datetime]$lastLcmPostpone = try { Get-ItemPropertyValue -Path HKLM:\SOFTWARE\DscLcmController -Name LastLcmPostpone } catch { Get-Date -Date 0 } Write-Host '----------------------------------------------------------------------------' Set-LcmPostpone $inMaintenanceWindow = Test-InMaintenanceWindow Write-Host if ($inMaintenanceWindow) { if (!$lcmConfiguration.RebootNodeIfNeeded) { Write-Host "RebootNodeIfNeeded is set to 'False', but it's in maintenance window, set RebootNodeIfNeeded to 'True'" Set-LcmRebootNodeIfNeededMode -RebootNodeIfNeeded $true } if ($maintenanceWindowMode -eq 'AutoCorrect' -and $currentConfigurationMode -ne 'ApplyAndAutoCorrect') { Write-Host "MaintenanceWindowMode is '$maintenanceWindowMode' but LCM is set to '$currentConfigurationMode'. Changing LCM to 'ApplyAndAutoCorrect'" Set-LcmMode -Mode 'ApplyAndAutoCorrect' $lcmModeChanged = 'ApplyAndAutoCorrect' } elseif ($maintenanceWindowMode -eq 'Monitor' -and $currentConfigurationMode -ne 'ApplyAndMonitor') { Write-Host "MaintenanceWindowMode is '$maintenanceWindowMode' but LCM is set to '$currentConfigurationMode'. Changing LCM to 'ApplyAndMonitor'" Set-LcmMode -Mode 'ApplyAndMonitor' $lcmModeChanged = 'ApplyAndMonitor' } } else{ if ($lcmConfiguration.RebootNodeIfNeeded) { Write-Host "RebootNodeIfNeeded is set to 'True', but it's not into maintenance window, set RebootNodeIfNeeded to 'False'" Set-LcmRebootNodeIfNeededMode -RebootNodeIfNeeded $false } } if ($inMaintenanceWindow) { $doAutoCorrect = Test-StartDscAutoCorrect $doRefresh = Test-StartDscRefresh if ($doRefresh) { Start-Refresh } else { Write-Host "NO ACTION: 'doRefresh' is false, not invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags '5' (Pull and Consistency Check)." } if ($doAutoCorrect) { Start-AutoCorrect } else { Write-Host "NO ACTION: 'doAutoCorrect' is false, not invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags '1' (Consistency Check)." } } Write-Host if ($lcmModeChanged) { Write-Host "Setting LCM back from '$lcmModeChanged' to '$currentConfigurationMode'." Set-LcmMode -Mode $currentConfigurationMode } Write-Host if (-not $doAutoCorrect) { $doMonitor = Test-StartDscMonitor if ($doMonitor) { Start-Monitor } else { Write-Host "NO ACTION: 'doMonitor' is false, not invoking Cim Method 'PerformRequiredConfigurationChecks' with Flags '1' (Consistency Check)." } } else { Write-Host "In AutoCorrect mode, skipping Montior" } $logItem = [pscustomobject]@{ CurrentTime = (Get-Date).ToString('M\/d\/yyyy h:m:s tt', [System.Globalization.CultureInfo]::InvariantCulture) InMaintenanceWindow = [int]$inMaintenanceWindow DoAutoCorrect = [int]$doAutoCorrect DoMonitor = [int]$doMonitor DoRefresh = [int]$doRefresh LastAutoCorrect = $lastAutoCorrect.ToString('M\/d\/yyyy h:m:s tt', [System.Globalization.CultureInfo]::InvariantCulture) LastMonitor = $lastMonitor.ToString('M\/d\/yyyy h:m:s tt', [System.Globalization.CultureInfo]::InvariantCulture) AutoCorrectInterval = $autoCorrectInterval AutoCorrectIntervalOverride = $autoCorrectIntervalOverride ConsistencyCheckErrors = $autoCorrectErrors MonitorInterval = $monitorInterval MonitorErrors = $monitorErrors LastRefresh = $lastRefresh.ToString('M\/d\/yyyy h:m:s tt', [System.Globalization.CultureInfo]::InvariantCulture) RefreshInterval = $refreshInterval RefreshIntervalOverride = $refreshIntervalOverride RefreshErrors = $refreshErrors MaxLcmRuntime = $maxLcmRuntime LcmRuntime = $lcmRuntime SendDscTaggingDataError = $sendDscTaggingDataError } | Export-Csv -Path "$path\LcmControllerSummary.csv" -Delimiter ',' -Append -Force if ($writeTranscripts) { Stop-Transcript } #------------------------ LcmController.log cleanup ---------------------------------- $pattern = '(\*{22}\r\nWindows PowerShell transcript start\r\n)((.|\r\n)+?)(End time: \d{14}\r\n\*{22})' $date = (Get-Date) - $logHistoryTimeSpan $lcmControllerLogContent = Get-Content -Path "$path\LcmController.log" -Raw $regexMatches = [regex]::Matches($lcmControllerLogContent, $pattern) $logEntries = $regexMatches | Where-Object { [datetime]::ParseExact((($_.Value -split "\n")[-2] -split ' ')[2].Trim(), 'yyyyMMddHHmmss', $null) -gt $date } #$logEntries | Group-Object -Property { [datetime]::ParseExact((($_.Value -split "\n")[-2] -split ' ')[2].Trim(),'yyyyMMddHHmmss',$null).ToString('yy MM dd') } Write-Host "Log file contained $($regexMatches.Count) entries, after cleanup if contains $($logEntries.Count) entries." $logEntries.Value | Out-File -FilePath "$path\LcmController.log" -Force #------------------ LcmControllerSummary.csv cleanup ------------------------------ $summaryContent = Import-Csv -Path "$path\LcmControllerSummary.csv" -Delimiter ',' $filteredSummaryContent = $summaryContent | Where-Object { [datetime]$_.CurrentTime -gt $date } Write-Host "Summary file contained $($summaryContent.Count) entries, after cleanup if contains $($filteredSummaryContent.Count) entries." $filteredSummaryContent | Export-Csv -Path "$path\LcmControllerSummary.csv" -Delimiter ',' -Force '@ configuration DscLcmController { param ( [Parameter(Mandatory = $true)] [ValidateSet('Monitor', 'AutoCorrect')] [string] $MaintenanceWindowMode, [Parameter(Mandatory = $true)] [timespan] $MonitorInterval, [Parameter(Mandatory = $true)] [timespan] $AutoCorrectInterval, [Parameter()] [bool] $AutoCorrectIntervalOverride, [Parameter(Mandatory = $true)] [timespan] $RefreshInterval, [Parameter()] [bool] $RefreshIntervalOverride, [Parameter(Mandatory = $true)] [timespan] $ControllerInterval, [Parameter()] [bool] $MaintenanceWindowOverride, [Parameter()] [timespan] $MaxLcmRuntime = (New-TimeSpan -Days 2), [Parameter()] [timespan] $LogHistoryTimeSpan = (New-TimeSpan -Days 90), [Parameter()] [bool] $SendDscTaggingData, [Parameter()] [bool] $WriteTranscripts ) Import-DscResource -ModuleName PSDesiredStateConfiguration Import-DscResource -ModuleName xPSDesiredStateConfiguration Import-DscResource -ModuleName ComputerManagementDsc xRegistry DscLcmController_MaintenanceWindowMode { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'MaintenanceWindowMode' ValueData = $MaintenanceWindowMode ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmController_MonitorInterval { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'MonitorInterval' ValueData = $MonitorInterval ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmController_AutoCorrectInterval { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'AutoCorrectInterval' ValueData = $AutoCorrectInterval ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmController_AutoCorrectIntervalOverride { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'AutoCorrectIntervalOverride' ValueData = [int]$AutoCorrectIntervalOverride ValueType = 'DWord' Ensure = 'Present' Force = $true } xRegistry DscLcmController_RefreshInterval { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'RefreshInterval' ValueData = $RefreshInterval ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmController_RefreshIntervalOverride { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'RefreshIntervalOverride' ValueData = [int]$RefreshIntervalOverride ValueType = 'DWord' Ensure = 'Present' Force = $true } xRegistry DscLcmController_ControllerInterval { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'ControllerInterval' ValueData = $ControllerInterval ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmController_MaintenanceWindowOverride { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'MaintenanceWindowOverride' ValueData = [int]$MaintenanceWindowOverride ValueType = 'DWord' Ensure = 'Present' Force = $true } xRegistry DscLcmController_WriteTranscripts { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'WriteTranscripts' ValueData = [int]$WriteTranscripts ValueType = 'DWord' Ensure = 'Present' Force = $true } xRegistry DscLcmController_MaxLcmRuntime { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'MaxLcmRuntime' ValueData = $MaxLcmRuntime ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmController_LogHistoryTimeSpan { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'LogHistoryTimeSpan' ValueData = $LogHistoryTimeSpan ValueType = 'String' Ensure = 'Present' Force = $true } xRegistry DscLcmController_SendDscTaggingData { Key = 'HKEY_LOCAL_MACHINE\SOFTWARE\DscLcmController' ValueName = 'SendDscTaggingData' ValueData = [int]$SendDscTaggingData ValueType = 'DWord' Ensure = 'Present' Force = $true } File DscLcmControllerScript { Ensure = 'Present' Type = 'File' DestinationPath = 'C:\ProgramData\Dsc\LcmController\LcmController.ps1' Contents = $dscLcmControllerScript } ScheduledTask DscControllerTask { DependsOn = '[File]DscLcmControllerScript' TaskName = 'DscLcmController' TaskPath = '\DscController' ActionExecutable = 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' ActionArguments = '-File C:\ProgramData\Dsc\LcmController\LcmController.ps1' ScheduleType = 'Once' RepeatInterval = $ControllerInterval RepetitionDuration = 'Indefinitely' StartTime = (Get-Date) } } |