Skip to content

Fix with oscdimg.exe search, ExecutionPolicy, compression, etc.. #319

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You can now use it on ANY Windows 11 release (not just a specific build), as wel
This is made possible thanks to the much-improved scripting capabilities of PowerShell, compared to the older Batch release.
</br>
Since it is written in PowerShell, you need to set the execution policy to `Unrestricted`, so that you could run the script.
If you haven't done this before, make sure to run `Set-ExecutionPolicy unrestricted` as administrator in PowerShell before running the script, otherwise it would just crash.
If you haven't done this before, make sure to run `Set-ExecutionPolicy -Scope Process unrestricted` as administrator in PowerShell before running the script, otherwise it would just crash.


This is a script created to automate the build of a streamlined Windows 11 image, similar to tiny11.
Expand Down
5 changes: 5 additions & 0 deletions Run.bat
Original file line number Diff line number Diff line change
@@ -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}"
29 changes: 20 additions & 9 deletions tiny11Coremaker.ps1
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Enable debugging
Set-PSDebug -Trace 1

# Check if PowerShell execution is restricted
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
Copy link
Author

@Snshadow Snshadow Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am curious if this part is actually called, is this for some possible cases where the user tries to run it from powershell they have been using for different activity which could have set ExecutionPolicy to the value that does not allow script to run? I think in normal cases, the user will run it with from the powershell which have the ExecutionPolicy that allow to run custom scripts, and it is inherited, which make it will never be the ones that need to be changed for elevation.

$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-Host "The script cannot be run without changing the execution policy. Exiting..."
exit
Expand Down Expand Up @@ -730,16 +732,25 @@ Write-Host "Exporting ESD. This may take a while..."
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"
# 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)) {
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 "ADK folder not found. Will be using bundled oscdimg.exe."


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 (-not (Test-Path -Path $localOSCDIMGPath)) {
Expand Down
85 changes: 46 additions & 39 deletions tiny11maker.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,26 @@
#Set-PSDebug -Trace 1

param (
[ValidatePattern('^[c-zC-Z]$')]
[ValidatePattern('^[c-zC-Z]:$')]
[string]$ScratchDisk
)

if (-not $ScratchDisk) {
$ScratchDisk = $PSScriptRoot -replace '[\\]+$', ''
$ScratchDisk = ((Get-Location).Drive.Name) + ":"
} else {
$ScratchDisk = $ScratchDisk + ":"
}

Write-Output "Scratch disk set to $ScratchDisk"

# Check if PowerShell execution is restricted
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-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-Host "The script cannot be run without changing the execution policy. Exiting..."
exit
Expand All @@ -42,8 +44,6 @@ if (! $myWindowsPrincipal.IsInRole($adminRole))
exit
}



# Start the transcript and prepare the window
Start-Transcript -Path "$ScratchDisk\tiny11.log"

Expand Down Expand Up @@ -98,8 +98,9 @@ try {
# This block will catch the error and suppress it.
}
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})' }

Expand All @@ -110,45 +111,42 @@ if ($languageLine) {
Write-Host "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-Host "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-Host "Architecture: $architecture"
} else {
Write-Host "Architecture information not found."
}

Write-Host "Mounting complete! Performing removal of applications..."

$packages = & 'dism' '/English' "/image:$($ScratchDisk)\scratchdir" '/Get-ProvisionedAppxPackages' |
Write-Host "Mounting complete! Performing removal of applications...`n"

$packages = Get-ProvisionedAppxPackage -Path "$ScratchDisk\scratchdir" |
ForEach-Object {
if ($_ -match 'PackageName : (.*)') {
$matches[1]
}
$_.PackageName
}

$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_'

$packagesToRemove = $packages | Where-Object {
$packageName = $_
$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-Host "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
Expand Down Expand Up @@ -388,10 +386,9 @@ Write-Host ' '
Write-Host "Unmounting image..."
Dismount-WindowsImage -Path $ScratchDisk\scratchdir -Save
Write-Host "Exporting image..."
# Compressiontype Recovery is not supported with PShell https://learn.microsoft.com/en-us/powershell/module/dism/export-windowsimage?view=windowsserver2022-ps#-compressiontype
Export-WindowsImage -SourceImagePath $ScratchDisk\tiny11\sources\install.wim -SourceIndex $index -DestinationImagePath $ScratchDisk\tiny11\sources\install2.wim -CompressionType Fast
Remove-Item -Path "$ScratchDisk\tiny11\sources\install.wim" -Force | Out-Null
Rename-Item -Path "$ScratchDisk\tiny11\sources\install2.wim" -NewName "install.wim" | Out-Null
# 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"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although it is said that Compressiontype Recovery is not supported with PShell, actually Export-WindowsImage used to support the same compression algorithm used for Recovery from Windows 10(it internally uses WIMExportFile, which used to support LZMS compression) and it even works with .wim extension.

Move-Item -Path "$ScratchDisk\tiny11\sources\install2.wim" -Destination "$ScratchDisk\tiny11\sources\install.wim" -Force | Out-Null
Write-Host "Windows image completed. Continuing with boot.wim."
Start-Sleep -Seconds 2
Clear-Host
Expand Down Expand Up @@ -436,22 +433,32 @@ Write-Host "The tiny11 image is now completed. Proceeding with the making of the
Write-Host "Copying unattended file for bypassing MS account on OOBE..."
Copy-Item -Path "$PSScriptRoot\autounattend.xml" -Destination "$ScratchDisk\tiny11\autounattend.xml" -Force | Out-Null
Write-Host "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-Host "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-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 (-not (Test-Path -Path $localOSCDIMGPath)) {
if (![System.IO.File]::Exists($localOSCDIMGPath)) {
Write-Host "Downloading oscdimg.exe..."
Invoke-WebRequest -Uri $url -OutFile $localOSCDIMGPath

if (Test-Path $localOSCDIMGPath) {
if ([System.IO.File]::Exists($localOSCDIMGPath)) {
Write-Host "oscdimg.exe downloaded successfully."
} else {
Write-Error "Failed to download oscdimg.exe."
Expand Down