Citrix Virtual Apps and Desktops
September 19, 2021

Отображение имени конечного устройства клиента в терминальных Citrix сессиях с помощью BGInfo

Очень часто бывает полезной информация о том, с какого устройства пользователь попал на терминальный сервер - и для сотрудника техподдержки, и для самого пользователя (например, он сможет сообщить эту информацию по телефону или в письме) - что существенно сократит время реагирования на какой-либо инцидент.

Данный функционал реализуем с помощью известной утилиты BGInfo из набора утилит Windows Sysinternals от небезызвестного Марка Руссиновича.

Нам понадобятся:

  • утилита bginfo
  • кастомизированный файл *.bgi для утилиты
  • PS скрипт для автоматического запуска
  • VBS скрипт для определения IPv4 адреса

Откроем bginfo и сразу сохраним всю конфигурацию в файл adatum.bgi:

позже мы оставим только нужные нам параметры

В файле adatum.bgi добавим кастомные информационные поля, которых нет в стандартном наборе. BGInfo позволяет получать необходимые значения разными способами - нас интересует посредством VBS скрипта и напрямую из текстового файла:

При создании полей BGInfo предупредит, что данных файлов по указанным к ним путям еще нет - игнорируем это и просто соглашаемся:

Уберем всё лишнее, и оставим только интересующую нас информацию:

Выберем фон рабочего стола по умолчанию:

Расположение нашей информации на экране:

Для каких типов подключений будет изменяться рабочий стол:

Сохраним все изменения в файле adatum.bgi.

Для определения IPv4 адреса сетевой платы воспользуемся VBS скриптом, т.к. дефолтные возможности BGInfo показывают сразу всю информацию обо всех интерфейсах, что визуально не очень приятно. Сохраним данный код в файл IPv4_Only.vbs:

strMsg = ""
strComputer = "."
intCounter = 0
 
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set IPConfigSet = objWMIService.ExecQuery("Select IPAddress from Win32_NetworkAdapterConfiguration WHERE IPEnabled = 'True'")
 
For Each IPConfig in IPConfigSet
 If Not IsNull(IPConfig.IPAddress) Then
 For i = LBound(IPConfig.IPAddress) to UBound(IPConfig.IPAddress)
  If Not Instr(IPConfig.IPAddress(i), ":") > 0 Then
    If intCounter > 0 Then
        strMsg = strMsg & vbcrlf & vbtab & IPConfig.IPAddress(i)
    Else
        strMsg = IPConfig.IPAddress(i)
    End If
    intCounter = intCounter + 1
  End If
 Next
 End If
Next

Echo strMsg

Сам запуск BGInfo с нужными нам параметрами, а так же формирование *.txt файлов для кастомных полей (которые мы создавали ранее) файла *.bgi, будем осуществлять через PowerShell скрипт bginfo.ps1:

$file_name = "$env:localappdata\Temp\device_name.txt"
$file_ip = "$env:localappdata\Temp\device_ip.txt"

#приостанавливаем выполнение скрипта на 1.5 секунды, чтобы информация, полученная далее посредством WMI
#успела появиться
Start-Sleep -Seconds 1.5

#воспользуемся WMI c пространством имен ситрикса для получения информации об имени устройства, с которого клиент
#попадает на терминальный сервер, а так же его IP адреса
Get-WmiObject -Namespace root\Citrix\euem -Class citrix_euem_clientConnect | ? {$_.Username -eq $env:USERNAME} | `
select -ExpandProperty *MachineName | Out-File $file_name -NoNewline
Get-WmiObject -Namespace root\Citrix\euem -Class citrix_euem_clientConnect | ? {$_.Username -eq $env:USERNAME} | `
Select -ExpandProperty *MachineIP | Out-File $file_ip -NoNewline

#запуск BGInfo с необходимыми нам аргументами
#adatum.bgi - файл с нашей конфигурацией
#silent - не показывать сообщения об ошибках
#timer:0 - таймер обратного отсчета. 0 - обновит фон рабочего стола мгновенно, без отображения окна конфигурации
#nolicprompt - не показывать лицензионное соглашение
C:\Windows\BGInfo\Bginfo.exe C:\Windows\BGInfo\adatum.bgi /silent /timer:0 /nolicprompt

Итак, все компоненты у нас есть. Дальше схема такая: групповой политикой будем копировать данные файлы на терминальные сервера, и в ней же создадим задание в планировщике (task scheduler) по запуску PS скрипта от имени пользователя.

Создадим политику и прилинкуем её на организационный юнит (organizational unit - OU), в котором лежат наши терминальные сервера:

Разместим папку с нашими файлами прямо в корне политики на контроллере домена:

Активируем обработку замыкания групповой политики (loopback processing mode) в режиме "Merge" (слияние):

Настроим копирование наших файлов в нужное нам место (можно копировать сразу целую папку BGInfo, но для наглядности будем копировать каждый файл отдельно):

Свойства для всех файлов идентичны:

Теперь создадим задание в планировщике:

Для того, чтобы автором задания значился пользователь, который зашел в свою сессию, отредактируем *.xml файл задания (появляется после его создания в групповой политике):

Само задание и его параметры:

Триггеры на срабатываение задания
Действие при активации триггера

Не забудьте обновить групповые политики на терминальных серверах, чтобы нужные нам файлы появились на них.

Теперь при логине посредством ситрикса на терминальном рабочем столе пользователя будет нужная нам информация. Посмотрим как это будет работать на практике:

PS: Данный функционал можно сделать и не привязываясь к WMI классам ситрикса, а, например, через PS модуль PSTerminalServices. Единственное неудобство - это то, что он по-умолчанию отсутствует.