Files
windows-builder/tiny10maker.ps1
2026-06-02 03:37:09 -07:00

1134 lines
67 KiB
PowerShell

# Enable debugging
#Set-PSDebug -Trace 1
param (
[ValidatePattern('^[c-zC-Z]:?$|^[a-zA-Z]:\\.*$')]
[string]$ScratchDisk,
[string]$windowsisopath,
[string]$imageindex,
[switch]$UseSetupTemplate
)
if (-not $ScratchDisk) {
$ScratchDisk = Join-Path $PSScriptRoot 'working' # Set to './working' in the script's directory
}
else {
if ($ScratchDisk -match '^[a-zA-Z]:?$') {
$ScratchDisk = $ScratchDisk[0] + ':'
}
}
Write-Output "Scratch disk set to $ScratchDisk"
# Normalize windowsisopath: accept D, D:, D:\ all as drive letter D:
if ($windowsisopath -match '^[a-zA-Z]:?\\?$') {
$windowsisopath = $windowsisopath[0] + ':'
}
# Check if PowerShell execution is Restricted or AllSigned or Undefined
$needchange = @("AllSigned", "Restricted", "Undefined")
$curpolicy = Get-ExecutionPolicy
if ($curpolicy -in $needchange) {
Write-Host "Your current PowerShell Execution Policy is set to $curpolicy, which prevents scripts from running. Do you want to change it to RemoteSigned? (yes/no)"
$response = Read-Host
if ($response -eq 'yes') {
Set-ExecutionPolicy RemoteSigned -Scope Process -Confirm:$false
}
else {
Write-Host "The script cannot be run without changing the execution policy. Exiting..."
exit
}
}
# Check and run the script as admin if required
$adminSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$adminGroup = $adminSID.Translate([System.Security.Principal.NTAccount])
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
if (! $myWindowsPrincipal.IsInRole($adminRole)) {
Write-Host "Restarting Tiny10 image creator as admin in a new window, you can close this one."
$newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
$argString = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
# Add additional parameters if they are set
if ($windowsisopath) {
$argString += " -windowsisopath `"$windowsisopath`""
}
if ($imageindex) {
$argString += " -imageindex `"$imageindex`""
}
if ($UseSetupTemplate) { $argString += " -UseSetupTemplate" }
$newProcess.Arguments = $argString;
$newProcess.Verb = "runas";
[System.Diagnostics.Process]::Start($newProcess);
exit
}
# Start the transcript and prepare the window
Start-Transcript -Path "$ScratchDisk\tiny10.log"
$Host.UI.RawUI.WindowTitle = "Tiny10 image creator"
Clear-Host
$hostArchitecture = $Env:PROCESSOR_ARCHITECTURE
$setupMediaTemplatePath = "$PSScriptRoot\setup-media-template"
New-Item -ItemType Directory -Force -Path "$ScratchDisk\tiny10\sources" | Out-Null
# -- Direct file input: auto-mount ISO or extract WIM/ESD --
$mountedISO = $null # path of ISO we mounted (for cleanup)
$sourceFromFile = $false # true when scratch dir populated directly from WIM/ESD
if ($windowsisopath -and $windowsisopath -notmatch '^[c-zC-Z]:$') {
$ext = [System.IO.Path]::GetExtension($windowsisopath).ToLower()
if ($ext -eq '.iso') {
Write-Host "ISO file provided - mounting: $windowsisopath"
$resolvedIso = (Resolve-Path $windowsisopath).Path
$mountResult = Mount-DiskImage -ImagePath $resolvedIso -PassThru -ErrorAction Stop
$mountedISO = $resolvedIso
$windowsisopath = ($mountResult | Get-Volume).DriveLetter + ":"
Write-Host "ISO mounted at $windowsisopath"
}
elseif ($ext -in @('.wim', '.esd')) {
$sourceFile = (Resolve-Path $windowsisopath).Path
Write-Host "Direct WIM/ESD source: $sourceFile"
$allIndexes = Get-WindowsImage -ImagePath $sourceFile
Write-Host "Indexes in source file:"
$allIndexes | ForEach-Object { Write-Host " [$($_.ImageIndex)] $($_.ImageName)" }
if ($allIndexes.Count -ge 4) {
# WOR-format ESD: idx 1 = setup structure, 2 = WinPE, 3 = Setup, 4+ = OS editions
Write-Host "Full ESD with setup structure detected."
if (-not $UseSetupTemplate) {
Write-Host "Extracting setup media structure (index 1)..."
Expand-WindowsImage -ImagePath $sourceFile -Index 1 -ApplyPath "$ScratchDisk\tiny10\" -ErrorAction Stop
$bootWimDest = "$ScratchDisk\tiny10\sources\boot.wim"
if (Test-Path $bootWimDest) { Remove-Item $bootWimDest -Force }
Write-Host "Building boot.wim (PE index 2 + Setup index 3)..."
& dism /English /Export-Image "/SourceImageFile:$sourceFile" "/SourceIndex:2" `
"/DestinationImageFile:$bootWimDest" /Compress:max /CheckIntegrity | Out-Null
& dism /English /Export-Image "/SourceImageFile:$sourceFile" "/SourceIndex:3" `
"/DestinationImageFile:$bootWimDest" /Compress:max /CheckIntegrity | Out-Null
}
if ($imageindex) {
$installSrcIndex = [int]$imageindex
} else {
$installSrcIndex = ($allIndexes | Where-Object { $_.ImageName -match 'Windows 10 Pro$' } |
Select-Object -First 1).ImageIndex
if (-not $installSrcIndex) { $installSrcIndex = $allIndexes[-1].ImageIndex }
$editionName = ($allIndexes | Where-Object { $_.ImageIndex -eq $installSrcIndex }).ImageName
Write-Host "Using install image index $installSrcIndex ($editionName)"
}
Write-Host "Extracting install image to sources\install.wim..."
Export-WindowsImage -SourceImagePath $sourceFile -SourceIndex $installSrcIndex `
-DestinationImagePath "$ScratchDisk\tiny10\sources\install.wim" -CompressionType None -ErrorAction Stop
$index = 1
$indexAlreadySelected = $true
$sourceFromFile = $true
Write-Host "Source extraction complete."
}
else {
# Install-only WIM/ESD - no boot structure
Write-Host "Install-only source (no setup structure). Copying to scratch..."
if ($ext -eq '.esd') {
Copy-Item $sourceFile "$ScratchDisk\tiny10\sources\install.esd" -Force
Set-ItemProperty "$ScratchDisk\tiny10\sources\install.esd" -Name IsReadOnly -Value $false -ErrorAction SilentlyContinue
} else {
Copy-Item $sourceFile "$ScratchDisk\tiny10\sources\install.wim" -Force
& takeown "/F" "$ScratchDisk\tiny10\sources\install.wim" | Out-Null
& icacls "$ScratchDisk\tiny10\sources\install.wim" "/grant" "$($adminGroup.Value):(F)" | Out-Null
try { Set-ItemProperty "$ScratchDisk\tiny10\sources\install.wim" -Name IsReadOnly -Value $false -ErrorAction Stop } catch {}
}
$sourceFromFile = $true
Write-Warning "No boot structure found. ISO creation will fail without etfsboot.com and efisys.bin."
Write-Warning "Use a full WOR-format ESD for a complete bootable image."
}
}
}
# -- Drive letter input (existing path) --
if (-not $sourceFromFile) {
if ($windowsisopath -match '^[c-zC-Z]:$') {
write-host "windows iso path: $windowsisopath"
$DriveLetter = $windowsisopath
}
else {
do {
$DriveLetter = Read-Host "Please enter the drive letter for the Windows 10 image, e.g. D:"
if ($DriveLetter -match '^[c-zC-Z]$') {
$DriveLetter = "$DriveLetter`:" # Ensure proper format
Write-Output "Drive letter set to $DriveLetter"
}
else {
Write-Output "Invalid drive letter. Please enter a letter between C and Z."
}
} while ($DriveLetter -notmatch '^[c-zC-Z]:$') # Continue until valid
}
# Multi-arch ISO: no sources\ at root but x64\sources\ present — use x64 only
if (-not (Test-Path "$DriveLetter\sources") -and (Test-Path "$DriveLetter\x64\sources")) {
Write-Host "Multi-architecture ISO detected. Using x64."
if ($UseSetupTemplate) {
if (Test-Path "$DriveLetter\x64\sources\install.esd") {
Write-Host "Found install.esd in x64 sources, converting to install.wim..."
if ($imageindex) { $esdIndex = $imageindex }
else {
Get-WindowsImage -ImagePath "$DriveLetter\x64\sources\install.esd"
$esdIndex = Read-Host "Please enter the image index"
}
Export-WindowsImage -SourceImagePath "$DriveLetter\x64\sources\install.esd" -SourceIndex $esdIndex -DestinationImagePath "$ScratchDisk\tiny10\sources\install.wim" -Compressiontype Maximum -CheckIntegrity
$index = 1
$indexAlreadySelected = $true
} else {
Write-Host "Template mode: copying install.wim from x64 source..."
Copy-Item -Path "$DriveLetter\x64\sources\install.wim" -Destination "$ScratchDisk\tiny10\sources\install.wim" -Force | Out-Null
}
} else {
foreach ($item in @('boot','efi','bootmgr','bootmgr.efi','setup.exe','autorun.inf')) {
if (Test-Path "$DriveLetter\$item") {
Copy-Item -Path "$DriveLetter\$item" -Destination "$ScratchDisk\tiny10\" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
}
Copy-Item -Path "$DriveLetter\x64\*" -Destination "$ScratchDisk\tiny10\" -Recurse -Force | Out-Null
Set-ItemProperty -Path "$ScratchDisk\tiny10\sources\install.esd" -Name IsReadOnly -Value $false -ErrorAction SilentlyContinue
if ((Test-Path "$ScratchDisk\tiny10\sources\install.esd") -and -not (Test-Path "$ScratchDisk\tiny10\sources\install.wim")) {
Write-Host "Found install.esd in x64 sources, converting to install.wim..."
if ($imageindex) { $esdIndex = $imageindex }
else {
Get-WindowsImage -ImagePath "$ScratchDisk\tiny10\sources\install.esd"
$esdIndex = Read-Host "Please enter the image index"
}
Export-WindowsImage -SourceImagePath "$ScratchDisk\tiny10\sources\install.esd" -SourceIndex $esdIndex -DestinationImagePath "$ScratchDisk\tiny10\sources\install.wim" -Compressiontype Maximum -CheckIntegrity
Remove-Item "$ScratchDisk\tiny10\sources\install.esd" -Force -ErrorAction SilentlyContinue | Out-Null
$index = 1
$indexAlreadySelected = $true
}
}
$sourceFromFile = $true
Write-Host "Copy complete!"
Start-Sleep -Seconds 2
Clear-Host
} else {
if ((-not $UseSetupTemplate -and (Test-Path "$DriveLetter\sources\boot.wim") -eq $false) -or (Test-Path "$DriveLetter\sources\install.wim") -eq $false) {
if ((Test-Path "$DriveLetter\sources\install.esd") -eq $true) {
Write-Host "Found install.esd, converting to install.wim..."
if ($imageindex) {
$esdIndex = $imageindex
Write-Host "Using provided image index: $esdIndex"
}
else {
Get-WindowsImage -ImagePath $DriveLetter\sources\install.esd
$esdIndex = Read-Host "Please enter the image index"
}
Write-Host ' '
Write-Host 'Converting install.esd to install.wim. This may take a while...'
Export-WindowsImage -SourceImagePath $DriveLetter\sources\install.esd -SourceIndex $esdIndex -DestinationImagePath $ScratchDisk\tiny10\sources\install.wim -Compressiontype Maximum -CheckIntegrity
$index = 1
$indexAlreadySelected = $true
Write-Host "ESD image index $esdIndex has been converted and is now index 1 in the WIM file."
}
else {
Write-Host "Can't find Windows OS Installation files in the specified Drive Letter.."
Write-Host "Please enter the correct DVD Drive Letter.."
exit
}
}
if ($UseSetupTemplate) {
if (-not $indexAlreadySelected) {
Write-Host "Template mode: copying install.wim from source..."
Copy-Item -Path "$DriveLetter\sources\install.wim" -Destination "$ScratchDisk\tiny10\sources\install.wim" -Force | Out-Null
}
} else {
Write-Host "Copying Windows image..."
Copy-Item -Path "$DriveLetter\*" -Destination "$ScratchDisk\tiny10" -Recurse -Force | Out-Null
Set-ItemProperty -Path "$ScratchDisk\tiny10\sources\install.esd" -Name IsReadOnly -Value $false > $null 2>&1
Remove-Item "$ScratchDisk\tiny10\sources\install.esd" > $null 2>&1
Write-Host "Copy complete!"
Start-Sleep -Seconds 2
Clear-Host
}
}
}
# -- Template mode: copy setup media base --
if ($UseSetupTemplate) {
if (-not (Test-Path "$setupMediaTemplatePath")) {
Write-Error "setup-media-template folder not found: $setupMediaTemplatePath"
exit 1
}
Write-Host "Copying setup media template to scratch..."
Copy-Item -Path "$setupMediaTemplatePath\*" -Destination "$ScratchDisk\tiny10" -Recurse -Force | Out-Null
Write-Host "Template copy complete."
}
# Only ask for image index if we haven't already selected one during ESD conversion
if ($indexAlreadySelected) {
Write-Host "Using converted image at index: $index"
}
elseif ($imageindex) {
$index = $imageindex
Write-Host "Using provided image index: $index"
}
else {
Write-Host "Getting image information..."
Get-WindowsImage -ImagePath $ScratchDisk\tiny10\sources\install.wim
$index = Read-Host "Please enter the image index : "
$ImagesIndex = (Get-WindowsImage -ImagePath $ScratchDisk\tiny10\sources\install.wim).ImageIndex
while ($ImagesIndex -notcontains $index) {
$index = Read-Host "Please enter a valide image index : "
}
}
Write-Host "Mounting Windows image. This may take a while."
$wimFilePath = "$ScratchDisk\tiny10\sources\install.wim"
& takeown "/F" $wimFilePath
& icacls $wimFilePath "/grant" "$($adminGroup.Value):(F)"
try {
Set-ItemProperty -Path $wimFilePath -Name IsReadOnly -Value $false -ErrorAction Stop
}
catch {
# This block will catch the error and suppress it.
}
New-Item -ItemType Directory -Force -Path "$ScratchDisk\scratchdir" > $null
Mount-WindowsImage -ImagePath $wimFilePath -Index $index -Path $ScratchDisk\scratchdir
# Powershell dism module does not have direct equivalent for /Get-Intl
$imageIntl = & dism /English /Get-Intl "/Image:$($ScratchDisk)\scratchdir"
$languageLine = $imageIntl -split '\n' | Where-Object { $_ -match 'Default system UI language : ([a-zA-Z]{2}-[a-zA-Z]{2})' }
if ($languageLine) {
$languageCode = $Matches[1]
Write-Host "Default system UI language code: $languageCode"
}
else {
Write-Host "Default system UI language code not found."
}
# Defined in (Microsoft.Dism.Commands.ImageInfoObject).Architecture formatting script
# 0 -> x86, 5 -> arm(currently unused), 6 -> ia64(currently unused), 9 -> x64, 12 -> arm64
switch ((Get-WindowsImage -ImagePath $wimFilePath -Index $index).Architecture) {
0 { $architecture = "x86" }
9 { $architecture = "amd64" }
12 { $architecture = "arm64" }
}
if ($architecture) {
Write-Host "Architecture: $architecture"
}
else {
Write-Host "Architecture information not found."
}
Write-Host "Mounting complete! Performing removal of applications..."
$packages = Get-ProvisionedAppxPackage -Path "$ScratchDisk\scratchdir" |
ForEach-Object {
$_.PackageName
}
$packagePrefixes = @(
'Clipchamp.Clipchamp_',
'Microsoft.3DBuilder_',
'Microsoft.Microsoft3DViewer_',
'Microsoft.BingFinance_',
'Microsoft.BingNews_',
'Microsoft.BingSearch_',
'Microsoft.BingSports_',
'Microsoft.BingWeather_',
'Microsoft.GamingApp_',
'Microsoft.GetHelp_',
'Microsoft.Getstarted_',
'Microsoft.MicrosoftOfficeHub_',
'Microsoft.MicrosoftSolitaireCollection_',
'Microsoft.OutlookForWindows_',
'Microsoft.People_',
'Microsoft.PowerAutomateDesktop_',
'Microsoft.SkypeApp_',
'Microsoft.Todos_',
'Microsoft.Windows.DevHome_',
'Microsoft.WindowsAlarms_',
'microsoft.windowscommunicationsapps_',
'Microsoft.WindowsFeedbackHub_',
'Microsoft.WindowsMaps_',
'Microsoft.WindowsSoundRecorder_',
'Microsoft.ZuneMusic_',
'Microsoft.ZuneVideo_',
'Microsoft.Xbox.TCUI_',
'Microsoft.XboxApp_',
'Microsoft.XboxGameOverlay_',
'Microsoft.XboxGamingOverlay_',
'Microsoft.XboxIdentityProvider_',
'Microsoft.XboxSpeechToTextOverlay_',
'MicrosoftCorporationII.MicrosoftFamily_',
'MicrosoftTeams_',
'MSTeams_',
'Microsoft.549981C3F5F10_',
'Microsoft.Copilot_',
'Microsoft.MSPaint_',
'Microsoft.Paint_',
'Microsoft.YourPhone_',
'Microsoft.WindowsCalculator_',
'Microsoft.WindowsCamera_',
'Microsoft.MicrosoftStickyNotes_',
'Microsoft.Office.OneNote_',
'Microsoft.OneConnect_',
'Microsoft.ConnectivityStore_',
'Microsoft.CommsPhone_',
'Microsoft.ScreenSketch_',
'Microsoft.Gaming.XboxGameCallableUI_',
'MicrosoftWindows.Client.WebExperience_',
'MicrosoftWindows.CrossDevice_'
)
$packagesToRemove = foreach ($pkg in $packages) {
if ($packagePrefixes | Where-Object { $pkg -like "$_*" }) {
$pkg
}
}
foreach ($package in $packagesToRemove) {
Write-Host "Removing $package..."
Remove-AppxProvisionedPackage -Path "$ScratchDisk\scratchdir" -PackageName "$package" | Out-Null
}
Write-Host "Removing Edge..."
# Remove Edge directories
Write-Host "Removing Edge directories..."
if (Test-Path "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\Edge") {
& 'takeown' '/f' "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\Edge" '/r' '/d' 'y' | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\Edge" '/grant' "$($adminGroup.Value):(F)" '/T' '/C' | Out-Null
Remove-Item -Path "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\Edge" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
if (Test-Path "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeUpdate") {
& 'takeown' '/f' "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeUpdate" '/r' '/d' 'y' | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeUpdate" '/grant' "$($adminGroup.Value):(F)" '/T' '/C' | Out-Null
Remove-Item -Path "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeUpdate" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
if (Test-Path "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeCore") {
& 'takeown' '/f' "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeCore" '/r' '/d' 'y' | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeCore" '/grant' "$($adminGroup.Value):(F)" '/T' '/C' | Out-Null
Remove-Item -Path "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeCore" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
# Also check for Edge in Program Files (some installations)
if (Test-Path "$ScratchDisk\scratchdir\Program Files\Microsoft\Edge") {
& 'takeown' '/f' "$ScratchDisk\scratchdir\Program Files\Microsoft\Edge" '/r' '/d' 'y' | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Program Files\Microsoft\Edge" '/grant' "$($adminGroup.Value):(F)" '/T' '/C' | Out-Null
Remove-Item -Path "$ScratchDisk\scratchdir\Program Files\Microsoft\Edge" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
if (Test-Path "$ScratchDisk\scratchdir\Program Files\Microsoft\EdgeUpdate") {
& 'takeown' '/f' "$ScratchDisk\scratchdir\Program Files\Microsoft\EdgeUpdate" '/r' '/d' 'y' | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Program Files\Microsoft\EdgeUpdate" '/grant' "$($adminGroup.Value):(F)" '/T' '/C' | Out-Null
Remove-Item -Path "$ScratchDisk\scratchdir\Program Files\Microsoft\EdgeUpdate" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
# Remove architecture-specific Edge WebView components
if ($architecture -eq 'amd64') {
$folderPath = Get-ChildItem -Path "$ScratchDisk\scratchdir\Windows\WinSxS" -Filter "amd64_microsoft-edge-webview_31bf3856ad364e35*" -Directory -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName
if ($folderPath) {
foreach ($folder in $folderPath) {
if (Test-Path $folder) {
& 'takeown' '/f' $folder '/r' '/d' 'y' | Out-Null
& 'icacls' $folder '/grant' "$($adminGroup.Value):(F)" '/T' '/C' | Out-Null
Remove-Item -Path $folder -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
}
}
else {
Write-Host "AMD64 Edge WebView folder not found."
}
}
elseif ($architecture -eq 'arm64') {
$folderPath = Get-ChildItem -Path "$ScratchDisk\scratchdir\Windows\WinSxS" -Filter "arm64_microsoft-edge-webview_31bf3856ad364e35*" -Directory -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName
if ($folderPath) {
foreach ($folder in $folderPath) {
if (Test-Path $folder) {
& 'takeown' '/f' $folder '/r' '/d' 'y' | Out-Null
& 'icacls' $folder '/grant' "$($adminGroup.Value):(F)" '/T' '/C' | Out-Null
Remove-Item -Path $folder -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
}
}
else {
Write-Host "ARM64 Edge WebView folder not found."
}
}
else {
Write-Host "Unknown architecture: $architecture"
}
# Remove Microsoft Edge WebView directory
#if (Test-Path "$ScratchDisk\scratchdir\Windows\System32\Microsoft-Edge-Webview") {
# & 'takeown' '/f' "$ScratchDisk\scratchdir\Windows\System32\Microsoft-Edge-Webview" '/r' '/d' 'y' | Out-Null
# & 'icacls' "$ScratchDisk\scratchdir\Windows\System32\Microsoft-Edge-Webview" '/grant' "$($adminGroup.Value):(F)" '/T' '/C' | Out-Null
# Remove-Item -Path "$ScratchDisk\scratchdir\Windows\System32\Microsoft-Edge-Webview" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
#}
Write-Host "Removing OneDrive..."
# Remove OneDrive setup file
if (Test-Path "$ScratchDisk\scratchdir\Windows\System32\OneDriveSetup.exe") {
& 'takeown' '/f' "$ScratchDisk\scratchdir\Windows\System32\OneDriveSetup.exe" | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Windows\System32\OneDriveSetup.exe" '/grant' "$($adminGroup.Value):(F)" '/C' | Out-Null
Remove-Item -Path "$ScratchDisk\scratchdir\Windows\System32\OneDriveSetup.exe" -Force -ErrorAction SilentlyContinue | Out-Null
}
if (Test-Path "$ScratchDisk\scratchdir\Windows\SysWOW64\OneDriveSetup.exe") {
& 'takeown' '/f' "$ScratchDisk\scratchdir\Windows\SysWOW64\OneDriveSetup.exe" | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Windows\SysWOW64\OneDriveSetup.exe" '/grant' "$($adminGroup.Value):(F)" '/C' | Out-Null
Remove-Item -Path "$ScratchDisk\scratchdir\Windows\SysWOW64\OneDriveSetup.exe" -Force -ErrorAction SilentlyContinue | Out-Null
}
Write-Host "Removal complete!"
Start-Sleep -Seconds 2
$replaceBranding = $true # Set to $false to skip branding replacement
if ($replaceBranding) {
# Replace basebrd.dll and shellbrd.dll for OEM branding
Write-Host "Replacing basebrd.dll/shellbrd.dll for OEM branding..."
# Take ownership and grant permissions before copying
& 'takeown' '/f' "$ScratchDisk\scratchdir\Windows\Branding\Basebrd\basebrd.dll" | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Windows\Branding\Basebrd\basebrd.dll" '/grant' "$($adminGroup.Value):(F)" '/C' | Out-Null
& 'takeown' '/f' "$ScratchDisk\scratchdir\Windows\Branding\Basebrd\en-US\basebrd.dll.mui" | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Windows\Branding\Basebrd\en-US\basebrd.dll.mui" '/grant' "$($adminGroup.Value):(F)" '/C' | Out-Null
& 'takeown' '/f' "$ScratchDisk\scratchdir\Windows\Branding\shellbrd\shellbrd.dll" | Out-Null
& 'icacls' "$ScratchDisk\scratchdir\Windows\Branding\shellbrd\shellbrd.dll" '/grant' "$($adminGroup.Value):(F)" '/C' | Out-Null
# Now copy the new files
Copy-Item -Path "$PSScriptRoot\includes\branding-resources\system\basebrd.dll" -Destination "$ScratchDisk\scratchdir\Windows\Branding\Basebrd\basebrd.dll" -Force | Out-Null
Copy-Item -Path "$PSScriptRoot\includes\branding-resources\system\basebrd.dll.mui" -Destination "$ScratchDisk\scratchdir\Windows\Branding\Basebrd\en-US\basebrd.dll.mui" -Force | Out-Null
Copy-Item -Path "$PSScriptRoot\includes\branding-resources\system\shellbrd.dll" -Destination "$ScratchDisk\scratchdir\Windows\Branding\shellbrd\shellbrd.dll" -Force | Out-Null
$brandingBootRes = "$PSScriptRoot\includes\branding-resources\system\bootres.dll"
if (Test-Path $brandingBootRes) {
Write-Host "Copying bootres.dll..."
foreach ($bootresPath in @(
"$ScratchDisk\scratchdir\Windows\Boot\EFI\bootres.dll",
"$ScratchDisk\scratchdir\Windows\Boot\PCAT\bootres.dll"
)) {
if (Test-Path $bootresPath) {
& 'takeown' '/f' $bootresPath | Out-Null
& 'icacls' $bootresPath '/grant' "$($adminGroup.Value):(F)" '/C' | Out-Null
Copy-Item -Path $brandingBootRes -Destination $bootresPath -Force | Out-Null
}
}
}
}
Start-Sleep -Seconds 2
Clear-Host
Write-Host "Loading registry..."
reg load HKLM\zCOMPONENTS $ScratchDisk\scratchdir\Windows\System32\config\COMPONENTS | Out-Null
reg load HKLM\zDEFAULT $ScratchDisk\scratchdir\Windows\System32\config\default | Out-Null
reg load HKLM\zNTUSER $ScratchDisk\scratchdir\Users\Default\ntuser.dat | Out-Null
reg load HKLM\zSOFTWARE $ScratchDisk\scratchdir\Windows\System32\config\SOFTWARE | Out-Null
reg load HKLM\zSYSTEM $ScratchDisk\scratchdir\Windows\System32\config\SYSTEM | Out-Null
Write-Host "Bypassing system requirements(on the system image):"
& 'reg' 'add' 'HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV1' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV2' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV1' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV2' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassCPUCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassRAMCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassSecureBootCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassStorageCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassTPMCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\MoSetup' '/v' 'AllowUpgradesWithUnsupportedTPMOrCPU' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\OOBE' '/v' 'BypassNRO' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
Write-Host "Disabling Sponsored Apps:"
& 'reg' 'add' 'HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'OemPreInstalledAppsEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'PreInstalledAppsEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SilentInstalledAppsEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'ContentDeliveryAllowed' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'FeatureManagementEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'PreInstalledAppsEverEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SoftLandingEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SubscribedContentEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SubscribedContent-310093Enabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SubscribedContent-338388Enabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SubscribedContent-338389Enabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SubscribedContent-338393Enabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SubscribedContent-353694Enabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SubscribedContent-353696Enabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SystemPaneSuggestionsEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'delete' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager\Subscriptions' '/f' | Out-Null
& 'reg' 'delete' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager\SuggestedApps' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\PushToInstall' '/v' 'DisablePushToInstall' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\MRT' '/v' 'DontOfferThroughWUAU' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\CloudContent' '/v' 'DisableConsumerAccountStateContent' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\CloudContent' '/v' 'DisableCloudOptimizedContent' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\CloudContent' '/v' 'DisableWindowsConsumerFeatures' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\PolicyManager\current\device\Start' '/v' 'ConfigureStartPins' '/t' 'REG_SZ' '/d' '{"pinnedList": [{}]}' '/f' | Out-Null
Write-Host "Configuring Windows Update to prevent cloud feature injection..."
# Disable feature updates (but allow security)
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' '/v' 'DeferFeatureUpdates' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' '/v' 'DeferFeatureUpdatesPeriodInDays' '/t' 'REG_DWORD' '/d' '365' '/f' | Out-Null
# Disable driver updates from Windows Update (cloud source)
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' '/v' 'ExcludeWUDriversInQualityUpdate' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
Write-Host "Disabling Delivery Optimization (P2P cloud updates)..."
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\DeliveryOptimization' '/v' 'DODownloadMode' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\ControlSet001\Services\DoSvc' '/v' 'Start' '/t' 'REG_DWORD' '/d' '4' '/f' | Out-Null
Write-Host "Disabling Diagnostic Data Viewer..."
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Diagnostics\DiagTrack' '/v' 'ShowedToastAtLevel' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\ControlSet001\Services\DiagTrack' '/v' 'Start' '/t' 'REG_DWORD' '/d' '4' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\ControlSet001\Services\dmwappushservice' '/v' 'Start' '/t' 'REG_DWORD' '/d' '4' '/f' | Out-Null
Write-Host "Disabling Cloud Store sync..."
# Windows.CloudStore.dll data sync
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\SettingSync' '/v' 'DisableSettingSync' '/t' 'REG_DWORD' '/d' '2' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\SettingSync' '/v' 'DisableSettingSyncUserOverride' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
# Per-user cloud sync disable
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\SettingSync' '/v' 'SyncPolicy' '/t' 'REG_DWORD' '/d' '5' '/f' | Out-Null
Write-Host "Disabling Windows Insider Program..."
# Prevents cloud-based preview builds
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\PreviewBuilds' '/v' 'AllowBuildPreview' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\PreviewBuilds' '/v' 'EnableConfigFlighting' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
Write-Host "Disabling Windows Feedback..."
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\DataCollection' '/v' 'DoNotShowFeedbackNotifications' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Siuf\Rules' '/v' 'NumberOfSIUFInPeriod' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Siuf\Rules' '/v' 'PeriodInNanoSeconds' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
Write-Host "Disabling Experimentation and Configuration Service..."
# Prevents A/B testing and cloud-based feature rollouts
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\PolicyManager\current\device\System' '/v' 'AllowExperimentation' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\PolicyManager\default\System\AllowExperimentation' '/v' 'value' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
Write-Host "Disabling Cortana and Search suggestions:"
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Search' '/v' 'BingSearchEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Search' '/v' 'CortanaConsent' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\Windows Search' '/v' 'AllowCortana' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' '/v' 'ShowCortanaButton' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
Write-Host "Enabling Local Accounts on OOBE:"
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\OOBE' '/v' 'BypassNRO' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
Copy-Item -Path "$PSScriptRoot\includes\autounattend-win10.xml" -Destination "$ScratchDisk\scratchdir\Windows\System32\Sysprep\autounattend.xml" -Force | Out-Null
Write-Host "Disabling Reserved Storage:"
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\ReserveManager' '/v' 'ShippedWithReserves' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
Write-Host "Disabling BitLocker Device Encryption"
& 'reg' 'add' 'HKLM\zSYSTEM\ControlSet001\Control\BitLocker' '/v' 'PreventDeviceEncryption' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
Write-Host "Removing Edge related registries"
& 'reg' 'delete' 'HKLM\zSOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft Edge' '/f' | Out-Null
& 'reg' 'delete' 'HKLM\zSOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft Edge Update' '/f' | Out-Null
Write-Host "Disabling OneDrive folder backup"
& 'reg' 'add' "HKLM\zSOFTWARE\Policies\Microsoft\Windows\OneDrive" '/v' 'DisableFileSyncNGSC' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
Write-Host "Disabling Telemetry:"
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\AdvertisingInfo' '/v' 'Enabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\Privacy' '/v' 'TailoredExperiencesWithDiagnosticDataEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Speech_OneCore\Settings\OnlineSpeechPrivacy' '/v' 'HasAccepted' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Input\TIPC' '/v' 'Enabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\InputPersonalization' '/v' 'RestrictImplicitInkCollection' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\InputPersonalization' '/v' 'RestrictImplicitTextCollection' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\InputPersonalization\TrainedDataStore' '/v' 'HarvestContacts' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Personalization\Settings' '/v' 'AcceptedPrivacyPolicy' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\DataCollection' '/v' 'AllowTelemetry' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\ControlSet001\Services\dmwappushservice' '/v' 'Start' '/t' 'REG_DWORD' '/d' '4' '/f' | Out-Null
## Disable Windows Spotlight and tips on lockscreen
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'RotatingLockScreenEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'RotatingLockScreenOverlayEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' '/v' 'SubscribedContent-338387Enabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
## Set default wallpaper and dark mode
Write-Host "Setting default dark mode..."
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' '/v' 'SystemUsesLightTheme' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' '/v' 'AppsUseLightTheme' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' '/v' 'EnableTransparency' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zDEFAULT\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' '/v' 'SystemUsesLightTheme' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zDEFAULT\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' '/v' 'AppsUseLightTheme' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zDEFAULT\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' '/v' 'EnableTransparency' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
Write-Host "Setting up the default wallpaper..."
& 'reg' 'add' 'HKLM\zDEFAULT\Control Panel\Desktop' '/v' 'WallPaper' '/t' 'REG_SZ' '/d' '%SystemRoot%\Windows\Web\Wallpaper\Windows\flooded-city.jpg' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zDEFAULT\Software\Microsoft\Windows\CurrentVersion\Explorer\Wallpapers' '/v' 'BackgroundType' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Control Panel\Desktop' '/v' 'WallPaper' '/t' 'REG_SZ' '/d' '%SystemRoot%\Windows\Web\Wallpaper\Windows\flooded-city.jpg' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\Explorer\Wallpapers' '/v' 'BackgroundType' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
Write-Host "Setting up the default lockscreen..."
& 'reg' 'add' 'HKLM\zDEFAULT\Software\Microsoft\Windows\CurrentVersion\Personalization' '/v' 'LockScreenImage' '/t' 'REG_SZ' '/d' '%SystemRoot%\Windows\Web\Wallpaper\Windows\leafy-greens.jpg' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\Personalization' '/v' 'LockScreenImage' '/t' 'REG_SZ' '/d' '%SystemRoot%\Windows\Web\Wallpaper\Windows\leafy-greens.jpg' '/f' | Out-Null
## this function allows PowerShell to take ownership of the Scheduled Tasks registry key from TrustedInstaller. Based on Jose Espitia's script.
function Enable-Privilege {
param(
[ValidateSet(
"SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege",
"SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege",
"SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
"SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
"SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege",
"SeLockMemoryPrivilege", "SeMachineAccountPrivilege", "SeManageVolumePrivilege",
"SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege",
"SeRestorePrivilege", "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege",
"SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", "SeSystemtimePrivilege",
"SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
"SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
$Privilege,
## The process on which to adjust the privilege. Defaults to the current process.
$ProcessId = $pid,
## Switch to disable the privilege, rather than enable it.
[Switch] $Disable
)
$definition = @'
using System;
using System.Runtime.InteropServices;
public class AdjPriv
{
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = new IntPtr(processHandle);
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
if(disable)
{
tp.Attr = SE_PRIVILEGE_DISABLED;
}
else
{
tp.Attr = SE_PRIVILEGE_ENABLED;
}
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
}
'@
$processHandle = (Get-Process -id $ProcessId).Handle
$type = Add-Type $definition -PassThru
$type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)
}
Enable-Privilege SeTakeOwnershipPrivilege
$regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks", [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
$regACL = $regKey.GetAccessControl()
$regACL.SetOwner($adminGroup)
$regKey.SetAccessControl($regACL)
$regKey.Close()
Write-Host "Owner changed to Administrators."
$regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks", [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::ChangePermissions)
$regACL = $regKey.GetAccessControl()
$regRule = New-Object System.Security.AccessControl.RegistryAccessRule ($adminGroup, "FullControl", "ContainerInherit", "None", "Allow")
$regACL.SetAccessRule($regRule)
$regKey.SetAccessControl($regACL)
Write-Host "Permissions modified for Administrators group."
Write-Host "Registry key permissions successfully updated."
$regKey.Close()
# Take ownership of Explorer Advanced settings
Write-Host "Taking ownership of Explorer Advanced settings..."
$regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("zNTUSER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced", [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
$regACL = $regKey.GetAccessControl()
$regACL.SetOwner($adminGroup)
$regKey.SetAccessControl($regACL)
$regKey.Close()
Write-Host "Explorer Advanced owner changed to Administrators."
$regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("zNTUSER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced", [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::ChangePermissions)
$regACL = $regKey.GetAccessControl()
$regRule = New-Object System.Security.AccessControl.RegistryAccessRule ($adminGroup, "FullControl", "ContainerInherit", "None", "Allow")
$regACL.SetAccessRule($regRule)
$regKey.SetAccessControl($regACL)
Write-Host "Explorer Advanced permissions modified for Administrators group."
Write-Host "Explorer Advanced registry key permissions successfully updated."
$regKey.Close()
# Clean up settings menu (Windows 10 specific paths)
Write-Host "Cleaning up Settings menu..."
& 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer' '/v' 'SettingsPageVisibility' '/t' 'REG_SZ' '/d' 'hide:gaming;cortana;search;maps;yourinfo;workplace;backup;sync;findmydevice;developers;activation' '/f' | Out-Null
# Delete scheduled tasks (with error suppression for missing keys)
Write-Host 'Deleting Application Compatibility Appraiser...'
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{0600DD45-FAF2-4131-A006-0B17509B9F78}' '/f' 2>$null | Out-Null
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{A0C71CB8-E8F0-498A-901D-4EDA09E07FF4}' '/f' 2>$null | Out-Null
Write-Host 'Deleting Customer Experience Improvement Program...'
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{4738DE7A-BCC1-4E2D-B1B0-CADB044BFA81}' '/f' 2>$null | Out-Null
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{6FAC31FA-4A85-4E64-BFD5-2154FF4594B3}' '/f' 2>$null | Out-Null
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{FC931F16-B50A-472E-B061-B6F79A71EF59}' '/f' 2>$null | Out-Null
Write-Host 'Deleting Program Data Updater...'
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{0671EB05-7D95-4153-A32B-1426B9FE61DB}' '/f' 2>$null | Out-Null
Write-Host 'Deleting autochk proxy...'
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{87BF85F4-2CE1-4160-96EA-52F554AA28A2}' '/f' 2>$null | Out-Null
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{8A9C643C-3D74-4099-B6BD-9C6D170898B1}' '/f' 2>$null | Out-Null
Write-Host 'Deleting QueueReporting...'
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{E3176A65-4E44-4ED3-AA73-3283660ACB9C}' '/f' 2>$null | Out-Null
& 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{6FD85B93-7A13-4DCA-B793-1D7D18FEAC39}' '/f' 2>$null | Out-Null
Write-Host "Tweaking complete!"
Write-Host "Unmounting Registry..."
$regKey.Close()
reg unload HKLM\zCOMPONENTS | Out-Null
reg unload HKLM\zDRIVERS | Out-Null
reg unload HKLM\zDEFAULT | Out-Null
reg unload HKLM\zNTUSER | Out-Null
reg unload HKLM\zSOFTWARE | Out-Null
reg unload HKLM\zSYSTEM | Out-Null
Write-Host "Cleaning up image..."
dism.exe /Image:$ScratchDisk\scratchdir /Cleanup-Image /StartComponentCleanup /ResetBase
Write-Host "Cleanup complete."
Write-Host ' '
Write-Host "Unmounting image..."
Dismount-WindowsImage -Path $ScratchDisk\scratchdir -Save
Write-Host "Exporting image..."
# Run `Export-WindowsImage` with undocumented CompressionType "LZMS" (which is the same compression used for Recovery from dism.exe)
Export-WindowsImage -SourceImagePath "$ScratchDisk\tiny10\sources\install.wim" -SourceIndex $index -DestinationImagePath "$ScratchDisk\tiny10\sources\install2.wim" -CompressionType "LZMS"
Move-Item -Path "$ScratchDisk\tiny10\sources\install2.wim" -Destination "$ScratchDisk\tiny10\sources\install.wim" -Force | Out-Null
Write-Host "Windows image completed. Continuing with boot.wim."
Start-Sleep -Seconds 2
Clear-Host
Write-Host "Mounting boot image:"
$wimFilePath = "$ScratchDisk\tiny10\sources\boot.wim"
& takeown "/F" $wimFilePath | Out-Null
& icacls $wimFilePath "/grant" "$($adminGroup.Value):(F)"
Set-ItemProperty -Path $wimFilePath -Name IsReadOnly -Value $false
Mount-WindowsImage -ImagePath $ScratchDisk\tiny10\sources\boot.wim -Index 2 -Path $ScratchDisk\scratchdir
Write-Host "Loading registry..."
reg load HKLM\zCOMPONENTS $ScratchDisk\scratchdir\Windows\System32\config\COMPONENTS
reg load HKLM\zDEFAULT $ScratchDisk\scratchdir\Windows\System32\config\default
reg load HKLM\zNTUSER $ScratchDisk\scratchdir\Users\Default\ntuser.dat
reg load HKLM\zSOFTWARE $ScratchDisk\scratchdir\Windows\System32\config\SOFTWARE
reg load HKLM\zSYSTEM $ScratchDisk\scratchdir\Windows\System32\config\SYSTEM
Write-Host "Bypassing system requirements(on the setup image)..."
& 'reg' 'add' 'HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV1' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV2' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV1' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV2' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassCPUCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassRAMCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassSecureBootCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassStorageCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassTPMCheck' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
& 'reg' 'add' 'HKLM\zSYSTEM\Setup\MoSetup' '/v' 'AllowUpgradesWithUnsupportedTPMOrCPU' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null
Write-Host "Tweaking complete! Unmounting Registry..."
$regKey.Close()
reg unload HKLM\zCOMPONENTS | Out-Null
reg unload HKLM\zDRIVERS | Out-Null
reg unload HKLM\zDEFAULT | Out-Null
reg unload HKLM\zNTUSER | Out-Null
$regKey.Close()
reg unload HKLM\zSOFTWARE | Out-Null
reg unload HKLM\zSYSTEM | Out-Null
if ($replaceBranding -and (Test-Path $brandingBootRes)) {
Write-Host "Copying bootres.dll to boot image..."
foreach ($bootresPath in @(
"$ScratchDisk\scratchdir\Windows\Boot\EFI\bootres.dll",
"$ScratchDisk\scratchdir\Windows\Boot\PCAT\bootres.dll",
"$ScratchDisk\scratchdir\Windows\Boot\Resources\bootres.dll"
)) {
if (Test-Path $bootresPath) {
& 'takeown' '/f' $bootresPath | Out-Null
& 'icacls' $bootresPath '/grant' "$($adminGroup.Value):(F)" '/C' | Out-Null
Copy-Item -Path $brandingBootRes -Destination $bootresPath -Force | Out-Null
}
}
}
# Change the background.bmp in the sources folder of the boot image
& takeown "/F" "$ScratchDisk\scratchdir\sources\background.bmp" | Out-Null
& icacls "$ScratchDisk\scratchdir\sources\background.bmp" "/grant" "$($adminGroup.Value):(F)"
Remove-Item -Path "$ScratchDisk\scratchdir\sources\background.bmp" -Force | Out-Null
Copy-Item -Path "$PSScriptRoot\includes\setup-bg.bmp" -Destination "$ScratchDisk\scratchdir\sources\background.bmp" -Force | Out-Null
# Change the setup.bmp in the system32 folder of the boot image
& takeown "/F" "$ScratchDisk\scratchdir\Windows\system32\setup.bmp" | Out-Null
& icacls "$ScratchDisk\scratchdir\Windows\system32\setup.bmp" "/grant" "$($adminGroup.Value):(F)"
Remove-Item -Path "$ScratchDisk\scratchdir\Windows\system32\setup.bmp" -Force | Out-Null
Copy-Item -Path "$PSScriptRoot\includes\setup-bg.bmp" -Destination "$ScratchDisk\scratchdir\Windows\system32\setup.bmp" -Force | Out-Null
& takeown "/F" "$ScratchDisk\scratchdir\sources\spwizimg.dll" | Out-Null
& icacls "$ScratchDisk\scratchdir\sources\spwizimg.dll" "/grant" "$($adminGroup.Value):(F)"
# Copy in new spwizimg.dll with custom spwizimg.dll resource if it exists
if (Test-Path -Path "$PSScriptRoot\includes\spwizimg.dll") {
Write-Host "Custom spwizimg.dll found. Replacing in boot image..."
Copy-Item -Path "$PSScriptRoot\includes\spwizimg.dll" -Destination "$ScratchDisk\scratchdir\sources\spwizimg.dll" -Force | Out-Null
}
# If there is a spwizimg-resources folder, use the resources inside to modify spwizimg.dll
elseif (Test-Path -Path "$PSScriptRoot\includes\branding-resources\spwizimg-resources\" ) {
Write-Host "Custom spwizimg-resources folder found. Modifying spwizimg.dll in boot image..."
$resourceFiles = Get-ChildItem -Path "$PSScriptRoot\includes\branding-resources\spwizimg-resources\" -File
# Create a copy of spwizimg.dll to work on
Copy-Item -Path "$ScratchDisk\scratchdir\sources\spwizimg.dll" -Destination "$ScratchDisk\scratchdir\sources\spwizimg-temp.dll" -Force | Out-Null
foreach ($resourceFile in $resourceFiles) {
$resourceName = $resourceFile.Name
$resourcePath = $resourceFile.FullName
# Extract resource ID from the filename (format: 405.png)
if ($resourceName -match "^(\d+)\.png$") {
# If the name is "setup-bg.png", set resource ID to 517
if ($resourceName -eq "setup-bg.png") {
$resourceId = 517
} else {
$resourceId = $matches[1]
}
# Use Resource Hacker to add/overwrite the resource in spwizimg.dll
Start-Process -FilePath "$PSScriptRoot\includes\utils\ResourceHacker.exe" -ArgumentList `
"-open `"$ScratchDisk\scratchdir\sources\spwizimg-temp.dll`"", `
"-save `"$ScratchDisk\scratchdir\sources\spwizimg-temp.dll2`"", `
"-action addoverwrite", `
"-resource `"$resourcePath`"", `
"-mask PNG,$resourceId,1033" `
-NoNewWindow -Wait
# Replace the temp dll with the modified one for the next iteration
Remove-Item -Path "$ScratchDisk\scratchdir\sources\spwizimg-temp.dll" -Force | Out-Null
Rename-Item -Path "$ScratchDisk\scratchdir\sources\spwizimg-temp.dll2" -NewName "spwizimg-temp.dll" | Out-Null
}
}
# After all resources have been processed, replace the original spwizimg.dll
Remove-Item -Path "$ScratchDisk\scratchdir\sources\spwizimg.dll" -Force | Out-Null
Rename-Item -Path "$ScratchDisk\scratchdir\sources\spwizimg-temp.dll" -NewName "spwizimg.dll" | Out-Null
}
# If no custom spwizimg.dll or spwizimg-resources folder, just replace the setup background image
else {
Write-Host "No custom spwizimg.dll or resources found. Replacing setup background image in spwizimg.dll..."
Start-Process -FilePath "$PSScriptRoot\includes\utils\ResourceHacker.exe" -ArgumentList `
"-open `"$ScratchDisk\scratchdir\sources\spwizimg.dll`"", `
"-save `"$ScratchDisk\scratchdir\sources\spwizimg.dll2`"", `
"-action addoverwrite", `
"-resource `"$PSScriptRoot\includes\branding-resources\spwizimg-resources\setup-bg.png`"", `
"-mask IMAGE,517,1033" `
-NoNewWindow -Wait
Remove-Item -Path "$ScratchDisk\scratchdir\sources\spwizimg.dll" -Force | Out-Null
Rename-Item -Path "$ScratchDisk\scratchdir\sources\spwizimg.dll2" -NewName "spwizimg.dll" | Out-Null
}
Write-Host "Unmounting image..."
Dismount-WindowsImage -Path $ScratchDisk\scratchdir -Save
Clear-Host
Write-Host "The tiny10 image is now completed. Proceeding with the making of the ISO..."
Write-Host "Copying unattended file for bypassing MS account on OOBE..."
Copy-Item -Path "$PSScriptRoot\includes\autounattend-win10.xml" -Destination "$ScratchDisk\tiny10\autounattend.xml" -Force | Out-Null
# If there is a $OEM$ folder, copy it to the setup image
if (Test-Path -Path "${PSScriptRoot}\includes\`$OEM$") {
Write-Host 'Adding $OEM$ to the setup image...'
Copy-Item -Path "${PSScriptRoot}\includes\`$OEM$" -Destination "$ScratchDisk\tiny10\sources\`$OEM$" -Recurse -Force | Out-Null
if (Test-Path "$PSScriptRoot\includes\utils\multi-staller\dist\MultiStaller.exe") {
Copy-Item -Path "$PSScriptRoot\includes\utils\multi-staller\dist\MultiStaller.exe" -Destination "$ScratchDisk\tiny10\sources\`$OEM$\`$$\OEM\" -Force | Out-Null
}
}
# If there is a WinPE_Drivers folder, copy it to the setup image
if (Test-Path -Path "${PSScriptRoot}\includes\WinPE_Drivers") {
Write-Host 'Adding WinPE_Drivers to the setup image...'
Copy-Item -Path "${PSScriptRoot}\includes\WinPE_Drivers" -Destination "$ScratchDisk\tiny10\WinPE_Drivers" -Recurse -Force | Out-Null
}
# Change the setup background bmp in the sources folder
Write-Host "Changing setup background image in setup image..."
& takeown "/F" "$ScratchDisk\tiny10\sources\background_cli.bmp" | Out-Null
& icacls "$ScratchDisk\tiny10\sources\background_cli.bmp" "/grant" "$($adminGroup.Value):(F)"
if (Test-Path "$PSScriptRoot\includes\branding-resources\setup-bg.bmp") {
Copy-Item -Path "$PSScriptRoot\includes\branding-resources\setup-bg.bmp" -Destination "$ScratchDisk\tiny10\sources\background_cli2.bmp" -Force | Out-Null
Remove-Item -Path "$ScratchDisk\tiny10\sources\background_cli.bmp" -Force | Out-Null
Rename-Item -Path "$ScratchDisk\tiny10\sources\background_cli2.bmp" -NewName "background_cli.bmp" | Out-Null
}
# Change the setup image spwizimg.dll in the sources folder
& takeown "/F" "$ScratchDisk\tiny10\sources\spwizimg.dll" | Out-Null
& icacls "$ScratchDisk\tiny10\sources\spwizimg.dll" "/grant" "$($adminGroup.Value):(F)"
# Copy in new spwizimg.dll with custom spwizimg.dll resource if it exists
if (Test-Path -Path "$PSScriptRoot\includes\spwizimg.dll") {
Write-Host "Custom spwizimg.dll found. Replacing in setup image..."
Copy-Item -Path "$PSScriptRoot\includes\spwizimg.dll" -Destination "$ScratchDisk\tiny10\sources\spwizimg.dll" -Force | Out-Null
}
# If there is a spwizimg-resources folder, use the resources inside to modify spwizimg.dll
elseif (Test-Path -Path "$PSScriptRoot\includes\spwizimg-res\") {
Write-Host "Custom spwizimg-resources folder found. Modifying spwizimg.dll in setup image..."
$resourceFiles = Get-ChildItem -Path "$PSScriptRoot\includes\branding-resources\spwizimg-resources\" -File
# Create a copy of spwizimg.dll to work on
Copy-Item -Path "$ScratchDisk\tiny10\sources\spwizimg.dll" -Destination "$ScratchDisk\tiny10\sources\spwizimg-temp.dll" -Force | Out-Null
foreach ($resourceFile in $resourceFiles) {
$resourceName = $resourceFile.Name
$resourcePath = $resourceFile.FullName
# Extract resource ID from the filename (format: 405.png)
if ($resourceName -match "^(\d+)\.png$") {
# If the name is "setup-bg.png", set resource ID to 517
if ($resourceName -eq "setup-bg.png") {
$resourceId = 517
} else {
$resourceId = $matches[1]
}
# Use Resource Hacker to add/overwrite the resource in spwizimg.dll
Start-Process -FilePath "$PSScriptRoot\includes\utils\ResourceHacker.exe" -ArgumentList `
"-open `"$ScratchDisk\tiny10\sources\spwizimg-temp.dll`"", `
"-save `"$ScratchDisk\tiny10\sources\spwizimg-temp.dll2`"", `
"-action addoverwrite", `
"-resource `"$resourcePath`"", `
"-mask PNG,$resourceId,1033" `
-NoNewWindow -Wait
# Replace the temp dll with the modified one for the next iteration
Remove-Item -Path "$ScratchDisk\tiny10\sources\spwizimg-temp.dll" -Force | Out-Null
Rename-Item -Path "$ScratchDisk\tiny10\sources\spwizimg-temp.dll2" -NewName "spwizimg-temp.dll" | Out-Null
}
}
# After all resources have been processed, replace the original spwizimg.dll
Remove-Item -Path "$ScratchDisk\tiny10\sources\spwizimg.dll" -Force | Out-Null
Rename-Item -Path "$ScratchDisk\tiny10\sources\spwizimg-temp.dll" -NewName "spwizimg.dll" | Out-Null
}
# If no custom spwizimg.dll or spwizimg-resources folder, just replace the setup background image
else {
Write-Host "No custom spwizimg.dll or resources found. Replacing setup background image in spwizimg.dll..."
Start-Process -FilePath "$PSScriptRoot\includes\utils\ResourceHacker.exe" -ArgumentList `
"-open `"$ScratchDisk\tiny10\sources\spwizimg.dll`"", `
"-save `"$ScratchDisk\tiny10\sources\spwizimg.dll2`"", `
"-action addoverwrite", `
"-resource `"$PSScriptRoot\includes\branding-resources\spwizimg-resources\setup-bg.png`"", `
"-mask IMAGE,517,1033" `
-NoNewWindow -Wait
Remove-Item -Path "$ScratchDisk\tiny10\sources\spwizimg.dll" -Force | Out-Null
Rename-Item -Path "$ScratchDisk\tiny10\sources\spwizimg.dll2" -NewName "spwizimg.dll" | Out-Null
}
# Add additional install.wim or install.esd files to the main install.wim
Write-Host "Checking for additional install.wim or install.esd files..."
$additionalWIM = Get-Item "$PSScriptRoot\includes\install.wim" -ErrorAction SilentlyContinue
$additionalESD = Get-Item "$PSScriptRoot\includes\install.esd" -ErrorAction SilentlyContinue
# Define the main install.wim path
$mainWIM = "$ScratchDisk\tiny10\sources\install.wim"
if ($additionalWIM) {
Write-Host "Additional WIM file found: $($additionalWIM.FullName). Adding it to the main install.wim..."
# Get all images from the additional WIM and add them
$additionalImages = Get-WindowsImage -ImagePath $additionalWIM.FullName
foreach ($imageInfo in $additionalImages) {
$imageIndex = $imageInfo.ImageIndex
$imageName = $imageInfo.ImageName
Write-Host "Adding image $imageIndex`: $imageName from WIM file..."
& 'dism' '/Export-Image' "/SourceImageFile:$($additionalWIM.FullName)" "/SourceIndex:$imageIndex" "/DestinationImageFile:$mainWIM" '/Compress:max' '/CheckIntegrity'
}
Write-Host "Successfully added all images from $($additionalWIM.FullName) to the main install.wim."
}
if ($additionalESD) {
Write-Host "Additional ESD file found: $($additionalESD.FullName). Adding it to the main install.wim..."
# Get all images from the additional ESD and add them
$additionalImages = Get-WindowsImage -ImagePath $additionalESD.FullName
foreach ($imageInfo in $additionalImages) {
$imageIndex = $imageInfo.ImageIndex
$imageName = $imageInfo.ImageName
Write-Host "Adding image $imageIndex`: $imageName from ESD file..."
& 'dism' '/Export-Image' "/SourceImageFile:$($additionalESD.FullName)" "/SourceIndex:$imageIndex" "/DestinationImageFile:$mainWIM" '/Compress:max' '/CheckIntegrity'
}
Write-Host "Successfully added all images from $($additionalESD.FullName) to the main install.wim."
}
if (-not $additionalWIM -and -not $additionalESD) {
Write-Host "No additional WIM or ESD files found."
}
# convert the install.wim to install.esd
Write-Host "Converting install.wim to install.esd..."
# Get all image indexes from the install.wim
$allImages = Get-WindowsImage -ImagePath "$ScratchDisk\tiny10\sources\install.wim"
Write-Host "Found $($allImages.Count) image(s) in install.wim"
# Export all images to install.esd using DISM.exe (since PowerShell DISM module doesn't support Recovery compression)
foreach ($imageInfo in $allImages) {
$currentIndex = $imageInfo.ImageIndex
$imageName = $imageInfo.ImageName
Write-Host "Exporting image $currentIndex`: $imageName..."
if ($currentIndex -eq $allImages[0].ImageIndex) {
# First image - create new install.esd in the working directory
& dism /English /Export-Image "/SourceImageFile:$ScratchDisk\tiny10\sources\install.wim" "/SourceIndex:$currentIndex" "/DestinationImageFile:$ScratchDisk\tiny10\sources\install.esd" /Compress:recovery /CheckIntegrity
}
else {
# Subsequent images - append to existing install.esd
& dism /English /Export-Image "/SourceImageFile:$ScratchDisk\tiny10\sources\install.wim" "/SourceIndex:$currentIndex" "/DestinationImageFile:$ScratchDisk\tiny10\sources\install.esd" /Compress:recovery /CheckIntegrity
}
}
Remove-Item -Path "$ScratchDisk\tiny10\sources\install.wim" -Force | Out-Null
Write-Host "All images converted from install.wim to install.esd successfully."
Write-Host "Creating ISO image..."
# Get Windows ADK path from registry(following Visual Studio's winsdk.bat approach).
$WinSDKPath = [Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots", "KitsRoot10", $null)
if ($null -eq $WinSDKPath) {
$WinSDKPath = [Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots", "KitsRoot10", $null)
}
if ($null -ne $WinSDKPath) {
# Trim the following backslash for path concatenation.
$WinSDKPath = $WinSDKPath.TrimEnd('\')
$ADKDepTools = "$WinSDKPath\Assessment and Deployment Kit\Deployment Tools\$hostarchitecture\Oscdimg"
}
$localOSCDIMGPath = "$PSScriptRoot\oscdimg.exe"
if ((Test-Path variable:ADKDepTools) -and (Test-Path "$ADKDepTools\oscdimg.exe" -PathType leaf)) {
Write-Host "Will be using oscdimg.exe from system ADK."
$OSCDIMG = "$ADKDepTools\oscdimg.exe"
}
else {
Write-Host "oscdimg.exe from system ADK not found. Will be using bundled oscdimg.exe."
$url = "https://msdl.microsoft.com/download/symbols/oscdimg.exe/3D44737265000/oscdimg.exe"
if (![System.IO.File]::Exists($localOSCDIMGPath)) {
Write-Host "Downloading oscdimg.exe..."
Invoke-WebRequest -Uri $url -OutFile $localOSCDIMGPath
if ([System.IO.File]::Exists($localOSCDIMGPath)) {
Write-Host "oscdimg.exe downloaded successfully."
}
else {
Write-Error "Failed to download oscdimg.exe."
exit 1
}
}
else {
Write-Host "oscdimg.exe already exists locally."
}
$OSCDIMG = $localOSCDIMGPath
}
& "$OSCDIMG" "-lTiny10_$architecture" '-m' '-o' '-u2' '-udfver102' "-bootdata:2#p0,e,b$ScratchDisk\tiny10\boot\etfsboot.com#pEF,e,b$ScratchDisk\tiny10\efi\microsoft\boot\efisys.bin" "$ScratchDisk\tiny10" "$PSScriptRoot\tiny10.iso"
# Finishing up
Write-Host "Creation completed! Performing Cleanup..."
Remove-Item -Path "$ScratchDisk\tiny10" -Recurse -Force | Out-Null
Remove-Item -Path "$ScratchDisk\scratchdir" -Recurse -Force | Out-Null
# Unmount ISO if we auto-mounted it
if ($mountedISO) {
Write-Host "Unmounting ISO: $mountedISO"
Dismount-DiskImage -ImagePath $mountedISO -ErrorAction SilentlyContinue | Out-Null
Write-Host "ISO unmounted."
}
# Stop the transcript
Stop-Transcript
exit