Hi i Just wanted to share this in case it can be of any help to someone.
Its a script (with GUI) which can be used to send messages to connected users in a pod.
The script uses the local instance so you need to connect to the connection server which belongs to the pod you want to send a message too.
It is only possible to sens a message desktop pool based.
I could not find a proper space to add this to teh vemware code part of the forum. but feel free to move this if this is not the right location.
#Powershell script with GUI to send messages to selected users in an horizon environment.
#The HTML 5 interface in horizon 7.x can only send messaged to 20 people at once where flash was able to send many more.
#This will probably be changed in a later release of horizon.
#This script was made to overcome this issue in case you need to send a message to more pople at once.
#It uses the local instance so connect so the connection server of the pod containing the pool you want to send a message too.
#The Script comes without any warranty.
#Mark Platte 2021
Add-Type -assembly System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
#variable setup
$strUser = ""
$strServer = ""
$strPassword = ""
$strdomain = ""
$script:hvServer
$script:hvServices
$script:queryResultsService
#form Setup
#form
$main_form = New-Object System.Windows.Forms.Form
$main_form.Text ='Horizon send Message ®Mark Platte 2021'
$main_form.Width = 800
$main_form.Height = 810
$main_form.ControlBox =$false
$main_form.StartPosition="CenterScreen"
$main_form.FormBorderStyle = "FixedSingle"
#button connect
$btnButtonConnect = New-Object System.Windows.Forms.Button
$btnButtonConnect.Location = New-Object System.Drawing.Size(0,120)
$btnButtonConnect.Size = New-Object System.Drawing.Size(780,25)
$btnButtonConnect.Text = "Connect to connection server"
$main_form.Controls.Add($btnButtonConnect)
#button exit
$btnExit = New-Object System.Windows.Forms.Button
$btnExit.Location = New-Object System.Drawing.Size(620,740)
$btnExit.Size = New-Object System.Drawing.Size(150,25)
$btnExit.Text = "Exit"
$main_form.Controls.Add($btnExit)
#button sendmessage
$btnSend = New-Object System.Windows.Forms.Button
$btnSend.Location = New-Object System.Drawing.Size(520,475)
$btnSend.Size = New-Object System.Drawing.Size(250,25)
$btnSend.Text = "Send Message(s)"
$main_form.Controls.Add($btnSend)
#button Select all
$btnSelect = New-Object System.Windows.Forms.Button
$btnSelect.Location = New-Object System.Drawing.Size(48,500)
$btnSelect.Size = New-Object System.Drawing.Size(100,25)
$btnSelect.Text = "Select all"
$main_form.Controls.Add($btnSelect)
#button deselectall
$btndeSelect = New-Object System.Windows.Forms.Button
$btndeSelect.Location = New-Object System.Drawing.Size(148,500)
$btndeSelect.Size = New-Object System.Drawing.Size(100,25)
$btndeSelect.Text = "Deselect all"
$main_form.Controls.Add($btndeSelect)
#button Ger users
$btnGetUsers = New-Object System.Windows.Forms.Button
$btnGetUsers.Location = New-Object System.Drawing.Size(525,158)
$btnGetUsers.Size = New-Object System.Drawing.Size(250,25)
$btnGetUsers.Text = "Get Connected Users"
$main_form.Controls.Add($btnGetUsers)
#labels
$lblServer = New-Object System.Windows.Forms.Label
$lblServer.Location = New-Object System.Drawing.Size(0,15)
$lblServer.Size = New-Object System.Drawing.Size(150,25)
$lblServer.Text = "Connection Server:"
$main_form.Controls.Add($lblServer)
$lblUser = New-Object System.Windows.Forms.Label
$lblUser.Location = New-Object System.Drawing.Size(0,40)
$lblUser.Size = New-Object System.Drawing.Size(150,25)
$lblUser.Text = "User Name:"
$main_form.Controls.Add($lblUser)
$lblPassword = New-Object System.Windows.Forms.Label
$lblPassword.Location = New-Object System.Drawing.Size(0,65)
$lblPassword.Size = New-Object System.Drawing.Size(150,25)
$lblPassword.Text = "Password:"
$main_form.Controls.Add($lblPassword)
$lbldomain = New-Object System.Windows.Forms.Label
$lbldomain.Location = New-Object System.Drawing.Size(0,90)
$lbldomain.Size = New-Object System.Drawing.Size(150,25)
$lbldomain.Text = "Domain:"
$main_form.Controls.Add($lbldomain)
$lblPool = New-Object System.Windows.Forms.Label
$lblPool.Location = New-Object System.Drawing.Size(0,165)
$lblPool.Size = New-Object System.Drawing.Size(75,25)
$lblPool.Text = "Select pool: "
$main_form.Controls.Add($lblPool)
$lblStatus = New-Object System.Windows.Forms.Label
$lblStatus.Location = New-Object System.Drawing.Size(50,740)
$lblStatus.Size = New-Object System.Drawing.Size(50,25)
$lblStatus.Text = "Status: "
$main_form.Controls.Add($lblStatus)
$lblMessage = New-Object System.Windows.Forms.Label
$lblMessage.Location = New-Object System.Drawing.Size(100,740)
$lblMessage.Size = New-Object System.Drawing.Size(700,25)
$lblMessage.Text = "Please fill in the requested information to connect"
$main_form.Controls.Add($lblMessage)
$lblPriority = New-Object System.Windows.Forms.Label
$lblPriority.Location = New-Object System.Drawing.Size(520,455)
$lblPriority.Size = New-Object System.Drawing.Size(55,25)
$lblPriority.Text = "Sevirity:"
$main_form.Controls.Add($lblPriority)
#textboxes
$txtServer = New-Object System.Windows.Forms.TextBox
$txtServer.Location = New-Object System.Drawing.Size(150,10)
$txtServer.Size = New-Object System.Drawing.Size(400,25)
$txtServer.Text = ""
$main_form.Controls.Add($txtServer)
$txtUser = New-Object System.Windows.Forms.TextBox
$txtUser.Location = New-Object System.Drawing.Size(150,35)
$txtUser.Size = New-Object System.Drawing.Size(400,25)
$txtUser.Text = ""
$main_form.Controls.Add($txtUser)
$txtPass = New-Object System.Windows.Forms.TextBox
$txtPass.Location = New-Object System.Drawing.Size(150,60)
$txtPass.Size = New-Object System.Drawing.Size(400,25)
$txtPass.Text = ""
$txtPass.PasswordChar ="*"
$main_form.Controls.Add($txtPass)
$txtdomain = New-Object System.Windows.Forms.TextBox
$txtdomain.Location = New-Object System.Drawing.Size(150,85)
$txtdomain.Size = New-Object System.Drawing.Size(400,25)
$txtdomain.Text = ""
$main_form.Controls.Add($txtdomain)
$txtMessage = New-Object System.Windows.Forms.TextBox
$txtMessage.Multiline =$true
$txtMessage.Location = New-Object System.Drawing.Size(520,200)
$txtMessage.Size = New-Object System.Drawing.Size(250,240)
$txtMessage.Text = ""
$main_form.Controls.Add($txtMessage)
$txtstatus = New-Object System.Windows.Forms.TextBox
$txtstatus.Location = New-Object System.Drawing.Size(50,530)
$txtstatus.Size = New-Object System.Drawing.Size(725,195)
$txtstatus.Multiline =$true
$txtstatus.ScrollBars="Vertical"
$txtstatus.Text = ""
$main_form.Controls.Add($txtstatus)
#comboboxes
$cbPools = New-Object System.Windows.Forms.ComboBox
$cbPools.Location = New-Object System.Drawing.Size(80,160)
$cbPools.Size = New-Object System.Drawing.Size(150,25)
$main_form.Controls.Add($cbPools)
$cbPriority = New-Object System.Windows.Forms.ComboBox
$cbPriority.Location = New-Object System.Drawing.Size(575,450)
$cbPriority.Size = New-Object System.Drawing.Size(195,25)
$cbPriority.Items.Add("WARNING")
$cbPriority.Items.Add("ERROR")
$cbPriority.Items.Add("INFO")
$cbPriority.SelectedIndex =2
$main_form.Controls.Add($cbPriority)
#ListView
$dvUsers = New-Object System.Windows.Forms.ListView
$dvUsers.Location = New-Object System.Drawing.Size(50,200)
$dvUsers.Size = New-Object System.Drawing.Size(450,300)
$dvUsers.MultiSelect =$true
$dvusers.CheckBoxes =$true
$dvUsers.View ="Details"
$dvUsers.GridLines =$true
$dvusers.Columns.Add("User").Width =150
$dvusers.Columns.Add("Session State").Width =150
$dvusers.Columns.Add("Desktop Pool").Width =150
$dvusers.Columns.Add("id").Width =150
$main_form.Controls.Add($dvUsers)
#Checkboxes
$checkbox1 = new-object System.Windows.Forms.checkbox
$checkbox1.Location = new-object System.Drawing.Size(250,145)
$checkbox1.Size = new-object System.Drawing.Size(250,50)
$checkbox1.Text = "Only get Conneted sessions"
$checkbox1.Checked = $true
$main_form.Controls.Add($checkbox1)
#functions
#fucntion to conenct to 1 connection server
function Connect-Horizon
{
try{
$lblMessage.text = "Trying to connect to " + $strServer.ToString()
Connect-HVServer -Server $strServer -User $strUser -Password $strPassword -Domain $strdomain
$lblMessage.text = "Connected to " + $strServer.ToString()
}
catch{$lblMessage.Text = "Error While connecting please check provided information "}
}
function Write-text($string)
{
$txtstatus.Text = $txtstatus.text + $string + "`r`n"
}
#eventhandling
#btnConnect handler
#Click will get details form textfields to getr connection information (its not all secure no secure string is used so be sureto close program after use)
#it will also populate the pool combobox.
$btnButtonConnect.Add_Click(
{
$cbPools.Items.Clear()
$strServer = $txtServer.Text.ToString()
$strUser =$txtUser.Text.ToString()
$strPassword = $txtPass.Text.ToString()
$strdomain = $txtdomain.Text.ToString()
if( $strServer -ne "" -and $strUser -ne "" -and $strPassword -ne "" )
{
$script:hvServer = Connect-Horizon
$script:hvServices = $hvServer.ExtensionData
try{
$queryServiceDesktop = New-Object VMware.Hv.QueryServiceService
$defn = New-Object VMware.Hv.QueryDefinition
$defn.queryEntityType = 'DesktopSummaryView'
$defn.sortBy = 'desktopSummaryData.name'
$defn.sortDescending = $true
$queryResultsDesktop = $queryServiceDesktop.QueryService_Create($script:hvServices, $defn)
try{
foreach ($DTresult in $queryResultsDesktop.Results)
{
$cbPools.Items.Add( $DTresult.DesktopSummaryData.Name.ToString())
}
$cbpools.SelectedIndex = 0
}
catch {Write-text "An error occured while retrieving data"}
}
catch{
Write-text "An Error Occured"
}
}
else {$lblMessage.text = "Provide all data"}
}
)
# click will query user sessions from connection server for the selected pool eithe rall sessions or only connected sessions based on checkbox
$btnGetUsers.Add_Click(
{
$queryServiceService = New-Object VMware.Hv.QueryServiceService
$defnService = New-Object VMware.Hv.QueryDefinition
$defnService.queryEntityType = 'SessionLocalSummaryView'
$defnService.sortDescending = $False
$script:queryResultsService = $queryServiceService.QueryService_query($script:hvServices, $defnService)
$dvUsers.Items.Clear()
try {
$lblMessage.text = "Getting Users"
$nUsers = 0
foreach ($result in $script:queryResultsService.Results)
{
if($checkbox1.CheckState -eq "Checked")
{
if($result.NamesData.DesktopPoolCN.ToString() -eq $cbPools.SelectedItem.ToString().ToLower() -and $result.SessionData.SessionState.ToString() -eq "CONNECTED")
{
$nUsers = $nUsers + 1
$lvData = New-Object System.Windows.Forms.ListViewItem
$lvData.Text = $result.NamesData.UserName.ToString()
$lvData.SubItems.Add($result.SessionData.SessionState.ToString())
$lvData.SubItems.Add($result.NamesData.DesktopPoolCN.ToString())
$lvData.SubItems.Add($result.Id.tostring())
$dvUsers.items.Add($lvData)
}
}
if($checkbox1.CheckState -eq "Unchecked")
{
if($result.NamesData.DesktopPoolCN.ToString() -eq $cbPools.SelectedItem.ToString().ToLower() )
{
$nUsers = $nUsers + 1
$lvData = New-Object System.Windows.Forms.ListViewItem
$lvData.Text = $result.NamesData.UserName.ToString()
$lvData.SubItems.Add($result.SessionData.SessionState.ToString())
$lvData.SubItems.Add($result.NamesData.DesktopPoolCN.ToString())
$lvData.SubItems.Add($result.Id.tostring())
$dvUsers.items.Add($lvData)
}
}
$lblMessage.text = "Retrieved " + $nUsers.ToString() + " sessions"
}
Write-text $lblMessage.text = "Retrieved " + $nUsers.ToString() + " sessions"
}
catch {}
}
)
#Click will send message to all selected users (it will loop trough query results so its not entirly optimal but I did not spend time in saving the ID to an object for later use.
$btnSend.Add_Click(
{
$nerror=0
$nsend=0
foreach($item in $dvUsers.CheckedItems)
{
foreach($result in $script:queryResultsService.Results)
{
if($result.NamesData.UserName.ToString() -eq $item.subitems[0].text)
{
$user = $result.NamesData.UserName.ToString()
try{
$hvServices.Session.Session_SendMessage($result.Id,$cbPriority.SelectedItem.ToString(),$txtMessage.Text.ToString())
$nsend = $nsend + 1
Write-text "Message send to : $user"
}
catch
{
$nerror = $nerror + 1
Write-text "Error While sending Message to : $user"
}
}
}
}
$ntotal = $nerror + $nsend
Write-text "Tried to send $ntotal message(s) | $nerror Errors | $nsend Send"
}
)
$btnSelect.Add_Click(
{
foreach($item in $dvUsers.Items){
$Item.checked =$true
}
}
)
$btndeSelect.Add_Click(
{
foreach($item in $dvUsers.Items){
$Item.checked =$false
}
}
)
#$hvServices.Session.Session_SendMessage($result.Id,"INFO","test vanuit powershell")
#btnExit handler
$btnExit.Add_Click(
{
try{
Disconnect-HVServer $txtServer.Text.ToString() -Force -Confirm $true
}
catch{write-host "Could not disconnect"}
$main_form.Close()
}
)
Write-text("Program started ")
$main_form.ShowDialog()
Hope it helps.
Mark