我在之前的一篇 聊聊VDI虚拟桌面的SID问题-前传(上) 简单介绍了Sysprep,作为这一篇的准备和铺垫。这一篇应该就看看VDI架构中底层虚拟化平台如何进行或增强这个自定义过程了。虽然当年领导者象限里的三家虚拟化平台(vSphere、Hyper-V、XenServer)我都还算熟悉,但针对Windows的自定义过程,一个使用自家比较完整的体系(System Center)不是一两句话的事情,一个现在逐渐式微……我还是以vSphere为例聊聊吧。
vSphere的自定义规范化过程
Sysprep实际上提供了面向虚拟机环境的命令行参数 /mode:vm
。但实际上我很少看到这个参数的使用。也可能Hyper-V和vSphere的实现会有所差异,在经常使用的实际上是另一种方式:通过Virtual Center创建自定义规范。
使用VC来创建客户虚拟机自定义规范的前提是,必须在虚拟机或模板上安装好最新的VMware Tools;客户操作系统必须安装在连接于虚拟机的SCSI节点0:0上的虚拟磁盘。详见:客户机操作系统自定义要求
确认满足要求之后,就可以在VC中创建Windows的自定义规范。以下是VDI场景中适合的步骤:
-
选择菜单 > 策略和配置文件,然后在“策略和配置文件”下单击虚拟机自定义规范。
-
单击创建新规范图标。此时将打开 新建虚拟机客户机自定义规范向导。
-
在名称和目标操作系统页面上,输入自定义规范的名称和描述,然后选择 Windows 作为目标客户机操作系统。
-
选择生成新的安全身份 (SID) 选项,然后单击下一步。如果还不确认是否要勾选这个选项,请参考之前的文章。
-
在设置注册信息页面上,输入虚拟机所有者的名称和组织,然后单击下一步。
-
在计算机名称页面上,选择使用虚拟机名称。在VDI架构中,桌面管理角色会通过VC来创建大量的Windows虚拟机,虚拟机名称将传递给vSphere并最终作为Windows虚拟机客户系统的计算机名。
-
在 Windows 许可证页面上,提供 Windows 操作系统的许可信息,然后单击下一步。
选项 操作 对于非服务器操作系统 键入新客户机操作系统的 Windows 产品密钥。 对于服务器操作系统 a. 键入新客户机操作系统的 Windows 产品密钥。<br>b. 选择包括服务器许可证信息。<br>c. 选择每个客户或每台服务器。<br>d. 如果选择每台服务器,请输入服务器接受的最大同时连接数。 -
在设置管理员密码页面上,配置虚拟机的管理员密码,然后单击下一步。
-
在时区页面上,选择虚拟机的时区,然后单击下一步。
-
(可选) 在运行一次页面上,指定用户首次登录到客户机操作系统时运行的命令,然后单击下一步。有关 RunOnce命令的信息,请参见 Microsoft Sysprep 文档。
-
在“网络”页面上,选择使用标准网络设置,以便 vCenter Server 使用默认设置在 DHCP 服务器中配置所有网络接口。单击下一步。
如果Vista之后的虚拟机使用了自定义sysprep应答文件,则需要参考 KB1029174
-
在设置工作组或域页面上,选择虚拟机加入Windows 服务器域,然后单击下一步。
-
在“即将完成”页面上,检查详细信息并单击完成以保存所做更改。
除了向导生成的标准自定义规范,还可以在向导中配置自定义Sysprep应答文件。只需要在向导开始时选择使用自定义 Sysprep 应答文件,就可以导入或者创建Sysprep应答文件。再次提醒,自定义应答文件时请参考 KB1029174。
所创建的自定义规范会在自定义规范管理器中列出,可使用该规范自定义虚拟机客户机操作系统。对于Horizon来说,可在创建桌面池向导里看到并选择VC中已创建的自定义规范。
在VC自定义过程的背后
由于之前出现了好几次自定义过程失败,我一直很好奇通过VC自定义虚拟机Windows的时候发生了什么。但直到目前我还没有找到确切的材料,只能靠猜了。
实际上,Sysprep提供的开发指南,以便软件或硬件无法通过sysprep完成通用化时自行解决问题。如果对这些扩展开发有兴趣,可参考:https://v.gd/hY6uqO
我猜VC创建的自定义流程会配合虚拟机客户系统中的VMware Tools参与很多底层的工作。这些工作包括但不限于处理虚拟硬件的驱动等等。事实上当使用VC的自定义规范对虚拟机自定义时,VC会在系统盘创建一个sysprep的目录,其中会有自己工具程序guestcustutil.exe,也会放置sysprep.xml应答文件。以下是一个范例:
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="generalize">
<component name="Microsoft-Windows-PnpSysprep" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<PersistAllDeviceInstalls>true</PersistAllDeviceInstalls>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<OOBE>
<SkipMachineOOBE>true</SkipMachineOOBE>
<HideEULAPage>true</HideEULAPage>
<SkipUserOOBE>true</SkipUserOOBE>
<ProtectYourPC>1</ProtectYourPC>
</OOBE>
<TimeZone>China Standard Time</TimeZone>
<UserAccounts>
<AdministratorPassword>
<EncryptedValue>************</EncryptedValue>
<PlainText>true</PlainText>
</AdministratorPassword>
</UserAccounts>
</component>
</settings>
<settings pass="specialize">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RegisteredOwner>modoo.top</RegisteredOwner>
<RegisteredOrganization>Tech.Unit</RegisteredOrganization>
<ComputerName>******</ComputerName>
</component>
<component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Identification>
<JoinDomain>modoo.top.local</JoinDomain>
<Credentials>
<Username>DomainJoinUser</Username>
<EncryptedPassword>************</EncryptedPassword>
<Domain>modoo.top.local</Domain>
</Credentials>
</Identification>
</component>
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Path>C:\sysprep\guestcustutil.exe restoreMountedDevices</Path>
<Order>1</Order>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Path>C:\sysprep\guestcustutil.exe flagComplete</Path>
<Order>2</Order>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Path>C:\sysprep\guestcustutil.exe deleteContainingFolder</Path>
<Order>3</Order>
</RunSynchronousCommand>
</RunSynchronous>
</component>
</settings>
</unattend>
在与 /generalize 选项一起运行 Sysprep 命令时,可以通过应答文件保留设备驱动程序:指定 XML应答文件 Microsoft-Windows-PnPSysprep 组件中PersistAllDeviceInstalls
的设置。 在 专门化 过程中,即插即用扫描计算机中的设备,然后为检测到的设备安装设备驱动程序。 默认情况下,通用化系统时,计算机会从系统中删除这些设备驱动程序。如果在应答文件中将 Microsoft-Windows-PnPSysprep 组件PersistAllDeviceInstalls
设置为 true, 则 Sysprep 不会删除检测到的设备驱动程序。我猜这样操作对于虚拟硬件全部相同的虚拟机来说,是可以加速识别和安装驱动的。
SkipMachineOOBE
、HideEULAPage
、SkipUserOOBE
、ProtectYourPC
的设置可以跳过用户交互。应答文件也如前文所述包含了时区、计算机名、加域以及使用的对应用户凭据等信息。最后,可以看到在用户第一次登录时,使用SynchronousCommand组件,按顺序执行了前面提到的guestcustutil.exe程序完成加载设备、设置标志及清理。
至此,我们对Windows系统的Sysprep和VC集成之后进行的自定义过程大致有了了解,可以继续尝试诊断解决问题了。
结束之前附送Linux虚拟机自定义规范介绍:创建 Linux 的自定义规范 ,和Windows不同,Linux客户系统中需要安装Perl语言来支持自定义过程。