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 + + + + + + + + + + +