Script to send message to all Global Sessions in a Cloud Pod Architecture

So last year I shared a script to send messages to local sessions in a pod regardless of Cloud Pod Architecture being used or not. With Horizon 8 2111 one of the new features is that you can also send messages to Global Sessions in other pods. I have created a script that messages to all those users. I used the same script as base but had to update Get-HorizonRestData to reflect the fact that sometimes some things need to be added to the url like ?pod_id=$podid in this case:

function Get-HorizonRestData(){
    [CmdletBinding(DefaultParametersetName='None')] 
    param(
        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $ServerURL,

        [Parameter(Mandatory=$true,
        ParameterSetName="filteringandpagination",
        HelpMessage='Array of ordered hashtables' )]
        [array] $filters,

        [Parameter(Mandatory=$true,
        ParameterSetName="filteringandpagination",
        HelpMessage='Type of filter Options: And, Or' )]
        [ValidateSet('And','Or')]
        [string] $Filtertype,

        [Parameter(Mandatory=$false,
        ParameterSetName="filteringandpagination",
        HelpMessage='Page size, default = 500' )]
        [int] $pagesize = 500,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [string] $RestMethod,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [PSCustomObject] $accessToken,

        [Parameter(Mandatory=$false,
        ParameterSetName="filteringandpagination",
        HelpMessage='$True for rest methods that contain pagination and filtering, default = False' )]
        [switch] $filteringandpagination,

        [Parameter(Mandatory=$false,
        ParameterSetName="id",
        HelpMessage='To be used with single id based queries like /monitor/v1/connection-servers/{id}' )]
        [string] $id,

        [Parameter(Mandatory=$false,
        HelpMessage='Extra additions to the query url that comes before the paging/filtering parts like brokering_pod_id=806ca in /rest/inventory/v1/global-sessions?brokering_pod_id=806ca&page=2&size=100' )]
        [string] $urldetails
    )
    
    if($filteringandpagination){
        if ($filters){
            $filterhashtable = [ordered]@{}
            $filterhashtable.add('type',$filtertype)
            $filterhashtable.filters = @()
            foreach($filter in $filters){
                $filterhashtable.filters+=$filter
            }
            $filterflat=$filterhashtable | convertto-json -Compress
            if($urldetails){
                $urlstart= $ServerURL+"/rest/"+$RestMethod+"?"+$urldetails+"&filter="+$filterflat+"&page="
            }
            else{
                $urlstart= $ServerURL+"/rest/"+$RestMethod+"?filter="+$filterflat+"&page="
            }
        }
        else{
            if($urldetails){
                $urlstart= $ServerURL+"/rest/"+$RestMethod+"?"+$urldetails+"&page="
            }
            else{
                $urlstart= $ServerURL+"/rest/"+$RestMethod+"?page="
            }
        }
        $results = [System.Collections.ArrayList]@()
        $page = 1
        $uri = $urlstart+$page+"&size=$pagesize"
        write-host $uri
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers (Get-HRHeader -accessToken $accessToken) -ResponseHeadersVariable responseheader
        $response.foreach({$results.add($_)}) | out-null
        if ($responseheader.HAS_MORE_RECORDS -contains "TRUE") {
            do {
                $page++
                $uri = $urlstart+$page+"&size=$pagesize"
                $response = Invoke-RestMethod $uri -Method 'GET' -Headers (Get-HRHeader -accessToken $accessToken) -ResponseHeadersVariable responseheader
                $response.foreach({$results.add($_)}) | out-null
            } until ($responseheader.HAS_MORE_RECORDS -notcontains "TRUE")
        }
    }
    elseif($id){
        $uri= $ServerURL+"/rest/"+$RestMethod+"/"+$id
        $results = Invoke-RestMethod $uri -Method 'GET' -Headers (Get-HRHeader -accessToken $accessToken) -ResponseHeadersVariable responseheader
    }
    else{
        if($urldetails){
            $uri= $ServerURL+"/rest/"+$RestMethod+"?"+$urldetails
        }
        else{
            $uri= $ServerURL+"/rest/"+$RestMethod
        }
        
        $results = Invoke-RestMethod $uri -Method 'GET' -Headers (Get-HRHeader -accessToken $accessToken) -ResponseHeadersVariable responseheader
    }

    return $results
}

