[HorizonRestAPI] Trying some of those new funky Horizon 8 REST api’s

In my last post I promised to provide some examples of those new REST api’s in Horizon 8. A couple of things that I will show:

I have changed how I run my scripts a bit in that I decided to go even lazier and store my credentials in an xml file:

$credential = Get-Credential
$credential | Export-CliXml -Path 'C:\My\Path\cred.xml'

and in my script I retrieve them

$url = "https://pod1cbr1.loft.lab"

$credentials=Import-Clixml .\creds.xml
$username=($credentials.username).split("\")[1]
$domain=($credentials.username).split("\")[0]
$password=$credentials.password

$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password) 
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)


function Get-HRHeader(){
    param($accessToken)
    return @{
        'Authorization' = 'Bearer ' + $($accessToken.access_token)
        'Content-Type' = "application/json"
    }
}
function Open-HRConnection(){
    param(
        [string] $username,
        [string] $password,
        [string] $domain,
        [string] $url
    )

    $Credentials = New-Object psobject -Property @{
        username = $username
        password = $password
        domain = $domain
    }

    return invoke-restmethod -Method Post -uri "$url/rest/login" -ContentType "application/json" -Body ($Credentials | ConvertTo-Json)
}

function Close-HRConnection(){
    param(
        $accessToken,
        $url
    )
    return Invoke-RestMethod -Method post -uri "$url/rest/logout" -ContentType "application/json" -Body ($accessToken | ConvertTo-Json)
}

$accessToken = Open-HRConnection -username $username -password $UnsecurePassword -domain $Domain -url $url

Invoke-RestMethod -Method Get -uri "$url/rest/config/v1/ic-domain-accounts" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken)

Sessions

The first call I will show is immediately one of the more important ones: session information. Currently only local sessions seem to be available so we’ll have to wait for global session information. This is the call I will use:

$sessions=Invoke-RestMethod -Method Get -uri "$url/rest/inventory/v1/sessions" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken)

with this result

So s lot of data but less directly readable results than the soap api’s but we do see all of it including deeper levels. For applications we do see something new though.

Yes that’s actually the local application that the user launched. In this case it was through a Global Entitlement named Global_Notepad so it’s not showing that. According to the soap api’s this should also be shown there but they never do as far as I know.

Messages

One of the other things that we can do is send messages. For this we need to create an variable with the following information:

{
  "message": "Sample Info Message",
  "message_type": "INFO",
  "session_ids": [
    "7cdd624f-37d1-46c1-ab96-695a5d13956f"
  ]
}

To make it more fun I will send a message to all my desktop sessions I put those first into an variable

$desktopsessions=$sessions | where {$_.session_type -eq "DESKTOP"}

and I will create the json like this

[email protected]{
  "message"="Wouter is sending a message";
  "message_type"="WARNING";
  "session_ids"=$desktopsessions.id -as [string[]]
}

this I will convert to a json and use the Put method

[email protected]{
  "message"="Wouter is sending a message";
  "message_type"="WARNING";
  "session_ids"=$desktopsessions.id -as [string[]]
}
$body = $json | ConvertTo-Json
Invoke-RestMethod -Method Post -uri "$url/rest/inventory/v1/sessions/action/send-message" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken) -body $body

As you see I get all status codes 200 back so I know it was a success and we do see that on the desktops as well.

Machines

So getting all machines is as easy as 1,2,3 with /inventory/v1/machines.

$machines=Invoke-RestMethod -Method Get -uri "$url/rest/inventory/v1/machines" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken)

Not a lot of new data, just less things we don’t need.

Reset

If you look good you’ll see that the machine I was showing is in the already used state. In my lab this happens because often I power down the lab while I still have some sessions running. Let’s reset this machine. What do we need for this first the api method and that’s /inventory/v1/machines/action/reset for requires:

Since I am far from fluent in REST api’s and json this took me a while to find out but I did it like this

$body=((Invoke-RestMethod -Method Get -uri "$url/rest/inventory/v1/machines" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken)) | where {$_.state -eq "ALREADY_USED"}).id -as [string[]] | convertto-json
Invoke-RestMethod -Method Post -uri "$url/rest/inventory/v1/machines/action/reset" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken) -body $body

so I use the method to pull the machines, filter on the state being “ALREADY_USED”, take the id of this as a string and convert that to json. When select the body I need to add the quotes and straight brackets because if it is a single string the json won’t be usable json. I will show it later with multiple systems that it’s not needed with multiples.

