Private/Build-LMSDTSchedulePayload.ps1
|
$Script:LMSDTValidWeekDays = @( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ) $Script:LMSDTValidWeekOfMonth = @( 'First', 'Second', 'Third', 'Fourth', 'Last' ) $Script:LMSDTRecurringSdtTypeMap = @{ Daily = 'daily' Weekly = 'weekly' Monthly = 'monthly' MonthlyByWeek = 'monthlyByWeek' } $Script:LMSDTScheduleParameterNames = @( 'StartDate', 'EndDate', 'Duration', 'Timezone', 'SdtType', 'StartHour', 'StartMinute', 'EndHour', 'EndMinute', 'WeekDay', 'WeekOfMonth', 'DayOfMonth' ) function ConvertTo-LMSDTScheduleSelection { [CmdletBinding()] param ( [Parameter(Mandatory)] [hashtable]$Selection ) if (-not $Selection.ContainsKey('ScheduleType')) { throw 'Schedule selection requires ScheduleType.' } $Result = @{} switch ($Selection.ScheduleType) { 'OneTimeDurationOnly' { $Result.Duration = $Selection.Duration } 'OneTimeStartDuration' { $Result.StartDate = $Selection.StartDate $Result.Duration = $Selection.Duration } 'OneTimeRange' { $Result.StartDate = $Selection.StartDate $Result.EndDate = $Selection.EndDate } 'Daily' { $Result.SdtType = 'Daily' $Result.StartHour = $Selection.StartHour $Result.StartMinute = $Selection.StartMinute $Result.EndHour = $Selection.EndHour $Result.EndMinute = $Selection.EndMinute } 'Weekly' { $Result.SdtType = 'Weekly' $Result.StartHour = $Selection.StartHour $Result.StartMinute = $Selection.StartMinute $Result.EndHour = $Selection.EndHour $Result.EndMinute = $Selection.EndMinute $Result.WeekDay = @($Selection.WeekDay) } 'Monthly' { $Result.SdtType = 'Monthly' $Result.StartHour = $Selection.StartHour $Result.StartMinute = $Selection.StartMinute $Result.EndHour = $Selection.EndHour $Result.EndMinute = $Selection.EndMinute $Result.DayOfMonth = $Selection.DayOfMonth } 'MonthlyByWeek' { $Result.SdtType = 'MonthlyByWeek' $Result.StartHour = $Selection.StartHour $Result.StartMinute = $Selection.StartMinute $Result.EndHour = $Selection.EndHour $Result.EndMinute = $Selection.EndMinute $Result.WeekDay = @($Selection.WeekDay) $Result.WeekOfMonth = $Selection.WeekOfMonth } default { throw "Unsupported schedule type '$($Selection.ScheduleType)'." } } if ($Selection.ContainsKey('Timezone') -and -not [String]::IsNullOrWhiteSpace($Selection.Timezone)) { $Result.Timezone = $Selection.Timezone } return $Result } function Get-LMSDTScheduleBoundParameters { [CmdletBinding()] param ( [Parameter(Mandatory)] [hashtable]$BoundParameters ) $ScheduleBound = @{} foreach ($Key in $Script:LMSDTScheduleParameterNames) { if ($BoundParameters.ContainsKey($Key)) { $ScheduleBound[$Key] = $BoundParameters[$Key] } } return $ScheduleBound } function Resolve-LMSDTScheduleParameterSetName { [CmdletBinding()] param ( [Parameter(Mandatory)] [hashtable]$BoundParameters, [switch]$AllowPartial ) $ScheduleBound = Get-LMSDTScheduleBoundParameters -BoundParameters $BoundParameters if ($ScheduleBound.Count -eq 0) { if ($AllowPartial) { return 'Partial' } throw 'No schedule parameters were specified.' } if ($ScheduleBound.ContainsKey('Duration') -and $ScheduleBound.ContainsKey('EndDate')) { throw 'Cannot specify both -Duration and -EndDate. Use -StartDate with -EndDate for a fixed window, or -Duration for a length-based one-time SDT.' } $HasRecurringMarker = $ScheduleBound.ContainsKey('SdtType') -or $ScheduleBound.ContainsKey('WeekDay') -or $ScheduleBound.ContainsKey('WeekOfMonth') -or $ScheduleBound.ContainsKey('DayOfMonth') $RecurringTimeFields = @('StartHour', 'StartMinute', 'EndHour', 'EndMinute') $RecurringTimeCount = @($RecurringTimeFields | Where-Object { $ScheduleBound.ContainsKey($_) }).Count $HasAnyRecurringTime = $RecurringTimeCount -gt 0 $HasAllRecurringTime = $RecurringTimeCount -eq $RecurringTimeFields.Count if ($HasRecurringMarker -or $HasAnyRecurringTime) { if ($ScheduleBound.ContainsKey('Duration') -or ($ScheduleBound.ContainsKey('StartDate') -and $ScheduleBound.ContainsKey('EndDate'))) { throw 'Cannot mix recurring schedule parameters with one-time parameters (-Duration or -StartDate/-EndDate).' } if ($HasAnyRecurringTime -and -not $HasAllRecurringTime) { throw 'Recurring schedules require -StartHour, -StartMinute, -EndHour, and -EndMinute.' } return 'Recurring' } if ($ScheduleBound.ContainsKey('StartDate') -and $ScheduleBound.ContainsKey('EndDate')) { return 'OneTimeRange' } if ($ScheduleBound.ContainsKey('Duration')) { return 'OneTimeDuration' } if ($AllowPartial) { return 'Partial' } throw @' Specify a schedule using one of: -Duration (optional -StartDate) for a one-time SDT -StartDate and -EndDate for a fixed one-time window -SdtType Daily|Weekly|Monthly|MonthlyByWeek with -StartHour, -StartMinute, -EndHour, and -EndMinute '@ } function Test-LMSDTDayOfMonth { [CmdletBinding()] param ( [Parameter(Mandatory)] [Int]$DayOfMonth ) if ($DayOfMonth -eq -3) { return $true } if ($DayOfMonth -ge 1 -and $DayOfMonth -le 31) { return $true } throw 'DayOfMonth must be between 1 and 31, or -3 for the last day of the month.' } function Test-LMSDTWeekDay { [CmdletBinding()] param ( [Parameter(Mandatory)] [AllowEmptyCollection()] [String[]]$WeekDay ) if ($null -eq $WeekDay -or $WeekDay.Count -eq 0) { throw 'WeekDay requires at least one day (Monday through Sunday).' } foreach ($Day in $WeekDay) { if ($Day -notin $Script:LMSDTValidWeekDays) { throw "Invalid WeekDay '$Day'. Valid values: $($Script:LMSDTValidWeekDays -join ', ')." } } return $true } function ConvertTo-LMSDTWeekDayApiValue { [CmdletBinding()] param ( [Parameter(Mandatory)] [String[]]$WeekDay ) Test-LMSDTWeekDay -WeekDay $WeekDay | Out-Null return ($WeekDay -join ',') } function Get-LMSDTRecurringDurationMinutes { [CmdletBinding()] param ( [Parameter(Mandatory)] [Int]$StartHour, [Parameter(Mandatory)] [Int]$StartMinute, [Parameter(Mandatory)] [Int]$EndHour, [Parameter(Mandatory)] [Int]$EndMinute ) $StartTotalMinutes = ($StartHour * 60) + $StartMinute $EndTotalMinutes = ($EndHour * 60) + $EndMinute $Duration = $EndTotalMinutes - $StartTotalMinutes if ($Duration -le 0) { $Duration += (24 * 60) } return $Duration } function Test-LMSDTScheduleParameters { [CmdletBinding()] param ( [Parameter(Mandatory)] [ValidateSet('OneTimeDuration', 'OneTimeRange', 'Recurring', 'Partial')] [String]$ParameterSetName, [Parameter(Mandatory)] [hashtable]$BoundParameters ) $StartDate = $BoundParameters['StartDate'] $EndDate = $BoundParameters['EndDate'] $Duration = $BoundParameters['Duration'] $SdtType = $BoundParameters['SdtType'] $StartHour = $BoundParameters['StartHour'] $StartMinute = $BoundParameters['StartMinute'] $EndHour = $BoundParameters['EndHour'] $EndMinute = $BoundParameters['EndMinute'] $WeekDay = $BoundParameters['WeekDay'] $WeekOfMonth = $BoundParameters['WeekOfMonth'] $DayOfMonth = $BoundParameters['DayOfMonth'] switch ($ParameterSetName) { 'OneTimeDuration' { if ($null -eq $Duration -or $Duration -le 0) { throw 'OneTimeDuration requires a positive -Duration value in minutes.' } if ($BoundParameters.ContainsKey('EndDate')) { throw 'Cannot specify both -Duration and -EndDate. Use -StartDate with -EndDate for a fixed window, or -Duration for a length-based one-time SDT.' } } 'OneTimeRange' { if ($null -eq $StartDate -or $null -eq $EndDate) { throw 'One-time SDTs with a fixed window require both -StartDate and -EndDate.' } if ($EndDate -le $StartDate) { throw 'EndDate must be after StartDate.' } if ($BoundParameters.ContainsKey('Duration')) { throw 'Cannot specify both -Duration and -EndDate. Use -StartDate with -EndDate for a fixed window, or -Duration for a length-based one-time SDT.' } } 'Recurring' { if ([String]::IsNullOrWhiteSpace($SdtType)) { throw 'Recurring SDTs require -SdtType (Daily, Weekly, Monthly, or MonthlyByWeek), or omit -SdtType when providing all four time fields to default to Daily.' } foreach ($RequiredParam in @('StartHour', 'StartMinute', 'EndHour', 'EndMinute')) { if (-not $BoundParameters.ContainsKey($RequiredParam)) { throw "Recurring requires -$RequiredParam." } } switch ($SdtType) { 'Weekly' { Test-LMSDTWeekDay -WeekDay $WeekDay | Out-Null } 'Monthly' { if (-not $BoundParameters.ContainsKey('DayOfMonth')) { throw 'Monthly recurring SDTs require -DayOfMonth.' } Test-LMSDTDayOfMonth -DayOfMonth $DayOfMonth | Out-Null } 'MonthlyByWeek' { Test-LMSDTWeekDay -WeekDay $WeekDay | Out-Null if ([String]::IsNullOrWhiteSpace($WeekOfMonth)) { throw 'MonthlyByWeek recurring SDTs require -WeekOfMonth.' } if ($WeekOfMonth -notin $Script:LMSDTValidWeekOfMonth) { throw "Invalid WeekOfMonth '$WeekOfMonth'. Valid values: $($Script:LMSDTValidWeekOfMonth -join ', ')." } } } } 'Partial' { if ($BoundParameters.ContainsKey('Duration') -and $BoundParameters.ContainsKey('EndDate')) { throw 'Cannot specify both -Duration and -EndDate in the same update.' } if ($BoundParameters.ContainsKey('DayOfMonth')) { Test-LMSDTDayOfMonth -DayOfMonth $DayOfMonth | Out-Null } if ($BoundParameters.ContainsKey('WeekDay')) { Test-LMSDTWeekDay -WeekDay $WeekDay | Out-Null } if ($BoundParameters.ContainsKey('WeekOfMonth') -and $WeekOfMonth -notin $Script:LMSDTValidWeekOfMonth) { throw "Invalid WeekOfMonth '$WeekOfMonth'. Valid values: $($Script:LMSDTValidWeekOfMonth -join ', ')." } if ($BoundParameters.ContainsKey('SdtType') -and $SdtType -notin $Script:LMSDTRecurringSdtTypeMap.Keys) { throw "Invalid SdtType '$SdtType'. Valid values: $($Script:LMSDTRecurringSdtTypeMap.Keys -join ', ')." } } } return $true } function Build-LMSDTSchedulePayload { [CmdletBinding()] param ( [ValidateSet('OneTimeDuration', 'OneTimeRange', 'Recurring', 'Partial')] [String]$ParameterSetName, [Parameter(Mandatory)] [hashtable]$BoundParameters, [switch]$AllowPartial ) if ([String]::IsNullOrWhiteSpace($ParameterSetName)) { $ParameterSetName = Resolve-LMSDTScheduleParameterSetName -BoundParameters $BoundParameters -AllowPartial:$AllowPartial } $ScheduleBound = Get-LMSDTScheduleBoundParameters -BoundParameters $BoundParameters if ($ParameterSetName -eq 'Recurring' -and -not $ScheduleBound.ContainsKey('SdtType')) { $ScheduleBound['SdtType'] = 'Daily' } Test-LMSDTScheduleParameters -ParameterSetName $ParameterSetName -BoundParameters $ScheduleBound | Out-Null $Timezone = $ScheduleBound['Timezone'] $StartDate = $ScheduleBound['StartDate'] $EndDate = $ScheduleBound['EndDate'] $Duration = $ScheduleBound['Duration'] $SdtType = $ScheduleBound['SdtType'] $StartHour = $ScheduleBound['StartHour'] $StartMinute = $ScheduleBound['StartMinute'] $EndHour = $ScheduleBound['EndHour'] $EndMinute = $ScheduleBound['EndMinute'] $WeekDay = $ScheduleBound['WeekDay'] $WeekOfMonth = $ScheduleBound['WeekOfMonth'] $DayOfMonth = $ScheduleBound['DayOfMonth'] $NeedsTimezone = $ParameterSetName -in @('OneTimeDuration', 'OneTimeRange', 'Recurring') -or ($ParameterSetName -eq 'Partial' -and ( $ScheduleBound.ContainsKey('StartDate') -or $ScheduleBound.ContainsKey('EndDate') -or $ScheduleBound.ContainsKey('Duration') )) $EffectiveTimezone = $null if ($NeedsTimezone) { $EffectiveTimezone = Resolve-LMSDTTimezone -Timezone $Timezone } elseif ($ScheduleBound.ContainsKey('Timezone') -and -not [String]::IsNullOrWhiteSpace($Timezone)) { Test-LMTimezoneId -Timezone $Timezone | Out-Null $EffectiveTimezone = Resolve-LMTimezoneToIANAId -Timezone $Timezone } $Data = @{} if ($null -ne $EffectiveTimezone -and ( $ParameterSetName -ne 'Partial' -or $ScheduleBound.ContainsKey('Timezone') -or $NeedsTimezone )) { $Data['timezone'] = $EffectiveTimezone } switch ($ParameterSetName) { 'OneTimeDuration' { $EffectiveStartDate = if ($StartDate) { $StartDate } else { Get-Date } $EffectiveEndDate = $EffectiveStartDate.AddMinutes($Duration) $Data['sdtType'] = 'oneTime' $Data['duration'] = $Duration $Data['startDateTime'] = ConvertTo-LMSDTEpochMillis -DateTime $EffectiveStartDate -Timezone $EffectiveTimezone $Data['endDateTime'] = ConvertTo-LMSDTEpochMillis -DateTime $EffectiveEndDate -Timezone $EffectiveTimezone } 'OneTimeRange' { $ComputedDuration = [Int][Math]::Round(($EndDate - $StartDate).TotalMinutes) $Data['sdtType'] = 'oneTime' $Data['duration'] = $ComputedDuration $Data['startDateTime'] = ConvertTo-LMSDTEpochMillis -DateTime $StartDate -Timezone $EffectiveTimezone $Data['endDateTime'] = ConvertTo-LMSDTEpochMillis -DateTime $EndDate -Timezone $EffectiveTimezone } 'Recurring' { $ApiSdtType = $Script:LMSDTRecurringSdtTypeMap[$SdtType] $RecurringDuration = Get-LMSDTRecurringDurationMinutes -StartHour $StartHour -StartMinute $StartMinute -EndHour $EndHour -EndMinute $EndMinute $Data['sdtType'] = $ApiSdtType $Data['duration'] = $RecurringDuration $Data['hour'] = $StartHour $Data['minute'] = $StartMinute $Data['endHour'] = $EndHour $Data['endMinute'] = $EndMinute switch ($SdtType) { 'Weekly' { $Data['weekDay'] = ConvertTo-LMSDTWeekDayApiValue -WeekDay $WeekDay } 'Monthly' { $Data['monthDay'] = $DayOfMonth } 'MonthlyByWeek' { $Data['weekDay'] = ConvertTo-LMSDTWeekDayApiValue -WeekDay $WeekDay $Data['weekOfMonth'] = $WeekOfMonth } } } 'Partial' { if ($ScheduleBound.ContainsKey('SdtType')) { $Data['sdtType'] = $Script:LMSDTRecurringSdtTypeMap[$SdtType] } if ($ScheduleBound.ContainsKey('Duration')) { $Data['duration'] = $Duration } if ($ScheduleBound.ContainsKey('StartHour')) { $Data['hour'] = $StartHour } if ($ScheduleBound.ContainsKey('StartMinute')) { $Data['minute'] = $StartMinute } if ($ScheduleBound.ContainsKey('EndHour')) { $Data['endHour'] = $EndHour } if ($ScheduleBound.ContainsKey('EndMinute')) { $Data['endMinute'] = $EndMinute } if ($ScheduleBound.ContainsKey('WeekDay')) { $Data['weekDay'] = ConvertTo-LMSDTWeekDayApiValue -WeekDay $WeekDay } if ($ScheduleBound.ContainsKey('DayOfMonth')) { $Data['monthDay'] = $DayOfMonth } if ($ScheduleBound.ContainsKey('WeekOfMonth')) { $Data['weekOfMonth'] = $WeekOfMonth } if ($ScheduleBound.ContainsKey('StartDate') -or $ScheduleBound.ContainsKey('EndDate') -or $ScheduleBound.ContainsKey('Duration')) { if (-not $EffectiveTimezone) { $EffectiveTimezone = Resolve-LMSDTTimezone -Timezone $Timezone $Data['timezone'] = $EffectiveTimezone } $PartialStartDate = if ($ScheduleBound.ContainsKey('StartDate')) { $StartDate } else { $null } $PartialEndDate = if ($ScheduleBound.ContainsKey('EndDate')) { $EndDate } else { $null } if ($ScheduleBound.ContainsKey('Duration')) { if ($PartialStartDate) { $PartialEndDate = $PartialStartDate.AddMinutes($Duration) } $Data['duration'] = $Duration } if ($PartialStartDate) { $Data['startDateTime'] = ConvertTo-LMSDTEpochMillis -DateTime $PartialStartDate -Timezone $EffectiveTimezone } if ($PartialEndDate) { $Data['endDateTime'] = ConvertTo-LMSDTEpochMillis -DateTime $PartialEndDate -Timezone $EffectiveTimezone } if ($ScheduleBound.ContainsKey('StartDate') -and $ScheduleBound.ContainsKey('EndDate') -and -not $ScheduleBound.ContainsKey('Duration')) { $Data['duration'] = [Int][Math]::Round(($EndDate - $StartDate).TotalMinutes) } } if ($ScheduleBound.ContainsKey('StartHour') -and $ScheduleBound.ContainsKey('StartMinute') -and $ScheduleBound.ContainsKey('EndHour') -and $ScheduleBound.ContainsKey('EndMinute') -and -not $ScheduleBound.ContainsKey('Duration')) { $Data['duration'] = Get-LMSDTRecurringDurationMinutes -StartHour $StartHour -StartMinute $StartMinute -EndHour $EndHour -EndMinute $EndMinute } } } return $Data } function Write-LMSDTSchedulePreview { [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Required for interactive wizards')] param ( [Parameter(Mandatory)] [hashtable]$PreviewPayload ) Write-Host "Schedule type: $($PreviewPayload.sdtType)" if ($PreviewPayload.ContainsKey('duration')) { Write-Host "Duration (minutes): $($PreviewPayload.duration)" } if ($PreviewPayload.ContainsKey('startDateTime')) { Write-Host "Start: $($PreviewPayload.startDateTime)" } if ($PreviewPayload.ContainsKey('endDateTime')) { Write-Host "End: $($PreviewPayload.endDateTime)" } if ($PreviewPayload.ContainsKey('hour')) { Write-Host "Time window: $($PreviewPayload.hour):$($PreviewPayload.minute.ToString('00')) - $($PreviewPayload.endHour):$($PreviewPayload.endMinute.ToString('00'))" } if ($PreviewPayload.ContainsKey('weekDay')) { Write-Host "WeekDay: $($PreviewPayload.weekDay)" } if ($PreviewPayload.ContainsKey('monthDay')) { Write-Host "MonthDay: $($PreviewPayload.monthDay)" } if ($PreviewPayload.ContainsKey('weekOfMonth')) { Write-Host "WeekOfMonth: $($PreviewPayload.weekOfMonth)" } if ($PreviewPayload.ContainsKey('timezone')) { Write-Host "Timezone: $($PreviewPayload.timezone)" } } function Invoke-LMCreateSDT { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'None')] param ( [Parameter(Mandatory)] [System.Management.Automation.PSCmdlet]$CallerPSCmdlet, [Parameter(Mandatory)] [hashtable]$Payload, [Parameter(Mandatory)] [String]$ShouldProcessTarget, [Parameter(Mandatory)] [String]$ShouldProcessAction ) if (-not $Script:LMAuth.Valid) { Write-Error 'Please ensure you are logged in before running any commands, use Connect-LMAccount to login and try again.' return } $ResourcePath = '/sdt/sdts' $RequestBody = Format-LMData -Data $Payload -UserSpecifiedKeys @() if ($CallerPSCmdlet.ShouldProcess($ShouldProcessTarget, $ShouldProcessAction)) { $Headers = New-LMHeader -Auth $Script:LMAuth -Method 'POST' -ResourcePath $ResourcePath -Data $RequestBody $Uri = "https://$($Script:LMAuth.Portal).$(Get-LMPortalURI)" + $ResourcePath Resolve-LMDebugInfo -Url $Uri -Headers $Headers[0] -Command $CallerPSCmdlet.MyInvocation -Payload $RequestBody return Invoke-LMRestMethod -CallerPSCmdlet $CallerPSCmdlet -Uri $Uri -Method 'POST' -Headers $Headers[0] -WebSession $Headers[1] -Body $RequestBody } } |