11# Enable debugging
2- # Set-PSDebug -Trace 1
2+ # Set-PSDebug -Trace 1
33
44param (
5- [ValidatePattern (' ^[c-zC-Z]$' )]
5+ [ValidatePattern (' ^[c-zC-Z]: $' )]
66 [string ]$ScratchDisk
77)
88
99if (-not $ScratchDisk ) {
10- $ScratchDisk = $PSScriptRoot -replace ' [\\]+$ ' , ' '
10+ $ScratchDisk = (( Get-Location ).Drive.Name) + " : "
1111} else {
1212 $ScratchDisk = $ScratchDisk + " :"
1313}
1414
1515Write-Output " Scratch disk set to $ScratchDisk "
1616
17- # Check if PowerShell execution is restricted
18- if ((Get-ExecutionPolicy ) -eq ' Restricted' ) {
19- 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)"
17+ # Check if PowerShell execution is Restricted or AllSigned or Undefined
18+ $needchange = @ (" AllSigned" , " Restricted" , " Undefined" )
19+ $curpolicy = Get-ExecutionPolicy
20+ if ($curpolicy -in $needchange ) {
21+ 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)"
2022 $response = Read-Host
2123 if ($response -eq ' yes' ) {
2224 Set-ExecutionPolicy RemoteSigned - Scope CurrentUser - Confirm:$false
25+ Set-ExecutionPolicy RemoteSigned - Scope Process - Confirm:$false
2326 } else {
2427 Write-Host " The script cannot be run without changing the execution policy. Exiting..."
2528 exit
@@ -32,8 +35,7 @@ $adminGroup = $adminSID.Translate([System.Security.Principal.NTAccount])
3235$myWindowsID = [System.Security.Principal.WindowsIdentity ]::GetCurrent()
3336$myWindowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($myWindowsID )
3437$adminRole = [System.Security.Principal.WindowsBuiltInRole ]::Administrator
35- if (! $myWindowsPrincipal.IsInRole ($adminRole ))
36- {
38+ if (! $myWindowsPrincipal.IsInRole ($adminRole )) {
3739 Write-Host " Restarting Tiny11 image creator as admin in a new window, you can close this one."
3840 $newProcess = new-object System.Diagnostics.ProcessStartInfo " PowerShell" ;
3941 $newProcess.Arguments = $myInvocation.MyCommand.Definition ;
@@ -42,10 +44,8 @@ if (! $myWindowsPrincipal.IsInRole($adminRole))
4244 exit
4345}
4446
45-
46-
4747# Start the transcript and prepare the window
48- Start-Transcript - Path " $ScratchDisk \tiny11.log"
48+ Start-Transcript - Path " $ScratchDisk \tiny11.log"
4949
5050$Host.UI.RawUI.WindowTitle = " Tiny11 image creator"
5151Clear-Host
@@ -87,19 +87,26 @@ Start-Sleep -Seconds 2
8787Clear-Host
8888Write-Host " Getting image information:"
8989Get-WindowsImage - ImagePath $ScratchDisk \tiny11\sources\install.wim
90- $index = Read-Host " Please enter the image index"
90+
91+ $index = Read-Host " Please enter the image index : "
92+ $ImagesIndex = (Get-WindowsImage - ImagePath $ScratchDisk \tiny11\sources\install.wim).ImageIndex
93+ while ($ImagesIndex -notcontains $index ) {
94+ $index = Read-Host " Please enter a valide image index : "
95+ }
96+
9197Write-Host " Mounting Windows image. This may take a while."
9298$wimFilePath = " $ScratchDisk \tiny11\sources\install.wim"
93- & takeown " /F" $wimFilePath
99+ & takeown " /F" $wimFilePath
94100& icacls $wimFilePath " /grant" " $ ( $adminGroup.Value ) :(F)"
95101try {
96102 Set-ItemProperty - Path $wimFilePath - Name IsReadOnly - Value $false - ErrorAction Stop
97103} catch {
98104 # This block will catch the error and suppress it.
99105}
100106New-Item - ItemType Directory - Force - Path " $ScratchDisk \scratchdir" > $null
101- Mount-WindowsImage - ImagePath $ScratchDisk \tiny11\sources\install.wim - Index $index - Path $ScratchDisk \scratchdir
107+ Mount-WindowsImage - ImagePath $wimFilePath - Index $index - Path $ScratchDisk \scratchdir
102108
109+ # Powershell dism module does not have direct equivalent for /Get-Intl
103110$imageIntl = & dism / English / Get-Intl " /Image:$ ( $ScratchDisk ) \scratchdir"
104111$languageLine = $imageIntl -split ' \n' | Where-Object { $_ -match ' Default system UI language : ([a-zA-Z]{2}-[a-zA-Z]{2})' }
105112
@@ -110,45 +117,71 @@ if ($languageLine) {
110117 Write-Host " Default system UI language code not found."
111118}
112119
113- $imageInfo = & ' dism' ' /English' ' /Get-WimInfo' " /wimFile:$ ( $ScratchDisk ) \tiny11\sources\install.wim" " /index:$index "
114- $lines = $imageInfo -split ' \r?\n'
115-
116- foreach ($line in $lines ) {
117- if ($line -like ' *Architecture : *' ) {
118- $architecture = $line -replace ' Architecture : ' , ' '
119- # If the architecture is x64, replace it with amd64
120- if ($architecture -eq ' x64' ) {
121- $architecture = ' amd64'
122- }
123- Write-Host " Architecture: $architecture "
124- break
125- }
120+ # Defined in (Microsoft.Dism.Commands.ImageInfoObject).Architecture formatting script
121+ # 0 -> x86, 5 -> arm(currently unused), 6 -> ia64(currently unused), 9 -> x64, 12 -> arm64
122+ switch ((Get-WindowsImage - ImagePath $wimFilePath - Index $index ).Architecture)
123+ {
124+ 0 { $architecture = " x86" }
125+ 9 { $architecture = " amd64" }
126+ 12 { $architecture = " arm64" }
126127}
127128
128129if (-not $architecture ) {
130+ if ($architecture ) {
131+ Write-Host " Architecture: $architecture "
132+ } else {
129133 Write-Host " Architecture information not found."
130134}
131135
132- Write-Host " Mounting complete! Performing removal of applications..."
136+ Write-Host " Mounting complete! Performing removal of applications...`n "
133137
134- $packages = & ' dism ' ' /English ' " /image: $ ( $ ScratchDisk) \scratchdir" ' /Get-ProvisionedAppxPackages ' |
138+ $packages = Get-ProvisionedAppxPackage - Path " $ ScratchDisk \scratchdir" |
135139 ForEach-Object {
136- if ($_ -match ' PackageName : (.*)' ) {
137- $matches [1 ]
138- }
140+ $_.PackageName
139141 }
140- $packagePrefixes = ' Clipchamp.Clipchamp_' , ' Microsoft.BingNews_' , ' Microsoft.BingWeather_' , ' Microsoft.GamingApp_' , ' Microsoft.GetHelp_' , ' Microsoft.Getstarted_' , ' Microsoft.MicrosoftOfficeHub_' , ' Microsoft.MicrosoftSolitaireCollection_' , ' Microsoft.People_' , ' Microsoft.PowerAutomateDesktop_' , ' Microsoft.Todos_' , ' Microsoft.WindowsAlarms_' , ' microsoft.windowscommunicationsapps_' , ' Microsoft.WindowsFeedbackHub_' , ' Microsoft.WindowsMaps_' , ' Microsoft.WindowsSoundRecorder_' , ' Microsoft.Xbox.TCUI_' , ' Microsoft.XboxGamingOverlay_' , ' Microsoft.XboxGameOverlay_' , ' Microsoft.XboxSpeechToTextOverlay_' , ' Microsoft.YourPhone_' , ' Microsoft.ZuneMusic_' , ' Microsoft.ZuneVideo_' , ' MicrosoftCorporationII.MicrosoftFamily_' , ' MicrosoftCorporationII.QuickAssist_' , ' MicrosoftTeams_' , ' Microsoft.549981C3F5F10_'
142+
143+ $packagePrefixes =
144+ ' Clipchamp.Clipchamp_' ,
145+ ' Microsoft.BingNews_' ,
146+ ' Microsoft.BingSearch_' ,
147+ ' Microsoft.BingWeather_' ,
148+ ' Microsoft.GamingApp_' ,
149+ ' Microsoft.GetHelp_' ,
150+ ' Microsoft.Getstarted_' ,
151+ ' Microsoft.MicrosoftOfficeHub_' ,
152+ ' Microsoft.MicrosoftSolitaireCollection_' ,
153+ ' Microsoft.OutlookForWindows_' ,
154+ ' Microsoft.People_' ,
155+ ' Microsoft.MicrosoftStickyNotes_' ,
156+ ' Microsoft.Todos_' ,
157+ ' Microsoft.WindowsAlarms_' ,
158+ ' microsoft.windowscommunicationsapps_' ,
159+ ' Microsoft.WindowsFeedbackHub_' ,
160+ ' Microsoft.WindowsMaps_' ,
161+ ' Microsoft.WindowsSoundRecorder_' ,
162+ ' Microsoft.Xbox.TCUI_' ,
163+ ' Microsoft.XboxGameOverlay_' ,
164+ ' Microsoft.XboxGamingOverlay_' ,
165+ ' Microsoft.XboxSpeechToTextOverlay_' ,
166+ ' Microsoft.YourPhone_' ,
167+ ' Microsoft.ZuneMusic_' ,
168+ ' Microsoft.ZuneVideo_' ,
169+ ' MicrosoftCorporationII.MicrosoftFamily_' ,
170+ ' MicrosoftCorporationII.QuickAssist_' ,
171+ ' MicrosoftTeams_' ,
172+ ' Microsoft.549981C3F5F10_' ,
173+ ' MSTeams_'
141174
142175$packagesToRemove = $packages | Where-Object {
143176 $packageName = $_
144177 $packagePrefixes -contains ($packagePrefixes | Where-Object { $packageName -like " $_ *" })
145178}
146179foreach ($package in $packagesToRemove ) {
147- & ' dism' ' /English' " /image:$ ( $ScratchDisk ) \scratchdir" ' /Remove-ProvisionedAppxPackage' " /PackageName:$package "
180+ Write-Host " Removing $package ..."
181+ Remove-AppxProvisionedPackage - Path " $ScratchDisk \scratchdir" - PackageName " $package " | Out-Null
148182}
149183
150-
151- Write-Host " Removing Edge:"
184+ Write-Host " `n Removing Edge:"
152185Remove-Item - Path " $ScratchDisk \scratchdir\Program Files (x86)\Microsoft\Edge" - Recurse - Force | Out-Null
153186Remove-Item - Path " $ScratchDisk \scratchdir\Program Files (x86)\Microsoft\EdgeUpdate" - Recurse - Force | Out-Null
154187Remove-Item - Path " $ScratchDisk \scratchdir\Program Files (x86)\Microsoft\EdgeCore" - Recurse - Force | Out-Null
@@ -258,8 +291,8 @@ Write-Host "Disabling Telemetry:"
258291& ' reg' ' add' ' HKLM\zNTUSER\Software\Microsoft\Personalization\Settings' ' /v' ' AcceptedPrivacyPolicy' ' /t' ' REG_DWORD' ' /d' ' 0' ' /f' | Out-Null
259292& ' reg' ' add' ' HKLM\zSOFTWARE\Policies\Microsoft\Windows\DataCollection' ' /v' ' AllowTelemetry' ' /t' ' REG_DWORD' ' /d' ' 0' ' /f' | Out-Null
260293& ' reg' ' add' ' HKLM\zSYSTEM\ControlSet001\Services\dmwappushservice' ' /v' ' Start' ' /t' ' REG_DWORD' ' /d' ' 4' ' /f' | Out-Null
261- # # Prevents installation or DevHome and Outlook
262- Write-Host " Prevents installation or DevHome and Outlook:"
294+ # # Prevents installation of DevHome and Outlook
295+ Write-Host " Prevents installation of DevHome and Outlook:"
263296& ' reg' ' add' ' HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\OutlookUpdate' ' /v' ' workCompleted' ' /t' ' REG_DWORD' ' /d' ' 1' ' /f' | Out-Null
264297& ' reg' ' add' ' HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\DevHomeUpdate' ' /v' ' workCompleted' ' /t' ' REG_DWORD' ' /d' ' 1' ' /f' | Out-Null
265298& ' reg' ' delete' ' HKLM\zSOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate' ' /f' | Out-Null
@@ -289,13 +322,13 @@ function Enable-Privilege {
289322 $definition = @'
290323 using System;
291324 using System.Runtime.InteropServices;
292-
325+
293326 public class AdjPriv
294327 {
295328 [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
296329 internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
297330 ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
298-
331+
299332 [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
300333 internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
301334 [DllImport("advapi32.dll", SetLastError = true)]
@@ -307,7 +340,7 @@ function Enable-Privilege {
307340 public long Luid;
308341 public int Attr;
309342 }
310-
343+
311344 internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
312345 internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
313346 internal const int TOKEN_QUERY = 0x00000008;
@@ -364,7 +397,7 @@ Write-Host 'Deleting Customer Experience Improvement Program'
364397reg delete " HKEY_LOCAL_MACHINE\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{4738DE7A-BCC1-4E2D-B1B0-CADB044BFA81}" / f | Out-Null
365398reg delete " HKEY_LOCAL_MACHINE\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{6FAC31FA-4A85-4E64-BFD5-2154FF4594B3}" / f | Out-Null
366399reg delete " HKEY_LOCAL_MACHINE\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{FC931F16-B50A-472E-B061-B6F79A71EF59}" / f | Out-Null
367- Write-Host ' Deleting Program Data Updater'
400+ Write-Host ' Deleting Program Data Updater'
368401reg delete " HKEY_LOCAL_MACHINE\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{0671EB05-7D95-4153-A32B-1426B9FE61DB}" / f | Out-Null
369402Write-Host ' Deleting autochk proxy'
370403reg delete " HKEY_LOCAL_MACHINE\zSOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\{87BF85F4-2CE1-4160-96EA-52F554AA28A2}" / f | Out-Null
@@ -396,7 +429,7 @@ Write-Host "Windows image completed. Continuing with boot.wim."
396429Start-Sleep - Seconds 2
397430Clear-Host
398431Write-Host " Mounting boot image:"
399- $wimFilePath = " $ScratchDisk \tiny11\sources\boot.wim"
432+ $wimFilePath = " $ScratchDisk \tiny11\sources\boot.wim"
400433& takeown " /F" $wimFilePath | Out-Null
401434& icacls $wimFilePath " /grant" " $ ( $adminGroup.Value ) :(F)"
402435Set-ItemProperty - Path $wimFilePath - Name IsReadOnly - Value $false
@@ -436,22 +469,31 @@ Write-Host "The tiny11 image is now completed. Proceeding with the making of the
436469Write-Host " Copying unattended file for bypassing MS account on OOBE..."
437470Copy-Item - Path " $PSScriptRoot \autounattend.xml" - Destination " $ScratchDisk \tiny11\autounattend.xml" - Force | Out-Null
438471Write-Host " Creating ISO image..."
439- $ADKDepTools = " C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\$hostarchitecture \Oscdimg"
472+ # Get Windows ADK path from registry(following Visual Studio's winsdk.bat approach).
473+ $WinSDKPath = [Microsoft.Win32.Registry ]::GetValue(" HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots" , " KitsRoot10" , $null )
474+ if (! $WinSDKPath ) {
475+ $WinSDKPath = [Microsoft.Win32.Registry ]::GetValue(" HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots" , " KitsRoot10" , $null )
476+ }
477+ if ($WinSDKPath ) {
478+ # Trim the following backslash for path concatenation.
479+ $WinSDKPath = $WinSDKPath.TrimEnd (' \' )
480+ $ADKDepTools = " $WinSDKPath \Assessment and Deployment Kit\Deployment Tools\$hostarchitecture \Oscdimg"
481+ }
440482$localOSCDIMGPath = " $PSScriptRoot \oscdimg.exe"
441483
442- if ([System.IO.Directory ]::Exists($ADKDepTools )) {
484+ if ($ADKDepTools -and [System.IO.File ]::Exists(" $ADKDepTools \oscdimg.exe " )) {
443485 Write-Host " Will be using oscdimg.exe from system ADK."
444486 $OSCDIMG = " $ADKDepTools \oscdimg.exe"
445487} else {
446- Write-Host " ADK folder not found. Will be using bundled oscdimg.exe."
447-
488+ Write-Host " oscdimg.exe from system ADK not found. Will be using bundled oscdimg.exe."
489+
448490 $url = " https://msdl.microsoft.com/download/symbols/oscdimg.exe/3D44737265000/oscdimg.exe"
449491
450- if (-not ( Test-Path - Path $localOSCDIMGPath )) {
492+ if (! [ System.IO.File ]::Exists( $localOSCDIMGPath )) {
451493 Write-Host " Downloading oscdimg.exe..."
452494 Invoke-WebRequest - Uri $url - OutFile $localOSCDIMGPath
453495
454- if (Test-Path $localOSCDIMGPath ) {
496+ if ([ System.IO.File ]::Exists( $localOSCDIMGPath ) ) {
455497 Write-Host " oscdimg.exe downloaded successfully."
456498 } else {
457499 Write-Error " Failed to download oscdimg.exe."
0 commit comments