I also had to change the get-horizonsessions to get-horizonglobalsessions

function get-horizonglobalsessions(){
    [CmdletBinding(DefaultParametersetName='None')] 
    param(
        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $ServerURL,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [PSCustomObject] $accessToken,

        [Parameter(Mandatory=$true,
        HelpMessage='Id of the Local pod to query' )]
        [string] $podid
    )
    try{
        $results=Get-HorizonRestData -ServerURL $url -RestMethod "/inventory/v1/global-sessions" -accessToken $accessToken -urldetails "pod_id=$podid"
    }
    catch{
        throw $_
    }
    return $results
}

And a new function get-pods

function Get-Pods(){
    [CmdletBinding(DefaultParametersetName='None')] 
    param(
        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $ServerURL,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [PSCustomObject] $accessToken
    )

    try{
        $results=Get-HorizonRestData -ServerURL $url -RestMethod "/federation/v1/pods" -accessToken $accessToken
    }
    catch{
        throw $_
    }
    return $results
}

while function send-horizongmessage was upgraded to send-horizonglobalmessage

function send-horizonglobalmessage(){
    [CmdletBinding(DefaultParametersetName='None')] 
    param(
        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $ServerURL,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [PSCustomObject] $accessToken,

        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [array] $Session_Ids,

        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $Message,

        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [validateset("ERROR","WARNING","INFO", IgnoreCase = $false)]
        [string] $Message_Type,

        [Parameter(Mandatory=$true,
        HelpMessage='Id of the Local pod to query' )]
        [string] $podid
    )

    $jsonhashtable = [ordered]@{}
    $jsonhashtable.global_session_action_specs=@()
    $sessiondetailshashtable = [ordered]@{}
    $sessiondetailshashtable.ids=$Session_Ids
    $sessiondetailshashtable.pod_id=$podid
    $jsonhashtable.global_session_action_specs+=$sessiondetailshashtable
    $jsonhashtable.message = $message
    $jsonhashtable.message_type = $Message_Type
    $json = $jsonhashtable | convertto-json -depth 100

    try{
        $results = Invoke-RestMethod -Method Post -uri "$ServerURL/rest/inventory/v1/global-sessions/action/send-message" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken) -body $json
    }
    catch{
        throw $_
    }
    return $results
}

and some other of the runtime pieces also changed

$pods=get-pods -accessToken $accessToken -ServerURL $url

foreach($pod in $pods){
    $podid=$pod.id
    $sessions = get-horizonglobalsessions -accessToken $accessToken -ServerURL $url -podid $podid
    send-horizonglobalmessage -accessToken $accessToken -ServerURL $url -Message_Type $Message_Type -message $message -Session_Ids ($sessions).id -podid $podid
}

And this is how you run it with the output in the vdi desktops

D:\GIT\Various_Scripts\Horizon_send_Global_messages.ps1 -Credential $creds -ConnectionServerFQDN pod1cbr1.loft.lab -message "test vExpert test" -Message_Type ERROR

This is the complete script but it can also be found on Github

<#
    .SYNOPSIS
    Send a message to all global sessions

    .DESCRIPTION
    This script uses the Horizon rest api's to all global sessions in a horizon cloud pod 

    .EXAMPLE
    .\Horizon_send_Global_messages.ps1 -Credential $creds -ConnectionServerFQDN pod2cbr1.loft.lab -message "test message" -message_type "ERROR"

    .PARAMETER Credential
    Mandatory: No
    Type: PSCredential
    Object with credentials for the connection server with domain\username and password

    .PARAMETER ConnectionServerFQDN
    Mandatory: Yes
    Default: String
    FQDN of the connection server to connect to

    .PARAMETER message
    Mandatory: Yes
    Message to send to the users

    .PARAMETER message_type
    Mandatory: Yes
    Message type: INFO, ERROR or WARNING

    .NOTES
    Created by: Wouter Kursten
    First version: 17-03-2022

    .COMPONENT
    Powershell Core

