public/Start-VSAPatchUpdate.ps1

function Start-VSAPatchUpdate
{
    <#
    .Synopsis
       Runs a patch update immediately.
    .DESCRIPTION
       Runs a patch update immediately.
       Takes either persistent or non-persistent connection information.
    .PARAMETER VSAConnection
        Specifies existing non-persistent VSAConnection.
    .PARAMETER URISuffix
        Specifies URI suffix if it differs from the default.
     .PARAMETER AgentGuids
        Specifies array of agent ids or single id
    .PARAMETER ServerTimeZone
        Specifies if procedure should be scheduled in server time zone
    .PARAMETER SkipIfOffLine
        Specifies if procedure should NOT be executed if agent is offline at scheduled time
    .PARAMETER PowerUpIfOffLine
        Specifies if machine should be powered up at scheduled time
    .PARAMETER SpecificDayOfMonth
        Specifies index of day in the month
    .PARAMETER EndAt
        Specifies 15 minutes interval when procedure should end
    .PARAMETER EndOn
        Specifies date and time when recurrence should be ended
    .PARAMETER EndAfterIntervalTimes
        Specifies if recurrence should end after specific amount of executions
    .PARAMETER Interval
        Specifies unit of measurement for interval of distribution window
    .PARAMETER Magniture
        Specifies numeric interval of distribution window
    .PARAMETER StartOn
    Specifies date and time when procedure should be executed
    .PARAMETER StartAt
    Specifies 15 minutes interval when procedure should be executed
    .PARAMETER ExcludeFrom
    Specifies interval for exclusion of execution
    .PARAMETER ExcludeTo
    Specifies interval for exclusion of execution
    .PARAMETER AgentTime
    Specifies if agent procedure should be scheduled in time of agent
    .EXAMPLE
       Start-VSAPatchUpdate -AgentGuids 323289329849, 0402309209209 -Repeat "Never" -PowerUpIfOffLine -SkipIfOffLine -EndOn "2021-09-30T11:20:00.000Z" -EndAt "2021-09-30T11:20:00.000Z"
    .EXAMPLE
       Start-VSAPatchUpdate -AgentGuids 323289329849, 0402309209209 -EndAt "T1345" -EndOn "2021-10-30T12:00:00.000Z" -Repeat "Days" -Times 3 -AgentTime -ExcludeFrom "T1000" -ExcludeTo "T1200"
    .INPUTS
       Accepts piped non-persistent VSAConnection
    .OUTPUTS
       Success or failure
    #>


    [CmdletBinding()]
    param ( 
        [parameter(Mandatory = $true, 
            ValueFromPipelineByPropertyName = $true)]
        [VSAConnection] $VSAConnection,

        [parameter(DontShow, Mandatory=$false,
            ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()] 
        [string] $URISuffix = "api/v1.0/assetmgmt/patch/runnow",

        [parameter(Mandatory=$true,
            ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()] 
        [array] $AgentGuids,

        [switch] $ServerTimeZone,

        [switch] $SkipIfOffLine,

        [switch] $PowerUpIfOffLine,

        [parameter(Mandatory = $false,
            ValueFromPipelineByPropertyName = $true)]
        [ValidateSet('Never', 'Minutes', 'Hours', 'Days', 'Weeks', 'Months', 'Years')]
        [string] $Repeat = 'Never',

        [Parameter(Mandatory = $false)]
        [ValidateScript({
            if( $_ -notmatch "^\d+$" ) {
                throw "Non-numeric value"
            }
            return $true
        })]
        [string] $SpecificDayOfMonth,

        [string] $EndAt,

        [string] $EndOn,

        [string] $EndAfterIntervalTimes,

        [string] $Interval = 'Minutes',
        [Parameter(Mandatory = $false)]
        [ValidateScript({
            if( $_ -notmatch "^\d+$" ) {
                throw "Non-numeric value"
            }
            return $true
        })]
        [string] $Magnitude = '0',

        [string] $StartOn,

        [string] $StartAt,

        [string] $ExcludeFrom,

        [string] $ExcludeTo,

        [switch] $AgentTime

        
)
   
    DynamicParam {
        if ('Never' -notmatch $Repeat) {
            $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

            # Helper function to create RuntimeDefinedParameter
            function New-RuntimeParameter {
                param (
                    [string]$Name,
                    [Type]$Type,
                    [string[]]$ValidateSet
                )

                $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]

                $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
                $ParameterAttribute.Mandatory = $false
                $AttributeCollection.Add($ParameterAttribute)

                if ($ValidateSet) {
                    $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($ValidateSet)
                    $AttributeCollection.Add($ValidateSetAttribute)
                }

                return New-Object System.Management.Automation.RuntimeDefinedParameter($Name, $Type, $AttributeCollection)
            }

            # Define parameters
            $RuntimeParameterDictionary.Add('Times', (New-RuntimeParameter -Name 'Times' -Type [int] -ValidateSet $null))

            $DaysOfWeekSet = @('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday')
            $RuntimeParameterDictionary.Add('DaysOfWeek', (New-RuntimeParameter -Name 'DaysOfWeek' -Type [string] -ValidateSet $DaysOfWeekSet))

            $DayOfMonthSet = @(
                'FirstSunday', 'SecondSunday', 'ThirdSunday', 'FourthSunday', 'LastSunday',
                'FirstMonday', 'SecondMonday', 'ThirdMonday', 'FourthMonday', 'LastMonday',
                'FirstTuesday', 'SecondTuesday', 'ThirdTuesday', 'FourthTuesday', 'LastTuesday',
                'FirstWednesday', 'SecondWednesday', 'ThirdWednesday', 'FourthWednesday', 'LastWednesday',
                'FirstThursday', 'SecondThursday', 'ThirdThursday', 'FourthThursday', 'LastThursday',
                'FirstFriday', 'SecondFriday', 'ThirdFriday', 'FourthFriday', 'LastFriday',
                'FirstSaturday', 'SecondSaturday', 'ThirdSaturday', 'FourthSaturday', 'LastSaturday',
                'FirstWeekDay', 'SecondWeekDay', 'ThirdWeekDay', 'FourthWeekDay', 'LastWeekDay',
                'FirstWeekendDay', 'SecondWeekendDay', 'ThirdWeekendDay', 'FourthWeekendDay', 'LastWeekendDay',
                'FirstDay', 'SecondDay', 'ThirdDay', 'FourthDay', 'LastDay'
            )
            $RuntimeParameterDictionary.Add('DayOfMonth', (New-RuntimeParameter -Name 'DayOfMonth' -Type [string] -ValidateSet $DayOfMonthSet))

            $MonthOfYearSet = @('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December')
            $RuntimeParameterDictionary.Add('MonthOfYear', (New-RuntimeParameter -Name 'MonthOfYear' -Type [string] -ValidateSet $MonthOfYearSet))

            return $RuntimeParameterDictionary
        }
    }

    Process {    
   
        [string] $Times       = $PSBoundParameters.Times
        [string] $DaysOfWeek  = $PSBoundParameters.DaysOfWeek
        [string] $DayOfMonth  = $PSBoundParameters.DayOfMonth
        [string] $MonthOfYear = $PSBoundParameters.MonthOfYear

        [hashtable]$Recurrence = @{
            Repeat                = $Repeat
            EndAt                 = $EndAt
            EndOn                 = $EndOn
            Times                 = $Times
            DaysOfWeek            = $DaysOfWeek
            DayOfMonth            = $DayOfMonth
            SpecificDayOfMonth    = $SpecificDayOfMonth
            MonthOfYear           = $MonthOfYear
            EndAfterIntervalTimes = $EndAfterIntervalTimes
        }
        foreach ( $key in $Recurrence.Keys.Clone()  ) {
            if ( -not $Recurrence[$key]) { $Recurrence.Remove($key) }
        }
    
        [hashtable]$Distribution = @{
            Interval  = $Interval
            Magnitude = $Magnitude
        }

        [hashtable]$Start =@{
            StartOn = $StartOn
            StartAt = $StartAt
        }

        [hashtable]$Exclusion =@{
            From = $ExcludeFrom
            To = $ExcludeTo
        }

        $BodyHT = @{
            ServerTimeZone   = $ServerTimeZone.ToBool()
            SkipIfOffline    = $SkipIfOffLine.ToBool()
            PowerUpIfOffLine = $PowerUpIfOffLine.ToBool()
            Recurrence       = $Recurrence
            Distribution     = $Distribution
            SchedInAgentTime = $AgentTime.ToBool()
            Start            = $Start
            AgentGuids       = $AgentGuids
        }
        foreach ( $key in $BodyHT.Keys.Clone()  ) {
            if ( -not $BodyHT[$key]) { $BodyHT.Remove($key) }
        }

        if ( (-not [string]::IsNullOrEmpty($ExcludeFrom)) -and (-not [string]::IsNullOrEmpty($ExcludeTo))) {
            $BodyHT.Add('Exclusion', $Exclusion)
        }

        [hashtable]$Params =@{
            URISuffix = $URISuffix
            Method    = 'PUT'
            Body      = $($BodyHT | ConvertTo-Json)
        }

        if($VSAConnection) {$Params.Add('VSAConnection', $VSAConnection)}

        return Invoke-VSARestMethod @Params
    }

}

Export-ModuleMember -Function Start-VSAPatchUpdate