Windows 镜像定制非常常见,无论是个人还是组织,为了满足各种需求,都可能进行 Windows 镜像定制。常见的定制内容就是精简系统,如移除不必要的系统组件、模块、app;以及其他一些系统配置,如关闭一些遥测数据发送,保护用户隐私安全。这些定制内容的效果,主要体现在用户后期使用操作系统的过程中。那么在用户安装操作系统的过程中,能不能根据需求做一些定制化的操作呢?答案是肯定的。
默认的Windows安装程序要求用户在安装过程中选择安装语言、安装版本、安装磁盘、所在时区以及后续的用户名和密码等设置。以下为普通安装过程:
思考一下Windows镜像文件安装操作系统过程,可以分为两种方式。首先进入到winPE环境,使用dism应用映像文件或者运行Windows安装程序。另外一种方式是从可启动的安装媒介,比如刻录的U盘或者DVD来运行Windows安装程序,进行Windows 操作系统的安装。
通过镜像文件安装操作系统的两种方式最终都会落脚到 Windows 安装程序。只要我们能够接管这一安装程序,或者说我们自己来实现一个安装程序来安装 Windows,就能够满足上面的需求。
到这里,定制 windows 10 安装程序的想法就通顺了:启动盘开始引导,进入winpe,调用定制后的 windows 安装程序,通过安装程序来安装操作系统。所有与用户的交互以及系统的安装工作都由安装程序来实现。所以,简单来说,这里只需要处理好winpe调用安装程序的过程以及准备安装程序这两点基本就够了。
思路确定,开始动手!
准备WinPE首先通过 Windows ADK制作WinPE。
Windows 镜像文件中带有一个PE文件,但选择 Windows ADK来制作winpe有两点考虑:1. 镜像自带winpe体积比较大,ADK中winpe更加精简,体积小;2. 镜像自带winpe出现过如汉化不全的问题,这时候不太好找到对应的语言包,而ADK中包含比较全面的工具包,所以直接选用ADK来制作winpe。
在页面 Windows ADK页面下载 Windows ADK,每一个ADK都有对应的windows适用版本,我这里选择windows 10 1809 版本:
Windows ADK for Windows 10 版本 1809
适用于 ADK 版本 1809 的 Windows PE 加载项
两个exe文件下载完成后进行安装,初始界面如图,其余按照默认选项点击"下一步"进行安装就好了。
ADK 安装界面
电脑WindowsPE加载项 安装界面
安装完成后,会在开始菜单出现:
选择"部署和映像工具环境",弹出ADK console。
执行 copype amd64 E:\Win10PE 命令,x64版本winpe就被提取出来,在 E:\Win10PE\media\sources 目录下就会得到boot.wim文件。
修改WinPE挂载winpe在E:\Win10PE\media\sources目录下创建boot文件夹,然后通过命令 dism /mount-wim /wimfile:"E:\Win10PE\media\sources\boot.wim" 电脑 /index:1 /mountdir:"E:\Win10PE\media\sources\boot" 将boot.wim文件挂载到boot目录。此时的目录结构如下图
添加中文语言支持1通过 Dism /Get-Packages /Image:"E:\Win10PE\media\sources\boot"命令查看winpe中安装的包
WinPE中需要配置语言支持中文,否则在后面显示中文的时候会出现乱码问题。
执行以下命令添加中文支持
添加中文语言包dism /Add-Package /Image:E:\Win10PE\media\sources\boot /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\zh-cn\lp.cab" dism /Add-Package 电脑 /Image:E:\Win10PE\media\sources\boot /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\zh-cn\WinPE-HTA_zh-cn.cab" 添加中文字体包dism /Add-Package /Image:E:\Win10PE\media\sources\boot /PackagePath:"C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs\WinPE-FontSupport-ZH-CN.cab" 区域设置更改为使用中文dism /Set-AllIntl:zh-CN /Image:"E:\Win10PE\media\sources\boot"
安装完成后,查看winpe中安装的包,语言包已经安装成功。
修改WinPE启动后调用程序默认情况下,Winpeshl.exe 是 Windows PE 启动时运行的第一个进程。Winpeshl.exe 在System32下搜索名为 Winpeshl.ini 的文件。Winpeshl.ini 可以控制是否将自定义shell程序加载到 Windows PE而不是默认的“命令提示符”窗口。 如果该文件不存在,Winpeshl.exe 会启动一个执行 Startnet.cmd 脚本的 Cmd.exe 进程。 如果 Winpeshl.ini 存在并且包含要启动的应用,则会执行这些应用而不是 Cmd.exe2。
ADK中的boot.wim挂载后,在 E:\Win10PE\media\sources\boot\Windows\System32 目录下没有 Winpeshl.ini 文件,需要手动创建,注意编码格式为utf8。
Winpeshl.ini的用法可以参考官方文档:Winpeshl.ini 参考:启动 WinPE 时启动应用
因为我只需要加载一个应用,所以在Winpeshl.ini中仅设置[LaunchApp]这一个条目就够了。CustomSetup.exe是我写的安装程序。
Winpeshl.ini 文件内容:
[LaunchApp]AppPath = %SYSTEMDRIVE%\Program Files\Custom\CustomSetup.exe
开发 Windows 安装程序
Windows PE 包含非常多的功能支持(Windows PE 功能支持),安装程序的实现主要用到 "Windows 应用程序编程接口(API)" 和 "映像管理和维护(DISM)工具"。
这里的 Windows 安装程序主要适用于执行自定义安装,也就是干净安装。这个阶段包含两个最基本的操作,一个是配置磁盘(分区和格式化)。另外一个就是将 Windows 的映像复制到磁盘。此外,还可以添加接受License以及一些其他的配置,为用户提供更丰富的控制接口。
我将在安装程序中实现这两个最基本的操作。因为是在 Windows PE 环境下执行,所以采用基本的WIN32编程来实现,不依赖于任何现有的框架。简单添加几个基本页面,具体的代码就不贴了。主要实现两个基本功能:对硬盘驱动器进行分区和拷贝、应用系统镜像。
硬盘分区的实现:
微软提供了一个 CreatePartitions-UEFI.txt 脚本,它将磁盘分为系统分区(S)、MSR保留分区、Windows分区(W)和恢复分区(R)。为了简化实现,安装程序首先查询用户硬盘驱动器总大小,根据用户输入的C盘和D盘大小,以脚本文件中内容作为模板,生成需要执行的脚本。然后执行脚本,实现硬盘分区和格式化。
镜像拷贝和应用的实现:
镜像的拷贝和应用主要利用dism工具实现,同时,还需要设置 Windows 的引导程序以及隐藏恢复分区。
应用映像(install.wim中内容)到 Windows 分区dism /Apply-Image /ImageFile:"$drive\sources\install.wim" /Index:1 /ApplyDir:"$windowsDrive"使用bcdboot工具配置系统分区$windowsDrive\Windows\System32\bcdboot $windowsDrive\Windows /s $systemDrive将 Windows 恢复环境(winre)工具复制到恢复工具分区中mkdir $recoveryDrive\Recovery\WindowsRExcopy /h $windowsDrive\Windows\System32\Recovery\Winre.wim $recoveryDrive\Recovery\WindowsRE\注册恢复工具的位置,然后使用 Diskpart 隐藏恢复分区$windowsDrive\Windows\System32\Reagentc /Setreimage /Path $recoveryDrive\Recovery\WindowsRE /Target $windowsDrive\Windows$windowsDrive\Windows\System32\Reagentc /Info /Target $windowsDrive\Windows
这里有一点要注意:因为在winpe环境中,除了‘x’是留给winpe虚拟盘的盘符,其他盘符是临时分配的。所以,以上这些命令中的drive信息都是通过枚举所有盘符获得对应的分区。
将两部分内容封装到安装程序中,将开发好的CustomSetup.exe按照Winpeshl.ini文件中的内容到放到指定位置。
至此,Windows 安装工具开发基本完成。通过dism /unmount-image /mountdir:"E:\Win10PE\media\sources\boot" /commit命令,卸载winpe并提交修改。
利用镜像编辑工具,将ISO文件中sources目录下的的boot.wim替换为制作好的boot.wim文件。同时,将ISO中与安装无关的文件删除。如下是原始ISO文件中的目录结构和定制安装程序之后ISO的目录结构:
原ISO的文件布局
新ISO的文件布局
定制镜像的安装效果在hyper-v中安装新的镜像文件,系统引导进入winpe并调用前面开发的 Windows 安装程序,以下为安装过程截图。
首页模拟了windows 10 原生的安装程序,添加了两个logo。
要求用户接受安装许可条款
查询磁盘总大小,在用户输入具体分配磁盘大小后,对磁盘进行分区操作。
添加了一页扩展页,这一页只是个示例,没有实际操作。
下一步就是将镜像内容复制到磁盘。
以上的操作完成以后,系统自动进行重启,然后系统将自动引导进入OOBE过程。
至此,定制 Windows 10 安装程序基本完成。当然,这里的重写安装程序只是一个探索性开始,还有很多的细节需要完善、很多的功能需要支持,如:对于硬件的兼容性检查,评估新的系统是否适用于当前的硬件,以保证老旧的硬件能够安装新版的操作系统,而不是直接就去安装;对于磁盘操作更加灵活,支持更多分区;增加网络安装的支持;增加无人值守安装的支持等等。
本文最想要说明的一个想法是在系统重新引导进入 Windows 之前的安装阶段,我们可以做非常多的事情,在这个过程中可以添加非常多的页面操作,比如说前面提到的安装第三方软件,让不同安全等级的用户选择对应的加密模块;在系统安装过程中向用户提供杀毒软件的选择;向用户提供合规软件版本列表供用户选择...更多的内容大家可以自己想象。
参考Add languages to images: https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/winpe-add-packages--optional-components-reference?view=windows-11#add-languages-to-images-that-include-optional-componentsWinPE: Create Apps: https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/winpe-create-apps?view=windows-11电脑