This function is based on the original code from Nickolaj Andersen that you can find here GitHub Get-MaintenanceWindows.ps1 however I have modified this to allow for Verbose output and to specify the day, month and year for which you want to determine the Maintenance Window. In addition since I work a lot with non-recurring Maintenance Windows (set for the complete year in advance) I have added a date match for RecurrenceType 1 (same as is done for other recurrence types). The changes have been made so that this function can be used in scripts to identify when a Maintenance Window occurs and combined with other functions to show which servers will be affected during that Maintenance Window.
NOTE: By including the SYNOPSIS and other information you can use get-help on the function to find out what parameters you can specify or read what this function actually can be used for. I can highly recommended to always include this information in your PowerShell function(s) so that anybody can understand it.
Examples:
In the below examples names pointing to a sitecode, collection ID or server name are blurred out (this is a real site server behind a FAKE FQDN).
In the example below you can see that the first detected Maintenance Window for April 2018 is on the 16th and this is returned as a value. This value can be used in other scripts to determine what and when, the currently shown Recurrence type is 1 (non-recurring).
In the example below the same command line as above was used however this time with the Verbose parameter to show more information of what is found/happening during the function execution, in this case a small sample was taken but more output is shown during the run until a match is found.
Code:
Function Get-SCCMCollectionMaintenanceWindow { <# .SYNOPSIS Gets the configured maintenance window(s) for the specified collection based on the SCCM Collection ID. .DESCRIPTION Displays the date and time of the Maintenance Window if found, if executed without a day,month or year the current day,month and year is used. You can use the parameters to find a Maintenance Window for a specific date in the (near) future. .EXAMPLE Get-SCCMCollectionMaintenanceWindow.ps1 -SCCMCollectionID <sccm collection id> .EXAMPLE Get-SCCMCollectionMaintenanceWindow.ps1 -SCCMCollectionID <sccm collection id> -Day 19 -Month 2 -Year 2018 .PARAMETER SCCMCollectionID The SCCMCollectionID parameter is the actual collection for which you want to query a Maintenance Window .PARAMETER Day Optional parameter that specifies the day for which to determine a Maintenance Window, if not specified the current day will be used .PARAMETER Month Optional parameter that specifies the month for which to determine a Maintenance Window, if not specified the current month will be used .PARAMETER Year Optional parameter that specifies the year for which to determine a Maintenance Window, if not specified the current year will be used .PARAMETER SiteServer Optional parameter that specifies the Site Server to use for all connections .PARAMETER SiteCode Optional parameter that specifies the Site Code however by default WMI is used to gather this from the Site Server #> Param( [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string]$SCCMCollectionID , [Parameter(Mandatory=$false)] [string]$SiteServer = "mysiteserver.example.com", [Parameter(Mandatory=$false)] [string]$SiteCode = (Get-WmiObject -Namespace "root\SMS" -Class SMS_ProviderLocation -ComputerName $SiteServer).SiteCode, [Parameter(Mandatory=$false)] [int]$Month, [Parameter(Mandatory=$false)] [int]$Day, [Parameter(Mandatory=$false)] [int]$Year ) Write-Verbose "SCCM Site Server : $($SiteServer)" Write-Verbose "SCCM Site code : $($SiteCode)" Write-Verbose "SCCM Collection ID : $($SCCMCollectionID)" If ($Month) { $MonthChosen = $True Write-Verbose "Chosen Month : $($Month)" } Else { [int]$Month = (Get-Date).Month $MonthChosen = $False Write-Verbose "Current Month : $($Month)" } If ($Year) { Write-Verbose "Chosen Year : $($Year)" } Else { [int]$Year = (Get-Date).Year Write-Verbose "Current Year : $($Year)" } If ($Day) { $DayChosen = $True Write-Verbose "Chosen Day : $($Day)" } Else { [int]$Day = (Get-Date).Day $DayChosen = $False Write-Verbose "Current Day : $($Day)" } $DateArray = @() Function Get-CMSchedule { param( $String ) $WMIConnection = [WmiClass]"\\$($SiteServer)\root\SMS\site_$($SiteCode):SMS_ScheduleMethods" $Schedule = $WMIConnection.psbase.GetMethodParameters("ReadFromString") $Schedule.StringData = $String $ScheduleData = $WMIConnection.psbase.InvokeMethod("ReadFromString",$Schedule,$null) $ScheduleInfo = $ScheduleData.TokenData return $ScheduleInfo } $CollectionSettings = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_CollectionSettings -ComputerName $SiteServer -Filter "CollectionID = '$($SCCMCollectionID)'" foreach ($CollectionSetting in $CollectionSettings) { $CollectionSetting.Get() ForEach ($MaintenanceWindow in $CollectionSetting.ServiceWindows) { $StartTime = [Management.ManagementDateTimeConverter]::ToDateTime($MaintenanceWindow.StartTime) $DateArray += $MaintenanceWindow $CollectionName = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_Collection -ComputerName $SiteServer -Filter "CollectionID = '$($CollectionSetting.CollectionID)'" | Select-Object -ExpandProperty Name Write-Verbose "SCCM Collection Name : $($SCCMCollectionID)" Write-Verbose "SCCM Maintenance Window Name : $($MaintenanceWindow.Name)" $SortedDateArray = $DateArray | Sort-Object -Property RecurrenceType | Select-Object Description, RecurrenceType, ServiceWindowSchedules, isEnabled Write-Verbose "Sorted Date Array : $($SortedDateArray)" $RecurrenceType1 = ($SortedDateArray | Where-Object { $_.RecurrenceType -eq 1 }) if ($RecurrenceType1 -ne $null) { foreach ($R1RecurrenceType in $RecurrenceType1) { Write-Verbose "RecurrenceType 1 : $($R1RecurrenceType.IsEnabled)" If ($R1RecurrenceType.IsEnabled -eq $true) { $R1Schedule = Get-CMSchedule -String $R1RecurrenceType.ServiceWindowSchedules Write-Verbose "Schedule : $($R1Schedule.StartTime)" $R1StartTime = [Management.ManagementDateTimeConverter]::ToDateTime($R1Schedule.StartTime) Write-Verbose "Start Time : $($R1StartTime)" $R1WorkingDate = (Get-Date -Month $Month -Year $Year -Day $Day) Write-Verbose "Working Date/Time : $($R1WorkingDate)" If (($R1StartTime.Day -eq $R1WorkingDate.Day) -and ($R1StartTime.Month -eq $R1WorkingDate.Month) -and ($R1StartTime.Year -eq $R1WorkingDate.Year)) { Write-Verbose "Start Day : $($R1StartTime.Day)" Write-Verbose "Start Month : $($R1StartTime.Month)" Write-Verbose "Start Year : $($R1StartTime.Year)" return $R1StartTime } If (($R1StartTime.Month -eq $R1WorkingDate.Month) -and ($R1StartTime.Year -eq $R1WorkingDate.Year)) { Write-Verbose "Start Day : $($R1StartTime.Day)" Write-Verbose "Start Month : $($R1StartTime.Month)" Write-Verbose "Start Year : $($R1StartTime.Year)" return $R1StartTime } } } } $RecurrenceType2 = ($SortedDateArray | Where-Object { $_.RecurrenceType -eq 2 }) if ($RecurrenceType2 -ne $null) { foreach ($R2RecurrenceType in $RecurrenceType2) { Write-Verbose "RecurrenceType 2 : $($R2RecurrenceType.IsEnabled)" If ($R2RecurrenceType.IsEnabled -eq $true) { $R2Schedule = Get-CMSchedule -String $R2RecurrenceType.ServiceWindowSchedules Write-Verbose "Schedule : $($R2Schedule.StartTime)" $R2StartTime = [Management.ManagementDateTimeConverter]::ToDateTime($R2Schedule.StartTime) Write-Verbose "Schedule Start Time : $($R2StartTime)" $R2DaySpan = $R2Schedule.DaySpan Write-Verbose "Day Span : $($R2DaySpan)" $R2CurrentDate = (Get-Date -Month $Month -Year $Year -Day $Day) Write-Verbose "Working Date/Time : $($R2CurrentDate)" If ($MonthChosen -eq $False -and $DayChosen -eq $False) { Write-Verbose "Month chosen on command line : $MonthChosen" Write-Verbose "Day chosen on command line : $DayChosen" do { $R2StartTime = $R2StartTime.AddDays($R2DaySpan) } until ($R2StartTime -ge $R2CurrentDate) } ElseIf ($MonthChosen -eq $True -and $DayChosen -eq $False) { Write-Verbose "Month chosen on command line : $MonthChosen" Write-Verbose "Day chosen on command line : $DayChosen" do { $R2StartTime = $R2StartTime.AddDays($R2DaySpan) } until ($R2StartTime.Month -eq $R2CurrentDate.Month) } ElseIf ($MonthChosen -eq $True -and $DayChosen -eq $True) { Write-Verbose "Month chosen on command line : $MonthChosen" Write-Verbose "Day chosen on command line : $DayChosen" do { $R2StartTime = $R2StartTime.AddDays($R2DaySpan) } until (($R2StartTime.Month -eq $R2CurrentDate.Month) -and ($R2StartTime.Day -eq $R2CurrentDate.Day)) } Write-Verbose "Scheduled Maintenance Date/Time : $($R2StartTime)" return $R2StartTime } } } $RecurrenceType3 = ($SortedDateArray | Where-Object { $_.RecurrenceType -eq 3 }) If ($RecurrenceType3 -ne $null) { foreach ($R3RecurrenceType in $RecurrenceType3) { Write-Verbose "RecurrenceType 3 : $($R3RecurrenceType.IsEnabled)" If ($R3RecurrenceType.IsEnabled -eq $true) { $R3Schedule = Get-CMSchedule -String $R3RecurrenceType.ServiceWindowSchedules Write-Verbose "Schedule : $($R3Schedule.StartTime)" $R3StartMin = [Management.ManagementDateTimeConverter]::ToDateTime($R3Schedule.StartTime) | Select-Object -ExpandProperty Minute Write-Verbose "Start Minute : $($R3StartMin)" $R3StartHour = [Management.ManagementDateTimeConverter]::ToDateTime($R3Schedule.StartTime) | Select-Object -ExpandProperty Hour Write-Verbose "Start Hour : $($R3StartHour)" $R3StartDay = $R3Schedule.Day switch ($R3StartDay) { 1 { $R3DayOfWeek = "Sunday" } 2 { $R3DayOfWeek = "Monday" } 3 { $R3DayOfWeek = "Tuesday" } 4 { $R3DayOfWeek = "Wednesday" } 5 { $R3DayOfWeek = "Thursday" } 6 { $R3DayOfWeek = "Friday" } 7 { $R3DayOfWeek = "Saturday" } } Write-Verbose "Start Day : $($R3StartDay) = $($R3DayOfWeek)" $R3WeekSpan = $R3Schedule.ForNumberOfWeeks switch ($R3WeekSpan) { 1 { $R3AddDays = 0 } 2 { $R3AddDays = 7 } 3 { $R3AddDays = 14 } 4 { $R3AddDays = 21 } } Write-Verbose "For Number of Weeks : $($R3WeekSpan)" $R3CurrentDate = (Get-Date -Month $Month -Year $Year -Day $Day) Write-Verbose "Working Date/Time : $($R3CurrentDate)" $R3DaysUntil = 0 While ($R3CurrentDate.DayOfWeek -ne "$($R3DayOfWeek)") { $R3DaysUntil++ $R3CurrentDate = $R3CurrentDate.AddDays(1) } If ($R3StartHour -le 9) { If ($R3StartMin -le 9) { $R3DateTime = ([datetime]::ParseExact("0$($R3StartHour):0$($R3StartMin)","hh:mm",$null)).AddDays($R3DaysUntil).AddDays($R3AddDays) } elseif ($R3StartMin -ge 10) { $R3DateTime = ([datetime]::ParseExact("0$($R3StartHour):$($R3StartMin)","hh:mm",$null)).AddDays($R3DaysUntil).AddDays($R3AddDays) } } elseif ($R3StartHour -ge 10) { If ($R3StartMin -le 9) { $R3DateTime = ([datetime]::ParseExact("$($R3StartHour):0$($R3StartMin)","hh:mm",$null)).AddDays($R3DaysUntil).AddDays($R3AddDays) } elseif ($R3StartMin -ge 10) { $R3DateTime = ([datetime]::ParseExact("$($R3StartHour):$($R3StartMin)","hh:mm",$null)).AddDays($R3DaysUntil).AddDays($R3AddDays) } } Write-Verbose "Scheduled Maintenance Date/Time : $($R3DateTime)" return $R3DateTime } } } $RecurrenceType4 = ($SortedDateArray | Where-Object { $_.RecurrenceType -eq 4 }) if ($RecurrenceType4 -ne $null) { foreach ($R4RecurrenceType in $RecurrenceType4) { Write-Verbose "RecurrenceType 4 : $($R4RecurrenceType.IsEnabled)" If ($R4RecurrenceType.IsEnabled -eq $true) { $R4Schedule = Get-CMSchedule -String $R4RecurrenceType.ServiceWindowSchedules Write-Verbose "Schedule : $($R4Schedule.StartTime)" $R4WeekOrder = $R4Schedule.WeekOrder Write-Verbose "Week Order : $($R4WeekOrder)" $R4StartHour = [Management.ManagementDateTimeConverter]::ToDateTime($R4Schedule.StartTime) | Select-Object -ExpandProperty Hour Write-Verbose "Start Hour : $($R4StartHour)" $R4StartMin = [Management.ManagementDateTimeConverter]::ToDateTime($R4Schedule.StartTime) | Select-Object -ExpandProperty Minute Write-Verbose "Start Minute : $($R4StartMin)" $R4StartSec = [Management.ManagementDateTimeConverter]::ToDateTime($R4Schedule.StartTime) | Select-Object -ExpandProperty Second Write-Verbose "Start Second : $($R4StartSec)" $R4WeekDay = $R4Schedule.Day switch ($R4WeekDay) { 1 { $R4DayOfWeek = "Sunday" } 2 { $R4DayOfWeek = "Monday" } 3 { $R4DayOfWeek = "Tuesday" } 4 { $R4DayOfWeek = "Wednesday" } 5 { $R4DayOfWeek = "Thursday" } 6 { $R4DayOfWeek = "Friday" } 7 { $R4DayOfWeek = "Saturday" } } Write-Verbose "Start Day : $($R4WeekDay) = $($R4DayOfWeek)" If ($R4WeekOrder -ge 1) { $R4Increment = 0 $R4Date = (Get-Date -Year $Year -Month $Month -Day 1 -Hour $($R4StartHour) -Minute $($R4StartMin) -Second $($R4StartSec)) Do { $R4Increment++ $R4CalcDate = $R4Date.AddDays($R4Increment) $R4CalcDayofWeek = $R4CalcDate.DayOfWeek } Until ($R4CalcDayofWeek -like $R4DayOfWeek) $R4CalcDateTime = $R4CalcDate If ($R4WeekOrder -eq 1) { $R4DateTime = $R4CalcDateTime } elseif ($R4WeekOrder -eq 2) { $R4DateTime = $R4CalcDateTime.AddDays(7) } elseif ($R4WeekOrder -eq 3) { $R4DateTime = $R4CalcDateTime.AddDays(14) } elseif ($R4WeekOrder -eq 4) { $R4DateTime = $R4CalcDateTime.AddDays(21) } } elseif ($R4WeekOrder -eq 0) { $R4Decrement = 0 $R4Date = (Get-Date -Year $Year -Month $Month -Day 1 -Hour $($R4StartHour) -Minute $($R4StartMin) -Second $($R4StartSec)).AddMonths(1) Do { $R4Decrement++ $R4CalcDate = $R4Date.AddDays(-$R4Decrement) $R4CalcDayofWeek = $R4CalcDate.DayOfWeek } Until ($R4CalcDayofWeek -like $R4DayOfWeek) $R4DateTime = $R4CalcDate } Write-Verbose "Scheduled Maintenance Date/Time : $($R4DateTime)" return $R4DateTime } } } $RecurrenceType5 = ($SortedDateArray | Where-Object { $_.RecurrenceType -eq 5 }) If ($RecurrenceType5 -ne $null) { foreach ($R5RecurrenceType in $RecurrenceType5) { Write-Verbose "RecurrenceType 5 : $($R5RecurrenceType.IsEnabled)" If ($R5RecurrenceType.IsEnabled -eq $true) { $R5Schedule = Get-CMSchedule -String $R5RecurrenceType.ServiceWindowSchedules Write-Verbose "Schedule : $($R5Schedule.StartTime)" $R5StartTime = [Management.ManagementDateTimeConverter]::ToDateTime($R5Schedule.StartTime) Write-Verbose "Schedule Start Time : $($R5StartTime)" $R5StartHour = $R5StartTime.Hour Write-Verbose "Start Hour : $($R5StartHour)" $R5StartMin = $R5StartTime.Minute Write-Verbose "Start Minute : $($R5StartMin)" $R5StartSec = $R5StartTime.Second Write-Verbose "Start Second : $($R5StartSec)" $R5MonthSpan = $R5Schedule.ForNumberOfMonths Write-Verbose "For Number of Months : $($R5MonthSpan)" $R5MonthDay = $R5Schedule.MonthDay Write-Verbose "Day of Month : $($R5MonthDay)" If ($R5Schedule.MonthDay -ge 1) { If ($R5MonthSpan -eq 1) { $R5DateTime = ((Get-Date -Year $Year -Month $Month -Day $($R5MonthDay) -Hour $($R5StartHour) -Minute $($R5StartMin) -Second $($R5StartSec))).DateTime } elseif ($R5MonthSpan -gt 1) { $R5DateTime = ((Get-Date -Year $Year -Month $Month -Day $($R5MonthDay) -Hour $($R5StartHour) -Minute $($R5StartMin) -Second $($R5StartSec)).AddMonths($R5MonthSpan)).DateTime } } elseif ($R5Schedule.MonthDay -eq 0) { $R5DateTime = ((Get-Date -Year $Year -Month $Month -Day 1 -Hour $($R5StartHour) -Minute $($R5StartMin) -Second $($R5StartSec)).AddMonths($R5MonthSpan).AddDays(-1)).DateTime } Write-Verbose "Scheduled Maintenance Date/Time : $($R5DateTime)" return $R5DateTime } } } } } }