diff --git a/config/tweaks.json b/config/tweaks.json index 794d6c3651..e9b8ca3798 100644 --- a/config/tweaks.json +++ b/config/tweaks.json @@ -2166,7 +2166,7 @@ " #:: Standalone script by AveYo Source: https://raw.githubusercontent.com/AveYo/fox/main/Edge_Removal.bat - curl.exe -s \"https://raw.githubusercontent.com/AveYo/fox/main/Edge_Removal.bat\" -o $ENV:temp\\edgeremoval.bat + curl.exe -s \"https://raw.githubusercontent.com/ChrisTitusTech/winutil/main/edgeremoval.bat\" -o $ENV:temp\\edgeremoval.bat Start-Process $ENV:temp\\edgeremoval.bat " diff --git a/edgeremoval.bat b/edgeremoval.bat new file mode 100644 index 0000000000..b950e873c8 --- /dev/null +++ b/edgeremoval.bat @@ -0,0 +1,236 @@ +@(set "0=%~f0"^)#) & powershell -nop -c iex([io.file]::ReadAllText($env:0)) & exit /b +#:: made by AveYo source: https://raw.githubusercontent.com/AveYo/fox/main/Edge_Removal.bat +sp 'HKCU:\Volatile Environment' 'Edge_Removal' @' + +$also_remove_webview = 0 + +$host.ui.RawUI.WindowTitle = 'Edge Removal - AveYo, 2023.09.09' +$remove_win32 = @("Microsoft Edge","Microsoft Edge Update"); $remove_appx = @("MicrosoftEdge"); $skip = @() # @("DevTools") +if ($also_remove_webview -eq 1) {$remove_win32 += "Microsoft EdgeWebView"; $remove_appx += "WebExperience","Win32WebViewHost"} + +## 1 bonus! enter into powershell console: firefox / edge / webview to install a browser / reinstall edge or webview after removal +function global:firefox { $url = 'https://download.mozilla.org/?product=firefox-stub' + $setup = "$((new-object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path)\Firefox Installer.exe" + write-host $url; Invoke-WebRequest $url -OutFile $setup; start $setup +} +function global:edge { $url = 'https://go.microsoft.com/fwlink/?linkid=2108834&Channel=Stable&language=en' + $setup = "$((new-object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path)\MicrosoftEdgeSetup.exe" + write-host $url; Invoke-WebRequest $url -OutFile $setup; prepare_edge; start $setup +} +function global:webview { $url = 'https://go.microsoft.com/fwlink/p/?LinkId=2124703' + $setup = "$((new-object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path)\MicrosoftEdgeWebview2Setup.exe" + write-host $url; Invoke-WebRequest $url -OutFile $setup; prepare_webview; start $setup +} +## helper for set-itemproperty remove-itemproperty new-item remove-item with auto test-path +function global:sp_test_path { if (test-path $args[0]) {Microsoft.PowerShell.Management\Set-ItemProperty @args} else { + Microsoft.PowerShell.Management\New-Item $args[0] -force -ea 0 >''; Microsoft.PowerShell.Management\Set-ItemProperty @args} } +function global:rp_test_path { if (test-path $args[0]) {Microsoft.PowerShell.Management\Remove-ItemProperty @args} } +function global:ni_test_path { if (-not (test-path $args[0])) {Microsoft.PowerShell.Management\New-Item @args} } +function global:ri_test_path { if (test-path $args[0]) {Microsoft.PowerShell.Management\Remove-Item @args} } +foreach ($f in 'sp','rp','ni','ri') {set-alias -Name $f -Value "${f}_test_path" -Scope Local -Option AllScope -force -ea 0} +## helper for edge reinstall - remove bundled OpenWebSearch redirector and edgeupdate policies +function global:prepare_edge { + foreach ($f in 'ni','ri','sp','rp') {set-alias -Name $f -Value "${f}_test_path" -Scope Local -Option AllScope -force -ea 0} + $MS=($env:ProgramFiles,${env:ProgramFiles(x86)})[[Environment]::Is64BitOperatingSystem]+'\Microsoft\Edge\Application\msedge.exe' + ri "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\msedge.exe" -recurse -force -ea 0 + ri "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ie_to_edge_stub.exe" -recurse -force -ea 0 + ri 'Registry::HKEY_Users\S-1-5-21*\Software\Classes\microsoft-edge' -recurse -force -ea 0 + ri 'Registry::HKEY_Users\S-1-5-21*\Software\Classes\MSEdgeHTM' -recurse -force -ea 0 + ni "HKLM:\SOFTWARE\Classes\microsoft-edge\shell\open\command" -force -ea 0 >'' + sp "HKLM:\SOFTWARE\Classes\microsoft-edge\shell\open\command" '(Default)' "`"$MS`" --single-argument %%1" -force -ea 0 + ni "HKLM:\SOFTWARE\Classes\MSEdgeHTM\shell\open\command" -force -ea 0 >'' + sp "HKLM:\SOFTWARE\Classes\MSEdgeHTM\shell\open\command" '(Default)' "`"$MS`" --single-argument %%1" -force -ea 0 + foreach ($p in 'HKLM:\SOFTWARE\Policies','HKLM:\SOFTWARE','HKLM:\SOFTWARE\WOW6432Node') { + rp "$p\Microsoft\EdgeUpdate" 'InstallDefault' -force -ea 0 + rp "$p\Microsoft\EdgeUpdate" 'Install{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}' -force -ea 0 + rp "$p\Microsoft\EdgeUpdate" 'Install{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' -force -ea 0 + } + $edgeupdate='Microsoft\EdgeUpdate\Clients\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}' + $webvupdate='Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' + $on_actions='on-os-upgrade','on-logon','on-logon-autolaunch','on-logon-startup-boost' + foreach ($p in 'HKLM:\SOFTWARE','HKLM:\SOFTWARE\Wow6432Node') { foreach ($launch in $on_actions) { + ri "$p\$edgeupdate\Commands\$launch" -force -ea 0; ri "$p\$webvupdate\Commands\$launch" -force -ea 0 + }} +} +## helper for webview reinstall - restore webexperience (widgets) if available +function global:prepare_webview { + $cfg = @{Register=$true; ForceApplicationShutdown=$true; ForceUpdateFromAnyVersion=$true; DisableDevelopmentMode=$true} + dir "$env:ProgramFiles\WindowsApps\MicrosoftWindows.Client.WebExperience*\AppxManifest.xml" -rec -ea 0 | Add-AppxPackage @cfg + dir "$env:SystemRoot\SystemApps\Microsoft.Win32WebViewHost*\AppxManifest.xml" -rec -ea 0 | Add-AppxPackage @cfg + kill -name explorer -ea 0; if ((get-process -name 'explorer' -ea 0) -eq $null) {start explorer} +} + +## 2 enable admin privileges +$D1=[uri].module.gettype('System.Diagnostics.Process')."GetM`ethods"(42) |where {$_.Name -eq 'SetPrivilege'} #`:no-ev-warn +'SeSecurityPrivilege','SeTakeOwnershipPrivilege','SeBackupPrivilege','SeRestorePrivilege'|foreach {$D1.Invoke($null, @("$_",2))} + +## 3 shut edge & webview clone stuff down and gather install paths +$shut = 'explorer','Widgets','widgetservice','msedgewebview2','MicrosoftEdge*','chredge','msedge','edge' +$shut+= 'msteams','msfamily','WebViewHost','Clipchamp' +cd $env:systemdrive; taskkill /im explorer.exe /f 2>&1 >''; foreach ($p in $shut) {kill -name $p -force -ea 0} +prepare_edge +## clear win32 uninstall block +foreach ($hk in 'HKCU:','HKLM:') { foreach ($wow in '','\Wow6432Node') { foreach ($i in $remove_win32) { + rp "$hk\SOFTWARE${wow}\Microsoft\Windows\CurrentVersion\Uninstall\$i" 'NoRemove' -force -ea 0 + ni "$hk\SOFTWARE${wow}\Microsoft\EdgeUpdateDev" -force >'' + sp "$hk\SOFTWARE${wow}\Microsoft\EdgeUpdateDev" 'AllowUninstall' 1 -type Dword -force +}}} +## find all Edge setup.exe and gather BHO paths for OpenWebSearch / MSEdgeRedirect usage +$edges = @(); $bho = @(); 'LocalApplicationData','ProgramFilesX86','ProgramFiles' |foreach { + $folder = [Environment]::GetFolderPath($_); $bho += dir "$folder\Microsoft\Edge*\ie_to_edge_stub.exe" -rec -ea 0 + if ($also_remove_webview -eq 1) {$edges += dir "$folder\Microsoft\Edge*\setup.exe" -rec -ea 0 |where {$_ -like '*EdgeWebView*'}} + $edges += dir "$folder\Microsoft\Edge*\setup.exe" -rec -ea 0 |where {$_ -notlike '*EdgeWebView*'} +} +## use dedicated C:\Scripts path to save OpenWebSearch (due to Sigma rules FUD) +$DIR = "$env:SystemDrive\Scripts"; mkdir $DIR -ea 0 >'' +## export OpenWebSearch innovative redirector - used by MSEdgeRedirect as well +foreach ($b in $bho) { if (test-path $b) { try {copy $b "$DIR\ie_to_edge_stub.exe" -force -ea 0} catch{} } } + +## 4 remove found *Edge* appx packages with unblock tricks +$provisioned = get-appxprovisionedpackage -online; $appxpackage = get-appxpackage -allusers; $eol = @() +$store = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore' +$users = @('S-1-5-18'); if (test-path $store) {$users += $((dir $store -ea 0 |where {$_ -like '*S-1-5-21*'}).PSChildName)} +foreach ($choice in $remove_appx) { if ('' -eq $choice.Trim()) {continue} + foreach ($appx in $($provisioned |where {$_.PackageName -like "*$choice*"})) { + $next = !1; foreach ($no in $skip) {if ($appx.PackageName -like "*$no*") {$next = !0}} ; if ($next) {continue} + $PackageName = $appx.PackageName; $PackageFamilyName = ($appxpackage |where {$_.Name -eq $appx.DisplayName}).PackageFamilyName + ni "$store\Deprovisioned\$PackageFamilyName" -force >''; $PackageFamilyName + foreach ($sid in $users) {ni "$store\EndOfLife\$sid\$PackageName" -force >''} ; $eol += $PackageName + dism /online /set-nonremovableapppolicy /packagefamily:$PackageFamilyName /nonremovable:0 >'' + remove-appxprovisionedpackage -packagename $PackageName -online -allusers >'' + } + foreach ($appx in $($appxpackage |where {$_.PackageFullName -like "*$choice*"})) { + $next = !1; foreach ($no in $skip) {if ($appx.PackageFullName -like "*$no*") {$next = !0}} ; if ($next) {continue} + $PackageFullName = $appx.PackageFullName; + ni "$store\Deprovisioned\$appx.PackageFamilyName" -force >''; $PackageFullName + foreach ($sid in $users) {ni "$store\EndOfLife\$sid\$PackageFullName" -force >''} ; $eol += $PackageFullName + dism /online /set-nonremovableapppolicy /packagefamily:$PackageFamilyName /nonremovable:0 >'' + remove-appxpackage -package $PackageFullName -allusers >'' + } +} + +## 5 run found *Edge* setup.exe with uninstall args and wait in-between +foreach ($setup in $edges) { if (test-path $setup) { + if ($setup -like '*EdgeWebView*') {$target = "--msedgewebview"} else {$target = "--msedge"} + $removal = "--uninstall $target --system-level --verbose-logging --force-uninstall" + try {write-host $setup $removal; start -wait $setup -args $removal} catch {} + do {sleep 3} while ((get-process -name 'setup','MicrosoftEdge*' -ea 0).Path -like '*\Microsoft\Edge*') +}} + +## 6 extra cleanup +foreach ($PF in $env:ProgramFiles,${env:ProgramFiles(x86)}) { if (test-path "$PF\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe") { + write-host "$PF\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe /uninstall" + start -wait "$PF\Microsoft\EdgeUpdate\MicrosoftEdgeUpdate.exe" -args '/uninstall' + do {sleep 3} while ((get-process -name 'setup','MicrosoftEdge*' -ea 0).Path -like '*\Microsoft\Edge*') + if ($also_remove_webview -eq 1) { foreach ($hk in 'HKCU:','HKLM:') { foreach ($wow in '','\Wow6432Node') { + ri "$hk\SOFTWARE${wow}\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft Edge Update" -rec -force -ea 0 }} + ri "$PF\Microsoft\EdgeUpdate" -rec -force -ea 0; Unregister-ScheduledTask -TaskName MicrosoftEdgeUpdate* -Confirm:$false -ea 0 + } +}} +$appdata = $([Environment]::GetFolderPath('ApplicationData')) +ri "$appdata\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Tombstones\Microsoft Edge.lnk" -force +ri "$appdata\Microsoft\Internet Explorer\Quick Launch\Microsoft Edge.lnk" -force + +## undo eol unblock trick to prevent latest cumulative update (LCU) failing +foreach ($sid in $users) { foreach ($PackageName in $eol) {ri "$store\EndOfLife\$sid\$PackageName" -force >''} } + +## set (almost) useless policies to prevent unsolicited reinstalls +foreach ($p in 'HKLM:\SOFTWARE\Policies','HKLM:\SOFTWARE','HKLM:\SOFTWARE\WOW6432Node') { + ni "$p\Microsoft\EdgeUpdate" -force >'' + sp "$p\Microsoft\EdgeUpdate" 'InstallDefault' 0 -type Dword -force + sp "$p\Microsoft\EdgeUpdate" 'Install{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}' 0 -type Dword -force + sp "$p\Microsoft\EdgeUpdate" 'Install{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' 1 -type Dword -force + sp "$p\Microsoft\EdgeUpdate" 'DoNotUpdateToEdgeWithChromium' 1 -type Dword -force +} +$edgeupdate='Microsoft\EdgeUpdate\Clients\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}' +$webvupdate='Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}' +$on_actions='on-os-upgrade','on-logon','on-logon-autolaunch','on-logon-startup-boost' +foreach ($p in 'HKLM:\SOFTWARE','HKLM:\SOFTWARE\Wow6432Node') { foreach ($launch in $on_actions) { + ni "$p\$edgeupdate\Commands\$launch" -force >''; sp "$p\$edgeupdate\Commands\$launch" 'CommandLine' 'systray.exe' -force + ni "$p\$webvupdate\Commands\$launch" -force >''; sp "$p\$webvupdate\Commands\$launch" 'CommandLine' 'systray.exe' -force +}} + +## 7 add bundled OpenWebSearch script to redirect microsoft-edge: anti-competitive links to the default browser +$MSEP = ($env:ProgramFiles,${env:ProgramFiles(x86)})[[Environment]::Is64BitOperatingSystem] + '\Microsoft\Edge\Application' +$IFEO = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options' +$MIN = ('--headless','--width 1 --height 1')[([environment]::OSVersion.Version.Build) -gt 25179] +$CMD = "$env:systemroot\system32\conhost.exe $MIN" # AveYo: minimize prompt - see Terminal issue #13914 +ni "HKLM:\SOFTWARE\Classes\microsoft-edge\shell\open\command" -force >'' +sp "HKLM:\SOFTWARE\Classes\microsoft-edge" '(Default)' 'URL:microsoft-edge' -force +sp "HKLM:\SOFTWARE\Classes\microsoft-edge" 'URL Protocol' '' -force +sp "HKLM:\SOFTWARE\Classes\microsoft-edge" 'NoOpenWith' '' -force +sp "HKLM:\SOFTWARE\Classes\microsoft-edge\shell\open\command" '(Default)' "`"$DIR\ie_to_edge_stub.exe`" %1" -force +ni "HKLM:\SOFTWARE\Classes\MSEdgeHTM\shell\open\command" -force >'' +sp "HKLM:\SOFTWARE\Classes\MSEdgeHTM" 'NoOpenWith' '' -force +sp "HKLM:\SOFTWARE\Classes\MSEdgeHTM\shell\open\command" '(Default)' "`"$DIR\ie_to_edge_stub.exe`" %1" -force +ni "$IFEO\ie_to_edge_stub.exe\0" -force >'' +sp "$IFEO\ie_to_edge_stub.exe" 'UseFilter' 1 -type Dword -force +sp "$IFEO\ie_to_edge_stub.exe\0" 'FilterFullPath' "$DIR\ie_to_edge_stub.exe" -force +sp "$IFEO\ie_to_edge_stub.exe\0" 'Debugger' "$CMD $DIR\OpenWebSearch.cmd" -force +ni "$IFEO\msedge.exe\0" -force >'' +sp "$IFEO\msedge.exe" 'UseFilter' 1 -type Dword -force +sp "$IFEO\msedge.exe\0" 'FilterFullPath' "$MSEP\msedge.exe" -force +sp "$IFEO\msedge.exe\0" 'Debugger' "$CMD $DIR\OpenWebSearch.cmd" -force + +$OpenWebSearch = @$ +@title OpenWebSearch Redux & echo off & set ?= open start menu web search, widgets links or help in your chosen browser - by AveYo +for /f %%E in ('"prompt $E$S& for %%e in (1) do rem"') do echo;%%E[2t 2>nul & rem AveYo: minimize prompt +call :reg_var "HKCU\SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice" ProgID ProgID +if /i "%ProgID%" equ "MSEdgeHTM" echo;Default browser is set to Edge! Change it or remove OpenWebSearch script. & pause & exit /b +call :reg_var "HKCR\%ProgID%\shell\open\command" "" Browser +set Choice=& for %%. in (%Browser%) do if not defined Choice set "Choice=%%~." +call :reg_var "HKCR\MSEdgeMHT\shell\open\command" "" FallBack +set "Edge=" & for %%. in (%FallBack%) do if not defined Edge set "Edge=%%~." +set "URI=" & set "URL=" & set "NOOP=" & set "PassTrough=%Edge:msedge=edge%" +set "CLI=%CMDCMDLINE:"=``% " +if defined CLI set "CLI=%CLI:*ie_to_edge_stub.exe`` =%" +if defined CLI set "CLI=%CLI:*ie_to_edge_stub.exe =%" +if defined CLI set "CLI=%CLI:*msedge.exe`` =%" +if defined CLI set "CLI=%CLI:*msedge.exe =%" +set "FIX=%CLI:~-1%" +if defined CLI if "%FIX%"==" " set "CLI=%CLI:~0,-1%" +if defined CLI set "RED=%CLI:microsoft-edge=%" +if defined CLI set "URL=%CLI:http=%" +if defined CLI set "ARG=%CLI:``="%" +if "%CLI%" equ "%RED%" (set NOOP=1) else if "%CLI%" equ "%URL%" (set NOOP=1) +if defined NOOP if exist "%PassTrough%" start "" "%PassTrough%" %ARG% +if defined NOOP exit /b +set "URL=%CLI:*microsoft-edge=%" +set "URL=http%URL:*http=%" +set "FIX=%URL:~-2%" +if defined URL if "%FIX%"=="``" set "URL=%URL:~0,-2%" +call :dec_url +start "" "%Choice%" "%URL%" +exit + +:reg_var [USAGE] call :reg_var "HKCU\Volatile Environment" value-or-"" variable [extra options] +set {var}=& set {reg}=reg query "%~1" /v %2 /z /se "," /f /e& if %2=="" set {reg}=reg query "%~1" /ve /z /se "," /f /e +for /f "skip=2 tokens=* delims=" %%V in ('%{reg}% %4 %5 %6 %7 %8 %9 2^>nul') do if not defined {var} set "{var}=%%V" +if not defined {var} (set {reg}=& set "%~3="& exit /b) else if %2=="" set "{var}=%{var}:*) =%"& rem AveYo: v3 +if not defined {var} (set {reg}=& set "%~3="& exit /b) else set {reg}=& set "%~3=%{var}:*) =%"& set {var}=& exit /b + +:dec_url brute url percent decoding by AveYo +set ".=%URL:!=}%"&setlocal enabledelayedexpansion& rem brute url percent decoding +set ".=!.:%%={!" &set ".=!.:{3A=:!" &set ".=!.:{2F=/!" &set ".=!.:{3F=?!" &set ".=!.:{23=#!" &set ".=!.:{5B=[!" &set ".=!.:{5D=]!" +set ".=!.:{40=@!"&set ".=!.:{21=}!" &set ".=!.:{24=$!" &set ".=!.:{26=&!" &set ".=!.:{27='!" &set ".=!.:{28=(!" &set ".=!.:{29=)!" +set ".=!.:{2A=*!"&set ".=!.:{2B=+!" &set ".=!.:{2C=,!" &set ".=!.:{3B=;!" &set ".=!.:{3D==!" &set ".=!.:{25=%%!"&set ".=!.:{20= !" +set ".=!.:{=%%!" &rem set ",=!.:%%=!" & if "!,!" neq "!.!" endlocal& set "URL=%.:}=!%" & call :dec_url +endlocal& set "URL=%.:}=!%" & exit /b +rem done + +$@ +[io.file]::WriteAllText("$DIR\OpenWebSearch.cmd", $OpenWebSearch) + +## 8 done +$done = gp 'Registry::HKEY_Users\S-1-5-21*\Volatile*' Edge_Removal -ea 0; if ($done) {rp $done.PSPath Edge_Removal -force -ea 0} +if ((get-process -name 'explorer' -ea 0) -eq $null) {start explorer} + +## 9 bonus enter into powershell console: firefox / edge / webview to install a browser / reinstall edge or webview after removal +${.} = [char]27; $firefox = "${.}[38;2;255;165;0m firefox"; $edge = "${.}[94m edge${.}[97m"; $webview = "${.}[94mwebview ${.}[97m" +write-host "`n${.}[40;32m EDGE REMOVED! ${.}[97m -GET-ANOTHER-BROWSER? ENTER:$firefox ${.}[97m -REINSTALL? ENTER:$edge / $webview" + +## 0 ask to run script as admin +'@.replace("$@","'@").replace("@$","@'") -force -ea 0; $code='gp ''Registry::HKEY_Users\S-1-5-21*\Volatile*'' Edge_Removal -ea 0' +start powershell -args "-nop -noe -c & {iex(($code)[0].Edge_Removal)}" -verb runas +$_Press_Enter +#:: diff --git a/winutil.ps1 b/winutil.ps1 index 2d92c3279b..e1c941e1e0 100755 --- a/winutil.ps1 +++ b/winutil.ps1 @@ -10,18 +10,18 @@ Author : Chris Titus @christitustech Runspace Author: @DeveloperDurp GitHub : https://github.com/ChrisTitusTech - Version : 23.09.23 + Version : 23.10.05 #> Start-Transcript $ENV:TEMP\Winutil.log -Append -#Load DLLs +# Load DLLs Add-Type -AssemblyName System.Windows.Forms -# variable to sync between runspaces +# Variable to sync between runspaces $sync = [Hashtable]::Synchronized(@{}) $sync.PSScriptRoot = $PSScriptRoot -$sync.version = "23.09.23" +$sync.version = "23.10.05" $sync.configs = @{} $sync.ProcessRunning = $false @@ -35,13 +35,19 @@ Function Get-WinUtilCheckBoxes { <# - .DESCRIPTION - Function is meant to find all checkboxes that are checked on the specific tab and input them into a script. + .SYNOPSIS + Finds all checkboxes that are checked on the specific tab and inputs them into a script. - Outputed data will be the names of the checkboxes that were checked + .PARAMETER Group + The group of checkboxes to check - .EXAMPLE + .PARAMETER unCheck + Whether to uncheck the checkboxes that are checked. Defaults to true + .OUTPUTS + A List containing the name of each checked checkbox + + .EXAMPLE Get-WinUtilCheckBoxes "WPFInstall" #> @@ -65,18 +71,18 @@ Function Get-WinUtilCheckBoxes { if ($uncheck -eq $true){ $CheckBox.value.ischecked = $false } - + } } } - + if($Group -eq "WPFTweaks"){ $filter = Get-WinUtilVariables -Type Checkbox | Where-Object {$psitem -like "WPF*Tweaks*"} $CheckBoxes = $sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} Foreach ($CheckBox in $CheckBoxes){ if($CheckBox.value.ischecked -eq $true){ $Output.Add($Checkbox.Name) - + if ($uncheck -eq $true){ $CheckBox.value.ischecked = $false } @@ -90,7 +96,7 @@ Function Get-WinUtilCheckBoxes { Foreach ($CheckBox in $CheckBoxes){ if($CheckBox.value.ischecked -eq $true){ $Output.Add($Checkbox.Name) - + if ($uncheck -eq $true){ $CheckBox.value.ischecked = $false } @@ -102,10 +108,16 @@ Function Get-WinUtilCheckBoxes { } function Get-WinUtilInstallerProcess { <# - - .DESCRIPTION - Meant to check for running processes and will return a boolean response - + + .SYNOPSIS + Checks if the given process is running + + .PARAMETER Process + The process to check + + .OUTPUTS + Boolean - True if the process is running + #> param($Process) @@ -120,15 +132,14 @@ function Get-WinUtilInstallerProcess { } function Get-WinUtilRegistry { <# - - .DESCRIPTION - This function will make all modifications to the registry - .EXAMPLE + .SYNOPSIS + Gets the value of a registry key - Set-WinUtilRegistry -Name "PublishUserActivities" -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Type "DWord" -Value "0" - - #> + .EXAMPLE + Get-WinUtilRegistry -Name "PublishUserActivities" -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Type "DWord" -Value "0" + + #> param ( $Name, $Path, @@ -136,7 +147,7 @@ function Get-WinUtilRegistry { $Value ) - Try{ + Try{ $syscheckvalue = Get-ItemPropertyValue -Path $Path -Value $Value # Return Value } @@ -153,13 +164,16 @@ function Get-WinUtilRegistry { } Function Get-WinUtilToggleStatus { <# - - .DESCRIPTION - Meant to pull the registry keys for a toggle switch and returns true or false - True should mean status is enabled - False should mean status is disabled - + .SYNOPSIS + Pulls the registry keys for the given toggle switch and checks whether the toggle should be checked or unchecked + + .PARAMETER ToggleSwitch + The name of the toggle to check + + .OUTPUTS + Boolean to set the toggle's status to + #> Param($ToggleSwitch) @@ -168,7 +182,7 @@ Function Get-WinUtilToggleStatus { $system = (Get-ItemProperty -path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize').SystemUsesLightTheme if($app -eq 0 -and $system -eq 0){ return $true - } + } else{ return $false } @@ -177,7 +191,7 @@ Function Get-WinUtilToggleStatus { $bingsearch = (Get-ItemProperty -path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Search').BingSearchEnabled if($bingsearch -eq 0){ return $false - } + } else{ return $true } @@ -186,10 +200,13 @@ Function Get-WinUtilToggleStatus { function Get-WinUtilVariables { <# - - .DESCRIPTION - placeholder - + + .SYNOPSIS + Gets every form object of the provided type + + .OUTPUTS + List containing every object that matches the provided type + #> param ( [Parameter()] @@ -197,7 +214,7 @@ function Get-WinUtilVariables { [string]$Type ) - $keys = $sync.keys | Where-Object {$psitem -like "WPF*"} + $keys = $sync.keys | Where-Object {$psitem -like "WPF*"} if($type){ $output = $keys | ForEach-Object { @@ -208,17 +225,17 @@ function Get-WinUtilVariables { } Catch{<#I am here so errors don't get outputted for a couple variables that don't have the .GetType() attribute#>} } - return $output + return $output } return $keys } function Install-WinUtilChoco { <# - - .DESCRIPTION - Function is meant to ensure Choco is installed - + + .SYNOPSIS + Installs Chocolatey if it is not already installed + #> try{ @@ -228,9 +245,9 @@ function Install-WinUtilChoco { Write-Host "Chocolatey Already Installed" return } - + Write-Host "Seems Chocolatey is not installed, installing now?" - #Let user decide if he wants to install Chocolatey + # Let user decide if they want to install Chocolatey $confirmation = Read-Host "Are you Sure You Want To Proceed:(y/n)" if ($confirmation -eq 'y') { Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) -ErrorAction Stop @@ -245,12 +262,19 @@ function Install-WinUtilChoco { Function Install-WinUtilProgramWinget { <# - - .DESCRIPTION - This will install programs via Winget using a new powershell.exe instance to prevent the GUI from locking up. - Note the triple quotes are required any time you need a " in a normal script block. - + .SYNOPSIS + Manages the provided programs using Winget + + .PARAMETER ProgramsToInstall + A list of programs to manage + + .PARAMETER manage + The action to perform on the programs, can be either 'Installing' or 'Uninstalling' + + .NOTES + The triple quotes are required any time you need a " in a normal script block. + #> param( @@ -264,7 +288,7 @@ Function Install-WinUtilProgramWinget { Write-Progress -Activity "$manage Applications" -Status "Starting" -PercentComplete 0 Foreach ($Program in $($ProgramsToInstall -split ",")){ - + Write-Progress -Activity "$manage Applications" -Status "$manage $Program $($x + 1) of $count" -PercentComplete $($x/$count*100) if($manage -eq "Installing"){ Start-Process -FilePath winget -ArgumentList "install -e --accept-source-agreements --accept-package-agreements --silent $Program" -NoNewWindow -Wait @@ -272,7 +296,7 @@ Function Install-WinUtilProgramWinget { if($manage -eq "Uninstalling"){ Start-Process -FilePath winget -ArgumentList "uninstall -e --purge --force --silent $Program" -NoNewWindow -Wait } - + $X++ } @@ -281,30 +305,30 @@ Function Install-WinUtilProgramWinget { } function Get-LatestHash { $shaUrl = ((Invoke-WebRequest $apiLatestUrl -UseBasicParsing | ConvertFrom-Json).assets | Where-Object { $_.name -match '^Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.txt$' }).browser_download_url - + $shaFile = Join-Path -Path $tempFolder -ChildPath 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.txt' $WebClient.DownloadFile($shaUrl, $shaFile) - + Get-Content $shaFile - } +} function Install-WinUtilWinget { - + <# - - .DESCRIPTION - Function is meant to ensure winget is installed - + + .SYNOPSIS + Installs Winget if it is not already installed + #> Try{ Write-Host "Checking if Winget is Installed..." if (Test-WinUtilPackageManager -winget) { - #Checks if winget executable exists and if the Windows Version is 1809 or higher + # Checks if winget executable exists and if the Windows Version is 1809 or higher Write-Host "Winget Already Installed" return } - #Gets the computer's information + # Gets the computer's information if ($null -eq $sync.ComputerInfo){ $ComputerInfo = Get-ComputerInfo -ErrorAction Stop } @@ -313,14 +337,14 @@ function Install-WinUtilWinget { } if (($ComputerInfo.WindowsVersion) -lt "1809") { - #Checks if Windows Version is too old for winget + # Checks if Windows Version is too old for winget Write-Host "Winget is not supported on this version of Windows (Pre-1809)" return } Write-Host "Running Alternative Installer and Direct Installing" Start-Process -Verb runas -FilePath powershell.exe -ArgumentList "irm https://raw.githubusercontent.com/ChrisTitusTech/winutil/main/winget.ps1 | iex" - + Write-Host "Winget Installed" } Catch{ @@ -328,11 +352,14 @@ function Install-WinUtilWinget { } } function Invoke-WinUtilBingSearch { - <# - - .DESCRIPTION - Sets Bing Search on or off - + <# + + .SYNOPSIS + Disables/Enables Bing Search + + .PARAMETER Enabled + Indicates whether to enable or disable Bing Search + #> Param($Enabled) Try{ @@ -362,13 +389,10 @@ Function Invoke-WinUtilCurrentSystem { <# - .DESCRIPTION - Function is meant to read existing system registry and check according configuration. - - Example: Is telemetry enabled? check the box. - - .EXAMPLE + .SYNOPSIS + Checks to see what tweaks have already been applied and what programs are installed, and checks the according boxes + .EXAMPLE Get-WinUtilCheckBoxes "WPFInstall" #> @@ -406,19 +430,19 @@ Function Invoke-WinUtilCurrentSystem { $registryKeys = $sync.configs.tweaks.$Config.registry $scheduledtaskKeys = $sync.configs.tweaks.$Config.scheduledtask $serviceKeys = $sync.configs.tweaks.$Config.service - + if($registryKeys -or $scheduledtaskKeys -or $serviceKeys){ $Values = @() Foreach ($tweaks in $registryKeys){ Foreach($tweak in $tweaks){ - + if(test-path $tweak.Path){ $actualValue = Get-ItemProperty -Name $tweak.Name -Path $tweak.Path -ErrorAction SilentlyContinue | Select-Object -ExpandProperty $($tweak.Name) $expectedValue = $tweak.Value if ($expectedValue -notlike $actualValue){ - $values += $False + $values += $False } } } @@ -427,7 +451,7 @@ Function Invoke-WinUtilCurrentSystem { Foreach ($tweaks in $scheduledtaskKeys){ Foreach($tweak in $tweaks){ $task = $ScheduledTasks | Where-Object {$($psitem.TaskPath + $psitem.TaskName) -like "\$($tweak.name)"} - + if($task){ $actualValue = $task.State $expectedValue = $tweak.State @@ -441,7 +465,7 @@ Function Invoke-WinUtilCurrentSystem { Foreach ($tweaks in $serviceKeys){ Foreach($tweak in $tweaks){ $Service = Get-Service -Name $tweak.Name - + if($Service){ $actualValue = $Service.StartType $expectedValue = $tweak.StartupType @@ -461,11 +485,14 @@ Function Invoke-WinUtilCurrentSystem { } Function Invoke-WinUtilDarkMode { - <# - - .DESCRIPTION - Sets Dark Mode on or off - + <# + + .SYNOPSIS + Enables/Disables Dark Mode + + .PARAMETER DarkMoveEnabled + Indicates the current dark mode state + #> Param($DarkMoveEnabled) Try{ @@ -477,7 +504,7 @@ Function Invoke-WinUtilDarkMode { Write-Host "Disabling Dark Mode" $DarkMoveValue = 1 } - + $Theme = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" Set-ItemProperty -Path $Theme -Name AppsUseLightTheme -Value $DarkMoveValue Set-ItemProperty -Path $Theme -Name SystemUsesLightTheme -Value $DarkMoveValue @@ -495,10 +522,10 @@ Function Invoke-WinUtilDarkMode { } function Invoke-WinUtilFeatureInstall { <# - - .DESCRIPTION - This function converts all the values from the tweaks.json and routes them to the appropriate function - + + .SYNOPSIS + Converts all the values from the tweaks.json and routes them to the appropriate function + #> param( @@ -508,7 +535,7 @@ function Invoke-WinUtilFeatureInstall { $CheckBox | ForEach-Object { if($sync.configs.feature.$psitem.feature){ Foreach( $feature in $sync.configs.feature.$psitem.feature ){ - Try{ + Try{ Write-Host "Installing $feature" Enable-WindowsOptionalFeature -Online -FeatureName $feature -All -NoRestart } @@ -519,10 +546,10 @@ function Invoke-WinUtilFeatureInstall { else{ Write-Warning "Unable to Install $feature due to unhandled exception" - Write-Warning $psitem.Exception.StackTrace + Write-Warning $psitem.Exception.StackTrace } } - } + } } if($sync.configs.feature.$psitem.InvokeScript){ Foreach( $script in $sync.configs.feature.$psitem.InvokeScript ){ @@ -539,24 +566,29 @@ function Invoke-WinUtilFeatureInstall { else{ Write-Warning "Unable to Install $feature due to unhandled exception" - Write-Warning $psitem.Exception.StackTrace + Write-Warning $psitem.Exception.StackTrace } } - } + } } } } function Invoke-WinUtilScript { <# - - .DESCRIPTION - This function will run a separate powershell script. Meant for things that can't be handled with the other functions - .EXAMPLE + .SYNOPSIS + Invokes the provided scriptblock. Intended for things that can't be handled with the other functions. + + .PARAMETER Name + The name of the scriptblock being invoked + .PARAMETER scriptblock + The scriptblock to be invoked + + .EXAMPLE $Scriptblock = [scriptblock]::Create({"Write-output 'Hello World'"}) Invoke-WinUtilScript -ScriptBlock $scriptblock -Name "Hello World" - + #> param ( $Name, @@ -586,16 +618,22 @@ function Invoke-WinUtilScript { Catch { # Generic catch block to handle any other type of exception Write-Warning "Unable to run script for $name due to unhandled exception" - Write-Warning $psitem.Exception.StackTrace + Write-Warning $psitem.Exception.StackTrace } - + } function Invoke-WinUtilTweaks { <# - - .DESCRIPTION - This function converts all the values from the tweaks.json and routes them to the appropriate function - + + .SYNOPSIS + Invokes the function associated with each provided checkbox + + .PARAMETER CheckBox + The checkbox to invoke + + .PARAMETER undo + Indicates whether to undo the operation contained in the checkbox + #> param( @@ -610,7 +648,7 @@ function Invoke-WinUtilTweaks { ScriptType = "UndoScript" } - } + } Else{ $Values = @{ Registry = "Value" @@ -652,14 +690,16 @@ function Invoke-WinUtilTweaks { } function Remove-WinUtilAPPX { <# - - .DESCRIPTION - This function will remove any of the provided APPX names - .EXAMPLE + .SYNOPSIS + Removes all APPX packages that match the given name + + .PARAMETER Name + The name of the APPX package to remove + .EXAMPLE Remove-WinUtilAPPX -Name "Microsoft.Microsoft3DViewer" - + #> param ( $Name @@ -676,24 +716,26 @@ function Remove-WinUtilAPPX { } Else{ Write-Warning "Unable to uninstall $name due to unhandled exception" - Write-Warning $psitem.Exception.StackTrace + Write-Warning $psitem.Exception.StackTrace } } Catch{ Write-Warning "Unable to uninstall $name due to unhandled exception" - Write-Warning $psitem.Exception.StackTrace + Write-Warning $psitem.Exception.StackTrace } } function Set-WinUtilDNS { <# - - .DESCRIPTION - This function will set the DNS of all interfaces that are in the "Up" state. It will lookup the values from the DNS.Json file - .EXAMPLE + .SYNOPSIS + Sets the DNS of all interfaces that are in the "Up" state. It will lookup the values from the DNS.Json file + .PARAMETER DNSProvider + The DNS provider to set the DNS server to + + .EXAMPLE Set-WinUtilDNS -DNSProvider "google" - + #> param($DNSProvider) if($DNSProvider -eq "Default"){return} @@ -713,20 +755,31 @@ function Set-WinUtilDNS { } Catch{ Write-Warning "Unable to set DNS Provider due to an unhandled exception" - Write-Warning $psitem.Exception.StackTrace + Write-Warning $psitem.Exception.StackTrace } } function Set-WinUtilRegistry { <# - - .DESCRIPTION - This function will make all modifications to the registry - .EXAMPLE + .SYNOPSIS + Modifies the registry based on the given inputs + + .PARAMETER Name + The name of the key to modify + + .PARAMETER Path + The path to the key + .PARAMETER Type + The type of value to set the key to + + .PARAMETER Value + The value to set the key to + + .EXAMPLE Set-WinUtilRegistry -Name "PublishUserActivities" -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Type "DWord" -Value "0" - - #> + + #> param ( $Name, $Path, @@ -734,7 +787,7 @@ function Set-WinUtilRegistry { $Value ) - Try{ + Try{ if(!(Test-Path 'HKU:\')){New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS} If (!(Test-Path $Path)) { @@ -758,11 +811,11 @@ function Set-WinUtilRegistry { } function Set-WinUtilRestorePoint { <# - - .DESCRIPTION - This function will make a Restore Point - #> + .SYNOPSIS + Creates a Restore Point + + #> # Check if the user has administrative privileges if (-Not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { @@ -782,7 +835,7 @@ function Set-WinUtilRestorePoint { $exists = Get-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRestore" -name "SystemRestorePointCreationFrequency" -ErrorAction SilentlyContinue if($null -eq $exists){ write-host 'Changing system to allow multiple restore points per day' - Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRestore" -Name "SystemRestorePointCreationFrequency" -Value "0" -Type DWord -Force -ErrorAction Stop | Out-Null + Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRestore" -Name "SystemRestorePointCreationFrequency" -Value "0" -Type DWord -Force -ErrorAction Stop | Out-Null } # Get all the restore points for the current day @@ -791,21 +844,26 @@ function Set-WinUtilRestorePoint { # Check if there is already a restore point created today if ($existingRestorePoints.Count -eq 0) { $description = "System Restore Point created by WinUtil" - + Checkpoint-Computer -Description $description -RestorePointType "MODIFY_SETTINGS" Write-Host -ForegroundColor Green "System Restore Point Created Successfully" } } function Set-WinUtilScheduledTask { <# - - .DESCRIPTION - This function will enable/disable the provided Scheduled Task - .EXAMPLE + .SYNOPSIS + Enables/Disables the provided Scheduled Task + + .PARAMETER Name + The path to the Scheduled Task + .PARAMETER State + The State to set the Task to + + .EXAMPLE Set-WinUtilScheduledTask -Name "Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser" -State "Disabled" - + #> param ( $Name, @@ -833,30 +891,35 @@ function Set-WinUtilScheduledTask { } Catch{ Write-Warning "Unable to run script for $name due to unhandled exception" - Write-Warning $psitem.Exception.StackTrace + Write-Warning $psitem.Exception.StackTrace } } Function Set-WinUtilService { <# - - .DESCRIPTION - This function will change the startup type of services and start/stop them as needed - .EXAMPLE + .SYNOPSIS + Changes the startup type of the given service + + .PARAMETER Name + The name of the service to modify + + .PARAMETER StartupType + The startup type to set the service to + .EXAMPLE Set-WinUtilService -Name "HomeGroupListener" -StartupType "Manual" - - #> + + #> param ( $Name, $StartupType ) try { Write-Host "Setting Service $Name to $StartupType" - + # Check if the service exists $service = Get-Service -Name $Name -ErrorAction Stop - + # Service exists, proceed with changing properties $service | Set-Service -StartupType $StartupType -ErrorAction Stop } @@ -867,18 +930,23 @@ Function Set-WinUtilService { Write-Warning "Unable to set $Name due to unhandled exception" Write-Warning $_.Exception.Message } - + } function Set-WinUtilUITheme { <# - - .DESCRIPTION - This function will set theme to the XAML file - .EXAMPLE + .SYNOPSIS + Sets the theme of the XAML file + + .PARAMETER inputXML + A string representing the XAML object to modify + + .PARAMETER themeName + The name of the theme to set the XAML to. Defaults to 'matrix' + .EXAMPLE Set-WinUtilUITheme -inputXAML $inputXAML - + #> param ( @@ -912,17 +980,23 @@ function Set-WinUtilUITheme { } catch { Write-Warning "Unable to apply theme" - Write-Warning $psitem.Exception.StackTrace + Write-Warning $psitem.Exception.StackTrace } return $inputXML; } function Test-WinUtilPackageManager { <# - - .DESCRIPTION - Checks for Winget or Choco depending on the parameter - + + .SYNOPSIS + Checks if Winget and/or Choco are installed + + .PARAMETER winget + Check if Winget is installed + + .PARAMETER choco + Check if Chocolatey is installed + #> Param( @@ -947,10 +1021,10 @@ function Test-WinUtilPackageManager { Function Update-WinUtilProgramWinget { <# - - .DESCRIPTION - This will update programs via Winget using a new powershell.exe instance to prevent the GUI from locking up. - + + .SYNOPSIS + This will update all programs using Winget + #> [ScriptBlock]$wingetinstall = { @@ -969,17 +1043,18 @@ Function Update-WinUtilProgramWinget { function Invoke-WPFButton { <# - - .DESCRIPTION - Meant to make creating buttons easier. There is a section below in the gui that will assign this function to every button. - This way you can dictate what each button does from this function. - - Input will be the name of the button that is clicked. + + .SYNOPSIS + Invokes the function associated with the clicked button + + .PARAMETER Button + The name of the button that was clicked + #> - - Param ([string]$Button) - #Use this to get the name of the button + Param ([string]$Button) + + # Use this to get the name of the button #[System.Windows.MessageBox]::Show("$Button","Chris Titus Tech's Windows Utility","OK","Info") Switch -Wildcard ($Button){ @@ -1023,11 +1098,14 @@ function Invoke-WPFButton { } } function Invoke-WPFControlPanel { - <# - - .DESCRIPTION - Simple Switch for legacy windows - + <# + + .SYNOPSIS + Opens the requested legacy panel + + .PARAMETER Panel + The panel to open + #> param($Panel) @@ -1042,11 +1120,11 @@ function Invoke-WPFControlPanel { } } function Invoke-WPFFeatureInstall { - <# - - .DESCRIPTION - GUI Function to install Windows Features - + <# + + .SYNOPSIS + Installs selected Windows Features + #> if($sync.ProcessRunning){ @@ -1069,26 +1147,30 @@ function Invoke-WPFFeatureInstall { Write-Host "--- Features are Installed ---" Write-Host "--- A Reboot may be required ---" Write-Host "===================================" - + $ButtonType = [System.Windows.MessageBoxButton]::OK $MessageboxTitle = "All features are now installed " $Messageboxbody = ("Done") $MessageIcon = [System.Windows.MessageBoxImage]::Information - + [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon) } } function Invoke-WPFFixesNetwork { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Resets various network configurations + #> Write-Host "Resetting Network with netsh" + + # Reset WinSock catalog to a clean state Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winsock", "reset" + # Resets WinHTTP proxy setting to DIRECT Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winhttp", "reset", "proxy" + # Removes all user configured IP settings Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "int", "ip", "reset" Write-Host "Process complete. Please reboot your computer." @@ -1099,20 +1181,20 @@ function Invoke-WPFFixesNetwork { $MessageIcon = [System.Windows.MessageBoxImage]::Information [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon) - Write-Host "=================================" - Write-Host "-- Reset Network Configuration --" - Write-Host "=================================" + Write-Host "==========================================" + Write-Host "-- Network Configuration has been Reset --" + Write-Host "==========================================" } function Invoke-WPFFixesUpdate { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Performs various tasks in an attempt to repair Windows Update + #> - ### Reset Windows Update Script - reregister dlls, services, and remove registry entries. + # Reset Windows Update Script - reregister dlls, services, and remove registry entries Write-Host "1. Stopping Windows Update Services..." Stop-Service -Name BITS Stop-Service -Name wuauserv @@ -1188,16 +1270,16 @@ Write-Host "12) Forcing discovery..." $MessageIcon = [System.Windows.MessageBoxImage]::Information [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon) - Write-Host "=================================" - Write-Host "-- Reset ALL Updates to Factory -" - Write-Host "=================================" + Write-Host "===============================================" + Write-Host "-- Reset All Windows Update Settings to Stock -" + Write-Host "===============================================" } Function Invoke-WPFFormVariables { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Prints the logo + #> #If ($global:ReadmeDisplay -ne $true) { Write-Host "If you need to reference this display again, run Get-FormVariables" -ForegroundColor Yellow; $global:ReadmeDisplay = $true } @@ -1232,8 +1314,11 @@ Function Invoke-WPFFormVariables { function Invoke-WPFGetInstalled { <# - .DESCRIPTION - placeholder + .SYNOPSIS + Invokes the function that gets the checkboxes to check in a new runspace + + .PARAMETER checkbox + Indicates whether to check for installed 'winget' programs or applied 'tweaks' #> param($checkbox) @@ -1262,9 +1347,9 @@ function Invoke-WPFGetInstalled { if($checkbox -eq "tweaks"){ Write-Host "Getting Installed Tweaks..." } - + $Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox - + $sync.form.Dispatcher.invoke({ foreach($checkbox in $Checkboxes){ $sync.$checkbox.ischecked = $True @@ -1277,14 +1362,19 @@ function Invoke-WPFGetInstalled { } function Invoke-WPFImpex { <# - - .DESCRIPTION - This function handles importing and exporting of the checkboxes checked for the tweaks section - .EXAMPLE + .SYNOPSIS + Handles importing and exporting of the checkboxes checked for the tweaks section + + .PARAMETER type + Indicates whether to 'import' or 'export' + .PARAMETER checkbox + The checkbox to export to a file or apply the imported file to + + .EXAMPLE Invoke-WPFImpex -type "export" - + #> param( $type, @@ -1295,7 +1385,7 @@ function Invoke-WPFImpex { $FileBrowser = New-Object System.Windows.Forms.SaveFileDialog } if ($type -eq "import"){ - $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog + $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog } $FileBrowser.InitialDirectory = [Environment]::GetFolderPath('Desktop') @@ -1305,7 +1395,7 @@ function Invoke-WPFImpex { if($FileBrowser.FileName -eq ""){ return } - + if ($type -eq "export"){ $jsonFile = Get-WinUtilCheckBoxes $checkbox -unCheck $false $jsonFile | ConvertTo-Json | Out-File $FileBrowser.FileName -Force @@ -1317,10 +1407,10 @@ function Invoke-WPFImpex { } function Invoke-WPFInstall { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Installs the selected programs using winget + #> if($sync.ProcessRunning){ @@ -1345,14 +1435,14 @@ function Invoke-WPFInstall { # Ensure winget is installed Install-WinUtilWinget - # Install all winget programs in new window + # Install all selected programs in new window Install-WinUtilProgramWinget -ProgramsToInstall $WingetInstall $ButtonType = [System.Windows.MessageBoxButton]::OK $MessageboxTitle = "Installs are Finished " $Messageboxbody = ("Done") $MessageIcon = [System.Windows.MessageBoxImage]::Information - + [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon) Write-Host "===========================================" @@ -1369,10 +1459,10 @@ function Invoke-WPFInstall { } function Invoke-WPFInstallUpgrade { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Invokes the function that upgrades all installed programs using winget + #> if(!(Test-WinUtilPackageManager -winget)){ Write-Host "===========================================" @@ -1396,20 +1486,37 @@ function Invoke-WPFInstallUpgrade { } function Invoke-WPFPanelAutologin { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Enables autologin using Sysinternals Autologon.exe + #> curl.exe -ss "https://live.sysinternals.com/Autologon.exe" -o $env:temp\autologin.exe # Official Microsoft recommendation https://learn.microsoft.com/en-us/sysinternals/downloads/autologon cmd /c $env:temp\autologin.exe /accepteula } function Invoke-WPFPanelDISM { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Checks for system corruption using Chkdsk, SFC, and DISM + + .DESCRIPTION + 1. Chkdsk - Fixes disk and filesystem corruption + 2. SFC Run 1 - Fixes system file corruption, and fixes DISM if it was corrupted + 3. DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted + 4. SFC Run 2 - Fixes system file corruption, this time with an almost guaranteed uncorrupted system image + + .NOTES + Command Arguments: + 1. Chkdsk + /Scan - Runs an online scan on the system drive, attempts to fix any corruption, and queues other corruption for fixing on reboot + 2. SFC + /ScanNow - Performs a scan of the system files and fixes any corruption + 3. DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted + /Online - Fixes the currently running system image + /Cleanup-Image - Performs cleanup operations on the image, could remove some unneeded temporary files + /Restorehealth - Performs a scan of the image and fixes any corruption + #> Start-Process PowerShell -ArgumentList "Write-Host '(1/4) Chkdsk' -ForegroundColor Green; Chkdsk /scan; Write-Host '`n(2/4) SFC - 1st scan' -ForegroundColor Green; sfc /scannow; @@ -1420,8 +1527,17 @@ function Invoke-WPFPanelDISM { function Invoke-WPFPresets { <# - .DESCRIPTION - Meant to make settings presets easier in the tweaks tab. Will pull the data from config/preset.json + .SYNOPSIS + Sets the options in the tweaks panel to the given preset + + .PARAMETER preset + The preset to set the options to + + .PARAMETER imported + If the preset is imported from a file, defaults to false + + .PARAMETER checkbox + The checkbox to set the options to, defaults to 'WPFTweaks' #> @@ -1461,40 +1577,41 @@ function Invoke-WPFPresets { function Invoke-WPFRunspace { <# - - .DESCRIPTION - Simple function to make it easier to invoke a runspace from inside the script. - .EXAMPLE + .SYNOPSIS + Creates and invokes a runspace using the given scriptblock and argumentlist - $params = @{ - ScriptBlock = $sync.ScriptsInstallPrograms - ArgumentList = "Installadvancedip,Installbitwarden" - Verbose = $true - } + .PARAMETER ScriptBlock + The scriptblock to invoke in the runspace + + .PARAMETER ArgumentList + A list of arguments to pass to the runspace + + .EXAMPLE + Invoke-WPFRunspace ` + -ScriptBlock $sync.ScriptsInstallPrograms ` + -ArgumentList "Installadvancedip,Installbitwarden" ` - Invoke-WPFRunspace @params - #> [CmdletBinding()] Param ( $ScriptBlock, $ArgumentList - ) + ) - #Crate a PowerShell instance. + # Create a PowerShell instance $script:powershell = [powershell]::Create() - #Add Scriptblock and Arguments to runspace + # Add Scriptblock and Arguments to runspace $script:powershell.AddScript($ScriptBlock) $script:powershell.AddArgument($ArgumentList) $script:powershell.RunspacePool = $sync.runspace - - #Run our RunspacePool. + + # Execute the RunspacePool $script:handle = $script:powershell.BeginInvoke() - #Cleanup our RunspacePool threads when they are complete ie. GC. + # Clean up the RunspacePool threads when they are complete, and invoke the garbage collector to clean up the memory if ($script:handle.IsCompleted) { $script:powershell.EndInvoke($script:handle) @@ -1507,15 +1624,18 @@ function Invoke-WPFRunspace { function Invoke-WPFShortcut { <# - .DESCRIPTION - Creates a shortcut + .SYNOPSIS + Creates a shortcut and prompts for a save location + + .PARAMETER ShortcutToAdd + The name of the shortcut to add #> param($ShortcutToAdd) Switch ($ShortcutToAdd) { "WinUtil" { - $SourceExe = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" + $SourceExe = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" $IRM = 'irm https://christitus.com/win | iex' $Powershell = '-ExecutionPolicy Bypass -Command "Start-Process powershell.exe -verb runas -ArgumentList' $ArgumentsToSourceExe = "$powershell '$IRM'" @@ -1534,16 +1654,19 @@ function Invoke-WPFShortcut { $Shortcut.TargetPath = $SourceExe $Shortcut.Arguments = $ArgumentsToSourceExe $Shortcut.Save() - + Write-Host "Shortcut for $ShortcutToAdd has been saved to $($FileBrowser.FileName)" } function Invoke-WPFTab { <# - - .DESCRIPTION - Sole purpose of this function is to reduce duplicated code for switching between tabs. - + + .SYNOPSIS + Sets the selected tab to the tab that was clicked + + .PARAMETER ClickedTab + The name of the tab that was clicked + #> Param ($ClickedTab) @@ -1552,7 +1675,7 @@ function Invoke-WPFTab { $x = [int]($ClickedTab -replace "WPFTab","" -replace "BT","") - 1 0..($Tabs.Count -1 ) | ForEach-Object { - + if ($x -eq $psitem){ $sync.$TabNav.Items[$psitem].IsSelected = $true } @@ -1564,17 +1687,18 @@ function Invoke-WPFTab { function Invoke-WPFToggle { <# - - .DESCRIPTION - Meant to make creating toggle switches easier. There is a section below in the gui that will assign this function to every switch. - This way you can dictate what each button does from this function. - - Input will be the name of the toggle that is checked. + + .SYNOPSIS + Invokes the scriptblock for the given toggle + + .PARAMETER Button + The name of the toggle to invoke + #> - - Param ([string]$Button) - #Use this to get the name of the button + Param ([string]$Button) + + # Use this to get the name of the button #[System.Windows.MessageBox]::Show("$Button","Chris Titus Tech's Windows Utility","OK","Info") Switch -Wildcard ($Button){ @@ -1586,10 +1710,10 @@ function Invoke-WPFToggle { } function Invoke-WPFtweaksbutton { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Invokes the functions associated with each group of checkboxes + #> if($sync.ProcessRunning){ @@ -1608,13 +1732,13 @@ function Invoke-WPFtweaksbutton { return } - Set-WinUtilRestorePoint - Invoke-WPFRunspace -ArgumentList $Tweaks -ScriptBlock { param($Tweaks) $sync.ProcessRunning = $true + Set-WinUtilRestorePoint + Foreach ($tweak in $tweaks){ Invoke-WinUtilTweaks $tweak } @@ -1634,26 +1758,28 @@ function Invoke-WPFtweaksbutton { } Function Invoke-WPFUltimatePerformance { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Creates or removes the Ultimate Performance power scheme + + .PARAMETER State + Indicates whether to enable or disable the Ultimate Performance power scheme + #> param($State) Try{ if($state -eq "Enabled"){ - # Define the name and GUID of the power scheme you want to add + # Define the name and GUID of the power scheme $powerSchemeName = "Ultimate Performance" $powerSchemeGuid = "e9a42b02-d5df-448d-aa00-03f14749eb61" # Get all power schemes $schemes = powercfg /list | Out-String -Stream - # Find the scheme you want to add + # Check if the power scheme already exists $ultimateScheme = $schemes | Where-Object { $_ -match $powerSchemeName } - # If the scheme does not exist, add it if ($null -eq $ultimateScheme) { Write-Host "Power scheme '$powerSchemeName' not found. Adding..." @@ -1665,16 +1791,16 @@ Function Invoke-WPFUltimatePerformance { } else { Write-Host "Power scheme '$powerSchemeName' already exists." - } + } } elseif($state -eq "Disabled"){ - # Define the name of the power scheme you want to remove + # Define the name of the power scheme $powerSchemeName = "Ultimate Performance" # Get all power schemes $schemes = powercfg /list | Out-String -Stream - # Find the scheme you want to remove + # Find the scheme to be removed $ultimateScheme = $schemes | Where-Object { $_ -match $powerSchemeName } # If the scheme exists, remove it @@ -1684,10 +1810,10 @@ Function Invoke-WPFUltimatePerformance { if($null -ne $guid){ Write-Host "Found power scheme '$powerSchemeName' with GUID $guid. Removing..." - + # Remove the power scheme powercfg /delete $guid - + Write-Host "Power scheme removed successfully." } else { @@ -1699,7 +1825,7 @@ Function Invoke-WPFUltimatePerformance { } } - + } Catch{ Write-Warning $psitem.Exception.Message @@ -1707,10 +1833,10 @@ Function Invoke-WPFUltimatePerformance { } function Invoke-WPFundoall { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Undoes every selected tweak + #> if($sync.ProcessRunning){ @@ -1725,8 +1851,8 @@ function Invoke-WPFundoall { $msg = "Please check the tweaks you wish to undo." [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) return - } - + } + Invoke-WPFRunspace -ArgumentList $Tweaks -ScriptBlock { param($Tweaks) @@ -1903,14 +2029,14 @@ function Invoke-WPFundoall { } function Invoke-WPFUnInstall { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Uninstalls the selected programs + #> if($sync.ProcessRunning){ - $msg = "Install process is currently running." + $msg = "Install process is currently running" [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) return } @@ -1925,7 +2051,7 @@ function Invoke-WPFUnInstall { $ButtonType = [System.Windows.MessageBoxButton]::YesNo $MessageboxTitle = "Are you sure?" - $Messageboxbody = ("This will uninstall the following applications `n $WingetInstall") + $Messageboxbody = ("This will uninstall the following applications: `n $WingetInstall") $MessageIcon = [System.Windows.MessageBoxImage]::Information $confirm = [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon) @@ -1937,23 +2063,23 @@ function Invoke-WPFUnInstall { try{ $sync.ProcessRunning = $true - # Install all winget programs in new window + # Install all selected programs in new window Install-WinUtilProgramWinget -ProgramsToInstall $WingetInstall -Manage "Uninstalling" $ButtonType = [System.Windows.MessageBoxButton]::OK $MessageboxTitle = "Uninstalls are Finished " $Messageboxbody = ("Done") $MessageIcon = [System.Windows.MessageBoxImage]::Information - + [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon) Write-Host "===========================================" - Write-Host "-- Uninstalls have finished ---" + Write-Host "-- Uninstalls have finished ---" Write-Host "===========================================" } Catch { Write-Host "===========================================" - Write-Host "-- Winget failed to install ---" + Write-Host "-- Winget failed to install ---" Write-Host "===========================================" } $sync.ProcessRunning = $False @@ -1961,10 +2087,10 @@ function Invoke-WPFUnInstall { } function Invoke-WPFUpdatesdefault { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Resets Windows Update settings to default + #> If (!(Test-Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU")) { New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Force | Out-Null @@ -2000,16 +2126,19 @@ function Invoke-WPFUpdatesdefault { Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Name "BranchReadinessLevel" -ErrorAction SilentlyContinue Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Name "DeferFeatureUpdatesPeriodInDays" -ErrorAction SilentlyContinue Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Name "DeferQualityUpdatesPeriodInDays" -ErrorAction SilentlyContinue - Write-Host "=================================" - Write-Host "--- Updates Set to Default ---" - Write-Host "=================================" + Write-Host "===================================================" + Write-Host "--- Windows Update Settings Reset to Default ---" + Write-Host "===================================================" } function Invoke-WPFUpdatesdisable { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Disables Windows Update + + .NOTES + Disabling Windows Update is not recommended. This is only for advanced users who know what they are doing. + #> If (!(Test-Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU")) { New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Force | Out-Null @@ -2033,15 +2162,22 @@ function Invoke-WPFUpdatesdisable { Get-Service -Name $service -ErrorAction SilentlyContinue | Set-Service -StartupType Disabled } Write-Host "=================================" - Write-Host "--- Updates ARE DISABLED ---" + Write-Host "--- Updates ARE DISABLED ---" Write-Host "=================================" } function Invoke-WPFUpdatessecurity { <# - - .DESCRIPTION - PlaceHolder - + + .SYNOPSIS + Sets Windows Update to recommended settings + + .DESCRIPTION + 1. Disables driver offering through Windows Update + 2. Disables Windows Update automatic restart + 3. Sets Windows Update to Semi-Annual Channel (Targeted) + 4. Defers feature updates for 365 days + 5. Defers quality updates for 4 days + #> Write-Host "Disabling driver offering through Windows Update..." If (!(Test-Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata")) { @@ -2092,7 +2228,7 @@ $inputXML = ' - + +