diff --git a/README.md b/README.md index 72ed878..88f03e2 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ The script has also been updated to use DISM's recovery compression, resulting i Also included is an unattended answer file, which is used to bypass the Microsoft Account on OOBE and to deploy the image with the `/compact` flag. It's open-source, **so feel free to add or remove anything you want!** Feedback is also much appreciated. -Also, for the very first time, **introducing tiny11 core builder**! A more powerful script, designed for a quick and dirty development testbed. Just the bare minimum, none of the fluff. +Also, for the very first time, **introducing tiny11 core builder**! A more powerful script, designed for a quick and dirty development testbed. Just the bare minimum, none of the fluff. This script generates a significantly reduced Windows 11 image. However, **it's not suitable for regular use due to its lack of serviceability - you can't add languages, updates, or features post-creation**. tiny11 Core is not a full Windows 11 substitute but a rapid testing or development tool, potentially useful for VM environments. --- @@ -24,18 +24,18 @@ This script generates a significantly reduced Windows 11 image. However, **it's ## Instructions: 1. Download Windows 11 from the [Microsoft website](https://www.microsoft.com/software-download/windows11) or [Rufus](https://github.com/pbatard/rufus) 2. Mount the downloaded ISO image using Windows Explorer. -3. Open **PowerShell 5.1** as Administrator. -5. Change the script execution policy : +3. Open **PowerShell 5.1** as Administrator. +4. Change the script execution policy : ```powershell Set-ExecutionPolicy Bypass -Scope Process ``` -> Using `-Scope Process` you keep your original policy intact as this change only lasts for the current PowerShell session. +> Using `-Scope Process` you keep your original policy intact as this change only lasts for the current PowerShell session. -6. Start the script : +5. Start the script : ```powershell C:/path/to/your/tiny11/script.ps1 -ISO -SCRATCH ``` -> You can see of the script by running the `get-help` command. +> You can see the description of the script by running the `get-help` command. 6. Select the drive letter where the image is mounted (only the letter, no colon (:)) 7. Select the SKU that you want the image to be based. diff --git a/Run.bat b/Run.bat new file mode 100644 index 0000000..996c80a --- /dev/null +++ b/Run.bat @@ -0,0 +1,5 @@ +:: Reference from https://github.com/Raphire/Win11Debloat/blob/master/Run.bat licensed under MIT license. + +@echo off + +Powershell -ExecutionPolicy Bypass -Command "& {Start-Process Powershell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%~dp0tiny11maker.ps1""' -Verb RunAs}" diff --git a/tiny11Coremaker.ps1 b/tiny11Coremaker.ps1 index 439768a..20239e2 100644 --- a/tiny11Coremaker.ps1 +++ b/tiny11Coremaker.ps1 @@ -1,10 +1,13 @@ -if ((Get-ExecutionPolicy) -eq 'Restricted') { - Write-Host "Your current PowerShell Execution Policy is set to Restricted, which prevents scripts from running. Do you want to change it to RemoteSigned? (yes/no)" +# Check if PowerShell execution is Restricted or AllSigned or Undefined +$needchange = @("AllSigned", "Restricted", "Undefined") +$curpolicy = Get-ExecutionPolicy +if ($curpolicy -in $needchange) { + Write-Output "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 CurrentUser -Confirm:$false + Set-ExecutionPolicy RemoteSigned -Scope Process -Confirm:$false } else { - Write-Host "The script cannot be run without changing the execution policy. Exiting..." + Write-Output "The script cannot be run without changing the execution policy. Exiting..." exit } } @@ -17,7 +20,7 @@ $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWin $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator if (! $myWindowsPrincipal.IsInRole($adminRole)) { - Write-Host "Restarting Tiny11 image creator as admin in a new window, you can close this one." + Write-Output "Restarting Tiny11 image creator as admin in a new window, you can close this one." $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell"; $newProcess.Arguments = $myInvocation.MyCommand.Definition; $newProcess.Verb = "runas"; @@ -26,13 +29,13 @@ if (! $myWindowsPrincipal.IsInRole($adminRole)) } Start-Transcript -Path "$PSScriptRoot\tiny11.log" # Ask the user for input -Write-Host "Welcome to tiny11 core builder! BETA 09-05-25" -Write-Host "This script generates a significantly reduced Windows 11 image. However, it's not suitable for regular use due to its lack of serviceability - you can't add languages, updates, or features post-creation. tiny11 Core is not a full Windows 11 substitute but a rapid testing or development tool, potentially useful for VM environments." -Write-Host "Do you want to continue? (y/n)" +Write-Output "Welcome to tiny11 core builder! BETA 09-05-25" +Write-Output "This script generates a significantly reduced Windows 11 image. However, it's not suitable for regular use due to its lack of serviceability - you can't add languages, updates, or features post-creation. tiny11 Core is not a full Windows 11 substitute but a rapid testing or development tool, potentially useful for VM environments." +Write-Output "Do you want to continue? (y/n)" $input = Read-Host if ($input -eq 'y') { - Write-Host "Off we go..." + Write-Output "Off we go..." Start-Sleep -Seconds 3 Clear-Host @@ -44,30 +47,30 @@ $DriveLetter = $DriveLetter + ":" if ((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..." + Write-Output "Found install.esd, converting to install.wim..." & 'dism' '/English' "/Get-WimInfo" "/wimfile:$DriveLetter\sources\install.esd" $index = Read-Host "Please enter the image index" - Write-Host ' ' - Write-Host 'Converting install.esd to install.wim. This may take a while...' + Write-Output ' ' + Write-Output 'Converting install.esd to install.wim. This may take a while...' & 'DISM' /Export-Image /SourceImageFile:"$DriveLetter\sources\install.esd" /SourceIndex:$index /DestinationImageFile:"$mainOSDrive\tiny11\sources\install.wim" /Compress:max /CheckIntegrity } else { - Write-Host "Can't find Windows OS Installation files in the specified Drive Letter.." - Write-Host "Please enter the correct DVD Drive Letter.." + Write-Output "Can't find Windows OS Installation files in the specified Drive Letter.." + Write-Output "Please enter the correct DVD Drive Letter.." exit } } -Write-Host "Copying Windows image..." +Write-Output "Copying Windows image..." Copy-Item -Path "$DriveLetter\*" -Destination "$mainOSDrive\tiny11" -Recurse -Force > null Set-ItemProperty -Path "$mainOSDrive\tiny11\sources\install.esd" -Name IsReadOnly -Value $false > $null 2>&1 Remove-Item "$mainOSDrive\tiny11\sources\install.esd" > $null 2>&1 -Write-Host "Copy complete!" +Write-Output "Copy complete!" Start-Sleep -Seconds 2 Clear-Host -Write-Host "Getting image information:" +Write-Output "Getting image information:" & 'dism' '/English' "/Get-WimInfo" "/wimfile:$mainOSDrive\tiny11\sources\install.wim" $index = Read-Host "Please enter the image index" -Write-Host "Mounting Windows image. This may take a while." +Write-Output "Mounting Windows image. This may take a while." $wimFilePath = "$($env:SystemDrive)\tiny11\sources\install.wim" & takeown "/F" $wimFilePath & icacls $wimFilePath "/grant" "$($adminGroup.Value):(F)" @@ -84,9 +87,9 @@ $languageLine = $imageIntl -split '\n' | Where-Object { $_ -match 'Default syste if ($languageLine) { $languageCode = $Matches[1] - Write-Host "Default system UI language code: $languageCode" + Write-Output "Default system UI language code: $languageCode" } else { - Write-Host "Default system UI language code not found." + Write-Output "Default system UI language code not found." } $imageInfo = & 'dism' '/English' '/Get-WimInfo' "/wimFile:$($env:SystemDrive)\tiny11\sources\install.wim" "/index:$index" @@ -99,16 +102,16 @@ foreach ($line in $lines) { if ($architecture -eq 'x64') { $architecture = 'amd64' } - Write-Host "Architecture: $architecture" + Write-Output "Architecture: $architecture" break } } if (-not $architecture) { - Write-Host "Architecture information not found." + Write-Output "Architecture information not found." } -Write-Host "Mounting complete! Performing removal of applications..." +Write-Output "Mounting complete! Performing removal of applications..." $packages = & 'dism' '/English' "/image:$($env:SystemDrive)\scratchdir" '/Get-ProvisionedAppxPackages' | ForEach-Object { @@ -123,11 +126,11 @@ $packagesToRemove = $packages | Where-Object { $packagePrefixes -contains ($packagePrefixes | Where-Object { $packageName -like "$_*" }) } foreach ($package in $packagesToRemove) { - write-host "Removing $package :" + Write-Output "Removing $package :" & 'dism' '/English' "/image:$($env:SystemDrive)\scratchdir" '/Remove-ProvisionedAppxPackage' "/PackageName:$package" } -Write-Host "Removing of system apps complete! Now proceeding to removal of system packages..." +Write-Output "Removing of system apps complete! Now proceeding to removal of system packages..." Start-Sleep -Seconds 1 Clear-Host @@ -160,26 +163,26 @@ foreach ($packagePattern in $packagePatterns) { # Extract the package identity $packageIdentity = ($package -split "\s+")[0] - Write-Host "Removing $packageIdentity..." + Write-Output "Removing $packageIdentity..." & dism /image:$scratchDir /Remove-Package /PackageName:$packageIdentity } } -Write-Host "Do you want to enable .NET 3.5? This cannot be done after the image has been created! (y/n)" +Write-Output "Do you want to enable .NET 3.5? This cannot be done after the image has been created! (y/n)" $input = Read-Host if ($input -eq 'y') { - Write-Host "Enabling .NET 3.5..." + Write-Output "Enabling .NET 3.5..." & 'dism' "/image:$scratchDir" '/enable-feature' '/featurename:NetFX3' '/All' "/source:$($env:SystemDrive)\tiny11\sources\sxs" - Write-Host ".NET 3.5 has been enabled." + Write-Output ".NET 3.5 has been enabled." } elseif ($input -eq 'n') { - Write-Host "You chose not to enable .NET 3.5. Continuing..." + Write-Output "You chose not to enable .NET 3.5. Continuing..." } else { - Write-Host "Invalid input. Please enter 'y' to enable .NET 3.5 or 'n' to continue without installing .net 3.5." + Write-Output "Invalid input. Please enter 'y' to enable .NET 3.5 or 'n' to continue without installing .net 3.5." } -Write-Host "Removing Edge:" +Write-Output "Removing Edge:" Remove-Item -Path "$mainOSDrive\scratchdir\Program Files (x86)\Microsoft\Edge" -Recurse -Force >null Remove-Item -Path "$mainOSDrive\scratchdir\Program Files (x86)\Microsoft\EdgeUpdate" -Recurse -Force >null Remove-Item -Path "$mainOSDrive\scratchdir\Program Files (x86)\Microsoft\EdgeCore" -Recurse -Force >null @@ -191,7 +194,7 @@ if ($architecture -eq 'amd64') { & icacls $folderPath "/grant" "$($adminGroup.Value):(F)" '/T' '/C' >null Remove-Item -Path $folderPath -Recurse -Force >null } else { - Write-Host "Folder not found." + Write-Output "Folder not found." } } elseif ($architecture -eq 'arm64') { $folderPath = Get-ChildItem -Path "$mainOSDrive\scratchdir\Windows\WinSxS" -Filter "arm64_microsoft-edge-webview_31bf3856ad364e35*" -Directory | Select-Object -ExpandProperty FullName >null @@ -201,33 +204,33 @@ if ($architecture -eq 'amd64') { & icacls $folderPath "/grant" "$($adminGroup.Value):(F)" '/T' '/C' >null Remove-Item -Path $folderPath -Recurse -Force >null } else { - Write-Host "Folder not found." + Write-Output "Folder not found." } } else { - Write-Host "Unknown architecture: $architecture" + Write-Output "Unknown architecture: $architecture" } & 'takeown' '/f' "$mainOSDrive\scratchdir\Windows\System32\Microsoft-Edge-Webview" '/r' & 'icacls' "$mainOSDrive\scratchdir\Windows\System32\Microsoft-Edge-Webview" '/grant' "$($adminGroup.Value):(F)" '/T' '/C' Remove-Item -Path "$mainOSDrive\scratchdir\Windows\System32\Microsoft-Edge-Webview" -Recurse -Force -Write-Host "Removing WinRE" +Write-Output "Removing WinRE" & 'takeown' '/f' "$mainOSDrive\scratchdir\Windows\System32\Recovery" '/r' & 'icacls' "$mainOSDrive\scratchdir\Windows\System32\Recovery" '/grant' 'Administrators:F' '/T' '/C' Remove-Item -Path "$mainOSDrive\scratchdir\Windows\System32\Recovery\winre.wim" -Recurse -Force New-Item -Path "$mainOSDrive\scratchdir\Windows\System32\Recovery\winre.wim" -ItemType File -Force -Write-Host "Removing OneDrive:" +Write-Output "Removing OneDrive:" & 'takeown' '/f' "$mainOSDrive\scratchdir\Windows\System32\OneDriveSetup.exe" >null & 'icacls' "$mainOSDrive\scratchdir\Windows\System32\OneDriveSetup.exe" '/grant' "$($adminGroup.Value):(F)" '/T' '/C' >null Remove-Item -Path "$mainOSDrive\scratchdir\Windows\System32\OneDriveSetup.exe" -Force >null -Write-Host "Removal complete!" +Write-Output "Removal complete!" Start-Sleep -Seconds 2 Clear-Host -Write-Host "Taking ownership of the WinSxS folder. This might take a while..." +Write-Output "Taking ownership of the WinSxS folder. This might take a while..." & 'takeown' '/f' "$mainOSDrive\scratchdir\Windows\WinSxS" '/r' & 'icacls' "$mainOSDrive\scratchdir\Windows\WinSxS" '/grant' "$($adminGroup.Value):(F)" '/T' '/C' -Write-host "Complete!" +Write-Output "Complete!" Start-Sleep -Seconds 2 Clear-Host -Write-Host "Preparing..." +Write-Output "Preparing..." $folderPath = Join-Path -Path $mainOSDrive -ChildPath "\scratchdir\Windows\WinSxS_edit" $sourceDirectory = "$mainOSDrive\scratchdir\Windows\WinSxS" $destinationDirectory = "$mainOSDrive\scratchdir\Windows\WinSxS_edit" @@ -272,7 +275,7 @@ if ($architecture -eq "amd64") { $sourceDirs = Get-ChildItem -Path $sourceDirectory -Filter $dir -Directory foreach ($sourceDir in $sourceDirs) { $destDir = Join-Path -Path $destinationDirectory -ChildPath $sourceDir.Name - Write-Host "Copying $sourceDir.FullName to $destDir" + Write-Output "Copying $sourceDir.FullName to $destDir" Copy-Item -Path $sourceDir.FullName -Destination $destDir -Recurse -Force } } @@ -319,25 +322,25 @@ foreach ($dir in $dirsToCopy) { $sourceDirs = Get-ChildItem -Path $sourceDirectory -Filter $dir -Directory foreach ($sourceDir in $sourceDirs) { $destDir = Join-Path -Path $destinationDirectory -ChildPath $sourceDir.Name - Write-Host "Copying $sourceDir.FullName to $destDir" + Write-Output "Copying $sourceDir.FullName to $destDir" Copy-Item -Path $sourceDir.FullName -Destination $destDir -Recurse -Force } } -Write-Host "Deleting WinSxS. This may take a while..." +Write-Output "Deleting WinSxS. This may take a while..." Remove-Item -Path $mainOSDrive\scratchdir\Windows\WinSxS -Recurse -Force Rename-Item -Path $mainOSDrive\scratchdir\Windows\WinSxS_edit -NewName $mainOSDrive\scratchdir\Windows\WinSxS -Write-Host "Complete!" +Write-Output "Complete!" -Write-Host "Loading registry..." +Write-Output "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):" +Write-Output "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 @@ -348,7 +351,7 @@ Write-Host "Bypassing system requirements(on the system image):" & '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 "Disabling Sponsored Apps:" +Write-Output "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 @@ -378,22 +381,22 @@ Write-Host "Disabling Sponsored Apps:" & 'reg' 'delete' 'HKLM\zNTUSER\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager\SuggestedApps' '/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 -Write-Host "Enabling Local Accounts on OOBE:" +Write-Output "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\autounattend.xml" -Destination "$ScratchDisk\scratchdir\Windows\System32\Sysprep\autounattend.xml" -Force | Out-Null -Write-Host "Disabling Reserved Storage:" +Write-Output "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" +Write-Output "Disabling BitLocker Device Encryption" & 'reg' 'add' 'HKLM\zSYSTEM\ControlSet001\Control\BitLocker' '/v' 'PreventDeviceEncryption' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null -Write-Host "Disabling Chat icon:" +Write-Output "Disabling Chat icon:" & 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\Windows Chat' '/v' 'ChatIcon' '/t' 'REG_DWORD' '/d' '3' '/f' | Out-Null & 'reg' 'add' 'HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced' '/v' 'TaskbarMn' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null -Write-Host "Removing Edge related registries" +Write-Output "Removing Edge related registries" reg delete "HKEY_LOCAL_MACHINE\zSOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft Edge" /f | Out-Null reg delete "HKEY_LOCAL_MACHINE\zSOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft Edge Update" /f | Out-Null -Write-Host "Disabling OneDrive folder backup" +Write-Output "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:" +Write-Output "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 @@ -404,22 +407,22 @@ Write-Host "Disabling Telemetry:" & '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 -Write-Host "Prevents installation or DevHome and Outlook:" +Write-Output "Prevents installation or DevHome and Outlook:" & 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\OutlookUpdate' '/v' 'workCompleted' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null & 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\DevHomeUpdate' '/v' 'workCompleted' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null & 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate' '/f' | Out-Null & 'reg' 'delete' 'HKLM\zSOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\DevHomeUpdate' '/f' | Out-Null -Write-Host "Disabling Copilot" +Write-Output "Disabling Copilot" & 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\WindowsCopilot' '/v' 'TurnOffWindowsCopilot' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null & 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Edge' '/v' 'HubsSidebarEnabled' '/t' 'REG_DWORD' '/d' '0' '/f' | Out-Null & 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\Explorer' '/v' 'DisableSearchBoxSuggestions' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null -Write-Host "Prevents installation of Teams:" +Write-Output "Prevents installation of Teams:" & 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Teams' '/v' 'DisableInstallation' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null -Write-Host "Prevent installation of New Outlook": +Write-Output "Prevent installation of New Outlook": & 'reg' 'add' 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\Windows Mail' '/v' 'PreventRun' '/t' 'REG_DWORD' '/d' '1' '/f' | Out-Null $tasksPath = "C:\scratchdir\Windows\System32\Tasks" -Write-Host "Deleting scheduled task definition files..." +Write-Output "Deleting scheduled task definition files..." # Application Compatibility Appraiser Remove-Item -Path "$tasksPath\Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser" -Force -ErrorAction SilentlyContinue @@ -436,8 +439,8 @@ Remove-Item -Path "$tasksPath\Microsoft\Windows\Chkdsk\Proxy" -Force -ErrorActio # Windows Error Reporting (QueueReporting) Remove-Item -Path "$tasksPath\Microsoft\Windows\Windows Error Reporting\QueueReporting" -Force -ErrorAction SilentlyContinue -Write-Host "Task files have been deleted." -Write-Host "Disabling Windows Update..." +Write-Output "Task files have been deleted." +Write-Output "Disabling Windows Update..." & 'reg' 'add' "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" '/v' 'StopWUPostOOBE1' '/t' 'REG_SZ' '/d' 'net stop wuauserv' '/f' & 'reg' 'add' "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" '/v' 'StopWUPostOOBE2' '/t' 'REG_SZ' '/d' 'sc stop wuauserv' '/f' & 'reg' 'add' "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" '/v' 'StopWUPostOOBE3' '/t' 'REG_SZ' '/d' 'sc config wuauserv start= disabled' '/f' @@ -454,7 +457,7 @@ Write-Host "Disabling Windows Update..." & 'reg' 'delete' 'HKLM\zSYSTEM\ControlSet001\Services\WaaSMedicSVC' '/f' & 'reg' 'delete' 'HKLM\zSYSTEM\ControlSet001\Services\UsoSvc' '/f' & 'reg' 'add' 'HKEY_LOCAL_MACHINE\zSOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' '/v' 'NoAutoUpdate' '/t' 'REG_DWORD' '/d' '1' '/f' -Write-Host "Disabling Windows Defender" +Write-Output "Disabling Windows Defender" # Set registry values for Windows Defender services $servicePaths = @( "WinDefend", @@ -468,39 +471,39 @@ foreach ($path in $servicePaths) { Set-ItemProperty -Path "HKLM:\zSYSTEM\ControlSet001\Services\$path" -Name "Start" -Value 4 } & 'reg' 'add' 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer' '/v' 'SettingsPageVisibility' '/t' 'REG_SZ' '/d' 'hide:virus;windowsupdate' '/f' -Write-Host "Tweaking complete!" -Write-Host "Unmounting Registry..." +Write-Output "Tweaking complete!" +Write-Output "Unmounting Registry..." reg unload HKLM\zCOMPONENTS >null reg unload HKLM\zDEFAULT >null reg unload HKLM\zNTUSER >null reg unload HKLM\zSOFTWARE reg unload HKLM\zSYSTEM >null -Write-Host "Cleaning up image..." +Write-Output "Cleaning up image..." & 'dism' '/English' "/image:$mainOSDrive\scratchdir" '/Cleanup-Image' '/StartComponentCleanup' '/ResetBase' >null -Write-Host "Cleanup complete." -Write-Host ' ' -Write-Host "Unmounting image..." +Write-Output "Cleanup complete." +Write-Output ' ' +Write-Output "Unmounting image..." & 'dism' '/English' '/unmount-image' "/mountdir:$mainOSDrive\scratchdir" '/commit' -Write-Host "Exporting image..." +Write-Output "Exporting image..." & 'dism' '/English' '/Export-Image' "/SourceImageFile:$mainOSDrive\tiny11\sources\install.wim" "/SourceIndex:$index" "/DestinationImageFile:$mainOSDrive\tiny11\sources\install2.wim" '/compress:max' Remove-Item -Path "$mainOSDrive\tiny11\sources\install.wim" -Force >null Rename-Item -Path "$mainOSDrive\tiny11\sources\install2.wim" -NewName "install.wim" >null -Write-Host "Windows image completed. Continuing with boot.wim." +Write-Output "Windows image completed. Continuing with boot.wim." Start-Sleep -Seconds 2 Clear-Host -Write-Host "Mounting boot image:" +Write-Output "Mounting boot image:" $wimFilePath = "$($env:SystemDrive)\tiny11\sources\boot.wim" & takeown "/F" $wimFilePath >null & icacls $wimFilePath "/grant" "$($adminGroup.Value):(F)" Set-ItemProperty -Path $wimFilePath -Name IsReadOnly -Value $false & 'dism' '/English' '/mount-image' "/imagefile:$mainOSDrive\tiny11\sources\boot.wim" '/index:2' "/mountdir:$mainOSDrive\scratchdir" -Write-Host "Loading registry..." +Write-Output "Loading registry..." reg load HKLM\zCOMPONENTS $mainOSDrive\scratchdir\Windows\System32\config\COMPONENTS reg load HKLM\zDEFAULT $mainOSDrive\scratchdir\Windows\System32\config\default reg load HKLM\zNTUSER $mainOSDrive\scratchdir\Users\Default\ntuser.dat reg load HKLM\zSOFTWARE $mainOSDrive\scratchdir\Windows\System32\config\SOFTWARE reg load HKLM\zSYSTEM $mainOSDrive\scratchdir\Windows\System32\config\SYSTEM -Write-Host "Bypassing system requirements(on the setup image):" +Write-Output "Bypassing system requirements(on the setup image):" & 'reg' 'add' 'HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV1' '/t' 'REG_DWORD' '/d' '0' '/f' >null & 'reg' 'add' 'HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV2' '/t' 'REG_DWORD' '/d' '0' '/f' >null & 'reg' 'add' 'HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache' '/v' 'SV1' '/t' 'REG_DWORD' '/d' '0' '/f' >null @@ -512,45 +515,54 @@ Write-Host "Bypassing system requirements(on the setup image):" & 'reg' 'add' 'HKLM\zSYSTEM\Setup\LabConfig' '/v' 'BypassTPMCheck' '/t' 'REG_DWORD' '/d' '1' '/f' >null & 'reg' 'add' 'HKLM\zSYSTEM\Setup\MoSetup' '/v' 'AllowUpgradesWithUnsupportedTPMOrCPU' '/t' 'REG_DWORD' '/d' '1' '/f' >null & 'reg' 'add' 'HKEY_LOCAL_MACHINE\zSYSTEM\Setup' '/v' 'CmdLine' '/t' 'REG_SZ' '/d' 'X:\sources\setup.exe' '/f' >null -Write-Host "Tweaking complete!" -Write-Host "Unmounting Registry..." +Write-Output "Tweaking complete!" +Write-Output "Unmounting Registry..." reg unload HKLM\zCOMPONENTS >null reg unload HKLM\zDEFAULT >null reg unload HKLM\zNTUSER >null reg unload HKLM\zSOFTWARE >null reg unload HKLM\zSYSTEM >null -Write-Host "Unmounting image..." +Write-Output "Unmounting image..." & 'dism' '/English' '/unmount-image' "/mountdir:$mainOSDrive\scratchdir" '/commit' Clear-Host -Write-Host "Exporting ESD. This may take a while..." +Write-Output "Exporting ESD. This may take a while..." & dism /Export-Image /SourceImageFile:"$mainOSDrive\tiny11\sources\install.wim" /SourceIndex:1 /DestinationImageFile:"$mainOSDrive\tiny11\sources\install.esd" /Compress:recovery Remove-Item "$mainOSDrive\tiny11\sources\install.wim" > $null 2>&1 -Write-Host "The tiny11 image is now completed. Proceeding with the making of the ISO..." -Write-Host "Creating ISO image..." -$ADKDepTools = "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\$hostarchitecture\Oscdimg" +Write-Output "The tiny11 image is now completed. Proceeding with the making of the ISO..." +Write-Output "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 ([System.IO.Directory]::Exists($ADKDepTools)) { - Write-Host "Will be using oscdimg.exe from system ADK." +if ((Test-Path variable:ADKDepTools) -and (Test-Path "$ADKDepTools\oscdimg.exe" -PathType leaf)) { + Write-Output "Will be using oscdimg.exe from system ADK." $OSCDIMG = "$ADKDepTools\oscdimg.exe" } else { - Write-Host "ADK folder not found. Will be using bundled oscdimg.exe." - - + Write-Output "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 (-not (Test-Path -Path $localOSCDIMGPath)) { - Write-Host "Downloading oscdimg.exe..." + Write-Output "Downloading oscdimg.exe..." Invoke-WebRequest -Uri $url -OutFile $localOSCDIMGPath if (Test-Path $localOSCDIMGPath) { - Write-Host "oscdimg.exe downloaded successfully." + Write-Output "oscdimg.exe downloaded successfully." } else { Write-Error "Failed to download oscdimg.exe." exit 1 } } else { - Write-Host "oscdimg.exe already exists locally." + Write-Output "oscdimg.exe already exists locally." } $OSCDIMG = $localOSCDIMGPath @@ -559,9 +571,9 @@ if ([System.IO.Directory]::Exists($ADKDepTools)) { & "$OSCDIMG" '-m' '-o' '-u2' '-udfver102' "-bootdata:2#p0,e,b$ScratchDisk\tiny11\boot\etfsboot.com#pEF,e,b$ScratchDisk\tiny11\efi\microsoft\boot\efisys.bin" "$ScratchDisk\tiny11" "$PSScriptRoot\tiny11.iso" # Finishing up -Write-Host "Creation completed! Press any key to exit the script..." +Write-Output "Creation completed! Press any key to exit the script..." Read-Host "Press Enter to continue" -Write-Host "Performing Cleanup..." +Write-Output "Performing Cleanup..." Remove-Item -Path "$mainOSDrive\tiny11" -Recurse -Force >null Remove-Item -Path "$mainOSDrive\scratchdir" -Recurse -Force >null @@ -571,9 +583,9 @@ Stop-Transcript exit } elseif ($input -eq 'n') { - Write-Host "You chose not to continue. The script will now exit." + Write-Output "You chose not to continue. The script will now exit." exit } else { - Write-Host "Invalid input. Please enter 'y' to continue or 'n' to exit." + Write-Output "Invalid input. Please enter 'y' to continue or 'n' to exit." } diff --git a/tiny11maker.ps1 b/tiny11maker.ps1 index 3d8b9f7..77e8355 100644 --- a/tiny11maker.ps1 +++ b/tiny11maker.ps1 @@ -23,7 +23,7 @@ prefer the use of full named parameter (eg: "-ISO") as you can put in the order you want. .NOTES - Auteur: ntdevlabs + Author: ntdevlabs Date: 09-07-25 #> @@ -68,12 +68,14 @@ function Remove-RegistryValue { } #---------[ Execution ]---------# -# Check if PowerShell execution is restricted -if ((Get-ExecutionPolicy) -eq 'Restricted') { - Write-Output "Your current PowerShell Execution Policy is set to Restricted, which prevents scripts from running. Do you want to change it to RemoteSigned? (yes/no)" +# 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 CurrentUser -Confirm:$false + Set-ExecutionPolicy RemoteSigned -Scope Process -Confirm:$false } else { Write-Output "The script cannot be run without changing the execution policy. Exiting..." exit @@ -162,8 +164,9 @@ try { Write-Error "$wimFilePath not found" } New-Item -ItemType Directory -Force -Path "$ScratchDisk\scratchdir" > $null -Mount-WindowsImage -ImagePath $ScratchDisk\tiny11\sources\install.wim -Index $index -Path $ScratchDisk\scratchdir +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})' } @@ -174,32 +177,26 @@ if ($languageLine) { Write-Output "Default system UI language code not found." } -$imageInfo = & 'dism' '/English' '/Get-WimInfo' "/wimFile:$($ScratchDisk)\tiny11\sources\install.wim" "/index:$index" -$lines = $imageInfo -split '\r?\n' - -foreach ($line in $lines) { - if ($line -like '*Architecture : *') { - $architecture = $line -replace 'Architecture : ','' - # If the architecture is x64, replace it with amd64 - if ($architecture -eq 'x64') { - $architecture = 'amd64' - } - Write-Output "Architecture: $architecture" - break - } +# 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 (-not $architecture) { +if ($architecture) { + Write-Output "Architecture: $architecture" +} else { Write-Output "Architecture information not found." } -Write-Output "Mounting complete! Performing removal of applications..." +Write-Output "Mounting complete! Performing removal of applications...`n" -$packages = & 'dism' '/English' "/image:$($ScratchDisk)\scratchdir" '/Get-ProvisionedAppxPackages' | +$packages = Get-ProvisionedAppxPackage -Path "$ScratchDisk\scratchdir" | ForEach-Object { - if ($_ -match 'PackageName : (.*)') { - $matches[1] - } + $_.PackageName } $packagePrefixes = 'AppUp.IntelManagementandSecurityStatus', @@ -253,7 +250,6 @@ $packagePrefixes = 'AppUp.IntelManagementandSecurityStatus', 'MicrosoftCorporationII.QuickAssist', 'MSTeams', 'MicrosoftTeams', -'Microsoft.WindowsTerminal', 'Microsoft.549981C3F5F10' $packagesToRemove = $packages | Where-Object { @@ -261,10 +257,11 @@ $packagesToRemove = $packages | Where-Object { $packagePrefixes -contains ($packagePrefixes | Where-Object { $packageName -like "*$_*" }) } foreach ($package in $packagesToRemove) { - & 'dism' '/English' "/image:$($ScratchDisk)\scratchdir" '/Remove-ProvisionedAppxPackage' "/PackageName:$package" + Write-Host "Removing $package..." + Remove-AppxProvisionedPackage -Path "$ScratchDisk\scratchdir" -PackageName "$package" | Out-Null } -Write-Output "Removing Edge:" +Write-Host "`nRemoving Edge:" Remove-Item -Path "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\Edge" -Recurse -Force | Out-Null Remove-Item -Path "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeUpdate" -Recurse -Force | Out-Null Remove-Item -Path "$ScratchDisk\scratchdir\Program Files (x86)\Microsoft\EdgeCore" -Recurse -Force | Out-Null @@ -392,10 +389,10 @@ Write-Output "Cleanup complete." Write-Output ' ' Write-Output "Unmounting image..." Dismount-WindowsImage -Path $ScratchDisk\scratchdir -Save -Write-Host "Exporting image..." -Dism.exe /Export-Image /SourceImageFile:"$ScratchDisk\tiny11\sources\install.wim" /SourceIndex:$index /DestinationImageFile:"$ScratchDisk\tiny11\sources\install2.wim" /Compress:recovery -Remove-Item -Path "$ScratchDisk\tiny11\sources\install.wim" -Force | Out-Null -Rename-Item -Path "$ScratchDisk\tiny11\sources\install2.wim" -NewName "install.wim" | Out-Null +Write-Output "Exporting image..." +# Run `Export-WindowsImage` with undocumented CompressionType "LZMS" (which is the same compression used for Recovery from dism.exe) +Export-WindowsImage -SourceImagePath "$ScratchDisk\tiny11\sources\install.wim" -SourceIndex "$index" -DestinationImagePath "$ScratchDisk\tiny11\sources\install2.wim" -CompressionType "LZMS" +Move-Item -Path "$ScratchDisk\tiny11\sources\install2.wim" -Destination "$ScratchDisk\tiny11\sources\install.wim" -Force | Out-Null Write-Output "Windows image completed. Continuing with boot.wim." Start-Sleep -Seconds 2 Clear-Host @@ -439,21 +436,32 @@ Write-Output "The tiny11 image is now completed. Proceeding with the making of t Write-Output "Copying unattended file for bypassing MS account on OOBE..." Copy-Item -Path "$PSScriptRoot\autounattend.xml" -Destination "$ScratchDisk\tiny11\autounattend.xml" -Force | Out-Null Write-Output "Creating ISO image..." -$ADKDepTools = "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\$hostarchitecture\Oscdimg" +# 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 (!$WinSDKPath) { + $WinSDKPath = [Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots", "KitsRoot10", $null) +} + +if ($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 ([System.IO.Directory]::Exists($ADKDepTools)) { +if ($ADKDepTools -and [System.IO.File]::Exists("$ADKDepTools\oscdimg.exe")) { Write-Output "Will be using oscdimg.exe from system ADK." $OSCDIMG = "$ADKDepTools\oscdimg.exe" } else { - Write-Output "ADK folder not found. Will be using bundled oscdimg.exe." + Write-Output "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 (-not (Test-Path -Path $localOSCDIMGPath)) { + if (![System.IO.File]::Exists($localOSCDIMGPath)) { Write-Output "Downloading oscdimg.exe..." Invoke-WebRequest -Uri $url -OutFile $localOSCDIMGPath - if (Test-Path $localOSCDIMGPath) { + if ([System.IO.File]::Exists($localOSCDIMGPath)) { Write-Output "oscdimg.exe downloaded successfully." } else { Write-Error "Failed to download oscdimg.exe."