autounattend.xml filesCustom scripts in autounattend.xml files are a powerful mechanism to customize your Windows installation. Some sample scripts are shown below.
7z2600-x64.exe) in the root folder of all attached drives, then install 7-Zip silently.
This is a .ps1 script that runs in the system context, before user accounts are created.
foreach( $drive in [System.IO.DriveInfo]::GetDrives() ) {
if( $found = Join-Path -Path $drive.RootDirectory -ChildPath '7z*-x64.exe' -Resolve -ErrorAction 'SilentlyContinue' ) {
Start-Process -FilePath $found -ArgumentList '/S /D="C:\Program Files\7-Zip"' -Wait;
return;
}
}
'Cannot find any files that match pattern.' | Write-Warning;
Configure form
This is a .ps1 script that runs when the first user logs on after Windows has been installed.
foreach( $drive in [System.IO.DriveInfo]::GetDrives() ) {
if( $found = Join-Path -Path $drive.RootDirectory -ChildPath 'Ninite*Installer.exe' -Resolve -ErrorAction 'SilentlyContinue' ) {
Start-Process -FilePath $found -Wait;
return;
}
}
'Cannot find any files that match pattern.' | Write-Warning;
Configure form
This is a .ps1 script that runs in the system context, before user accounts are created.
$uri = [uri]::new( 'https://dl.google.com/chrome/install/chrome_installer.exe' );
$file = "$env:TEMP\{0}" -f $uri.Segments[-1];
[System.Net.WebClient]::new().DownloadFile( $uri, $file );
Start-Process -FilePath $file -ArgumentList '/silent /install' -Wait;
Remove-Item -LiteralPath $file -ErrorAction 'SilentlyContinue';
Configure form
This is a .ps1 script that runs in the system context, before user accounts are created.
$uri = [uri]::new( 'https://aka.ms/vs/17/release/vc_redist.x64.exe' );
$file = "$env:TEMP\{0}" -f $uri.Segments[-1];
[System.Net.WebClient]::new().DownloadFile( $uri, $file );
Start-Process -FilePath $file -ArgumentList '/quiet /norestart' -Wait;
Remove-Item -LiteralPath $file -ErrorAction 'SilentlyContinue';
Configure form
This is a .ps1 script that runs when the first user logs on after Windows has been installed.
if( [System.Environment]::OSVersion.Version.Build -lt 26100 ) {
'This script requires Windows 11 24H2 or later.' | Write-Warning;
return;
}
$timeout = [datetime]::Now.AddMinutes( 5 );
$exe = "$env:LOCALAPPDATA\Microsoft\WindowsApps\winget.exe";
while( $true ) {
if( $exe | Test-Path ) {
& $exe install --exact --id Mozilla.Firefox --silent --accept-package-agreements --accept-source-agreements --source winget --scope machine;
return;
}
if( [datetime]::Now -gt $timeout ) {
"File '${exe}' does not exist." | Write-Warning;
return;
}
"Waiting for '${exe}' to become available..." | Write-Host;
Start-Sleep -Seconds 1;
}
Configure form
This is a .ps1 script that runs when the first user logs on after Windows has been installed.
$user = 'brave';
$repository = 'brave-browser';
$uri = $(
& {
$ProgressPreference = 'SilentlyContinue';
Invoke-WebRequest -Uri "https://api.github.com/repos/${user}/${repository}/releases?per_page=100" -UseBasicParsing -Headers @{
Accept = 'application/vnd.github.v3+json';
} | Select-Object -ExpandProperty 'Content' | ConvertFrom-Json;
};
) | ForEach-Object -Process {
if( $_.draft -or $_.prerelease ) {
return;
}
foreach( $b in ( $_.assets.browser_download_url -match 'StandaloneSetup\.exe$' ) ) {
return [uri]::new( $b );
}
} | Select-Object -First 1;
if( -not $uri ) {
throw 'Cannot determine URL of latest Brave installer.';
}
$file = "${env:TEMP}\{0}" -f $uri.Segments[-1];
[System.Net.WebClient]::new().DownloadFile( $uri, $file );
Unblock-File -LiteralPath $file;
Start-Process -FilePath $file -Wait;
Remove-Item -LiteralPath $file -ErrorAction 'SilentlyContinue';
Configure form
This is a .ps1 script that runs when the first user logs on after Windows has been installed.
$user = 'microsoft';
$repository = 'terminal';
$latest = $(
& {
$ProgressPreference = 'SilentlyContinue';
Invoke-WebRequest -Uri "https://api.github.com/repos/${user}/${repository}/releases" -UseBasicParsing -Headers @{
Accept = 'application/vnd.github.v3+json';
} | Select-Object -ExpandProperty 'Content' | ConvertFrom-Json;
};
) | Where-Object -FilterScript {
-not $_.draft -and -not $_.prerelease;
} | Select-Object -First 1;
$latest.assets.browser_download_url | Where-Object -FilterScript {
$_ -match '\.msixbundle$';
} | Select-Object -First 1 | ForEach-Object -Process {
$uri = [uri]::new( $_ );
$file = "$env:TEMP\{0}" -f $uri.Segments[-1];
[System.Net.WebClient]::new().DownloadFile( $uri, $file );
Add-AppxProvisionedPackage -Online -PackagePath $file -SkipLicense;
Remove-Item -LiteralPath $file -ErrorAction 'SilentlyContinue';
};
Configure form
\sources\sxs\microsoft-windows-netfx3-ondemand-package~*.cab instead of downloading it from Windows Update.
This is a .ps1 script that runs when the first user logs on after Windows has been installed.
foreach( $drive in [System.IO.DriveInfo]::GetDrives() ) {
if( $found = Join-Path -Path $drive.RootDirectory -ChildPath 'sources\sxs' -Resolve -ErrorAction 'SilentlyContinue' ) {
Enable-WindowsOptionalFeature -Online -FeatureName 'NetFx3' -Source $found -NoRestart;
return;
}
}
'Cannot find any files that match pattern.' | Write-Warning;
Configure form
vioscsi.sys driver when a virtio-win-*.iso image is mounted.
This is a .ps1 script that runs in the system context, before user accounts are created.
foreach( $drive in [System.IO.DriveInfo]::GetDrives() ) {
if( $found = Join-Path -Path $drive.RootDirectory -ChildPath 'vioscsi\w11\amd64\vioscsi.inf' -Resolve -ErrorAction 'SilentlyContinue' ) {
pnputil.exe /add-driver $found /install;
return;
}
}
'Cannot find any files that match pattern.' | Write-Warning;
Configure form
ping), in Windows Firewall.
This is a .ps1 script that runs in the system context, before user accounts are created.
New-NetFirewallRule -DisplayName 'ICMPv4' -Profile 'Any' -Protocol 'ICMPv4' -Action 'Allow'; New-NetFirewallRule -DisplayName 'ICMPv6' -Profile 'Any' -Protocol 'ICMPv6' -Action 'Allow';Configure form
This is a .ps1 script that runs in the system context, before user accounts are created.
Set-NetFirewallProfile -DefaultInboundAction 'Block' -DefaultOutboundAction 'Allow' -Name '*';Configure form
This is a .ps1 script that runs in the system context, before user accounts are created.
$params = @{
Path = 'Registry::HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer';
};
New-Item @params -ErrorAction 'SilentlyContinue';
Set-ItemProperty @params -Name 'NoDriveAutoRun' -Type 'DWord' -Value $(
( 1 -shl 26 ) - 1; # 0x3FFFFFF
);
Set-ItemProperty @params -Name 'NoDriveTypeAutoRun' -Type 'DWord' -Value $(
( 1 -shl 8 ) - 1; # 0xFF
);
Configure form
This is a .ps1 script that runs in the system context, before user accounts are created.
$out = & "$env:windir\System32\powercfg.exe" /DuplicateScheme 'e9a42b02-d5df-448d-aa00-03f14749eb61';
if( $out -match '\s([a-f0-9-]{36})\s' ) {
& "$env:windir\System32\powercfg.exe" /SetActive $Matches[1];
} else {
'Could not enable Ultimate Performance power scheme.' | Write-Warning;
}
Configure form
winver.exe.
This is a .reg script that runs in the system context, before user accounts are created.
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion] "RegisteredOrganization"="Foo" "RegisteredOwner"="Bar"Configure form
dir command.
This is a .cmd script that runs in the system context, before user accounts are created.
setx.exe DIRCMD "/A /O:GN /C /N" /mConfigure form
This is a .reg script that runs in the system context, before user accounts are created.
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Remote Assistance] "fAllowToGetHelp"=dword:00000000Configure form
D:\Users (instead the default %SystemDrive%\Users), without moving the Public and Default profiles.
This is a .cmd script that runs in the system context, before user accounts are created.
mkdir D:\Users reg.exe add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList" /v ProfilesDirectory /t REG_SZ /d "D:\Users" /f reg.exe add "HKLM\Software\WOW6432Node\Microsoft\Windows NT\CurrentVersion\ProfileList" /v ProfilesDirectory /t REG_SZ /d "D:\Users" /fConfigure form
This is a .ps1 script that runs when the first user logs on after Windows has been installed.
Get-NetConnectionProfile -InterfaceAlias 'Ethernet*' | Set-NetConnectionProfile -NetworkCategory 'Private';Configure form
the latest features and security updatesduring Setup, which often feels agonizingly slow. This script makes Windows skip this tedious process by pausing Windows Update for one hour.
This is a .ps1 script that runs in the system context, before user accounts are created.
$format = 'yyyy-MM-ddTHH\:mm\:ssK';
$now = [datetime]::UtcNow;
$start = $now.ToString($format);
$end = $now.AddHours(1).ToString($format);
$params = @{
LiteralPath = 'Registry::HKLM\Software\Microsoft\WindowsUpdate\UX\Settings';
Type = 'String';
Force = $true;
Verbose = $true;
};
'PauseFeatureUpdatesStartTime', 'PauseQualityUpdatesStartTime', 'PauseUpdatesStartTime' | foreach {
Set-ItemProperty @params -Name $_ -Value $start;
};
'PauseFeatureUpdatesEndTime', 'PauseQualityUpdatesEndTime', 'PauseUpdatesExpiryTime' | foreach {
Set-ItemProperty @params -Name $_ -Value $end;
};
Configure form
This is a .ps1 script that runs in the system context, before user accounts are created.
foreach( $profile in 'DomainProfile', 'StandardProfile', 'PublicProfile' ) {
reg.exe add "HKLM\System\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\${profile}" /v DisableNotifications /d 1 /t REG_DWORD /f;
}
Configure form
This is a .ps1 script that runs in the system context, before user accounts are created.
function New-Shortcut {
[CmdletBinding()]
param(
[string]
$FilePath,
[string]
$Target
);
$wsh = New-Object -ComObject 'WScript.Shell';
$shortcut = $wsh.CreateShortcut( $FilePath );
$shortcut.TargetPath = $Target;
$shortcut.Save();
}
New-Shortcut -FilePath 'C:\Users\Public\Desktop\Download Chrome.url' -Target 'https://www.google.com/chrome/';
New-Shortcut -FilePath 'C:\Users\Public\Desktop\System Properties.lnk' -Target '%windir%\System32\SystemPropertiesAdvanced.exe';
Configure form
background.png in the root folder of all attached drives and use it as the desktop wallpaper.
This is a .ps1 script to set the desktop wallpaper.
foreach( $drive in [System.IO.DriveInfo]::GetDrives() ) {
if( $found = Join-Path -Path $drive.RootDirectory -ChildPath 'background.png' -Resolve -ErrorAction 'SilentlyContinue' ) {
return [System.IO.File]::ReadAllBytes( $found );
}
}
'Cannot find any files that match pattern.' | Write-Warning;
Configure form
lockscreen.png in the root folder of all attached drives and use it as the lock screen image.
This is a .ps1 script to set the lock screen image.
foreach( $drive in [System.IO.DriveInfo]::GetDrives() ) {
if( $found = Join-Path -Path $drive.RootDirectory -ChildPath 'lockscreen.png' -Resolve -ErrorAction 'SilentlyContinue' ) {
return [System.IO.File]::ReadAllBytes( $found );
}
}
'Cannot find any files that match pattern.' | Write-Warning;
Configure form
This is a .ps1 script to set the computer name.
$adapter = Get-NetAdapter -Name 'Ethernet*' -ErrorAction 'SilentlyContinue' | Select-Object -First 1;
if( $adapter ) {
return 'PC-' + ( $adapter.MacAddress -replace '-', '' );
} else {
"Could not find Ethernet adapter." | Write-Warning;
}
Configure form
This is a .ps1 script to set the computer name.
[ipaddress] $addr = Get-NetIPAddress -InterfaceAlias 'Ethernet' -AddressFamily 'IPv4' -ErrorAction 'SilentlyContinue' | Select-Object -First 1 -ExpandProperty 'IPv4Address';
if( $addr ) {
return 'PC-{0}-{1}' -f $addr.GetAddressBytes()[-2, -1];
} else {
"Could not determine IP address." | Write-Warning;
}
Configure form
This is a .ps1 script to set the computer name.
Add-Type -AssemblyName 'Microsoft.VisualBasic'; return [Microsoft.VisualBasic.Interaction]::InputBox( 'Enter a valid computer name:', 'Computer name', '' );Configure form