Public/Setup-ScheduledTask.ps1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
function Setup-ScheduledTask { [CmdletBinding(DefaultParameterSetName='DefinitionFile')] Param( [Parameter(ParameterSetName='DefinitionFile', Mandatory=$true)] [ValidateScript({Test-Path $_ -PathType Leaf})] [ValidateNotNullOrEmpty()] [string[]]$DefinitionFile , [Parameter(ParameterSetName='DefinitionDirectory', Mandatory=$true)] [ValidateScript({Test-Path $_ -PathType Container})] [ValidateNotNullOrEmpty()] [string[]]$DefinitionDirectory , [Parameter(ParameterSetName='DefinitionObject', Mandatory=$true, ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [object[]]$DefinitionObject , [Parameter(ParameterSetName='DefinitionFile', Mandatory=$false)] [Parameter(ParameterSetName='DefinitionDirectory', Mandatory=$false)] [switch]$AsJson ) begin { try { # Import definitions as an array of hashtable definitions (begin) $DefinitionsCollection = New-Object System.Collections.ArrayList if ($DefinitionFile) { $DefinitionFileCollection = Get-Item $DefinitionFile }elseif ($DefinitionDirectory) { $DefinitionFileCollection = if ($AsJson) { Get-ChildItem $DefinitionDirectory -File | ? { $_.Extension -eq '.json' } }else { Get-ChildItem $DefinitionDirectory -File | ? { $_.Extension -eq '.ps1' } } } if ($DefinitionFile -or $DefinitionDirectory) { if (!$DefinitionFileCollection) { "No definitions could be found from the specified definition files or directories." | Write-Error return } $DefinitionCollectionRaw = $DefinitionFileCollection | % { if ($AsJson) { # If multiple .json files are found, the resulting collection on PS 5.1 is a collection of the arrays of objects within each .json file's content rather than the objects themselves. # This results in a situation, where when looping over objects within $DefinitionsCollection, only the last object within each array is processed in the pipeline, leading to the serialization and creation / application of only those tasks. # This behavior appears related to a limitation of `ConvertFrom-Json` prior to PS 6.0: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertfrom-json#-ashashtable and does not seem to affect parallel CI jobs on PS 7.2.6 . # To ensure all objects are processed, return each object within the .json array object regardless of PS version. # Missing tasks: https://dev.azure.com/theohbrothers/ScheduledTaskManagement/_build/results?buildId=437&view=logs&j=a4c7e33e-604c-560c-49b1-4d6828efc661&t=3de151fa-1c49-59eb-ac4b-c29a43df6985 # Missing and incorrect objects: https://dev.azure.com/theohbrothers/ScheduledTaskManagement/_build/results?buildId=448&view=logs&j=a4c7e33e-604c-560c-49b1-4d6828efc661&t=3de151fa-1c49-59eb-ac4b-c29a43df6985 # Expected objects and tasks: https://dev.azure.com/theohbrothers/ScheduledTaskManagement/_build/results?buildId=450&view=logs&j=a4c7e33e-604c-560c-49b1-4d6828efc661&t=3de151fa-1c49-59eb-ac4b-c29a43df6985 Get-Content $_.FullName | ConvertFrom-Json | % { $_ } }else { . $_.FullName } } }elseif ($DefinitionObject) { # $DefinitionObject being non-null in the begin block indicates the value was not passed via pipeline $isDefinitionObjectValueFromPipeline = $false }else { $isDefinitionObjectValueFromPipeline = $true } }catch { Write-Error -Exception $_.Exception -Message $_.Exception.Message -Category $_.CategoryInfo.Category -TargetObject $_.TargetObject } }process { try { # Import definitions as an array of hashtable definitions (process) if ($DefinitionObject) { $DefinitionCollectionRaw = $DefinitionObject # Store the array of objects or present object of $DefinitionObject processed within the pipeline } $DefinitionCollectionRaw | % { $definitionHashtable = if ($_.GetType() -ne [hashtable]) { $_ | ConvertTo-Hashtable } else { $_ } $definition = $definitionHashtable | Validate-DefinitionObject if ($definition) { if ($DefinitionObject) { if ($isDefinitionObjectValueFromPipeline) { $DefinitionsCollection.Clear() # Clear the $DefinitionsCollection arraylist to have the variable store only the present object of $DefinitionObject processed within the pipeline } } $DefinitionsCollection.Add($definition) | Out-Null } } # Serialize definitions $DefinitionsCollectionSerialized = $DefinitionsCollection | % { "Serializing task definition:" | Write-Verbose $_ | Out-String -Stream | % { $_.Trim() } | ? { $_ } | Write-Verbose try { Serialize-DefinitionObject -DefinitionObject $_ }catch { Write-Error -Exception $_.Exception -Message $_.Exception.Message -Category $_.CategoryInfo.Category -TargetObject $_.TargetObject } } # Setup scheduled tasks $DefinitionsCollectionSerialized | % { "Setting up task:" | Write-Verbose $_ | Out-String -Stream | % { $_.Trim() } | ? { $_ } | Write-Verbose try { Apply-ScheduledTask -DefinitionObject $_ }catch { Write-Error -Exception $_.Exception -Message $_.Exception.Message -Category $_.CategoryInfo.Category -TargetObject $_.TargetObject } } }catch { Write-Error -Exception $_.Exception -Message $_.Exception.Message -Category $_.CategoryInfo.Category -TargetObject $_.TargetObject } } } |