Jump to content

BillP

Hornbill Users
  • Posts

    24
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by BillP

  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. 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.

  3. On 6/23/2021 at 2:31 PM, Stuart Riddell said:

    Hi @Gerry

    The problem is when the replies refer to function calls that exist in one API library but not another.

    This block is valid for calls using the GO library but not the .NET library because it was added to one but not the other.  In this respect, the API libraries need to be kept up to date.

        Esp.XmlWriter doc = new Esp.XmlWriter(); 
        doc.openElement("searchFilter"); 
            doc.textElement("column", "h_container_id"); 
            doc.textElement("value", 126); 
            doc.textElement("matchType", "all"); 
        doc.closeElement("searchFilter"); 

     

     

    Whilst looking for the example above, I also found the issue where Hornbill developers told the Community how to download the attachments.  It was raised by another member and made my day when it was published.  This is the method we've been using and no longer works.

     

     

    Stuart

    @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

     

     

  4. 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

  5. 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.

  6. @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>> 

     

  7. 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.

  8. 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.

  9. 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?

  10. 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!

  11. 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

    • Like 1
  12. I'm looking to update the profile images of users from jpg files (not Active Directory) and I've found that there's an API activity::profileImageSet that lets me set an image (and a matching API activity::profileImageGet to retrieve the image).

    1), are these the correct APIs to be using, or is there an API under admin:: that I should be using?

    2), both of these require an objectRef, but the documentation doesn't say anything beyond:

    Name    Type    Attributes    Description
    objectRef    xs:anyURI    required once    The URN defining the social object who's profile image is to be looked up.

    what would the URN for a user look like?

    3), when downloading an existing image, an imageReference is specified, which is presumably relative to the WebDav root, or some subfolder thereof.  Can you confirm how to get from this to something that can be downloaded via WebDav

    4), when uploading a new image via activity::profileImageSet I can see that I can specify an external URL, but I'd prefer to upload the JPG files via WebDav, as it keeps everything inside Hornbill and doesn't require me to post employee portraits to publicly-visible URLs.  Where should I post such images?

    Thank you.

    Bill

  13. @VictorCan you clarify that, please?

    https://eurapi.hornbill.com/myorg/dav/reports/109/Documotive Requests_5008.csv
    succeeds

    but

    https://eurapi.hornbill.com/myorg/dav/cafs_raw/fs_entity/8d0703328b4819440d1676c463783216de5b3605.data
    fails (401)

    in both cases the calling code is based on the referenced article above, and is (in the second case):

            $url = $baseEndpoint + "/dav" + $attachmentDetails.h_contentlocation
            Try {
                $wc = New-Object System.Net.WebClient
                $key = $HornbillAPIKey
               # $key = "abcdef1234567890abcdef1234567890"
                $wc.Headers.Add("Authorization","ESP-APIKEY " + $key)
            
                $wc.DownloadFile($url,$outputLocation)
    #        return -1
            }
            Catch {
                Write-Error $_.Exception.Message
                exit 0
                #echo("hey ho pip and dandy")
                #return $apiResponse
            }

    you will observe the fake API KEY (currently commented out).

    My deduction - possibly wrong - is that the api key's account has group rights to access dav/reports but does not have group rights to dav/cafs_raw , hence my framing my question in terms of permissions or roles that might need to be applied to the account.  Have I misinterpreted the symptoms?  Is there a different way I should be downloading from dav/cafs_raw ?

    Thank you for your continuing patience...

  14. I did a little investigation and I tried an invalid API key, which gave a 403 (Forbidden) error, whereas my real API key gave a 401 (Unauthorized) error, from which I deduce that the API KEY is being checked, i.e. passing the Authentication (identity is valid) but is failing Authorization (identity is not allowed to do the thing).  The 401 accords with https://tools.ietf.org/html/rfc7235#page-6 (when credentials are supplied) though I'm not sure that the 403 is right for the other case.  I may be being over-picky.

  15. I am writing a powershell script to automate one particular ticket type that can be raised by our users.  I've been able to create a report that lists all open tickets of the relevant type, and I'm able to retrieve the report using the techniques described at 

    However, each ticket includes an attachment that needs to be passed to the automation.  I can use smGetAttachments to retrieve information about the attachment, but I'm stuck how to retrieve the attachment itself from powershell.

    smGetAttachments returns fields like the below:

    h_pk_id           : 16271
    h_request_id      : SR00040620
    h_contentlocation : /cafs_raw/fs_entity/8d0703328b4819440d1676c463783216de5b3605.data
    h_filename        : xxxxxxxx mail merge- yyyyyy letters.doc
    h_size            : 1566208
    h_timestamp       : 2020-08-06 10:38:27Z
    h_visibility      : trustedGuest

    I'd expect to take the h_contentlocation field and concatenate this to my instance URL plus some intermediate folder  to download the actual attachment using system.net.webclient, much as per the referenced topic.  However, I'm unable to discover what to put between the instance URL and the h_contentlocation.

    Or is some entirely different technique required?

    Regards

    Bill

  16. Following on from this, I'm able to download my own reports, which include references to attachments, such as:
     


    h_pk_id           : 16271
    h_request_id      : SR00040620
    h_contentlocation : /cafs_raw/fs_entity/8d0703328b4819440d1676c463783216de5b3605.data
    h_filename        : xxxxxxxx mail merge- yyyyyy letters.doc
    h_size            : 1566208
    h_timestamp       : 2020-08-06 10:38:27Z
    h_visibility      : trustedGuest

    Presumably I can now take the h_contentlocation field and concatenate this to my instance URL plus some intermediate folder  to download the actual attachment using system.net.webclient, much as above.  However, I'm unable to discover what to put between the instance URL and the h_contentlocation.

    Or is some entirely other technique required?

    Regards

    Bill

×
×
  • Create New...