Инфраструктура непостоянных виртуальных устройств (NP-VDI)
NP-VDI позволяет ИТ-подразделениям быстро готовить виртуальные ПК вместе с физическими устройствами, используя для этого единую платформу. Встроенное автоматизированное управление экономит время, сокращает расходы и обеспечивает комплексное управление конечными системами в облачных средах.
Последовательность действий
Развертывание агента на базовом образе:
-
Агент устанавливается на чистой виртуальной машине (без регистрации).
-
Затем агент вручную регистрируется как "Базовый образ" с помощью предоставленного средства командной строки.
Закрытие базового образа:
-
После регистрации агентом базового образа и проверки конфигурации виртуальной машины последняя "закрывается" с помощью командной строки.
Создание экземпляров:
-
Новые экземпляры NP-VDI можно создавать из базового образа, генерируя новый MAC-адрес для каждого сеанса.
-
Платформа Ivanti Neurons обнаруживает и отслеживает их как уникальные краткосрочные конечные системы, управляемые с помощью базового образа.
Управление политиками:
-
Изменения политики можно вносить на уровне базового образа. Все сохраненные экземпляры наследуют последнюю примененную политику при следующей регистрации.
Действие 1. Подготовка базового образа
Для подготовки базового образа выполните следующие действия:
- Перейдите Агент > Развертывание агентов > Установка вручную.
- На вкладке "Установка вручную" выберите политику агента и ключ подписки.
- Выберите Windows. Затем выберите Режим установки и нажмите Загрузить.
Будет загружен установщик агента.Это действие загрузит два файла. Сохраните программу установки с именем файла "IvantiCloudAgent.exe.options". Этот файл будет использоваться для установки.
- Установите загруженный агент NP-VDI.
Для установки агента:- Переименуйте связанный файл IvantiCloudAgent.exe.options перед установкой.
- Запустите программу установки. Когда появится кнопка активации или параметр файлов Cookie нажмите Отмена.
Это установит агент на конечную систему без регистрации в Tenant.
- Зарегистрируйте агент в качестве базового образа. Для регистрации в качестве базового образа выполните следующую команду от имени администратора в месте установки агента:
STAgentCtl.exe register --asBaseImage <Base Image Name> --instanceIdType MacAddress --enrollmentkey "%enrollmentkey%" --baseurl https://agentreg.ivanticloud.com
В приведенной выше команде:
<Base Image Name> - это имя базового образа устройства.
%enrollmentkey% - это комбинация tenantid_activationkey.
instanceIdType может иметь значения: "MacAddress", "HostName" или “Custom”. Используется в качестве уникального флага для идентификации экземпляра.
Если используется значение "Custom" (Особый), параметр tagList, содержащий разделенный запятыми список особых тегов, может быть указан для идентификации этого агента. Для получения дополнительной информация об особых тегах см. разделы Список особых тегов и Обновление тегов.
Параметры tenantid и activationkey можно найти в связанном файле параметров, загруженном с агентом, как это показано в примере далее:
tenantid = 11111111-1111-1111-1111-4gc02d5b0f0d
activationkey = 9aI7SOQNybweiM2QKI7kcqIG8ufUFU21AvZwJwAEx6C-SAO5UGK62YkEgm89kvC2m-xwLesZA4t1_TBtEjIQMVaBU0KsVe-V60ZLBwWu83YREcUp3diAFvHjBvLtkxT3
cloudhost=https:agentreg.ivanticlouddev.comКлюч подписки для вышеуказанного кода:
%enrollmentkey% = 11111111-1111-1111-1111-4gc02d5b0f0d_9aI7SOQNybweiM2QKI7kcqIG8ufUFU21AvZwJwAEx6C-SAO5UGK62YkEgm89kvC2m-xwLesZA4t1_TBtEjIQMVaBU0KsVe-V60ZLBwWu83YREcUp3diAFvHjBvLtkxT3Командная строка для регистрации устройства с примерным Tenant для базового образа с именем "Win11":
STAgentCtl.exe register --asBaseImage Win11 --instanceIdType MacAddress --enrollmentkey “11111111-1111-1111-1111-4gc02d5b0f0d_9aI7SOQNybweiM2QKI7kcqIG8ufUFU21AvZwJwAEx6C-SAO5UGK62YkEgm89kvC2m-xwLesZA4t1_TBtEjIQMVaBU0KsVe-V60ZLBwWu83YREcUp3diAFvHjBvLtkxT3" --baseurl https://agentreg.ivanticloud.com
- Для обновления базового образа:
- Загрузите сценарий PowerShell с портала сообщества Ivanti: Ivanti-Neurons -Non-Persistent-VDI - Agent Script.
Перед запуском сценария PowerShell убедитесь, что администратор имеет соответствующие разрешения для его запуска на базовом образе, поскольку политика выполнения на конечных системах может блокировать следующее:
Для проверки используйте команду "Get-ExecutionPolicy".
Для изменения используйте команду "Set-ExecutionPolicy RemoteSigned".
- Если сценарий запускается без каких-либо параметров, он попытается выполнить следующие действия:
- Отменить закрытие агента.
- Выполнить обновления для агентов и программ.
- Снова закрыть агент.
- Если агент уже открыт и должен оставаться в этом виде после обновления. Перешлите параметр "DoNotSeal" для выполнения тех же действий, за исключением закрытия образа.
- По умолчанию аут-аут для обновлений составляет 300 секунд. Вы можете изменить время, указав аргумент "-TimeoutSec".
Для справки: копия сценария доступна в разделе Приложения.
- Для подготовки базового образа:
- Выполните команду "STAgentCtl.exe prepareImage", чтобы подготовить закрытый непостоянный базовый образ для NP-VDI.
Эта команда является обязательной, останавливает все службы и удаляет любые данные, связанные с фактическим ИД агента базового образа. После загрузки непостоянного экземпляра службы будут перезагружены.ИД агента будет меняться при каждом использовании непостоянного экземпляра, созданного из базового образа.
- Используйте следующие команды для закрытия базового образа вручную (вне сценария обновления):
- Для закрытия базового образа вручную введите "STAgentCtl.exe seal".
Используйте команду "unseal" для открытия образа. Эта функция остается активной до перезапуска системы или использования команды "Seal" (закрытие).
- Для закрытия базового образа вручную введите "STAgentCtl.exe seal".
- Выполните команду "STAgentCtl.exe prepareImage", чтобы подготовить закрытый непостоянный базовый образ для NP-VDI.
- (Необязательно) Подготовьте образ для использования с помощью sysprep.
Если подготовка непостоянного ПО включает этап sysprep, она удалит закрытый ключ сертификата агента из хранилища сертификатов. Для решения этой проблемы выполните следующие действия:Администратор должен использовать собственный пароль экспорта сертификата - в противном случае этот процесс завершится с ошибкой.
- Выполните поиск серийного номера сертификата с помощью команды certutil -store “Ivanti Cloud Agent Agent”.
В этом поле отображается сертификат из хранилища сертификатов агентов. - После выполнения команды“stagentctl prepareImage” в действии 7 можно экспортировать сертификат агента с помощью следующей команды:
certutil -exportPFX -privatekey -p "%pfxpass%" “Ivanti Cloud Agent Agent” %serialnumber% "%ProgramFiles%\Ivanti\Ivanti Cloud Agent\agent.pfx" NoChain,NoRoot
В приведенной выше команде:
%pfxpass% - это пароль, предоставленный администратором.
%serialnumber% - это обнаруженный серийный номер сертификата агента.
- Загрузите сценарий SetupComplete.cmd с веб-сайта сообщества пользователей Ivanti: Восстановите закрытый ключ из экспортированного сценария файла .pfx.
- Отредактируйте сценарий SetupComplete.cmd и обновите пароль, чтобы он соответствовал паролю, используемому для экспорта сертификата, используемого в действии 2.
- Сохраните сценарий в %WINDIR%\Setup\Scripts\SetupComplete.cmd на золотом изображении.
Сценарий будет автоматически запущен после завершения настройки Windows (что произойдет при первой загрузке устройства после sysprep).Это приведет к восстановлению закрытого ключа из экспортированного файла .pfx, а затем к удалению файла .pfx и самого сценария для предотвращения разглашения секрета в непостоянные экземпляры.
Сертификат с темой OU “ST Agent” (например, "Тема: OU=ST Agent, CN=011472EFB12BABF06122F2903BBE12AC4E32EBFE5082”) должен быть экспортирован с помощью соответствующего серийного номера из этой записи.
- Выполните поиск серийного номера сертификата с помощью команды certutil -store “Ivanti Cloud Agent Agent”.
Действие 2. Создание и тестирование экземпляров NP-VDI
Для запуска нового экземпляра из базового образа выполните следующие действия:
-
Убедитесь, что каждому новому экземпляру назначен новый MAC-адрес (для работы параметра instanceIdType MacAddress).
Или убедитесь, что используется другое имя хоста или тег. -
Запустите экземпляр виртуальной машины и убедитесь, что он отображается в интерфейсе Neurons как уникальная конечная система NP-VDI. Для этого перейдите в раздел интерфейса Ivanti Neurons: Агенты > Управление агентами.
Доступен новый столбец Тип VDI, в котором указывается, является ли устройство базовым образом, непостоянным или постоянным. -
Теперь каждая конечная система с агентом привязана на странице управления агентами к странице устройств. Нажмите имя конечной системы с агентом, чтобы открыть новое окно с изображением устройства в виде "Устройства".
-
Нажмите Связанные экземпляры для отображения всех экземпляров, созданных из этого базового образа.
Непостоянные экземпляры будут помечены в виде "Устройства" как непостоянные.
Действие 3. Переназначение политики с помощью NP-VDI
Для переназначения политики для базового образа непосредственно из интерфейса платформы Ivanti Neurons, выполните следующие действия:
-
Перейдите Агенты > Политики агента.
-
Выберите базовый образ, а затем Переназначение политики в меню Действия.
-
Выберите политику для переназначения и нажмите Сохранить.
Это выполнит переназначение политики. После переназначения политики базовому образу все непостоянные экземпляры VDI унаследуют ее при следующей регистрации (по умолчанию каждые 200 минут). -
Проверьте, что новые экземпляры наследуют обновленную политику после регистрации, используя интерфейс агентов Ivanti Neurons или программы управления агентами, или из самого непостоянного образа, используя командную строку "Stagentctl status".
Действия перезагрузки нельзя выполнить на самом экземпляре NP-VDI. Это приведет к сбросу устройства в исходное состояние, что может привести к потере данных, полученных во время сеанса.
Кроме того, действия, доступные в виде "Устройства" для непостоянных экземпляров, не содержат операций перезагрузки.
Дополнительные команды STAgentCtle.exe
Вы можете использовать следующие дополнительные команды:
-
Для открытия базового агента для обновлений, введите команду "Stagentctl.exe unseal".
-
Для принудительного ожидания командной строкой завершения обновления перед возвратом управления введите команду "Stagentctl.exe update –wait".
Команда "ожидания" может столкнуться с проблемами после обновления агента, так как это требует запуска исполняемых файлов агента, что приведет к необходимости перезагрузки после обновления. Чтобы избежать этой проблемы, Ivanti предлагает сценарий PowerShell, который позволяет выполнить синхронную команду обновления.
-
Для закрытия базового агента для обновлений введите команду "Stagentctl.exe unseal".
Список особых тегов
Список особых тегов - это определяемая пользователем коллекция тегов, которые могут быть назначены конечным системам в платформе Ivanti Neurons, включая экземпляры NP-VDI. Особые теги помогают классифицировать, организовывать и идентифицировать устройства на основе деловых, операционных или технических требований.
Например, во время использования тег "Sales-[MacAddress]" генерирует уникальный тег для каждого устройства путем замены параметра [MacAddress] фактическим MAC-адресом устройства. Эта функция особенно полезна для создания уникальных тегов для непостоянных экземпляров VDI.
Используйте следующий синтаксис для сравнения атрибутов устройства и переменных среды:
-
Для указания MAC-адреса используйте "[MacAddress]"
-
Для указания имени хоста адреса используйте "[HostName]"
-
<name>Для указания переменной среды используйте "[env:]"
<name>Где - имя переменной среды, чувствительное к регистру ввода.
Обновление тегов
Теги, назначенные во время регистрации базового образа, остаются статическими для всех связанных экземпляров. Если необходимо обновить теги, повторно зарегистрируйте/закройте базовый образ или используйте автоматизацию для назначения тегов на основе текущий критериев после развертывания виртуальных машин.
Приложение
.SYNOPSIS
Выполняет обновление непостоянного агента, ожидая завершения обновления с последующим закрытием агента.
.PARAMETER TimeoutSec
Общий тайм-аут в секундах.
.PARAMETER UpgradeCode
Код обновления для агента.
.PARAMETER DoNotSeal
Этот параметр указывает, что нельзя закрывать агент после обновления.
#>
param
(
[int] $TimeoutSec = 300,
[guid] $UpgradeCode = "{0C5D7E9C-0424-462D-A570-2A7469EE3739}", # Neurons Agent
[switch] $DoNotSeal
)
function Check-UpdatersComplete
{
$updaters = Get-Process -Name "STAgentUpdater" -ErrorAction SilentlyContinue
return ($updaters.Count -eq 0)
}
function Wait-UpdatersComplete([DateTime] $timeoutDateTime, [int] $checkIntervalSec)
{
while ((Get-Date) -lt $timeoutDateTime)
{
if (Check-UpdatersComplete)
{
return
}
Start-Sleep -Seconds $checkIntervalSec
}
throw "Тайм-аут ожидания до завершения."
}
function Get-AgentVersionFromManifest([string] $manifestPath, [string] $platformKey)
{
if (-not (Test-Path $manifestPath))
{
throw "Не удалось найти манифест в '$manifestPath'."
}
[xml]$manifestXml = Get-Content $manifestPath
$agentFile = $manifestXml.manifest.files.file | Where-Object { $_.key -eq $platformKey }
if (-not ($agentFile))
{
throw "Запись агента с key='$platformKey' не найдена."
}
if (-not ($agentFile.version))
{
throw "Не удалось найти версию агента в манифесте."
}
return [version]::Parse($agentFile.version)
}
function Get-CurrentAgentVersion([guid] $agentUpgradeCode)
{
$agentProductCode = Get-ProductCode -UpgradeCode $agentUpgradeCode
$agentObject = Get-WmiObject -Class Win32_Product | Where-Object { [guid]::Parse($_.IdentifyingNumber) -eq $agentProductCode }
if (-not ($agentObject))
{
throw "Установленный агент не найден."
}
if (-not ($agentObject.Version))
{
throw "Версия установленного агента не найдена."
}
return [version]::Parse($agentObject.Version)
}
function Check-AgentUpToDate([string] $manifestPath, [guid] $agentUpgradeCode, [string] $platformKey)
{
$manifestVersion = Get-AgentVersionFromManifest -ManifestPath $manifestPath -PlatformKey $platformKey
$currentVersion = Get-CurrentAgentVersion -AgentUpgradeCode $agentUpgradeCode
return ($currentVersion -ge $manifestVersion)
}
function Wait-AgentUpdated([DateTime] $timeoutDateTime, [int] $checkIntervalSec, [string] $manifestPath, [guid] $agentUpgradeCode, [string] $platformKey)
{
while ((Get-Date) -lt $timeoutDateTime)
{
if (Check-AgentUpToDate -ManifestPath $manifestPath -AgentUpgradeCode $agentUpgradeCode -PlatformKey $platformKey)
{
return
}
Start-Sleep -Seconds $checkIntervalSec
}
throw "Ожидание тайм-аута обновления агента."
}
function Update-Agent([DateTime] $timeoutDateTime, [string] $manifestPath, [guid] $agentUpgradeCode, [string] $agentCtlPath, [string] $platformKey)
{
$timeoutSec = [math]::Ceiling(($timeoutDateTime - (Get-Date)).TotalSeconds)
if ($timeoutSec -le 0)
{
throw "Нельзя выполнить регистрацию из-за слишком короткого тайм-аута."
}
& $agentCtlPath update --checkin --wait $timeoutSec
if (-not $?)
{
throw "Ошибка операции регистрации."
}
& $agentCtlPath update --all
if (-not $?)
{
throw "Ошибка операции обновления."
}
Wait-AgentUpdated -TimeoutDateTime $timeoutDateTime -CheckIntervalSec 1 -ManifestPath $manifestPath -AgentUpgradeCode $agentUpgradeCode -PlatformKey $platformKey
Wait-UpdatersComplete -TimeoutDateTime $timeoutDateTime -CheckIntervalSec 1
$timeoutSec = [math]::Ceiling(($timeoutDateTime - (Get-Date)).TotalSeconds)
if ($timeoutSec -le 0)
{
throw "Нельзя выполнить окончательное обновление из-за небольшого тайм-аута."
}
& $agentCtlPath update --all --wait $timeoutSec
if (-not $?)
{
throw "Ошибка операции окончательного обновления."
}
}
function Get-ProductCode([guid] $upgradeCode)
{
$upgradeCodeStr = $upgradeCode.ToString("B") # Format as {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
$wmiFilter = "Property='UpgradeCode' AND Value='$upgradeCodeStr'"
$productCode = @(Get-WmiObject -Class Win32_Property -Filter $wmiFilter).ProductCode
if ($productCode.Count -eq 0)
{
throw "Код обновления $upgradeCode' не найден."
}
if ($productCode.Count -gt 1)
{
throw "Найдено несколько продуктов с одинаковым кодом обновления $upgradeCode'."
}
return [guid]::Parse($productCode)
}
function Get-AgentEnvironment([string] $installDirPath)
{
$configPath = Join-Path $installDirPath "AgentEnvironment.config"
if (-Not (Test-Path $configPath))
{
throw "Файл конфигурации не найден в $configPath."
}
[xml]$agentEnvironment = Get-Content $configPath
return $agentEnvironment
}
function Get-InstallLocation([guid] $productCode)
{
$productObject = Get-WmiObject -Class Win32_Product | Where-Object { [guid]::Parse($_.IdentifyingNumber) -eq $productCode }
if ($null -eq $productObject)
{
throw "GUID продукта не найден."
}
return $productObject.InstallLocation
}
$timeoutDateTime = (Get-Date).AddSeconds($TimeoutSec)
Write-Host "Сбор информации..."
try
{
$agentProductCode = Get-ProductCode -UpgradeCode $UpgradeCode
$installDirPath = Get-InstallLocation -ProductCode $agentProductCode
Write-Host " Каталог установки: $installDirPath"
$agentEnvironment = Get-AgentEnvironment -InstallDirPath $installDirPath
$dataDirPath = $agentEnvironment.agentEnvironment.agentDataDirectory
Write-Host " Каталог данных: $dataDirPath"
$regPath = Join-Path "HKLM:" $agentEnvironment.agentEnvironment.registryPath
Write-Host " Раздел реестра: $regPath"
$platformKey = Get-ItemProperty -Path $regPath -Name "PlatformManifestKey" -ErrorAction Stop | Select-Object -ExpandProperty "PlatformManifestKey" -ErrorAction Stop
Write-Host " Ключ платформы: $platformKey"
$agentCtlPath = Join-Path $installDirPath "STAgentCtl.exe"
$manifestPath = Join-Path $dataDirPath "manifest.xml"
}
catch
{
Write-Error "ОШИБКА: $_"
exit -1
}
if ((Get-Date) -gt $timeoutDateTime)
{
Write-Error "ОШИБКА: Тайм-аут завершен до начала обновления агента."
exit -1
}
Write-Host "Открытие агента..."
& $agentCtlPath unseal
if (-not $?)
{
Write-Error "ОШИБКА: Невозможно выполнить операцию открытия."
exit -1
}
Write-Host "Открытие агента..."
$result = -1
try
{
Update-Agent -TimeoutDateTime $timeoutDateTime -ManifestPath $manifestPath -AgentUpgradeCode $UpgradeCode -AgentCtlPath $agentCtlPath -PlatformKey $platformKey
$result = 0
}
catch
{
Write-Error "ОШИБКА: $_"
}
if ($DoNotSeal)
{
if ($result -eq 0)
{
Write-Host "Агент успешно обновлен."
}
else
{
Write-Error "ОШИБКА: Ошибка обновления агента."
}
exit $result
}
Write-Host "Закрытие агента..."
& $agentCtlPath seal
if (-not $?)
{
Write-Error "ОШИБКА: Невозможно выполнить операцию закрытия!"
exit -1
}
if ($result -eq 0)
{
Write-Host "Агент успешно обновлен и закрыт."
}
exit $result
(@ECHO OFF
set pw=supersecret
set logfile=C:\ProgramData\Ivanti\Ivanti Cloud Agent\Logs\agentkeyrestore.log
set certFile=C:\Program Files\Ivanti\Ivanti Cloud Agent\agent.pfx
set scriptPath=%0%
ECHO %date% %time% - Начато восстановление ключа агента >> "%logfile%"
IF EXIST "%certFile%" (
certutil -f -p "%pw%" -privatekey -importPFX "Облачный агент Ivanti" "%certFile%" NoCert,NoExport >> "%logfile%" 2>&1
IF %ERRORLEVEL% NEQ 0 (
ECHO Ошибка импорта ключа агента >> "%logfile%"
)
ECHO Удаление файла ключа агента >> "%logfile%"
del "%certFile%" >> "%logfile%" 2>&1
IF %ERRORLEVEL% NEQ 0 (
ECHO Ошибка удаления файла ключа агента >> "%logfile%"
)
ECHO %date% %time% - Восстановление ключа агента завершено >> "%logfile%"
) ELSE (
ECHO %date% %time% - Ошибка восстановления ключа агента: ключ агента не найден >> "%logfile%"
)
ECHO Удаление сценария >> "%logfile%"
del "%scriptPath%" >> "%logfile%" 2>&1
"REM - С этого момента выполнение дальнейших команд невозможно, так как файл сценария удален."