From 70f3ed541f9d3e2f2b6760688f5bb11f6c8ca8cb Mon Sep 17 00:00:00 2001 From: CodingWonders <101426328+CodingWonders@users.noreply.github.com> Date: Thu, 28 Mar 2024 16:50:49 +0100 Subject: [PATCH] Fixed Ventoy drive copy typo and began conversion of DISM commands into DISM cmdlets (#1727) * Fixed Ventoy drive copy typo * DISM cmdlet Update (Part 1) Began replacing basic DISM commands with cmdlets from the DISM module. This change only affects the mount, unmount, and export operations. All other operations still use DISM --------- Co-authored-by: Chris Titus --- functions/private/Invoke-MicroWin-Helper.ps1 | 2 +- functions/public/Invoke-WPFMicrowin.ps1 | 20 +- winutil.ps1 | 12591 ----------------- 3 files changed, 15 insertions(+), 12598 deletions(-) diff --git a/functions/private/Invoke-MicroWin-Helper.ps1 b/functions/private/Invoke-MicroWin-Helper.ps1 index 58acf581..3ae08d49 100644 --- a/functions/private/Invoke-MicroWin-Helper.ps1 +++ b/functions/private/Invoke-MicroWin-Helper.ps1 @@ -195,7 +195,7 @@ function Copy-ToUSB([string] $fileToCopy) Write-Progress -Activity "Copying File" -Status "Progress" -PercentComplete $completed -CurrentOperation ("{0:N2} MB / {1:N2} MB" -f ($_.BytesTransferred / 1MB), ($totalSize / 1MB)) } - Write-Host "File copied to Ventoy drive $($volume.DriveLette)" + Write-Host "File copied to Ventoy drive $($volume.DriveLetter)" return } } diff --git a/functions/public/Invoke-WPFMicrowin.ps1 b/functions/public/Invoke-WPFMicrowin.ps1 index 8aa4d79a..6c8a2d6a 100644 --- a/functions/public/Invoke-WPFMicrowin.ps1 +++ b/functions/public/Invoke-WPFMicrowin.ps1 @@ -100,8 +100,16 @@ public class PowerManagement { try { Write-Host "Mounting Windows image. This may take a while." - dism /mount-image /imagefile:$mountDir\sources\install.wim /index:$index /mountdir:$scratchDir - Write-Host "Mounting complete! Performing removal of applications..." + Mount-WindowsImage -ImagePath "$mountDir\sources\install.wim" -Index $index -Path "$scratchDir" + if ($?) + { + Write-Host "Mounting complete! Performing removal of applications..." + } + else + { + Write-Host "Could not mount image. Exiting..." + return + } if ($injectDrivers) { @@ -299,13 +307,13 @@ public class PowerManagement { Write-Host "Cleanup complete." Write-Host "Unmounting image..." - dism /unmount-image /mountdir:$scratchDir /commit + Dismount-WindowsImage -Path $scratchDir -Save } try { Write-Host "Exporting image into $mountDir\sources\install2.wim" - dism /Export-Image /SourceImageFile:"$mountDir\sources\install.wim" /SourceIndex:$index /DestinationImageFile:"$mountDir\sources\install2.wim" /compress:max + Export-WindowsImage -SourceImagePath "$mountDir\sources\install.wim" -SourceIndex $index -DestinationImagePath "$mountDir\sources\install2.wim" -CompressionType "Max" Write-Host "Remove old '$mountDir\sources\install.wim' and rename $mountDir\sources\install2.wim" Remove-Item "$mountDir\sources\install.wim" Rename-Item "$mountDir\sources\install2.wim" "$mountDir\sources\install.wim" @@ -319,7 +327,7 @@ public class PowerManagement { # Next step boot image Write-Host "Mounting boot image $mountDir\sources\boot.wim into $scratchDir" - dism /mount-image /imagefile:"$mountDir\sources\boot.wim" /index:2 /mountdir:"$scratchDir" + Mount-WindowsImage -ImagePath "$mountDir\sources\boot.wim" -Index 2 -Path "$scratchDir" if ($injectDrivers) { @@ -365,7 +373,7 @@ public class PowerManagement { reg unload HKLM\zSYSTEM Write-Host "Unmounting image..." - dism /unmount-image /mountdir:$scratchDir /commit + Dismount-WindowsImage -Path $scratchDir -Save Write-Host "Creating ISO image" diff --git a/winutil.ps1 b/winutil.ps1 index 1bd8ad90..e69de29b 100644 --- a/winutil.ps1 +++ b/winutil.ps1 @@ -1,12591 +0,0 @@ - -################################################################################################################ -### ### -### WARNING: This file is automatically generated DO NOT modify this file directly as it will be overwritten ### -### ### -################################################################################################################ - -<# -.NOTES - Author : Chris Titus @christitustech - Runspace Author: @DeveloperDurp - GitHub : https://github.com/ChrisTitusTech - Version : 24.03.28 -#> -param ( - [switch]$Debug, - [string]$Config, - [switch]$Run -) - -# Set DebugPreference based on the -Debug switch -if ($Debug) { - $DebugPreference = "Continue" -} - -if ($Config) { - $PARAM_CONFIG = $Config -} - -$PARAM_RUN = $false -# Handle the -Run switch -if ($Run) { - Write-Host "Running config file tasks..." - $PARAM_RUN = $true -} - -if (!(Test-Path -Path $ENV:TEMP)) { - New-Item -ItemType Directory -Force -Path $ENV:TEMP -} - -Start-Transcript $ENV:TEMP\Winutil.log -Append - -# Load DLLs -Add-Type -AssemblyName PresentationFramework -Add-Type -AssemblyName System.Windows.Forms - -# Variable to sync between runspaces -$sync = [Hashtable]::Synchronized(@{}) -$sync.PSScriptRoot = $PSScriptRoot -$sync.version = "24.03.28" -$sync.configs = @{} -$sync.ProcessRunning = $false - -$currentPid = [System.Security.Principal.WindowsIdentity]::GetCurrent() -$principal = new-object System.Security.Principal.WindowsPrincipal($currentPid) -$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator - - -if ($principal.IsInRole($adminRole)) -{ - $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Admin)" - clear-host -} -else -{ - $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell"; - $newProcess.Arguments = $myInvocation.MyCommand.Definition; - $newProcess.Verb = "runas"; - [System.Diagnostics.Process]::Start($newProcess); - break -} -function ConvertTo-Icon { - <# - - .DESCRIPTION - This function will convert PNG to ICO file - - .EXAMPLE - ConvertTo-Icon -bitmapPath "$env:TEMP\cttlogo.png" -iconPath $iconPath - #> - param( [Parameter(Mandatory=$true)] - $bitmapPath, - $iconPath = "$env:temp\newicon.ico" - ) - - Add-Type -AssemblyName System.Drawing - - if (Test-Path $bitmapPath) { - $b = [System.Drawing.Bitmap]::FromFile($bitmapPath) - $icon = [System.Drawing.Icon]::FromHandle($b.GetHicon()) - $file = New-Object System.IO.FileStream($iconPath, 'OpenOrCreate') - $icon.Save($file) - $file.Close() - $icon.Dispose() - #explorer "/SELECT,$iconpath" - } - else { Write-Warning "$BitmapPath does not exist" } -} -function Copy-Files { - <# - - .DESCRIPTION - This function will make all modifications to the registry - - .EXAMPLE - - Set-WinUtilRegistry -Name "PublishUserActivities" -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Type "DWord" -Value "0" - - #> - param ( - [string] $Path, - [string] $Destination, - [switch] $Recurse = $false, - [switch] $Force = $false - ) - - try { - - $files = Get-ChildItem -Path $path -Recurse:$recurse - Write-Host "Copy $($files.Count)(s) from $path to $destination" - - foreach($file in $files) - { - $status = "Copy files {0} on {1}: {2}" -f $counter, $files.Count, $file.Name - Write-Progress -Activity "Copy Windows files" -Status $status -PercentComplete ($counter++/$files.count*100) - $restpath = $file.FullName -Replace $path, '' - - if($file.PSIsContainer -eq $true) - { - Write-Debug "Creating $($destination + $restpath)" - New-Item ($destination+$restpath) -Force:$force -Type Directory -ErrorAction SilentlyContinue - } - else - { - Write-Debug "Copy from $($file.FullName) to $($destination+$restpath)" - Copy-Item $file.FullName ($destination+$restpath) -ErrorAction SilentlyContinue -Force:$force - Set-ItemProperty -Path ($destination+$restpath) -Name IsReadOnly -Value $false - } - } - Write-Progress -Activity "Copy Windows files" -Status "Ready" -Completed - } - Catch{ - Write-Warning "Unable to Copy all the files due to unhandled exception" - Write-Warning $psitem.Exception.StackTrace - } -} -function Get-LocalizedYesNo { - <# - .SYNOPSIS - This function runs choice.exe and captures its output to extract yes no in a localized Windows - - .DESCRIPTION - The function retrieves the output of the command 'cmd /c "choice nul"' and converts the default output for Yes and No - in the localized format, such as "Yes=, No=". - - .EXAMPLE - $yesNoArray = Get-LocalizedYesNo - Write-Host "Yes=$($yesNoArray[0]), No=$($yesNoArray[1])" - #> - - # Run choice and capture its options as output - # The output shows the options for Yes and No as "[Y,N]?" in the (partitially) localized format. - # eg. English: [Y,N]? - # Dutch: [Y,N]? - # German: [J,N]? - # French: [O,N]? - # Spanish: [S,N]? - # Italian: [S,N]? - # Russian: [Y,N]? - - $line = cmd /c "choice nul" - $charactersArray = @() - $regexPattern = '([a-zA-Z])' - $charactersArray = [regex]::Matches($line, $regexPattern) | ForEach-Object { $_.Groups[1].Value } - - Write-Debug "According to takeown.exe local Yes is $charactersArray[0]" - # Return the array of characters - return $charactersArray - } - - -function Get-LocalizedYesNoTakeown { - <# - .SYNOPSIS - This function runs takeown.exe and captures its output to extract yes no in a localized Windows - - .DESCRIPTION - The function retrieves lines from the output of takeown.exe until there are at least 2 characters - captured in a specific format, such as "Yes=, No=". - - .EXAMPLE - $yesNoArray = Get-LocalizedYesNo - Write-Host "Yes=$($yesNoArray[0]), No=$($yesNoArray[1])" - #> - - # Run takeown.exe and capture its output - $takeownOutput = & takeown.exe /? | Out-String - - # Parse the output and retrieve lines until there are at least 2 characters in the array - $found = $false - $charactersArray = @() - foreach ($line in $takeownOutput -split "`r`n") - { - # skip everything before /D flag help - if ($found) - { - # now that /D is found start looking for a single character in double quotes - # in help text there is another string in double quotes but it is not a single character - $regexPattern = '"([a-zA-Z])"' - - $charactersArray = [regex]::Matches($line, $regexPattern) | ForEach-Object { $_.Groups[1].Value } - - # if ($charactersArray.Count -gt 0) { - # Write-Output "Extracted symbols: $($matches -join ', ')" - # } else { - # Write-Output "No matches found." - # } - - if ($charactersArray.Count -ge 2) - { - break - } - } - elseif ($line -match "/D ") - { - $found = $true - } - } - - Write-Debug "According to takeown.exe local Yes is $charactersArray[0]" - # Return the array of characters - return $charactersArray - } -function Get-Oscdimg { - <# - - .DESCRIPTION - This function will download oscdimg file from github Release folders and put it into env:temp folder - - .EXAMPLE - Get-Oscdimg - #> - param( [Parameter(Mandatory=$true)] - [string]$oscdimgPath - ) - $oscdimgPath = "$env:TEMP\oscdimg.exe" - $downloadUrl = "https://github.com/ChrisTitusTech/winutil/raw/main/releases/oscdimg.exe" - Invoke-RestMethod -Uri $downloadUrl -OutFile $oscdimgPath - $hashResult = Get-FileHash -Path $oscdimgPath -Algorithm SHA256 - $sha256Hash = $hashResult.Hash - - Write-Host "[INFO] oscdimg.exe SHA-256 Hash: $sha256Hash" - - $expectedHash = "AB9E161049D293B544961BFDF2D61244ADE79376D6423DF4F60BF9B147D3C78D" # Replace with the actual expected hash - if ($sha256Hash -eq $expectedHash) { - Write-Host "Hashes match. File is verified." - } else { - Write-Host "Hashes do not match. File may be corrupted or tampered with." - } -} -function Get-TabXaml { - <# - .SYNOPSIS - Generates XAML for a tab in the WinUtil GUI - This function is used to generate the XAML for the applications tab in the WinUtil GUI - It takes the tabname and the number of columns to display the applications in as input and returns the XAML for the tab as output - .PARAMETER tabname - The name of the tab to generate XAML for - .PARAMETER columncount - The number of columns to display the applications in - .OUTPUTS - The XAML for the tab - .EXAMPLE - Get-TabXaml "applications" 3 - #> - - - param( [Parameter(Mandatory=$true)] - $tabname, - $columncount = 0 - ) - $organizedData = @{} - # Iterate through JSON data and organize by panel and category - foreach ($appName in $sync.configs.$tabname.PSObject.Properties.Name) { - $appInfo = $sync.configs.$tabname.$appName - - # Create an object for the application - $appObject = [PSCustomObject]@{ - Name = $appName - Category = $appInfo.Category - Content = $appInfo.Content - Choco = $appInfo.choco - Winget = $appInfo.winget - Panel = if ($columncount -gt 0 ) { "0" } else {$appInfo.panel} - Link = $appInfo.link - Description = $appInfo.description - # Type is (Checkbox,Toggle,Button,Combobox ) (Default is Checkbox) - Type = $appInfo.type - ComboItems = $appInfo.ComboItems - # Checked is the property to set startup checked status of checkbox (Default is false) - Checked = $appInfo.Checked - } - - if (-not $organizedData.ContainsKey($appObject.panel)) { - $organizedData[$appObject.panel] = @{} - } - - if (-not $organizedData[$appObject.panel].ContainsKey($appObject.Category)) { - $organizedData[$appObject.panel][$appObject.Category] = @{} - } - - # Store application data in a sub-array under the category - # Add Order property to keep the original order of tweaks and features - $organizedData[$appObject.panel][$appInfo.Category]["$($appInfo.order)$appName"] = $appObject - } - $panelcount=0 - $paneltotal = $organizedData.Keys.Count - if ($columncount -gt 0) { - $appcount = $sync.configs.$tabname.PSObject.Properties.Name.count + $organizedData["0"].Keys.count - $maxcount = [Math]::Round( $appcount / $columncount + 0.5) - $paneltotal = $columncount - } - # add ColumnDefinitions to evenly draw colums - $blockXml="`n"+("`n"*($paneltotal))+"`n" - # Iterate through organizedData by panel, category, and application - $count = 0 - foreach ($panel in ($organizedData.Keys | Sort-Object)) { - $blockXml += "`n`n" - $panelcount++ - foreach ($category in ($organizedData[$panel].Keys | Sort-Object)) { - $count++ - if ($columncount -gt 0) { - $panelcount2 = [Int](($count)/$maxcount-0.5) - if ($panelcount -eq $panelcount2 ) { - $blockXml +="`n`n`n" - $blockXml += "`n`n" - $panelcount++ - } - } - $blockXml += "`n`n" - $blockXml += "`n`n" - $panelcount++ - } - } - $appInfo = $organizedData[$panel][$category][$appName] - if ("Toggle" -eq $appInfo.Type) { - $blockXml += "`n`n" - } elseif ("Combobox" -eq $appInfo.Type) { - $blockXml += "`n" - # If it is a digit, type is button and button length is digits - } elseif ($appInfo.Type -match "^[\d\.]+$") { - $blockXml += " - - - - - - Choose Windows SKU - - Choose Windows features you want to remove from the ISO - - - - - - - - - - -