- PowerShell 100%
| archive | ||
| ArfNet-ApplyBGInfo.ps1 | ||
| ArfNet-Interactive.ps1 | ||
| ArfNet-Provision-Run.reg | ||
| ArfNet-Provision-System-Task.xml | ||
| ArfNet-Provision-System.ps1 | ||
| ArfNet-Provision-Task.xml | ||
| ArfNet-Provision.ps1 | ||
| ArfNet-UserLaunch.ps1 | ||
| README.md | ||
| Register-ArfNetProvisionTask.ps1 | ||
ArfNet-PVE — Windows VM provisioning
PowerShell tooling for Windows 10/11 VMs on Proxmox with a config-2 drive.
On Windows 10 22H2, even Administrator accounts (without a true elevated SYSTEM token) cannot reliably Set-Date, write RealTimeIsUniversal under HKLM, or change IP/hostname. Those operations run as SYSTEM at startup. BGInfo and desktop apps run as the logged-on user (roadmaster).
Two scheduled tasks
| Task | When | Runs as | Script | Does |
|---|---|---|---|---|
ArfNet-Provision-System |
Startup (+30s) | SYSTEM | ArfNet-Provision-System.ps1 |
Config-drive hostname/IP, fixed time, UTC registry, disable NTP |
ArfNet-Provision |
User logon (+10s) | .\roadmaster | ArfNet-Provision.ps1 |
Triggers system task, BGInfo wallpaper, user launch apps |
| Log | Written by |
|---|---|
C:\Scripts\Provision-System.log |
SYSTEM task (time, identity) |
C:\Scripts\Provision.log |
User logon task |
C:\Scripts\BGInfo.log |
ArfNet-ApplyBGInfo.ps1 |
C:\Scripts\UserLaunch.log |
ArfNet-UserLaunch.ps1 |
Legacy scripts are in archive/. Do not deploy them with the current scripts.
Flow
flowchart TD
Boot([Boot]) --> Sys[ArfNet-Provision-System / SYSTEM]
Sys --> Id{Config drive differs?}
Id -->|IP/name| Apply[Set IP / rename + reboot]
Apply --> Boot
Id -->|No| Time[Set time + UTC registry]
Logon([User logon roadmaster]) --> User[ArfNet-Provision.ps1]
User --> Trigger[Start system task]
Trigger --> BGInfo[BGInfo wallpaper]
BGInfo --> Apps[User launch apps]
Repository layout
| Path | Description |
|---|---|
ArfNet-Provision-System.ps1 |
Privileged: identity, time (SYSTEM only) |
ArfNet-Provision.ps1 |
User session: BGInfo + user launch |
ArfNet-UserLaunch.ps1 |
Per-app delays + two executables |
ArfNet-ApplyBGInfo.ps1 |
BGInfo in user HKCU + wallpaper refresh |
ArfNet-Interactive.ps1 |
Session helpers |
Register-ArfNetProvisionTask.ps1 |
Registers both tasks |
ArfNet-Provision-System-Task.xml |
SYSTEM startup task XML |
ArfNet-Provision-Task.xml |
User logon task XML |
archive/ |
Superseded scripts |
VM install
-
Copy to
C:\Scripts\:ArfNet-Provision-System.ps1 ArfNet-Provision.ps1 ArfNet-UserLaunch.ps1 ArfNet-ApplyBGInfo.ps1 ArfNet-Interactive.ps1 Register-ArfNetProvisionTask.ps1 ArfNet-Provision-System-Task.xml ArfNet-Provision-Task.xml -
Edit settings in
ArfNet-Provision-System.ps1(time, NIC) andArfNet-UserLaunch.ps1(apps). Set.\roadmasterin XML / register script if needed. -
Register tasks (elevated PowerShell):
cd C:\Scripts .\Register-ArfNetProvisionTask.ps1 -LogonUser ".\roadmaster" -
Install BGInfo at
C:\Program Files\BGInfo\withDefault.bgi(wallpaper enabled in the.bgi).
Configuration
ArfNet-Provision-System.ps1 (SYSTEM)
| Setting | Default | Purpose |
|---|---|---|
$TargetTime |
2025-08-29 08:00:00 |
Fixed clock |
$InterfaceAlias |
Ethernet |
NIC name |
$IpPrefixLength |
16 |
Prefix for 172.16.x.x |
ArfNet-Provision.ps1 (user logon)
| Setting | Default | Purpose |
|---|---|---|
$LogonUser |
.\roadmaster |
Must match user task principal |
$SystemTaskName |
ArfNet-Provision-System |
Started at logon as a fallback |
ArfNet-UserLaunch.ps1
Per-program DelaySeconds, Path, Arguments, WorkingDirectory. Set $LogonUser = ".\roadmaster".
Task Scheduler
Register both tasks (recommended)
Imports the bundled XML files via schtasks /Create /XML (same as manual Task Scheduler import):
cd C:\Scripts
.\Register-ArfNetProvisionTask.ps1 -LogonUser ".\roadmaster"
XML files must sit next to the register script or under C:\Scripts\.
Or import XML manually / with schtasks
schtasks /Create /TN "ArfNet-Provision-System" /XML "C:\Scripts\ArfNet-Provision-System-Task.xml" /F
schtasks /Create /TN "ArfNet-Provision" /XML "C:\Scripts\ArfNet-Provision-Task.xml" /F
Edit <UserId>.\roadmaster</UserId> in the user XML before manual import, or pass -LogonUser to the register script (it patches the XML for you).
To replace existing tasks:
schtasks /Delete /TN "ArfNet-Provision-System" /F
schtasks /Delete /TN "ArfNet-Provision" /F
.\Register-ArfNetProvisionTask.ps1 -LogonUser ".\roadmaster"
The register script uses schtasks /Create /XML only. It does not use Register-ScheduledTask / New-ScheduledTask* (those often fail on Windows 10 22H2).
Verify
Get-ScheduledTask ArfNet-Provision-System, ArfNet-Provision | Format-Table TaskName, State
(Get-ScheduledTask ArfNet-Provision-System).Principal.UserId # NT AUTHORITY\SYSTEM
(Get-ScheduledTask ArfNet-Provision).Principal.UserId # .\roadmaster
Start-ScheduledTask -TaskName ArfNet-Provision-System
Start-ScheduledTask -TaskName ArfNet-Provision
Get-Content C:\Scripts\Provision-System.log -Tail 10
Get-Content C:\Scripts\Provision.log -Tail 10
Manual testing
# Privileged (run elevated — or use the SYSTEM task)
Start-ScheduledTask -TaskName ArfNet-Provision-System
# User desktop (logged in as roadmaster)
powershell -ExecutionPolicy Bypass -File C:\Scripts\ArfNet-Provision.ps1
Do not expect Set-Date to work in a normal roadmaster PowerShell window on Windows 10 without SYSTEM — that is expected.
Troubleshooting
| Symptom | Check |
|---|---|
| Time / IP / hostname not applied | Provision-System.log, task principal is NT AUTHORITY\SYSTEM, run Start-ScheduledTask ArfNet-Provision-System |
| BGInfo log OK, no wallpaper | User task principal is .\roadmaster (not HOSTNAME$); Default.bgi has wallpaper enabled; BGInfo.log |
| Apps not visible | Same as BGInfo — must run as desktop user, not SYSTEM |
| Register script fails | Use the XML files directly (schtasks commands above) or Task Scheduler → Import Task |
runner=WORKGROUP\HOSTNAME$ in Provision.log |
Re-import user XML / register with -LogonUser ".\roadmaster" |
Notes
- Windows 10 22H2: UAC splits “Administrator” from true machine privileges; use the SYSTEM task for time and network identity.
- After rename:
RunOncerunsArfNet-Provision-System.ps1again after reboot. - Settings: keep
$TargetTime/ NIC values inArfNet-Provision-System.ps1; app paths inArfNet-UserLaunch.ps1;$LogonUserinArfNet-Provision.ps1, user XML, and register script should match. - Config drive: volume
config-2or first CD-ROM; scans\openstack\**forhostname:andaddress 172.16.x.x.