非持久虛擬裝置基礎架構 (NP-VDI)
NP-VDI 讓您的 IT 團隊能夠快速佈建虛擬桌面與實體裝置,所有這些都來自單一的統一平台。 內建的自動化管理可節省時間、減少手動開銷,並獲得雲端環境中的全面端點控制。
功能工作流程
基於基本影像的代理程式部署:
-
代理程式已於乾淨的 VM 上安裝 (未註冊)。
-
代理程式隨即使用提供的命令列工具手動註冊為「基本映像」。
密封基礎映像:
-
一旦基本映像代理程式已註冊且組態已驗證,VM 透過命令列「密封」。
魚叉式網路釣魚執行個體:
-
新的 NP-VDI 執行個體可從基本映像中旋轉,通常為每個工作階段產生新的 MAC 位址。
-
Ivanti Neurons 會偵測並追蹤這些項目,使其成為在基本映像下管理的唯一短期端點。
原則管理:
-
可在基本影像層級進行原則變更。 所有放棄的執行個體會在下次簽入時繼承最新的套用原則。
步驟 1: 準備基本影像
若要準備基本影像,請依照以下步驟進行:
- 導覽至代理程式 > 代理程式部署 > 手動安裝。
- 在手動安裝標籤上,選擇代理程式原則和註冊金鑰。
- 選取 Windows。 接著,選擇安裝模式並按一下下載。
將下載代理程式安裝程式。此動作會下載兩個檔案。 儲存檔案名稱為 "IvantiCloudAgent.exe.options" 的安裝程式。 此檔案將用於安裝。
- 安裝下載的 NP-VDI 代理程式。
若要安裝代理程式:- 在安裝之前重新命名相關的 IvantiCloudAgent.exe.options 檔案。
- 執行安裝程式。 出現啟用金鑰或 Cookie 選項時,按一下取消。
這將在端點上安裝代理程式,而不向租用戶註冊。
- 將代理程式註冊為基本影像。 若要註冊為基本映像,請以管理員身分從代理程式安裝位置執行下列命令:
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" 或「自訂」。 這將用作識別執行個體的唯一旗標。
如果使用「自訂」,可以指定包含逗號分隔的自訂標記清單的 tagList 選項來識別該代理程式。 如需自訂標籤的詳細資訊,請參閱自訂標籤清單和更新標籤區段。
可以在相關的 .options 檔案中找到 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使用名稱為「Win11」的基礎映像的範例租用戶註冊裝置所用的命令列將如下所示:
STAgentCtl.exe register --asBaseImage Win11 --instanceIdType MacAddress --enrollmentkey “11111111-1111-1111-1111-4gc02d5b0f0d_9aI7SOQNybweiM2QKI7kcqIG8ufUFU21AvZwJwAEx6C-SAO5UGK62YkEgm89kvC2m-xwLesZA4t1_TBtEjIQMVaBU0KsVe-V60ZLBwWu83YREcUp3diAFvHjBvLtkxT3" --baseurl https://agentreg.ivanticloud.com
- 若要更新基本影像:
- 從 Ivanti 社群入口網站下載 PowerShell 指令碼: Ivanti-Neurons - 非持久 VDI - 代理程式指令碼。
在執行 PowerShell 指令碼之前,請檢查管理員是否具有在基本映像上執行此動作的相關權限,因為端點上的執行原則可能會封鎖此權限:
若要檢查,請使用「Get-ExecutionPolicy」命令。
若要變更,請使用「Set-ExecutionPolicy RemoteSigned」命令。
- 如果執行指令碼時沒有任何參數,則指令碼將嘗試下列動作:
- 解除代理程式密封。
- 執行代理程式和引擎的更新。
- 再次密封代理程式。
- 如果代理程式已解除密封,更新後應保持未密封狀態。 傳遞 "DoNotSeal" 參數以執行所有相同的步驟,封裝映像除外。
- 更新的預設逾時為 300 秒。 您可以通過傳遞「-TimeoutSec」引數來變更時間。
如需其他參考,可以在附錄區段下存取指令碼的副本。
- 若要準備基本影像:
- 執行 "STAgentCtl.exe prepareImage" 命令,讓密封、非持續的基本影像準備好供 NP-VDI 使用。
此命令為強制性,會停止所有服務並刪除與基礎映像的實際代理程式 ID 相關的任何資料。 非持續執行個體啟動時,服務會重新啟動。代理程式 ID 將隨每個非持久執行個體從基礎映像中旋轉而變更。
- 使用以下命令手動密封基礎映像 (在升級指令碼之外):
- 若要手動將基本影像密封,請輸入「STAgentCtl.exe seal」。
使用 "unseal" 命令將映像解開密封。 在系統重新啟動或使用 "Seal" 命令之前,此動作會保持作用中狀態。
- 若要手動將基本影像密封,請輸入「STAgentCtl.exe seal」。
- 執行 "STAgentCtl.exe prepareImage" 命令,讓密封、非持續的基本影像準備好供 NP-VDI 使用。
- (選用) 準備影像以搭配 "sysprep" 使用。
如果非持續桌面準備包含 sysprep 階段,它將從憑證存放區移除代理程式憑證的私密金鑰。 若要解決此問題,請依照以下步驟進行:管理員必須提供他們自己的憑證匯出密碼;否則此程序將失敗。
- 使用 certutil -store “Ivanti Cloud Agent Agent” 命令找到憑證序列號。
這會列出代理程式憑證儲存區中的憑證。 - 在步驟 7 中執行指令「stagentctl prepareImage」,您可以使用下列命令匯出代理程式憑證:
certutil -exportPFX -privatekey -p "%pfxpass%" “Ivanti Cloud Agent Agent” %serialnumber% "%ProgramFiles%\Ivanti\Ivanti Cloud Agent\agent.pfx" NoChain,NoRoot
在上述命令中:
%pfxpass% 是由管理員提供的密碼。
%serialnumber% 是代理程式憑證的序號。
- 從此處 Ivanti 社群網站下載可用的 SetupComplete.cmd 指令碼: 從匯出的 .pfx 檔案指令碼還原私密金鑰。
- 編輯 SetupComplete.cmd 指令碼,並更新密碼以符合匯出步驟 2 中所用憑證所需的密碼。
- 將指令碼儲存在金色影像上的 %WINDIR%\Setup\Scripts\SetupComplete.cmd。
一旦 Windows 安裝完成 (在 sysprep 後首次啟動裝置時執行),指令碼將自動執行。這將從匯出的 .pfx 檔案還原私密金鑰,然後同時刪除 .pfx 檔案和指令碼本身,使得密碼不會外洩到非持續性執行個體中。
具有主旨 OU「ST 代理程式」的憑證 (例如 "Subject: OU=ST Agent, CN=011472EFB12BABF06122F2903BBE12AC4E32EBFE5082”) 應使用該項目的對應序號匯出。
- 使用 certutil -store “Ivanti Cloud Agent Agent” 命令找到憑證序列號。
步驟 2: 建立並測試 NP-VDI 執行個體
若要從基礎映像旋轉新執行個體,請依照以下步驟進行:
-
確保為每個新執行個體指派新的 MAC 位址 (以確保 instanceIdType MacAddress 選項有效)。
或者,確保使用不同的主機名稱或標記。 -
啟動虛擬電腦執行個體,並確認該執行個體在 Neurons UI 中顯示為唯一的 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 指令碼,允許執行同步更新命令。
-
若要關閉基本代理程式以進行更新,請輸入「Stagentclt.exe seal」命令。
自訂標記清單
自訂標記清單是使用者定義的標記集合,可以指派給 Ivanti Neurons 中的端點,包括 NP-VDI 執行個體。 自訂標記有助於根據業務、營運或技術需求對裝置進行分類、組織和識別。
例如,使用「銷售-[MacAddress]標記,透過將裝置MacAddress」取代為裝置的實際 MAC 位址,為每個裝置產生唯一的標籤。 此功能對於為非持續性 VDI 執行個體產生唯一標記特別有用。
使用下列語法參考裝置屬性和環境變數:
-
若要參考 MAC 位址,請使用「[MacAddress]」
-
若要參照主機名稱,請使用「[HostName]」
-
若要參照環境變數,請使用 "[env:<name>]"
<name> 是環境變數區分大小寫的名稱。
更新標記
基本影像註冊期間指派的標籤會保持靜態狀態,以用於所有相關執行個體。 如果您需要更新標記,請重新註冊/密封基本影像,或在 VM 部署之後依據目前標準指派標記。
附錄
.SYNOPSIS
更新非持續性代理程式,等待更新完成,然後選擇性密封代理程式。
.PARAMETER TimeoutSec
總逾時秒數。
.PARAMETER UpgradeCode
正在更新的代理程式的升級代碼。
.PARAMETER DoNotSeal
此參數指定更新後不密封代理程式。
#>
參數
(
[int] $TimeoutSec = 300,
[guid] $UpgradeCode = "{0C5D7E9C-0424-462D-A570-2A7469EE3739}", # Neurons Agent
[switch] $DoNotSeal
)
函數 Check-UpdatersComplete
{
$updaters = Get-Process -Name "STAgentUpdater" -ErrorAction SilentlyContinue
return ($updaters.Count -eq 0)
}
函數 Wait-UpdatersComplete([DateTime] $timeoutDateTime, [int] $checkIntervalSec)
{
while ((Get-Date) -lt $timeoutDateTime)
{
if (Check-UpdatersComplete)
{
返回
}
Start-Sleep -Seconds $checkIntervalSec
}
引發「等待所有更新程式完成逾時」。
}
函數 Get-AgentVersionFromManifest([string] $manifestPath, [string] $platformKey)
{
if (-not (Test-Path $manifestPath))
{
引發「在 '$manifestPath' 找不到資訊清單」。
}
[xml]$manifestXml = Get-Content $manifestPath
$agentFile = $manifestXml.manifest.files.file | Where-Object { $_.key -eq $platformKey }
if (-not ($agentFile))
{
引發「未找到 key='$platformKey' 的代理程式項目」。
}
if (-not ($agentFile.version))
{
引發「無法找到資訊清單中的代理程式版本」。
}
return [version]::Parse($agentFile.version)
}
函數 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))
{
引發「找不到安裝的代理程式」。
}
if (-not ($agentObject.Version))
{
引發「找不到安裝的代理程式版本」。
}
return [version]::Parse($agentObject.Version)
}
函數 Check-AgentUpToDate([string] $manifestPath, [guid] $agentUpgradeCode, [string] $platformKey)
{
$manifestVersion = Get-AgentVersionFromManifest -ManifestPath $manifestPath -PlatformKey $platformKey
$currentVersion = Get-CurrentAgentVersion -AgentUpgradeCode $agentUpgradeCode
return ($currentVersion -ge $manifestVersion)
}
函數 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)
{
返回
}
Start-Sleep -Seconds $checkIntervalSec
}
引發「等待代理程式更新逾時」。
}
函數 Update-Agent([DateTime] $timeoutDateTime, [string] $manifestPath, [guid] $agentUpgradeCode, [string] $agentCtlPath, [string] $platformKey)
{
$timeoutSec = [math]::Ceiling(($timeoutDateTime - (Get-Date)).TotalSeconds)
if ($timeoutSec -le 0)
{
引發「由於短暫逾時,無法執行簽入」。
}
& $agentCtlPath update --checkin --wait $timeoutSec
if (-not $?)
{
引發「簽入操作失敗」。
}
& $agentCtlPath update --all
if (-not $?)
{
引發「更新操作失敗」。
}
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)
{
引發「由於短暫逾時,無法執行最終更新」。
}
& $agentCtlPath update --all --wait $timeoutSec
if (-not $?)
{
引發「最終更新操作失敗」。
}
}
函數 Get-ProductCode([guid] $upgradeCode)
{
$upgradeCodeStr = $upgradeCode.ToString("B") # 格式化為 {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)
{
找不到「找不到升級代碼 '$upgradeCode'」。
}
if ($productCode.Count -gt 1)
{
引發「找到具有相同升級碼 '$upgradeCode' 的多個產品」。
}
return [guid]::Parse($productCode)
}
函數 Get-AgentEnvironment([string] $installDirPath)
{
$configPath = Join-Path $installDirPath "AgentEnvironment.config"
if (-Not (Test-Path $configPath))
{
引發「在 $configPath 找不到組態檔案」。
}
[xml]$agentEnvironment = Get-Content $configPath
return $agentEnvironment
}
函數 Get-InstallLocation([guid] $productCode)
{
$productObject = Get-WmiObject -Class Win32_Product | Where-Object { [guid]::Parse($_.IdentifyingNumber) -eq $productCode }
if ($null -eq $productObject)
{
引發「找不到產品 GUID」。
}
return $productObject.InstallLocation
}
$timeoutDateTime = (Get-Date).AddSeconds($TimeoutSec)
寫入主機「正在收集資訊...」
嘗試
{
$agentProductCode = Get-ProductCode -UpgradeCode $UpgradeCode
$installDirPath = Get-InstallLocation -ProductCode $agentProductCode
寫入主機「安裝目錄: $installDirPath」
$agentEnvironment = Get-AgentEnvironment -InstallDirPath $installDirPath
$dataDirPath = $agentEnvironment.agentEnvironment.agentDataDirectory
寫入主機「資料目錄: $dataDirPath」
$regPath = Join-Path "HKLM:" $agentEnvironment.agentEnvironment.registryPath
寫入主機「登錄金鑰: $regPath」
$platformKey = Get-ItemProperty -Path $regPath -Name "PlatformManifestKey" -ErrorAction Stop | Select-Object -ExpandProperty "PlatformManifestKey" -ErrorAction Stop
寫入主機「平台金鑰: $platformKey」
$agentCtlPath = Join-Path $installDirPath "STAgentCtl.exe"
$manifestPath = Join-Path $dataDirPath "manifest.xml"
}
捕獲
{
寫入錯誤「錯誤: $_」
exit -1
}
if ((Get-Date) -gt $timeoutDateTime)
{
寫入錯誤「錯誤: 代理程式更新開始前逾時。」
exit -1
}
寫入主機「正在解除代理程式密封...」
& $agentCtlPath unseal
if (-not $?)
{
寫入錯誤「錯誤: 無法執行取消密封操作」。
exit -1
}
寫入主機「正在更新代理程式...」
$result = -1
嘗試
{
Update-Agent -TimeoutDateTime $timeoutDateTime -ManifestPath $manifestPath -AgentUpgradeCode $UpgradeCode -AgentCtlPath $agentCtlPath -PlatformKey $platformKey
$result = 0
}
捕獲
{
寫入錯誤「錯誤: $_」
}
if ($DoNotSeal)
{
if ($result -eq 0)
{
寫入主機「代理程式已成功更新」。
}
else
{
寫入錯誤「錯誤: 代理程式更新失敗。」
}
exit $result
}
寫入主機「正在停止代理程式...」
& $agentCtlPath seal
if (-not $?)
{
寫入錯誤「錯誤: 無法密封代理程式!」
exit -1
}
if ($result -eq 0)
{
寫入主機「代理程式已成功更新並封裝」。
}
exit $result
(@ECHO 關閉
設定 pw=supersecret
set logfile=C:\ProgramData\Ivanti\Ivanti Cloud Agent\Logs\agentkeyrestore.log
set certFile=C:\Program Files\Ivanti\Ivanti Cloud Agent\agent.pfx
設定 scriptPath=%0%
ECHO %date% %time% 代理程式金鑰還原已開始 >> "%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 匯入代理程式金鑰失敗 >> "%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 無法從此點執行進一步的指令,因為已刪除指令碼檔案」