diff --git a/functions/private/Invoke-WinUtilISO.ps1 b/functions/private/Invoke-WinUtilISO.ps1 index a5a0a420..412e6963 100644 --- a/functions/private/Invoke-WinUtilISO.ps1 +++ b/functions/private/Invoke-WinUtilISO.ps1 @@ -269,6 +269,17 @@ function Invoke-WinUtilISOModify { $sync["WPFWin11ISOModifySection"].Visibility = "Collapsed" $expandedHeight = [Math]::Max(400, $sync.Window.ActualHeight - 100) $sync["WPFWin11ISOStatusLog"].Height = $expandedHeight + $sync["Win11ISOLogExpanded"] = $true + # Register the resize handler once so the log tracks window resizes + if (-not $sync["Win11ISOResizeHandlerAdded"]) { + $sync.Window.add_SizeChanged({ + if ($sync["Win11ISOLogExpanded"]) { + $sync["WPFWin11ISOStatusLog"].Height = [Math]::Max(400, $sync.Window.ActualHeight - 100) + $sync["WPFWin11ISOStatusLog"].ScrollToEnd() + } + }) + $sync["Win11ISOResizeHandlerAdded"] = $true + } }) # ── 1. Create working directory structure ── @@ -303,11 +314,38 @@ function Invoke-WinUtilISOModify { Log "Applying WinUtil modifications to install.wim..." Invoke-WinUtilISOScript -ScratchDir $mountDir -ISOContentsDir $isoContents -AutoUnattendXml $autounattendContent -Log { param($m) Log $m } + # ── 4b. DISM component store cleanup ── + # /ResetBase removes all superseded component versions from WinSxS, + # which is the single largest space saving possible (typically 300–800 MB). + # This must be done while the image is still mounted. + SetProgress "Cleaning up component store (WinSxS)..." 56 + Log "Running DISM component store cleanup (/ResetBase)..." + & dism /English "/image:$mountDir" /Cleanup-Image /StartComponentCleanup /ResetBase | ForEach-Object { Log $_ } + Log "Component store cleanup complete." + # ── 5. Save and dismount the WIM ── SetProgress "Saving modified install.wim..." 65 - Log "Dismounting and saving install.wim..." + Log "Dismounting and saving install.wim. This will take several minutes..." Dismount-WindowsImage -Path $mountDir -Save -ErrorAction Stop | Out-Null Log "install.wim saved." + + # ── 5b. Strip unused editions — export only the selected index ── + # A standard multi-edition install.wim can be 4–5 GB; exporting a + # single index typically drops it to ~3 GB, saving 1–2 GB in the ISO. + SetProgress "Removing unused editions from install.wim..." 70 + Log "Exporting edition '$selectedEditionName' (Index $selectedWimIndex) to a single-edition install.wim..." + $exportWim = Join-Path $isoContents "sources\install_export.wim" + Export-WindowsImage ` + -SourceImagePath $localWim ` + -SourceIndex $selectedWimIndex ` + -DestinationImagePath $exportWim ` + -ErrorAction Stop | Out-Null + Remove-Item -Path $localWim -Force + Rename-Item -Path $exportWim -NewName "install.wim" -Force + # Update local path so later steps (e.g. ISO build) reference the new file + $localWim = Join-Path $isoContents "sources\install.wim" + Log "Unused editions removed. install.wim now contains only '$selectedEditionName'." + SetProgress "Dismounting source ISO..." 80 # ── 6. Dismount the original ISO ── @@ -388,6 +426,7 @@ function Invoke-WinUtilISOModify { $sync["WPFWin11ISOMountSection"].Visibility = "Visible" $sync["WPFWin11ISOModifySection"].Visibility = "Visible" } + $sync["Win11ISOLogExpanded"] = $false $sync["WPFWin11ISOStatusLog"].Height = 140 }) } diff --git a/functions/private/Invoke-WinUtilISOScript.ps1 b/functions/private/Invoke-WinUtilISOScript.ps1 index 62255c33..0f05b632 100644 --- a/functions/private/Invoke-WinUtilISOScript.ps1 +++ b/functions/private/Invoke-WinUtilISOScript.ps1 @@ -255,6 +255,10 @@ function Invoke-WinUtilISOScript { _ISOScript-SetReg 'HKLM\zSOFTWARE\Policies\Microsoft\Edge' 'HubsSidebarEnabled' 'REG_DWORD' '0' _ISOScript-SetReg 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\Explorer' 'DisableSearchBoxSuggestions' 'REG_DWORD' '1' + & $Log "Disabling Windows Update during OOBE (re-enabled on first logon via FirstLogon.ps1)..." + _ISOScript-SetReg 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' 'NoAutoUpdate' 'REG_DWORD' '1' + _ISOScript-SetReg 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' 'DisableWindowsUpdateAccess' 'REG_DWORD' '1' + & $Log "Preventing installation of Teams..." _ISOScript-SetReg 'HKLM\zSOFTWARE\Policies\Microsoft\Teams' 'DisableInstallation' 'REG_DWORD' '1' @@ -281,5 +285,13 @@ function Invoke-WinUtilISOScript { Remove-Item "$tasksPath\Microsoft\Windows\Windows Error Reporting\QueueReporting" -Force -ErrorAction SilentlyContinue & $Log "Scheduled task files deleted." -} + # ═════════════════════════════════════════════════════════════════════════ + # 6. Remove ISO support folder (fresh-install only; not needed) + # ═════════════════════════════════════════════════════════════════════════ + if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) { + & $Log "Removing ISO support\ folder..." + Remove-Item -Path (Join-Path $ISOContentsDir "support") -Recurse -Force -ErrorAction SilentlyContinue + & $Log "ISO support\ folder removed." + } +} diff --git a/tools/autounattend.xml b/tools/autounattend.xml index b5a9ffcb..3ffc4d91 100644 --- a/tools/autounattend.xml +++ b/tools/autounattend.xml @@ -1,239 +1,499 @@ - - - - + + + - - - - - - - false - - - - - - false - OnError - - - - /IMAGE/NAME - Windows 11 Pro - - - - - - + - true - - OnError + 00000-00000-00000-00000-00000 + Always + true - + false + + + 1 + reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassTPMCheck /t REG_DWORD /d 1 /f + + + 2 + reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassSecureBootCheck /t REG_DWORD /d 1 /f + + + 3 + reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassRAMCheck /t REG_DWORD /d 1 /f + + - - + - - - - - * - - - UTC - - - false - + + + + 1 + powershell.exe -WindowStyle "Normal" -NoProfile -Command "$xml = [xml]::new(); $xml.Load('C:\Windows\Panther\unattend.xml'); $sb = [scriptblock]::Create( $xml.unattend.Extensions.ExtractScript ); Invoke-Command -ScriptBlock $sb -ArgumentList $xml;" + + + 2 + powershell.exe -WindowStyle "Normal" -ExecutionPolicy "Unrestricted" -NoProfile -File "C:\Windows\Setup\Scripts\Specialize.ps1" + + + 3 + reg.exe load "HKU\DefaultUser" "C:\Users\Default\NTUSER.DAT" + + + 4 + powershell.exe -WindowStyle "Normal" -ExecutionPolicy "Unrestricted" -NoProfile -File "C:\Windows\Setup\Scripts\DefaultUser.ps1" + + + 5 + reg.exe unload "HKU\DefaultUser" + + - - - - 0 - - - - + + - - - + - - true - - - - - - false - - - true - - - true - - 3 + true + true + true - - - - - + + + 1 + powershell.exe -WindowStyle "Normal" -ExecutionPolicy "Unrestricted" -NoProfile -File "C:\Windows\Setup\Scripts\FirstLogon.ps1" + + + + +param( + [xml]$Document +); +foreach( $file in $Document.unattend.Extensions.File ) { + $path = [System.Environment]::ExpandEnvironmentVariables( $file.GetAttribute( 'path' ) ); + mkdir -Path( $path | Split-Path -Parent ) -ErrorAction 'SilentlyContinue'; + $encoding = switch( [System.IO.Path]::GetExtension( $path ) ) { + { $_ -in '.ps1', '.xml' } { [System.Text.Encoding]::UTF8; } + { $_ -in '.reg', '.vbs', '.js' } { [System.Text.UnicodeEncoding]::new( $false, $true ); } + default { [System.Text.Encoding]::Default; } + }; + $bytes = $encoding.GetPreamble() + $encoding.GetBytes( $file.InnerText.Trim() ); + [System.IO.File]::WriteAllBytes( $path, $bytes ); +} + + +<LayoutModificationTemplate xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification" xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout" xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout" xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout" Version="1"> + <CustomTaskbarLayoutCollection PinListPlacement="Replace"> + <defaultlayout:TaskbarLayout> + <taskbar:TaskbarPinList> + <taskbar:DesktopApp DesktopApplicationLinkPath="#leaveempty" /> + </taskbar:TaskbarPinList> + </defaultlayout:TaskbarLayout> + </CustomTaskbarLayoutCollection> +</LayoutModificationTemplate> + + +HKU = &H80000003 +Set reg = GetObject("winmgmts://./root/default:StdRegProv") +Set fso = CreateObject("Scripting.FileSystemObject") + +If reg.EnumKey(HKU, "", sids) = 0 Then + If Not IsNull(sids) Then + For Each sid In sids + key = sid + "\Software\Policies\Microsoft\Windows\Explorer" + name = "LockedStartLayout" + If reg.GetDWORDValue(HKU, key, name, existing) = 0 Then + reg.SetDWORDValue HKU, key, name, 0 + End If + Next + End If +End If + + +<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> + <Triggers> + <EventTrigger> + <Enabled>true</Enabled> + <Subscription>&lt;QueryList&gt;&lt;Query Id="0" Path="Application"&gt;&lt;Select Path="Application"&gt;*[System[Provider[@Name='UnattendGenerator'] and EventID=1]]&lt;/Select&gt;&lt;/Query&gt;&lt;/QueryList&gt;</Subscription> + </EventTrigger> + </Triggers> + <Principals> + <Principal id="Author"> + <UserId>S-1-5-18</UserId> + <RunLevel>LeastPrivilege</RunLevel> + </Principal> + </Principals> + <Settings> + <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> + <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> + <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries> + <AllowHardTerminate>true</AllowHardTerminate> + <StartWhenAvailable>false</StartWhenAvailable> + <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable> + <IdleSettings> + <StopOnIdleEnd>true</StopOnIdleEnd> + <RestartOnIdle>false</RestartOnIdle> + </IdleSettings> + <AllowStartOnDemand>true</AllowStartOnDemand> + <Enabled>true</Enabled> + <Hidden>false</Hidden> + <RunOnlyIfIdle>false</RunOnlyIfIdle> + <WakeToRun>false</WakeToRun> + <ExecutionTimeLimit>PT72H</ExecutionTimeLimit> + <Priority>7</Priority> + </Settings> + <Actions Context="Author"> + <Exec> + <Command>C:\Windows\System32\wscript.exe</Command> + <Arguments>C:\Windows\Setup\Scripts\UnlockStartLayout.vbs</Arguments> + </Exec> + </Actions> +</Task> + + +$json = '{"pinnedList":[]}'; +if( [System.Environment]::OSVersion.Version.Build -lt 20000 ) { + return; +} +$key = 'Registry::HKLM\SOFTWARE\Microsoft\PolicyManager\current\device\Start'; +New-Item -Path $key -ItemType 'Directory' -ErrorAction 'SilentlyContinue'; +Set-ItemProperty -LiteralPath $key -Name 'ConfigureStartPins' -Value $json -Type 'String'; + + +$lightThemeSystem = 0; +$lightThemeApps = 0; +$accentColorOnStart = 0; +$enableTransparency = 0; +$htmlAccentColor = '#0078D4'; +& { + $params = @{ + LiteralPath = 'Registry::HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize'; + Force = $true; + Type = 'DWord'; + }; + Set-ItemProperty @params -Name 'SystemUsesLightTheme' -Value $lightThemeSystem; + Set-ItemProperty @params -Name 'AppsUseLightTheme' -Value $lightThemeApps; + Set-ItemProperty @params -Name 'ColorPrevalence' -Value $accentColorOnStart; + Set-ItemProperty @params -Name 'EnableTransparency' -Value $enableTransparency; +}; +& { + Add-Type -AssemblyName 'System.Drawing'; + $accentColor = [System.Drawing.ColorTranslator]::FromHtml( $htmlAccentColor ); + + function ConvertTo-DWord { + param( + [System.Drawing.Color] + $Color + ); + + [byte[]]$bytes = @( + $Color.R; + $Color.G; + $Color.B; + $Color.A; + ); + return [System.BitConverter]::ToUInt32( $bytes, 0); + } + + $startColor = [System.Drawing.Color]::FromArgb( 0xD2, $accentColor ); + Set-ItemProperty -LiteralPath 'Registry::HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent' -Name 'StartColorMenu' -Value( ConvertTo-DWord -Color $accentColor ) -Type 'DWord' -Force; + Set-ItemProperty -LiteralPath 'Registry::HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent' -Name 'AccentColorMenu' -Value( ConvertTo-DWord -Color $accentColor ) -Type 'DWord' -Force; + Set-ItemProperty -LiteralPath 'Registry::HKCU\Software\Microsoft\Windows\DWM' -Name 'AccentColor' -Value( ConvertTo-DWord -Color $accentColor ) -Type 'DWord' -Force; + $params = @{ + LiteralPath = 'Registry::HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent'; + Name = 'AccentPalette'; + }; + $palette = Get-ItemPropertyValue @params; + $index = 20; + $palette[ $index++ ] = $accentColor.R; + $palette[ $index++ ] = $accentColor.G; + $palette[ $index++ ] = $accentColor.B; + $palette[ $index++ ] = $accentColor.A; + Set-ItemProperty @params -Value $palette -Type 'Binary' -Force; +}; + + +$scripts = @( + { + reg.exe add "HKLM\SYSTEM\Setup\MoSetup" /v AllowUpgradesWithUnsupportedTPMOrCPU /t REG_DWORD /d 1 /f; + }; + { + net.exe accounts /maxpwage:UNLIMITED; + }; + { + reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableCloudOptimizedContent" /t REG_DWORD /d 1 /f; + [System.Diagnostics.EventLog]::CreateEventSource( 'UnattendGenerator', 'Application' ); + }; + { + Register-ScheduledTask -TaskName 'UnlockStartLayout' -Xml $( Get-Content -LiteralPath 'C:\Windows\Setup\Scripts\UnlockStartLayout.xml' -Raw ); + }; + { + reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f + }; + { + Remove-Item -LiteralPath 'C:\Users\Public\Desktop\Microsoft Edge.lnk' -ErrorAction 'SilentlyContinue' -Verbose; + }; + { + reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Dsh" /v AllowNewsAndInterests /t REG_DWORD /d 0 /f; + }; + { + reg.exe add "HKLM\Software\Policies\Microsoft\Edge" /v HideFirstRunExperience /t REG_DWORD /d 1 /f; + }; + { + reg.exe add "HKLM\Software\Policies\Microsoft\Edge\Recommended" /v BackgroundModeEnabled /t REG_DWORD /d 0 /f; + reg.exe add "HKLM\Software\Policies\Microsoft\Edge\Recommended" /v StartupBoostEnabled /t REG_DWORD /d 0 /f; + }; + { + & 'C:\Windows\Setup\Scripts\SetStartPins.ps1'; + }; + { + reg.exe add "HKU\.DEFAULT\Control Panel\Accessibility\StickyKeys" /v Flags /t REG_SZ /d 10 /f; + }; + { + reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v NoAutoUpdate /t REG_DWORD /d 1 /f; + reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v DisableWindowsUpdateAccess /t REG_DWORD /d 1 /f; + }; +); + +& { + [float]$complete = 0; + [float]$increment = 100 / $scripts.Count; + foreach( $script in $scripts ) { + Write-Progress -Id 0 -Activity 'Running scripts to customize your Windows installation. Do not close this window.' -PercentComplete $complete; + '*** Will now execute command «{0}».' -f $( + $str = $script.ToString().Trim() -replace '\s+', ' '; + $max = 100; + if( $str.Length -le $max ) { + $str; + } else { + $str.Substring( 0, $max - 1 ) + '…'; + } + ); + $start = [datetime]::Now; + & $script; + '*** Finished executing command after {0:0} ms.' -f [datetime]::Now.Subtract( $start ).TotalMilliseconds; + "`r`n" * 3; + $complete += $increment; + } +} *>&1 | Out-String -Width 1KB -Stream >> "C:\Windows\Setup\Scripts\Specialize.log"; + + +$scripts = @( + { + [System.Diagnostics.EventLog]::WriteEntry( 'UnattendGenerator', "User '$env:USERNAME' has requested to unlock the Start menu layout.", [System.Diagnostics.EventLogEntryType]::Information, 1 ); + }; + { + Remove-Item -Path "${env:USERPROFILE}\Desktop\*.lnk" -Force -ErrorAction 'SilentlyContinue'; + Remove-Item -Path "$env:HOMEDRIVE\Users\Default\Desktop\*.lnk" -Force -ErrorAction 'SilentlyContinue'; + }; + { + $taskbarPath = "$env:AppData\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar"; + if( Test-Path $taskbarPath ) { + Get-ChildItem -Path $taskbarPath -File | Remove-Item -Force; + } + Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband' -Name 'FavoritesRemovedChanges' -Force -ErrorAction 'SilentlyContinue'; + Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband' -Name 'FavoritesChanges' -Force -ErrorAction 'SilentlyContinue'; + Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband' -Name 'Favorites' -Force -ErrorAction 'SilentlyContinue'; + }; + { + reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /ve /f; + }; + { + Set-ItemProperty -LiteralPath 'Registry::HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' -Name 'LaunchTo' -Type 'DWord' -Value 1; + }; + { + Set-ItemProperty -LiteralPath 'Registry::HKCU\Software\Microsoft\Windows\CurrentVersion\Search' -Name 'SearchboxTaskbarMode' -Type 'DWord' -Value 0; + }; + { + & 'C:\Windows\Setup\Scripts\SetColorTheme.ps1'; + }; + { + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.Suggested" /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.Suggested" /v Enabled /t REG_DWORD /d 0 /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.StartupApp" /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.StartupApp" /v Enabled /t REG_DWORD /d 0 /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Microsoft.SkyDrive.Desktop" /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Microsoft.SkyDrive.Desktop" /v Enabled /t REG_DWORD /d 0 /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.AccountHealth" /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.AccountHealth" /v Enabled /t REG_DWORD /d 0 /f; + }; + { + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Start" /v AllAppsViewMode /t REG_DWORD /d 2 /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_IrisRecommendations /t REG_DWORD /d 0 /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_AccountNotifications /t REG_DWORD /d 0 /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Start" /v ShowAllPinsList /t REG_DWORD /d 0 /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Start" /v ShowFrequentList /t REG_DWORD /d 0 /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Start" /v ShowRecentList /t REG_DWORD /d 0 /f; + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_TrackDocs /t REG_DWORD /d 0 /f; + }; + { + Add-Type -TypeDefinition @" +using System; +using System.Runtime.InteropServices; +public class Win32Broadcast { + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)] + public static extern IntPtr SendMessageTimeout( + IntPtr hWnd, + uint Msg, + IntPtr wParam, + string lParam, + uint fuFlags, + uint uTimeout, + out IntPtr lpdwResult); +} +"@; + [Win32Broadcast]::SendMessageTimeout( [IntPtr]0xffff, 0x1A, [IntPtr]::Zero, 'ImmersiveColorSet', 0x2, 100, [ref]([IntPtr]::Zero) ); + }; + { + Get-Process -Name 'explorer' -ErrorAction 'SilentlyContinue' | Where-Object -FilterScript { + $_.SessionId -eq ( Get-Process -Id $PID ).SessionId; + } | Stop-Process -Force; + }; +); + +& { + [float]$complete = 0; + [float]$increment = 100 / $scripts.Count; + foreach( $script in $scripts ) { + Write-Progress -Id 0 -Activity 'Running scripts to configure this user account. Do not close this window.' -PercentComplete $complete; + '*** Will now execute command «{0}».' -f $( + $str = $script.ToString().Trim() -replace '\s+', ' '; + $max = 100; + if( $str.Length -le $max ) { + $str; + } else { + $str.Substring( 0, $max - 1 ) + '…'; + } + ); + $start = [datetime]::Now; + & $script; + '*** Finished executing command after {0:0} ms.' -f [datetime]::Now.Subtract( $start ).TotalMilliseconds; + "`r`n" * 3; + $complete += $increment; + } +} *>&1 | Out-String -Width 1KB -Stream >> "$env:TEMP\UserOnce.log"; + + +$scripts = @( + { + reg.exe add "HKU\DefaultUser\Software\Policies\Microsoft\Windows\Explorer" /v "StartLayoutFile" /t REG_SZ /d "C:\Windows\Setup\Scripts\TaskbarLayoutModification.xml" /f; + reg.exe add "HKU\DefaultUser\Software\Policies\Microsoft\Windows\Explorer" /v "LockedStartLayout" /t REG_DWORD /d 1 /f; + }; + { + reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v ShowTaskViewButton /t REG_DWORD /d 0 /f; + }; + { + reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v TaskbarAl /t REG_DWORD /d 0 /f; + }; + { + foreach( $root in 'Registry::HKU\.DEFAULT', 'Registry::HKU\DefaultUser' ) { + Set-ItemProperty -LiteralPath "$root\Control Panel\Keyboard" -Name 'InitialKeyboardIndicators' -Type 'String' -Value 2 -Force; + } + }; + { + reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\TaskbarDeveloperSettings" /v TaskbarEndTask /t REG_DWORD /d 1 /f; + }; + { + reg.exe add "HKU\DefaultUser\Control Panel\Accessibility\StickyKeys" /v Flags /t REG_SZ /d 10 /f; + }; + { + reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\DWM" /v ColorPrevalence /t REG_DWORD /d 0 /f; + }; + { + reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\RunOnce" /v "UnattendedSetup" /t REG_SZ /d "powershell.exe -WindowStyle \""Normal\"" -ExecutionPolicy \""Unrestricted\"" -NoProfile -File \""C:\Windows\Setup\Scripts\UserOnce.ps1\""" /f; + }; +); + +& { + [float]$complete = 0; + [float]$increment = 100 / $scripts.Count; + foreach( $script in $scripts ) { + Write-Progress -Id 0 -Activity 'Running scripts to modify the default user’’s registry hive. Do not close this window.' -PercentComplete $complete; + '*** Will now execute command «{0}».' -f $( + $str = $script.ToString().Trim() -replace '\s+', ' '; + $max = 100; + if( $str.Length -le $max ) { + $str; + } else { + $str.Substring( 0, $max - 1 ) + '…'; + } + ); + $start = [datetime]::Now; + & $script; + '*** Finished executing command after {0:0} ms.' -f [datetime]::Now.Subtract( $start ).TotalMilliseconds; + "`r`n" * 3; + $complete += $increment; + } +} *>&1 | Out-String -Width 1KB -Stream >> "C:\Windows\Setup\Scripts\DefaultUser.log"; + + +$scripts = @( + { + cmd.exe /c "rmdir C:\Windows.old"; + }; + { + Remove-Item -LiteralPath @( + 'C:\Windows\Panther\unattend.xml'; + 'C:\Windows\Panther\unattend-original.xml'; + 'C:\Windows\Setup\Scripts\Wifi.xml'; + ) -Force -ErrorAction 'SilentlyContinue' -Verbose; + }; + { + reg.exe delete "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v NoAutoUpdate /f; + reg.exe delete "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v DisableWindowsUpdateAccess /f; + }; + { + try { + if( (Get-WindowsOptionalFeature -Online | Where-Object { $_.State -eq 'Enabled' -and $_.FeatureName -like 'Recall' }).Count -gt 0 ) { + Disable-WindowsOptionalFeature -Online -FeatureName 'Recall' -Remove; + } + } catch {} + }; + { + if( (Get-BitLockerVolume -MountPoint $Env:SystemDrive).ProtectionStatus -eq 'On' ) { + Disable-BitLocker -MountPoint $Env:SystemDrive; + } + }; + { + try { + if( (bcdedit | Select-String 'path').Count -eq 2 ) { + bcdedit /set `{bootmgr`} timeout 0; + } + } catch {} + }; +); + +& { + [float]$complete = 0; + [float]$increment = 100 / $scripts.Count; + foreach( $script in $scripts ) { + Write-Progress -Id 0 -Activity 'Running scripts to finalize your Windows installation. Do not close this window.' -PercentComplete $complete; + '*** Will now execute command «{0}».' -f $( + $str = $script.ToString().Trim() -replace '\s+', ' '; + $max = 100; + if( $str.Length -le $max ) { + $str; + } else { + $str.Substring( 0, $max - 1 ) + '…'; + } + ); + $start = [datetime]::Now; + & $script; + '*** Finished executing command after {0:0} ms.' -f [datetime]::Now.Subtract( $start ).TotalMilliseconds; + "`r`n" * 3; + $complete += $increment; + } +} *>&1 | Out-String -Width 1KB -Stream >> "C:\Windows\Setup\Scripts\FirstLogon.log"; + + diff --git a/tools/first-startup.ps1 b/tools/first-startup.ps1 new file mode 100644 index 00000000..19150c49 --- /dev/null +++ b/tools/first-startup.ps1 @@ -0,0 +1,152 @@ +# Set the global error action preference to continue +$ErrorActionPreference = "Continue" +function Remove-RegistryValue { + param ( + [Parameter(Mandatory = $true)] + [string]$RegistryPath, + + [Parameter(Mandatory = $true)] + [string]$ValueName + ) + + # Check if the registry path exists + if (Test-Path -Path $RegistryPath) { + $registryValue = Get-ItemProperty -Path $RegistryPath -Name $ValueName -ErrorAction SilentlyContinue + + # Check if the registry value exists + if ($registryValue) { + # Remove the registry value + Remove-ItemProperty -Path $RegistryPath -Name $ValueName -Force + Write-Host "Registry value '$ValueName' removed from '$RegistryPath'." + } else { + Write-Host "Registry value '$ValueName' not found in '$RegistryPath'." + } + } else { + Write-Host "Registry path '$RegistryPath' not found." + } +} + +"FirstStartup has worked" | Out-File -FilePath "$env:HOMEDRIVE\windows\LogFirstRun.txt" -Append -NoClobber + +# Remove Windows.old if it exists +cmd.exe /c "rmdir /s /q C:\Windows.old" 2>$null + +# Remove unattend and setup script files +Remove-Item -LiteralPath @( + 'C:\Windows\Panther\unattend.xml' + 'C:\Windows\Panther\unattend-original.xml' + 'C:\Windows\Setup\Scripts\Wifi.xml' +) -Force -ErrorAction 'SilentlyContinue' + +# Re-enable Windows Update (was disabled during OOBE to prevent interruptions) +reg.exe delete "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v NoAutoUpdate /f 2>$null +reg.exe delete "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v DisableWindowsUpdateAccess /f 2>$null + +$taskbarPath = "$env:AppData\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar" +# Delete all files on the Taskbar +if (Test-Path "$taskbarPath") { + Get-ChildItem -Path $taskbarPath -File | Remove-Item -Force +} +Remove-RegistryValue -RegistryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -ValueName "FavoritesRemovedChanges" +Remove-RegistryValue -RegistryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -ValueName "FavoritesChanges" +Remove-RegistryValue -RegistryPath "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband" -ValueName "Favorites" + +# Delete Edge Icon from the desktop +$edgeShortcutFiles = Get-ChildItem -Path $desktopPath -Filter "*Edge*.lnk" +# Check if Edge shortcuts exist on the desktop +if ($edgeShortcutFiles) { + foreach ($shortcutFile in $edgeShortcutFiles) { + # Remove each Edge shortcut + Remove-Item -Path $shortcutFile.FullName -Force + Write-Host "Edge shortcut '$($shortcutFile.Name)' removed from the desktop." + } +} +Remove-Item -Path "$env:USERPROFILE\Desktop\*.lnk" +Remove-Item -Path "$env:HOMEDRIVE\Users\Default\Desktop\*.lnk" + +try +{ + if ((Get-WindowsOptionalFeature -Online | Where-Object { $_.State -eq 'Enabled' -and $_.FeatureName -like "Recall" }).Count -gt 0) + { + Disable-WindowsOptionalFeature -Online -FeatureName "Recall" -Remove + } +} +catch +{ + +} + +if ((Get-BitLockerVolume -MountPoint $Env:SystemDrive).ProtectionStatus -eq 'On') { + Write-Host "Disabling BitLocker..." + Disable-BitLocker -MountPoint $Env:SystemDrive +} + +# Get BCD entries and set bootmgr timeout accordingly +try +{ + # Check if the number of occurrences of "path" is 2 - this fixes the Boot Manager screen issue (#2562) + if ((bcdedit | Select-String "path").Count -eq 2) + { + # Set bootmgr timeout to 0 + bcdedit /set `{bootmgr`} timeout 0 + } +} +catch +{ + +} + +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.Suggested" /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.Suggested" /v Enabled /t REG_DWORD /d 0 /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.StartupApp" /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.StartupApp" /v Enabled /t REG_DWORD /d 0 /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Microsoft.SkyDrive.Desktop" /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Microsoft.SkyDrive.Desktop" /v Enabled /t REG_DWORD /d 0 /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.AccountHealth" /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.AccountHealth" /v Enabled /t REG_DWORD /d 0 /f + +# This will set List view in Start menu on Win11 25H2. This will not do anything in 24H2 and older +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Start" /v AllAppsViewMode /t REG_DWORD /d 2 /f + +# This will disable the Recommendations in 25H2. This is much simpler than the method used in 24H2 that requires the Education Environment policy +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_IrisRecommendations /t REG_DWORD /d 0 /f + +# Other Start Menu settings +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_AccountNotifications /t REG_DWORD /d 0 /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Start" /v ShowAllPinsList /t REG_DWORD /d 0 /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Start" /v ShowFrequentList /t REG_DWORD /d 0 /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Start" /v ShowRecentList /t REG_DWORD /d 0 /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v Start_TrackDocs /t REG_DWORD /d 0 /f + +# Color Modes -- requires sending messages to apply to everything +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v "AppsUseLightTheme" /t REG_DWORD /d 0 /f +reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v "SystemUsesLightTheme" /t REG_DWORD /d 0 /f + +# Send the WM_SETTINGCHANGE message to all windows +Add-Type -TypeDefinition @" +using System; +using System.Runtime.InteropServices; +public class Win32 { + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)] + public static extern IntPtr SendMessageTimeout( + IntPtr hWnd, + uint Msg, + IntPtr wParam, + string lParam, + uint fuFlags, + uint uTimeout, + out IntPtr lpdwResult); +} +"@ + +$HWND_BROADCAST = [IntPtr]0xffff +$WM_SETTINGCHANGE = 0x1A +$SMTO_ABORTIFHUNG = 0x2 +$timeout = 100 + +# Send the broadcast message to all windows +[Win32]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [IntPtr]::Zero, "ImmersiveColorSet", $SMTO_ABORTIFHUNG, $timeout, [ref]([IntPtr]::Zero)) + +Clear-Host +Write-Host "The taskbar will take around a minute to show up, but you can start using your computer now. Try pressing the Windows key to open the Start menu, or Windows + E to launch File Explorer." +Start-Sleep -Seconds 10 diff --git a/xaml/inputXML.xaml b/xaml/inputXML.xaml index 61ec39e7..08dd13c4 100644 --- a/xaml/inputXML.xaml +++ b/xaml/inputXML.xaml @@ -1554,7 +1554,7 @@