When preparing a Windows Server 2025 template for VMware vSphere or Aria Automation, you may encounter two separate problems after running Sysprep:
- The cloned virtual machine starts, but the desktop remains black and Windows Explorer does not load.
- The Administrator password selected during deployment is not applied by Cloudbase-Init.
This article explains the working solutions for both issues and shows how to integrate them into a reusable Windows Server template.
Problem 1: Black Screen and Explorer Crash After Sysprep
After deploying a clone from a sysprepped Windows Server 2025 template, Windows may start successfully, but the user sees a black screen instead of the desktop.
Windows Explorer may crash with an error similar to:
Faulting application name: Explorer.EXE
Exception code: 0xc0000409
In this case, some Windows Shell and XAML system packages are not registered correctly for the logged-in user after Sysprep. The affected components can be repaired by registering their AppX manifests again.
Create the Shell Repair Script
Create the following directory:
C:\ProgramData\ShellRepair
Create this PowerShell script:
C:\ProgramData\ShellRepair\Repair-Shell.ps1
Use the following content:
$ErrorActionPreference = "Stop"
$markerPath = "HKCU:\Software\Company\ShellRepair"
$logDirectory = "C:\ProgramData\ShellRepair\Logs"
$logFile = Join-Path $logDirectory "$env:USERNAME.log"
New-Item -Path $logDirectory -ItemType Directory -Force | Out-Null
function Write-Log {
param(
[Parameter(Mandatory)]
[string]$Message
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $logFile -Value "$timestamp $Message"
}
try {
$completed = Get-ItemPropertyValue `
-Path $markerPath `
-Name "Completed" `
-ErrorAction SilentlyContinue
if ($completed -eq 1) {
Write-Log "Shell repair already completed for this user."
exit 0
}
Write-Log "Starting shell repair."
$manifests = @(
"C:\Windows\SystemApps\MicrosoftWindows.Client.CBS_cw5n1h2txyewy\AppxManifest.xml",
"C:\Windows\SystemApps\Microsoft.UI.Xaml.CBS_8wekyb3d8bbwe\AppxManifest.xml",
"C:\Windows\SystemApps\MicrosoftWindows.Client.Core_cw5n1h2txyewy\AppxManifest.xml"
)
foreach ($manifest in $manifests) {
if (Test-Path $manifest) {
Add-AppxPackage `
-Register `
-Path $manifest `
-DisableDevelopmentMode
Write-Log "Registered $manifest"
}
else {
Write-Log "Manifest not found: $manifest"
}
}
New-Item -Path $markerPath -Force | Out-Null
New-ItemProperty `
-Path $markerPath `
-Name "Completed" `
-Value 1 `
-PropertyType DWord `
-Force | Out-Null
Stop-Process -Name sihost -Force -ErrorAction SilentlyContinue
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
Start-Process explorer.exe
Write-Log "Shell repair completed successfully."
}
catch {
Write-Log "Shell repair failed: $($_.Exception.Message)"
exit 1
}
The script registers the required Windows Shell packages and restarts the Shell Infrastructure Host and Windows Explorer.
A registry marker is created for each user:
HKCU\Software\Company\ShellRepair
Completed = 1
This prevents the repair process from running repeatedly for the same user.
Per-user logs are stored in:
C:\ProgramData\ShellRepair\Logs\<username>.log
Create the Scheduled Task
Run the following PowerShell script as Administrator on the template:
$taskName = "Repair Windows Shell at User Logon"
$scriptPath = "C:\ProgramData\ShellRepair\Repair-Shell.ps1"
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -AtLogOn
$principal = New-ScheduledTaskPrincipal `
-GroupId "BUILTIN\Users" `
-RunLevel Limited
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries `
-ExecutionTimeLimit (New-TimeSpan -Minutes 5)
Register-ScheduledTask `
-TaskName $taskName `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Settings $settings `
-Description "Registers required Windows shell packages once for each user after Sysprep." `
-Force
The task starts at every user logon, but the repair itself runs only once per user because of the registry marker.
Problem 2: Cloudbase-Init Does Not Apply the Administrator Password
The second issue occurs when Cloudbase-Init does not apply the password supplied by VMware or Aria Automation.
The Cloudbase-Init log may contain the following message:
Plugin 'SetUserPasswordPlugin' execution already done, skipping
This means that Cloudbase-Init believes the password plugin has already run for the current instance. As a result, the password configuration is skipped.
Cause of the Problem
Cloudbase-Init stores plugin execution state in the Windows Registry under:
HKLM\SOFTWARE\Cloudbase Solutions\Cloudbase-Init\<instance-id>
When the OVF environment does not provide a unique instance ID, Cloudbase-Init may use the default value:
iid-ovf
The stored plugin state can then be found under:
HKLM\SOFTWARE\Cloudbase Solutions\Cloudbase-Init\iid-ovf\Plugins
If this registry state remains inside the source template, every clone may be identified as the same Cloudbase-Init instance. Cloudbase-Init then skips plugins that were already marked as completed, including the password plugin.
Remove Cloudbase-Init Instance State Before Sysprep
Before running the final Sysprep operation, stop the Cloudbase-Init service and delete all stored instance state:
Stop-Service cloudbase-init -Force -ErrorAction SilentlyContinue
$statePath = "HKLM:\SOFTWARE\Cloudbase Solutions\Cloudbase-Init"
if (Test-Path $statePath) {
Get-ChildItem -Path $statePath |
Where-Object {
$_.PSChildName -like "iid-*"
} |
Remove-Item -Recurse -Force
}
This removes instance-specific state such as:
HKLM\SOFTWARE\Cloudbase Solutions\Cloudbase-Init\iid-ovf
It does not remove the Cloudbase-Init installation or its configuration files.
Cloudbase-Init Main Configuration
The main configuration file is:
C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf\cloudbase-init.conf
Important configuration options include:
[DEFAULT]
username=Administrator
groups=Administrators
inject_user_password=true
config_drive_raw_hhd=true
config_drive_cdrom=true
config_drive_vfat=true
verbose=true
debug=true
metadata_services=cloudbaseinit.metadata.services.ovfservice.OvfService
plugins=cloudbaseinit.plugins.windows.createuser.CreateUserPlugin,cloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugin,cloudbaseinit.plugins.common.sshpublickeys.SetUserSSHPublicKeysPlugin,cloudbaseinit.plugins.common.userdata.UserDataPlugin
The important settings are:
inject_user_password=truecloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugincloudbaseinit.metadata.services.ovfservice.OvfService
Final Template Preparation Script
The following script stops Cloudbase-Init, removes saved instance state and starts Sysprep:
$ErrorActionPreference = "Stop"
$cloudbaseService = "cloudbase-init"
$statePath = "HKLM:\SOFTWARE\Cloudbase Solutions\Cloudbase-Init"
$sysprepPath = "C:\Windows\System32\Sysprep\Sysprep.exe"
try {
Stop-Service `
-Name $cloudbaseService `
-Force `
-ErrorAction SilentlyContinue
if (Test-Path $statePath) {
$instanceKeys = Get-ChildItem -Path $statePath |
Where-Object {
$_.PSChildName -like "iid-*"
}
foreach ($instanceKey in $instanceKeys) {
Remove-Item `
-Path $instanceKey.PSPath `
-Recurse `
-Force
}
}
if (-not (Test-Path $sysprepPath)) {
throw "Sysprep executable was not found."
}
Start-Process `
-FilePath $sysprepPath `
-ArgumentList "/generalize", "/oobe", "/shutdown", "/mode:vm" `
-Wait
}
catch {
Write-Error $_.Exception.Message
exit 1
}
Save the script as:
C:\ProgramData\Prepare-CloudbaseTemplate.ps1
Run it as Administrator:
powershell.exe `
-NoProfile `
-ExecutionPolicy Bypass `
-File "C:\ProgramData\Prepare-CloudbaseTemplate.ps1"
Sysprep Command
The script runs the following Sysprep command:
C:\Windows\System32\Sysprep\Sysprep.exe `
/generalize `
/oobe `
/shutdown `
/mode:vm
The parameters perform the following actions:
/generalizeremoves machine-specific information and prepares Windows for cloning./oobestarts the cloned VM in the Windows out-of-box preparation phase./shutdownshuts down the source VM after Sysprep completes./mode:vmoptimizes Sysprep for deployment to similar virtual hardware on the same hypervisor.
Important Template Rule
After Sysprep shuts down the virtual machine, do not power on the source VM again.
Booting the source VM may start Cloudbase-Init and recreate the iid-ovf registry state. Convert the powered-off VM directly to a VMware template or use it as the source for cloning.
Recommended Workflow
- Complete the Windows Server, VMware Tools, application and security configuration.
- Install and configure Cloudbase-Init.
- Create the Shell Repair PowerShell script.
- Create the Shell Repair Scheduled Task.
- Stop the Cloudbase-Init service.
- Delete all Cloudbase-Init registry keys matching
iid-*. - Run Sysprep with
/generalize /oobe /shutdown /mode:vm. - Do not power on the source VM after Sysprep.
- Convert the powered-off VM to a VMware template.
- Deploy a new VM through VMware vSphere or Aria Automation.
- Cloudbase-Init applies the supplied Administrator password.
- The Shell Repair task runs at the first user logon and repairs Windows Explorer if required.
Conclusion
The Windows Server 2025 black screen issue can be resolved by re-registering the required Windows Shell and XAML packages for each user.
The Cloudbase-Init password issue is resolved by deleting the saved iid-* instance state before running the final Sysprep operation. This prevents cloned virtual machines from inheriting completed plugin state from the template.
Using both fixes provides a repeatable Windows Server 2025 template workflow for VMware vSphere and Aria Automation.
Fixing the Black Screen After Sysprep and Cloudbase-Init Password Injection Issues on Windows Server 2025
When preparing a Windows Server 2025 template for VMware vSphere or Aria Automation, you may encounter two separate problems after running Sysprep:
- The cloned virtual machine starts, but the desktop remains black and Windows Explorer does not load.
- The Administrator password selected during deployment is not applied by Cloudbase-Init.
This article explains the working solutions for both issues and shows how to integrate them into a reusable Windows Server template.
Problem 1: Black Screen and Explorer Crash After Sysprep
After deploying a clone from a sysprepped Windows Server 2025 template, Windows may start successfully, but the user sees a black screen instead of the desktop.
Windows Explorer may crash with an error similar to:
Faulting application name: Explorer.EXE
Exception code: 0xc0000409
In this case, some Windows Shell and XAML system packages are not registered correctly for the logged-in user after Sysprep. The affected components can be repaired by registering their AppX manifests again.
Create the Shell Repair Script
Create the following directory:
C:\ProgramData\ShellRepair
Create this PowerShell script:
C:\ProgramData\ShellRepair\Repair-Shell.ps1
Use the following content:
$ErrorActionPreference = "Stop"
$markerPath = "HKCU:\Software\Company\ShellRepair"
$logDirectory = "C:\ProgramData\ShellRepair\Logs"
$logFile = Join-Path $logDirectory "$env:USERNAME.log"
New-Item -Path $logDirectory -ItemType Directory -Force | Out-Null
function Write-Log {
param(
[Parameter(Mandatory)]
[string]$Message
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $logFile -Value "$timestamp $Message"
}
try {
$completed = Get-ItemPropertyValue `
-Path $markerPath `
-Name "Completed" `
-ErrorAction SilentlyContinue
if ($completed -eq 1) {
Write-Log "Shell repair already completed for this user."
exit 0
}
Write-Log "Starting shell repair."
$manifests = @(
"C:\Windows\SystemApps\MicrosoftWindows.Client.CBS_cw5n1h2txyewy\AppxManifest.xml",
"C:\Windows\SystemApps\Microsoft.UI.Xaml.CBS_8wekyb3d8bbwe\AppxManifest.xml",
"C:\Windows\SystemApps\MicrosoftWindows.Client.Core_cw5n1h2txyewy\AppxManifest.xml"
)
foreach ($manifest in $manifests) {
if (Test-Path $manifest) {
Add-AppxPackage `
-Register `
-Path $manifest `
-DisableDevelopmentMode
Write-Log "Registered $manifest"
}
else {
Write-Log "Manifest not found: $manifest"
}
}
New-Item -Path $markerPath -Force | Out-Null
New-ItemProperty `
-Path $markerPath `
-Name "Completed" `
-Value 1 `
-PropertyType DWord `
-Force | Out-Null
Stop-Process -Name sihost -Force -ErrorAction SilentlyContinue
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
Start-Process explorer.exe
Write-Log "Shell repair completed successfully."
}
catch {
Write-Log "Shell repair failed: $($_.Exception.Message)"
exit 1
}
The script registers the required Windows Shell packages and restarts the Shell Infrastructure Host and Windows Explorer.
A registry marker is created for each user:
HKCU\Software\Company\ShellRepair
Completed = 1
This prevents the repair process from running repeatedly for the same user.
Per-user logs are stored in:
C:\ProgramData\ShellRepair\Logs\<username>.log
Create the Scheduled Task
Run the following PowerShell script as Administrator on the template:
$taskName = "Repair Windows Shell at User Logon"
$scriptPath = "C:\ProgramData\ShellRepair\Repair-Shell.ps1"
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -AtLogOn
$principal = New-ScheduledTaskPrincipal `
-GroupId "BUILTIN\Users" `
-RunLevel Limited
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries `
-ExecutionTimeLimit (New-TimeSpan -Minutes 5)
Register-ScheduledTask `
-TaskName $taskName `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Settings $settings `
-Description "Registers required Windows shell packages once for each user after Sysprep." `
-Force
The task starts at every user logon, but the repair itself runs only once per user because of the registry marker.
Problem 2: Cloudbase-Init Does Not Apply the Administrator Password
The second issue occurs when Cloudbase-Init does not apply the password supplied by VMware or Aria Automation.
The Cloudbase-Init log may contain the following message:
Plugin 'SetUserPasswordPlugin' execution already done, skipping
This means that Cloudbase-Init believes the password plugin has already run for the current instance. As a result, the password configuration is skipped.
Cause of the Problem
Cloudbase-Init stores plugin execution state in the Windows Registry under:
HKLM\SOFTWARE\Cloudbase Solutions\Cloudbase-Init\<instance-id>
When the OVF environment does not provide a unique instance ID, Cloudbase-Init may use the default value:
iid-ovf
The stored plugin state can then be found under:
HKLM\SOFTWARE\Cloudbase Solutions\Cloudbase-Init\iid-ovf\Plugins
If this registry state remains inside the source template, every clone may be identified as the same Cloudbase-Init instance. Cloudbase-Init then skips plugins that were already marked as completed, including the password plugin.
Remove Cloudbase-Init Instance State Before Sysprep
Before running the final Sysprep operation, stop the Cloudbase-Init service and delete all stored instance state:
Stop-Service cloudbase-init -Force -ErrorAction SilentlyContinue
$statePath = "HKLM:\SOFTWARE\Cloudbase Solutions\Cloudbase-Init"
if (Test-Path $statePath) {
Get-ChildItem -Path $statePath |
Where-Object {
$_.PSChildName -like "iid-*"
} |
Remove-Item -Recurse -Force
}
This removes instance-specific state such as:
HKLM\SOFTWARE\Cloudbase Solutions\Cloudbase-Init\iid-ovf
It does not remove the Cloudbase-Init installation or its configuration files.
Cloudbase-Init Main Configuration
The main configuration file is:
C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf\cloudbase-init.conf
Important configuration options include:
[DEFAULT]
username=Administrator
groups=Administrators
inject_user_password=true
config_drive_raw_hhd=true
config_drive_cdrom=true
config_drive_vfat=true
verbose=true
debug=true
metadata_services=cloudbaseinit.metadata.services.ovfservice.OvfService
plugins=cloudbaseinit.plugins.windows.createuser.CreateUserPlugin,cloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugin,cloudbaseinit.plugins.common.sshpublickeys.SetUserSSHPublicKeysPlugin,cloudbaseinit.plugins.common.userdata.UserDataPlugin
The important settings are:
inject_user_password=truecloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugincloudbaseinit.metadata.services.ovfservice.OvfService
Final Template Preparation Script
The following script stops Cloudbase-Init, removes saved instance state and starts Sysprep:
$ErrorActionPreference = "Stop"
$cloudbaseService = "cloudbase-init"
$statePath = "HKLM:\SOFTWARE\Cloudbase Solutions\Cloudbase-Init"
$sysprepPath = "C:\Windows\System32\Sysprep\Sysprep.exe"
try {
Stop-Service `
-Name $cloudbaseService `
-Force `
-ErrorAction SilentlyContinue
if (Test-Path $statePath) {
$instanceKeys = Get-ChildItem -Path $statePath |
Where-Object {
$_.PSChildName -like "iid-*"
}
foreach ($instanceKey in $instanceKeys) {
Remove-Item `
-Path $instanceKey.PSPath `
-Recurse `
-Force
}
}
if (-not (Test-Path $sysprepPath)) {
throw "Sysprep executable was not found."
}
Start-Process `
-FilePath $sysprepPath `
-ArgumentList "/generalize", "/oobe", "/shutdown", "/mode:vm" `
-Wait
}
catch {
Write-Error $_.Exception.Message
exit 1
}
Save the script as:
C:\ProgramData\Prepare-CloudbaseTemplate.ps1
Run it as Administrator:
powershell.exe `
-NoProfile `
-ExecutionPolicy Bypass `
-File "C:\ProgramData\Prepare-CloudbaseTemplate.ps1"
Sysprep Command
The script runs the following Sysprep command:
C:\Windows\System32\Sysprep\Sysprep.exe `
/generalize `
/oobe `
/shutdown `
/mode:vm
The parameters perform the following actions:
/generalizeremoves machine-specific information and prepares Windows for cloning./oobestarts the cloned VM in the Windows out-of-box preparation phase./shutdownshuts down the source VM after Sysprep completes./mode:vmoptimizes Sysprep for deployment to similar virtual hardware on the same hypervisor.
Important Template Rule
After Sysprep shuts down the virtual machine, do not power on the source VM again.
Booting the source VM may start Cloudbase-Init and recreate the iid-ovf registry state.
Convert the powered-off VM directly to a VMware template or use it as the source for cloning.
Recommended Workflow
- Complete the Windows Server, VMware Tools, application and security configuration.
- Install and configure Cloudbase-Init.
- Create the Shell Repair PowerShell script.
- Create the Shell Repair Scheduled Task.
- Stop the Cloudbase-Init service.
- Delete all Cloudbase-Init registry keys matching
iid-*. - Run Sysprep with
/generalize /oobe /shutdown /mode:vm. - Do not power on the source VM after Sysprep.
- Convert the powered-off VM to a VMware template.
- Deploy a new VM through VMware vSphere or Aria Automation.
- Cloudbase-Init applies the supplied Administrator password.
- The Shell Repair task runs at the first user logon and repairs Windows Explorer if required.
Conclusion
The Windows Server 2025 black screen issue can be resolved by re-registering the required Windows Shell and XAML packages for each user.
The Cloudbase-Init password issue is resolved by deleting the saved iid-* instance state before running the final Sysprep operation.
This prevents cloned virtual machines from inheriting completed plugin state from the template.
Using both fixes provides a repeatable Windows Server 2025 template workflow for VMware vSphere and Aria Automation.