#>

[CmdletBinding()]
param (
    [Parameter(Mandatory=$false,
    HelpMessage='Credential object as domain\username with password' )]
    [PSCredential] $Credential,

    [Parameter(Mandatory=$true,  HelpMessage='FQDN of the connectionserver' )]
    [ValidateNotNullOrEmpty()]
    [string] $ConnectionServerFQDN,

    [Parameter(Mandatory=$true,
    HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
    [string] $Message,

    [Parameter(Mandatory=$true,
    HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
    [validateset("ERROR","WARNING","INFO", IgnoreCase = $false)]
    [string] $Message_Type
)

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)
}

function Get-HorizonRestData(){
    [CmdletBinding(DefaultParametersetName='None')] 
    param(
        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $ServerURL,

        [Parameter(Mandatory=$true,
        ParameterSetName="filteringandpagination",
        HelpMessage='Array of ordered hashtables' )]
        [array] $filters,

        [Parameter(Mandatory=$true,
        ParameterSetName="filteringandpagination",
        HelpMessage='Type of filter Options: And, Or' )]
        [ValidateSet('And','Or')]
        [string] $Filtertype,

        [Parameter(Mandatory=$false,
        ParameterSetName="filteringandpagination",
        HelpMessage='Page size, default = 500' )]
        [int] $pagesize = 500,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [string] $RestMethod,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [PSCustomObject] $accessToken,

        [Parameter(Mandatory=$false,
        ParameterSetName="filteringandpagination",
        HelpMessage='$True for rest methods that contain pagination and filtering, default = False' )]
        [switch] $filteringandpagination,

        [Parameter(Mandatory=$false,
        ParameterSetName="id",
        HelpMessage='To be used with single id based queries like /monitor/v1/connection-servers/{id}' )]
        [string] $id,

        [Parameter(Mandatory=$false,
        HelpMessage='Extra additions to the query url that comes before the paging/filtering parts like brokering_pod_id=806ca in /rest/inventory/v1/global-sessions?brokering_pod_id=806ca&page=2&size=100' )]
        [string] $urldetails
    )
    
    if($filteringandpagination){
        if ($filters){
            $filterhashtable = [ordered]@{}
            $filterhashtable.add('type',$filtertype)
            $filterhashtable.filters = @()
            foreach($filter in $filters){
                $filterhashtable.filters+=$filter
            }
            $filterflat=$filterhashtable | convertto-json -Compress
            if($urldetails){
                $urlstart= $ServerURL+"/rest/"+$RestMethod+"?"+$urldetails+"&filter="+$filterflat+"&page="
            }
            else{
                $urlstart= $ServerURL+"/rest/"+$RestMethod+"?filter="+$filterflat+"&page="
            }
        }
        else{
            if($urldetails){
                $urlstart= $ServerURL+"/rest/"+$RestMethod+"?"+$urldetails+"&page="
            }
            else{
                $urlstart= $ServerURL+"/rest/"+$RestMethod+"?page="
            }
        }
        $results = [System.Collections.ArrayList]@()
        $page = 1
        $uri = $urlstart+$page+"&size=$pagesize"
        write-host $uri
        $response = Invoke-RestMethod $uri -Method 'GET' -Headers (Get-HRHeader -accessToken $accessToken) -ResponseHeadersVariable responseheader
        $response.foreach({$results.add($_)}) | out-null
        if ($responseheader.HAS_MORE_RECORDS -contains "TRUE") {
            do {
                $page++
                $uri = $urlstart+$page+"&size=$pagesize"
                $response = Invoke-RestMethod $uri -Method 'GET' -Headers (Get-HRHeader -accessToken $accessToken) -ResponseHeadersVariable responseheader
                $response.foreach({$results.add($_)}) | out-null
            } until ($responseheader.HAS_MORE_RECORDS -notcontains "TRUE")
        }
    }
    elseif($id){
        $uri= $ServerURL+"/rest/"+$RestMethod+"/"+$id
        $results = Invoke-RestMethod $uri -Method 'GET' -Headers (Get-HRHeader -accessToken $accessToken) -ResponseHeadersVariable responseheader
    }
    else{
        if($urldetails){
            $uri= $ServerURL+"/rest/"+$RestMethod+"?"+$urldetails
        }
        else{
            $uri= $ServerURL+"/rest/"+$RestMethod
        }
        
        $results = Invoke-RestMethod $uri -Method 'GET' -Headers (Get-HRHeader -accessToken $accessToken) -ResponseHeadersVariable responseheader
    }

    return $results
}

function get-horizonglobalsessions(){
    [CmdletBinding(DefaultParametersetName='None')] 
    param(
        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $ServerURL,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [PSCustomObject] $accessToken,

        [Parameter(Mandatory=$true,
        HelpMessage='Id of the Local pod to query' )]
        [string] $podid
    )
    try{
        $results=Get-HorizonRestData -ServerURL $url -RestMethod "/inventory/v1/global-sessions" -accessToken $accessToken -urldetails "pod_id=$podid"
    }
    catch{
        throw $_
    }
    return $results
}

function Get-Pods(){
    [CmdletBinding(DefaultParametersetName='None')] 
    param(
        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $ServerURL,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [PSCustomObject] $accessToken
    )

    try{
        $results=Get-HorizonRestData -ServerURL $url -RestMethod "/federation/v1/pods" -accessToken $accessToken
    }
    catch{
        throw $_
    }
    return $results
}

function send-horizonglobalmessage(){
    [CmdletBinding(DefaultParametersetName='None')] 
    param(
        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $ServerURL,

        [Parameter(Mandatory=$true,
        HelpMessage='Part after the url in the swagger UI i.e. /external/v1/ad-users-or-groups' )]
        [PSCustomObject] $accessToken,

        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [array] $Session_Ids,

        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [string] $Message,

        [Parameter(Mandatory=$true,
        HelpMessage='url to the server i.e. https://pod1cbr1.loft.lab' )]
        [validateset("ERROR","WARNING","INFO", IgnoreCase = $false)]
        [string] $Message_Type,

        [Parameter(Mandatory=$true,
        HelpMessage='Id of the Local pod to query' )]
        [string] $podid
    )

    $jsonhashtable = [ordered]@{}
    $jsonhashtable.global_session_action_specs=@()
    $sessiondetailshashtable = [ordered]@{}
    $sessiondetailshashtable.ids=$Session_Ids
    $sessiondetailshashtable.pod_id=$podid
    $jsonhashtable.global_session_action_specs+=$sessiondetailshashtable
    $jsonhashtable.message = $message
    $jsonhashtable.message_type = $Message_Type
    $json = $jsonhashtable | convertto-json -depth 100

    try{
        $results = Invoke-RestMethod -Method Post -uri "$ServerURL/rest/inventory/v1/global-sessions/action/send-message" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken) -body $json
    }
    catch{
        throw $_
    }
    return $results
}

if($Credential){
    $creds = $credential
}
else{
    $creds = get-credential
}

$ErrorActionPreference = 'Stop'

$username=($creds.username).split("\")[1]
$domain=($creds.username).split("\")[0]
$password=$creds.password

$url = "https://$ConnectionServerFQDN"

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

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

$pods=get-pods -accessToken $accessToken -ServerURL $url

foreach($pod in $pods){
    $podid=$pod.id
    $sessions = get-horizonglobalsessions -accessToken $accessToken -ServerURL $url -podid $podid
    send-horizonglobalmessage -accessToken $accessToken -ServerURL $url -Message_Type $Message_Type -message $message -Session_Ids ($sessions).id -podid $podid
}

 

Bookmark the permalink.

Comments are closed.