$body=((Invoke-RestMethod -Method Get -uri "$url/rest/inventory/v1/machines" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken))  | where {$_.state -eq "AVAILABLE"}).id -as [string[]] | convertto-json
Invoke-RestMethod -Method Post -uri "$url/rest/inventory/v1/machines/action/reset" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken) -body $body

[HorizonRestAPI] Handling Instant Clone Administrator accounts

One of the options already available using the Horizon REST API‘s is working with Instant Clone Administrators. In total there are 5 API calls available and I will give an explanation for al 5 on how to use them. As you can see you’ll run all of them against /rest/config/v1/ic-domain-accounts.

GET : for all Instant Clone Domain accounts

POST : to create a new Instant Clone Domain accounts

GET : To retreive a specific Instant Clone Domain account with it’s ID

PUT : to update an Instant Clone Domain account.

DELETE : To delete an Instant Clone Domain account

Getting Started

To start showing these I am starting with the same base that I used in my first blog post about the Horizon REST api’s:

$url = read-host -prompt "Connection server url" 
$username = read-host -prompt "Username" 
$password = read-host -prompt "Password" -AsSecureString 
$Domain = read-host -Prompt "Domain" 
$url = "https://pod1cbr1.loft.lab"


$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password) 
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)


function Get-HRHeader(){
    param($accessToken)
    return @{
        'Authorization' = 'Bearer ' + $($accessToken.access_token)
        'Content-Type' = "application/json"
    }
}
function Open-HRConnection(){
    param(
        [string] $username,
        [string] $password,
        [string] $domain,
        [string] $url
    )

    $Credentials = New-Object psobject -Property @{
        username = $username
        password = $password
        domain = $domain
    }

    return invoke-restmethod -Method Post -uri "$url/rest/login" -ContentType "application/json" -Body ($Credentials | ConvertTo-Json)
}

function Close-HRConnection(){
    param(
        $accessToken,
        $url
    )
    return Invoke-RestMethod -Method post -uri "$url/rest/logout" -ContentType "application/json" -Body ($accessToken | ConvertTo-Json)
}

$accessToken = Open-HRConnection -username $username -password $UnsecurePassword -domain $Domain -url $url

Invoke-RestMethod -Method Get -uri "$url/rest/config/v1/ic-domain-accounts" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken)

GET

The regular get is really straight forward, just invoke a get and you get the results.

Invoke-RestMethod -Method Get -uri "$url/rest/config/v1/ic-domain-accounts" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken)

As you can see I currently have 2 accounts configured.

POST

With post we can configure a new Instant Clone Domain account. Let’s see what we need. According to the API explorer it looks like we need to supply a domain ID, password and account.

To get the domain ID we’ll actually need to do a GET against another url:

$domains=Invoke-RestMethod -Method Get -uri "$url/rest/external/v1/ad-domains" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken)

Now I will create the json that we’ll need to configure the account. The $data variable is just a regular powershell array that  afterwards convert to the actual json

$domainid=$domains |select-object -expandproperty id -first 1

[email protected]{
ad_domain_id= $domainid;
password= "password";
username= "username"
}

$body= $data | ConvertTo-Json

Now let’s use the Post method to apply this

Oops, too slow let’s authenticate and try again

Invoke-RestMethod -Method Post -uri "$url/rest/config/v1/ic-domain-accounts" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken) -body $body

There are a few remarks about this: no propper error is returned when a wrong username and password is used. Wen you try to create an account that already exists it will return a 409 conflict.

GET with ID

This is straightforward again, just extend the url for the get with the ID of the account you want to get. I grabbed this from the regular pul request and filtered on the user account I just created

$icaccounts= Invoke-RestMethod -Method Get -uri "$url/rest/config/v1/ic-domain-accounts" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken) 
$accountid=($icaccounts | where {$_.username -eq "username"}).id 
Invoke-RestMethod -Method Get -uri "$url/rest/config/v1/ic-domain-accounts/$accountid" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken)

PUT

Put can be used to change a users password. It’s requires a combination of the url with the ID from the get with id and a body like in the Post.

[email protected]{password="Demo-02"}
$body = $data | ConvertTo-Json
Invoke-RestMethod -Method Put -uri "$url/rest/config/v1/ic-domain-accounts/$accountid" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken) -Body $body

DELETE

To delete an account simply use the url with the id in it with the DELETE method

Invoke-RestMethod -Method Delete -uri "$url/rest/config/v1/ic-domain-accounts/$accountid" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken)