Private/Set-AtwsData.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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
<# .COPYRIGHT Copyright (c) ECIT Solutions AS. All rights reserved. Licensed under the MIT license. See https://github.com/ecitsolutions/Autotask/blob/master/LICENSE.md for license information. #> Function Set-AtwsData { <# .SYNOPSIS This function creates or updates one or more Autotask entities with new or modified properties. .DESCRIPTION This function creates or updates one or more Autotask entities with new or modified properties .INPUTS [PSObject[]]. One or more Autotask entities to update .OUTPUTS [PSObject[]]. The updated entities are re-downloaded from the API. .EXAMPLE Set-AtwsData -Entity $Entity Passes all Autotask entities in $Entity to the Autotask webservices API using the .update() method .EXAMPLE Set-AtwsData -Entity $Entity -Create Passes all Autotask entities in $Entity to the Autotask webservices API using the .create() method .NOTES NAME: Set-AtwsData .LINK Get-AtwsData Remove-AtwsData #> [cmdletbinding()] [OutputType([PSObject[]])] param ( [Parameter( Mandatory = $true, ValueFromPipeline = $true )] [ValidateNotNullOrEmpty()] [PSObject[]] $Entity, [ValidateRange(0, 100)] [Int] $ErrorLimit = 10, [switch] $Create ) begin { # Enable modern -Debug behavior if ($PSCmdlet.MyInvocation.BoundParameters['Debug'].IsPresent) { $DebugPreference = 'Continue' } Write-Debug ('{0}: Begin of function' -F $MyInvocation.MyCommand.Name) if (-not($Script:Atws.integrationsValue)) { Throw [ApplicationException] 'Not connected to Autotask WebAPI. Re-import module with valid credentials.' } # reset errorcounter $errorCount = 0 } process { If ($Create.IsPresent) { Write-Verbose ('{0}: Calling .Create() for {1} objects of type {2}' -F $MyInvocation.MyCommand.Name, $Entity.Count, $Entity[0].GetType().Name) } Else { Write-Verbose ('{0}: Calling .Update() for {1} objects of type {2}' -F $MyInvocation.MyCommand.Name, $Entity.Count, $Entity[0].GetType().Name) } # Convert from local time and label settings $Entity = $Entity | ConvertFrom-LocalObject # update() function can take up to 200 objects at a time for ($i = 0; $i -lt $Entity.count; $i += 200) { $j = $i + 199 if ($j -ge $Entity.count) { $j = $Entity.count - 1 } Write-Debug -Message ('{0}: Creating chunk from index {1} to index {2}' -F $MyInvocation.MyCommand.Name, $i, $j) # Explicit selection of list type. ArrayList supports .remove() [Collections.ArrayList]$workingSet = $Entity[$i .. $j] # We are going to try multiple times if the first attempt fails Do { # Reset error list $errors = @() # Are we creating or updating? if ($Create.IsPresent) { # We are creating. i.e. New- $result = $atws.create($Script:Atws.integrationsValue, $workingSet) # Check for duplicates $duplicates = $result.EntityReturnInfoResults | Where-Object { $_.DuplicateStatus.Found -and -not $_.DuplicateStauts.Ignored } foreach ($duplicate in $duplicates) { Write-Warning ('{0}: Duplicate found for Object Id {1} on {2}' -F $MyInvocation.MyCommand.Name, $duplicate.EntityId, $duplicate.DuplicateStatus.MatchInfo) } } else { # We are updating $result = $atws.update($Script:Atws.integrationsValue, $workingSet) } for ($t = 0; $t -lt $result.errors.Count; $t += 2) { # Count the errors, we have a limit $errorCount++ # First line is the error message $message = $result.errors[$t].Message if ($result.errors.Count -gt $t) { # Next line may include the element index, first element = 1 if ($result.errors[$t + 1].Message -match '\[(\d+)\]') { [int]$index = $Matches[1] } else { $index = 1 } } # Powershell arrays has first element = 0 $index-- # Get the element $element = $workingSet[$index] # Remove element from Workingset $errors += $element # Notify caller of skipped element Write-Warning ('Element with index {0} of type {1} with Id {2} was skipped because {3}' -F $Entity.IndexOf($element), $element.GetType().Name, $element.id, $message) } # .remove() any errors from the workingSet foreach ($element in $errors) { $workingSet.Remove($element) } # Keep on trying until there are no errors, the workingSet is empty (every element failed) # or the error limit has been reached } Until ($result.errors.Count -eq 0 -or $workingSet.Count -eq 0 -or $errorCount -ge $ErrorLimit) # We have tried multiple times! Still errors? if ($result.errors.Count -eq 0) { # The API documentation explicitly states that you can only use the objects returned # by the .create() or .set() function to get the new objects ID. # so to return objects with accurately represents what has been created we have to # get them again by id # But not all objects support queries, for instance service adjustments, # so we need the entity info to determine if we can make a query $EntityInfo = Get-AtwsFieldInfo -Entity $result.EntityResultType -EntityInfo if ($result.EntityResults.Count -gt 0 -and $EntityInfo.CanQuery) { $newObjectFilter = 'id -eq {0}' -F ($result.EntityResults.Id -join ' -or id -eq ') $endResult += Get-AtwsData -Entity $result.EntityResultType -Filter $newObjectFilter } } else { # Still errors. Post them to the error stream and bail out. Write-Error ($result.errors.Message -join "`n") Break } } } end { if ($endResult.count -gt 0) { Write-Debug ('{0}: End of function, returning {1} updated {2}(s)' -F $MyInvocation.MyCommand.Name, $result.count, $result[0].GetType().Name) Return $endResult } else { Write-Debug ('{0}: End of function, no objects to return.' -F $MyInvocation.MyCommand.Name, $result.count) } } } |