Jump to content

BillP

Hornbill Users
  • Posts

    24
  • Joined

  • Last visited

  • Days Won

    1

BillP last won the day on March 6 2021

BillP had the most liked content!

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

BillP's Achievements

Apprentice

Apprentice (3/14)

  • Dedicated Rare
  • One Year In
  • Reacting Well
  • First Post
  • Collaborator

Recent Badges

2

Reputation

  1. Hi @Ehsan I can confirm that the above process works fine. Thank you again. For the benefit of others attempting a similar task, the code looks like this: # # previously - fetch a list of requests from h_itsm_requests # # iterate through the requests $DIRequests | where {$_."ServiceName" -eq "Documotive"} | where {$_."Catalog" -eq "Request Documents to be Indexed"} | foreach { $entry = $_ | Add-Member NoteProperty FileLocation "" -PassThru $requestID = $entry."RequestID" Write-Host "Request: $requestID for $($entry.CustomerName) is $($entry.Status)" if ($requestID -eq "SR00058943") { $entry | Out-Null } # if (-not [string]::IsNullOrWhiteSpace($entry.AttachmentLocation)) { if ($true) { Add-HB-Param -ParamName "requestId" -ParamValue $requestID Add-HB-Param -ParamName "startRow" -ParamValue 0 Add-HB-Param -ParamName "rowCount" -ParamValue 1 # Invoke XMLMC call, output returned as PSObject type $requestOutput = Invoke-HB-XMLMC "apps/com.hornbill.servicemanager/Requests" "smGetAttachments" if ($requestOutput.Status -eq "fail") { Write-PSFMessage -Level Debug -Tag "ERROR" -Message "failed to retrieve attachments: $($requestOutput.Error)" } if ($requestOutput.Params -ne $null) { $attachmentDetails = $requestOutput.Params.attachments | ConvertFrom-Json $outputFolder = Join-Path $AttachmentFolder $entry.RequestID if (-not (Test-Path -LiteralPath $outputFolder)) { mkdir $outputFolder | Out-Null } if (-not [string]::IsNullOrWhiteSpace($attachmentDetails.h_filename)) { $outputLocation = Join-Path $outputFolder $($attachmentDetails.h_filename) # # new mechanism, as described at https://community.hornbill.com/topic/19200-how-do-i-retrieve-an-attachment-using-the-api/ (response from Ehsan) Add-HB-Param -ParamName "keyValue" -ParamValue $requestID Add-HB-Param -ParamName "filePath" -ParamValue $attachmentDetails.h_filename $AttachInfoOutput = Invoke-HB-XMLMC "apps/com.hornbill.servicemanager/Requests" "entityAttachGetInfo" if ($AttachInfoOutput.Status -eq "fail") { Write-PSFMessage -Level Debug -Tag "ERROR" -Message "failed to retrieve attachment info: $($AttachInfoOutput.Error)" } else { $attachmentInfo = $AttachInfoOutput.Params $fileAccessToken = $attachmentInfo.accessToken $root = 'https://mdh-p01-api.hornbill.com/xxxxxx/dav/secure-content/download/' # root obtained as per Ehsan's post above $url = $root + $fileAccessToken if (-not (Test-Path -LiteralPath $outputLocation)) { Try { $wc = New-Object System.Net.WebClient $key = $HornbillAPIKey # $key = "abcdef1234567890abcdef1234567890" $wc.Headers.Add("Authorization","ESP-APIKEY " + $key) $wc.DownloadFile($url,$outputLocation) Write-Host "Downloaded from $url to $outputLocation" Write-PSFMessage -Level Debug -Tag "INFO" -Message "Downloaded from $url to $outputLocation" if ($outputLocation -like "*.zip") { [System.IO.Compression.ZipFile]::ExtractToDirectory($outputLocation,$outputFolder) Get-ChildItem $outputFolder -Include '*.doc*' -Recurse | Select-Object -First 1 | foreach { $outputLocation = $_.FullName} } $entry.FileLocation = $outputLocation } Catch { Write-Error "Aborting: $($_.Exception.Message)" Write-PSFMessage -Level Debug -Tag "ERROR" -Message "Aborting: $($_.Exception.Message)" exit 0 #echo("hey ho pip and dandy") #return $apiResponse } } else { Write-Host "Already downloaded: $outputLocation" Write-PSFMessage -Level Debug -Tag "INFO" -Message "Already downloaded: $outputLocation" } # other stuff } } else { # no attachment $message = "Request: $requestID for $($entry.CustomerName) - attachment name is blank" Write-PSFMessage -Level Debug -Tag "ERROR" -Message $message Write-Host @errorColours $message } } else { # no attachment $message = "Request: $requestID for $($entry.CustomerName) - no attachment found on request" Write-PSFMessage -Level Debug -Tag "ERROR" -Message $message Write-Host @errorColours $message } }
  2. @Ehsan thank you for the prompt and full response. I'll work through the steps and let you know how I get on.
  3. Over on this thread I discovered that the API referenced by has broken. I initially reported the error on the other thread, but I think it makes more sense to continue the on this thread, with all the history in the same place. The impact to the business is that file GET requests still return 200, but the content is garbage, and this garbage has been posted to the next stage of the automation (an archival process) since I don't know when. I'm currently working out how much archival is going to have to be re-done, and telling the support desk how many archival requests are going to have to be re-done. Fortunately we still have the original documents (which Hornbill has at least preserved). Nonetheless, I am on the wrong end of a difficult conversation. @Ehsan I trust this helps you identify the API that's broken.
  4. Over on this thread I discovered that the API referenced by has broken. I initially reported the error on the other thread, but I think it makes more sense to continue the on this thread, with all the history in the same place. @Ehsan I trust this helps you identify the API that's broken.
  5. @Ehsan @Gerry I've just discovered through this thread that this API has been broken for a while. In my case, it has failed in a way that doesn't cause an exception, but instead brings down an error web page, rather than the document it was supposed to fetch. No error was reported, so I'm still working out how long this has been broken and how many bad documents have been processed by our archival process. I will say - understated - that I am not pleased. I don't see a usable fix posted in this thread. Do you have a plan to fix the API or replace it? Bill
  6. Hi @simonadams This is a standalone PowerShell application (i.e. a set of powershell scheduled jobs), which manages Starters and Leavers directly. It's driven by our HR system (iTrent), which supplies Starter and Leaver notifications via a mix of emails to Hornbill and to a notification mailbox, all of which are cross-checked against each other in the powershell to build up the set of actions in AD, Azure AD, Office 365, Hornbill and (eventually) LoB apps. It all hooks into pre-existing Hornbill workflows that were designed for manual operation. It's also a work in progress. I'm happy to share more details if it helps, but that may not be of interest to this forum. Let me know. Bill Powell
  7. Thank you @SamS, I can confirm that this other API works. I checked out what happened when specifying multiple taskStatus values: $SRRef = "SR00055137" Add-HB-Param -ParamName "requestId" -ParamValue $SRRef Add-HB-Param -ParamName "returnRelatedData" -ParamValue "true" Add-HB-Param -ParamName "returnActivityStreamAccessToken" -ParamValue "true" $xmlmcOutput = Invoke-HB-XMLMC "apps/com.hornbill.servicemanager/Requests" "getRequestRecord" if ($xmlmcOutput.Status -eq "fail") { Write-PSFMessage -Level Debug -Tag "ERROR" -Message "failed to update request timeline: $($xmlmcOutput.Error)" } Add-HB-Param -ParamName "objectRefUrn" "urn:sys:entity:com.hornbill.servicemanager:Requests:$SRRef" Add-HB-Param -ParamName "counters" -ParamValue "true" Add-HB-Param -ParamName "taskStatus" -ParamValue 0 Add-HB-Param -ParamName "taskStatus" -ParamValue 1 Add-HB-Param -ParamName "taskStatus" -ParamValue 2 Add-HB-Param -ParamName "taskStatus" -ParamValue 3 Add-HB-Param -ParamName "taskStatus" -ParamValue 4 Add-HB-Param -ParamName "taskStatus" -ParamValue 5 Add-HB-Param -ParamName "taskStatus" -ParamValue 6 Add-HB-Param -ParamName "taskStatus" -ParamValue 7 Add-HB-Param -ParamName "rowstart" -ParamValue 0 Add-HB-Param -ParamName "limit" -ParamValue 10 $xmlmcOutput = Invoke-HB-XMLMC "apps/com.hornbill.core/Task" "getEntityTasks" if ($xmlmcOutput.Status -eq "fail") { Write-PSFMessage -Level Debug -Tag "ERROR" -Message "failed to update request timeline: $($xmlmcOutput.Error)" } $taskInfo = $xmlmcOutput.Params.tasks | ConvertFrom-Json Outputting the contents of $taskinfo I see: [DBG]: PS C:\Projects\LeaverTermination>> $taskInfo 0 : {} 1 : {@{taskid=TSK20210819000013; status=1; title=Link Employees Assets; owner=SYS_BPM_MANAGER; outcomes=Completed; createdon=2021-08-19 15:24:56; priority=5; details=Link the employees assets to the request - these are to be returned on their last working day; assigned=urn:sys:role:Service Desk; reference=bpmTask; progress=0; extra={}; objectrefurn=urn:sys:entity:com.hornbill.servicemanager:Requests:SR00055137}, @{taskid=TSK20210819000014; status=1; title=Line Manager Confirmation; owner=SYS_BPM_MANAGER; outcomes=Completed; createdon=2021-08-19 15:24:56; priority=5; details=Contact the employees line manager to understand whether any special requirements are needed once the employee has left the organisation. e.g. e-mail forwards, out-of-office, access to Onedrive etc.; assigned=urn:sys:role:Service Desk; reference=bpmTask; progress=0; extra={}; objectrefurn=urn:sys:entity:com.hornbill.servicemanager:Requests:SR00055137}} 2 : {} 3 : {} 4 : {@{taskid=TSK20210819000012; status=4; title=Set Active Directory Account to Expire; owner=SYS_BPM_MANAGER; outcomes=Completed; outcome=Completed; createdon=2021-08-19 15:24:56; completedon=2021-08-20 16:53:19; priority=5; details=Set the employees Active Directory account to expire on the date specified; assigned=urn:sys:role:Service Desk; reference=bpmTask; progress=100; extra={}; timespent=0; objectrefurn=urn:sys:entity:com.hornbill.servicemanager:Requests:SR00055137}} 5 : {} 6 : {} 7 : {} [DBG]: PS C:\Projects\LeaverTermination>> which would appear to correspond to 2 tasks not started and 1 task completed. The task status values of 1 and 4 are a bit opaque - but this gets me going. Next stop - setting specific tasks to completed by the API. Thanks again for the assistance.
  8. @Steve Giller The value of objectRefUrn is: urn:sys:entity:com.hornbill.servicemanager:Requests:SR00055137 immediately after executing the task::taskGetList my debug session shows: [DBG]: PS C:\Projects\LeaverTermination>> $taskUrn urn:sys:entity:com.hornbill.core:task:TSK20210819000012 [DBG]: PS C:\Projects\LeaverTermination>> $SRUrn urn:sys:entity:com.hornbill.servicemanager:Requests:SR00055137 [DBG]: PS C:\Projects\LeaverTermination>> $requestOutput Status Params Error ------ ------ ----- ok [DBG]: PS C:\Projects\LeaverTermination>> $requestOutput.Params [DBG]: PS C:\Projects\LeaverTermination>> $requestOutput.Params -eq $null True [DBG]: PS C:\Projects\LeaverTermination>> $taskId TSK20210819000012 [DBG]: PS C:\Projects\LeaverTermination>>
  9. Context: I'm looking at automating tasks around employee lifecycle management - new starters and leavers. We have service requests associated with these events, and those have associated tasks, such as creation of Active Directory accounts, or the setting of an account expiration date on an AD account. I'm trying to navigate from the entity to get a list of all the tasks associated with a given service request. $SRRef = "SR00055137" Add-HB-Param -ParamName "requestId" -ParamValue $SRRef Add-HB-Param -ParamName "returnRelatedData" -ParamValue "true" Add-HB-Param -ParamName "returnActivityStreamAccessToken" -ParamValue "true" $xmlmcOutput = Invoke-HB-XMLMC "apps/com.hornbill.servicemanager/Requests" "getRequestRecord" if ($xmlmcOutput.Status -eq "fail") { Write-PSFMessage -Level Debug -Tag "ERROR" -Message "failed to update request timeline: $($xmlmcOutput.Error)" } $MainInfo = $xmlmcOutput.Params.primaryEntityData | ConvertFrom-Json $RelatedInfo = $xmlmcOutput.Params.relatedEntityData | ConvertFrom-Json $primaryEntityData = $xmlmcOutput.Params.primaryEntityData | ConvertFrom-Json $activityStreamId = $primaryEntityData.record.h_activity_stream_id $accessToken = $xmlmcOutput.Params.accessToken # # now pull back the activityStream Add-HB-Param -ParamName "activityStreamID" $activityStreamId Add-HB-Param -ParamName "accessToken" $accessToken $requestOutput = Invoke-HB-XMLMC "activity" "activityStreamQuery" if ($requestOutput.Status -ne "ok") { # Write-Host "failed" } $activityStream = [object[]]($requestOutput.Params.activity) # force it to always be an array # even if 0 or 1 elements $activityStream | foreach { $activity = $_ if ($activity.content -match "^Task '{""Set Active Directory Account to Expire"", ""([a-zA-Z0-9\:\.]+)""}' was added$") { $activity | Out-Null $taskUrn = $Matches[1] if ($taskUrn -match ".*(TSK[0-9]*)") { $taskId = $Matches[1] # # get the info for the task Add-HB-Param -ParamName "taskId" $taskId $requestOutput = Invoke-HB-XMLMC "task" "taskGetInfo" if ($requestOutput.Status -ne "ok") { # Write-Host "failed" } $taskInfo = $requestOutput.Params # # now we can get a list of all tasks $SRUrn = $taskInfo.objectRefUrn Add-HB-Param -ParamName "objectRefUrn" $SRUrn $requestOutput = Invoke-HB-XMLMC "task" "taskGetList" if ($requestOutput.Status -ne "ok") { # Write-Host "failed" } } } } First Question - I was expecting to be able to get a list of tasks from apps/com.hornbill.servicemanager/Requests::getRequestRecord - but nothing obvious showed up in the responses. Instead I got there by parsing elements of the activity stream to find the notification that a task I was interested in had been added. From that I parsed the Task's Urn, and from that the TaskId. Surely there's a simpler way? From that TaskId I was able to invoke task::taskGetInfo which gave me info about the task. I was able to see the format of the Urn for the service request - urn:sys:entity:com.hornbill.servicemanager:Requests:SR00055137 . Second Question - I was expecting hoping to be able to get a list of tasks using task::taskGetList specifying the Urn of the service request to limit the output to tasks belonging to that service request. The request succeeded, but returned an empty list. Can I use task::taskGetList to get a list of tasks belonging to a service request, and if so, what parameters do I need to supply.
  10. Thanks @Steve G That all works nicely. For the benefit of others here's the working code in the context of the larger task. For the sake of clarity, I've not yet put in most of the error handling... # # check all tickets reported as owned by sweng team # create new stories where tickets don't already have stories / bugs # sync back changes once the TP entity is being worked on $DevTicketList | where {$_.Status -notin @("status.closed","status.cancelled")} | foreach { $DevTicket = $_ # # get the latest info from the ticket - the report may be out-of-date Add-HB-Param -ParamName "requestId" -ParamValue $DevTicket.RequestID $requestOutput = Invoke-HB-XMLMC "apps/com.hornbill.servicemanager/Requests" "smGetReqDetails2" if ($requestOutput.Status -ne "ok") { # Write-Host "failed" } else { # # we have the latest details for the Hornbill ticket $requestDetails = $requestOutput.Params.requestDetails | ConvertFrom-Json # # also fetch timeline - see https://community.hornbill.com/topic/20790-api-to-read-back-posts-from-the-request-timeline/ Add-HB-Param -ParamName "requestId" $requestDetails.h_pk_reference Add-HB-Param -ParamName "returnActivityStreamAccessToken" "true" $requestOutput = Invoke-HB-XMLMC "apps/com.hornbill.servicemanager/Requests" "getRequestRecord" if ($requestOutput.Status -ne "ok") { # Write-Host "failed" } $primaryEntityData = $requestOutput.Params.primaryEntityData | ConvertFrom-Json $activityStreamId = $primaryEntityData.record.h_activity_stream_id $accessToken = $requestOutput.Params.accessToken # # now pull back the activityStream Add-HB-Param -ParamName "activityStreamID" $activityStreamId Add-HB-Param -ParamName "accessToken" $accessToken $requestOutput = Invoke-HB-XMLMC "activity" "activityStreamQuery" if ($requestOutput.Status -ne "ok") { # Write-Host "failed" } $activityStream = [object[]]($requestOutput.Params.activity) # force it to always be an array # even if 0 or 1 elements at this point the variable $activityStream contains a list (array) of rich objects, each representing a single post or other activity from the timeline. Note: The [object[]] construct may not be familiar to novice PowerShell users, but is used to force a return value which may be $null, an empty array, a single element, or a list of multiple elements to always be an array, with the intuitive number of elements, so that it can be consistently treated by whatever code follows, which in this case will be a foreach {} construction. Hope that's useful.
  11. I'm writing an integration between Hornbill and the Software Development team's agile project board, Target Process (TP). The Software Devs want to see support tickets come in from Hornbill and appear on their TP sprint board as a story (service request) or a bug (incident), to appear alongside all the other engineering work they do. As they work on the bug (say), certain events need to be pushed back to the Hornbill request, so that the Operations Team can see progress without having to be licensed for TP. This is straightforward - I have got this to work in powershell using: Invoke-HB-XMLMC "apps/com.hornbill.servicemanager/Requests" "updateReqTimeline" What I now need to do is to read back all posts on the timeline, using a "complementary" API, so I can add these as comments to the bug in TP (obviously filtering out those created by the integration). I have searched the servicemanager API documentation, but there's a bit of terminology I'm missing, because I can't find a get or read operation to retrieve posts from the timeline. Please, what is that API?
  12. Here's a similar snippet of code, for those who find all the quotes and + signs confusing: $requestDetails = $requestOutput.Params.requestDetails | ConvertFrom-Json if ($requestDetails.h_custom_t -ne $TPEntity.Id) { [string]$CustomT = $TPEntity.Id $JsonCustomT = New-Object PSObject | Add-Member NoteProperty h_custom_t $CustomT -PassThru | ConvertTo-Json Add-HB-Param -ParamName "requestId" -ParamValue $requestDetails.h_pk_reference Add-HB-Param -ParamName "customFields" -ParamValue $JsonCustomT $requestOutput = Invoke-HB-XMLMC "apps/com.hornbill.servicemanager/Requests" "update" if ($requestOutput.Status -ne "ok") { # Write-Host "failed to set custom_t to $CustomT" } } What's going on here is that I'm using the h_custom_t field to store an external reference from Hornbill to the software development team's own SCRUM tracking system - the Hornbill Request Details are in $requestDetails and the SCRUM tracking story Id is in $TPEntity.Id If they don't match (which they won't, because up till now there's only been a one-way link), then I copy the Id into a new string $CustomT, and create a custom object from it, with a single, named field. ConvertTo-Json does the heavy lifting. Importantly, if the custom field itself contained quotes or other unusual characters, the ConvertTo-Json will take care of any necessary escape sequences or code conversions. Barely a quote in sight!
  13. Hi @Steve G Thank you - that worked perfectly. For the benefit of the community, here is the PowerShell that I used: # # import external modules (originally installed from PSGallery) # Import-Module HornbillAPI Import-Module PSFramework #region Utility Functions function Create-TempFolder { $tmpDir = [System.IO.Path]::GetTempPath() $tmpFolder = [System.IO.Path]::GetRandomFileName() $tmpDir = Join-Path -Path $tmpDir -ChildPath $tmpFolder [System.IO.Directory]::CreateDirectory($tmpDir) | Out-Null $tmpDir } function Get-ImageFromURL ($SourceURL,$TargetPath,$HornbillKey) { Write-Host $SourceURL $headers = @{} if ($HornbillKey -ne $null) { $headers["Authorization"] = "ESP-APIKEY $HornbillKey" } try { $result = Invoke-WebRequest -Uri $SourceURL -Method GET -OutFile $TargetPath -Headers $headers } Catch { Write-Error $_.Exception.Message Write-PSFMessage -Level Debug -Tag "ERROR" -Message "Downloaded report $outputLocation failed: $($_.Exception.Message)" } } function Upload-ImageToSession ($LocalImagePath,$DestinationURL,$HornbillKey) { Write-Host $DestinationURL $headers = @{} if ($HornbillKey -ne $null) { $headers["Authorization"] = "ESP-APIKEY $HornbillKey" } try { $result = Invoke-WebRequest -Uri $DestinationURL -Method PUT -InFile $LocalImagePath -Headers $headers } Catch { Write-Error $_.Exception.Message Write-PSFMessage -Level Debug -Tag "ERROR" -Message "Downloaded report $outputLocation failed: $($_.Exception.Message)" } } #endregion ################################################################### # Source of random faces # see https://www.theverge.com/tldr/2019/2/15/18226005/ai-generated-fake-people-portraits-thispersondoesnotexist-stylegan $faceURL = "https://thispersondoesnotexist.com/image" # unique every time $maleFace = "https://images.generated.photos/3m_U6OpnJvpM8HUrtmpIuH113nnU6QNDMnNGkVq9VkM/rs:fit:512:512/wm:0.95:sowe:18:18:0.33/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA5NDI4MDQuanBn.jpg" $UserName = "zebz" # test user 1 $UserName = "aarona" # test user 2 #region Fetch a random image for testing if ($TempFolder -eq $null) { $TempFolder = Create-TempFolder } $UserImageJPG = "$UserName.jpg" $imagePath = Join-Path $TempFolder $UserImageJPG if (-not (Test-Path -LiteralPath $imagePath)) { Get-ImageFromURL -SourceURL $faceURL -TargetPath $imagePath # -HornbillKey $HornbillAPIKey } #endregion $baseEndpoint = "https://eurapi.hornbill.com/myorganisationhere" $davendpoint = "$baseEndpoint/dav" # # we have a source image - upload it to the dav/session area $SourceImage = "/session/$UserImageJPG" $HornbillTempImageURL = $davendpoint + $SourceImage Upload-ImageToSession -LocalImagePath $imagePath -DestinationURL $HornbillTempImageURL -HornbillKey $HornbillAPIKey # # image is uploaded - now set it as the profile image. # note the use of the deleteSourceFile parameter to delete the image - this stops filling the dav/session area with junk $UserReference = "urn:sys:user:$UserName" Add-HB-Param "objectRef" $UserReference Add-HB-Param "sourceImage" $SourceImage Add-HB-Param "deleteSourceFile" $true # omit to keep the source image - why would you want to do this, though? $xmlmcOutput = Invoke-HB-XMLMC "activity" "profileImageSet" if ($xmlmcOutput.Status -ne "ok") { Write-PSFMessage -Level Debug -Tag "ERROR" -Message "failed to set user profile image : $($xmlmcOutput.Error)" } # # now fetch it back at 256x256 resolution (original was at 1024x1024) # # step 1 - get the image reference Add-HB-Param "objectRef" $UserReference $xmlmcOutput = Invoke-HB-XMLMC "activity" "profileImageGet" if ($xmlmcOutput.Status -ne "ok") { Write-PSFMessage -Level Debug -Tag "ERROR" -Message "failed to get user profile image : $($xmlmcOutput.Error)" } $imageReference = $xmlmcOutput.Params.imageReference # # step 2 - build the url and fetch the file $res = "_256x256.jpg" $HornbillFetchImageURL = $davendpoint + "/_static/img/$imageReference" + $res $downloadPath = Join-Path $TempFolder "$UserName$res" Get-ImageFromURL -SourceURL $HornbillFetchImageURL -TargetPath $downloadPath -HornbillKey $HornbillAPIKey Hope that's of use. Thanks again Bill
  14. @Steve G apologies for tagging you on this, but I've had no response on this in over 2 weeks. Do I need to clarify the question? Are my answers out there in the documentation and I just need to look harder?
×
×
  • Create New...