From 4be4805e7cce9777e9e626b4153719ae269d9870 Mon Sep 17 00:00:00 2001 From: Chris Titus Date: Tue, 28 Nov 2023 16:11:11 -0600 Subject: [PATCH] Test 2023 11 15 (#1209) * Compile Winutil * fix enable toggle visual shape (#1179) * Compile Winutil * Update README.md (#1142) * Update README.md * Update README.md Update the README.md to be more precise & clear. Fix up grammatical mistakes, allow users to figure out their issues easier. Fix crediting of IRM execution script. * Update README.md * Compile Winutil * replacing the hard-coded paths for windows dir (#1126) * Changed version of python for winget to 3.12 (#1137) * Compile Winutil * Added Programs to the Install List (#1143) * Added the checkboxes of what I want to add * Added duplicati * Added KDE Connect * Added OpenVPN Connect * Added Oracle Virtual Box * Added Paint.net * Fixed an error spotted in the KDE Connect package names * Added the checkboxes into inputXML.xaml * Added the package details to config\applications.json * Reverted changes from winutil --------- Co-authored-by: Chris Titus * Compile Winutil * New Section: Customize Preferences (inside tweaks section) (#1163) * convert numlock on startup checkboxs into toggle button * convert verboselogon checkbox into toggle button * gui changes : added new section, new style for toggle buttons * convert showfileextentions checkbox into toggle button * convert mouse acceleration checkboxs into togglebutton * manor changes : cleanup, adding tooltips * fix style of toggle tweaks added new style 'labelfortweaks' that fix sytle and give mouse hover effect like previous tweaks that are using checkbox style but here for toggle tweaks we are using label and to make other tweaks style 'labelfortweaks' sytle is used. it mimic the style of checkbox style --------- Co-authored-by: Chris Titus * Compile Winutil * add Thunderbird (#1165) * Compile Winutil * Update the screenshot in README w/ dark mode (#1173) * took a pr on main and pulling it to test (#1175) * Add Session messenger to the applications list. (#1166) * Update applications.json * Update inputXML.xaml * Compile Winutil --------- Co-authored-by: charlescgs <135472912+charlescgs@users.noreply.github.com> Co-authored-by: ChrisTitusTech * Compile Winutil * fix enable toggle visual shape --------- Co-authored-by: ChrisTitusTech Co-authored-by: aim Co-authored-by: edelvarden <42596339+edelvarden@users.noreply.github.com> Co-authored-by: dass2608 <139251779+dass2608@users.noreply.github.com> Co-authored-by: Inventhrice <45127310+Inventhrice@users.noreply.github.com> Co-authored-by: Chris Titus Co-authored-by: Antun Nitraj Co-authored-by: Meen Beese Co-authored-by: charlescgs <135472912+charlescgs@users.noreply.github.com> Co-authored-by: padsalatushal * Add 2 Applications (#1180) This adds KDE Dolphin File Manager and Sublime Merge. * Compile Winutil * Microwin and fixes (#1184) * Microwin and fixes * comment out product key --------- Co-authored-by: KonTy Co-authored-by: Chris Titus * Compile Winutil * Microwin Fixes * Set owner fix for issue (#1184) (#1185) * Microwin and fixes * Fix for #1184, takeown doesn't work on non English Windows --------- Co-authored-by: KonTy * Compile Winutil * Microwin Fix on Bare Metal Fixes the "The computer restarted unexpectedly" error on a fresh install * Compile Winutil * MicroWin: fixing German and Spanish bugs (#1194) * Fixing German and other languages local issue, also doing some house keeping * Fixed several Microwin bugs * Fixing local bug and adding copy to USB feature * Adding driver injection capabilities and fixing bugs in Microwin --------- Co-authored-by: KonTy * Compile Winutil * error check before removing mountDir * MicroWin Finalized - fix typo - changed oscdimg from using & to Start-Process * Compile Winutil * winget reinstall addition * Adding Floorp Browser (#1204) * Update applications.json * Khalylexe patch 1 (#2) * Update inputXML.xaml * Update applications.json (#1) * Update applications.json * Update applications.json * Update inputXML.xaml * Compile Winutil * Mercury Browser from Alex313031 (#1206) * Compile Winutil * Add Git Extensions git client (#1201) * Compile Winutil * Add PDFsam Basic (#1198) * Compile Winutil * Add new applications (#1197) * Compile Winutil * fixed typo in a few places. (#1192) * Compile Winutil * Added new tools! (#1190) * Update applications.json Added: - Anki - Clipgrab - clink - copyq - Devtoys - ohmyposh - masscode - portmaster - starship * Update inputXML.xaml added the software to the form --------- Co-authored-by: Chris Titus * Compile Winutil * Update applications.json (#1187) Added to choco : nilesoft-shell prismlauncher bluestacks flameshot * Compile Winutil * fix unit test * Update functions.Tests.ps1 FIXED * fix trailing comma * Compile Winutil * Update winutil.ps1 --------- Co-authored-by: ChrisTitusTech Co-authored-by: Padsala Tushal <57517785+padsalatushal@users.noreply.github.com> Co-authored-by: aim Co-authored-by: edelvarden <42596339+edelvarden@users.noreply.github.com> Co-authored-by: dass2608 <139251779+dass2608@users.noreply.github.com> Co-authored-by: Inventhrice <45127310+Inventhrice@users.noreply.github.com> Co-authored-by: Antun Nitraj Co-authored-by: Meen Beese Co-authored-by: charlescgs <135472912+charlescgs@users.noreply.github.com> Co-authored-by: padsalatushal Co-authored-by: AshlynOrSomethin <31773733+AshlynOrSomethin@users.noreply.github.com> Co-authored-by: KonTy <9524513+KonTy@users.noreply.github.com> Co-authored-by: KonTy Co-authored-by: Khalyl <119526243+Khalylexe@users.noreply.github.com> Co-authored-by: Rodhri Erebo <109485128+erebus05@users.noreply.github.com> Co-authored-by: Julius Vitkauskas Co-authored-by: Finn Krestel <83225836+FinnKrestel@users.noreply.github.com> Co-authored-by: BladeWDR Co-authored-by: Albert <87888006+MustCodeAl@users.noreply.github.com> Co-authored-by: Straight <107145976+DaEpicR@users.noreply.github.com> --- .gitignore | 3 +- config/applications.json | 104 +- config/themes.json | 18 +- functions/private/Copy-Files.ps1 | 48 + functions/private/Get-LocalizedYesNo.ps1 | 42 + functions/private/Get-WinUtilVariables.ps1 | 2 +- functions/private/Install-WinUtilWinget.ps1 | 2 + functions/private/MicroWin-Helper.ps1 | 564 ++++++ functions/private/Remove-WinUtilAPPX.ps1 | 6 +- functions/public/Invoke-WPFButton.ps1 | 3 + functions/public/Invoke-WPFFixesWinget.ps1 | 13 + functions/public/Invoke-WPFFormVariables.ps1 | 1 - functions/public/Invoke-WPFGetIso.ps1 | 125 ++ functions/public/Invoke-WPFMicrowin.ps1 | 335 ++++ functions/public/Invoke-WPFTab.ps1 | 20 +- pester/functions.Tests.ps1 | 4 +- scripts/main.ps1 | 191 +- scripts/start.ps1 | 20 +- winutil.ps1 | 1892 +++++++++++++++++- xaml/inputXML.xaml | 396 +++- 20 files changed, 3652 insertions(+), 137 deletions(-) create mode 100644 functions/private/Copy-Files.ps1 create mode 100644 functions/private/Get-LocalizedYesNo.ps1 create mode 100644 functions/private/MicroWin-Helper.ps1 create mode 100644 functions/public/Invoke-WPFFixesWinget.ps1 create mode 100644 functions/public/Invoke-WPFGetIso.ps1 create mode 100644 functions/public/Invoke-WPFMicrowin.ps1 diff --git a/.gitignore b/.gitignore index b1f1a5bf..7499f6a9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,5 @@ Microsoft.PowerShell.ConsoleHost.dll ### MacOS ### # General -.DS_Store \ No newline at end of file +.DS_Store +microwin.log diff --git a/config/applications.json b/config/applications.json index 3de94361..38fe6c92 100755 --- a/config/applications.json +++ b/config/applications.json @@ -15,10 +15,18 @@ "Winget": "Alacritty.Alacritty", "choco": "alacritty" }, + "WPFInstallangryipscanner": { + "Winget": "angryziber.AngryIPScanner", + "choco": "angryip" + }, "WPFInstallanydesk": { "winget": "AnyDeskSoftwareGmbH.AnyDesk", "choco": "anydesk" }, + "WPFInstallanki": { + "winget": "Anki.Anki", + "choco": "anki" + }, "WPFInstallaimp": { "winget": "AIMP.AIMP", "choco": "aimp" @@ -41,7 +49,7 @@ }, "WPFInstallbluestacks": { "winget": "BlueStack.BlueStacks", - "choco": "na" + "choco": "bluestacks" }, "WPFInstallbrave": { "winget": "Brave.Brave", @@ -51,10 +59,18 @@ "winget": "Klocman.BulkCrapUninstaller", "choco": "bulk-crap-uninstaller" }, + "WPFInstallcalibre": { + "winget": "calibre.calibre", + "choco": "calibre" + }, "WPFInstallchrome": { "winget": "Google.Chrome", "choco": "googlechrome" }, + "WPFInstallcopyq": { + "winget": "copyq", + "choco": "copyq" + }, "WPFInstallchromium": { "winget": "eloston.ungoogled-chromium", "choco": "chromium" @@ -63,6 +79,14 @@ "winget": "CiderCollective.Cider", "choco": "cider" }, + "WPFInstallclink": { + "winget": "chrisant996.Clink", + "choco": "clink" + }, + "WPFInstallclipgrab": { + "winget": "na", + "choco": "clipgrab" + }, "WPFInstallcpuz": { "winget": "CPUID.CPU-Z", "choco": "cpu-z" @@ -75,6 +99,10 @@ "winget": "DelugeTeam.Deluge", "choco": "deluge" }, + "WPFInstalldevtoys": { + "winget": "devtoys", + "choco": "devToys" + }, "WPFInstalldiscord": { "winget": "Discord.Discord", "choco": "discord" @@ -99,6 +127,10 @@ "winget": "Microsoft.DotNet.DesktopRuntime.7", "choco": "dotnet-7.0-runtime" }, + "WPFInstalldolphin": { + "winget": "KDE.Dolphin", + "choco": "na" + }, "WPFInstallduplicati": { "winget": "Duplicati.Duplicati", "choco": "duplicati" @@ -131,9 +163,13 @@ "winget": "Mozilla.Firefox", "choco": "firefox" }, + "WPFInstallfloorp": { + "winget": "Ablaze.Floorp", + "choco": "na" + }, "WPFInstallflameshot": { "winget": "Flameshot.Flameshot", - "choco": "na" + "choco": "flameshot" }, "WPFInstallflux": { "winget": "flux.flux", @@ -167,6 +203,10 @@ "winget": "Git.Git;GitHub.GitHubDesktop", "choco": "git;github-desktop" }, + "WPFInstallgitextensions": { + "winget": "Git.Git;GitExtensionsTeam.GitExtensions", + "choco": "git;gitextensions" + }, "WPFInstallglaryutilities": { "Winget": "Glarysoft.GlaryUtilities", "choco": "glaryutilities-free" @@ -195,6 +235,10 @@ "winget": "HandBrake.HandBrake", "choco": "handbrake" }, + "WPFInstallheidisql": { + "winget": "HeidiSQL.HeidiSQL", + "choco": "heidisql" + }, "WPFInstallheroiclauncher": { "winget": "HeroicGamesLauncher.HeroicGamesLauncher", "choco": "na" @@ -303,14 +347,26 @@ "winget": "LibreWolf.LibreWolf", "choco": "librewolf" }, + "WPFInstalllinphone": { + "winget": "BelledonneCommunications.Linphone", + "choco": "linphone" + }, "WPFInstallmalwarebytes": { "winget": "Malwarebytes.Malwarebytes", "choco": "malwarebytes" }, + "WPFInstallmasscode": { + "winget": "antonreshetov.massCode", + "choco": "na" + }, "WPFInstallmatrix": { "winget": "Element.Element", "choco": "element-desktop" }, + "WPFInstallmercury": { + "winget": "Alex313031.Mercury", + "choco": "na" + }, "WPFInstallmonitorian": { "winget": "emoacht.Monitorian", "choco": "monitorian" @@ -347,6 +403,10 @@ "winget": "Neovim.Neovim", "choco": "neovim" }, + "WPFInstallnextclouddesktop": { + "winget": "Nextcloud.NextcloudDesktop", + "choco": "nextcloud-client" + }, "WPFInstallnglide": { "winget": "ZeusSoftware.nGlide", "choco": "na" @@ -403,6 +463,10 @@ "winget": "Apache.OpenOffice", "choco": "openoffice" }, + "WPFInstallopenrgb": { + "winget": "CalcProgrammer1.OpenRGB", + "choco": "openrgb" + }, "WPFInstallopenshell": { "winget": "Open-Shell.Open-Shell-Menu", "choco": "open-shell" @@ -415,10 +479,18 @@ "winget": "Oracle.VirtualBox", "choco": "virtualbox" }, + "WPFInstallownclouddesktop": { + "winget": "ownCloud.ownCloudDesktop", + "choco": "owncloud-client" + }, "WPFInstallPaintdotnet": { "winget": "dotPDNLLC.paintdotnet", "choco": "paint.net" }, + "WPFInstallpdfsam": { + "winget": "PDFsam.PDFsam", + "choco": "pdfsam" + }, "WPFInstallpeazip": { "winget": "Giorgiotani.Peazip", "choco": "peazip" @@ -431,13 +503,21 @@ "winget": "Microsoft.PowerShell", "choco": "powershell-core" }, + "WPFInstallposh": { + "winget": "JanDeDobbeleer.OhMyPosh", + "choco": "oh-my-posh" + }, "WPFInstallpowertoys": { "winget": "Microsoft.PowerToys", "choco": "powertoys" }, + "WPFInstallportmaster": { + "winget": "portmaster", + "choco": "portmaster" + }, "WPFInstallprismlauncher": { "winget": "PrismLauncher.PrismLauncher", - "choco": "na" + "choco": "prismlauncher" }, "WPFInstallprocesslasso": { "winget": "BitSum.ProcessLasso", @@ -493,7 +573,7 @@ }, "WPFInstallshell": { "winget": "Nilesoft.Shell", - "choco": "na" + "choco": "nilesoft-shell" }, "WPFInstallsignal": { "winget": "OpenWhisperSystems.Signal", @@ -519,11 +599,19 @@ "winget": "Valve.Steam", "choco": "steam-client" }, + "WPFInstallstarship": { + "winget": "starship", + "choco": "starship" + }, "WPFInstallstrawberry": { "winget": "StrawberryMusicPlayer.Strawberry", "choco": "strawberrymusicplayer" }, - "WPFInstallsublime": { + "WPFInstallsublimemerge": { + "winget": "SublimeHQ.SublimeMerge", + "choco": "sublimemerge" + }, + "WPFInstallsublimetext": { "winget": "SublimeHQ.SublimeText.4", "choco": "sublimetext4" }, @@ -668,9 +756,9 @@ "choco": "xdm" }, "WPFInstallzerotierone": { - "winget": "ZeroTier.ZeroTierOne", - "choco": "zerotier-one" - }, + "winget": "ZeroTier.ZeroTierOne", + "choco": "zerotier-one" + }, "WPFInstallzoom": { "winget": "Zoom.Zoom", "choco": "zoom" diff --git a/config/themes.json b/config/themes.json index a710b134..4041d1fe 100644 --- a/config/themes.json +++ b/config/themes.json @@ -11,9 +11,13 @@ "ButtonConfigBackgroundColor": "#444444", "ButtonUpdatesBackgroundColor": "#555555", "ButtonInstallForegroundColor": "#FFFFFF", + "ButtonTweaksForegroundColor": "#FFFFFF", + "ButtonConfigForegroundColor": "#FFFFFF", + "ButtonUpdatesForegroundColor": "#FFFFFF", "ButtonBackgroundColor": "#CACACA", "ButtonBackgroundPressedColor": "#FFFFFF", - "ButtonBackgroundMouseoverColor": "AliceBlue", + "ButtonBackgroundMouseoverColor": "#A55A64", + "ButtonBackgroundSelectedColor": "#BADFFF", "ButtonForegroundColor": "#000000", "ButtonBorderThickness": "0", "ButtonMargin": "0,3,0,3", @@ -31,12 +35,16 @@ "ButtonConfigBackgroundColor": "#444444", "ButtonUpdatesBackgroundColor": "#555555", "ButtonInstallForegroundColor": "#FFFFFF", - "ButtonBackgroundColor": "#000000", + "ButtonTweaksForegroundColor": "#FFFFFF", + "ButtonConfigForegroundColor": "#FFFFFF", + "ButtonUpdatesForegroundColor": "#FFFFFF", + "ButtonBackgroundColor": "#000019", "ButtonBackgroundPressedColor": "#FFFFFF", "ButtonBackgroundMouseoverColor": "#A55A64", + "ButtonBackgroundSelectedColor": "#FF5733", "ButtonForegroundColor": "#9CCC65", - "ButtonBorderThickness": "3", - "ButtonMargin": "2", - "ButtonCornerRadius": "4" + "ButtonBorderThickness": "1", + "ButtonMargin": "1", + "ButtonCornerRadius": "2" } } diff --git a/functions/private/Copy-Files.ps1 b/functions/private/Copy-Files.ps1 new file mode 100644 index 00000000..4c054c81 --- /dev/null +++ b/functions/private/Copy-Files.ps1 @@ -0,0 +1,48 @@ +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 + } +} \ No newline at end of file diff --git a/functions/private/Get-LocalizedYesNo.ps1 b/functions/private/Get-LocalizedYesNo.ps1 new file mode 100644 index 00000000..d537d711 --- /dev/null +++ b/functions/private/Get-LocalizedYesNo.ps1 @@ -0,0 +1,42 @@ +function Get-LocalizedYesNo { + <# + .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") + { + if ($found) + { + $characters = $line -split '(")([A-Za-z])(")' | Where-Object { $_ -match '^[A-Za-z]$' } + $charactersArray += $characters + + 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 + } \ No newline at end of file diff --git a/functions/private/Get-WinUtilVariables.ps1 b/functions/private/Get-WinUtilVariables.ps1 index cd0309cb..f7cffc38 100644 --- a/functions/private/Get-WinUtilVariables.ps1 +++ b/functions/private/Get-WinUtilVariables.ps1 @@ -11,7 +11,7 @@ function Get-WinUtilVariables { #> param ( [Parameter()] - [ValidateSet("CheckBox", "Button")] + [ValidateSet("CheckBox", "Button", "ToggleButton")] [string]$Type ) diff --git a/functions/private/Install-WinUtilWinget.ps1 b/functions/private/Install-WinUtilWinget.ps1 index 0adfceb8..4be11a82 100644 --- a/functions/private/Install-WinUtilWinget.ps1 +++ b/functions/private/Install-WinUtilWinget.ps1 @@ -14,6 +14,8 @@ function Install-WinUtilWinget { .SYNOPSIS Installs Winget if it is not already installed + .DESCRIPTION + This function will download the latest version of winget and install it. If winget is already installed, it will do nothing. #> Try{ Write-Host "Checking if Winget is Installed..." diff --git a/functions/private/MicroWin-Helper.ps1 b/functions/private/MicroWin-Helper.ps1 new file mode 100644 index 00000000..8bed2cd2 --- /dev/null +++ b/functions/private/MicroWin-Helper.ps1 @@ -0,0 +1,564 @@ +function Remove-Features([switch] $dumpFeatures = $false, [switch] $keepDefender = $false) { +<# + + .SYNOPSIS + Removes certain features from ISO image + + .PARAMETER Name + dumpFeatures - Dumps all features found in the ISO into a file called allfeaturesdump.txt. This file can be examined and used to decide what to remove. + keepDefender - Should Defender be removed from the ISO? + + .EXAMPLE + Remove-Features -keepDefender:$false + +#> + $appxlist = dism /image:$scratchDir /Get-Features | Select-String -Pattern "Feature Name : " -CaseSensitive -SimpleMatch + $appxlist = $appxlist -split "Feature Name : " | Where-Object {$_} + if ($dumpFeatures) + { + $appxlist > allfeaturesdump.txt + } + + $appxlist = $appxlist | Where-Object { + $_ -NotLike "*Printing*" -AND + $_ -NotLike "*TelnetClient*" -AND + $_ -NotLike "*PowerShell*" -AND + $_ -NotLike "*NetFx*" + } + + if ($keepDefender) { $appxlist = $appxlist | Where-Object { $_ -NotLike "*Defender*" }} + + foreach($feature in $appxlist) + { + $status = "Removing feature $feature" + Write-Progress -Activity "Removing features" -Status $status -PercentComplete ($counter++/$appxlist.Count*100) + Write-Debug "Removing feature $feature" + # dism /image:$scratchDir /Disable-Feature /FeatureName:$feature /Remove /NoRestart > $null + } + Write-Progress -Activity "Removing features" -Status "Ready" -Completed +} + +function Remove-Packages +{ + $appxlist = dism /Image:$scratchDir /Get-Packages | Select-String -Pattern "Package Identity : " -CaseSensitive -SimpleMatch + $appxlist = $appxlist -split "Package Identity : " | Where-Object {$_} + + $appxlist = $appxlist | Where-Object { + $_ -NotLike "*ApplicationModel*" -AND + $_ -NotLike "*indows-Client-LanguagePack*" -AND + $_ -NotLike "*LanguageFeatures-Basic*" -AND + $_ -NotLike "*Package_for_ServicingStack*" -AND + $_ -NotLike "*.NET*" -AND + $_ -NotLike "*Store*" -AND + $_ -NotLike "*VCLibs*" -AND + $_ -NotLike "*AAD.BrokerPlugin", + $_ -NotLike "*LockApp*" -AND + $_ -NotLike "*Notepad*" -AND + $_ -NotLike "*immersivecontrolpanel*" -AND + $_ -NotLike "*ContentDeliveryManager*" -AND + $_ -NotLike "*PinningConfirMationDialog*" -AND + $_ -NotLike "*SecHealthUI*" -AND + $_ -NotLike "*SecureAssessmentBrowser*" -AND + $_ -NotLike "*PrintDialog*" -AND + $_ -NotLike "*AssignedAccessLockApp*" -AND + $_ -NotLike "*OOBENetworkConnectionFlow*" -AND + $_ -NotLike "*Apprep.ChxApp*" -AND + $_ -NotLike "*CBS*" -AND + $_ -NotLike "*OOBENetworkCaptivePortal*" -AND + $_ -NotLike "*PeopleExperienceHost*" -AND + $_ -NotLike "*ParentalControls*" -AND + $_ -NotLike "*Win32WebViewHost*" -AND + $_ -NotLike "*InputApp*" -AND + $_ -NotLike "*AccountsControl*" -AND + $_ -NotLike "*AsyncTextService*" -AND + $_ -NotLike "*CapturePicker*" -AND + $_ -NotLike "*CredDialogHost*" -AND + $_ -NotLike "*BioEnrollMent*" -AND + $_ -NotLike "*ShellExperienceHost*" -AND + $_ -NotLike "*DesktopAppInstaller*" -AND + $_ -NotLike "*WebMediaExtensions*" -AND + $_ -NotLike "*WMIC*" -AND + $_ -NotLike "*UI.XaML*" + } + + foreach ($appx in $appxlist) + { + $status = "Removing $appx" + Write-Progress -Activity "Removing Apps" -Status $status -PercentComplete ($counter++/$appxlist.Count*100) + dism /image:$scratchDir /Remove-Package /PackageName:$appx /NoRestart + } + Write-Progress -Activity "Removing Apps" -Status "Ready" -Completed +} + +function Remove-ProvisionedPackages +{ + $appxProvisionedPackages = Get-AppxProvisionedPackage -Path "$($scratchDir)" | Where-Object { + $_.PackageName -NotLike "*AppInstaller*" -AND + $_.PackageName -NotLike "*Store*" -and + $_.PackageName -NotLike "*dism*" -and + $_.PackageName -NotLike "*Foundation*" -and + $_.PackageName -NotLike "*FodMetadata*" -and + $_.PackageName -NotLike "*LanguageFeatures*" -and + $_.PackageName -NotLike "*Notepad*" -and + $_.PackageName -NotLike "*Printing*" -and + $_.PackageName -NotLike "*Wifi*" -and + $_.PackageName -NotLike "*Foundation*" + } + + $counter = 0 + foreach ($appx in $appxProvisionedPackages) + { + $status = "Removing Provisioned $appx" + Write-Progress -Activity "Removing Provisioned Apps" -Status $status -PercentComplete ($counter++/$appxProvisionedPackages.Count*100) + dism /image:$scratchDir /Remove-ProvisionedAppxPackage /PackageName:$appx /NoRestart + + } + Write-Progress -Activity "Removing Provisioned Apps" -Status "Ready" -Completed +} + +function Copy-ToUSB([string] $fileToCopy) +{ + foreach ($volume in Get-Volume) { + if ($volume -and $volume.FileSystemLabel -ieq "ventoy") { + $destinationPath = "$($volume.DriveLetter):\" + #Copy-Item -Path $fileToCopy -Destination $destinationPath -Force + # Get the total size of the file + $totalSize = (Get-Item $fileToCopy).length + + Copy-Item -Path $fileToCopy -Destination $destinationPath -Verbose -Force -Recurse -Container -PassThru | + ForEach-Object { + # Calculate the percentage completed + $completed = ($_.BytesTransferred / $totalSize) * 100 + + # Display the progress bar + 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)" + return + } + } + Write-Host "Ventoy USB Key is not inserted" +} + +function Remove-FileOrDirectory([string] $pathToDelete, [string] $mask = "", [switch] $Directory = $false) +{ + if(([string]::IsNullOrEmpty($pathToDelete))) { return } + if (-not (Test-Path -Path "$($pathToDelete)")) { return } + + $yesNo = Get-LocalizedYesNo + + # Specify the path to the directory + # $directoryPath = "$($scratchDir)\Windows\System32\LogFiles\WMI\RtBackup" + # takeown /a /r /d $yesNo[0] /f "$($directoryPath)" > $null + # icacls "$($directoryPath)" /q /c /t /reset > $null + # icacls $directoryPath /setowner "*S-1-5-32-544" + # icacls $directoryPath /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q + # Remove-Item -Path $directoryPath -Recurse -Force + + # # Grant full control to BUILTIN\Administrators using icacls + # $directoryPath = "$($scratchDir)\Windows\System32\WebThreatDefSvc" + # takeown /a /r /d $yesNo[0] /f "$($directoryPath)" > $null + # icacls "$($directoryPath)" /q /c /t /reset > $null + # icacls $directoryPath /setowner "*S-1-5-32-544" + # icacls $directoryPath /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q + # Remove-Item -Path $directoryPath -Recurse -Force + + $itemsToDelete = [System.Collections.ArrayList]::new() + + if ($mask -eq "") + { + Write-Debug "Adding $($pathToDelete) to array." + [void]$itemsToDelete.Add($pathToDelete) + } + else + { + Write-Debug "Adding $($pathToDelete) to array and mask is $($mask)" + if ($Directory) { $itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse -Directory } + else { $itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse } + } + + foreach($itemToDelete in $itemsToDelete) + { + $status = "Deleteing $($itemToDelete)" + Write-Progress -Activity "Removing Items" -Status $status -PercentComplete ($counter++/$itemsToDelete.Count*100) + + if (Test-Path -Path "$($itemToDelete)" -PathType Container) + { + $status = "Deleting directory: $($itemToDelete)" + + takeown /r /d $yesNo[0] /a /f "$($itemToDelete)" + icacls "$($itemToDelete)" /q /c /t /reset + icacls $itemToDelete /setowner "*S-1-5-32-544" + icacls $itemToDelete /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q + Remove-Item -Force -Recurse "$($itemToDelete)" + } + elseif (Test-Path -Path "$($itemToDelete)" -PathType Leaf) + { + $status = "Deleting file: $($itemToDelete)" + + takeown /a /f "$($itemToDelete)" + icacls "$($itemToDelete)" /q /c /t /reset + icacls "$($itemToDelete)" /setowner "*S-1-5-32-544" + icacls "$($itemToDelete)" /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q + Remove-Item -Force "$($itemToDelete)" + } + } + Write-Progress -Activity "Removing Items" -Status "Ready" -Completed +} + +function New-Unattend { + + # later if we wont to remove even more bloat EU requires MS to remove everything from English(world) + # Below is an example how to do it we probably should create a drop down with common locals + # + # + # + # + # en-US + # + # en-US + # en-US + # en-US + # en-US + # + # + + # + # + # + # en-US + # en-US + # en-US + # en-US + # + # + # using here string to embedd unattend + # + # 1 + # net user administrator /active:yes + # + + $unattend = @' + + + + + 0 + + + false + + + + + + + 1 + CMD /C echo LAU GG>C:\Windows\LogAuditUser.txt + StartMenu + + + + + + + + true + false + false + true + true + true + 3 + + + + 1 + cmd.exe /c echo 23>c:\windows\csup.txt + + + 2 + CMD /C echo GG>C:\Windows\LogOobeSystem.txt + + + 3 + powershell -ExecutionPolicy Bypass -File c:\windows\FirstStartup.ps1 + + + + + +'@ + $unattend | Out-File -FilePath "$env:temp\unattend.xml" -Force +} + +function New-CheckInstall { + + # using here string to embedd firstrun + $checkInstall = @' + @echo off + if exist "C:\windows\cpu.txt" ( + echo C:\windows\cpu.txt exists + ) else ( + echo C:\windows\cpu.txt does not exist + ) + if exist "C:\windows\SerialNumber.txt" ( + echo C:\windows\SerialNumber.txt exists + ) else ( + echo C:\windows\SerialNumber.txt does not exist + ) + if exist "C:\unattend.xml" ( + echo C:\unattend.xml exists + ) else ( + echo C:\unattend.xml does not exist + ) + if exist "C:\Windows\Setup\Scripts\SetupComplete.cmd" ( + echo C:\Windows\Setup\Scripts\SetupComplete.cmd exists + ) else ( + echo C:\Windows\Setup\Scripts\SetupComplete.cmd does not exist + ) + if exist "C:\Windows\Panther\unattend.xml" ( + echo C:\Windows\Panther\unattend.xml exists + ) else ( + echo C:\Windows\Panther\unattend.xml does not exist + ) + if exist "C:\Windows\System32\Sysprep\unattend.xml" ( + echo C:\Windows\System32\Sysprep\unattend.xml exists + ) else ( + echo C:\Windows\System32\Sysprep\unattend.xml does not exist + ) + if exist "C:\Windows\FirstStartup.ps1" ( + echo C:\Windows\FirstStartup.ps1 exists + ) else ( + echo C:\Windows\FirstStartup.ps1 does not exist + ) + if exist "C:\Windows\winutil.ps1" ( + echo C:\Windows\winutil.ps1 exists + ) else ( + echo C:\Windows\winutil.ps1 does not exist + ) + if exist "C:\Windows\LogSpecialize.txt" ( + echo C:\Windows\LogSpecialize.txt exists + ) else ( + echo C:\Windows\LogSpecialize.txt does not exist + ) + if exist "C:\Windows\LogAuditUser.txt" ( + echo C:\Windows\LogAuditUser.txt exists + ) else ( + echo C:\Windows\LogAuditUser.txt does not exist + ) + if exist "C:\Windows\LogOobeSystem.txt" ( + echo C:\Windows\LogOobeSystem.txt exists + ) else ( + echo C:\Windows\LogOobeSystem.txt does not exist + ) + if exist "c:\windows\csup.txt" ( + echo c:\windows\csup.txt exists + ) else ( + echo c:\windows\csup.txt does not exist + ) + if exist "c:\windows\LogFirstRun.txt" ( + echo c:\windows\LogFirstRun.txt exists + ) else ( + echo c:\windows\LogFirstRun.txt does not exist + ) +'@ + $checkInstall | Out-File -FilePath "$env:temp\checkinstall.cmd" -Force -Encoding Ascii +} + +function New-FirstRun { + + # using here string to embedd firstrun + $firstRun = @' + # 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." + } + } + + function Stop-UnnecessaryServices + { + $servicesAuto = @" + "AudioSrv", + "AudioEndpointBuilder", + "BFE", + "BITS", + "BrokerInfrastructure", + "CDPSvc", + "CDPUserSvc_dc2a4", + "CoreMessagingRegistrar", + "CryptSvc", + "DPS", + "DcomLaunch", + "Dhcp", + "DispBrokerDesktopSvc", + "Dnscache", + "DoSvc", + "DusmSvc", + "EventLog", + "EventSystem", + "FontCache", + "LSM", + "LanmanServer", + "LanmanWorkstation", + "MapsBroker", + "MpsSvc", + "OneSyncSvc_dc2a4", + "Power", + "ProfSvc", + "RpcEptMapper", + "RpcSs", + "SCardSvr", + "SENS", + "SamSs", + "Schedule", + "SgrmBroker", + "ShellHWDetection", + "Spooler", + "SysMain", + "SystemEventsBroker", + "TextInputManagementService", + "Themes", + "TrkWks", + "UserManager", + "VGAuthService", + "VMTools", + "WSearch", + "Wcmsvc", + "WinDefend", + "Winmgmt", + "WlanSvc", + "WpnService", + "WpnUserService_dc2a4", + "cbdhsvc_dc2a4", + "edgeupdate", + "gpsvc", + "iphlpsvc", + "mpssvc", + "nsi", + "sppsvc", + "tiledatamodelsvc", + "vm3dservice", + "webthreatdefusersvc_dc2a4", + "wscsvc" +"@ + + $allServices = Get-Service | Where-Object { $_.StartType -eq "Automatic" -and $servicesAuto -NotContains $_.Name} + foreach($service in $allServices) + { + Stop-Service -Name $service.Name -PassThru + Set-Service $service.Name -StartupType Manual + "Stopping service $($service.Name)" | Out-File -FilePath c:\windows\LogFirstRun.txt -Append -NoClobber + } + } + + "FirstStartup has worked" | Out-File -FilePath c:\windows\LogFirstRun.txt -Append -NoClobber + + $Theme = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" + Set-ItemProperty -Path $Theme -Name AppsUseLightTheme -Value 1 + Set-ItemProperty -Path $Theme -Name SystemUsesLightTheme -Value 1 + + # figure this out later how to set updates to security only + #Import-Module -Name PSWindowsUpdate; + #Stop-Service -Name wuauserv + #Set-WUSettings -MicrosoftUpdateEnabled -AutoUpdateOption 'Never' + #Start-Service -Name wuauserv + + Stop-UnnecessaryServices + + $taskbarPath = "$env:AppData\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar" + # Delete all files on the Taskbar + 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" + + # Stop-Process -Name explorer -Force + + $process = Get-Process -Name "explorer" + Stop-Process -InputObject $process + # Wait for the process to exit + Wait-Process -InputObject $process + Start-Sleep -Seconds 3 + + # 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 "C:\Users\Default\Desktop\*.lnk" + + # ************************************************ + # Create WinUtil shortcut on the desktop + # + $desktopPath = "$($env:USERPROFILE)\Desktop" + # Specify the target PowerShell command + $command = "powershell.exe -NoProfile -ExecutionPolicy Bypass -Command 'irm https://christitus.com/win | iex'" + # Specify the path for the shortcut + $shortcutPath = Join-Path $desktopPath 'winutil.lnk' + # Create a shell object + $shell = New-Object -ComObject WScript.Shell + + # Create a shortcut object + $shortcut = $shell.CreateShortcut($shortcutPath) + + if (Test-Path -Path "c:\Windows\cttlogo.png") + { + $shortcut.IconLocation = "c:\Windows\cttlogo.png" + } + + # Set properties of the shortcut + $shortcut.TargetPath = "powershell.exe" + $shortcut.Arguments = "-NoProfile -ExecutionPolicy Bypass -Command `"$command`"" + # Save the shortcut + $shortcut.Save() + Write-Host "Shortcut created at: $shortcutPath" + # + # Done create WinUtil shortcut on the desktop + # ************************************************ + + Start-Process explorer + +'@ + $firstRun | Out-File -FilePath "$env:temp\FirstStartup.ps1" -Force +} \ No newline at end of file diff --git a/functions/private/Remove-WinUtilAPPX.ps1 b/functions/private/Remove-WinUtilAPPX.ps1 index db6471a5..e54a3475 100644 --- a/functions/private/Remove-WinUtilAPPX.ps1 +++ b/functions/private/Remove-WinUtilAPPX.ps1 @@ -15,16 +15,16 @@ function Remove-WinUtilAPPX { $Name ) - Try{ + Try { Write-Host "Removing $Name" Get-AppxPackage "*$Name*" | Remove-AppxPackage -ErrorAction SilentlyContinue Get-AppxProvisionedPackage -Online | Where-Object DisplayName -like "*$Name*" | Remove-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue } Catch [System.Exception] { - if($psitem.Exception.Message -like "*The requested operation requires elevation*"){ + if ($psitem.Exception.Message -like "*The requested operation requires elevation*") { Write-Warning "Unable to uninstall $name due to a Security Exception" } - Else{ + else { Write-Warning "Unable to uninstall $name due to unhandled exception" Write-Warning $psitem.Exception.StackTrace } diff --git a/functions/public/Invoke-WPFButton.ps1 b/functions/public/Invoke-WPFButton.ps1 index d8579479..e17a349c 100644 --- a/functions/public/Invoke-WPFButton.ps1 +++ b/functions/public/Invoke-WPFButton.ps1 @@ -46,11 +46,14 @@ function Invoke-WPFButton { "WPFPaneluser" {Invoke-WPFControlPanel -Panel $button} "WPFUpdatesdefault" {Invoke-WPFUpdatesdefault} "WPFFixesUpdate" {Invoke-WPFFixesUpdate} + "WPFFixesWinget" {Invoke-WPFFixesWinget} "WPFFixesNetwork" {Invoke-WPFFixesNetwork} "WPFUpdatesdisable" {Invoke-WPFUpdatesdisable} "WPFUpdatessecurity" {Invoke-WPFUpdatessecurity} "WPFWinUtilShortcut" {Invoke-WPFShortcut -ShortcutToAdd "WinUtil"} "WPFGetInstalled" {Invoke-WPFGetInstalled -CheckBox "winget"} "WPFGetInstalledTweaks" {Invoke-WPFGetInstalled -CheckBox "tweaks"} + "WPFGetIso" {Invoke-WPFGetIso} + "WPFMicrowin" {Invoke-WPFMicrowin} } } \ No newline at end of file diff --git a/functions/public/Invoke-WPFFixesWinget.ps1 b/functions/public/Invoke-WPFFixesWinget.ps1 new file mode 100644 index 00000000..36a8afab --- /dev/null +++ b/functions/public/Invoke-WPFFixesWinget.ps1 @@ -0,0 +1,13 @@ +function Invoke-WPFFixesWinget { + + <# + + .SYNOPSIS + Fixes Winget by running choco install winget + .DESCRIPTION + BravoNorris for the fantastic idea of a button to reinstall winget + #> + + Start-Process -FilePath "choco" -ArgumentList "install winget -y" -NoNewWindow -Wait + +} \ No newline at end of file diff --git a/functions/public/Invoke-WPFFormVariables.ps1 b/functions/public/Invoke-WPFFormVariables.ps1 index 5905e0f8..6a2d2e7a 100644 --- a/functions/public/Invoke-WPFFormVariables.ps1 +++ b/functions/public/Invoke-WPFFormVariables.ps1 @@ -29,7 +29,6 @@ Function Invoke-WPFFormVariables { Write-Host "====Chris Titus Tech=====" Write-Host "=====Windows Toolbox=====" - #====DEBUG GUI Elements==== #Write-Host "Found the following interactable elements from our form" -ForegroundColor Cyan diff --git a/functions/public/Invoke-WPFGetIso.ps1 b/functions/public/Invoke-WPFGetIso.ps1 new file mode 100644 index 00000000..44572a13 --- /dev/null +++ b/functions/public/Invoke-WPFGetIso.ps1 @@ -0,0 +1,125 @@ +function Invoke-WPFGetIso { + <# + .DESCRIPTION + Function to get the path to Iso file for MicroWin, unpack that isom=, read basic information and populate the UI Options + #> + + Write-Host "Invoking WPFGetIso" + + if($sync.ProcessRunning){ + $msg = "GetIso process is currently running." + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) + return + } + + Write-Host " _ __ __ _ " + Write-Host " /\/\ (_) ___ _ __ ___ / / /\ \ \(_) _ __ " + Write-Host " / \ | | / __|| '__| / _ \ \ \/ \/ /| || '_ \ " + Write-Host "/ /\/\ \| || (__ | | | (_) | \ /\ / | || | | | " + Write-Host "\/ \/|_| \___||_| \___/ \/ \/ |_||_| |_| " + + $oscdImgFound = [bool] (Get-Command -ErrorAction Ignore -Type Application oscdimg) + Write-Host "oscdimge.exe on system: $oscdImgFound" + + if (!$oscdImgFound) + { + [System.Windows.MessageBox]::Show("oscdimge.exe is not found on the system, you need to download it first before running this function!") + + # the step below needs choco to download oscdimg + $chocoFound = [bool] (Get-Command -ErrorAction Ignore -Type Application choco) + Write-Host "choco on system: $oscdImgFound" + if (!$chocoFound) + { + [System.Windows.MessageBox]::Show("choco.exe is not found on the system, you need choco to download oscdimg.exe") + return + } + + Start-Process -Verb runas -FilePath powershell.exe -ArgumentList "choco install windows-adk-oscdimg" + [System.Windows.MessageBox]::Show("oscdimg is installed, now close, reopen PowerShell terminal and re-launch winutil.ps1 !!!") + return + } + + [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null + $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog + $openFileDialog.initialDirectory = $initialDirectory + $openFileDialog.filter = "ISO files (*.iso)| *.iso" + $openFileDialog.ShowDialog() | Out-Null + $filePath = $openFileDialog.FileName + + if ([string]::IsNullOrEmpty($filePath)) + { + Write-Host "No ISO is chosen" + break + } + + Write-Host "File path $($filePath)" + if (-not (Test-Path -Path $filePath -PathType Leaf)) + { + $msg = "File you've chosen doesn't exist" + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error) + break + } + + Write-Host "Mounting Iso. Please wait." + $mountedISO = Mount-DiskImage -PassThru "$filePath" + Write-Host "Done mounting Iso $mountedISO" + $driveLetter = (Get-Volume -DiskImage $mountedISO).DriveLetter + Write-Host "Iso mounted to '$driveLetter'" + # storing off values in hidden fields for further steps + # there is probably a better way of doing this, I don't have time to figure this out + $sync.MicrowinIsoDrive.Text = $driveLetter + + Write-Host "Setting up mount dir and scratch dirs" + $mountDir = "c:\microwin" + $scratchDir = "c:\microwinscratch" + $sync.MicrowinMountDir.Text = $mountDir + $sync.MicrowinScratchDir.Text = $scratchDir + Write-Host "Done setting up mount dir and scratch dirs" + + try { + + $data = @($driveLetter, $filePath) + New-Item -ItemType Directory -Force -Path "$($mountDir)" | Out-Null + New-Item -ItemType Directory -Force -Path "$($scratchDir)" | Out-Null + Write-Host "Copying Windows image. This will take awhile, please don't use UI or cancel this step!" + + # xcopy we can verify files and also not copy files that already exist, but hard to measure + # xcopy.exe /E /I /H /R /Y /J $DriveLetter":" $mountDir >$null + $totalTime = Measure-Command { Copy-Files "$($driveLetter):" $mountDir -Recurse -Force } + Write-Host "Copy complete! Total Time: $($totalTime.Minutes)m$($totalTime.Seconds)s" + + $wimFile = "$mountDir\sources\install.wim" + Write-Host "Getting image information $wimFile" + + if (-not (Test-Path -Path $wimFile -PathType Leaf)) + { + $msg = "install wim file doesn't exist in the image, are you sure you used Windows image??" + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error) + throw + } + Get-WindowsImage -ImagePath $wimFile | ForEach-Object { + $imageIdx = $_.ImageIndex + $imageName = $_.ImageName + $sync.MicrowinWindowsFlavors.Items.Add("$imageIdx : $imageName") + } + $sync.MicrowinWindowsFlavors.SelectedIndex = 0 + Get-Volume $driveLetter | Get-DiskImage | Dismount-DiskImage + Write-Host "Selected value '$($sync.MicrowinWindowsFlavors.SelectedValue)'....." + + $sync.MicrowinOptionsPanel.Visibility = 'Visible' + } catch { + Write-Host "Dismounting bad image..." + Get-Volume $driveLetter | Get-DiskImage | Dismount-DiskImage + Remove-Item -Recurse -Force "$($scratchDir)" + Remove-Item -Recurse -Force "$($mountDir)" + } + + Write-Host "Done reading and unpacking ISO" + Write-Host "" + Write-Host "*********************************" + Write-Host "Check the UI for further steps!!!" + + $sync.ProcessRunning = $false +} + + diff --git a/functions/public/Invoke-WPFMicrowin.ps1 b/functions/public/Invoke-WPFMicrowin.ps1 new file mode 100644 index 00000000..7c12f3d5 --- /dev/null +++ b/functions/public/Invoke-WPFMicrowin.ps1 @@ -0,0 +1,335 @@ +function Invoke-WPFMicrowin { + <# + .DESCRIPTION + Invoke MicroWin routines... + #> + + if($sync.ProcessRunning) { + $msg = "GetIso process is currently running." + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) + return + } + + $index = $sync.MicrowinWindowsFlavors.SelectedValue.Split(":")[0].Trim() + Write-Host "Index chosen: '$index' from $($sync.MicrowinWindowsFlavors.SelectedValue)" + + $keepPackages = $sync.WPFMicrowinKeepProvisionedPackages.IsChecked + $keepProvisionedPackages = $sync.WPFMicrowinKeepAppxPackages.IsChecked + $keepDefender = $sync.WPFMicrowinKeepDefender.IsChecked + $keepEdge = $sync.WPFMicrowinKeepEdge.IsChecked + $copyToUSB = $sync.WPFMicrowinCopyToUsb.IsChecked + $injectDrivers = $sync.MicrowinInjectDrivers.IsChecked + + $mountDir = $sync.MicrowinMountDir.Text + $scratchDir = $sync.MicrowinScratchDir.Text + + $mountDirExists = Test-Path $mountDir + $scratchDirExists = Test-Path $scratchDir + if (-not $mountDirExists -or -not $scratchDirExists) + { + Write-Error "Required directories '$mountDirExists' '$scratchDirExists' and do not exist." + return + } + + 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..." + + if ($injectDrivers) + { + $driverPath = $sync.MicrowinDriverLocation.Text + if (Test-Path $driverPath) + { + Write-Host "Adding Windows Drivers image($scratchDir) drivers($driverPath) " + dism /image:$scratchDir /add-driver /driver:$driverPath /recurse | Out-Host + } + else + { + Write-Host "Path to drivers is invalid continuing without driver injection" + } + } + + Write-Host "Remove Features from the image" + Remove-Features -keepDefender:$keepDefender + Write-Host "Removing features complete!" + + Write-Host "Removing Appx Bloat" + if (!$keepPackages) + { + Remove-Packages + } + if (!$keepProvisionedPackages) + { + Remove-ProvisionedPackages + } + + # special code, for some reason when you try to delete some inbox apps + # we have to get and delete log files directory. + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\LogFiles\WMI\RtBackup" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\WebThreatDefSvc" -Directory + + # Defender is hidden in 2 places we removed a feature above now need to remove it from the disk + if (!$keepDefender) + { + Write-Host "Removing Defender" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Defender" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Defender" + } + if (!$keepEdge) + { + Write-Host "Removing Edge" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Microsoft" -mask "*edge*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Microsoft" -mask "*edge*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*edge*" -Directory + } + + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\DiagTrack" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\InboxApps" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\SecurityHealthSystray.exe" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\LocationNotificationWindows.exe" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Photo Viewer" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Photo Viewer" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Media Player" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Media Player" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Mail" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Mail" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Internet Explorer" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Internet Explorer" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\GameBarPresenceWriter" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\OneDriveSetup.exe" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\OneDrive.ico" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*Windows.Search*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*narratorquickstart*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*Xbox*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*ParentalControls*" -Directory + Write-Host "Removal complete!" + + # *************************** Automation black *************************** + # this doesn't work for some reason, this script is not being run at the end of the install + # if someone knows how to fix this, feel free to modify + New-Item -ItemType Directory -Force -Path $scratchDir\Windows\Setup\Scripts\ + "wmic cpu get Name > C:\windows\cpu.txt" | Out-File -FilePath "$($scratchDir)\Windows\Setup\Scripts\SetupComplete.cmd" -NoClobber -Append + "wmic bios get serialnumber > C:\windows\SerialNumber.txt" | Out-File -FilePath "$($scratchDir)\Windows\Setup\Scripts\SetupComplete.cmd" -NoClobber -Append + "devmgmt.msc /s" | Out-File -FilePath "$($scratchDir)\Windows\Setup\Scripts\SetupComplete.cmd" -NoClobber -Append + + Write-Host "Create unattend.xml" + New-Unattend + Write-Host "Done Create unattend.xml" + Write-Host "Copy unattend.xml file into the ISO" + New-Item -ItemType Directory -Force -Path "$($scratchDir)\Windows\Panther" + Copy-Item "$env:temp\unattend.xml" "$($scratchDir)\Windows\Panther\unattend.xml" -force + New-Item -ItemType Directory -Force -Path "$($scratchDir)\Windows\System32\Sysprep" + Copy-Item "$env:temp\unattend.xml" "$($scratchDir)\Windows\System32\Sysprep\unattend.xml" -force + Copy-Item "$env:temp\unattend.xml" "$($scratchDir)\unattend.xml" -force + Write-Host "Done Copy unattend.xml" + + Write-Host "Create FirstRun" + New-FirstRun + Write-Host "Done create FirstRun" + Write-Host "Copy FirstRun.ps1 into the ISO" + Copy-Item "$env:temp\FirstStartup.ps1" "$($scratchDir)\Windows\FirstStartup.ps1" -force + Write-Host "Done copy FirstRun.ps1" + + Write-Host "Copy link to winutil.ps1 into the ISO" + $desktopDir = "$($scratchDir)\Windows\Users\Default\Desktop" + New-Item -ItemType Directory -Force -Path "$desktopDir" + dism /image:$($scratchDir) /set-profilepath:"$($scratchDir)\Windows\Users\Default" + $command = "powershell.exe -NoProfile -ExecutionPolicy Bypass -Command 'irm https://christitus.com/win | iex'" + $shortcutPath = "$desktopDir\WinUtil.lnk" + $shell = New-Object -ComObject WScript.Shell + $shortcut = $shell.CreateShortcut($shortcutPath) + + if (Test-Path -Path "$env:TEMP\cttlogo.png") + { + $pngPath = "$env:TEMP\cttlogo.png" + $icoPath = "$env:TEMP\cttlogo.ico" + Add-Type -AssemblyName System.Drawing + $pngImage = [System.Drawing.Image]::FromFile($pngPath) + $pngImage.Save($icoPath, [System.Drawing.Imaging.ImageFormat]::Icon) + Write-Host "ICO file created at: $icoPath" + Copy-Item "$env:TEMP\cttlogo.png" "$($scratchDir)\Windows\cttlogo.png" -force + Copy-Item "$env:TEMP\cttlogo.ico" "$($scratchDir)\cttlogo.ico" -force + $shortcut.IconLocation = "c:\cttlogo.ico" + } + + $shortcut.TargetPath = "powershell.exe" + $shortcut.Arguments = "-NoProfile -ExecutionPolicy Bypass -Command `"$command`"" + $shortcut.Save() + Write-Host "Shortcut to winutil created at: $shortcutPath" + # *************************** Automation black *************************** + + Write-Host "Copy checkinstall.cmd into the ISO" + New-CheckInstall + Copy-Item "$env:temp\checkinstall.cmd" "$($scratchDir)\Windows\checkinstall.cmd" -force + Write-Host "Done copy checkinstall.cmd" + + Write-Host "Creating a directory that allows to bypass Wifi setup" + New-Item -ItemType Directory -Force -Path "$($scratchDir)\Windows\System32\OOBE\BYPASSNRO" + + Write-Host "Loading registry" + reg load HKLM\zCOMPONENTS "$($scratchDir)\Windows\System32\config\COMPONENTS" + reg load HKLM\zDEFAULT "$($scratchDir)\Windows\System32\config\default" + reg load HKLM\zNTUSER "$($scratchDir)\Users\Default\ntuser.dat" + reg load HKLM\zSOFTWARE "$($scratchDir)\Windows\System32\config\SOFTWARE" + reg load HKLM\zSYSTEM "$($scratchDir)\Windows\System32\config\SYSTEM" + + Write-Host "Disabling Teams" + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Communications" /v "ConfigureChatAutoInstall" /t REG_DWORD /d 0 /f >$null 2>&1 + reg add "HKLM\zSOFTWARE\Policies\Microsoft\Windows\Windows Chat" /v ChatIcon /t REG_DWORD /d 2 /f >$null 2>&1 + reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "TaskbarMn" /t REG_DWORD /d 0 /f >$null 2>&1 + reg query "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Communications" /v "ConfigureChatAutoInstall" >$null 2>&1 + # Write-Host Error code $LASTEXITCODE + Write-Host "Done disabling Teams" + + Write-Host "Bypassing system requirements (system image)" + reg add "HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache" /v "SV1" /t REG_DWORD /d 0 /f + reg add "HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache" /v "SV2" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache" /v "SV1" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache" /v "SV2" /t REG_DWORD /d 0 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassCPUCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassRAMCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassSecureBootCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassStorageCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassTPMCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\MoSetup" /v "AllowUpgradesWithUnsupportedTPMOrCPU" /t REG_DWORD /d 1 /f + + if (!$keepEdge) + { + Write-Host "Removing Edge icon from taskbar" + reg delete "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Taskband" /v "Favorites" /f >$null 2>&1 + reg delete "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Taskband" /v "FavoritesChanges" /f >$null 2>&1 + reg delete "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Taskband" /v "Pinned" /f >$null 2>&1 + reg delete "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Taskband" /v "LayoutCycle" /f >$null 2>&1 + Write-Host "Edge icon removed from taskbar" + } + + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Search" /v "SearchboxTaskbarMode" /t REG_DWORD /d 0 /f + Write-Host "Setting all services to start manually" + reg add "HKLM\zSOFTWARE\CurrentControlSet\Services" /v Start /t REG_DWORD /d 3 /f + # Write-Host $LASTEXITCODE + + Write-Host "Enabling Local Accounts on OOBE" + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" /v "BypassNRO" /t REG_DWORD /d "1" /f + + Write-Host "Disabling Sponsored Apps" + reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "OemPreInstalledAppsEnabled" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEnabled" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SilentInstalledAppsEnabled" /t REG_DWORD /d 0 /f + reg add "HKLM\zSOFTWARE\Policies\Microsoft\Windows\CloudContent" /v "DisableWindowsConsumerFeatures" /t REG_DWORD /d 1 /f + reg add "HKLM\zSOFTWARE\Microsoft\PolicyManager\current\device\Start" /v "ConfigureStartPins" /t REG_SZ /d '{\"pinnedList\": [{}]}' /f + Write-Host "Done removing Sponsored Apps" + + Write-Host "Disabling Reserved Storage" + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\ReserveManager" /v "ShippedWithReserves" /t REG_DWORD /d 0 /f + + Write-Host "Changing theme to dark. This only works on Activated Windows" + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v "AppsUseLightTheme" /t REG_DWORD /d 0 /f + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v "SystemUsesLightTheme" /t REG_DWORD /d 0 /f + + } catch { + Write-Error "An unexpected error occurred: $_" + } finally { + Write-Host "Unmounting Registry..." + reg unload HKLM\zCOMPONENTS + reg unload HKLM\zDEFAULT + reg unload HKLM\zNTUSER + reg unload HKLM\zSOFTWARE + reg unload HKLM\zSYSTEM + + Write-Host "Cleaning up image..." + dism /image:$scratchDir /Cleanup-Image /StartComponentCleanup /ResetBase + Write-Host "Cleanup complete." + + Write-Host "Unmounting image..." + dism /unmount-image /mountdir:$scratchDir /commit + } + + 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 + 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" + + if (-not (Test-Path -Path "$mountDir\sources\install.wim")) + { + Write-Error "Somethig went wrong and '$mountDir\sources\install.wim' doesn't exist. Please report this bug to the devs" + return + } + Write-Host "Windows image completed. Continuing with boot.wim." + + # 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" + + Write-Host "Loading registry..." + reg load HKLM\zCOMPONENTS "$($scratchDir)\Windows\System32\config\COMPONENTS" >$null + reg load HKLM\zDEFAULT "$($scratchDir)\Windows\System32\config\default" >$null + reg load HKLM\zNTUSER "$($scratchDir)\Users\Default\ntuser.dat" >$null + reg load HKLM\zSOFTWARE "$($scratchDir)\Windows\System32\config\SOFTWARE" >$null + reg load HKLM\zSYSTEM "$($scratchDir)\Windows\System32\config\SYSTEM" >$null + Write-Host "Bypassing system requirements on the setup image" + reg add "HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache" /v "SV1" /t REG_DWORD /d 0 /f + reg add "HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache" /v "SV2" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache" /v "SV1" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache" /v "SV2" /t REG_DWORD /d 0 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassCPUCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassRAMCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassSecureBootCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassStorageCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassTPMCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\MoSetup" /v "AllowUpgradesWithUnsupportedTPMOrCPU" /t REG_DWORD /d 1 /f + # Fix Computer Restarted Unexpectedly Error on New Bare Metal Install + reg add "HKLM\zSYSTEM\Setup\Status\ChildCompletion" /v "setup.exe" /t REG_DWORD /d 3 /f + } catch { + Write-Error "An unexpected error occurred: $_" + } finally { + Write-Host "Unmounting Registry..." + reg unload HKLM\zCOMPONENTS + reg unload HKLM\zDEFAULT + reg unload HKLM\zNTUSER + reg unload HKLM\zSOFTWARE + reg unload HKLM\zSYSTEM + + Write-Host "Unmounting image..." + dism /unmount-image /mountdir:$scratchDir /commit + + Write-Host "Creating ISO image" + #& oscdimg.exe -m -o -u2 -udfver102 -bootdata:2#p0,e,b$mountDir\boot\etfsboot.com#pEF,e,b$mountDir\efi\microsoft\boot\efisys.bin $mountDir $env:temp\microwin.iso + Start-Process -FilePath "oscdimg.exe" -ArgumentList "-m -o -u2 -udfver102 -bootdata:2#p0,e,b$mountDir\boot\etfsboot.com#pEF,e,b$mountDir\efi\microsoft\boot\efisys.bin $mountDir $env:temp\microwin.iso" -NoNewWindow -Wait + + if ($copyToUSB) + { + Write-Host "Copying microwin.iso to the USB drive" + Copy-ToUSB("$env:temp\microwin.iso") + Write-Host "Done Copying microwin.iso to USB drive!" + } + + Write-Host " _____ " + Write-Host "(____ \ " + Write-Host " _ \ \ ___ ____ ____ " + Write-Host "| | | / _ \| _ \ / _ ) " + Write-Host "| |__/ / |_| | | | ( (/ / " + Write-Host "|_____/ \___/|_| |_|\____) " + + # Check if the ISO was successfully created - CTT edit + if ($LASTEXITCODE -eq 0) { + Write-Host "Done. ISO image is located here: $env:temp\microwin.iso" + Write-Host "Performing Cleanup" + Remove-Item -Recurse -Force "$($scratchDir)" + Remove-Item -Recurse -Force "$($mountDir)" + } else { + Write-Host "ISO creation failed. The "$($mountDir)" directory has not been removed." + } + + + $sync.MicrowinOptionsPanel.Visibility = 'Collapsed' + + $sync.MicrowinFinalIsoLocation.Text = "$env:temp\microwin.iso" + + $sync.ProcessRunning = $false + } +} \ No newline at end of file diff --git a/functions/public/Invoke-WPFTab.ps1 b/functions/public/Invoke-WPFTab.ps1 index 14d26c5e..644348d9 100644 --- a/functions/public/Invoke-WPFTab.ps1 +++ b/functions/public/Invoke-WPFTab.ps1 @@ -11,17 +11,21 @@ function Invoke-WPFTab { #> Param ($ClickedTab) - $Tabs = Get-WinUtilVariables | Where-Object {$psitem -like "WPFTab?BT"} - $TabNav = Get-WinUtilVariables | Where-Object {$psitem -like "WPFTabNav"} - $x = [int]($ClickedTab -replace "WPFTab","" -replace "BT","") - 1 - 0..($Tabs.Count -1 ) | ForEach-Object { + $tabNav = Get-WinUtilVariables | Where-Object {$psitem -like "WPFTabNav"} + $tabNumber = [int]($ClickedTab -replace "WPFTab","" -replace "BT","") - 1 - if ($x -eq $psitem){ - $sync.$TabNav.Items[$psitem].IsSelected = $true + $filter = Get-WinUtilVariables -Type ToggleButton | Where-Object {$psitem -like "WPFTab?BT"} + $sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} | ForEach-Object { + if ($ClickedTab -ne $PSItem.name) { + $sync[$PSItem.Name].IsChecked = $false + # $tabNumber = [int]($PSItem.Name -replace "WPFTab","" -replace "BT","") - 1 + # $sync.$tabNav.Items[$tabNumber].IsSelected = $false } - else{ - $sync.$TabNav.Items[$psitem].IsSelected = $false + else { + $sync["$ClickedTab"].IsChecked = $true + $tabNumber = [int]($ClickedTab-replace "WPFTab","" -replace "BT","") - 1 + $sync.$tabNav.Items[$tabNumber].IsSelected = $true } } } diff --git a/pester/functions.Tests.ps1 b/pester/functions.Tests.ps1 index 8a499d24..1ec1e286 100644 --- a/pester/functions.Tests.ps1 +++ b/pester/functions.Tests.ps1 @@ -16,9 +16,7 @@ Describe "Functions"{ fullname = $psitem.FullName } { Get-ChildItem function:\$basename | should -Not -BeNullOrEmpty - } { - get-help $basename -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Description | should -Not -BeNullOrEmpty - } + } } } } diff --git a/scripts/main.ps1 b/scripts/main.ps1 index 3a536e58..a490b86e 100644 --- a/scripts/main.ps1 +++ b/scripts/main.ps1 @@ -96,6 +96,16 @@ $sync.keys | ForEach-Object { } } +$sync.keys | ForEach-Object { + if($sync.$psitem){ + if($($sync["$psitem"].GetType() | Select-Object -ExpandProperty Name) -eq "ToggleButton"){ + $sync["$psitem"].Add_Click({ + [System.Object]$Sender = $args[0] + Invoke-WPFButton $Sender.name + }) + } + } +} $sync.keys | ForEach-Object { if($sync.$psitem){ @@ -113,7 +123,6 @@ $sync.keys | ForEach-Object { } } - #=========================================================================== # Setup background config #=========================================================================== @@ -121,9 +130,7 @@ $sync.keys | ForEach-Object { # Load computer information in the background Invoke-WPFRunspace -ScriptBlock { $sync.ConfigLoaded = $False - $sync.ComputerInfo = Get-ComputerInfo - $sync.ConfigLoaded = $True } | Out-Null @@ -146,7 +153,181 @@ $sync["Form"].Add_Closing({ [System.GC]::Collect() }) -# Show the form -$sync["Form"].ShowDialog() | out-null +# add some shortcuts for people that don't like clicking +$commonKeyEvents = { + if ($sync.ProcessRunning -eq $true) { + return + } + # Escape removes focus from the searchbox that way all shortcuts will start workinf again + if ($_.Key -eq "Escape") { + if ($sync.CheckboxFilter.IsFocused) + { + $sync.CheckboxFilter.SelectAll() + $sync.CheckboxFilter.Text = "" + $sync.CheckboxFilter.Focus() + return + } + } + + # don't ask, I know what I'm doing, just go... + if (($_.Key -eq "Q" -and $_.KeyboardDevice.Modifiers -eq "Ctrl")) + { + $this.Close() + } + + # $ret = [System.Windows.Forms.MessageBox]::Show("Are you sure you want to Exit?", "Winutil", [System.Windows.Forms.MessageBoxButtons]::YesNo, + # [System.Windows.Forms.MessageBoxIcon]::Question, [System.Windows.Forms.MessageBoxDefaultButton]::Button2) + + # switch ($ret) { + # "Yes" { + # $this.Close() + # } + # "No" { + # return + # } + # } + + + if ($_.KeyboardDevice.Modifiers -eq "Alt") { + # this is an example how to handle shortcuts per tab + # Alt-I on the MicroWin tab (4) would press GetIso Button + # NOTE: All per tab shortcuts have to be handled *before* regular tab keys + # if ($_.SystemKey -eq "I") { + # $TabNav = Get-WinUtilVariables | Where-Object {$psitem -like "WPFTabNav"} + # if ($sync.$TabNav.Items[4].IsSelected -eq $true) { + # Invoke-WPFButton "WPFGetIso" + # break + # } + # } + if ($_.SystemKey -eq "I") { + Invoke-WPFButton "WPFTab1BT" + } + if ($_.SystemKey -eq "T") { + Invoke-WPFButton "WPFTab2BT" + } + if ($_.SystemKey -eq "C") { + Invoke-WPFButton "WPFTab3BT" + } + if ($_.SystemKey -eq "U") { + Invoke-WPFButton "WPFTab4BT" + } + if ($_.SystemKey -eq "M") { + Invoke-WPFButton "WPFTab5BT" + } + } + # shortcut for the filter box + if ($_.Key -eq "F" -and $_.KeyboardDevice.Modifiers -eq "Ctrl") { + if ($sync.CheckboxFilter.Text -eq "Ctrl-F to filter") { + $sync.CheckboxFilter.SelectAll() + $sync.CheckboxFilter.Text = "" + } + $sync.CheckboxFilter.Focus() + } +} +$sync["Form"].Add_PreViewKeyDown($commonKeyEvents) + +# adding some left mouse window move on drag capability +$sync["Form"].Add_MouseLeftButtonDown({ + $sync["Form"].DragMove() +}) + +# setting window icon to make it look more professional +$sync["Form"].Add_Loaded({ + + $downloadUrl = "https://christitus.com/images/logo-full.png" + $destinationPath = Join-Path $env:TEMP "cttlogo.png" + + # Check if the file already exists + if (-not (Test-Path $destinationPath)) { + # File does not exist, download it + $wc = New-Object System.Net.WebClient + $wc.DownloadFile($downloadUrl, $destinationPath) + Write-Output "File downloaded to: $destinationPath" + } else { + Write-Output "File already exists at: $destinationPath" + } + $sync["Form"].Icon = $destinationPath + + Try { + [Void][Window] + } Catch { + Add-Type @" + using System; + using System.Runtime.InteropServices; + public class Window { + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw); + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ShowWindow(IntPtr handle, int state); + } + public struct RECT { + public int Left; // x position of upper-left corner + public int Top; // y position of upper-left corner + public int Right; // x position of lower-right corner + public int Bottom; // y position of lower-right corner + } +"@ + } + + $processId = [System.Diagnostics.Process]::GetCurrentProcess().Id + $windowHandle = (Get-Process -Id $processId).MainWindowHandle + $rect = New-Object RECT + [Void][Window]::GetWindowRect($windowHandle,[ref]$rect) + + # only snap upper edge don't move left to right, in case people have multimon setup + $x = $rect.Left + $y = 0 + $width = $rect.Right - $rect.Left + $height = $rect.Bottom - $rect.Top + + # Move the window to that position... + [Void][Window]::MoveWindow($windowHandle, $x, $y, $width, $height, $True) + Invoke-WPFTab "WPFTab1BT" + $sync["Form"].Focus() +}) + +$sync["CheckboxFilter"].Add_TextChanged({ + #Write-host $sync.CheckboxFilter.Text + + $filter = Get-WinUtilVariables -Type Checkbox + $CheckBoxes = $sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} + $textToSearch = $sync.CheckboxFilter.Text + Foreach ($CheckBox in $CheckBoxes) { + #Write-Host "$($sync.CheckboxFilter.Text)" + if ($CheckBox -eq $null -or $CheckBox.Value -eq $null -or $CheckBox.Value.Content -eq $null) { + continue + } + if ($CheckBox.Value.Content.ToLower().Contains($textToSearch)) { + $CheckBox.Value.Visibility = "Visible" + } + else { + $CheckBox.Value.Visibility = "Collapsed" + } + } +}) + + +$downloadUrl = "https://christitus.com/images/logo-full.png" +$destinationPath = Join-Path $env:TEMP "cttlogo.png" + +# Check if the file already exists +if (-not (Test-Path $destinationPath)) { + # File does not exist, download it + $wc = New-Object System.Net.WebClient + $wc.DownloadFile($downloadUrl, $destinationPath) + Write-Output "File downloaded to: $destinationPath" +} else { + Write-Output "File already exists at: $destinationPath" +} + +# show current windowsd Product ID +#Write-Host "Your Windows Product Key: $((Get-WmiObject -query 'select * from SoftwareLicensingService').OA3xOriginalProductKey)" + +$sync["Form"].ShowDialog() | out-null Stop-Transcript \ No newline at end of file diff --git a/scripts/start.ps1 b/scripts/start.ps1 index 2f3f5156..7ae8eed7 100644 --- a/scripts/start.ps1 +++ b/scripts/start.ps1 @@ -9,6 +9,7 @@ Start-Transcript $ENV:TEMP\Winutil.log -Append # Load DLLs +Add-Type -AssemblyName PresentationFramework Add-Type -AssemblyName System.Windows.Forms # Variable to sync between runspaces @@ -18,9 +19,20 @@ $sync.version = "#{replaceme}" $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 (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { - Write-Output "Winutil needs to be run as Administrator. Attempting to relaunch." - Start-Process -Verb runas -FilePath powershell.exe -ArgumentList "iwr -useb https://christitus.com/win | iex" - break +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 +} \ No newline at end of file diff --git a/winutil.ps1 b/winutil.ps1 index 9c89cfaa..fba58f6a 100755 --- a/winutil.ps1 +++ b/winutil.ps1 @@ -10,27 +10,129 @@ Author : Chris Titus @christitustech Runspace Author: @DeveloperDurp GitHub : https://github.com/ChrisTitusTech - Version : 23.11.14 + Version : 23.11.28 #> 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 = "23.11.14" +$sync.version = "23.11.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 (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { - Write-Output "Winutil needs to be run as Administrator. Attempting to relaunch." - Start-Process -Verb runas -FilePath powershell.exe -ArgumentList "iwr -useb https://christitus.com/win | iex" +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 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 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") + { + if ($found) + { + $characters = $line -split '(")([A-Za-z])(")' | Where-Object { $_ -match '^[A-Za-z]$' } + $charactersArray += $characters + + 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-WinUtilCheckBoxes { <# @@ -249,7 +351,7 @@ function Get-WinUtilVariables { #> param ( [Parameter()] - [ValidateSet("CheckBox", "Button")] + [ValidateSet("CheckBox", "Button", "ToggleButton")] [string]$Type ) @@ -357,6 +459,8 @@ function Install-WinUtilWinget { .SYNOPSIS Installs Winget if it is not already installed + .DESCRIPTION + This function will download the latest version of winget and install it. If winget is already installed, it will do nothing. #> Try{ Write-Host "Checking if Winget is Installed..." @@ -861,6 +965,570 @@ function Invoke-WinUtilVerboseLogon { Write-Warning $psitem.Exception.StackTrace } } +function Remove-Features([switch] $dumpFeatures = $false, [switch] $keepDefender = $false) { +<# + + .SYNOPSIS + Removes certain features from ISO image + + .PARAMETER Name + dumpFeatures - Dumps all features found in the ISO into a file called allfeaturesdump.txt. This file can be examined and used to decide what to remove. + keepDefender - Should Defender be removed from the ISO? + + .EXAMPLE + Remove-Features -keepDefender:$false + +#> + $appxlist = dism /image:$scratchDir /Get-Features | Select-String -Pattern "Feature Name : " -CaseSensitive -SimpleMatch + $appxlist = $appxlist -split "Feature Name : " | Where-Object {$_} + if ($dumpFeatures) + { + $appxlist > allfeaturesdump.txt + } + + $appxlist = $appxlist | Where-Object { + $_ -NotLike "*Printing*" -AND + $_ -NotLike "*TelnetClient*" -AND + $_ -NotLike "*PowerShell*" -AND + $_ -NotLike "*NetFx*" + } + + if ($keepDefender) { $appxlist = $appxlist | Where-Object { $_ -NotLike "*Defender*" }} + + foreach($feature in $appxlist) + { + $status = "Removing feature $feature" + Write-Progress -Activity "Removing features" -Status $status -PercentComplete ($counter++/$appxlist.Count*100) + Write-Debug "Removing feature $feature" + # dism /image:$scratchDir /Disable-Feature /FeatureName:$feature /Remove /NoRestart > $null + } + Write-Progress -Activity "Removing features" -Status "Ready" -Completed +} + +function Remove-Packages +{ + $appxlist = dism /Image:$scratchDir /Get-Packages | Select-String -Pattern "Package Identity : " -CaseSensitive -SimpleMatch + $appxlist = $appxlist -split "Package Identity : " | Where-Object {$_} + + $appxlist = $appxlist | Where-Object { + $_ -NotLike "*ApplicationModel*" -AND + $_ -NotLike "*indows-Client-LanguagePack*" -AND + $_ -NotLike "*LanguageFeatures-Basic*" -AND + $_ -NotLike "*Package_for_ServicingStack*" -AND + $_ -NotLike "*.NET*" -AND + $_ -NotLike "*Store*" -AND + $_ -NotLike "*VCLibs*" -AND + $_ -NotLike "*AAD.BrokerPlugin", + $_ -NotLike "*LockApp*" -AND + $_ -NotLike "*Notepad*" -AND + $_ -NotLike "*immersivecontrolpanel*" -AND + $_ -NotLike "*ContentDeliveryManager*" -AND + $_ -NotLike "*PinningConfirMationDialog*" -AND + $_ -NotLike "*SecHealthUI*" -AND + $_ -NotLike "*SecureAssessmentBrowser*" -AND + $_ -NotLike "*PrintDialog*" -AND + $_ -NotLike "*AssignedAccessLockApp*" -AND + $_ -NotLike "*OOBENetworkConnectionFlow*" -AND + $_ -NotLike "*Apprep.ChxApp*" -AND + $_ -NotLike "*CBS*" -AND + $_ -NotLike "*OOBENetworkCaptivePortal*" -AND + $_ -NotLike "*PeopleExperienceHost*" -AND + $_ -NotLike "*ParentalControls*" -AND + $_ -NotLike "*Win32WebViewHost*" -AND + $_ -NotLike "*InputApp*" -AND + $_ -NotLike "*AccountsControl*" -AND + $_ -NotLike "*AsyncTextService*" -AND + $_ -NotLike "*CapturePicker*" -AND + $_ -NotLike "*CredDialogHost*" -AND + $_ -NotLike "*BioEnrollMent*" -AND + $_ -NotLike "*ShellExperienceHost*" -AND + $_ -NotLike "*DesktopAppInstaller*" -AND + $_ -NotLike "*WebMediaExtensions*" -AND + $_ -NotLike "*WMIC*" -AND + $_ -NotLike "*UI.XaML*" + } + + foreach ($appx in $appxlist) + { + $status = "Removing $appx" + Write-Progress -Activity "Removing Apps" -Status $status -PercentComplete ($counter++/$appxlist.Count*100) + dism /image:$scratchDir /Remove-Package /PackageName:$appx /NoRestart + } + Write-Progress -Activity "Removing Apps" -Status "Ready" -Completed +} + +function Remove-ProvisionedPackages +{ + $appxProvisionedPackages = Get-AppxProvisionedPackage -Path "$($scratchDir)" | Where-Object { + $_.PackageName -NotLike "*AppInstaller*" -AND + $_.PackageName -NotLike "*Store*" -and + $_.PackageName -NotLike "*dism*" -and + $_.PackageName -NotLike "*Foundation*" -and + $_.PackageName -NotLike "*FodMetadata*" -and + $_.PackageName -NotLike "*LanguageFeatures*" -and + $_.PackageName -NotLike "*Notepad*" -and + $_.PackageName -NotLike "*Printing*" -and + $_.PackageName -NotLike "*Wifi*" -and + $_.PackageName -NotLike "*Foundation*" + } + + $counter = 0 + foreach ($appx in $appxProvisionedPackages) + { + $status = "Removing Provisioned $appx" + Write-Progress -Activity "Removing Provisioned Apps" -Status $status -PercentComplete ($counter++/$appxProvisionedPackages.Count*100) + dism /image:$scratchDir /Remove-ProvisionedAppxPackage /PackageName:$appx /NoRestart + + } + Write-Progress -Activity "Removing Provisioned Apps" -Status "Ready" -Completed +} + +function Copy-ToUSB([string] $fileToCopy) +{ + foreach ($volume in Get-Volume) { + if ($volume -and $volume.FileSystemLabel -ieq "ventoy") { + $destinationPath = "$($volume.DriveLetter):\" + #Copy-Item -Path $fileToCopy -Destination $destinationPath -Force + # Get the total size of the file + $totalSize = (Get-Item $fileToCopy).length + + Copy-Item -Path $fileToCopy -Destination $destinationPath -Verbose -Force -Recurse -Container -PassThru | + ForEach-Object { + # Calculate the percentage completed + $completed = ($_.BytesTransferred / $totalSize) * 100 + + # Display the progress bar + 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)" + return + } + } + Write-Host "Ventoy USB Key is not inserted" +} + +function Remove-FileOrDirectory([string] $pathToDelete, [string] $mask = "", [switch] $Directory = $false) +{ + if(([string]::IsNullOrEmpty($pathToDelete))) { return } + if (-not (Test-Path -Path "$($pathToDelete)")) { return } + + $yesNo = Get-LocalizedYesNo + + # Specify the path to the directory + # $directoryPath = "$($scratchDir)\Windows\System32\LogFiles\WMI\RtBackup" + # takeown /a /r /d $yesNo[0] /f "$($directoryPath)" > $null + # icacls "$($directoryPath)" /q /c /t /reset > $null + # icacls $directoryPath /setowner "*S-1-5-32-544" + # icacls $directoryPath /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q + # Remove-Item -Path $directoryPath -Recurse -Force + + # # Grant full control to BUILTIN\Administrators using icacls + # $directoryPath = "$($scratchDir)\Windows\System32\WebThreatDefSvc" + # takeown /a /r /d $yesNo[0] /f "$($directoryPath)" > $null + # icacls "$($directoryPath)" /q /c /t /reset > $null + # icacls $directoryPath /setowner "*S-1-5-32-544" + # icacls $directoryPath /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q + # Remove-Item -Path $directoryPath -Recurse -Force + + $itemsToDelete = [System.Collections.ArrayList]::new() + + if ($mask -eq "") + { + Write-Debug "Adding $($pathToDelete) to array." + [void]$itemsToDelete.Add($pathToDelete) + } + else + { + Write-Debug "Adding $($pathToDelete) to array and mask is $($mask)" + if ($Directory) { $itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse -Directory } + else { $itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse } + } + + foreach($itemToDelete in $itemsToDelete) + { + $status = "Deleteing $($itemToDelete)" + Write-Progress -Activity "Removing Items" -Status $status -PercentComplete ($counter++/$itemsToDelete.Count*100) + + if (Test-Path -Path "$($itemToDelete)" -PathType Container) + { + $status = "Deleting directory: $($itemToDelete)" + + takeown /r /d $yesNo[0] /a /f "$($itemToDelete)" + icacls "$($itemToDelete)" /q /c /t /reset + icacls $itemToDelete /setowner "*S-1-5-32-544" + icacls $itemToDelete /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q + Remove-Item -Force -Recurse "$($itemToDelete)" + } + elseif (Test-Path -Path "$($itemToDelete)" -PathType Leaf) + { + $status = "Deleting file: $($itemToDelete)" + + takeown /a /f "$($itemToDelete)" + icacls "$($itemToDelete)" /q /c /t /reset + icacls "$($itemToDelete)" /setowner "*S-1-5-32-544" + icacls "$($itemToDelete)" /grant "*S-1-5-32-544:(OI)(CI)F" /t /c /q + Remove-Item -Force "$($itemToDelete)" + } + } + Write-Progress -Activity "Removing Items" -Status "Ready" -Completed +} + +function New-Unattend { + + # later if we wont to remove even more bloat EU requires MS to remove everything from English(world) + # Below is an example how to do it we probably should create a drop down with common locals + # + # + # + # + # en-US + # + # en-US + # en-US + # en-US + # en-US + # + # + + # + # + # + # en-US + # en-US + # en-US + # en-US + # + # + # using here string to embedd unattend + # + # 1 + # net user administrator /active:yes + # + + $unattend = @' + + + + + 0 + + + false + + + + + + + 1 + CMD /C echo LAU GG>C:\Windows\LogAuditUser.txt + StartMenu + + + + + + + + true + false + false + true + true + true + 3 + + + + 1 + cmd.exe /c echo 23>c:\windows\csup.txt + + + 2 + CMD /C echo GG>C:\Windows\LogOobeSystem.txt + + + 3 + powershell -ExecutionPolicy Bypass -File c:\windows\FirstStartup.ps1 + + + + + +'@ + $unattend | Out-File -FilePath "$env:temp\unattend.xml" -Force +} + +function New-CheckInstall { + + # using here string to embedd firstrun + $checkInstall = @' + @echo off + if exist "C:\windows\cpu.txt" ( + echo C:\windows\cpu.txt exists + ) else ( + echo C:\windows\cpu.txt does not exist + ) + if exist "C:\windows\SerialNumber.txt" ( + echo C:\windows\SerialNumber.txt exists + ) else ( + echo C:\windows\SerialNumber.txt does not exist + ) + if exist "C:\unattend.xml" ( + echo C:\unattend.xml exists + ) else ( + echo C:\unattend.xml does not exist + ) + if exist "C:\Windows\Setup\Scripts\SetupComplete.cmd" ( + echo C:\Windows\Setup\Scripts\SetupComplete.cmd exists + ) else ( + echo C:\Windows\Setup\Scripts\SetupComplete.cmd does not exist + ) + if exist "C:\Windows\Panther\unattend.xml" ( + echo C:\Windows\Panther\unattend.xml exists + ) else ( + echo C:\Windows\Panther\unattend.xml does not exist + ) + if exist "C:\Windows\System32\Sysprep\unattend.xml" ( + echo C:\Windows\System32\Sysprep\unattend.xml exists + ) else ( + echo C:\Windows\System32\Sysprep\unattend.xml does not exist + ) + if exist "C:\Windows\FirstStartup.ps1" ( + echo C:\Windows\FirstStartup.ps1 exists + ) else ( + echo C:\Windows\FirstStartup.ps1 does not exist + ) + if exist "C:\Windows\winutil.ps1" ( + echo C:\Windows\winutil.ps1 exists + ) else ( + echo C:\Windows\winutil.ps1 does not exist + ) + if exist "C:\Windows\LogSpecialize.txt" ( + echo C:\Windows\LogSpecialize.txt exists + ) else ( + echo C:\Windows\LogSpecialize.txt does not exist + ) + if exist "C:\Windows\LogAuditUser.txt" ( + echo C:\Windows\LogAuditUser.txt exists + ) else ( + echo C:\Windows\LogAuditUser.txt does not exist + ) + if exist "C:\Windows\LogOobeSystem.txt" ( + echo C:\Windows\LogOobeSystem.txt exists + ) else ( + echo C:\Windows\LogOobeSystem.txt does not exist + ) + if exist "c:\windows\csup.txt" ( + echo c:\windows\csup.txt exists + ) else ( + echo c:\windows\csup.txt does not exist + ) + if exist "c:\windows\LogFirstRun.txt" ( + echo c:\windows\LogFirstRun.txt exists + ) else ( + echo c:\windows\LogFirstRun.txt does not exist + ) +'@ + $checkInstall | Out-File -FilePath "$env:temp\checkinstall.cmd" -Force -Encoding Ascii +} + +function New-FirstRun { + + # using here string to embedd firstrun + $firstRun = @' + # 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." + } + } + + function Stop-UnnecessaryServices + { + $servicesAuto = @" + "AudioSrv", + "AudioEndpointBuilder", + "BFE", + "BITS", + "BrokerInfrastructure", + "CDPSvc", + "CDPUserSvc_dc2a4", + "CoreMessagingRegistrar", + "CryptSvc", + "DPS", + "DcomLaunch", + "Dhcp", + "DispBrokerDesktopSvc", + "Dnscache", + "DoSvc", + "DusmSvc", + "EventLog", + "EventSystem", + "FontCache", + "LSM", + "LanmanServer", + "LanmanWorkstation", + "MapsBroker", + "MpsSvc", + "OneSyncSvc_dc2a4", + "Power", + "ProfSvc", + "RpcEptMapper", + "RpcSs", + "SCardSvr", + "SENS", + "SamSs", + "Schedule", + "SgrmBroker", + "ShellHWDetection", + "Spooler", + "SysMain", + "SystemEventsBroker", + "TextInputManagementService", + "Themes", + "TrkWks", + "UserManager", + "VGAuthService", + "VMTools", + "WSearch", + "Wcmsvc", + "WinDefend", + "Winmgmt", + "WlanSvc", + "WpnService", + "WpnUserService_dc2a4", + "cbdhsvc_dc2a4", + "edgeupdate", + "gpsvc", + "iphlpsvc", + "mpssvc", + "nsi", + "sppsvc", + "tiledatamodelsvc", + "vm3dservice", + "webthreatdefusersvc_dc2a4", + "wscsvc" +"@ + + $allServices = Get-Service | Where-Object { $_.StartType -eq "Automatic" -and $servicesAuto -NotContains $_.Name} + foreach($service in $allServices) + { + Stop-Service -Name $service.Name -PassThru + Set-Service $service.Name -StartupType Manual + "Stopping service $($service.Name)" | Out-File -FilePath c:\windows\LogFirstRun.txt -Append -NoClobber + } + } + + "FirstStartup has worked" | Out-File -FilePath c:\windows\LogFirstRun.txt -Append -NoClobber + + $Theme = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" + Set-ItemProperty -Path $Theme -Name AppsUseLightTheme -Value 1 + Set-ItemProperty -Path $Theme -Name SystemUsesLightTheme -Value 1 + + # figure this out later how to set updates to security only + #Import-Module -Name PSWindowsUpdate; + #Stop-Service -Name wuauserv + #Set-WUSettings -MicrosoftUpdateEnabled -AutoUpdateOption 'Never' + #Start-Service -Name wuauserv + + Stop-UnnecessaryServices + + $taskbarPath = "$env:AppData\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar" + # Delete all files on the Taskbar + 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" + + # Stop-Process -Name explorer -Force + + $process = Get-Process -Name "explorer" + Stop-Process -InputObject $process + # Wait for the process to exit + Wait-Process -InputObject $process + Start-Sleep -Seconds 3 + + # 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 "C:\Users\Default\Desktop\*.lnk" + + # ************************************************ + # Create WinUtil shortcut on the desktop + # + $desktopPath = "$($env:USERPROFILE)\Desktop" + # Specify the target PowerShell command + $command = "powershell.exe -NoProfile -ExecutionPolicy Bypass -Command 'irm https://christitus.com/win | iex'" + # Specify the path for the shortcut + $shortcutPath = Join-Path $desktopPath 'winutil.lnk' + # Create a shell object + $shell = New-Object -ComObject WScript.Shell + + # Create a shortcut object + $shortcut = $shell.CreateShortcut($shortcutPath) + + if (Test-Path -Path "c:\Windows\cttlogo.png") + { + $shortcut.IconLocation = "c:\Windows\cttlogo.png" + } + + # Set properties of the shortcut + $shortcut.TargetPath = "powershell.exe" + $shortcut.Arguments = "-NoProfile -ExecutionPolicy Bypass -Command `"$command`"" + # Save the shortcut + $shortcut.Save() + Write-Host "Shortcut created at: $shortcutPath" + # + # Done create WinUtil shortcut on the desktop + # ************************************************ + + Start-Process explorer + +'@ + $firstRun | Out-File -FilePath "$env:temp\FirstStartup.ps1" -Force +} function Remove-WinUtilAPPX { <# @@ -878,16 +1546,16 @@ function Remove-WinUtilAPPX { $Name ) - Try{ + Try { Write-Host "Removing $Name" Get-AppxPackage "*$Name*" | Remove-AppxPackage -ErrorAction SilentlyContinue Get-AppxProvisionedPackage -Online | Where-Object DisplayName -like "*$Name*" | Remove-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue } Catch [System.Exception] { - if($psitem.Exception.Message -like "*The requested operation requires elevation*"){ + if ($psitem.Exception.Message -like "*The requested operation requires elevation*") { Write-Warning "Unable to uninstall $name due to a Security Exception" } - Else{ + else { Write-Warning "Unable to uninstall $name due to unhandled exception" Write-Warning $psitem.Exception.StackTrace } @@ -1261,12 +1929,15 @@ function Invoke-WPFButton { "WPFPaneluser" {Invoke-WPFControlPanel -Panel $button} "WPFUpdatesdefault" {Invoke-WPFUpdatesdefault} "WPFFixesUpdate" {Invoke-WPFFixesUpdate} + "WPFFixesWinget" {Invoke-WPFFixesWinget} "WPFFixesNetwork" {Invoke-WPFFixesNetwork} "WPFUpdatesdisable" {Invoke-WPFUpdatesdisable} "WPFUpdatessecurity" {Invoke-WPFUpdatessecurity} "WPFWinUtilShortcut" {Invoke-WPFShortcut -ShortcutToAdd "WinUtil"} "WPFGetInstalled" {Invoke-WPFGetInstalled -CheckBox "winget"} "WPFGetInstalledTweaks" {Invoke-WPFGetInstalled -CheckBox "tweaks"} + "WPFGetIso" {Invoke-WPFGetIso} + "WPFMicrowin" {Invoke-WPFMicrowin} } } function Invoke-WPFControlPanel { @@ -1446,6 +2117,19 @@ Write-Host "12) Forcing discovery..." Write-Host "-- Reset All Windows Update Settings to Stock -" Write-Host "===============================================" } +function Invoke-WPFFixesWinget { + + <# + + .SYNOPSIS + Fixes Winget by running choco install winget + .DESCRIPTION + BravoNorris for the fantastic idea of a button to reinstall winget + #> + + Start-Process -FilePath "choco" -ArgumentList "install winget -y" -NoNewWindow -Wait + +} Function Invoke-WPFFormVariables { <# @@ -1477,7 +2161,6 @@ Function Invoke-WPFFormVariables { Write-Host "====Chris Titus Tech=====" Write-Host "=====Windows Toolbox=====" - #====DEBUG GUI Elements==== #Write-Host "Found the following interactable elements from our form" -ForegroundColor Cyan @@ -1532,6 +2215,131 @@ function Invoke-WPFGetInstalled { $sync.ProcessRunning = $false } } +function Invoke-WPFGetIso { + <# + .DESCRIPTION + Function to get the path to Iso file for MicroWin, unpack that isom=, read basic information and populate the UI Options + #> + + Write-Host "Invoking WPFGetIso" + + if($sync.ProcessRunning){ + $msg = "GetIso process is currently running." + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) + return + } + + Write-Host " _ __ __ _ " + Write-Host " /\/\ (_) ___ _ __ ___ / / /\ \ \(_) _ __ " + Write-Host " / \ | | / __|| '__| / _ \ \ \/ \/ /| || '_ \ " + Write-Host "/ /\/\ \| || (__ | | | (_) | \ /\ / | || | | | " + Write-Host "\/ \/|_| \___||_| \___/ \/ \/ |_||_| |_| " + + $oscdImgFound = [bool] (Get-Command -ErrorAction Ignore -Type Application oscdimg) + Write-Host "oscdimge.exe on system: $oscdImgFound" + + if (!$oscdImgFound) + { + [System.Windows.MessageBox]::Show("oscdimge.exe is not found on the system, you need to download it first before running this function!") + + # the step below needs choco to download oscdimg + $chocoFound = [bool] (Get-Command -ErrorAction Ignore -Type Application choco) + Write-Host "choco on system: $oscdImgFound" + if (!$chocoFound) + { + [System.Windows.MessageBox]::Show("choco.exe is not found on the system, you need choco to download oscdimg.exe") + return + } + + Start-Process -Verb runas -FilePath powershell.exe -ArgumentList "choco install windows-adk-oscdimg" + [System.Windows.MessageBox]::Show("oscdimg is installed, now close, reopen PowerShell terminal and re-launch winutil.ps1 !!!") + return + } + + [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null + $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog + $openFileDialog.initialDirectory = $initialDirectory + $openFileDialog.filter = "ISO files (*.iso)| *.iso" + $openFileDialog.ShowDialog() | Out-Null + $filePath = $openFileDialog.FileName + + if ([string]::IsNullOrEmpty($filePath)) + { + Write-Host "No ISO is chosen" + break + } + + Write-Host "File path $($filePath)" + if (-not (Test-Path -Path $filePath -PathType Leaf)) + { + $msg = "File you've chosen doesn't exist" + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error) + break + } + + Write-Host "Mounting Iso. Please wait." + $mountedISO = Mount-DiskImage -PassThru "$filePath" + Write-Host "Done mounting Iso $mountedISO" + $driveLetter = (Get-Volume -DiskImage $mountedISO).DriveLetter + Write-Host "Iso mounted to '$driveLetter'" + # storing off values in hidden fields for further steps + # there is probably a better way of doing this, I don't have time to figure this out + $sync.MicrowinIsoDrive.Text = $driveLetter + + Write-Host "Setting up mount dir and scratch dirs" + $mountDir = "c:\microwin" + $scratchDir = "c:\microwinscratch" + $sync.MicrowinMountDir.Text = $mountDir + $sync.MicrowinScratchDir.Text = $scratchDir + Write-Host "Done setting up mount dir and scratch dirs" + + try { + + $data = @($driveLetter, $filePath) + New-Item -ItemType Directory -Force -Path "$($mountDir)" | Out-Null + New-Item -ItemType Directory -Force -Path "$($scratchDir)" | Out-Null + Write-Host "Copying Windows image. This will take awhile, please don't use UI or cancel this step!" + + # xcopy we can verify files and also not copy files that already exist, but hard to measure + # xcopy.exe /E /I /H /R /Y /J $DriveLetter":" $mountDir >$null + $totalTime = Measure-Command { Copy-Files "$($driveLetter):" $mountDir -Recurse -Force } + Write-Host "Copy complete! Total Time: $($totalTime.Minutes)m$($totalTime.Seconds)s" + + $wimFile = "$mountDir\sources\install.wim" + Write-Host "Getting image information $wimFile" + + if (-not (Test-Path -Path $wimFile -PathType Leaf)) + { + $msg = "install wim file doesn't exist in the image, are you sure you used Windows image??" + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error) + throw + } + Get-WindowsImage -ImagePath $wimFile | ForEach-Object { + $imageIdx = $_.ImageIndex + $imageName = $_.ImageName + $sync.MicrowinWindowsFlavors.Items.Add("$imageIdx : $imageName") + } + $sync.MicrowinWindowsFlavors.SelectedIndex = 0 + Get-Volume $driveLetter | Get-DiskImage | Dismount-DiskImage + Write-Host "Selected value '$($sync.MicrowinWindowsFlavors.SelectedValue)'....." + + $sync.MicrowinOptionsPanel.Visibility = 'Visible' + } catch { + Write-Host "Dismounting bad image..." + Get-Volume $driveLetter | Get-DiskImage | Dismount-DiskImage + Remove-Item -Recurse -Force "$($scratchDir)" + Remove-Item -Recurse -Force "$($mountDir)" + } + + Write-Host "Done reading and unpacking ISO" + Write-Host "" + Write-Host "*********************************" + Write-Host "Check the UI for further steps!!!" + + $sync.ProcessRunning = $false +} + + function Invoke-WPFImpex { <# @@ -1656,6 +2464,341 @@ function Invoke-WPFInstallUpgrade { Write-Host "-- You can close this window if desired ---" Write-Host "===========================================" } +function Invoke-WPFMicrowin { + <# + .DESCRIPTION + Invoke MicroWin routines... + #> + + if($sync.ProcessRunning) { + $msg = "GetIso process is currently running." + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) + return + } + + $index = $sync.MicrowinWindowsFlavors.SelectedValue.Split(":")[0].Trim() + Write-Host "Index chosen: '$index' from $($sync.MicrowinWindowsFlavors.SelectedValue)" + + $keepPackages = $sync.WPFMicrowinKeepProvisionedPackages.IsChecked + $keepProvisionedPackages = $sync.WPFMicrowinKeepAppxPackages.IsChecked + $keepDefender = $sync.WPFMicrowinKeepDefender.IsChecked + $keepEdge = $sync.WPFMicrowinKeepEdge.IsChecked + $copyToUSB = $sync.WPFMicrowinCopyToUsb.IsChecked + $injectDrivers = $sync.MicrowinInjectDrivers.IsChecked + + $mountDir = $sync.MicrowinMountDir.Text + $scratchDir = $sync.MicrowinScratchDir.Text + + $mountDirExists = Test-Path $mountDir + $scratchDirExists = Test-Path $scratchDir + if (-not $mountDirExists -or -not $scratchDirExists) + { + Write-Error "Required directories '$mountDirExists' '$scratchDirExists' and do not exist." + return + } + + 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..." + + if ($injectDrivers) + { + $driverPath = $sync.MicrowinDriverLocation.Text + if (Test-Path $driverPath) + { + Write-Host "Adding Windows Drivers image($scratchDir) drivers($driverPath) " + dism /image:$scratchDir /add-driver /driver:$driverPath /recurse | Out-Host + } + else + { + Write-Host "Path to drivers is invalid continuing without driver injection" + } + } + + Write-Host "Remove Features from the image" + Remove-Features -keepDefender:$keepDefender + Write-Host "Removing features complete!" + + Write-Host "Removing Appx Bloat" + if (!$keepPackages) + { + Remove-Packages + } + if (!$keepProvisionedPackages) + { + Remove-ProvisionedPackages + } + + # special code, for some reason when you try to delete some inbox apps + # we have to get and delete log files directory. + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\LogFiles\WMI\RtBackup" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\WebThreatDefSvc" -Directory + + # Defender is hidden in 2 places we removed a feature above now need to remove it from the disk + if (!$keepDefender) + { + Write-Host "Removing Defender" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Defender" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Defender" + } + if (!$keepEdge) + { + Write-Host "Removing Edge" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Microsoft" -mask "*edge*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Microsoft" -mask "*edge*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*edge*" -Directory + } + + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\DiagTrack" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\InboxApps" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\SecurityHealthSystray.exe" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\LocationNotificationWindows.exe" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Photo Viewer" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Photo Viewer" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Media Player" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Media Player" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Mail" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Mail" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Internet Explorer" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Internet Explorer" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\GameBarPresenceWriter" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\OneDriveSetup.exe" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\OneDrive.ico" + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*Windows.Search*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*narratorquickstart*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*Xbox*" -Directory + Remove-FileOrDirectory -pathToDelete "$($scratchDir)\Windows\SystemApps" -mask "*ParentalControls*" -Directory + Write-Host "Removal complete!" + + # *************************** Automation black *************************** + # this doesn't work for some reason, this script is not being run at the end of the install + # if someone knows how to fix this, feel free to modify + New-Item -ItemType Directory -Force -Path $scratchDir\Windows\Setup\Scripts\ + "wmic cpu get Name > C:\windows\cpu.txt" | Out-File -FilePath "$($scratchDir)\Windows\Setup\Scripts\SetupComplete.cmd" -NoClobber -Append + "wmic bios get serialnumber > C:\windows\SerialNumber.txt" | Out-File -FilePath "$($scratchDir)\Windows\Setup\Scripts\SetupComplete.cmd" -NoClobber -Append + "devmgmt.msc /s" | Out-File -FilePath "$($scratchDir)\Windows\Setup\Scripts\SetupComplete.cmd" -NoClobber -Append + + Write-Host "Create unattend.xml" + New-Unattend + Write-Host "Done Create unattend.xml" + Write-Host "Copy unattend.xml file into the ISO" + New-Item -ItemType Directory -Force -Path "$($scratchDir)\Windows\Panther" + Copy-Item "$env:temp\unattend.xml" "$($scratchDir)\Windows\Panther\unattend.xml" -force + New-Item -ItemType Directory -Force -Path "$($scratchDir)\Windows\System32\Sysprep" + Copy-Item "$env:temp\unattend.xml" "$($scratchDir)\Windows\System32\Sysprep\unattend.xml" -force + Copy-Item "$env:temp\unattend.xml" "$($scratchDir)\unattend.xml" -force + Write-Host "Done Copy unattend.xml" + + Write-Host "Create FirstRun" + New-FirstRun + Write-Host "Done create FirstRun" + Write-Host "Copy FirstRun.ps1 into the ISO" + Copy-Item "$env:temp\FirstStartup.ps1" "$($scratchDir)\Windows\FirstStartup.ps1" -force + Write-Host "Done copy FirstRun.ps1" + + Write-Host "Copy link to winutil.ps1 into the ISO" + $desktopDir = "$($scratchDir)\Windows\Users\Default\Desktop" + New-Item -ItemType Directory -Force -Path "$desktopDir" + dism /image:$($scratchDir) /set-profilepath:"$($scratchDir)\Windows\Users\Default" + $command = "powershell.exe -NoProfile -ExecutionPolicy Bypass -Command 'irm https://christitus.com/win | iex'" + $shortcutPath = "$desktopDir\WinUtil.lnk" + $shell = New-Object -ComObject WScript.Shell + $shortcut = $shell.CreateShortcut($shortcutPath) + + if (Test-Path -Path "$env:TEMP\cttlogo.png") + { + $pngPath = "$env:TEMP\cttlogo.png" + $icoPath = "$env:TEMP\cttlogo.ico" + Add-Type -AssemblyName System.Drawing + $pngImage = [System.Drawing.Image]::FromFile($pngPath) + $pngImage.Save($icoPath, [System.Drawing.Imaging.ImageFormat]::Icon) + Write-Host "ICO file created at: $icoPath" + Copy-Item "$env:TEMP\cttlogo.png" "$($scratchDir)\Windows\cttlogo.png" -force + Copy-Item "$env:TEMP\cttlogo.ico" "$($scratchDir)\cttlogo.ico" -force + $shortcut.IconLocation = "c:\cttlogo.ico" + } + + $shortcut.TargetPath = "powershell.exe" + $shortcut.Arguments = "-NoProfile -ExecutionPolicy Bypass -Command `"$command`"" + $shortcut.Save() + Write-Host "Shortcut to winutil created at: $shortcutPath" + # *************************** Automation black *************************** + + Write-Host "Copy checkinstall.cmd into the ISO" + New-CheckInstall + Copy-Item "$env:temp\checkinstall.cmd" "$($scratchDir)\Windows\checkinstall.cmd" -force + Write-Host "Done copy checkinstall.cmd" + + Write-Host "Creating a directory that allows to bypass Wifi setup" + New-Item -ItemType Directory -Force -Path "$($scratchDir)\Windows\System32\OOBE\BYPASSNRO" + + Write-Host "Loading registry" + reg load HKLM\zCOMPONENTS "$($scratchDir)\Windows\System32\config\COMPONENTS" + reg load HKLM\zDEFAULT "$($scratchDir)\Windows\System32\config\default" + reg load HKLM\zNTUSER "$($scratchDir)\Users\Default\ntuser.dat" + reg load HKLM\zSOFTWARE "$($scratchDir)\Windows\System32\config\SOFTWARE" + reg load HKLM\zSYSTEM "$($scratchDir)\Windows\System32\config\SYSTEM" + + Write-Host "Disabling Teams" + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Communications" /v "ConfigureChatAutoInstall" /t REG_DWORD /d 0 /f >$null 2>&1 + reg add "HKLM\zSOFTWARE\Policies\Microsoft\Windows\Windows Chat" /v ChatIcon /t REG_DWORD /d 2 /f >$null 2>&1 + reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "TaskbarMn" /t REG_DWORD /d 0 /f >$null 2>&1 + reg query "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Communications" /v "ConfigureChatAutoInstall" >$null 2>&1 + # Write-Host Error code $LASTEXITCODE + Write-Host "Done disabling Teams" + + Write-Host "Bypassing system requirements (system image)" + reg add "HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache" /v "SV1" /t REG_DWORD /d 0 /f + reg add "HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache" /v "SV2" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache" /v "SV1" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache" /v "SV2" /t REG_DWORD /d 0 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassCPUCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassRAMCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassSecureBootCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassStorageCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassTPMCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\MoSetup" /v "AllowUpgradesWithUnsupportedTPMOrCPU" /t REG_DWORD /d 1 /f + + if (!$keepEdge) + { + Write-Host "Removing Edge icon from taskbar" + reg delete "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Taskband" /v "Favorites" /f >$null 2>&1 + reg delete "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Taskband" /v "FavoritesChanges" /f >$null 2>&1 + reg delete "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Taskband" /v "Pinned" /f >$null 2>&1 + reg delete "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Taskband" /v "LayoutCycle" /f >$null 2>&1 + Write-Host "Edge icon removed from taskbar" + } + + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Search" /v "SearchboxTaskbarMode" /t REG_DWORD /d 0 /f + Write-Host "Setting all services to start manually" + reg add "HKLM\zSOFTWARE\CurrentControlSet\Services" /v Start /t REG_DWORD /d 3 /f + # Write-Host $LASTEXITCODE + + Write-Host "Enabling Local Accounts on OOBE" + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" /v "BypassNRO" /t REG_DWORD /d "1" /f + + Write-Host "Disabling Sponsored Apps" + reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "OemPreInstalledAppsEnabled" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEnabled" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SilentInstalledAppsEnabled" /t REG_DWORD /d 0 /f + reg add "HKLM\zSOFTWARE\Policies\Microsoft\Windows\CloudContent" /v "DisableWindowsConsumerFeatures" /t REG_DWORD /d 1 /f + reg add "HKLM\zSOFTWARE\Microsoft\PolicyManager\current\device\Start" /v "ConfigureStartPins" /t REG_SZ /d '{\"pinnedList\": [{}]}' /f + Write-Host "Done removing Sponsored Apps" + + Write-Host "Disabling Reserved Storage" + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\ReserveManager" /v "ShippedWithReserves" /t REG_DWORD /d 0 /f + + Write-Host "Changing theme to dark. This only works on Activated Windows" + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v "AppsUseLightTheme" /t REG_DWORD /d 0 /f + reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" /v "SystemUsesLightTheme" /t REG_DWORD /d 0 /f + + } catch { + Write-Error "An unexpected error occurred: $_" + } finally { + Write-Host "Unmounting Registry..." + reg unload HKLM\zCOMPONENTS + reg unload HKLM\zDEFAULT + reg unload HKLM\zNTUSER + reg unload HKLM\zSOFTWARE + reg unload HKLM\zSYSTEM + + Write-Host "Cleaning up image..." + dism /image:$scratchDir /Cleanup-Image /StartComponentCleanup /ResetBase + Write-Host "Cleanup complete." + + Write-Host "Unmounting image..." + dism /unmount-image /mountdir:$scratchDir /commit + } + + 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 + 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" + + if (-not (Test-Path -Path "$mountDir\sources\install.wim")) + { + Write-Error "Somethig went wrong and '$mountDir\sources\install.wim' doesn't exist. Please report this bug to the devs" + return + } + Write-Host "Windows image completed. Continuing with boot.wim." + + # 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" + + Write-Host "Loading registry..." + reg load HKLM\zCOMPONENTS "$($scratchDir)\Windows\System32\config\COMPONENTS" >$null + reg load HKLM\zDEFAULT "$($scratchDir)\Windows\System32\config\default" >$null + reg load HKLM\zNTUSER "$($scratchDir)\Users\Default\ntuser.dat" >$null + reg load HKLM\zSOFTWARE "$($scratchDir)\Windows\System32\config\SOFTWARE" >$null + reg load HKLM\zSYSTEM "$($scratchDir)\Windows\System32\config\SYSTEM" >$null + Write-Host "Bypassing system requirements on the setup image" + reg add "HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache" /v "SV1" /t REG_DWORD /d 0 /f + reg add "HKLM\zDEFAULT\Control Panel\UnsupportedHardwareNotificationCache" /v "SV2" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache" /v "SV1" /t REG_DWORD /d 0 /f + reg add "HKLM\zNTUSER\Control Panel\UnsupportedHardwareNotificationCache" /v "SV2" /t REG_DWORD /d 0 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassCPUCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassRAMCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassSecureBootCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassStorageCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassTPMCheck" /t REG_DWORD /d 1 /f + reg add "HKLM\zSYSTEM\Setup\MoSetup" /v "AllowUpgradesWithUnsupportedTPMOrCPU" /t REG_DWORD /d 1 /f + # Fix Computer Restarted Unexpectedly Error on New Bare Metal Install + reg add "HKLM\zSYSTEM\Setup\Status\ChildCompletion" /v "setup.exe" /t REG_DWORD /d 3 /f + } catch { + Write-Error "An unexpected error occurred: $_" + } finally { + Write-Host "Unmounting Registry..." + reg unload HKLM\zCOMPONENTS + reg unload HKLM\zDEFAULT + reg unload HKLM\zNTUSER + reg unload HKLM\zSOFTWARE + reg unload HKLM\zSYSTEM + + Write-Host "Unmounting image..." + dism /unmount-image /mountdir:$scratchDir /commit + + Write-Host "Creating ISO image" + #& oscdimg.exe -m -o -u2 -udfver102 -bootdata:2#p0,e,b$mountDir\boot\etfsboot.com#pEF,e,b$mountDir\efi\microsoft\boot\efisys.bin $mountDir $env:temp\microwin.iso + Start-Process -FilePath "oscdimg.exe" -ArgumentList "-m -o -u2 -udfver102 -bootdata:2#p0,e,b$mountDir\boot\etfsboot.com#pEF,e,b$mountDir\efi\microsoft\boot\efisys.bin $mountDir $env:temp\microwin.iso" -NoNewWindow -Wait + + if ($copyToUSB) + { + Write-Host "Copying microwin.iso to the USB drive" + Copy-ToUSB("$env:temp\microwin.iso") + Write-Host "Done Copying microwin.iso to USB drive!" + } + + Write-Host " _____ " + Write-Host "(____ \ " + Write-Host " _ \ \ ___ ____ ____ " + Write-Host "| | | / _ \| _ \ / _ ) " + Write-Host "| |__/ / |_| | | | ( (/ / " + Write-Host "|_____/ \___/|_| |_|\____) " + + # Check if the ISO was successfully created - CTT edit + if ($LASTEXITCODE -eq 0) { + Write-Host "Done. ISO image is located here: $env:temp\microwin.iso" + Write-Host "Performing Cleanup" + Remove-Item -Recurse -Force "$($scratchDir)" + Remove-Item -Recurse -Force "$($mountDir)" + } else { + Write-Host "ISO creation failed. The "$($mountDir)" directory has not been removed." + } + + + $sync.MicrowinOptionsPanel.Visibility = 'Collapsed' + + $sync.MicrowinFinalIsoLocation.Text = "$env:temp\microwin.iso" + + $sync.ProcessRunning = $false + } +} function Invoke-WPFPanelAutologin { <# @@ -1842,17 +2985,21 @@ function Invoke-WPFTab { #> Param ($ClickedTab) - $Tabs = Get-WinUtilVariables | Where-Object {$psitem -like "WPFTab?BT"} - $TabNav = Get-WinUtilVariables | Where-Object {$psitem -like "WPFTabNav"} - $x = [int]($ClickedTab -replace "WPFTab","" -replace "BT","") - 1 - 0..($Tabs.Count -1 ) | ForEach-Object { + $tabNav = Get-WinUtilVariables | Where-Object {$psitem -like "WPFTabNav"} + $tabNumber = [int]($ClickedTab -replace "WPFTab","" -replace "BT","") - 1 - if ($x -eq $psitem){ - $sync.$TabNav.Items[$psitem].IsSelected = $true + $filter = Get-WinUtilVariables -Type ToggleButton | Where-Object {$psitem -like "WPFTab?BT"} + $sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} | ForEach-Object { + if ($ClickedTab -ne $PSItem.name) { + $sync[$PSItem.Name].IsChecked = $false + # $tabNumber = [int]($PSItem.Name -replace "WPFTab","" -replace "BT","") - 1 + # $sync.$tabNav.Items[$tabNumber].IsSelected = $false } - else{ - $sync.$TabNav.Items[$psitem].IsSelected = $false + else { + $sync["$ClickedTab"].IsChecked = $true + $tabNumber = [int]($ClickedTab-replace "WPFTab","" -replace "BT","") - 1 + $sync.$tabNav.Items[$tabNumber].IsSelected = $true } } } @@ -2408,6 +3555,86 @@ $inputXML = ' + + + + + + + + + + - - - - - + @@ -2714,18 +3994,54 @@ $inputXML = ' - + + + + Chose Windows SKU + + Choose Windows features you want to remove from the ISO + + + + + + + + + + + + + + + Chose Windows SKU + + Choose Windows features you want to remove from the ISO + + + + + + + + + + +