上一篇
用 Cloudbase-Init + sysprep 做模板,重而且容易踩坑。这篇换个思路:一个 PowerShell 脚本注册成开机计划任务,启动时自己读 PVE 的 ConfigDrive(卷标 config-2)应用配置 —— 不依赖 Cloudbase-Init,不 sysprep,不禁用 Administrator。
前置:PVE 必须把 OS Type 设为 Windows
这一步是关键。PVE 8+ 在 OS Type 为 Linux 时,会把 cipassword 用 Linux crypt 哈希存储;只有 OS Type 选 Windows(win10 / win11 等)时才会以明文写入 ConfigDrive,Windows 才能拿来设密码。
PVE Web UI:VM → Options → OS Type → Microsoft Windows,选对应版本。
或者命令行:
1qm set <vmid> --ostype win11
然后给 VM 挂上 Cloud-Init 盘并设密码:
1qm set <vmid> --ide2 local-lvm:cloudinit
2qm set <vmid> --cipassword '你的密码'
3qm cloudinit update <vmid>
Web UI 改完 Cloud-Init 任何字段后记得点 Regenerate Image。
一键安装
VM 内以管理员身份打开 PowerShell:
1$ErrorActionPreference='Stop'; Set-ExecutionPolicy Bypass -Scope Process -Force; [Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12; $p="$env:TEMP\my-cloudinit.ps1"; iwr 'https://x.csz.net/scripts/my-cloudinit.ps1' -OutFile $p -UseBasicParsing; & $p -Mode Install
执行后会:
- 把脚本拷到
C:\Program Files\my-cloudinit\my-cloudinit.ps1 - 注册名为
MyCloudInit的开机计划任务(SYSTEM 权限,开机立即跑,最多等 60s 等 ConfigDrive 出现) - 询问是否立即手动跑一次
这个脚本不能用
iex (irm ...)—— Install 模式需要把脚本文件复制到安装目录,所以必须先落盘再执行。用
iwr而不是irm:Invoke-RestMethod -OutFile在 PowerShell 5.1 上对非 JSON/XML 响应有时不写盘,Invoke-WebRequest -OutFile更可靠。强制 TLS 1.2:旧版 Windows Server 默认还是 TLS 1.0/1.1,握 GitHub Pages / Cloudflare 的手会失败;
$ErrorActionPreference='Stop'让下载失败时立刻终止,避免无文件就去执行。
工作流程
每次开机,计划任务会:
- 等卷标
config-2的盘出现 - 读
openstack/latest/meta_data.json/user_data/network_data.json - 按
instance-id(uuid)去重,已执行过则跳过 - 设 Administrator 明文密码、改主机名、配网络、NTFS 分区扩容、跑
runcmd
也就是说,把这台 VM 转模板克隆,每个克隆出来的新 VM 第一次开机会自动应用 PVE Cloud-Init 注入的配置;同一台机器再开机不会重复执行(除非克隆出新的 instance-id)。
调试
如果第一次没生效,VM 内跑:
1& "C:\Program Files\my-cloudinit\my-cloudinit.ps1" -Mode Debug
会生成一份完整诊断报告 C:\ProgramData\my-cloudinit\debug-report.txt,包含卷列表、网卡、ConfigDrive 文件清单、meta_data.json / user_data / 网络配置内容、演练(dry-run)执行结果等。
日志在 C:\ProgramData\my-cloudinit\my-cloudinit.log。
密码不生效的几种应急办法
如果 PVE 端忘了改 OS Type,cipassword 已经是 Linux crypt 哈希,脚本会拒绝设置,并提示几种补救方式:
- A:把 OS Type 改成 win11 后重新设 cipassword + Regenerate Image(推荐)
- B:在 ConfigDrive 盘根目录加文件
WINPASS(明文密码)—— 通过自定义 user-data 或 snippet 写入 - C:用
qm set <vmid> --cicustom user=local:snippets/win.yaml自己写明文 user-data - D:临时测试,VM 内执行
'你的密码' | Out-File C:\ProgramData\my-cloudinit\WINPASS -Encoding ASCII -NoNewline,下次开机优先级最高
脚本源码
注意脚本含中文输出,文件保留了 UTF-8 BOM 以兼容 PowerShell 5.1。