Choco Logic Refactor and Add Checkbox to prefer Chocolatey over Winget (#2596)

* First Selector and Logic

* Extend Functionality

* Switch to PreferChocolatey Checkbox

* Persist Choco Preference across program restarts

* Change Logging, Fix interactivity and optimize uninstall

* Implement "Get-Installed" (quick-and-dirty)

* Code Formatting

* Rename File/Function, Refactor Choco Install, Add Status Indicator

* Add documentation

---------

Co-authored-by: Chris Titus <contact@christitus.com>
This commit is contained in:
Martin Wiethan 2024-09-10 20:02:22 +02:00 committed by GitHub
parent 2b9b1b026c
commit 14d20cd161
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 356 additions and 134 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 213 KiB

View File

@ -69,7 +69,7 @@ function Invoke-WPFTweakPS7{
Write-Host "Powershell 7 is already installed." Write-Host "Powershell 7 is already installed."
} else { } else {
Write-Host "Installing Powershell 7..." Write-Host "Installing Powershell 7..."
Invoke-WinUtilWingetProgram -Action Install -Programs @("Microsoft.PowerShell") Install-WinUtilProgramWinget -Action Install -Programs @("Microsoft.PowerShell")
} }
$targetTerminalName = "PowerShell" $targetTerminalName = "PowerShell"
} }
@ -105,10 +105,10 @@ function Invoke-WPFTweakPS7{
} }
``` ```
## Function: Invoke-WinUtilWingetProgram ## Function: Install-WinUtilProgramWinget
```powershell ```powershell
Function Invoke-WinUtilWingetProgram { Function Install-WinUtilProgramWinget {
<# <#
.SYNOPSIS .SYNOPSIS
Runs the designated action on the provided programs using Winget Runs the designated action on the provided programs using Winget

View File

@ -29,6 +29,11 @@
* Click the `Clear Selection` button. * Click the `Clear Selection` button.
* This will unselect all checked programs. * This will unselect all checked programs.
=== "prefer Chocolatey"
* Check the `prefer Chocolatey` checkbox
* By default Winutil will use winget to install/upgrade/remove packages and fallback to Chocolatey. This option reverses the preference.
* This preference will be used for all Buttons on the Install page and persist across Winutil restarts
![Install Image](assets/Install-Tab-Dark.png#only-dark) ![Install Image](assets/Install-Tab-Dark.png#only-dark)
![Install Image](assets/Install-Tab-Light.png#only-light) ![Install Image](assets/Install-Tab-Light.png#only-light)
!!! tip !!! tip

View File

@ -15,8 +15,8 @@ function Install-WinUtilChoco {
} }
Write-Host "Seems Chocolatey is not installed, installing now." Write-Host "Seems Chocolatey is not installed, installing now."
Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) -ErrorAction Stop Start-Process -FilePath "powershell" -ArgumentList "Set-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) -ErrorAction Stop" -Wait -NoNewWindow
powershell choco feature enable -n allowGlobalConfirmation Start-Process -FilePath "powershell" -ArgumentList "choco feature enable -n allowGlobalConfirmation" -Wait -NoNewWindow
} catch { } catch {
Write-Host "===========================================" -Foregroundcolor Red Write-Host "===========================================" -Foregroundcolor Red

View File

@ -1,102 +1,258 @@
function Install-WinUtilProgramChoco { function Install-WinUtilProgramChoco {
<# <#
.SYNOPSIS .SYNOPSIS
Manages the provided programs using Chocolatey Manages the installation or uninstallation of a list of Chocolatey packages.
.PARAMETER ProgramsToInstall .PARAMETER Programs
A list of programs to manage A string array containing the programs to be installed or uninstalled.
.PARAMETER manage .PARAMETER Action
The action to perform on the programs, can be either 'Installing' or 'Uninstalling' Specifies the action to perform: "Install" or "Uninstall". The default value is "Install".
.NOTES .DESCRIPTION
The triple quotes are required any time you need a " in a normal script block. This function processes a list of programs to be managed using Chocolatey. Depending on the specified action, it either installs or uninstalls each program in the list, updating the taskbar progress accordingly. After all operations are completed, temporary output files are cleaned up.
.EXAMPLE
Install-WinUtilProgramChoco -Programs @("7zip","chrome") -Action "Uninstall"
#> #>
param( param(
[Parameter(Mandatory, Position=0)] [Parameter(Mandatory, Position = 0)]
[PsCustomObject]$ProgramsToInstall, [string[]]$Programs,
[Parameter(Position=1)] [Parameter(Position = 1)]
[String]$manage = "Installing" [String]$Action = "Install"
) )
$x = 0 function Initialize-OutputFile {
$count = $ProgramsToInstall.Count <#
.SYNOPSIS
# This check isn't really necessary, as there's a couple of checks before this Private Function gets called, but just to make sure ;) Initializes an output file by removing any existing file and creating a new, empty file at the specified path.
if($count -le 0) {
throw "Private Function 'Install-WinUtilProgramChoco' expected Parameter 'ProgramsToInstall' to be of size 1 or greater, instead got $count,`nPlease double check your code and re-compile WinUtil." .PARAMETER filePath
The full path to the file to be initialized.
.DESCRIPTION
This function ensures that the specified file is reset by removing any existing file at the provided path and then creating a new, empty file. It is useful when preparing a log or output file for subsequent operations.
.EXAMPLE
Initialize-OutputFile -filePath "C:\temp\output.txt"
#>
param ($filePath)
Remove-Item -Path $filePath -Force -ErrorAction SilentlyContinue
New-Item -ItemType File -Path $filePath | Out-Null
} }
Write-Progress -Activity "$manage Applications" -Status "Starting" -PercentComplete 0 function Run-ChocoCommand {
Write-Host "===========================================" <#
Write-Host "-- Configuring Chocolatey pacakages ---" .SYNOPSIS
Write-Host "===========================================" Executes a Chocolatey command with the specified arguments and returns the exit code.
Foreach ($Program in $ProgramsToInstall) {
Write-Progress -Activity "$manage Applications" -Status "$manage $($Program.choco) $($x + 1) of $count" -PercentComplete $($x/$count*100) .PARAMETER arguments
if($manage -eq "Installing") { The arguments to be passed to the Chocolatey command.
write-host "Starting install of $($Program.choco) with Chocolatey."
try { .DESCRIPTION
$tryUpgrade = $false This function runs a specified Chocolatey command by passing the provided arguments to the `choco` executable. It waits for the process to complete and then returns the exit code, allowing the caller to determine success or failure based on the exit code.
$installOutputFilePath = "$env:TEMP\Install-WinUtilProgramChoco.install-command.output.txt"
New-Item -ItemType File -Path $installOutputFilePath .RETURNS
$chocoInstallStatus = $(Start-Process -FilePath "choco" -ArgumentList "install $($Program.choco) -y" -Wait -PassThru -RedirectStandardOutput $installOutputFilePath).ExitCode [int]
if(($chocoInstallStatus -eq 0) -AND (Test-Path -Path $installOutputFilePath)) { The exit code of the Chocolatey command.
$keywordsFound = Get-Content -Path $installOutputFilePath | Where-Object {$_ -match "reinstall" -OR $_ -match "already installed"}
if ($keywordsFound) { .EXAMPLE
$tryUpgrade = $true $exitCode = Run-ChocoCommand -arguments "install 7zip -y"
#>
param ($arguments)
return (Start-Process -FilePath "choco" -ArgumentList $arguments -Wait -PassThru).ExitCode
}
function Check-UpgradeNeeded {
<#
.SYNOPSIS
Checks if an upgrade is needed for a Chocolatey package based on the content of a log file.
.PARAMETER filePath
The path to the log file that contains the output of a Chocolatey install command.
.DESCRIPTION
This function reads the specified log file and checks for keywords that indicate whether an upgrade is needed. It returns a boolean value indicating whether the terms "reinstall" or "already installed" are present, which suggests that the package might need an upgrade.
.RETURNS
[bool]
True if the log file indicates that an upgrade is needed; otherwise, false.
.EXAMPLE
$isUpgradeNeeded = Check-UpgradeNeeded -filePath "C:\temp\install-output.txt"
#>
param ($filePath)
return Get-Content -Path $filePath | Select-String -Pattern "reinstall|already installed" -Quiet
}
function Update-TaskbarProgress {
<#
.SYNOPSIS
Updates the taskbar progress based on the current installation progress.
.PARAMETER currentIndex
The current index of the program being installed or uninstalled.
.PARAMETER totalPrograms
The total number of programs to be installed or uninstalled.
.DESCRIPTION
This function calculates the progress of the installation or uninstallation process and updates the taskbar accordingly. The taskbar is set to "Normal" if all programs have been processed, otherwise, it is set to "Error" as a placeholder.
.EXAMPLE
Update-TaskbarProgress -currentIndex 3 -totalPrograms 10
#>
param (
[int]$currentIndex,
[int]$totalPrograms
)
$progressState = if ($currentIndex -eq $totalPrograms) { "Normal" } else { "Error" }
$sync.form.Dispatcher.Invoke([action] { Set-WinUtilTaskbaritem -state $progressState -value ($currentIndex / $totalPrograms) })
}
function Install-ChocoPackage {
<#
.SYNOPSIS
Installs a Chocolatey package and optionally upgrades it if needed.
.PARAMETER Program
A string containing the name of the Chocolatey package to be installed.
.PARAMETER currentIndex
The current index of the program in the list of programs to be managed.
.PARAMETER totalPrograms
The total number of programs to be installed.
.DESCRIPTION
This function installs a Chocolatey package by running the `choco install` command. If the installation output indicates that an upgrade might be needed, the function will attempt to upgrade the package. The taskbar progress is updated after each package is processed.
.EXAMPLE
Install-ChocoPackage -Program $Program -currentIndex 0 -totalPrograms 5
#>
param (
[string]$Program,
[int]$currentIndex,
[int]$totalPrograms
)
$installOutputFile = "$env:TEMP\Install-WinUtilProgramChoco.install-command.output.txt"
Initialize-OutputFile $installOutputFile
Write-Host "Starting installation of $Program with Chocolatey."
try {
$installStatusCode = Run-ChocoCommand "install $Program -y --log-file $installOutputFile"
if ($installStatusCode -eq 0) {
if (Check-UpgradeNeeded $installOutputFile) {
$upgradeStatusCode = Run-ChocoCommand "upgrade $Program -y"
Write-Host "$Program was" $(if ($upgradeStatusCode -eq 0) { "upgraded successfully." } else { "not upgraded." })
}
else {
Write-Host "$Program installed successfully."
} }
} }
# TODO: Implement the Upgrade part using 'choco upgrade' command, this will make choco consistent with WinGet, as WinGet tries to Upgrade when you use the install command. else {
if ($tryUpgrade) { Write-Host "Failed to install $Program."
throw "Automatic Upgrade for Choco isn't implemented yet, a feature to make it consistent with WinGet, the install command using choco simply failed because $($Program.choco) is already installed."
}
if(($chocoInstallStatus -eq 0) -AND ($tryUpgrade -eq $false)) {
Write-Host "$($Program.choco) installed successfully using Chocolatey."
$X++
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Normal" -value ($x/$count) })
continue
} else {
Write-Host "Failed to install $($Program.choco) using Chocolatey, Chocolatey output:`n`n$(Get-Content -Path $installOutputFilePath)."
$X++
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Error" -value ($x/$count) })
}
} catch {
Write-Host "Failed to install $($Program.choco) due to an error: $_"
$X++
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Error" -value ($x/$count) })
} }
} }
catch {
if($manage -eq "Uninstalling") { Write-Host "Failed to install $Program due to an error: $_"
write-host "Starting uninstall of $($Program.choco) with Chocolatey." }
finally {
Update-TaskbarProgress $currentIndex $totalPrograms
}
}
function Uninstall-ChocoPackage {
<#
.SYNOPSIS
Uninstalls a Chocolatey package and any related metapackages.
.PARAMETER Program
A string containing the name of the Chocolatey package to be uninstalled.
.PARAMETER currentIndex
The current index of the program in the list of programs to be managed.
.PARAMETER totalPrograms
The total number of programs to be uninstalled.
.DESCRIPTION
This function uninstalls a Chocolatey package and any related metapackages (e.g., .install or .portable variants). It updates the taskbar progress after processing each package.
.EXAMPLE
Uninstall-ChocoPackage -Program $Program -currentIndex 0 -totalPrograms 5
#>
param (
[string]$Program,
[int]$currentIndex,
[int]$totalPrograms
)
$uninstallOutputFile = "$env:TEMP\Install-WinUtilProgramChoco.uninstall-command.output.txt"
Initialize-OutputFile $uninstallOutputFile
Write-Host "Searching for metapackages of $Program (.install or .portable)"
$chocoPackages = ((choco list | Select-String -Pattern "$Program(\.install|\.portable)?").Matches.Value) -join " "
if ($chocoPackages) {
Write-Host "Starting uninstallation of $chocoPackages with Chocolatey."
try { try {
$uninstallOutputFilePath = "$env:TEMP\Install-WinUtilProgramChoco.uninstall-command.output.txt" $uninstallStatusCode = Run-ChocoCommand "uninstall $chocoPackages -y"
New-Item -ItemType File -Path $uninstallOutputFilePath Write-Host "$Program" $(if ($uninstallStatusCode -eq 0) { "uninstalled successfully." } else { "failed to uninstall." })
$chocoUninstallStatus = $(Start-Process -FilePath "choco" -ArgumentList "uninstall $($Program.choco) -y" -Wait -PassThru).ExitCode
if($chocoUninstallStatus -eq 0) {
Write-Host "$($Program.choco) uninstalled successfully using Chocolatey."
$x++
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Normal" -value ($x/$count) })
continue
} else {
Write-Host "Failed to uninstall $($Program.choco) using Chocolatey, Chocolatey output:`n`n$(Get-Content -Path $uninstallOutputFilePath)."
$x++
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Error" -value ($x/$count) })
}
} catch {
Write-Host "Failed to uninstall $($Program.choco) due to an error: $_"
$x++
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Error" -value ($x/$count) })
} }
catch {
Write-Host "Failed to uninstall $Program due to an error: $_"
}
finally {
Update-TaskbarProgress $currentIndex $totalPrograms
}
}
else {
Write-Host "$Program is not installed."
}
} }
$totalPrograms = $Programs.Count
if ($totalPrograms -le 0) {
throw "Parameter 'Programs' must have at least one item."
} }
Write-Progress -Activity "$manage Applications" -Status "Finished" -Completed
# Cleanup leftovers files Write-Host "==========================================="
if(Test-Path -Path $installOutputFilePath) { Remove-Item -Path $installOutputFilePath } Write-Host "-- Configuring Chocolatey packages ---"
if(Test-Path -Path $uninstallOutputFilePath) { Remove-Item -Path $uninstallOutputFilePath } Write-Host "==========================================="
return; for ($currentIndex = 0; $currentIndex -lt $totalPrograms; $currentIndex++) {
$Program = $Programs[$currentIndex]
Set-WinUtilProgressBar -label "$Action $($Program)" -percent ($currentIndex / $totalPrograms * 100)
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -value ($currentIndex / $totalPrograms)})
switch ($Action) {
"Install" {
Install-ChocoPackage -Program $Program -currentIndex $currentIndex -totalPrograms $totalPrograms
}
"Uninstall" {
Uninstall-ChocoPackage -Program $Program -currentIndex $currentIndex -totalPrograms $totalPrograms
}
default {
throw "Invalid action parameter value: '$Action'."
}
}
}
Set-WinUtilProgressBar -label "$($Action)ation done" -percent 100
# Cleanup Output Files
$outputFiles = @("$env:TEMP\Install-WinUtilProgramChoco.install-command.output.txt", "$env:TEMP\Install-WinUtilProgramChoco.uninstall-command.output.txt")
foreach ($filePath in $outputFiles) {
Remove-Item -Path $filePath -Force -ErrorAction SilentlyContinue
}
} }

