$global:request_header = @{ "accept"="*/*" "content-type"="application/json" } function Test-Server { param ( [Parameter(Mandatory)] [string]$server ) try { $result = (new-object System.Net.Sockets.TcpClient).ConnectAsync($server,443).Wait(500) } catch { $result = $false } return $result } function Get-HorizonKeyAgreement { param ( [Parameter(Mandatory)] [string]$server ) $login_headers = $global:request_header $kaUri = "https://$server/rest/key-agreement" $body = '{"identifier":"string","nonce":"string","public_key":"string","supported_schemes": ["SCHEME-AES2"]}' if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } if (Test-Server -server $server) { try { $response = Invoke-RestMethod -Method Post -Uri $kaUri -Body $body -Headers $login_headers -SessionVariable websession -SkipCertificateCheck } catch { Write-Host "ERROR accessing $loginUri" Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription } if ($response -ne $null) { $response | Add-Member -MemberType NoteProperty -Name server_name -Value $server $response | Add-Member -MemberType NoteProperty -Name session -Value $websession $response | Add-Member -MemberType NoteProperty -Name user_name -Value "$domain\$username" } return $response } else { throw "Error: Unable to verify server $server on port 443." } } function Connect-HorizonServer { param ( [System.Management.Automation.PSCredential]$credential, [Parameter(Mandatory)] [string]$Server ) $loginUri = "https://$server/rest/login" if ($credential) { $username = $credential.UserName.split("\")[1] $domain = $credential.UserName.split("\")[0] $password = $credential.GetNetworkCredential().Password } $login_headers = $global:request_header $body = '{"domain":"' + $domain + '","password":"' + $password + '","username":"' + $username + '"}' if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } if (Test-Server -server $server) { try { $response = Invoke-RestMethod -Method Post -Uri $loginUri -Body $body -Headers $login_headers -SessionVariable websession -SkipCertificateCheck } catch { Write-Host "ERROR accessing $loginUri" Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription } $response | Add-Member -MemberType NoteProperty -Name server_name -Value $server $response | Add-Member -MemberType NoteProperty -Name session -Value $websession $response | Add-Member -MemberType NoteProperty -Name user_name -Value "$domain\$username" return $response } else { throw "Error: Unable to verify server $server on port 443." } } function Refresh-HorizonConnection { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $body = @{"refresh_token"="$token"} $refreshUri = "https://$server/rest/refresh" Write-Host $body try { $result = Invoke-RestMethod -Method Post -Uri $refreshUri -Headers $request_header -Body $body -SkipCertificateCheck } catch { Write-Error -Message "ERROR accessing $refreshUri`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" return } return $result } function Get-HorizonMachine { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $machineUri = "https://$server/rest/inventory/v5/machines?sort_by=name&order_by=ASC" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } try { $machines = Invoke-RestMethod -Method Get -Uri $machineUri -Headers $request_header -SkipCertificateCheck } catch { throw "ERROR accessing $machineUri`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $machines } function Remove-HorizonMachine { param ( [string]$id = "", [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $ids = $id.split(",") if ($ids.length -gt 1) { $body = "{""machine_ids"":[" foreach ($thisid in $ids) { $thisid = $thisid.Trim('"') if ($body -ne "{""machine_ids"":[") { $body += "," } $body += '"' + $thisid + '"' } $body += ']}' } else { $body = ']"{""machine_ids"":[""' + $id + '""]}' } $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $machineUri = "https://$server/rest/inventory/v1/machines" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } try { $result = Invoke-RestMethod -Method DELETE -Uri $machineUri -Body $body -Headers $request_header -SkipCertificateCheck -ErrorAction:SilentlyContinue } catch { $_.Exception.Response.StatusCode.value $_.Exception.Response.StatusDescription throw "ERROR accessing $machineUri`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $result } function Get-HorizonSession { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $sessionUri = "https://$server/rest/inventory/v2/sessions?sort_by=session_type&order_by=ASC" $userURI = "https://$server/rest/external/v2/ad-users-or-groups/**ID**" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } try { $sessions = Invoke-RestMethod -Method Get -Uri $sessionUri -Headers $request_header -SkipCertificateCheck $sessions | Add-Member -MemberType NoteProperty -Name user_name -Value "" $sessions | Add-Member -MemberType NoteProperty -Name user_principal_name -Value "" $sessions | Add-Member -MemberType NoteProperty -Name session_length -Value 0 $sessions | Add-Member -MemberType NoteProperty -Name connected_length -Value 0 } catch { throw "ERROR accessing $sessionUri`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } foreach($session in $sessions) { $user = $Horizon | Get-HorizonADUser -id $session.user_id $session.user_name = $user.login_name $session.user_principal_name = $user.user_principal_name $session.session_length = Get-HorizonSessionLength -session $session $session.connected_length = Get-HorizonSessionConnectedLength -session $session } return $sessions } function Get-HorizonVcenter { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $vcuri = "https://$server/rest/config/v1/virtual-centers" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } try { $vcs = Invoke-RestMethod -Method Get -Uri $vcUri -Headers $request_header -SkipCertificateCheck } catch { throw "ERROR accessing $vcUri`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $vcs } function Get-HorizonBaseVMs { param ( [Parameter(Mandatory)] [string]$vcid, [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $bvuri = "https://$server/rest/external/v1/base-vms?vcenter_id=$vcid&filter_incompatible_vms=true" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } try { $bvs = Invoke-RestMethod -Method Get -Uri $bvUri -Headers $request_header -SkipCertificateCheck } catch { throw "ERROR accessing $bvUri`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $bvs } function Get-HorizonBaseSnapshots { param ( [Parameter(Mandatory)] [string]$vcid, [Parameter(Mandatory)] [string]$vmid, [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $bsuri = "https://$server/rest/external/v1/base-vms?vcenter_id=$vcid&base_vm_id=$vmid" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } try { $bss = Invoke-RestMethod -Method Get -Uri $bsUri -Headers $request_header -SkipCertificateCheck } catch { throw "ERROR accessing $bsUri`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $bss } function Get-HorizonEntitlements { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $enturi = "https://$server/rest/entitlements/v1/desktop-pools" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } try { $entitlements = Invoke-RestMethod -Method Get -Uri $entUri -Headers $request_header -SkipCertificateCheck } catch { throw "ERROR accessing $entUri`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $entitlements } Function Get-HorizonEntitlementDetail { param ( [pscustomobject] $entitlements, [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $domains = $Horizon | Get-HorizonAdDomains if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } $result = @() foreach ($entitlement in $entitlements) { $entsid = $entitlement $user = $Horizon | Get-HorizonADUser -id $entitlement $object = $null if ($user) { if ($user.group) { $type = "Group" } else { $type = "User" } $object = [PSCustomObject]@{ Type = $type Domain = $user.domain SID = $entitlement SamAccountName = $user.login_name GivenName = $user.first_name Surname = $user.last_name Name = $user.name UserPrincipalName = $user.user_principal_name } } $result += $object } return $result } function Get-HorizonDesktopPool { param ( [string]$poolname = "", [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $pooluri = "https://$server/rest/inventory/v8/desktop-pools?sort_by=name&order_by=ASC" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } if (Test-Server -server $server) { try { $pools = Invoke-RestMethod -Method Get -Uri $pooluri -Headers $request_header -SkipCertificateCheck if ($poolname) { $pools = $pools | Where-Object {$_.Name -eq $poolname} } } catch { Write-Host "ERROR accessing $poolUri" Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription return $null } if ($pools) { $pools | Add-Member -MemberType NoteProperty -Name machines -Value @() $pools | Add-Member -MemberType NoteProperty -Name sessions -Value @() $pools | Add-Member -MemberType NoteProperty -Name vCenter -Value "" $pools | Add-Member -MemberType NoteProperty -Name cluster -Value "" $pools | Add-Member -MemberType NoteProperty -Name GpuEnabled -Value 0 $pools | Add-Member -MemberType NoteProperty -Name Entitlements -Value @() $machines = $Horizon | Get-HorizonMachine $sessions = $Horizon | Get-HorizonSession $counter = 1 foreach ($pool in $pools) { if ($null -ne $pool.provisioing_settings) { $pool.provisioning_settings | Add-Member -MemberType NoteProperty -Name base_vm_name -Value "" $pool.provisioning_settings | Add-Member -MemberType NoteProperty -Name snapshot_path -Value "" $pool.provisioning_settings | Add-Member -MemberType NoteProperty -Name datacenter_name -Value "" $pool.provisioning_settings | Add-Member -MemberType NoteProperty -Name resource_pool_name -Value "" $pool.provisioning_settings | Add-Member -MemberType NoteProperty -Name base_folder_path -Value "" } if ($null -ne $pool.storage_settings.datastores) { $pool.storage_settings.datastores | Add-Member -MemberType NoteProperty -Name name -Value "" } Write-Progress -Activity "Processing Pools" -Status "Processing $counter of $($pools.length) - $($pool.name)" -PercentComplete (($counter / $pools.length) *100) -Id 1 $mymachines = $machines | where {$_.desktop_pool_id -eq $pool.id} $pool.machines += $mymachines $mysessions = $sessions | where {$_.desktop_pool_id -eq $pool.id} $pool.sessions += $mysessions foreach($session in $pool.sessions) { $machineDNSName = ($mymachines | where {$_.id -eq $session.machine_id}).dns_name $machineName = ($mymachines | where {$_.id -eq $session.machine_id}).name $session | Add-Member -MemberType NoteProperty -Name machine_name -Value $machineName $session | Add-Member -MemberType NoteProperty -Name machine_dns_name -Value $machineDNSName } $pool.vCenter = (Get-HorizonVcenter -Horizon $Horizon | where-object {$_.id -eq $pool.vcenter_id}).server_name if (-not ($global:DefaultVIServer.Name -contains $pool.vCenter)) { throw "Not Connected to vCenter $($pool.vCenter)" } $pool.cluster = (Get-Cluster | where {$_.id -eq "ClusterComputeResource-$($pool.provisioning_settings.host_or_cluster_id)"}).name if ($null -ne $pool.provisioning_settings.base_vm_name) { $pool.provisioning_settings.base_vm_name = (Get-View -Id "VirtualMachine-$($pool.provisioning_settings.parent_vm_id)").Name $snappath = "" $goldVM = Get-VM $pool.provisioning_settings.base_vm_name $thissnap = $goldVM | Get-Snapshot | Where-Object {$_.Id -eq "VirtualMachineSnapshot-$($pool.provisioning_settings.base_snapshot_id)"} while ($thissnap.parentsnapshotid.length -gt 0) { if ($snappath -eq "") { $snappath = $thissnap.Name } else { $snappath = $thissnap.Name + "\" + $snappath } $thissnap = Get-VM $pool.provisioning_settings.base_vm_name | Get-Snapshot | Where-Object {$_.Id -eq $thissnap.ParentSnapshotId} } if ($snappath -eq "") { $snappath = $thissnap.Name } else { $snappath = $thissnap.Name + "\" + $snappath } $pool.provisioning_settings.snapshot_path = $snappath $pool.provisioning_settings.resource_pool_name = $goldVM.ResourcePool $pool.provisioning_settings.datacenter_name = (Get-View "Datacenter-$($pool.provisioning_settings.datacenter_id)").Name $basefolderpath = "" $thisfolder = Get-View "Folder-$($pool.provisioning_settings.vm_folder_id)" while ($thisfolder.parentsnapshotid.length -gt 0) { if ($basefolderpath -eq "") { $basefolderpath = $thisfolder.Name } else { $basefolderpath = $thisfolder.Name + "\" + $basefolderpath } $thisfolder = Get-View "Folder-$($thisfolder.Parent)" } if ($basefolderpath -eq "") { $basefolderpath = $thisfolder.Name } else { $basefolderpath = $thisfolder.Name + "\" + $basefolderpath } $pool.provisioning_settings.base_folder_path = $basefolderpath $datastores = @() foreach ($datastore in $pool.storage_settings.datastores) { $thisds = Get-View -Id "Datastore-$($datastore.datastore_id)" $datastore.name = $thisds.Name $datastores += $thisds.Name } } $pool.GpuEnabled = ($pool.display_protocol_settings.vgpu_grid_profile.Length -gt 0); $entsids = ($Horizon | Get-HorizonEntitlements | Where-Object {$_.id -eq $pool.id}).ad_user_or_group_ids if ($entsids.length -gt 0) { $entitlements = $Horizon | Get-HorizonEntitlementDetail -entitlements $entsids $pool.entitlements = $entitlements } ++$counter } Write-Progress -Activity "Processing Pools" -Completed -Id 1 return $pools } } else { return $false } } function Get-HorizonAdDomains { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $domainURI = "https://$server/rest/external/v2/ad-domains" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } try { $domains = Invoke-RestMethod -Method Get -Uri $domainUri -Headers $request_header -SkipCertificateCheck } catch { throw "ERROR accessing $domainUri`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $domains } Function Get-HorizonADUser { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon, [string]$Domain = "", [string]$Id = "", [string]$Name = "", [int]$Page = 0, [int]$PageSize = 0 ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $userlookupURI = "https://$server/rest/external/v1/ad-users-or-groups" $extension = ""; if ($domain -ne "") { $extension = "?group_only=false&filter={`"type`":`"Equals`",`"name`":`"domain`",`"value`":`"$domain`"}" if ($Page -ne 0) { $extension += "&page=$Page" if ($PageSize -ne 0) { $extension += "&size=$PageSize" } } } if ($Id -ne "") { $extension = "/$($Id)?group_only=false" } if ($Name -ne "") { $extension = "?group_only=false&filter={`"type`":`"Equals`",`"name`":`"user_principal_name`",`"value`":`"$Name`"}" } $userlookupURI += $extension if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } try { if ($global:kishorizondebug) { Write-Host URI: $userlookupURI Write-Host body: $body } $users = Invoke-RestMethod -Method Get -Uri $userlookupURI -Headers $request_header -SkipCertificateCheck if ($global:kishorizondebug) { Write-Host $users } } catch { throw "ERROR accessing $userlookupURI`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $users } function Invoke-SSHCommand { param ( [Parameter(Mandatory)] $ComputerName, [Parameter(Mandatory)] $Command, [Parameter(Mandatory)] $Credential ) $username = $($Credential.UserName) $password = $($Credential.GetNetworkCredential().password) $done = $false $count = 0; while (!$done) { $result = invoke-command {sshpass -p $password ssh $username@$ComputerName "$command"} if ($result) { $done = $true } else { ++$count if ($count >=5) { $done = $true } } } return $result } function Get-HorizonSessionLength { param ( [Parameter(Mandatory)] $session ) $now = [int](get-date -UFormat %s -Millisecond 0) $start = $session.start_time $retval = $now - ($start/ 1000) return $retval; } function Get-HorizonSessionConnectedLength { param ( [Parameter(Mandatory)] $session ) $retval = ($session.session_state -eq "CONNECTED") ? [math]::round($session.last_session_duration_ms/1000) : 0 return $retval; } function Add-HorizonMachineToPool { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon, [parameter(Mandatory = $true)][string[]] $MachineName, [parameter(Mandatory = $true)] $PoolName ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} $PoolID = (Get-HorizonDesktopPool -Horizon $Horizon -PoolName $PoolName).id $machineAddURI = "https://$server/rest/inventory/v1/desktop-pools/$PoolID/action/add-machines-by-name" if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } $body = @{ machine_names = $MachineName } | ConvertTo-Json try { $result = Invoke-RestMethod -Method Post -Uri $machineAddURI -body $body -Headers $request_header -SkipCertificateCheck } catch { throw "ERROR accessing $machineAddURI`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $result } function Grant-HorizonDesktop { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon, [parameter(Mandatory = $true)] $MachineName, [parameter(Mandatory = $true)] $UserUPN ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } $MachineID = (Get-HorizonMachine -Horizon $Horizon | where {$_.name -eq $MachineName}).id if ($global:kishorizondebug) { Write-Host MachineID: $MachineID } if ($MachineID -eq $null) { return [PSCustomObject]@{ Success = $false Message = Machine $MachneName does not exist in any desktop pool. } } $UserID = (Get-HorizonAdUser -Horizon $Horizon -Name $UserUPN).id if ($global:kishorizondebug) { Write-Host UserID: $UserID } if ($UserID -eq $null) { return [PSCustomObject]@{ Success = $false Message = User $UserUPN cannot be found. } } $desktopAssignURI = "https://$server/rest/inventory/v1/machines/$MachineID/action/assign-users" $body = "[ ""$UserID"" ]" if ($global:kishorizondebug) { Write-Host body: $body } try { $result = Invoke-RestMethod -Method Post -Uri $desktopAssignURI -body $body -Headers $request_header -SkipCertificateCheck } catch { throw "ERROR accessing $desktopAssignURI`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $result } function Revoke-HorizonDesktop { param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Horizon, [parameter(Mandatory = $true)] $MachineName ) $token = $Horizon.access_token $server = $Horizon.server_name $request_header = $global:request_header $request_header += @{"authorization"="Bearer $token"} if ($global:kishorizondebug) { Write-Host $MyInvocation.MyCommand.Name Starting } $MachineID = (Get-HorizonMachine -Horizon $Horizon | where {$_.name -eq $MachineName}).id if ($global:kishorizondebug) { Write-Host MachineID: $MachineID } if ($MachineID -eq $null) { return [PSCustomObject]@{ Success = $false Message = Machine $MachneName does not exist in any desktop pool. } } $desktopRevokeURI = "https://$server/rest/inventory/v1/machines/$MachineID/action/assign-users" $body = "[ ""$UserID"" ]" if ($global:kishorizondebug) { Write-Host body: $body } try { $result = Invoke-RestMethod -Method Post -Uri $desktopAssignURI -body $body -Headers $request_header -SkipCertificateCheck } catch { throw "ERROR accessing $desktopAssignURI`nStatusCode: $($_.Exception.Response.StatusCode.value__)`nStatusDescription: $($_.Exception.Response.StatusDescription)" } return $result } Export-ModuleMember -Function Connect-HorizonServer Export-ModuleMember -Function Get-HorizonVcenter Export-ModuleMember -Function Get-HorizonDesktopPool Export-ModuleMember -Function Get-HorizonMachine Export-ModuleMember -Function Remove-HorizonMachine Export-ModuleMember -Function Get-HorizonSession Export-ModuleMember -Function Get-HorizonAdDomains Export-ModuleMember -Function Get-HorizonAdUser Export-ModuleMember -Function Invoke-SSHCommand Export-ModuleMember -Function Get-HorizonSessionLength Export-ModuleMember -Function Get-HorizonKeyAgreement Export-ModuleMember -Function Get-HorizonEntitlements Export-ModuleMember -Function Get-HorizonEntitlementDetail Export-ModuleMember -Function Add-HorizonMachineToPool Export-ModuleMember -Function Grant-HorizonDesktop