Infraestructura de dispositivos virtuales no persistentes (NP-VDI)
NP-VDI permite al equipo de TI aprovisionar rápidamente escritorios virtuales junto con dispositivos físicos desde una única plataforma unificada. La gestión automatizada integrada ahorra tiempo, reduce la carga de trabajo manual y proporciona un control integral de los endpoints en entornos de nube.
Flujo de la funcionalidad
Despliegue del agente en la imagen base:
-
El agente se instala, pero no se registra, en una máquina virtual limpia.
-
A continuación, se registra manualmente como “Imagen base” mediante las herramientas de línea de comandos proporcionadas.
Sellado de la imagen base:
-
Una vez registrado el agente de la imagen base y validada la configuración, la máquina virtual se “sella” mediante la línea de comandos.
Creación de instancias:
-
Las nuevas instancias de NP-VDI se pueden crear a partir de la imagen base y, por lo general, generan una nueva dirección MAC para cada sesión.
-
Ivanti Neurons las detecta y realiza su seguimiento como endpoints únicos y temporales asociados a la imagen base.
Gestión de políticas:
-
Los cambios en las políticas se pueden realizar desde el nivel de la imagen base. Todas las instancias creadas heredan la política aplicada más recientemente en la siguiente comunicación con el agente.
Paso 1: Preparar la imagen base
Para preparar la imagen base, siga estos pasos:
- Vaya a Agente > Despliegue de agente > Instalación manual.
- En la pestaña Instalación manual, seleccione una política de agente y una clave de inscripción.
- Seleccione Windows. Seleccione un Modo de instalación y haga clic en Descargar.
Se descargará el instalador del agente.Esta acción descarga dos archivos. Guarde el instalador con el nombre de archivo "IvantiCloudAgent.exe.options". Este archivo se utilizará durante la instalación.
- Instale el agente NP-VDI descargado.
Para instalar el agente:- Cambie el nombre del archivo IvantiCloudAgent.exe.options asociado antes de iniciar la instalación.
- Ejecute el instalador. Cuando aparezca la opción Clave de activación o Cookie, seleccione Cancelar.
De este modo, el agente se instala en el endpoint sin registrarlo en el entorno.
- Registrar el agente como una imagen base. Para registrar el agente como imagen base, ejecute el siguiente comando como administrador desde la ubicación de instalación del agente:
STAgentCtl.exe register --asBaseImage <Base Image Name> --instanceIdType MacAddress --enrollmentkey "%enrollmentkey%" --baseurl https://agentreg.ivanticloud.com
En el comando anterior:
<Base Image Name> corresponde al nombre del dispositivo de imagen base.
%enrollmentkey% es una combinación de tenantid_activationkey.
instanceIdType puede ser "MacAddress", "HostName" o "Custom". Este parámetro se utiliza como identificador único de la instancia.
Si se utiliza "Custom» (personalizado), se puede especificar una opción tagList que contenga una lista de etiquetas personalizadas separadas por comas para identificar ese agente. Para obtener más información sobre las etiquetas personalizadas, consulte la sección Lista de etiquetas personalizadas y actualización de etiquetas.
Los valores tenantid t activationkey se encuentran en el archivo .options correspondiente, que se descarga junto con el agente, como se muestra en el siguiente ejemplo:
tenantid = 11111111-1111-1111-1111-4gc02d5b0f0d
activationkey = 9aI7SOQNybweiM2QKI7kcqIG8ufUFU21AvZwJwAEx6C-SAO5UGK62YkEgm89kvC2m-xwLesZA4t1_TBtEjIQMVaBU0KsVe-V60ZLBwWu83YREcUp3diAFvHjBvLtkxT3
cloudhost=https:agentreg.ivanticlouddev.comLa clave de inscripción para el código anterior es:
%enrollmentkey% = 11111111-1111-1111-1111-4gc02d5b0f0d_9aI7SOQNybweiM2QKI7kcqIG8ufUFU21AvZwJwAEx6C-SAO5UGK62YkEgm89kvC2m-xwLesZA4t1_TBtEjIQMVaBU0KsVe-V60ZLBwWu83YREcUp3diAFvHjBvLtkxT3El comando para registrar un dispositivo en el abonado de ejemplo con una imagen base denominada “Win11” es el siguiente:
STAgentCtl.exe register --asBaseImage Win11 --instanceIdType MacAddress --enrollmentkey “11111111-1111-1111-1111-4gc02d5b0f0d_9aI7SOQNybweiM2QKI7kcqIG8ufUFU21AvZwJwAEx6C-SAO5UGK62YkEgm89kvC2m-xwLesZA4t1_TBtEjIQMVaBU0KsVe-V60ZLBwWu83YREcUp3diAFvHjBvLtkxT3" --baseurl https://agentreg.ivanticloud.com
- Para actualizar la imagen base:
- Descargue el script de PowerShell desde el portal de la comunidad de Ivanti: Ivanti-Neurons -Non-Persistent-VDI - Agent Script.
Antes de ejecutar el script de PowerShell, asegúrese de que el administrador dispone de los permisos necesarios para ejecutarlo en la imagen base, ya que la política de ejecución del endpoint podría impedir su ejecución.
Para comprobarlo, utilice el comando "Get-ExecutionPolicy".
Para modificarlo, utilice el comando "Set-ExecutionPolicy RemoteSigned".
- Si el script se ejecuta sin parámetros, intentará realizar las siguientes acciones:
- Quitar el sellado del agente
- Ejecutar las actualizaciones de ambos agentes y motores.
- Volver a sellar el agente.
- Si el agente ya está sin sellar, debe permanecer sin sellar después de la actualización. Utilice el parámetro "DoNotSeal" para realizar todos los pasos anteriores, excepto volver a sellar la imagen.
- El tiempo de espera predeterminado para las actualizaciones es de 300 segundos. Puede modificar este tiempo mediante el argumento “-TimeoutSec”.
Como referencia adicional, puede consultar una copia del script en la sección Apéndice.
- Para preparar la imagen base:
- Ejecute el comando "STAgentCtl.exe prepareImage" para preparar una imagen base sellada y no persistente para NP-VDI.
Este comando es obligatorio, ya que detiene todos los servicios y elimina los datos asociados al ID de agente actual de la imagen base. Cuando se inicia la instancia no persistente, los servicios se reinician.El ID de agente cambia cada vez que se crea una nueva instancia no persistente a partir de la imagen base.
- Utilice los siguientes comandos para gestionar manualmente el sellado de la imagen base, fuera del script de actualización:
- Para sellar manualmente la imagen base, introduzca "STAgentCtl.exe seal".
Utilice el comando "unseal" para quitar el sellado de la imagen. Esto permanecerá activo hasta que se reinicie el sistema o se ejecute el comando "Seal".
- Para sellar manualmente la imagen base, introduzca "STAgentCtl.exe seal".
- Ejecute el comando "STAgentCtl.exe prepareImage" para preparar una imagen base sellada y no persistente para NP-VDI.
- (Opcional) Preparar la imagen para utilizarla con "sysprep".
Si la preparación del escritorio no persistente incluye una etapa de sysprep, la clave privada del certificado del agente se eliminará del almacén de certificados. Para evitar este problema, siga estos pasos:El administrador debe proporcionar una contraseña propia para exportar el certificado. De lo contrario, el proceso fallará.
- Localice el número de serie del certificado mediante el comando certutil -store “Ivanti Cloud Agent Agent”.
Este comando muestra los certificados almacenados en el almacén de certificados del agente. - Después de ejecutar el comando “stagentctl prepareImage” en el paso 7, puede exportar el certificado del agente mediante el siguiente comando:
certutil -exportPFX -privatekey -p "%pfxpass%" “Ivanti Cloud Agent Agent” %serialnumber% "%ProgramFiles%\Ivanti\Ivanti Cloud Agent\agent.pfx" NoChain,NoRoot
En el comando anterior:
%pfxpass% corresponde a una contraseña proporcionada por el administrador.
%serialnumber% corresponde al número de serie del certificado del agente identificado anteriormente.
- Descargue el script SetupComplete.cmd desde el sitio web de la comunidad de Ivanti:Restore private key from exported .pfx file script.
- Edite el script SetupComplete.cmd y actualice la contraseña para que coincida con la contraseña utilizada para exportar el certificado en el paso 2.
- Guarde el script en %WINDIR%\Setup\Scripts\SetupComplete.cmd en la imagen maestra.
El script se ejecutará automáticamente una vez completada la instalación de Windows, es decir, la primera vez que se inicie el dispositivo después de ejecutar sysprep.El script restaurará la clave privada desde el archivo .pfx exportado y, a continuación, eliminará tanto el archivo .pfx como el propio script para evitar que el secreto quede expuesto en las instancias no persistentes.
Identifique el certificado cuyo asunto tenga la unidad organizativa (OU) “ST Agent” (por ejemplo, "Subject: OU=ST Agent, CN=011472EFB12BABF06122F2903BBE12AC4E32EBFE5082”). A continuación, expórtelo utilizando el número de serie correspondiente a dicha entrada.
- Localice el número de serie del certificado mediante el comando certutil -store “Ivanti Cloud Agent Agent”.
Paso 2: Crear y probar instancias de NP-VDI
Para crear una nueva instancia desde la imagen base, siga estos pasos:
-
Asegúrese de que cada nueva instancia reciba una dirección MAC diferente para que funcione la opción instanceIdType MacAddress.
Como alternativa, utilice un nombre de host o una etiqueta diferente para cada instancia. -
Inicie la instancia de la máquina virtual y compruebe que aparece en la interfaz de Neurons como un endpoint NP-VDI único. Para ello, vaya a Agentes > Gestión de agentes en la interfaz de Ivanti Neurons.
La nueva columna Tipo de VDI indica si el dispositivo es una Imagen base, No persistente o Persistente. -
Cada endpoint de agente está ahora vinculado desde la página Gestión de agentes a la página Dispositivos. Haga clic en el nombre del punto de conexión del agente para abrir una nueva ventana con el dispositivo en la vista Dispositivos.
-
Seleccione Instancias vinculadas para consultar todas las instancias creadas a partir de esta imagen base.
Las instancias no persistentes aparecerán identificadas como No persistente en la vista Dispositivos.
Paso 3: Reasignar una política con NP-VDI
Para reasignar una política a la imagen base directamente desde la interfaz de Ivanti Neurons, siga estos pasos:
-
Vaya a Agentes > Políticas del agente.
-
Seleccione la imagen base y, en el menú Acciones, seleccione Reasignar política.
-
Seleccione la política que desea reasignar y haga clic en Guardar.
De este modo, se reasigna la política. Una vez reasignada la política a la imagen base, todas las instancias de VDI no persistentes heredarán la política la próxima vez que se comuniquen con el servidor, lo que ocurre cada 200 minutos de forma predeterminada. -
Compruebe que las nuevas instancias heredan la política actualizada después de comunicarse con el servidor. Puede hacerlo desde la interfaz Agentes de Ivanti Neurons o Administración de agentes, o directamente desde la imagen no persistente mediante el comando "Stagentctl status".
No es posible reiniciar una instancia de NP-VDI. El reinicio restablecería el dispositivo a su estado inicial, lo que podría provocar que el usuario perdiera el trabajo realizado durante su sesión.
Además, las acciones disponibles para las instancias no persistentes en la vista Dispositivos no incluyen opciones de reinicio.
Comandos adicionales de STAgentCtle.exe
También puede utilizar los siguientes comandos:
-
Para quitar el sellado del agente base y permitir las actualizaciones, introduzca "Stagentctl.exe unseal".
-
Para que la línea de comandos espere hasta que finalice la actualización antes de devolver el control, introduzca "Stagentctl.exe update –wait".
El comando wait (esperar) puede generar problemas al actualizar el agente, ya que requiere que los ejecutables del agente estén en ejecución. Por este motivo, puede ser necesario reiniciar el dispositivo una vez completada la actualización. Para evitar este problema, Ivanti ofrece un script de PowerShell que permite ejecutar el comando de actualización de forma síncrona.
-
Para volver a sellar el agente base después de las actualizaciones, introduzca el comando "Stagentclt.exe seal".
Lista de etiquetas personalizadas
Una lista de etiquetas personalizadas es un conjunto de etiquetas definido por el usuario que puede asignarse a endpoints de Ivanti Neurons, incluidas las instancias de NP-VDI. Las etiquetas personalizadas permiten clasificar, organizar e identificar los dispositivos en función de requisitos empresariales, operativos o técnicos.
Por ejemplo, al utilizar "Sales-[MacAddress]", se genera una etiqueta única para cada dispositivo, ya que [MacAddress] se sustituye por la dirección MAC real del dispositivo. Esta funcionalidad resulta especialmente útil para generar etiquetas únicas para instancias de VDI no persistentes.
Utilice la siguiente sintaxis para hacer referencia a atributos del dispositivo y variables de entorno:
-
Para hacer referencia a la dirección MAC, utilice "[MacAddress]"
-
Para hacer referencia al nombre del host, utilice "[HostName]"
-
<name>Para hacer referencia a una variable de entorno, utilice "[env:]"
<name>donde corresponde al nombre de la variable de entorno y distingue entre mayúsculas y minúsculas.
Actualizar etiquetas
Las etiquetas asignadas durante el registro de la imagen base permanecen estáticas en todas las instancias asociadas. Si necesita actualizar las etiquetas, vuelva a registrar o sellar la imagen base. Como alternativa, puede utilizar la automatización para asignar etiquetas según los criterios actuales después de implementar la máquina virtual.
Apéndice
.SYNOPSIS
Actualiza un agente no persistente, espera a que finalice la actualización y, opcionalmente, vuelve a sellarlo.
.PARAMETER TimeoutSec
Tiempo de espera total en segundos.
.PARAMETER UpgradeCode
Código de actualización del agente que se va a actualizar.
.PARAMETER DoNotSeal
Especifica que el agente no se debe volver a sellar después de la actualización.
#>
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 "Se agotó el tiempo de espera mientras se esperaba a que todos los actualizadores terminaran."
}
function Get-AgentVersionFromManifest([string] $manifestPath, [string] $platformKey)
{
if (-not (Test-Path $manifestPath))
{
throw "No se pudo encontrar el manifiesto en '$manifestPath'."
}
[xml]$manifestXml = Get-Content $manifestPath
$agentFile = $manifestXml.manifest.files.file | Where-Object { $_.key -eq $platformKey }
if (-not ($agentFile))
{
throw "No se encontró una entrada de agente con la clave ='$platformKey' not found."
}
if (-not ($agentFile.version))
{
throw "No se pudo encontrar la versión del agente en el manifiesto."
}
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 "Installed agent not found."
}
if (-not ($agentObject.Version))
{
throw "No se encontró el agente instalado."
}
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 "Se agotó el tiempo de espera mientras se esperaba la actualización del agente."
}
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 "No se pudo realizar el check-in debido a un tiempo de espera demasiado corto."
}
& $agentCtlPath update --checkin --wait $timeoutSec
if (-not $?)
{
throw "Se produjo un error en la operación de check-in."
}
& $agentCtlPath update --all
if (-not $?)
{
throw "Se produjo un error en la operación de actualización."
}
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 "No se pudo realizar la actualización final debido a un tiempo de espera demasiado corto."
}
& $agentCtlPath update --all --wait $timeoutSec
if (-not $?)
{
throw "Se produjo un error en la operación de actualización final.."
}
}
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 "No se encontró el código de actualización '$upgradeCode'."
}
if ($productCode.Count -gt 1)
{
throw "Se encontraron varios productos con el mismo código de actualización '$upgradeCode'."
}
return [guid]::Parse($productCode)
}
function Get-AgentEnvironment([string] $installDirPath)
{
$configPath = Join-Path $installDirPath "AgentEnvironment.config"
if (-Not (Test-Path $configPath))
{
throw "No se encontró el archivo de configuración en $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 "No se encontró el GUID del producto."
}
return $productObject.InstallLocation
}
$timeoutDateTime = (Get-Date).AddSeconds($TimeoutSec)
Write-Host "Gathering information..."
try
{
$agentProductCode = Get-ProductCode -UpgradeCode $UpgradeCode
$installDirPath = Get-InstallLocation -ProductCode $agentProductCode
Write-Host " Install directory: $installDirPath"
$agentEnvironment = Get-AgentEnvironment -InstallDirPath $installDirPath
$dataDirPath = $agentEnvironment.agentEnvironment.agentDataDirectory
Write-Host " Data directory: $dataDirPath"
$regPath = Join-Path "HKLM:" $agentEnvironment.agentEnvironment.registryPath
Write-Host " Registry key: $regPath"
$platformKey = Get-ItemProperty -Path $regPath -Name "PlatformManifestKey" -ErrorAction Stop | Select-Object -ExpandProperty "PlatformManifestKey" -ErrorAction Stop
Write-Host " Platform key: $platformKey"
$agentCtlPath = Join-Path $installDirPath "STAgentCtl.exe"
$manifestPath = Join-Path $dataDirPath "manifest.xml"
}
catch
{
Write-Error "ERROR: $_"
exit -1
}
if ((Get-Date) -gt $timeoutDateTime)
{
Write-Error "ERROR: The timeout expired before the agent update could begin."
exit -1
}
Write-Host "Unsealing the agent..."
& $agentCtlPath unseal
if (-not $?)
{
Write-Error "ERROR: can't perform unseal operation."
exit -1
}
Write-Host "Updating the agent..."
$result = -1
try
{
Update-Agent -TimeoutDateTime $timeoutDateTime -ManifestPath $manifestPath -AgentUpgradeCode $UpgradeCode -AgentCtlPath $agentCtlPath -PlatformKey $platformKey
$result = 0
}
catch
{
Write-Error "ERROR: $_"
}
if ($DoNotSeal)
{
if ($result -eq 0)
{
Write-Host "The agent has been successfully updated."
}
else
{
Write-Error "ERROR: agent update failed."
}
exit $result
}
Write-Host "Sealing the agent..."
& $agentCtlPath seal
if (-not $?)
{
Write-Error "ERROR: can't seal the agent!"
exit -1
}
if ($result -eq 0)
{
Write-Host "The agent has been successfully updated and sealed."
}
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% Agent key restore started >> "%logfile%"
IF EXIST "%certFile%" (
certutil -f -p "%pw%" -privatekey -importPFX "Ivanti Cloud Agent Agent" "%certFile%" NoCert,NoExport >> "%logfile%" 2>&1
IF %ERRORLEVEL% NEQ 0 (
ECHO Failed to import agent key >> "%logfile%"
)
ECHO Removing agent key file >> "%logfile%"
del "%certFile%" >> "%logfile%" 2>&1
IF %ERRORLEVEL% NEQ 0 (
ECHO Failed to delete agent key file >> "%logfile%"
)
ECHO %date% %time% Agent key restore complete >> "%logfile%"
) ELSE (
ECHO %date% %time% Agent key restore failed: no agent key file found >> "%logfile%"
)
ECHO Removing script >> "%logfile%"
del "%scriptPath%" >> "%logfile%" 2>&1
“REM no se pueden ejecutar más comandos a partir de este punto porque el archivo de script se ha eliminado”