Public/New-SpecScheduledTask.ps1
Function New-SpecScheduledTask { <# .SYNOPSIS This function creates a new scheduled task with specified settings and options. .DESCRIPTION The New-SpecScheduledTask function creates a new scheduled task based on the provided parameters. It supports creating various types of tasks with different triggers, actions, principals, settings, and options. .PARAMETER Taskname Specifies the name of the scheduled task. If not provided, the leaf name of the specified path will be used. .PARAMETER Description Specifies the description of the scheduled task. .PARAMETER TaskFolder Specifies the folder in which the task will be created. Default is 'Specsavers'. .PARAMETER Path Specifies the path to the executable or script for the task action. .PARAMETER Arguments Specifies the arguments to be passed to the task action. (Do not use if it is a .ps1 file) .PARAMETER StartIn Specifies the working directory for the task action. (Do not use if it is a .ps1 file) .PARAMETER Trigger Specifies the trigger type for the task. Valid values are "AtLogon," "AtStartup," and "Daily." .PARAMETER RunAs Specifies the user account or security group to run the task as. Valid values are 'NT AUTHORITY\SYSTEM' and 'BUILTIN\Users'. Default is 'NT AUTHORITY\SYSTEM''. .PARAMETER DelayTaskByXMinutes Specifies the number of minutes to delay the task execution. e.g. 15 If you need to use over an hour, continue to use minutes, eg 68 (equivalent to 1 hour 8 minutes) .PARAMETER RunWithHighestPrivilege Indicates whether the task should be run with the highest privileges. .PARAMETER StartTaskImmediately Indicates whether to start the task immediately after creating it. .PARAMETER IgnoreTestPath Allows ignoring the path verification step. If the path does not exist then the scheduled task will still be created. .PARAMETER RandomiseTaskUpToXMinutes Specifies the number of minutes to randomly delay the task execution (used with the "Daily" trigger type). eg 30 If you need to use over an hour, continue to use minutes, eg 68 (equivalent to 1 hour 8 minutes) .PARAMETER Time Specifies the time for the trigger (used with the "Daily" trigger type). '04:00pm', '16:00', '3:12am' and '03:12' are all valid time values. .EXAMPLE $taskStatus = New-SpecScheduledTask -Description "My Task" -Path "C:\Scripts\MyScript.ps1" -Trigger "Daily" -Time "02:00" -RunWithHighestPrivilege -StartTaskImmediately Creates a new scheduled task named "My Task" that runs a PowerShell script daily at 2:00 AM with highest privileges and starts the task immediately. .EXAMPLE $taskStatus = New-SpecScheduledTask -Taskname "MyTask" -Description "My Task" -Path "C:\Program Files\MyApp.exe" -RunAs "NT AUTHORITY\SYSTEM" -DelayTaskByXMinutes 15 -IgnoreTestPath Creates a new scheduled task named "MyTask" that runs an executable with a 15-minute delay and ignores path verification. .NOTES Author: owen.heaume Date: August 10, 2023 Version: 2.0 - initial function 2.1 - remove check to see if startin or args used on .ps1 script as it is now allowed 2.2 - add parameter $RepeatEveryXMinutes to allow for repeating tasks and relevant code updates 2.3 - Added TurnOffExecutionTimeLimit parameter to turn off the execution time limit. .OUTPUTS Status Codes: - 901: Path does not exist and -IgnoreTestPath not used. - 900: Task already exists. - 910: An error occurred assigning task action configuration. - 911: An error occurred assigning task trigger configuration. - 912: An error occurred assigning task principal configuration. - 913: An error occurred assigning task settings configuration. - 914: An error occurred creating the task using Register-ScheduledTask. - 915: An error occurred starting the task using Start-ScheduledTask. - 916: Incorrect parameter combination ( -arguments or -Startin with .ps1 extension n path) - 917: Incorrect parameter combination (Do not use '-DelayTaskByXMinutes' with '-randomiseTaskUpToXminutes') - 0: Successful task creation. #> [cmdletbinding()] Param ( [parameter (mandatory = $false)] [string]$Taskname, [parameter (mandatory = $true)] [string]$Description, [parameter (mandatory = $false)] [string]$TaskFolder = 'Specsavers', [parameter (mandatory = $true)] [string]$Path, [parameter (mandatory = $false)] [string]$Arguments, [parameter (mandatory = $false)] [string]$StartIn, [parameter (mandatory = $false)] [ValidateSet('AtLogon', 'AtStartup', 'Daily')] [string]$Trigger = 'AtStartUp', [parameter (mandatory = $false)] [ValidateSet('BUILTIN\Users', 'NT AUTHORITY\SYSTEM', 'BUILTIN\Administrators')] [string]$RunAs = 'NT AUTHORITY\SYSTEM', [parameter (mandatory = $false)] [int]$DelayTaskByXMinutes, [parameter (mandatory = $false)] $RepeatEveryXMinutes, [switch]$RunWithHighestPrivilege, [switch]$StartTaskImmediately, [switch]$IgnoreTestPath, [switch]$TurnOffExecutionTimeLimit ) DynamicParam { if ($Trigger -eq 'Daily') { # Define parameter attributes $paramAttributes = New-Object -Type System.Management.Automation.ParameterAttribute $paramAttributes.Mandatory = $true # Create collection of the attributes $paramAttributesCollect = New-Object -Type ` System.Collections.ObjectModel.Collection[System.Attribute] $paramAttributesCollect.Add($paramAttributes) # Create parameter with name, type, and attributes $dynParam1 = New-Object -Type ` System.Management.Automation.RuntimeDefinedParameter("RandomiseTaskUpToXMinutes", [int], $paramAttributesCollect) $dynParam2 = New-Object -Type ` System.Management.Automation.RuntimeDefinedParameter("Time", [string], $paramAttributesCollect) # Add parameter to parameter dictionary and return the object $paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary $paramDictionary.Add("RandomiseTaskUpToXMinutes", $dynParam1) $paramDictionary.Add("Time", $dynParam2) return $paramDictionary } } Begin { # Assign dynamic parameters to variables so they can be tested if they were used later in the script. $RandomiseTaskUpToXMinutes = $PSBoundParameters['RandomiseTaskUpToXMinutes'] $Time = $PSBoundParameters['Time'] } Process { # check parameters combinations are valid # if ((Test-SpecPS1Extension -filePath $path -verbose:$false) -and ($Arguments -or $StartIn)) { # Write-warning "Please do not use '-Arguments' or '-StartIn' when the path contains a PowerShell (.ps1) script" # return 916 # } if ($Trigger -eq 'Daily' -and $RandomiseTaskUpToXMinutes -and $DelayTaskByXMinutes) { Write-Warning "Please do not use '-DelayTaskByXMinutes' with '-randomiseTaskUpToXminutes'" return 917 } # Path check $pathExists = Test-Path $Path -PathType Leaf if ($IgnoreTestPath) { Write-Verbose "Skipping path verification due to -IgnoreTestPath switch" } if ($pathExists -eq $false -and $IgnoreTestPath -eq $false) { Write-Warning "The path $path does not exist. Please use the -IgnoreTestPath switch to override this error." return 901 } # If -TaskName was not used, then get the leaf name of the path to use instead if ([string]::IsNullOrEmpty($taskname)) { $TaskName = Get-SpecLeafName -Path $Path } # Check if the task already exists $TaskExists = Get-SpecScheduledTask -TaskName $TaskName if ($TaskExists -eq 900) { # 900 is the error code for the Get-SpecScheduledTask function Write-Host "The task $TaskName already exists. Please use a different name." -ForegroundColor DarkYellow return 900 } # Create the scheduled task action $taskAction = New-SpecScheduledTaskAction -IsPs1Script (Test-SpecPS1Extension -filePath $Path) -path $Path -arguments $Arguments -startin $StartIn if ($TaskAction -eq 910) { # 910 is the error code for the New-SpecScheduledTaskAction function Write-Warning "New-SpecScheduledTaskAction: Task Action configuration could not be assigned." return 910 } # Create the task trigger if ($Trigger -eq 'daily') { Write-Verbose "The '-daily' trigger has been selected" $taskTrigger = New-SpecScheduledTaskTrigger -trigger $Trigger -time $Time -RandomiseTaskUpTo $RandomiseTaskUpToXMinutes -RepeatEveryXMinutes $RepeatEveryXMinutes } else { $taskTrigger = New-SpecScheduledTaskTrigger -trigger $Trigger -DelayTaskUpToXMinutes $DelayTaskByXMinutes -RepeatEveryXMinutes $RepeatEveryXMinutes } if ($taskTrigger -eq 911) { # 911 is the error code for the New-SpecScheduledTaskTrigger function Write-Warning "New-SpecScheduledTaskTrigger: Trigger configuration could not be assigned." return 911 } # Set the task run level if ($RunWithHighestPrivilege.IsPresent) { Write-Verbose "The '-RunWithHighestPrivilege' switch has been selected" $taskPrincipal = New-SpecScheduledTaskPrincipal -RunAs $RunAs -RunWithHighestPrivilege } else { $taskPrincipal = New-SpecScheduledTaskPrincipal -RunAs $RunAs } if ($taskPrincipal -eq 912) { # 912 is the error code for the New-SpecScheduledTaskPrincipal function Write-Warning "New-SpecScheduledTaskPrincipal: Task principal could not be assigned." return 912 } # Set the task settings if ($TurnOffExecutionTimeLimit.IsPresent) { $taskSettings = New-SpecScheduledTaskSettingsSet -TurnOffExecutionTimeLimit } else { $taskSettings = New-SpecScheduledTaskSettingsSet } if ($taskSettings -eq 913) { # 913 is the error code for the New-SpecScheduledTaskSettingsSet function Write-Warning "New-SpecScheduledTaskSettingsSet: Task settings could not be assigned." return 913 } # Create the scheduled task $params = @{ TaskName = $TaskName Description = $Description TaskPath = "\$TaskFolder" Action = $taskAction Trigger = $taskTrigger Principal = $taskPrincipal Settings = $taskSettings } $result = Create-SpecScheduledTask @params if ($result -eq 914) { Write-Warning "Create-SpecScheduledTask: An error occured creating the task." return 914 } # Start the task immediately if the -StartTaskImmediately switch was used if ($StartTaskImmediately.IsPresent) { try { Write-Verbose "Starting task $TaskName" Start-ScheduledTask -TaskName $TaskName -TaskPath "\$TaskFolder" -ea stop -ev x Write-Verbose "Task $TaskName started successfully." } catch { Write-Warning "Start-ScheduledTask: An error occured starting the task: $x" return 915 } } #write-verbose "Task $TaskName created successfully." return 0 } } |