View File

@ -1,4 +1,4 @@
Function Invoke-WinUtilWingetProgram { Function Install-WinUtilProgramWinget {
<# <#
.SYNOPSIS .SYNOPSIS
Runs the designated action on the provided programs using Winget Runs the designated action on the provided programs using Winget

View File

@ -13,6 +13,16 @@ Function Invoke-WinUtilCurrentSystem {
param( param(
$CheckBox $CheckBox
) )
if ($CheckBox -eq "choco") {
$apps = (choco list | Select-String -Pattern "^\S+").Matches.Value
$filter = Get-WinUtilVariables -Type Checkbox | Where-Object {$psitem -like "WPFInstall*"}
$sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} | ForEach-Object {
$dependencies = @($sync.configs.applications.$($psitem.Key).choco -split ";")
if ($dependencies -in $apps) {
Write-Output $psitem.name
}
}
}
if ($checkbox -eq "winget") { if ($checkbox -eq "winget") {

View File

@ -1,6 +1,6 @@
function Invoke-WPFGetInstalled { function Invoke-WPFGetInstalled {
<# <#
TODO: Add the Option to use Chocolatey as Engine
.SYNOPSIS .SYNOPSIS
Invokes the function that gets the checkboxes to check in a new runspace Invokes the function that gets the checkboxes to check in a new runspace
@ -16,12 +16,12 @@ function Invoke-WPFGetInstalled {
return return
} }
if(((Test-WinUtilPackageManager -winget) -eq "not-installed") -and $checkbox -eq "winget") { if(($sync.WPFpreferChocolatey.IsChecked -eq $false) -and ((Test-WinUtilPackageManager -winget) -eq "not-installed") -and $checkbox -eq "winget") {
return return
} }
$preferChoco = $sync.WPFpreferChocolatey.IsChecked
Invoke-WPFRunspace -ArgumentList $checkbox -DebugPreference $DebugPreference -ScriptBlock { Invoke-WPFRunspace -ArgumentList $checkbox, $preferChoco -DebugPreference $DebugPreference -ScriptBlock {
param($checkbox, $DebugPreference) param($checkbox, $preferChoco, $DebugPreference)
$sync.ProcessRunning = $true $sync.ProcessRunning = $true
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" }) $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" })
@ -32,8 +32,12 @@ function Invoke-WPFGetInstalled {
if($checkbox -eq "tweaks") { if($checkbox -eq "tweaks") {
Write-Host "Getting Installed Tweaks..." Write-Host "Getting Installed Tweaks..."
} }
if ($preferChoco -and $checkbox -eq "winget") {
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox $Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox "choco"
}
else{
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox
}
$sync.form.Dispatcher.invoke({ $sync.form.Dispatcher.invoke({
foreach($checkbox in $Checkboxes) { foreach($checkbox in $Checkboxes) {

View File

@ -19,10 +19,9 @@ function Invoke-WPFInstall {
[System.Windows.MessageBox]::Show($WarningMsg, $AppTitle, [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) [System.Windows.MessageBox]::Show($WarningMsg, $AppTitle, [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
return return
} }
$ChocoPreference = $($sync.WPFpreferChocolatey.IsChecked)
Invoke-WPFRunspace -ArgumentList $PackagesToInstall,$ChocoPreference -DebugPreference $DebugPreference -ScriptBlock {
Invoke-WPFRunspace -ArgumentList $PackagesToInstall -DebugPreference $DebugPreference -ScriptBlock { param($PackagesToInstall, $ChocoPreference, $DebugPreference)
param($PackagesToInstall, $DebugPreference)
if ($PackagesToInstall.count -eq 1) { if ($PackagesToInstall.count -eq 1) {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" }) $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" })
} else { } else {
@ -30,17 +29,29 @@ function Invoke-WPFInstall {
} }
$packagesWinget, $packagesChoco = { $packagesWinget, $packagesChoco = {
$packagesWinget = [System.Collections.ArrayList]::new() $packagesWinget = [System.Collections.ArrayList]::new()
$packagesChoco = [System.Collections.Generic.List`1[System.Object]]::new() $packagesChoco = [System.Collections.ArrayList]::new()
foreach ($package in $PackagesToInstall) {
foreach ($package in $PackagesToInstall) {
if ($ChocoPreference) {
if ($package.choco -eq "na") {
$packagesWinget.add($package.winget)
Write-Host "Queueing $($package.winget) for Winget install"
} else {
$null = $packagesChoco.add($package.choco)
Write-Host "Queueing $($package.choco) for Chocolatey install"
}
}
else {
if ($package.winget -eq "na") { if ($package.winget -eq "na") {
$packagesChoco.add($package) $packagesChoco.add($package.choco)
Write-Host "Queueing $($package.choco) for Chocolatey install" Write-Host "Queueing $($package.choco) for Chocolatey install"
} else { } else {
$null = $packagesWinget.add($($package.winget)) $null = $packagesWinget.add($($package.winget))
Write-Host "Queueing $($package.winget) for Winget install" Write-Host "Queueing $($package.winget) for Winget install"
} }
} }
return $packagesWinget, $packagesChoco }
return $packagesWinget, $packagesChoco
}.Invoke($PackagesToInstall) }.Invoke($PackagesToInstall)
try { try {
@ -48,12 +59,12 @@ function Invoke-WPFInstall {
$errorPackages = @() $errorPackages = @()
if($packagesWinget.Count -gt 0) { if($packagesWinget.Count -gt 0) {
Install-WinUtilWinget Install-WinUtilWinget
$errorPackages += Invoke-WinUtilWingetProgram -Action Install -Programs $packagesWinget Install-WinUtilProgramWinget -Action Install -Programs $packagesWinget
$errorPackages| ForEach-Object {if($_.choco -ne "na") {$packagesChoco += $_}}
} }
if($packagesChoco.Count -gt 0) { if($packagesChoco.Count -gt 0) {
Install-WinUtilChoco Install-WinUtilChoco
Install-WinUtilProgramChoco -ProgramsToInstall $packagesChoco Install-WinUtilProgramChoco -Action Install -Programs $packagesChoco
} }
Write-Host "===========================================" Write-Host "==========================================="
Write-Host "-- Installs have finished ---" Write-Host "-- Installs have finished ---"

View File

@ -2,25 +2,35 @@ function Invoke-WPFInstallUpgrade {
<# <#
.SYNOPSIS .SYNOPSIS
Invokes the function that upgrades all installed programs using winget Invokes the function that upgrades all installed programs
#> #>
if((Test-WinUtilPackageManager -winget) -eq "not-installed") { if ($sync.WPFpreferChocolatey.IsChecked) {
return Install-WinUtilChoco
$chocoUpgradeStatus = (Start-Process "choco" -ArgumentList "upgrade all -y" -Wait -PassThru -NoNewWindow).ExitCode
if ($chocoUpgradeStatus -eq 0) {
Write-Host "Upgrade Successful"
}
else{
Write-Host "Error Occured. Return Code: $chocoUpgradeStatus"
}
} }
else{
if((Test-WinUtilPackageManager -winget) -eq "not-installed") {
return
}
if(Get-WinUtilInstallerProcess -Process $global:WinGetInstall) { if(Get-WinUtilInstallerProcess -Process $global:WinGetInstall) {
$msg = "[Invoke-WPFInstallUpgrade] Install process is currently running. Please check for a powershell window labeled 'Winget Install'" $msg = "[Invoke-WPFInstallUpgrade] Install process is currently running. Please check for a powershell window labeled 'Winget Install'"
[System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
return return
}
Update-WinUtilProgramWinget
Write-Host "==========================================="
Write-Host "-- Updates started ---"
Write-Host "-- You can close this window if desired ---"
Write-Host "==========================================="
} }
# Set-WinUtilTaskbaritem -state "Indeterminate"
Update-WinUtilProgramWinget
Write-Host "==========================================="
Write-Host "-- Updates started ---"
Write-Host "-- You can close this window if desired ---"
Write-Host "==========================================="
} }

View File

@ -30,7 +30,9 @@ function Invoke-WPFRunspace {
# Add Scriptblock and Arguments to runspace # Add Scriptblock and Arguments to runspace
$script:powershell.AddScript($ScriptBlock) $script:powershell.AddScript($ScriptBlock)
$script:powershell.AddArgument($ArgumentList) foreach ($Argument in $ArgumentList) {
$script:powershell.AddArgument($Argument)
}
$script:powershell.AddArgument($DebugPreference) # Pass DebugPreference to the script block $script:powershell.AddArgument($DebugPreference) # Pass DebugPreference to the script block
$script:powershell.RunspacePool = $sync.runspace $script:powershell.RunspacePool = $sync.runspace

View File

@ -17,7 +17,7 @@ function Invoke-WPFTweakPS7{
Write-Host "Powershell 7 is already installed." Write-Host "Powershell 7 is already installed."
} else { } else {
Write-Host "Installing Powershell 7..." Write-Host "Installing Powershell 7..."
Invoke-WinUtilWingetProgram -Action Install -Programs @("Microsoft.PowerShell") Install-WinUtilProgramWinget -Action Install -Programs @("Microsoft.PowerShell")
} }
$targetTerminalName = "PowerShell" $targetTerminalName = "PowerShell"
} }

View File

@ -28,38 +28,51 @@ function Invoke-WPFUnInstall {
$confirm = [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon) $confirm = [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon)
if($confirm -eq "No") {return} if($confirm -eq "No") {return}
$ChocoPreference = $($sync.WPFpreferChocolatey.IsChecked)
Invoke-WPFRunspace -ArgumentList $PackagesToInstall, $ChocoPreference -DebugPreference $DebugPreference -ScriptBlock {
Invoke-WPFRunspace -ArgumentList $PackagesToInstall -DebugPreference $DebugPreference -ScriptBlock { param($PackagesToInstall, $ChocoPreference, $DebugPreference)
param($PackagesToInstall, $DebugPreference)
if ($PackagesToInstall.count -eq 1) { if ($PackagesToInstall.count -eq 1) {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" }) $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" })
} else { } else {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" }) $sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" })
} }
$packagesWinget, $packagesChoco = { $packagesWinget, $packagesChoco = {
$packagesWinget = [System.Collections.Generic.List`1[System.Object]]::new() $packagesWinget = [System.Collections.ArrayList]::new()
$packagesChoco = [System.Collections.Generic.List`1[System.Object]]::new() $packagesChoco = [System.Collections.ArrayList]::new()
foreach ($package in $PackagesToInstall) {
if ($package.winget -eq "na") { foreach ($package in $PackagesToInstall) {
$packagesChoco.add($package) if ($ChocoPreference) {
Write-Host "Queueing $($package.choco) for Chocolatey Uninstall" if ($package.choco -eq "na") {
$packagesWinget.add($package.winget)
Write-Host "Queueing $($package.winget) for Winget uninstall"
} else { } else {
$packagesWinget.add($($package.winget)) $null = $packagesChoco.add($package.choco)
Write-Host "Queueing $($package.winget) for Winget Uninstall" Write-Host "Queueing $($package.choco) for Chocolatey uninstall"
} }
} }
return $packagesWinget, $packagesChoco else {
if ($package.winget -eq "na") {
$packagesChoco.add($package.choco)
Write-Host "Queueing $($package.choco) for Chocolatey uninstall"
} else {
$null = $packagesWinget.add($($package.winget))
Write-Host "Queueing $($package.winget) for Winget uninstall"
}
}
}
return $packagesWinget, $packagesChoco
}.Invoke($PackagesToInstall) }.Invoke($PackagesToInstall)
try { try {
$sync.ProcessRunning = $true $sync.ProcessRunning = $true
# Install all selected programs in new window # Install all selected programs in new window
if($packagesWinget.Count -gt 0) { if($packagesWinget.Count -gt 0) {
Invoke-WinUtilWingetProgram -Action Uninstall -Programs $packagesWinget Install-WinUtilProgramWinget -Action Uninstall -Programs $packagesWinget
} }
if($packagesChoco.Count -gt 0) { if($packagesChoco.Count -gt 0) {
Install-WinUtilProgramChoco -ProgramsToInstall $packagesChoco -Manage "Uninstalling" Install-WinUtilProgramChoco -Action Uninstall -Programs $packagesChoco
} }
Write-Host "===========================================" Write-Host "==========================================="

View File

@ -116,6 +116,14 @@ Invoke-WPFUIElements -configVariable $sync.configs.feature -targetGridName "feat
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {$sync["$("$($psitem.Name)")"] = $sync["Form"].FindName($psitem.Name)} $xaml.SelectNodes("//*[@Name]") | ForEach-Object {$sync["$("$($psitem.Name)")"] = $sync["Form"].FindName($psitem.Name)}
#Persist the Chocolatey preference across winutil restarts
$ChocoPreferencePath = "$env:LOCALAPPDATA\winutil\preferChocolatey.ini"
$sync.WPFpreferChocolatey.Add_Checked({New-Item -Path $ChocoPreferencePath -Force })
$sync.WPFpreferChocolatey.Add_Unchecked({Remove-Item $ChocoPreferencePath -Force})
if (Test-Path $ChocoPreferencePath) {
$sync.WPFpreferChocolatey.IsChecked = $true
}
$sync.keys | ForEach-Object { $sync.keys | ForEach-Object {
if($sync.$psitem) { if($sync.$psitem) {
if($($sync["$psitem"].GetType() | Select-Object -ExpandProperty Name) -eq "ToggleButton") { if($($sync["$psitem"].GetType() | Select-Object -ExpandProperty Name) -eq "ToggleButton") {

View File

@ -833,6 +833,9 @@
<Button Name="WPFUninstall" Content=" Uninstall Selected" Margin="2"/> <Button Name="WPFUninstall" Content=" Uninstall Selected" Margin="2"/>
<Button Name="WPFGetInstalled" Content=" Get Installed" Margin="2"/> <Button Name="WPFGetInstalled" Content=" Get Installed" Margin="2"/>
<Button Name="WPFClearInstallSelection" Content=" Clear Selection" Margin="2"/> <Button Name="WPFClearInstallSelection" Content=" Clear Selection" Margin="2"/>
<CheckBox Name="WPFpreferChocolatey" VerticalAlignment="Center" VerticalContentAlignment="Center">
<TextBlock Text="Prefer Chocolatey" ToolTip="Prefers Chocolatey as Download Engine instead of Winget" VerticalAlignment="Center" />
</CheckBox>
</StackPanel> </StackPanel>
<ScrollViewer x:Name="scrollViewer" Grid.Row="1" Grid.Column="0" Margin="{TabContentMargin}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" <ScrollViewer x:Name="scrollViewer" Grid.Row="1" Grid.Column="0" Margin="{TabContentMargin}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"