mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-08-10 01:51:18 +10:00
Compare commits
8
Commits
51cb3811dd
...
26.07.17
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c104d02e2 | ||
|
|
06f33e88ba | ||
|
|
b9dee86694 | ||
|
|
3d1904ebbe | ||
|
|
70f1c50bdd | ||
|
|
2e5df82979 | ||
|
|
29595f90e2 | ||
|
|
9ed06e793a |
@@ -1,4 +1,4 @@
|
|||||||
name: Auto-merge Docs PRs
|
name: Auto-merge Automated Update PRs
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -8,7 +8,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
auto-merge:
|
auto-merge:
|
||||||
if: github.event.pull_request.head.ref == 'docs-update' && (github.event.pull_request.user.login == 'ChrisTitusTech' || github.event.pull_request.user.login == 'github-actions[bot]')
|
if: (github.event.pull_request.head.ref == 'docs-update' || github.event.pull_request.head.ref == 'sponsors-update') && (github.event.pull_request.user.login == 'ChrisTitusTech' || github.event.pull_request.user.login == 'github-actions[bot]')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|||||||
@@ -109,6 +109,21 @@ jobs:
|
|||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
version: ${{ env.VERSION }}
|
version: ${{ env.VERSION }}
|
||||||
|
|
||||||
|
- name: Remove Automated Updates from Release Notes
|
||||||
|
id: filter_notes
|
||||||
|
shell: pwsh
|
||||||
|
env:
|
||||||
|
RELEASE_NOTES: ${{ steps.generate_notes.outputs.body }}
|
||||||
|
run: |
|
||||||
|
$filteredNotes = ($env:RELEASE_NOTES -split '\r?\n' | Where-Object {
|
||||||
|
$_ -notmatch '(?i)Update (Generated Dev Docs|Sponsors)'
|
||||||
|
}) -join "`n"
|
||||||
|
|
||||||
|
$delimiter = [guid]::NewGuid().ToString()
|
||||||
|
"body<<$delimiter" >> $env:GITHUB_OUTPUT
|
||||||
|
$filteredNotes >> $env:GITHUB_OUTPUT
|
||||||
|
$delimiter >> $env:GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Create and Upload Release
|
- name: Create and Upload Release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: softprops/action-gh-release@v3
|
uses: softprops/action-gh-release@v3
|
||||||
@@ -116,7 +131,7 @@ jobs:
|
|||||||
tag_name: ${{ env.VERSION }}
|
tag_name: ${{ env.VERSION }}
|
||||||
name: Pre-Release ${{ env.VERSION }}
|
name: Pre-Release ${{ env.VERSION }}
|
||||||
body: |
|
body: |
|
||||||
${{ steps.generate_notes.outputs.body }}
|
${{ steps.filter_notes.outputs.body }}
|
||||||
|
|
||||||

|

|
||||||
append_body: false
|
append_body: false
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
id: cpr
|
id: cpr
|
||||||
uses: peter-evans/create-pull-request@v8
|
uses: peter-evans/create-pull-request@v8
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.AUTO_MERGE }}
|
||||||
commit-message: 'Update sponsors in README'
|
commit-message: 'Update sponsors in README'
|
||||||
title: 'chore: Update Sponsors README'
|
title: 'chore: Update Sponsors README'
|
||||||
body: 'Automated update of sponsors section'
|
body: 'Automated update of sponsors section'
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ See https://github.com/ChrisTitusTech/winutil/blob/main/.github/CONTRIBUTING.md
|
|||||||
|
|
||||||
These are the sponsors that help keep this project alive with monthly contributions.
|
These are the sponsors that help keep this project alive with monthly contributions.
|
||||||
|
|
||||||
<!-- sponsors --><a href="https://github.com/ysaito8015"><img src="https://github.com/ysaito8015.png" width="60px" alt="User avatar: Yusuke Saito" /></a><a href="https://github.com/dwelfusius"><img src="https://github.com/dwelfusius.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/mews-se"><img src="https://github.com/mews-se.png" width="60px" alt="User avatar: Martin Stockzell" /></a><a href="https://github.com/jdiegmueller"><img src="https://github.com/jdiegmueller.png" width="60px" alt="User avatar: Jason A. Diegmueller" /></a><a href="https://github.com/robertsandrock"><img src="https://github.com/robertsandrock.png" width="60px" alt="User avatar: RMS" /></a><a href="https://github.com/paulsheets"><img src="https://github.com/paulsheets.png" width="60px" alt="User avatar: Paul" /></a><a href="https://github.com/djones369"><img src="https://github.com/djones369.png" width="60px" alt="User avatar: Dave J (WhamGeek)" /></a><a href="https://github.com/anthonymendez"><img src="https://github.com/anthonymendez.png" width="60px" alt="User avatar: Anthony Mendez" /></a><a href="https://github.com/FatBastard0"><img src="https://github.com/FatBastard0.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/DursleyGuy"><img src="https://github.com/DursleyGuy.png" width="60px" alt="User avatar: DursleyGuy" /></a><a href="https://github.com/DwayneTheRockLobster1"><img src="https://github.com/DwayneTheRockLobster1.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/KieraKujisawa"><img src="https://github.com/KieraKujisawa.png" width="60px" alt="User avatar: Kiera Meredith" /></a><a href="https://github.com/andrewpayne68"><img src="https://github.com/andrewpayne68.png" width="60px" alt="User avatar: Andrew P" /></a><a href="https://github.com/johanwildeboer"><img src="https://github.com/johanwildeboer.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/lukas346"><img src="https://github.com/lukas346.png" width="60px" alt="User avatar: Wook" /></a><a href="https://github.com/tsv31"><img src="https://github.com/tsv31.png" width="60px" alt="User avatar: Sorin" /></a><!-- sponsors -->
|
<!-- sponsors --><a href="https://github.com/ysaito8015"><img src="https://github.com/ysaito8015.png" width="60px" alt="User avatar: Yusuke Saito" /></a><a href="https://github.com/dwelfusius"><img src="https://github.com/dwelfusius.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/mews-se"><img src="https://github.com/mews-se.png" width="60px" alt="User avatar: Martin Stockzell" /></a><a href="https://github.com/jdiegmueller"><img src="https://github.com/jdiegmueller.png" width="60px" alt="User avatar: Jason A. Diegmueller" /></a><a href="https://github.com/robertsandrock"><img src="https://github.com/robertsandrock.png" width="60px" alt="User avatar: RMS" /></a><a href="https://github.com/paulsheets"><img src="https://github.com/paulsheets.png" width="60px" alt="User avatar: Paul" /></a><a href="https://github.com/djones369"><img src="https://github.com/djones369.png" width="60px" alt="User avatar: Dave J (WhamGeek)" /></a><a href="https://github.com/anthonymendez"><img src="https://github.com/anthonymendez.png" width="60px" alt="User avatar: Anthony Mendez" /></a><a href="https://github.com/FatBastard0"><img src="https://github.com/FatBastard0.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/DursleyGuy"><img src="https://github.com/DursleyGuy.png" width="60px" alt="User avatar: DursleyGuy" /></a><a href="https://github.com/DwayneTheRockLobster1"><img src="https://github.com/DwayneTheRockLobster1.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/KieraKujisawa"><img src="https://github.com/KieraKujisawa.png" width="60px" alt="User avatar: Kiera Meredith" /></a><a href="https://github.com/andrewpayne68"><img src="https://github.com/andrewpayne68.png" width="60px" alt="User avatar: Andrew P" /></a><a href="https://github.com/johanwildeboer"><img src="https://github.com/johanwildeboer.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/lukas346"><img src="https://github.com/lukas346.png" width="60px" alt="User avatar: Wook" /></a><a href="https://github.com/tsv31"><img src="https://github.com/tsv31.png" width="60px" alt="User avatar: Sorin" /></a><a href="https://github.com/seanh1995"><img src="https://github.com/seanh1995.png" width="60px" alt="User avatar: Sean (ANGRYxScotsman)" /></a><!-- sponsors -->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@
|
|||||||
"AppInstallUnselectedColor": "#F7F7F7",
|
"AppInstallUnselectedColor": "#F7F7F7",
|
||||||
"AppInstallHighlightedColor": "#CFCFCF",
|
"AppInstallHighlightedColor": "#CFCFCF",
|
||||||
"AppInstallSelectedColor": "#C2C2C2",
|
"AppInstallSelectedColor": "#C2C2C2",
|
||||||
"AppInstallOverlayBackgroundColor": "#6A6D72",
|
|
||||||
"ComboBoxForegroundColor": "#232629",
|
"ComboBoxForegroundColor": "#232629",
|
||||||
"ComboBoxBackgroundColor": "#F7F7F7",
|
"ComboBoxBackgroundColor": "#F7F7F7",
|
||||||
"LabelboxForegroundColor": "#232629",
|
"LabelboxForegroundColor": "#232629",
|
||||||
@@ -60,7 +59,6 @@
|
|||||||
"ScrollBarDraggingColor": "#6A6D72",
|
"ScrollBarDraggingColor": "#6A6D72",
|
||||||
"ProgressBarForegroundColor": "#2E77FF",
|
"ProgressBarForegroundColor": "#2E77FF",
|
||||||
"ProgressBarBackgroundColor": "Transparent",
|
"ProgressBarBackgroundColor": "Transparent",
|
||||||
"ProgressBarTextColor": "#232629",
|
|
||||||
"ButtonInstallBackgroundColor": "#F7F7F7",
|
"ButtonInstallBackgroundColor": "#F7F7F7",
|
||||||
"ButtonTweaksBackgroundColor": "#F7F7F7",
|
"ButtonTweaksBackgroundColor": "#F7F7F7",
|
||||||
"ButtonConfigBackgroundColor": "#F7F7F7",
|
"ButtonConfigBackgroundColor": "#F7F7F7",
|
||||||
@@ -88,7 +86,6 @@
|
|||||||
"AppInstallUnselectedColor": "#232629",
|
"AppInstallUnselectedColor": "#232629",
|
||||||
"AppInstallHighlightedColor": "#3C3C3C",
|
"AppInstallHighlightedColor": "#3C3C3C",
|
||||||
"AppInstallSelectedColor": "#4C4C4C",
|
"AppInstallSelectedColor": "#4C4C4C",
|
||||||
"AppInstallOverlayBackgroundColor": "#2E3135",
|
|
||||||
"ComboBoxForegroundColor": "#F7F7F7",
|
"ComboBoxForegroundColor": "#F7F7F7",
|
||||||
"ComboBoxBackgroundColor": "#1E3747",
|
"ComboBoxBackgroundColor": "#1E3747",
|
||||||
"LabelboxForegroundColor": "#5BDCFF",
|
"LabelboxForegroundColor": "#5BDCFF",
|
||||||
@@ -102,7 +99,6 @@
|
|||||||
"ScrollBarDraggingColor": "#5E81AC",
|
"ScrollBarDraggingColor": "#5E81AC",
|
||||||
"ProgressBarForegroundColor": "#6EFF72",
|
"ProgressBarForegroundColor": "#6EFF72",
|
||||||
"ProgressBarBackgroundColor": "Transparent",
|
"ProgressBarBackgroundColor": "Transparent",
|
||||||
"ProgressBarTextColor": "#232629",
|
|
||||||
"ButtonInstallBackgroundColor": "#222222",
|
"ButtonInstallBackgroundColor": "#222222",
|
||||||
"ButtonTweaksBackgroundColor": "#333333",
|
"ButtonTweaksBackgroundColor": "#333333",
|
||||||
"ButtonConfigBackgroundColor": "#444444",
|
"ButtonConfigBackgroundColor": "#444444",
|
||||||
|
|||||||
@@ -5,15 +5,53 @@ description: ""
|
|||||||
|
|
||||||
```powershell {filename="functions/public/Invoke-WPFOOSU.ps1",linenos=inline,linenostart=1}
|
```powershell {filename="functions/public/Invoke-WPFOOSU.ps1",linenos=inline,linenostart=1}
|
||||||
function Invoke-WPFOOSU {
|
function Invoke-WPFOOSU {
|
||||||
try {
|
if ($sync.ProcessRunning) {
|
||||||
$ProgressPreference = 'SilentlyContinue'
|
Show-WinUtilMessage -Message "Another process is currently running." -Title "WinUtil" -Button "OK" -Icon "Warning"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
Invoke-WebRequest -Uri https://dl5.oo-software.com/files/ooshutup10/OOSU10.exe -OutFile "$winutildir\ooshutup10.exe"
|
$downloadPath = Join-Path $sync.winutildir "ooshutup10.exe"
|
||||||
Start-Process -FilePath "$winutildir\ooshutup10.exe"
|
$sync.ProcessRunning = $true
|
||||||
|
|
||||||
$ProgressPreference = 'Continue'
|
Invoke-WPFRunspace -ParameterList @(,("downloadPath", $downloadPath)) -ScriptBlock {
|
||||||
} catch {
|
param($downloadPath)
|
||||||
Write-Error "Couldn't download O&O ShutUp10. Please make sure you have an active Internet connection."
|
|
||||||
|
$hasUI = $null -ne $sync.Form -and $null -ne $sync.Form.Dispatcher
|
||||||
|
|
||||||
|
try {
|
||||||
|
Write-WinUtilLog -Component "OOSU" -Message "Downloading O&O ShutUp10++."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Downloading O&O ShutUp10++ (0%)" -Percent 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Save-WinUtilFile -Uri "https://dl5.oo-software.com/files/ooshutup10/OOSU10.exe" -DestinationPath $downloadPath -ProgressCallback {
|
||||||
|
param($percent)
|
||||||
|
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Downloading O&O ShutUp10++ ($percent%)" -Percent $percent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Launching O&O ShutUp10++" -Percent 100
|
||||||
|
}
|
||||||
|
Start-Process -FilePath $downloadPath
|
||||||
|
|
||||||
|
Write-WinUtilLog -Component "OOSU" -Message "O&O ShutUp10++ launched."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "O&O ShutUp10++ launched" -Percent 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-WinUtilLog -Level "ERROR" -Component "OOSU" -Message "O&O ShutUp10++ download failed: $($_.Exception.Message)"
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "O&O ShutUp10++ download failed" -Percent 100
|
||||||
|
}
|
||||||
|
Write-Error "Couldn't download O&O ShutUp10. Please make sure you have an active Internet connection."
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$sync.ProcessRunning = $false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ For a better Windows experience with minimal risk:
|
|||||||
|
|
||||||
1. Check multiple application boxes
|
1. Check multiple application boxes
|
||||||
2. All checked apps will install in sequence
|
2. All checked apps will install in sequence
|
||||||
3. Progress is shown in the bottom panel
|
3. Install and uninstall progress is shown in the window-level bottom panel, including the current package or package-manager batch and overall completion
|
||||||
|
|
||||||
### Applying Tweaks
|
### Applying Tweaks
|
||||||
|
|
||||||
|
|||||||
@@ -9,28 +9,30 @@ WinUtil provides three update modes so you can choose how aggressively Windows U
|
|||||||
|
|
||||||
Changing modes adjusts system-wide Windows Update behavior. After switching modes, give Windows a moment to apply the policy and plan for a restart if the new state does not appear immediately.
|
Changing modes adjusts system-wide Windows Update behavior. After switching modes, give Windows a moment to apply the policy and plan for a restart if the new state does not appear immediately.
|
||||||
|
|
||||||
{{< image src="images/updates-tab-new" alt="Updates tab in WinUtil" >}}
|
- **Recommended**: Prioritizes stability while still receiving security updates
|
||||||
|
- **Windows Default**: Restores standard Windows Update behavior
|
||||||
|
- **Disable Updates**: Blocks Windows Update and should only be used with extreme caution
|
||||||
|
|
||||||
- **Default (Out of the Box) Settings**: Restores standard Windows Update behavior
|
### Windows Default
|
||||||
- **Security (Recommended) Settings**: Prioritizes stability while still receiving security updates
|
|
||||||
- **Disable ALL Updates**: Turns off Windows Update entirely and should only be used with extreme caution
|
|
||||||
|
|
||||||
### Default (Out of Box) Settings
|
- **What it does**: Removes Windows Update policies managed by WinUtil, restores update service startup settings, and re-enables update scheduled tasks.
|
||||||
|
|
||||||
- **What it does**: Restores the default Windows Update configuration.
|
|
||||||
- **Best for**: Systems where you want Windows to manage updates normally.
|
- **Best for**: Systems where you want Windows to manage updates normally.
|
||||||
- **Notes**: This removes custom update settings previously applied by WinUtil. If update errors continue, use the reset option in the **Config** tab to restore Microsoft Update services to their default state.
|
- **Notes**: Only values managed by WinUtil are removed; other Windows Update policies are left in place. If update errors continue, use the reset option in the **Config** tab to repair Microsoft Update components.
|
||||||
|
|
||||||
### Security (Recommended) Settings
|
### Recommended
|
||||||
|
|
||||||
- **What it does**: Applies a more conservative update strategy designed for most users.
|
- **What it does**: Applies a more conservative update strategy designed for most users.
|
||||||
- **Feature updates**: Delayed by **365 days** to reduce the chance of disruption from major Windows changes.
|
- **Feature updates**: Delayed by **365 days** to reduce the chance of disruption from major Windows changes.
|
||||||
- **Security updates**: Delayed by **4 days** to allow time for early issues to surface while still keeping the system protected.
|
- **Quality updates**: Delayed by **4 days** to allow time for early issues to surface while still keeping the system protected.
|
||||||
|
- **Drivers**: Excluded from Windows quality updates.
|
||||||
|
- **Restarts**: Scheduled updates do not automatically restart Windows while a user is signed in. A restart explicitly scheduled by a user still takes precedence.
|
||||||
|
- **Availability**: Update deferral policies apply to Windows Pro, Enterprise, and Education editions.
|
||||||
- **Why use it**: This mode offers the best balance between security and stability, which is why it is the recommended option for most PCs.
|
- **Why use it**: This mode offers the best balance between security and stability, which is why it is the recommended option for most PCs.
|
||||||
|
|
||||||
### Disable ALL Updates (NOT RECOMMENDED!)
|
### Disable Updates (NOT RECOMMENDED!)
|
||||||
|
|
||||||
- **What it does**: Disables all Windows updates.
|
- **What it does**: Disables automatic update policy, stops and disables update services, disables update scheduled tasks, and clears downloaded update files.
|
||||||
- **Best for**: Highly controlled or special-purpose systems where updates must remain off temporarily.
|
- **Best for**: Highly controlled or special-purpose systems where updates must remain off temporarily.
|
||||||
- **Warning**: This leaves the system without security patches and significantly increases security risk.
|
- **Warning**: This leaves the system without security patches and significantly increases security risk.
|
||||||
|
- **Notes**: Windows servicing can restore update components in some circumstances. Use **Restore Defaults** when you are ready to receive updates again.
|
||||||
- **Recommendation**: Avoid this mode unless you fully understand the tradeoffs and have a specific reason to use it.
|
- **Recommendation**: Avoid this mode unless you fully understand the tradeoffs and have a specific reason to use it.
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
function Hide-WPFInstallAppBusy {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Hides the busy overlay in the install app area of the WPF form.
|
|
||||||
This is used to indicate that an install or uninstall has finished.
|
|
||||||
#>
|
|
||||||
Invoke-WPFUIThread -ScriptBlock {
|
|
||||||
$sync.InstallAppAreaOverlay.Visibility = [Windows.Visibility]::Collapsed
|
|
||||||
$sync.InstallAppAreaBorder.IsEnabled = $true
|
|
||||||
$sync.InstallAppAreaScrollViewer.Effect.Radius = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,8 +5,6 @@
|
|||||||
This is used as the parent object for all category and app entries on the install tab
|
This is used as the parent object for all category and app entries on the install tab
|
||||||
Used to as part of the Install Tab UI generation
|
Used to as part of the Install Tab UI generation
|
||||||
|
|
||||||
Also creates an overlay with a progress bar and text to indicate that an install or uninstall is in progress
|
|
||||||
|
|
||||||
.PARAMETER TargetElement
|
.PARAMETER TargetElement
|
||||||
The element to which the AppArea should be added
|
The element to which the AppArea should be added
|
||||||
|
|
||||||
@@ -19,22 +17,14 @@
|
|||||||
$Border = New-Object Windows.Controls.Border
|
$Border = New-Object Windows.Controls.Border
|
||||||
$Border.VerticalAlignment = "Stretch"
|
$Border.VerticalAlignment = "Stretch"
|
||||||
$Border.SetResourceReference([Windows.Controls.Control]::StyleProperty, "BorderStyle")
|
$Border.SetResourceReference([Windows.Controls.Control]::StyleProperty, "BorderStyle")
|
||||||
$sync.InstallAppAreaBorder = $Border
|
|
||||||
|
|
||||||
# Add a ScrollViewer, because the ItemsControl does not support scrolling by itself
|
# Add a ScrollViewer, because the ItemsControl does not support scrolling by itself
|
||||||
$scrollViewer = New-Object Windows.Controls.ScrollViewer
|
$scrollViewer = New-Object Windows.Controls.ScrollViewer
|
||||||
$scrollViewer.VerticalScrollBarVisibility = 'Auto'
|
$scrollViewer.VerticalScrollBarVisibility = 'Auto'
|
||||||
$scrollViewer.HorizontalAlignment = 'Stretch'
|
$scrollViewer.HorizontalAlignment = 'Stretch'
|
||||||
$scrollViewer.VerticalAlignment = 'Stretch'
|
$scrollViewer.VerticalAlignment = 'Stretch'
|
||||||
$scrollViewer.CanContentScroll = $true
|
$scrollViewer.CanContentScroll = $true
|
||||||
$sync.InstallAppAreaScrollViewer = $scrollViewer
|
|
||||||
$Border.Child = $scrollViewer
|
$Border.Child = $scrollViewer
|
||||||
|
|
||||||
# Initialize the Blur Effect for the ScrollViewer, which will be used to indicate that an install/uninstall is in progress
|
|
||||||
$blurEffect = New-Object Windows.Media.Effects.BlurEffect
|
|
||||||
$blurEffect.Radius = 0
|
|
||||||
$scrollViewer.Effect = $blurEffect
|
|
||||||
|
|
||||||
## Create the ItemsControl, which will be the parent of all the app entries
|
## Create the ItemsControl, which will be the parent of all the app entries
|
||||||
$itemsControl = New-Object Windows.Controls.ItemsControl
|
$itemsControl = New-Object Windows.Controls.ItemsControl
|
||||||
$itemsControl.HorizontalAlignment = 'Stretch'
|
$itemsControl.HorizontalAlignment = 'Stretch'
|
||||||
@@ -52,61 +42,5 @@
|
|||||||
# Add the Border containing the App Area to the target Grid
|
# Add the Border containing the App Area to the target Grid
|
||||||
$targetGrid.Children.Add($Border) | Out-Null
|
$targetGrid.Children.Add($Border) | Out-Null
|
||||||
|
|
||||||
$overlay = New-Object Windows.Controls.Border
|
|
||||||
$overlay.CornerRadius = New-Object Windows.CornerRadius(10)
|
|
||||||
$overlay.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallOverlayBackgroundColor")
|
|
||||||
$overlay.Visibility = [Windows.Visibility]::Collapsed
|
|
||||||
|
|
||||||
# Also add the overlay to the target Grid on top of the App Area
|
|
||||||
$targetGrid.Children.Add($overlay) | Out-Null
|
|
||||||
$sync.InstallAppAreaOverlay = $overlay
|
|
||||||
|
|
||||||
$overlayText = New-Object Windows.Controls.TextBlock
|
|
||||||
$overlayText.Text = "Installing apps..."
|
|
||||||
$overlayText.HorizontalAlignment = 'Center'
|
|
||||||
$overlayText.VerticalAlignment = 'Center'
|
|
||||||
$overlayText.SetResourceReference([Windows.Controls.TextBlock]::ForegroundProperty, "MainForegroundColor")
|
|
||||||
$overlayText.Background = "Transparent"
|
|
||||||
$overlayText.SetResourceReference([Windows.Controls.TextBlock]::FontSizeProperty, "HeaderFontSize")
|
|
||||||
$overlayText.SetResourceReference([Windows.Controls.TextBlock]::FontFamilyProperty, "MainFontFamily")
|
|
||||||
$overlayText.SetResourceReference([Windows.Controls.TextBlock]::FontWeightProperty, "MainFontWeight")
|
|
||||||
$overlayText.SetResourceReference([Windows.Controls.TextBlock]::MarginProperty, "MainMargin")
|
|
||||||
$sync.InstallAppAreaOverlayText = $overlayText
|
|
||||||
|
|
||||||
$progressbar = New-Object Windows.Controls.ProgressBar
|
|
||||||
$progressbar.Name = "ProgressBar"
|
|
||||||
$progressbar.Width = 250
|
|
||||||
$progressbar.Height = 50
|
|
||||||
$sync.ProgressBar = $progressbar
|
|
||||||
|
|
||||||
# Add a TextBlock overlay for the progress bar text
|
|
||||||
$progressBarTextBlock = New-Object Windows.Controls.TextBlock
|
|
||||||
$progressBarTextBlock.Name = "progressBarTextBlock"
|
|
||||||
$progressBarTextBlock.FontWeight = [Windows.FontWeights]::Bold
|
|
||||||
$progressBarTextBlock.FontSize = 16
|
|
||||||
$progressBarTextBlock.Width = $progressbar.Width
|
|
||||||
$progressBarTextBlock.Height = $progressbar.Height
|
|
||||||
$progressBarTextBlock.SetResourceReference([Windows.Controls.TextBlock]::ForegroundProperty, "ProgressBarTextColor")
|
|
||||||
$progressBarTextBlock.TextTrimming = "CharacterEllipsis"
|
|
||||||
$progressBarTextBlock.Background = "Transparent"
|
|
||||||
$sync.progressBarTextBlock = $progressBarTextBlock
|
|
||||||
|
|
||||||
# Create a Grid to overlay the text on the progress bar
|
|
||||||
$progressGrid = New-Object Windows.Controls.Grid
|
|
||||||
$progressGrid.Width = $progressbar.Width
|
|
||||||
$progressGrid.Height = $progressbar.Height
|
|
||||||
$progressGrid.Margin = "0,10,0,10"
|
|
||||||
$progressGrid.Children.Add($progressbar) | Out-Null
|
|
||||||
$progressGrid.Children.Add($progressBarTextBlock) | Out-Null
|
|
||||||
|
|
||||||
$overlayStackPanel = New-Object Windows.Controls.StackPanel
|
|
||||||
$overlayStackPanel.Orientation = "Vertical"
|
|
||||||
$overlayStackPanel.HorizontalAlignment = 'Center'
|
|
||||||
$overlayStackPanel.VerticalAlignment = 'Center'
|
|
||||||
$overlayStackPanel.Children.Add($overlayText) | Out-Null
|
|
||||||
$overlayStackPanel.Children.Add($progressGrid) | Out-Null
|
|
||||||
|
|
||||||
$overlay.Child = $overlayStackPanel
|
|
||||||
|
|
||||||
return $itemsControl
|
return $itemsControl
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ function Initialize-WinUtilTabContent {
|
|||||||
"AppX" {
|
"AppX" {
|
||||||
Invoke-WPFUIElements -configVariable $sync.configs.appx -targetGridName "appxpanel" -columncount 2
|
Invoke-WPFUIElements -configVariable $sync.configs.appx -targetGridName "appxpanel" -columncount 2
|
||||||
}
|
}
|
||||||
"Win11 Creator" {
|
"Win11ISO" {
|
||||||
if ($sync.Form -and $sync.Form.Dispatcher) {
|
if ($sync.Form -and $sync.Form.Dispatcher) {
|
||||||
$sync.Form.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{ Invoke-WinUtilISOCheckExistingWork }) | Out-Null
|
$sync.Form.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{ Invoke-WinUtilISOCheckExistingWork }) | Out-Null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,32 +15,36 @@ Function Invoke-WinUtilCurrentSystem {
|
|||||||
)
|
)
|
||||||
if ($CheckBox -eq "choco") {
|
if ($CheckBox -eq "choco") {
|
||||||
$apps = (choco list | Select-String -Pattern "^\S+").Matches.Value
|
$apps = (choco list | Select-String -Pattern "^\S+").Matches.Value
|
||||||
$filter = Get-WinUtilVariables -Type Checkbox | Where-Object {$psitem -like "WPFInstall*"}
|
$sync.configs.applicationsHashtable.GetEnumerator() | ForEach-Object {
|
||||||
$sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} | ForEach-Object {
|
$packageId = ($_.Value.choco -split ";")[-1].Trim()
|
||||||
$dependencies = @($sync.configs.applications.$($psitem.Key).choco -split ";")
|
if ($packageId -ne "na" -and $packageId -in $apps) {
|
||||||
if ($dependencies -in $apps) {
|
Write-Output $_.Key
|
||||||
Write-Output $psitem.name
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($checkbox -eq "winget") {
|
if ($checkbox -eq "winget") {
|
||||||
|
|
||||||
$originalEncoding = [Console]::OutputEncoding
|
$originalEncoding = [Console]::OutputEncoding
|
||||||
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
|
try {
|
||||||
$Sync.InstalledPrograms = @("winget", "msstore") | ForEach-Object {
|
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
|
||||||
winget list -s $psitem | Select-Object -skip 3 | ConvertFrom-String -PropertyNames "Name", "Id", "Version", "Available" -Delimiter '\s{2,}'
|
$installedProgramOutput = @(winget list --accept-source-agreements --disable-interactivity 2>&1)
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "winget list failed with exit code $LASTEXITCODE."
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
[Console]::OutputEncoding = $originalEncoding
|
||||||
}
|
}
|
||||||
[Console]::OutputEncoding = $originalEncoding
|
$installedProgramText = $installedProgramOutput -join "`n"
|
||||||
|
|
||||||
$filter = Get-WinUtilVariables -Type Checkbox | Where-Object {$psitem -like "WPFInstall*"}
|
$sync.configs.applicationsHashtable.GetEnumerator() | ForEach-Object {
|
||||||
$sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} | ForEach-Object {
|
$packageId = (($_.Value.winget -split ";")[-1] -replace "^msstore:", "").Trim()
|
||||||
$dependencies = @($sync.configs.applications.$($psitem.Key).winget -split ";") | ForEach-Object {
|
if ([string]::IsNullOrWhiteSpace($packageId) -or $packageId -eq "na") {
|
||||||
$psitem -replace "^msstore:", ""
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($dependencies[-1] -in $sync.InstalledPrograms.Id) {
|
$packagePattern = "(?im)[^\S\r\n]{2,}$([regex]::Escape($packageId))(?=[^\S\r\n]{2,}|$)"
|
||||||
Write-Output $psitem.name
|
if ($installedProgramText -match $packagePattern) {
|
||||||
|
Write-Output $_.Key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Write-Win11ISOLog "Mounting ISO: $isoPath"
|
Write-Win11ISOLog "Mounting ISO: $isoPath"
|
||||||
Set-WinUtilProgressBar -Label "Mounting ISO..." -Percent 10
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Mounting ISO..." -Percent 10
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Mount-DiskImage -ImagePath $isoPath
|
Mount-DiskImage -ImagePath $isoPath
|
||||||
@@ -59,7 +59,7 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
$driveLetter = (Get-DiskImage -ImagePath $isoPath | Get-Volume).DriveLetter + ":"
|
$driveLetter = (Get-DiskImage -ImagePath $isoPath | Get-Volume).DriveLetter + ":"
|
||||||
Write-Win11ISOLog "Mounted at drive $driveLetter"
|
Write-Win11ISOLog "Mounted at drive $driveLetter"
|
||||||
|
|
||||||
Set-WinUtilProgressBar -Label "Verifying ISO contents..." -Percent 30
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Verifying ISO contents..." -Percent 30
|
||||||
|
|
||||||
$wimPath = Join-Path $driveLetter "sources\install.wim"
|
$wimPath = Join-Path $driveLetter "sources\install.wim"
|
||||||
$esdPath = Join-Path $driveLetter "sources\install.esd"
|
$esdPath = Join-Path $driveLetter "sources\install.esd"
|
||||||
@@ -70,13 +70,13 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
[System.Windows.MessageBox]::Show(
|
[System.Windows.MessageBox]::Show(
|
||||||
"This does not appear to be a valid Windows ISO.`n`ninstall.wim / install.esd was not found.",
|
"This does not appear to be a valid Windows ISO.`n`ninstall.wim / install.esd was not found.",
|
||||||
"Invalid ISO", "OK", "Error")
|
"Invalid ISO", "OK", "Error")
|
||||||
Set-WinUtilProgressBar -Label "" -Percent 0
|
Set-WinUtilTweaksProgressIndicator -Visible $false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
$activeWim = if (Test-Path $wimPath) { $wimPath } else { $esdPath }
|
$activeWim = if (Test-Path $wimPath) { $wimPath } else { $esdPath }
|
||||||
|
|
||||||
Set-WinUtilProgressBar -Label "Reading image metadata..." -Percent 55
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Reading image metadata..." -Percent 55
|
||||||
$imageInfo = Get-WindowsImage -ImagePath $activeWim | Select-Object ImageIndex, ImageName
|
$imageInfo = Get-WindowsImage -ImagePath $activeWim | Select-Object ImageIndex, ImageName
|
||||||
|
|
||||||
if (-not ($imageInfo | Where-Object { $_.ImageName -match "Windows 11" })) {
|
if (-not ($imageInfo | Where-Object { $_.ImageName -match "Windows 11" })) {
|
||||||
@@ -85,7 +85,7 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
[System.Windows.MessageBox]::Show(
|
[System.Windows.MessageBox]::Show(
|
||||||
"No Windows 11 edition was found in this ISO.`n`nOnly official Windows 11 ISOs are supported.",
|
"No Windows 11 edition was found in this ISO.`n`nOnly official Windows 11 ISOs are supported.",
|
||||||
"Not a Windows 11 ISO", "OK", "Error")
|
"Not a Windows 11 ISO", "OK", "Error")
|
||||||
Set-WinUtilProgressBar -Label "" -Percent 0
|
Set-WinUtilTweaksProgressIndicator -Visible $false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
$sync["Win11ISOImagePath"] = $isoPath
|
$sync["Win11ISOImagePath"] = $isoPath
|
||||||
$sync["WPFWin11ISOModifySection"].Visibility = "Visible"
|
$sync["WPFWin11ISOModifySection"].Visibility = "Visible"
|
||||||
|
|
||||||
Set-WinUtilProgressBar -Label "ISO verified" -Percent 100
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "ISO verified" -Percent 100
|
||||||
Write-Win11ISOLog "ISO verified OK. Editions found: $($imageInfo.Count)"
|
Write-Win11ISOLog "ISO verified OK. Editions found: $($imageInfo.Count)"
|
||||||
} catch {
|
} catch {
|
||||||
Write-Win11ISOLog "ERROR during mount/verify: $_"
|
Write-Win11ISOLog "ERROR during mount/verify: $_"
|
||||||
@@ -123,7 +123,7 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
"Error", "OK", "Error")
|
"Error", "OK", "Error")
|
||||||
} finally {
|
} finally {
|
||||||
Start-Sleep -Milliseconds 800
|
Start-Sleep -Milliseconds 800
|
||||||
Set-WinUtilProgressBar -Label "" -Percent 0
|
Set-WinUtilTweaksProgressIndicator -Visible $false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +151,7 @@ function Invoke-WinUtilISOModify {
|
|||||||
|
|
||||||
$sync["WPFWin11ISOModifyButton"].IsEnabled = $false
|
$sync["WPFWin11ISOModifyButton"].IsEnabled = $false
|
||||||
$sync["Win11ISOModifying"] = $true
|
$sync["Win11ISOModifying"] = $true
|
||||||
|
$sync["Win11ISOProcessRunning"] = $true
|
||||||
|
|
||||||
$workDir = Join-Path $env:TEMP "WinUtil_Win11ISO_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
$workDir = Join-Path $env:TEMP "WinUtil_Win11ISO_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||||||
if (Test-Path $workDir) {
|
if (Test-Path $workDir) {
|
||||||
@@ -203,9 +204,10 @@ function Invoke-WinUtilISOModify {
|
|||||||
|
|
||||||
function SetProgress($label, $pct) {
|
function SetProgress($label, $pct) {
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = $label
|
$sync["WPFTweaksProgressBar"].Visibility = "Visible"
|
||||||
$sync.progressBarTextBlock.ToolTip = $label
|
$sync["WPFTweaksProgressLabel"].Text = $label
|
||||||
$sync.ProgressBar.Value = [Math]::Max($pct, 5)
|
$sync["WPFTweaksProgressLabel"].ToolTip = $label
|
||||||
|
$sync["WPFTweaksProgressValue"].Value = [Math]::Max($pct, 5)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,10 +454,12 @@ function Invoke-WinUtilISOModify {
|
|||||||
} finally {
|
} finally {
|
||||||
Start-Sleep -Milliseconds 800
|
Start-Sleep -Milliseconds 800
|
||||||
$sync["Win11ISOModifying"] = $false
|
$sync["Win11ISOModifying"] = $false
|
||||||
|
$sync["Win11ISOProcessRunning"] = $false
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = ""
|
$sync["WPFTweaksProgressBar"].Visibility = "Collapsed"
|
||||||
$sync.progressBarTextBlock.ToolTip = ""
|
$sync["WPFTweaksProgressLabel"].Text = ""
|
||||||
$sync.ProgressBar.Value = 0
|
$sync["WPFTweaksProgressLabel"].ToolTip = ""
|
||||||
|
$sync["WPFTweaksProgressValue"].Value = 0
|
||||||
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true
|
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true
|
||||||
if ($sync["WPFWin11ISOOutputSection"].Visibility -ne "Visible") {
|
if ($sync["WPFWin11ISOOutputSection"].Visibility -ne "Visible") {
|
||||||
$sync["WPFWin11ISOSelectSection"].Visibility = "Visible"
|
$sync["WPFWin11ISOSelectSection"].Visibility = "Visible"
|
||||||
@@ -514,6 +518,7 @@ function Invoke-WinUtilISOCleanAndReset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $false
|
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $false
|
||||||
|
$sync["Win11ISOProcessRunning"] = $true
|
||||||
|
|
||||||
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
||||||
$runspace.ApartmentState = "STA"
|
$runspace.ApartmentState = "STA"
|
||||||
@@ -538,9 +543,10 @@ function Invoke-WinUtilISOCleanAndReset {
|
|||||||
|
|
||||||
function SetProgress($label, $pct) {
|
function SetProgress($label, $pct) {
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = $label
|
$sync["WPFTweaksProgressBar"].Visibility = "Visible"
|
||||||
$sync.progressBarTextBlock.ToolTip = $label
|
$sync["WPFTweaksProgressLabel"].Text = $label
|
||||||
$sync.ProgressBar.Value = [Math]::Max($pct, 5)
|
$sync["WPFTweaksProgressLabel"].ToolTip = $label
|
||||||
|
$sync["WPFTweaksProgressValue"].Value = [Math]::Max($pct, 5)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,20 +634,24 @@ function Invoke-WinUtilISOCleanAndReset {
|
|||||||
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true
|
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true
|
||||||
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $true
|
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $true
|
||||||
|
|
||||||
$sync.progressBarTextBlock.Text = ""
|
$sync["WPFTweaksProgressBar"].Visibility = "Collapsed"
|
||||||
$sync.progressBarTextBlock.ToolTip = ""
|
$sync["WPFTweaksProgressLabel"].Text = ""
|
||||||
$sync.ProgressBar.Value = 0
|
$sync["WPFTweaksProgressLabel"].ToolTip = ""
|
||||||
|
$sync["WPFTweaksProgressValue"].Value = 0
|
||||||
|
|
||||||
$sync["WPFWin11ISOStatusLog"].Text = "Ready. Please select a Windows 11 ISO to begin."
|
$sync["WPFWin11ISOStatusLog"].Text = "Ready. Please select a Windows 11 ISO to begin."
|
||||||
})
|
})
|
||||||
} catch {
|
} catch {
|
||||||
Log "ERROR during Clean & Reset: $_"
|
Log "ERROR during Clean & Reset: $_"
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = ""
|
$sync["WPFTweaksProgressBar"].Visibility = "Collapsed"
|
||||||
$sync.progressBarTextBlock.ToolTip = ""
|
$sync["WPFTweaksProgressLabel"].Text = ""
|
||||||
$sync.ProgressBar.Value = 0
|
$sync["WPFTweaksProgressLabel"].ToolTip = ""
|
||||||
|
$sync["WPFTweaksProgressValue"].Value = 0
|
||||||
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $true
|
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $true
|
||||||
})
|
})
|
||||||
|
} finally {
|
||||||
|
$sync["Win11ISOProcessRunning"] = $false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -706,6 +716,7 @@ function Invoke-WinUtilISOExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$sync["WPFWin11ISOChooseISOButton"].IsEnabled = $false
|
$sync["WPFWin11ISOChooseISOButton"].IsEnabled = $false
|
||||||
|
$sync["Win11ISOProcessRunning"] = $true
|
||||||
|
|
||||||
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
||||||
$runspace.ApartmentState = "STA"
|
$runspace.ApartmentState = "STA"
|
||||||
@@ -726,9 +737,10 @@ function Invoke-WinUtilISOExport {
|
|||||||
|
|
||||||
function SetProgress($label, $pct) {
|
function SetProgress($label, $pct) {
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = $label
|
$sync["WPFTweaksProgressBar"].Visibility = "Visible"
|
||||||
$sync.progressBarTextBlock.ToolTip = $label
|
$sync["WPFTweaksProgressLabel"].Text = $label
|
||||||
$sync.ProgressBar.Value = [Math]::Max($pct, 5)
|
$sync["WPFTweaksProgressLabel"].ToolTip = $label
|
||||||
|
$sync["WPFTweaksProgressValue"].Value = [Math]::Max($pct, 5)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,10 +800,12 @@ function Invoke-WinUtilISOExport {
|
|||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
Start-Sleep -Milliseconds 800
|
Start-Sleep -Milliseconds 800
|
||||||
|
$sync["Win11ISOProcessRunning"] = $false
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = ""
|
$sync["WPFTweaksProgressBar"].Visibility = "Collapsed"
|
||||||
$sync.progressBarTextBlock.ToolTip = ""
|
$sync["WPFTweaksProgressLabel"].Text = ""
|
||||||
$sync.ProgressBar.Value = 0
|
$sync["WPFTweaksProgressLabel"].ToolTip = ""
|
||||||
|
$sync["WPFTweaksProgressValue"].Value = 0
|
||||||
$sync["WPFWin11ISOChooseISOButton"].IsEnabled = $true
|
$sync["WPFWin11ISOChooseISOButton"].IsEnabled = $true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$sync["WPFWin11ISOWriteUSBButton"].IsEnabled = $false
|
$sync["WPFWin11ISOWriteUSBButton"].IsEnabled = $false
|
||||||
|
$sync["Win11ISOProcessRunning"] = $true
|
||||||
Write-Win11ISOLog "Starting USB write to Disk $diskNum..."
|
Write-Win11ISOLog "Starting USB write to Disk $diskNum..."
|
||||||
|
|
||||||
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
||||||
@@ -86,9 +87,10 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
|
|
||||||
function SetProgress($label, $pct) {
|
function SetProgress($label, $pct) {
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = $label
|
$sync["WPFTweaksProgressBar"].Visibility = "Visible"
|
||||||
$sync.progressBarTextBlock.ToolTip = $label
|
$sync["WPFTweaksProgressLabel"].Text = $label
|
||||||
$sync.ProgressBar.Value = [Math]::Max($pct, 5)
|
$sync["WPFTweaksProgressLabel"].ToolTip = $label
|
||||||
|
$sync["WPFTweaksProgressValue"].Value = [Math]::Max($pct, 5)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,10 +257,12 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
Start-Sleep -Milliseconds 800
|
Start-Sleep -Milliseconds 800
|
||||||
|
$sync["Win11ISOProcessRunning"] = $false
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = ""
|
$sync["WPFTweaksProgressBar"].Visibility = "Collapsed"
|
||||||
$sync.progressBarTextBlock.ToolTip = ""
|
$sync["WPFTweaksProgressLabel"].Text = ""
|
||||||
$sync.ProgressBar.Value = 0
|
$sync["WPFTweaksProgressLabel"].ToolTip = ""
|
||||||
|
$sync["WPFTweaksProgressValue"].Value = 0
|
||||||
$sync["WPFWin11ISOWriteUSBButton"].IsEnabled = $true
|
$sync["WPFWin11ISOWriteUSBButton"].IsEnabled = $true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
function Save-WinUtilFile {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Downloads a file and reports transfer progress.
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[uri]$Uri,
|
||||||
|
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string]$DestinationPath,
|
||||||
|
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[scriptblock]$ProgressCallback
|
||||||
|
)
|
||||||
|
|
||||||
|
$response = $null
|
||||||
|
$responseStream = $null
|
||||||
|
$outputStream = $null
|
||||||
|
|
||||||
|
try {
|
||||||
|
$request = [System.Net.WebRequest]::Create($Uri)
|
||||||
|
$response = $request.GetResponse()
|
||||||
|
$totalBytes = $response.ContentLength
|
||||||
|
$responseStream = $response.GetResponseStream()
|
||||||
|
$outputStream = [System.IO.File]::Create($DestinationPath)
|
||||||
|
$buffer = New-Object byte[] 81920
|
||||||
|
$downloadedBytes = 0L
|
||||||
|
$lastPercent = -1
|
||||||
|
|
||||||
|
while (($bytesRead = $responseStream.Read($buffer, 0, $buffer.Length)) -gt 0) {
|
||||||
|
$outputStream.Write($buffer, 0, $bytesRead)
|
||||||
|
$downloadedBytes += $bytesRead
|
||||||
|
|
||||||
|
if ($totalBytes -gt 0) {
|
||||||
|
$percent = [Math]::Min(100, [int](($downloadedBytes / $totalBytes) * 100))
|
||||||
|
if ($percent -ne $lastPercent) {
|
||||||
|
& $ProgressCallback $percent
|
||||||
|
$lastPercent = $percent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($lastPercent -ne 100) {
|
||||||
|
& $ProgressCallback 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ($null -ne $outputStream) {
|
||||||
|
$outputStream.Dispose()
|
||||||
|
}
|
||||||
|
if ($null -ne $responseStream) {
|
||||||
|
$responseStream.Dispose()
|
||||||
|
}
|
||||||
|
if ($null -ne $response) {
|
||||||
|
$response.Dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
function Set-WinUtilProgressbar{
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
This function is used to Update the Progress Bar displayed in the winutil GUI.
|
|
||||||
It will be automatically hidden if the user clicks something and no process is running
|
|
||||||
.PARAMETER Label
|
|
||||||
The Text to be overlaid onto the Progress Bar
|
|
||||||
.PARAMETER PERCENT
|
|
||||||
The percentage of the Progress Bar that should be filled (0-100)
|
|
||||||
#>
|
|
||||||
param(
|
|
||||||
[string]$Label,
|
|
||||||
[ValidateRange(0,100)]
|
|
||||||
[int]$Percent
|
|
||||||
)
|
|
||||||
|
|
||||||
$progressLabel = $Label
|
|
||||||
|
|
||||||
Invoke-WPFUIThread -ScriptBlock {$sync.progressBarTextBlock.Text = $progressLabel}
|
|
||||||
Invoke-WPFUIThread -ScriptBlock {$sync.progressBarTextBlock.ToolTip = $progressLabel}
|
|
||||||
if ($Percent -lt 5 ) {
|
|
||||||
$Percent = 5 # Ensure the progress bar is not empty, as it looks weird
|
|
||||||
}
|
|
||||||
Invoke-WPFUIThread -ScriptBlock { $sync.ProgressBar.Value = $Percent}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,8 @@ function Set-WinUtilTweaksProgressIndicator {
|
|||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Shows, updates, or hides the window-level progress indicator used by long-running
|
Shows, updates, or hides the window-level progress indicator used by long-running
|
||||||
workflows such as Tweaks, Undo, and AppX management. It lives outside the TabControl,
|
workflows such as app management, Tweaks, AppX management, and Win11 Creator.
|
||||||
so unlike the Install tab's progress bar it stays visible no matter which tab is active.
|
It lives outside the TabControl, so it stays visible no matter which tab is active.
|
||||||
.PARAMETER Visible
|
.PARAMETER Visible
|
||||||
Whether the indicator should be shown or hidden.
|
Whether the indicator should be shown or hidden.
|
||||||
.PARAMETER Label
|
.PARAMETER Label
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
function Show-WPFInstallAppBusy {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Displays a busy overlay in the install app area of the WPF form.
|
|
||||||
This is used to indicate that an install or uninstall is in progress.
|
|
||||||
Dynamically updates the size of the overlay based on the app area on each invocation.
|
|
||||||
.PARAMETER text
|
|
||||||
The text to display in the busy overlay. Defaults to "Installing apps...".
|
|
||||||
#>
|
|
||||||
param (
|
|
||||||
$text = "Installing apps..."
|
|
||||||
)
|
|
||||||
$overlayText = $text
|
|
||||||
|
|
||||||
Invoke-WPFUIThread -ScriptBlock {
|
|
||||||
$sync.InstallAppAreaOverlay.Visibility = [Windows.Visibility]::Visible
|
|
||||||
$sync.InstallAppAreaOverlay.Width = $($sync.InstallAppAreaScrollViewer.ActualWidth * 0.4)
|
|
||||||
$sync.InstallAppAreaOverlay.Height = $($sync.InstallAppAreaScrollViewer.ActualWidth * 0.4)
|
|
||||||
$sync.InstallAppAreaOverlayText.Text = $overlayText
|
|
||||||
$sync.InstallAppAreaBorder.IsEnabled = $false
|
|
||||||
$sync.InstallAppAreaScrollViewer.Effect.Radius = 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,8 +14,7 @@ function Invoke-WPFButton {
|
|||||||
|
|
||||||
# Use this to get the name of the button
|
# Use this to get the name of the button
|
||||||
#[System.Windows.MessageBox]::Show("$Button","Chris Titus Tech's Windows Utility","OK","Info")
|
#[System.Windows.MessageBox]::Show("$Button","Chris Titus Tech's Windows Utility","OK","Info")
|
||||||
if (-not $sync.ProcessRunning) {
|
if (-not $sync.ProcessRunning -and -not $sync.Win11ISOProcessRunning) {
|
||||||
Set-WinUtilProgressBar -label "" -percent 0
|
|
||||||
Set-WinUtilTweaksProgressIndicator -Visible $false
|
Set-WinUtilTweaksProgressIndicator -Visible $false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
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
|
||||||
|
|
||||||
@@ -19,35 +18,72 @@ function Invoke-WPFGetInstalled {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
$managerPreference = $sync.preferences.packagemanager
|
$managerPreference = $sync.preferences.packagemanager
|
||||||
|
$operation = [Hashtable]::Synchronized(@{
|
||||||
Invoke-WPFRunspace -ParameterList @(("managerPreference", $managerPreference),("checkbox", $checkbox)) -ScriptBlock {
|
Checkboxes = @()
|
||||||
param (
|
Error = $null
|
||||||
[string]$checkbox,
|
})
|
||||||
[string]$managerPreference
|
$completeAction = [Action[hashtable, string]]{
|
||||||
|
param(
|
||||||
|
[hashtable]$completedOperation,
|
||||||
|
[string]$completedCheckbox
|
||||||
)
|
)
|
||||||
$sync.ProcessRunning = $true
|
try {
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Indeterminate" }
|
if ($completedOperation.Error) {
|
||||||
|
Write-WinUtilLog -Level "ERROR" -Component "Install" -Message "Get installed state failed: $($completedOperation.Error)"
|
||||||
|
Write-Warning "Unable to get installed state: $($completedOperation.Error)"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if ($checkbox -eq "winget") {
|
if ($completedCheckbox -eq "winget") {
|
||||||
Write-Host "Getting Installed Programs..."
|
foreach ($checkboxName in $completedOperation.Checkboxes) {
|
||||||
switch ($managerPreference) {
|
if (-not $sync.selectedApps.Contains($checkboxName)) {
|
||||||
"Choco"{$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox "choco"; break}
|
$sync.selectedApps.Add($checkboxName)
|
||||||
"Winget"{$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox; break}
|
}
|
||||||
|
}
|
||||||
|
Reset-WPFCheckBoxes -checkboxfilterpattern "WPFInstall*"
|
||||||
|
} else {
|
||||||
|
foreach ($checkboxName in $completedOperation.Checkboxes) {
|
||||||
|
$sync.$checkboxName.ischecked = $True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$sync.ProcessRunning = $false
|
||||||
|
Set-WinUtilTaskbaritem -state "None"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sync.ProcessRunning = $true
|
||||||
|
Set-WinUtilTaskbaritem -state "Indeterminate"
|
||||||
|
try {
|
||||||
|
Invoke-WPFRunspace -ParameterList @(
|
||||||
|
("managerPreference", $managerPreference),
|
||||||
|
("checkbox", $checkbox),
|
||||||
|
("operation", $operation),
|
||||||
|
("completeAction", $completeAction)
|
||||||
|
) -ScriptBlock {
|
||||||
|
param (
|
||||||
|
[string]$checkbox,
|
||||||
|
[string]$managerPreference,
|
||||||
|
[hashtable]$operation,
|
||||||
|
[Action[hashtable, string]]$completeAction
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
if ($checkbox -eq "winget") {
|
||||||
|
switch ($managerPreference) {
|
||||||
|
"Choco" { $operation.Checkboxes = @(Invoke-WinUtilCurrentSystem -CheckBox "choco"); break }
|
||||||
|
"Winget" { $operation.Checkboxes = @(Invoke-WinUtilCurrentSystem -CheckBox $checkbox); break }
|
||||||
|
}
|
||||||
|
} elseif ($checkbox -eq "tweaks") {
|
||||||
|
$operation.Checkboxes = @(Invoke-WinUtilCurrentSystem -CheckBox $checkbox)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
$operation.Error = $_.Exception.Message
|
||||||
|
} finally {
|
||||||
|
$sync.Form.Dispatcher.BeginInvoke($completeAction, [object[]]@($operation, $checkbox)) | Out-Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif ($checkbox -eq "tweaks") {
|
} catch {
|
||||||
Write-Host "Getting Installed Tweaks..."
|
$operation.Error = $_.Exception.Message
|
||||||
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox
|
$completeAction.Invoke($operation, $checkbox)
|
||||||
}
|
|
||||||
|
|
||||||
$sync.form.Dispatcher.invoke({
|
|
||||||
foreach ($checkbox in $Checkboxes) {
|
|
||||||
$sync.$checkbox.ischecked = $True
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
Write-Host "Done..."
|
|
||||||
$sync.ProcessRunning = $false
|
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,33 +31,81 @@ function Invoke-WPFInstall {
|
|||||||
|
|
||||||
$packagesWinget = $packagesSorted['Winget']
|
$packagesWinget = $packagesSorted['Winget']
|
||||||
$packagesChoco = $packagesSorted['Choco']
|
$packagesChoco = $packagesSorted['Choco']
|
||||||
|
$totalPackages = @($packagesWinget).Count + @($packagesChoco).Count
|
||||||
|
$completedPackages = 0
|
||||||
|
$hasUI = $null -ne $sync.Form -and $null -ne $sync.Form.Dispatcher
|
||||||
Write-WinUtilLog -Component "Install" -Message "Install package manager split: winget=$(@($packagesWinget).Count), choco=$(@($packagesChoco).Count)"
|
Write-WinUtilLog -Component "Install" -Message "Install package manager split: winget=$(@($packagesWinget).Count), choco=$(@($packagesChoco).Count)"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$sync.ProcessRunning = $true
|
$sync.ProcessRunning = $true
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Preparing app install (0/$totalPackages)" -Percent 0
|
||||||
|
Invoke-WPFUIThread -ScriptBlock {
|
||||||
|
if ($null -ne $sync.ItemsControl) {
|
||||||
|
$sync.ItemsControl.IsEnabled = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if($packagesWinget.Count -gt 0 -and $packagesWinget -ne "0") {
|
if($packagesWinget.Count -gt 0 -and $packagesWinget -ne "0") {
|
||||||
Show-WPFInstallAppBusy -text "Installing apps..."
|
|
||||||
Install-WinUtilWinget
|
Install-WinUtilWinget
|
||||||
Install-WinUtilProgramWinget -Action Install -Programs $packagesWinget
|
foreach ($program in $packagesWinget) {
|
||||||
|
$position = $completedPackages + 1
|
||||||
|
$startPercent = [int](($completedPackages / $totalPackages) * 100)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Installing $program ($position/$totalPackages)" -Percent $startPercent
|
||||||
|
}
|
||||||
|
|
||||||
|
Install-WinUtilProgramWinget -Action Install -Programs @($program)
|
||||||
|
$completedPackages++
|
||||||
|
$completedPercent = [int](($completedPackages / $totalPackages) * 100)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Installed $program ($completedPackages/$totalPackages)" -Percent $completedPercent
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($completedPercent / 100) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if($packagesChoco.Count -gt 0) {
|
if($packagesChoco.Count -gt 0) {
|
||||||
|
$position = $completedPackages + 1
|
||||||
|
$startPercent = [int](($completedPackages / $totalPackages) * 100)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Installing Chocolatey packages ($position/$totalPackages)" -Percent $startPercent
|
||||||
|
}
|
||||||
|
|
||||||
Install-WinUtilChoco
|
Install-WinUtilChoco
|
||||||
Install-WinUtilProgramChoco -Action Install -Programs $packagesChoco
|
Install-WinUtilProgramChoco -Action Install -Programs $packagesChoco
|
||||||
|
$completedPackages += @($packagesChoco).Count
|
||||||
|
$completedPercent = [int](($completedPackages / $totalPackages) * 100)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Installed Chocolatey packages ($completedPackages/$totalPackages)" -Percent $completedPercent
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($completedPercent / 100) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Hide-WPFInstallAppBusy
|
|
||||||
Write-Host "==========================================="
|
Write-Host "==========================================="
|
||||||
Write-Host "-- Installs have finished ---"
|
Write-Host "-- Installs have finished ---"
|
||||||
Write-Host "==========================================="
|
Write-Host "==========================================="
|
||||||
Write-WinUtilLog -Component "Install" -Message "Install workflow completed."
|
Write-WinUtilLog -Component "Install" -Message "Install workflow completed."
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "App install finished" -Percent 100
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Hide-WPFInstallAppBusy
|
|
||||||
Write-Host "==========================================="
|
Write-Host "==========================================="
|
||||||
Write-Host "Error: $_"
|
Write-Host "Error: $_"
|
||||||
Write-Host "==========================================="
|
Write-Host "==========================================="
|
||||||
Write-WinUtilLog -Level "ERROR" -Component "Install" -Message "Install workflow failed: $($_.Exception.Message)"
|
Write-WinUtilLog -Level "ERROR" -Component "Install" -Message "Install workflow failed: $($_.Exception.Message)"
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "App install failed" -Percent 100
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
if ($hasUI) {
|
||||||
|
Invoke-WPFUIThread -ScriptBlock {
|
||||||
|
if ($null -ne $sync.ItemsControl) {
|
||||||
|
$sync.ItemsControl.IsEnabled = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
$sync.ProcessRunning = $False
|
$sync.ProcessRunning = $False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,50 @@
|
|||||||
function Invoke-WPFOOSU {
|
function Invoke-WPFOOSU {
|
||||||
try {
|
if ($sync.ProcessRunning) {
|
||||||
$ProgressPreference = 'SilentlyContinue'
|
Show-WinUtilMessage -Message "Another process is currently running." -Title "WinUtil" -Button "OK" -Icon "Warning"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
Invoke-WebRequest -Uri https://dl5.oo-software.com/files/ooshutup10/OOSU10.exe -OutFile "$winutildir\ooshutup10.exe"
|
$downloadPath = Join-Path $sync.winutildir "ooshutup10.exe"
|
||||||
Start-Process -FilePath "$winutildir\ooshutup10.exe"
|
$sync.ProcessRunning = $true
|
||||||
|
|
||||||
$ProgressPreference = 'Continue'
|
Invoke-WPFRunspace -ParameterList @(,("downloadPath", $downloadPath)) -ScriptBlock {
|
||||||
} catch {
|
param($downloadPath)
|
||||||
Write-Error "Couldn't download O&O ShutUp10. Please make sure you have an active Internet connection."
|
|
||||||
|
$hasUI = $null -ne $sync.Form -and $null -ne $sync.Form.Dispatcher
|
||||||
|
|
||||||
|
try {
|
||||||
|
Write-WinUtilLog -Component "OOSU" -Message "Downloading O&O ShutUp10++."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Downloading O&O ShutUp10++ (0%)" -Percent 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Save-WinUtilFile -Uri "https://dl5.oo-software.com/files/ooshutup10/OOSU10.exe" -DestinationPath $downloadPath -ProgressCallback {
|
||||||
|
param($percent)
|
||||||
|
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Downloading O&O ShutUp10++ ($percent%)" -Percent $percent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Launching O&O ShutUp10++" -Percent 100
|
||||||
|
}
|
||||||
|
Start-Process -FilePath $downloadPath
|
||||||
|
|
||||||
|
Write-WinUtilLog -Component "OOSU" -Message "O&O ShutUp10++ launched."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "O&O ShutUp10++ launched" -Percent 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-WinUtilLog -Level "ERROR" -Component "OOSU" -Message "O&O ShutUp10++ download failed: $($_.Exception.Message)"
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "O&O ShutUp10++ download failed" -Percent 100
|
||||||
|
}
|
||||||
|
Write-Error "Couldn't download O&O ShutUp10. Please make sure you have an active Internet connection."
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$sync.ProcessRunning = $false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ public sealed class WinUtilRunspaceCleanupState
|
|||||||
|
|
||||||
public static class WinUtilRunspaceCleanup
|
public static class WinUtilRunspaceCleanup
|
||||||
{
|
{
|
||||||
|
public static readonly System.Threading.WaitOrTimerCallback Callback = Cleanup;
|
||||||
|
|
||||||
public static void Cleanup(object state, bool timedOut)
|
public static void Cleanup(object state, bool timedOut)
|
||||||
{
|
{
|
||||||
var cleanupState = state as WinUtilRunspaceCleanupState;
|
var cleanupState = state as WinUtilRunspaceCleanupState;
|
||||||
@@ -89,8 +91,7 @@ public static class WinUtilRunspaceCleanup
|
|||||||
$cleanupState = [WinUtilRunspaceCleanupState]::new()
|
$cleanupState = [WinUtilRunspaceCleanupState]::new()
|
||||||
$cleanupState.PowerShell = $powershell
|
$cleanupState.PowerShell = $powershell
|
||||||
$cleanupState.Handle = $handle
|
$cleanupState.Handle = $handle
|
||||||
$cleanupCallback = [System.Threading.WaitOrTimerCallback][WinUtilRunspaceCleanup]::Cleanup
|
[System.Threading.ThreadPool]::RegisterWaitForSingleObject($handle.AsyncWaitHandle, [WinUtilRunspaceCleanup]::Callback, $cleanupState, -1, $true) | Out-Null
|
||||||
[System.Threading.ThreadPool]::RegisterWaitForSingleObject($handle.AsyncWaitHandle, $cleanupCallback, $cleanupState, -1, $true) | Out-Null
|
|
||||||
|
|
||||||
# Return the handle
|
# Return the handle
|
||||||
return $handle
|
return $handle
|
||||||
|
|||||||
@@ -7,11 +7,21 @@ function Invoke-WPFSelectedCheckboxesUpdate ($type, $checkboxName) {
|
|||||||
'^WPFAppx' { 'selectedAppx' }
|
'^WPFAppx' { 'selectedAppx' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$selectionChanged = $false
|
||||||
if ($type -eq "Add") {
|
if ($type -eq "Add") {
|
||||||
if (-not $sync.$listName.Contains($checkboxName)) {
|
if (-not $sync.$listName.Contains($checkboxName)) {
|
||||||
$sync.$listName.Add($checkboxName)
|
$sync.$listName.Add($checkboxName)
|
||||||
|
$selectionChanged = $true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$sync.$listName.Remove($checkboxName)
|
$selectionChanged = $sync.$listName.Remove($checkboxName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($listName -eq "selectedApps" -and $selectionChanged) {
|
||||||
|
$sync.WPFselectedAppsButton.Content = "Selected Apps: $($sync.selectedApps.Count)"
|
||||||
|
$sync.selectedAppsstackPanel.Children.Clear()
|
||||||
|
$sync.selectedApps | Sort-Object | ForEach-Object {
|
||||||
|
Add-SelectedAppsMenuItem -name $sync.configs.applicationsHashtable.$_.Content -key $_
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,11 +404,16 @@ function Invoke-WPFUIElements {
|
|||||||
$textBlock.ToolTip = $entryInfo.Link
|
$textBlock.ToolTip = $entryInfo.Link
|
||||||
$textBlock.Style = $HoverTextBlockStyle
|
$textBlock.Style = $HoverTextBlockStyle
|
||||||
$textBlock.UseLayoutRounding = $true
|
$textBlock.UseLayoutRounding = $true
|
||||||
|
|
||||||
$textBlock.VerticalAlignment = "Center"
|
$textBlock.VerticalAlignment = "Center"
|
||||||
$textBlock.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSize")
|
$textBlock.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSize")
|
||||||
$textBlock.Tag = $checkBox
|
$textBlock.Tag = $checkBox
|
||||||
|
|
||||||
|
$textBlock.Add_MouseUp({
|
||||||
|
[System.Object]$Sender = $args[0]
|
||||||
|
Start-Process $Sender.ToolTip -ErrorAction Stop
|
||||||
|
})
|
||||||
|
|
||||||
$updateLinkMargin = {
|
$updateLinkMargin = {
|
||||||
[System.Object]$Sender = $args[0]
|
[System.Object]$Sender = $args[0]
|
||||||
$linkedCheckBox = $Sender.Tag
|
$linkedCheckBox = $Sender.Tag
|
||||||
|
|||||||
@@ -42,11 +42,21 @@ function Invoke-WPFUnInstall {
|
|||||||
|
|
||||||
$packagesWinget = $packagesSorted['Winget']
|
$packagesWinget = $packagesSorted['Winget']
|
||||||
$packagesChoco = $packagesSorted['Choco']
|
$packagesChoco = $packagesSorted['Choco']
|
||||||
|
$totalPackages = @($packagesWinget).Count + @($packagesChoco).Count
|
||||||
|
$completedPackages = 0
|
||||||
|
$hasUI = $null -ne $sync.Form -and $null -ne $sync.Form.Dispatcher
|
||||||
Write-WinUtilLog -Component "Uninstall" -Message "Uninstall package manager split: winget=$(@($packagesWinget).Count), choco=$(@($packagesChoco).Count)"
|
Write-WinUtilLog -Component "Uninstall" -Message "Uninstall package manager split: winget=$(@($packagesWinget).Count), choco=$(@($packagesChoco).Count)"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$sync.ProcessRunning = $true
|
$sync.ProcessRunning = $true
|
||||||
Show-WPFInstallAppBusy -text "Uninstalling apps..."
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Preparing app uninstall (0/$totalPackages)" -Percent 0
|
||||||
|
Invoke-WPFUIThread -ScriptBlock {
|
||||||
|
if ($null -ne $sync.ItemsControl) {
|
||||||
|
$sync.ItemsControl.IsEnabled = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($packagesWinget -contains "Microsoft.Edge") {
|
if ($packagesWinget -contains "Microsoft.Edge") {
|
||||||
New-Item -Path "$Env:SystemRoot\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\MicrosoftEdge.exe" -Force
|
New-Item -Path "$Env:SystemRoot\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\MicrosoftEdge.exe" -Force
|
||||||
@@ -54,25 +64,62 @@ function Invoke-WPFUnInstall {
|
|||||||
|
|
||||||
# Uninstall all selected programs in new window
|
# Uninstall all selected programs in new window
|
||||||
if($packagesWinget.Count -gt 0) {
|
if($packagesWinget.Count -gt 0) {
|
||||||
Install-WinUtilProgramWinget -Action Uninstall -Programs $packagesWinget
|
foreach ($program in $packagesWinget) {
|
||||||
|
$position = $completedPackages + 1
|
||||||
|
$startPercent = [int](($completedPackages / $totalPackages) * 100)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Uninstalling $program ($position/$totalPackages)" -Percent $startPercent
|
||||||
|
}
|
||||||
|
|
||||||
|
Install-WinUtilProgramWinget -Action Uninstall -Programs @($program)
|
||||||
|
$completedPackages++
|
||||||
|
$completedPercent = [int](($completedPackages / $totalPackages) * 100)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Uninstalled $program ($completedPackages/$totalPackages)" -Percent $completedPercent
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($completedPercent / 100) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if($packagesChoco.Count -gt 0) {
|
if($packagesChoco.Count -gt 0) {
|
||||||
|
$position = $completedPackages + 1
|
||||||
|
$startPercent = [int](($completedPackages / $totalPackages) * 100)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Uninstalling Chocolatey packages ($position/$totalPackages)" -Percent $startPercent
|
||||||
|
}
|
||||||
|
|
||||||
Install-WinUtilProgramChoco -Action Uninstall -Programs $packagesChoco
|
Install-WinUtilProgramChoco -Action Uninstall -Programs $packagesChoco
|
||||||
|
$completedPackages += @($packagesChoco).Count
|
||||||
|
$completedPercent = [int](($completedPackages / $totalPackages) * 100)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Uninstalled Chocolatey packages ($completedPackages/$totalPackages)" -Percent $completedPercent
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($completedPercent / 100) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Hide-WPFInstallAppBusy
|
|
||||||
Write-Host "==========================================="
|
Write-Host "==========================================="
|
||||||
Write-Host "-- Uninstalls have finished ---"
|
Write-Host "-- Uninstalls have finished ---"
|
||||||
Write-Host "==========================================="
|
Write-Host "==========================================="
|
||||||
Write-WinUtilLog -Component "Uninstall" -Message "Uninstall workflow completed."
|
Write-WinUtilLog -Component "Uninstall" -Message "Uninstall workflow completed."
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "App uninstall finished" -Percent 100
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Hide-WPFInstallAppBusy
|
|
||||||
Write-Host "==========================================="
|
Write-Host "==========================================="
|
||||||
Write-Host "Error: $_"
|
Write-Host "Error: $_"
|
||||||
Write-Host "==========================================="
|
Write-Host "==========================================="
|
||||||
Write-WinUtilLog -Level "ERROR" -Component "Uninstall" -Message "Uninstall workflow failed: $($_.Exception.Message)"
|
Write-WinUtilLog -Level "ERROR" -Component "Uninstall" -Message "Uninstall workflow failed: $($_.Exception.Message)"
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "App uninstall failed" -Percent 100
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
if ($hasUI) {
|
||||||
|
Invoke-WPFUIThread -ScriptBlock {
|
||||||
|
if ($null -ne $sync.ItemsControl) {
|
||||||
|
$sync.ItemsControl.IsEnabled = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
$sync.ProcessRunning = $False
|
$sync.ProcessRunning = $False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,22 +5,51 @@ function Invoke-WPFUpdatesdefault {
|
|||||||
Resets Windows Update settings to default
|
Resets Windows Update settings to default
|
||||||
|
|
||||||
#>
|
#>
|
||||||
$ErrorActionPreference = 'SilentlyContinue'
|
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Resetting Windows Update settings to default."
|
Write-WinUtilLog -Component "Updates" -Message "Resetting Windows Update settings to default."
|
||||||
|
|
||||||
Write-Host "Removing Windows Update policy settings..." -ForegroundColor Green
|
Write-Host "Removing Windows Update settings managed by WinUtil..." -ForegroundColor Green
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Removing Windows Update policy registry paths."
|
Write-WinUtilLog -Component "Updates" -Message "Removing Windows Update registry values managed by WinUtil."
|
||||||
|
|
||||||
Remove-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Recurse -Force
|
$registryValues = @(
|
||||||
Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization" -Recurse -Force
|
@{
|
||||||
Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Recurse -Force
|
Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"
|
||||||
Remove-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata" -Recurse -Force
|
Names = @("NoAutoUpdate", "AUOptions", "NoAutoRebootWithLoggedOnUsers", "AUPowerManagement")
|
||||||
Remove-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching" -Recurse -Force
|
},
|
||||||
Remove-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -Recurse -Force
|
@{
|
||||||
|
Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
|
||||||
|
Names = @("ExcludeWUDriversInQualityUpdate", "DeferFeatureUpdates", "DeferFeatureUpdatesPeriodInDays", "DeferQualityUpdates", "DeferQualityUpdatesPeriodInDays")
|
||||||
|
},
|
||||||
|
@{
|
||||||
|
Path = "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings"
|
||||||
|
Names = @("BranchReadinessLevel", "DeferFeatureUpdatesPeriodInDays", "DeferQualityUpdatesPeriodInDays")
|
||||||
|
},
|
||||||
|
@{
|
||||||
|
Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata"
|
||||||
|
Names = @("PreventDeviceMetadataFromNetwork")
|
||||||
|
},
|
||||||
|
@{
|
||||||
|
Path = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching"
|
||||||
|
Names = @("DontPromptForWindowsUpdate", "DontSearchWindowsUpdate", "DriverUpdateWizardWuSearchEnabled")
|
||||||
|
},
|
||||||
|
@{
|
||||||
|
Path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config"
|
||||||
|
Names = @("DODownloadMode")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
Write-Host "Showing Windows Updates in settings..."
|
foreach ($registryEntry in $registryValues) {
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Showing Windows Update settings page."
|
foreach ($valueName in $registryEntry.Names) {
|
||||||
Remove-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer -Name SettingsPageVisibility
|
Remove-ItemProperty -Path $registryEntry.Path -Name $valueName -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$explorerPolicyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer"
|
||||||
|
$settingsPageVisibility = (Get-ItemProperty -Path $explorerPolicyPath -Name "SettingsPageVisibility" -ErrorAction SilentlyContinue).SettingsPageVisibility
|
||||||
|
if ($settingsPageVisibility -eq "hide:windowsupdate") {
|
||||||
|
Write-Host "Removing WinUtil's legacy Windows Update page restriction..."
|
||||||
|
Write-WinUtilLog -Component "Updates" -Message "Removing the legacy Windows Update settings page restriction."
|
||||||
|
Remove-ItemProperty -Path $explorerPolicyPath -Name "SettingsPageVisibility" -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "Reenabling Windows Update Services..." -ForegroundColor Green
|
Write-Host "Reenabling Windows Update Services..." -ForegroundColor Green
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Restoring Windows Update service startup types."
|
Write-WinUtilLog -Component "Updates" -Message "Restoring Windows Update service startup types."
|
||||||
@@ -35,12 +64,8 @@ function Invoke-WPFUpdatesdefault {
|
|||||||
|
|
||||||
Write-Host "Restored UsoSvc to Automatic."
|
Write-Host "Restored UsoSvc to Automatic."
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Starting UsoSvc service and restoring startup type to Automatic."
|
Write-WinUtilLog -Component "Updates" -Message "Starting UsoSvc service and restoring startup type to Automatic."
|
||||||
Start-Service -Name UsoSvc
|
|
||||||
Set-Service -Name UsoSvc -StartupType Automatic
|
Set-Service -Name UsoSvc -StartupType Automatic
|
||||||
|
Start-Service -Name UsoSvc
|
||||||
Write-Host "Restored WaaSMedicSvc to Manual."
|
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Restoring WaaSMedicSvc service to Manual."
|
|
||||||
Set-Service -Name WaaSMedicSvc -StartupType Manual
|
|
||||||
|
|
||||||
Write-Host "Enabling update related scheduled tasks..." -ForegroundColor Green
|
Write-Host "Enabling update related scheduled tasks..." -ForegroundColor Green
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Enabling update related scheduled tasks."
|
Write-WinUtilLog -Component "Updates" -Message "Enabling update related scheduled tasks."
|
||||||
@@ -54,13 +79,9 @@ function Invoke-WPFUpdatesdefault {
|
|||||||
'\Microsoft\WindowsUpdate\*'
|
'\Microsoft\WindowsUpdate\*'
|
||||||
|
|
||||||
foreach ($Task in $Tasks) {
|
foreach ($Task in $Tasks) {
|
||||||
Get-ScheduledTask -TaskPath $Task | Enable-ScheduledTask -ErrorAction SilentlyContinue
|
Get-ScheduledTask -TaskPath $Task -ErrorAction SilentlyContinue | Enable-ScheduledTask -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "Windows Local Policies Reset to Default."
|
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Resetting local security policy to defaults with secedit."
|
|
||||||
secedit /configure /cfg "$Env:SystemRoot\inf\defltbase.inf" /db defltbase.sdb
|
|
||||||
|
|
||||||
Write-Host "===================================================" -ForegroundColor Green
|
Write-Host "===================================================" -ForegroundColor Green
|
||||||
Write-Host "--- Windows Update Settings Reset to Default ---" -ForegroundColor Green
|
Write-Host "--- Windows Update Settings Reset to Default ---" -ForegroundColor Green
|
||||||
Write-Host "===================================================" -ForegroundColor Green
|
Write-Host "===================================================" -ForegroundColor Green
|
||||||
|
|||||||
@@ -8,7 +8,17 @@ function Invoke-WPFUpdatesdisable {
|
|||||||
Disabling Windows Update is not recommended. This is only for advanced users who know what they are doing.
|
Disabling Windows Update is not recommended. This is only for advanced users who know what they are doing.
|
||||||
|
|
||||||
#>
|
#>
|
||||||
$ErrorActionPreference = 'SilentlyContinue'
|
$confirmation = Show-WinUtilMessage `
|
||||||
|
-Message "Disabling Windows Update stops update services, disables scheduled tasks, and clears downloaded update files. Security updates will not be installed until defaults are restored. Continue?" `
|
||||||
|
-Title "Disable Windows Update?" `
|
||||||
|
-Button "YesNo" `
|
||||||
|
-Icon "Warning"
|
||||||
|
|
||||||
|
if ($confirmation -ne "Yes") {
|
||||||
|
Write-WinUtilLog -Component "Updates" -Message "Windows Update disable workflow cancelled."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Disabling Windows Update settings."
|
Write-WinUtilLog -Component "Updates" -Message "Disabling Windows Update settings."
|
||||||
|
|
||||||
Write-Host "Configuring registry settings..." -ForegroundColor Yellow
|
Write-Host "Configuring registry settings..." -ForegroundColor Yellow
|
||||||
@@ -21,24 +31,14 @@ function Invoke-WPFUpdatesdisable {
|
|||||||
New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config" -Force
|
New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config" -Force
|
||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config" -Name "DODownloadMode" -Type DWord -Value 0
|
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config" -Name "DODownloadMode" -Type DWord -Value 0
|
||||||
|
|
||||||
Write-Host "Hiding Windows Updates from settings..."
|
foreach ($serviceName in @("BITS", "wuauserv", "UsoSvc")) {
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Hiding Windows Update settings page."
|
Write-Host "Stopping and disabling $serviceName service."
|
||||||
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer -Name SettingsPageVisibility -Value hide:windowsupdate
|
Write-WinUtilLog -Component "Updates" -Message "Stopping and disabling $serviceName service."
|
||||||
|
Stop-Service -Name $serviceName -Force -ErrorAction SilentlyContinue
|
||||||
|
Set-Service -Name $serviceName -StartupType Disabled
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "Disabled BITS Service."
|
Remove-Item -Path "C:\Windows\SoftwareDistribution\*" -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Disabling BITS service."
|
|
||||||
Set-Service -Name BITS -StartupType Disabled
|
|
||||||
|
|
||||||
Write-Host "Disabled wuauserv Service."
|
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Disabling wuauserv service."
|
|
||||||
Set-Service -Name wuauserv -StartupType Disabled
|
|
||||||
|
|
||||||
Write-Host "Disabled UsoSvc Service."
|
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Stopping and disabling UsoSvc service."
|
|
||||||
Stop-Service -Name UsoSvc -Force
|
|
||||||
Set-Service -Name UsoSvc -StartupType Disabled
|
|
||||||
|
|
||||||
Remove-Item "C:\Windows\SoftwareDistribution\*" -Recurse -Force
|
|
||||||
Write-Host "Cleared SoftwareDistribution folder."
|
Write-Host "Cleared SoftwareDistribution folder."
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Cleared SoftwareDistribution folder."
|
Write-WinUtilLog -Component "Updates" -Message "Cleared SoftwareDistribution folder."
|
||||||
|
|
||||||
@@ -54,11 +54,11 @@ function Invoke-WPFUpdatesdisable {
|
|||||||
'\Microsoft\WindowsUpdate\*'
|
'\Microsoft\WindowsUpdate\*'
|
||||||
|
|
||||||
foreach ($Task in $Tasks) {
|
foreach ($Task in $Tasks) {
|
||||||
Get-ScheduledTask -TaskPath $Task | Disable-ScheduledTask -ErrorAction SilentlyContinue
|
Get-ScheduledTask -TaskPath $Task -ErrorAction SilentlyContinue | Disable-ScheduledTask -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "=================================" -ForegroundColor Green
|
Write-Host "=================================" -ForegroundColor Green
|
||||||
Write-Host "--- Updates Are Disabled ---" -ForegroundColor Green
|
Write-Host "--- Windows Update Is Disabled ---" -ForegroundColor Green
|
||||||
Write-Host "=================================" -ForegroundColor Green
|
Write-Host "=================================" -ForegroundColor Green
|
||||||
|
|
||||||
Write-Host "Note: You must restart your system in order for all changes to take effect." -ForegroundColor Yellow
|
Write-Host "Note: You must restart your system in order for all changes to take effect." -ForegroundColor Yellow
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ function Invoke-WPFUpdatessecurity {
|
|||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
1. Disables driver offering through Windows Update
|
1. Disables driver offering through Windows Update
|
||||||
2. Disables Windows Update automatic restart
|
2. Defers feature updates for 365 days
|
||||||
3. Sets Windows Update to Semi-Annual Channel (Targeted)
|
3. Defers quality updates for 4 days
|
||||||
4. Defers feature updates for 365 days
|
4. Prevents automatic restarts while a user is signed in
|
||||||
5. Defers quality updates for 4 days
|
|
||||||
|
|
||||||
#>
|
#>
|
||||||
|
|
||||||
@@ -17,6 +16,32 @@ function Invoke-WPFUpdatessecurity {
|
|||||||
Write-WinUtilLog -Component "Updates" -Message "Applying recommended Windows Update settings."
|
Write-WinUtilLog -Component "Updates" -Message "Applying recommended Windows Update settings."
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Disabling driver offering through Windows Update."
|
Write-WinUtilLog -Component "Updates" -Message "Disabling driver offering through Windows Update."
|
||||||
|
|
||||||
|
$windowsUpdatePolicyPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
|
||||||
|
$automaticUpdatePolicyPath = Join-Path $windowsUpdatePolicyPath "AU"
|
||||||
|
|
||||||
|
Write-Host "Restoring Windows Update availability..."
|
||||||
|
Write-WinUtilLog -Component "Updates" -Message "Restoring Windows Update services and scheduled tasks before applying recommended settings."
|
||||||
|
|
||||||
|
Remove-ItemProperty -Path $automaticUpdatePolicyPath -Name "NoAutoUpdate" -ErrorAction SilentlyContinue
|
||||||
|
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config" -Name "DODownloadMode" -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
Set-Service -Name BITS -StartupType Manual
|
||||||
|
Set-Service -Name wuauserv -StartupType Manual
|
||||||
|
Set-Service -Name UsoSvc -StartupType Automatic
|
||||||
|
Start-Service -Name UsoSvc
|
||||||
|
|
||||||
|
$Tasks =
|
||||||
|
'\Microsoft\Windows\InstallService\*',
|
||||||
|
'\Microsoft\Windows\UpdateOrchestrator\*',
|
||||||
|
'\Microsoft\Windows\UpdateAssistant\*',
|
||||||
|
'\Microsoft\Windows\WaaSMedic\*',
|
||||||
|
'\Microsoft\Windows\WindowsUpdate\*',
|
||||||
|
'\Microsoft\WindowsUpdate\*'
|
||||||
|
|
||||||
|
foreach ($Task in $Tasks) {
|
||||||
|
Get-ScheduledTask -TaskPath $Task -ErrorAction SilentlyContinue | Enable-ScheduledTask -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata" -Force
|
New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata" -Force
|
||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata" -Name "PreventDeviceMetadataFromNetwork" -Type DWord -Value 1
|
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata" -Name "PreventDeviceMetadataFromNetwork" -Type DWord -Value 1
|
||||||
|
|
||||||
@@ -26,24 +51,30 @@ function Invoke-WPFUpdatessecurity {
|
|||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching" -Name "DontSearchWindowsUpdate" -Type DWord -Value 1
|
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching" -Name "DontSearchWindowsUpdate" -Type DWord -Value 1
|
||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching" -Name "DriverUpdateWizardWuSearchEnabled" -Type DWord -Value 0
|
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching" -Name "DriverUpdateWizardWuSearchEnabled" -Type DWord -Value 0
|
||||||
|
|
||||||
New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -Force
|
New-Item -Path $windowsUpdatePolicyPath -Force
|
||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -Name "ExcludeWUDriversInQualityUpdate" -Type DWord -Value 1
|
Set-ItemProperty -Path $windowsUpdatePolicyPath -Name "ExcludeWUDriversInQualityUpdate" -Type DWord -Value 1
|
||||||
|
|
||||||
Write-Host "Setting cumulative updates back by 1 year and security updates by 4 days..."
|
Write-Host "Deferring feature updates by 365 days and quality updates by 4 days..."
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Deferring feature updates by 365 days and quality updates by 4 days."
|
Write-WinUtilLog -Component "Updates" -Message "Deferring feature updates by 365 days and quality updates by 4 days."
|
||||||
|
|
||||||
New-Item -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Force
|
Set-ItemProperty -Path $windowsUpdatePolicyPath -Name "DeferFeatureUpdates" -Type DWord -Value 1
|
||||||
|
Set-ItemProperty -Path $windowsUpdatePolicyPath -Name "DeferFeatureUpdatesPeriodInDays" -Type DWord -Value 365
|
||||||
|
Set-ItemProperty -Path $windowsUpdatePolicyPath -Name "DeferQualityUpdates" -Type DWord -Value 1
|
||||||
|
Set-ItemProperty -Path $windowsUpdatePolicyPath -Name "DeferQualityUpdatesPeriodInDays" -Type DWord -Value 4
|
||||||
|
|
||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Name "BranchReadinessLevel" -Type DWord -Value 20
|
$legacySettingsPath = "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings"
|
||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Name "DeferFeatureUpdatesPeriodInDays" -Type DWord -Value 365
|
foreach ($legacyValue in @("BranchReadinessLevel", "DeferFeatureUpdatesPeriodInDays", "DeferQualityUpdatesPeriodInDays")) {
|
||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Name "DeferQualityUpdatesPeriodInDays" -Type DWord -Value 4
|
Remove-ItemProperty -Path $legacySettingsPath -Name $legacyValue -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "Disabling Windows Update automatic restart..."
|
Write-Host "Preventing automatic restarts while users are signed in..."
|
||||||
Write-WinUtilLog -Component "Updates" -Message "Disabling Windows Update automatic restart while users are logged in."
|
Write-WinUtilLog -Component "Updates" -Message "Configuring scheduled automatic updates without restarting while users are signed in."
|
||||||
|
|
||||||
New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Force
|
New-Item -Path $automaticUpdatePolicyPath -Force
|
||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "NoAutoRebootWithLoggedOnUsers" -Type DWord -Value 1
|
# NoAutoRebootWithLoggedOnUsers only applies when automatic updates use option 4.
|
||||||
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "AUPowerManagement" -Type DWord -Value 0
|
Set-ItemProperty -Path $automaticUpdatePolicyPath -Name "AUOptions" -Type DWord -Value 4
|
||||||
|
Set-ItemProperty -Path $automaticUpdatePolicyPath -Name "NoAutoRebootWithLoggedOnUsers" -Type DWord -Value 1
|
||||||
|
Set-ItemProperty -Path $automaticUpdatePolicyPath -Name "AUPowerManagement" -Type DWord -Value 0
|
||||||
|
|
||||||
Write-Host "================================="
|
Write-Host "================================="
|
||||||
Write-Host "-- Updates Set to Recommended ---"
|
Write-Host "-- Updates Set to Recommended ---"
|
||||||
|
|||||||
@@ -39,14 +39,12 @@ function Invoke-WPFtweaksbutton {
|
|||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" }
|
||||||
}
|
}
|
||||||
|
|
||||||
Set-WinUtilProgressBar -Label "Creating restore point" -Percent 0
|
|
||||||
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Creating restore point" -Percent 0
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Creating restore point" -Percent 0
|
||||||
Write-WinUtilLog -Component "Tweaks" -Message "Creating restore point before applying selected tweaks."
|
Write-WinUtilLog -Component "Tweaks" -Message "Creating restore point before applying selected tweaks."
|
||||||
Invoke-WinUtilTweaks $restorePointTweak
|
Invoke-WinUtilTweaks $restorePointTweak
|
||||||
$completedSteps = 1
|
$completedSteps = 1
|
||||||
|
|
||||||
if ($tweaksToRun.Count -eq 0 -and $dnsProvider -eq "Default") {
|
if ($tweaksToRun.Count -eq 0 -and $dnsProvider -eq "Default") {
|
||||||
Set-WinUtilProgressBar -Label "Tweaks finished" -Percent 100
|
|
||||||
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Tweaks finished" -Percent 100
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Tweaks finished" -Percent 100
|
||||||
$sync.ProcessRunning = $false
|
$sync.ProcessRunning = $false
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
@@ -77,14 +75,12 @@ function Invoke-WPFtweaksbutton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for ($i = 0; $i -lt $tweaks.Count; $i++) {
|
for ($i = 0; $i -lt $tweaks.Count; $i++) {
|
||||||
Set-WinUtilProgressBar -Label "Applying $($tweaks[$i])" -Percent ($completedSteps / $totalSteps * 100)
|
|
||||||
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Applying $($tweaks[$i]) ($($completedSteps + 1)/$totalSteps)" -Percent ($completedSteps / $totalSteps * 100)
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Applying $($tweaks[$i]) ($($completedSteps + 1)/$totalSteps)" -Percent ($completedSteps / $totalSteps * 100)
|
||||||
Invoke-WinUtilTweaks $tweaks[$i]
|
Invoke-WinUtilTweaks $tweaks[$i]
|
||||||
$completedSteps++
|
$completedSteps++
|
||||||
$progress = $completedSteps / $totalSteps
|
$progress = $completedSteps / $totalSteps
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value $progress }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value $progress }
|
||||||
}
|
}
|
||||||
Set-WinUtilProgressBar -Label "Tweaks finished" -Percent 100
|
|
||||||
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Tweaks finished" -Percent 100
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Tweaks finished" -Percent 100
|
||||||
$sync.ProcessRunning = $false
|
$sync.ProcessRunning = $false
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
|
|||||||
@@ -33,13 +33,11 @@ function Invoke-WPFundoall {
|
|||||||
|
|
||||||
|
|
||||||
for ($i = 0; $i -lt $tweaks.Count; $i++) {
|
for ($i = 0; $i -lt $tweaks.Count; $i++) {
|
||||||
Set-WinUtilProgressBar -Label "Undoing $($tweaks[$i])" -Percent ($i / $tweaks.Count * 100)
|
|
||||||
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Undoing $($tweaks[$i]) ($($i + 1)/$($tweaks.Count))" -Percent ($i / $tweaks.Count * 100)
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Undoing $($tweaks[$i]) ($($i + 1)/$($tweaks.Count))" -Percent ($i / $tweaks.Count * 100)
|
||||||
Invoke-WinUtiltweaks $tweaks[$i] -undo $true
|
Invoke-WinUtiltweaks $tweaks[$i] -undo $true
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($i/$tweaks.Count) }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($i/$tweaks.Count) }
|
||||||
}
|
}
|
||||||
|
|
||||||
Set-WinUtilProgressBar -Label "Undo Tweaks Finished" -Percent 100
|
|
||||||
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Undo Tweaks Finished" -Percent 100
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Undo Tweaks Finished" -Percent 100
|
||||||
$sync.ProcessRunning = $false
|
$sync.ProcessRunning = $false
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
|
|||||||
@@ -46,9 +46,6 @@ BeforeAll {
|
|||||||
function Invoke-WPFUIThread {
|
function Invoke-WPFUIThread {
|
||||||
param([scriptblock]$ScriptBlock)
|
param([scriptblock]$ScriptBlock)
|
||||||
}
|
}
|
||||||
function Set-WinUtilProgressBar {
|
|
||||||
param($Label, $Percent)
|
|
||||||
}
|
|
||||||
function Set-WinUtilTweaksProgressIndicator {
|
function Set-WinUtilTweaksProgressIndicator {
|
||||||
param($Visible, $Label, $Percent)
|
param($Visible, $Label, $Percent)
|
||||||
}
|
}
|
||||||
@@ -235,7 +232,6 @@ Describe "Get installed AppX selection" {
|
|||||||
WPFAppxMissing = [pscustomobject]@{ IsChecked = $false }
|
WPFAppxMissing = [pscustomobject]@{ IsChecked = $false }
|
||||||
})
|
})
|
||||||
|
|
||||||
Mock Set-WinUtilProgressBar { }
|
|
||||||
Mock Set-WinUtilTweaksProgressIndicator { }
|
Mock Set-WinUtilTweaksProgressIndicator { }
|
||||||
Mock Get-WinUtilInstalledAPPX { @("Example.Package") }
|
Mock Get-WinUtilInstalledAPPX { @("Example.Package") }
|
||||||
Mock Invoke-WPFAppxInstall { }
|
Mock Invoke-WPFAppxInstall { }
|
||||||
|
|||||||
@@ -18,10 +18,9 @@ BeforeAll {
|
|||||||
function Get-WinUtilSelectedPackages {
|
function Get-WinUtilSelectedPackages {
|
||||||
param($PackageList, [string]$Preference)
|
param($PackageList, [string]$Preference)
|
||||||
}
|
}
|
||||||
function Show-WPFInstallAppBusy {
|
function Set-WinUtilTweaksProgressIndicator {
|
||||||
param($text)
|
param($Visible, $Label, $Percent)
|
||||||
}
|
}
|
||||||
function Hide-WPFInstallAppBusy { }
|
|
||||||
function Install-WinUtilWinget { }
|
function Install-WinUtilWinget { }
|
||||||
function Install-WinUtilChoco { }
|
function Install-WinUtilChoco { }
|
||||||
function Install-WinUtilProgramWinget {
|
function Install-WinUtilProgramWinget {
|
||||||
@@ -74,6 +73,9 @@ BeforeAll {
|
|||||||
preferences = [pscustomobject]@{
|
preferences = [pscustomobject]@{
|
||||||
packagemanager = "Winget"
|
packagemanager = "Winget"
|
||||||
}
|
}
|
||||||
|
Form = [pscustomobject]@{
|
||||||
|
Dispatcher = [pscustomobject]@{}
|
||||||
|
}
|
||||||
configs = @{
|
configs = @{
|
||||||
applicationsHashtable = $applications
|
applicationsHashtable = $applications
|
||||||
}
|
}
|
||||||
@@ -187,8 +189,7 @@ Describe "Invoke-WPFInstall runspace body" {
|
|||||||
Mock Get-WinUtilSelectedPackages {
|
Mock Get-WinUtilSelectedPackages {
|
||||||
New-WinUtilPackageSplit -Winget @("Git.Git") -Choco @("vlc")
|
New-WinUtilPackageSplit -Winget @("Git.Git") -Choco @("vlc")
|
||||||
}
|
}
|
||||||
Mock Show-WPFInstallAppBusy { }
|
Mock Set-WinUtilTweaksProgressIndicator { }
|
||||||
Mock Hide-WPFInstallAppBusy { }
|
|
||||||
Mock Install-WinUtilWinget { }
|
Mock Install-WinUtilWinget { }
|
||||||
Mock Install-WinUtilChoco { }
|
Mock Install-WinUtilChoco { }
|
||||||
Mock Install-WinUtilProgramWinget { }
|
Mock Install-WinUtilProgramWinget { }
|
||||||
@@ -212,8 +213,17 @@ Describe "Invoke-WPFInstall runspace body" {
|
|||||||
Should -Invoke -CommandName Get-WinUtilSelectedPackages -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Get-WinUtilSelectedPackages -Times 1 -Exactly -ParameterFilter {
|
||||||
@($PackageList).Count -eq 1 -and $Preference -eq "Winget"
|
@($PackageList).Count -eq 1 -and $Preference -eq "Winget"
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Show-WPFInstallAppBusy -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
$text -eq "Installing apps..."
|
$Visible -eq $true -and $Label -eq "Preparing app install (0/2)" -and $Percent -eq 0
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Installed Git.Git (1/2)" -and $Percent -eq 50
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Installed Chocolatey packages (2/2)" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "App install finished" -and $Percent -eq 100
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Install-WinUtilWinget -Times 1 -Exactly
|
Should -Invoke -CommandName Install-WinUtilWinget -Times 1 -Exactly
|
||||||
Should -Invoke -CommandName Install-WinUtilProgramWinget -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Install-WinUtilProgramWinget -Times 1 -Exactly -ParameterFilter {
|
||||||
@@ -223,21 +233,34 @@ Describe "Invoke-WPFInstall runspace body" {
|
|||||||
Should -Invoke -CommandName Install-WinUtilProgramChoco -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Install-WinUtilProgramChoco -Times 1 -Exactly -ParameterFilter {
|
||||||
$Action -eq "Install" -and @($Programs)[0] -eq "vlc"
|
$Action -eq "Install" -and @($Programs)[0] -eq "vlc"
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Hide-WPFInstallAppBusy -Times 1 -Exactly
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*$sync.ItemsControl.IsEnabled = $false*'
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*$sync.ItemsControl.IsEnabled = $true*'
|
||||||
|
}
|
||||||
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "None" -overlay "checkmark"*'
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "None" -overlay "checkmark"*'
|
||||||
}
|
}
|
||||||
$script:sync.ProcessRunning | Should -BeFalse
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
It "hides the busy overlay, sets taskbar error state, and clears ProcessRunning on failure" {
|
It "shows failure progress, sets taskbar error state, and clears ProcessRunning on failure" {
|
||||||
Mock Install-WinUtilProgramWinget { throw "winget failed" }
|
Mock Install-WinUtilProgramWinget { throw "winget failed" }
|
||||||
|
|
||||||
Invoke-WPFInstall
|
Invoke-WPFInstall
|
||||||
|
|
||||||
& $script:capturedInstallScriptBlock -PackagesToInstall @($script:package) -ManagerPreference "Winget"
|
& $script:capturedInstallScriptBlock -PackagesToInstall @($script:package) -ManagerPreference "Winget"
|
||||||
|
|
||||||
Should -Invoke -CommandName Hide-WPFInstallAppBusy -Times 1 -Exactly
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "App install failed" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*$sync.ItemsControl.IsEnabled = $false*'
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*$sync.ItemsControl.IsEnabled = $true*'
|
||||||
|
}
|
||||||
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "Error" -overlay "warning"*'
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "Error" -overlay "warning"*'
|
||||||
}
|
}
|
||||||
@@ -345,8 +368,7 @@ Describe "Invoke-WPFUnInstall runspace body" {
|
|||||||
Mock Get-WinUtilSelectedPackages {
|
Mock Get-WinUtilSelectedPackages {
|
||||||
New-WinUtilPackageSplit -Winget @("Git.Git") -Choco @("vlc")
|
New-WinUtilPackageSplit -Winget @("Git.Git") -Choco @("vlc")
|
||||||
}
|
}
|
||||||
Mock Show-WPFInstallAppBusy { }
|
Mock Set-WinUtilTweaksProgressIndicator { }
|
||||||
Mock Hide-WPFInstallAppBusy { }
|
|
||||||
Mock Install-WinUtilProgramWinget { }
|
Mock Install-WinUtilProgramWinget { }
|
||||||
Mock Install-WinUtilProgramChoco { }
|
Mock Install-WinUtilProgramChoco { }
|
||||||
Mock Invoke-WPFUIThread { }
|
Mock Invoke-WPFUIThread { }
|
||||||
@@ -369,8 +391,17 @@ Describe "Invoke-WPFUnInstall runspace body" {
|
|||||||
Should -Invoke -CommandName Get-WinUtilSelectedPackages -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Get-WinUtilSelectedPackages -Times 1 -Exactly -ParameterFilter {
|
||||||
@($PackageList).Count -eq 1 -and $Preference -eq "Winget"
|
@($PackageList).Count -eq 1 -and $Preference -eq "Winget"
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Show-WPFInstallAppBusy -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
$text -eq "Uninstalling apps..."
|
$Visible -eq $true -and $Label -eq "Preparing app uninstall (0/2)" -and $Percent -eq 0
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Uninstalled Git.Git (1/2)" -and $Percent -eq 50
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Uninstalled Chocolatey packages (2/2)" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "App uninstall finished" -and $Percent -eq 100
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Install-WinUtilProgramWinget -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Install-WinUtilProgramWinget -Times 1 -Exactly -ParameterFilter {
|
||||||
$Action -eq "Uninstall" -and @($Programs)[0] -eq "Git.Git"
|
$Action -eq "Uninstall" -and @($Programs)[0] -eq "Git.Git"
|
||||||
@@ -378,21 +409,34 @@ Describe "Invoke-WPFUnInstall runspace body" {
|
|||||||
Should -Invoke -CommandName Install-WinUtilProgramChoco -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Install-WinUtilProgramChoco -Times 1 -Exactly -ParameterFilter {
|
||||||
$Action -eq "Uninstall" -and @($Programs)[0] -eq "vlc"
|
$Action -eq "Uninstall" -and @($Programs)[0] -eq "vlc"
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Hide-WPFInstallAppBusy -Times 1 -Exactly
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*$sync.ItemsControl.IsEnabled = $false*'
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*$sync.ItemsControl.IsEnabled = $true*'
|
||||||
|
}
|
||||||
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "None" -overlay "checkmark"*'
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "None" -overlay "checkmark"*'
|
||||||
}
|
}
|
||||||
$script:sync.ProcessRunning | Should -BeFalse
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
}
|
}
|
||||||
|
|
||||||
It "hides the busy overlay, sets taskbar error state, and clears ProcessRunning on failure" {
|
It "shows failure progress, sets taskbar error state, and clears ProcessRunning on failure" {
|
||||||
Mock Install-WinUtilProgramWinget { throw "winget failed" }
|
Mock Install-WinUtilProgramWinget { throw "winget failed" }
|
||||||
|
|
||||||
Invoke-WPFUnInstall -PackagesToUninstall @($script:package)
|
Invoke-WPFUnInstall -PackagesToUninstall @($script:package)
|
||||||
|
|
||||||
& $script:capturedUninstallScriptBlock -PackagesToUninstall @($script:package) -ManagerPreference "Winget"
|
& $script:capturedUninstallScriptBlock -PackagesToUninstall @($script:package) -ManagerPreference "Winget"
|
||||||
|
|
||||||
Should -Invoke -CommandName Hide-WPFInstallAppBusy -Times 1 -Exactly
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "App uninstall failed" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*$sync.ItemsControl.IsEnabled = $false*'
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*$sync.ItemsControl.IsEnabled = $true*'
|
||||||
|
}
|
||||||
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "Error" -overlay "warning"*'
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "Error" -overlay "warning"*'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,23 @@ Describe "Initialize-WinUtilTabContent" {
|
|||||||
$targetGridName -eq "appxpanel" -and $columncount -eq 2
|
$targetGridName -eq "appxpanel" -and $columncount -eq 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "checks for existing Win11ISO work when the tab is initialized" {
|
||||||
|
Add-Type -AssemblyName WindowsBase
|
||||||
|
$dispatcher = [pscustomobject]@{}
|
||||||
|
$dispatcher | Add-Member -MemberType ScriptMethod -Name BeginInvoke -Value {
|
||||||
|
param($priority, $action)
|
||||||
|
$action.Invoke()
|
||||||
|
}
|
||||||
|
$script:sync.Form = [pscustomobject]@{ Dispatcher = $dispatcher }
|
||||||
|
Mock Invoke-WinUtilISOCheckExistingWork { }
|
||||||
|
|
||||||
|
Initialize-WinUtilTabContent -TabName "Win11ISO"
|
||||||
|
Initialize-WinUtilTabContent -TabName "Win11ISO"
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Invoke-WinUtilISOCheckExistingWork -Times 1 -Exactly
|
||||||
|
$script:sync.InitializedTabs["Win11ISO"] | Should -BeTrue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Describe "Startup lazy tab wiring" {
|
Describe "Startup lazy tab wiring" {
|
||||||
@@ -96,4 +113,12 @@ Describe "Startup lazy tab wiring" {
|
|||||||
$rendererScript | Should -Match '\$sync\.Buttons\.Add\(\$button\.Name\)'
|
$rendererScript | Should -Match '\$sync\.Buttons\.Add\(\$button\.Name\)'
|
||||||
$mainScript | Should -Match '\$sync\.Buttons -notcontains \$psitem'
|
$mainScript | Should -Match '\$sync\.Buttons -notcontains \$psitem'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "binds generated documentation links when lazy panels are rendered" {
|
||||||
|
$rendererScript = Get-Content -Path (Join-Path $script:repoRoot "functions\public\Invoke-WPFUIElements.ps1") -Raw
|
||||||
|
$mainScript = Get-Content -Path (Join-Path $script:repoRoot "scripts\main.ps1") -Raw
|
||||||
|
|
||||||
|
$rendererScript | Should -Match '(?s)if \(\$entryInfo\.Link\).*\$textBlock\.Add_MouseUp\(\{.*Start-Process \$Sender\.ToolTip -ErrorAction Stop'
|
||||||
|
$mainScript | Should -Not -Match '\.Name\.EndsWith\("Link"\)'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
#===========================================================================
|
||||||
|
# Tests - O&O ShutUp10++ Download Workflow
|
||||||
|
#===========================================================================
|
||||||
|
|
||||||
|
BeforeAll {
|
||||||
|
$script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||||
|
|
||||||
|
. (Join-Path $script:repoRoot "functions\private\Save-WinUtilFile.ps1")
|
||||||
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFOOSU.ps1")
|
||||||
|
|
||||||
|
function Invoke-WPFRunspace {
|
||||||
|
param($ArgumentList, $ParameterList, [scriptblock]$ScriptBlock)
|
||||||
|
}
|
||||||
|
function Set-WinUtilTweaksProgressIndicator {
|
||||||
|
param($Visible, $Label, $Percent)
|
||||||
|
}
|
||||||
|
function Show-WinUtilMessage {
|
||||||
|
param($Message, $Title, $Button, $Icon)
|
||||||
|
}
|
||||||
|
function Write-WinUtilLog {
|
||||||
|
param($Message, $Level, $Component)
|
||||||
|
}
|
||||||
|
|
||||||
|
function script:New-WinUtilOOSUTestContext {
|
||||||
|
param([bool]$ProcessRunning = $false)
|
||||||
|
|
||||||
|
$script:sync = [Hashtable]::Synchronized(@{
|
||||||
|
ProcessRunning = $ProcessRunning
|
||||||
|
winutildir = $TestDrive
|
||||||
|
Form = [pscustomobject]@{
|
||||||
|
Dispatcher = [pscustomobject]@{}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Save-WinUtilFile" {
|
||||||
|
It "copies a download and reports its percentage" {
|
||||||
|
$sourcePath = Join-Path $TestDrive "source.bin"
|
||||||
|
$destinationPath = Join-Path $TestDrive "destination.bin"
|
||||||
|
$sourceBytes = [byte[]](0..255)
|
||||||
|
[System.IO.File]::WriteAllBytes($sourcePath, $sourceBytes)
|
||||||
|
$reportedProgress = [System.Collections.Generic.List[int]]::new()
|
||||||
|
|
||||||
|
Save-WinUtilFile -Uri ([uri]$sourcePath) -DestinationPath $destinationPath -ProgressCallback {
|
||||||
|
param($percent)
|
||||||
|
$reportedProgress.Add($percent)
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.IO.File]::ReadAllBytes($destinationPath) | Should -Be $sourceBytes
|
||||||
|
$reportedProgress[-1] | Should -Be 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Invoke-WPFOOSU" {
|
||||||
|
BeforeEach {
|
||||||
|
New-WinUtilOOSUTestContext
|
||||||
|
$script:capturedScriptBlock = $null
|
||||||
|
$script:capturedParameterList = $null
|
||||||
|
|
||||||
|
Mock Invoke-WPFRunspace {
|
||||||
|
$script:capturedScriptBlock = $ScriptBlock
|
||||||
|
$script:capturedParameterList = $ParameterList
|
||||||
|
[pscustomobject]@{ MockHandle = $true }
|
||||||
|
}
|
||||||
|
Mock Set-WinUtilTweaksProgressIndicator { }
|
||||||
|
Mock Show-WinUtilMessage { }
|
||||||
|
Mock Write-WinUtilLog { }
|
||||||
|
Mock Start-Process { }
|
||||||
|
Mock Write-Error { }
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterEach {
|
||||||
|
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name capturedScriptBlock -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name capturedParameterList -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
It "queues the download in a background runspace" {
|
||||||
|
Invoke-WPFOOSU
|
||||||
|
|
||||||
|
$script:sync.ProcessRunning | Should -BeTrue
|
||||||
|
Should -Invoke Invoke-WPFRunspace -Times 1 -Exactly
|
||||||
|
$script:capturedParameterList[0][0] | Should -Be "downloadPath"
|
||||||
|
$script:capturedParameterList[0][1] | Should -Be (Join-Path $TestDrive "ooshutup10.exe")
|
||||||
|
}
|
||||||
|
|
||||||
|
It "does not start while another process is running" {
|
||||||
|
New-WinUtilOOSUTestContext -ProcessRunning $true
|
||||||
|
|
||||||
|
Invoke-WPFOOSU
|
||||||
|
|
||||||
|
Should -Invoke Show-WinUtilMessage -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Message -eq "Another process is currently running." -and
|
||||||
|
$Title -eq "WinUtil" -and
|
||||||
|
$Button -eq "OK" -and
|
||||||
|
$Icon -eq "Warning"
|
||||||
|
}
|
||||||
|
Should -Not -Invoke Invoke-WPFRunspace
|
||||||
|
}
|
||||||
|
|
||||||
|
It "maps download progress to the window indicator and launches O&O ShutUp10++" {
|
||||||
|
Mock Save-WinUtilFile {
|
||||||
|
& $ProgressCallback 35
|
||||||
|
& $ProgressCallback 100
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-WPFOOSU
|
||||||
|
& $script:capturedScriptBlock -downloadPath $script:capturedParameterList[0][1]
|
||||||
|
|
||||||
|
Should -Invoke Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Downloading O&O ShutUp10++ (0%)" -and $Percent -eq 0
|
||||||
|
}
|
||||||
|
Should -Invoke Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Downloading O&O ShutUp10++ (35%)" -and $Percent -eq 35
|
||||||
|
}
|
||||||
|
Should -Invoke Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "O&O ShutUp10++ launched" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke Start-Process -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$FilePath -eq (Join-Path $TestDrive "ooshutup10.exe")
|
||||||
|
}
|
||||||
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
It "shows failure progress and clears the running state when the download fails" {
|
||||||
|
Mock Save-WinUtilFile { throw "download failed" }
|
||||||
|
|
||||||
|
Invoke-WPFOOSU
|
||||||
|
& $script:capturedScriptBlock -downloadPath $script:capturedParameterList[0][1]
|
||||||
|
|
||||||
|
Should -Invoke Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "O&O ShutUp10++ download failed" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Not -Invoke Start-Process
|
||||||
|
Should -Invoke Write-Error -Times 1 -Exactly
|
||||||
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -140,6 +140,10 @@ Describe "Invoke-WPFRunspace behavior" {
|
|||||||
$runspaceScript | Should -Not -Match '\$script:powershell'
|
$runspaceScript | Should -Not -Match '\$script:powershell'
|
||||||
$runspaceScript | Should -Not -Match '\$script:handle'
|
$runspaceScript | Should -Not -Match '\$script:handle'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "exposes a strongly typed cleanup callback" {
|
||||||
|
([WinUtilRunspaceCleanup]::Callback -is [System.Threading.WaitOrTimerCallback]) | Should -BeTrue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Describe "Public runspace callers" {
|
Describe "Public runspace callers" {
|
||||||
|
|||||||
@@ -6,12 +6,82 @@ $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
|||||||
|
|
||||||
BeforeAll {
|
BeforeAll {
|
||||||
$script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
$script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||||
|
. (Join-Path $script:repoRoot "functions\private\Invoke-WinUtilCurrentSystem.ps1")
|
||||||
. (Join-Path $script:repoRoot "functions\private\Set-WinUtilRegistry.ps1")
|
. (Join-Path $script:repoRoot "functions\private\Set-WinUtilRegistry.ps1")
|
||||||
. (Join-Path $script:repoRoot "functions\private\Set-WinUtilService.ps1")
|
. (Join-Path $script:repoRoot "functions\private\Set-WinUtilService.ps1")
|
||||||
|
|
||||||
|
function winget {
|
||||||
|
param([Parameter(ValueFromRemainingArguments = $true)]$Arguments)
|
||||||
|
}
|
||||||
|
function choco {
|
||||||
|
param([Parameter(ValueFromRemainingArguments = $true)]$Arguments)
|
||||||
|
}
|
||||||
function Write-WinUtilLog { }
|
function Write-WinUtilLog { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Describe "Invoke-WinUtilCurrentSystem installed apps" {
|
||||||
|
BeforeEach {
|
||||||
|
$script:sync = [Hashtable]::Synchronized(@{
|
||||||
|
configs = [pscustomobject]@{
|
||||||
|
applicationsHashtable = @{
|
||||||
|
WPFInstallGit = [pscustomobject]@{ winget = "Git.Git"; choco = "git" }
|
||||||
|
WPFInstallChatGPT = [pscustomobject]@{ winget = "msstore:9NT1R1C2HH7J"; choco = "na" }
|
||||||
|
WPFInstallMissing = [pscustomobject]@{ winget = "Git"; choco = "missing" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Mock winget {
|
||||||
|
$global:LASTEXITCODE = 0
|
||||||
|
$script:wingetArguments = @($Arguments)
|
||||||
|
@(
|
||||||
|
"Name Id Version Source",
|
||||||
|
"--------------------------------",
|
||||||
|
"Git Git.Git 2.0 winget",
|
||||||
|
"ChatGPT 9NT1R1C2HH7J 1.0 msstore"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Mock choco {
|
||||||
|
$script:chocoArguments = @($Arguments)
|
||||||
|
@("Chocolatey v2", "git 2.0", "2 packages installed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterEach {
|
||||||
|
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name wingetArguments -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name chocoArguments -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
It "matches single standard and Microsoft Store package IDs" {
|
||||||
|
$result = @(Invoke-WinUtilCurrentSystem -CheckBox "winget")
|
||||||
|
|
||||||
|
$result | Should -HaveCount 2
|
||||||
|
$result | Should -Contain "WPFInstallGit"
|
||||||
|
$result | Should -Contain "WPFInstallChatGPT"
|
||||||
|
$result | Should -Not -Contain "WPFInstallMissing"
|
||||||
|
Should -Invoke -CommandName winget -Times 1 -Exactly
|
||||||
|
$script:wingetArguments | Should -Be @("list", "--accept-source-agreements", "--disable-interactivity")
|
||||||
|
}
|
||||||
|
|
||||||
|
It "fails promptly when Winget cannot list applications" {
|
||||||
|
Mock winget {
|
||||||
|
$global:LASTEXITCODE = 1
|
||||||
|
"winget failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Invoke-WinUtilCurrentSystem -CheckBox "winget" } | Should -Throw "winget list failed with exit code 1."
|
||||||
|
}
|
||||||
|
|
||||||
|
It "matches the primary Chocolatey package ID in one list call" {
|
||||||
|
$result = @(Invoke-WinUtilCurrentSystem -CheckBox "choco")
|
||||||
|
|
||||||
|
$result | Should -Be @("WPFInstallGit")
|
||||||
|
Should -Invoke -CommandName choco -Times 1 -Exactly
|
||||||
|
$script:chocoArguments | Should -Be @("list")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Describe "Set-WinUtilRegistry" {
|
Describe "Set-WinUtilRegistry" {
|
||||||
BeforeEach {
|
BeforeEach {
|
||||||
$script:testPathResults = @{}
|
$script:testPathResults = @{}
|
||||||
|
|||||||
@@ -31,9 +31,6 @@ BeforeAll {
|
|||||||
function Invoke-WPFUIThread {
|
function Invoke-WPFUIThread {
|
||||||
param([scriptblock]$ScriptBlock)
|
param([scriptblock]$ScriptBlock)
|
||||||
}
|
}
|
||||||
function Set-WinUtilProgressBar {
|
|
||||||
param($Label, $Percent)
|
|
||||||
}
|
|
||||||
function Set-WinUtilTweaksProgressIndicator {
|
function Set-WinUtilTweaksProgressIndicator {
|
||||||
param($Visible, $Label, $Percent)
|
param($Visible, $Label, $Percent)
|
||||||
}
|
}
|
||||||
@@ -187,7 +184,6 @@ Describe "Invoke-WPFtweaksbutton" {
|
|||||||
Mock Invoke-WPFRunspace { [pscustomobject]@{ MockHandle = $true } }
|
Mock Invoke-WPFRunspace { [pscustomobject]@{ MockHandle = $true } }
|
||||||
Mock Invoke-WinUtilTweaks { }
|
Mock Invoke-WinUtilTweaks { }
|
||||||
Mock Invoke-WPFUIThread { }
|
Mock Invoke-WPFUIThread { }
|
||||||
Mock Set-WinUtilProgressBar { }
|
|
||||||
Mock Write-WinUtilLog { }
|
Mock Write-WinUtilLog { }
|
||||||
Mock Write-Host { }
|
Mock Write-Host { }
|
||||||
}
|
}
|
||||||
|
|||||||
+119
-9
@@ -61,17 +61,32 @@ namespace System.Windows.Controls
|
|||||||
|
|
||||||
. (Join-Path $script:repoRoot "functions\private\Update-WinUtilSelections.ps1")
|
. (Join-Path $script:repoRoot "functions\private\Update-WinUtilSelections.ps1")
|
||||||
. (Join-Path $script:repoRoot "functions\private\Reset-WPFCheckBoxes.ps1")
|
. (Join-Path $script:repoRoot "functions\private\Reset-WPFCheckBoxes.ps1")
|
||||||
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFGetInstalled.ps1")
|
||||||
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFSelectedCheckboxesUpdate.ps1")
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFSelectedCheckboxesUpdate.ps1")
|
||||||
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFButton.ps1")
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFButton.ps1")
|
||||||
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFToggleAllCategories.ps1")
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFToggleAllCategories.ps1")
|
||||||
|
|
||||||
function Set-WinUtilProgressBar {
|
|
||||||
param($Label, $Percent)
|
|
||||||
}
|
|
||||||
|
|
||||||
function Set-WinUtilTweaksProgressIndicator {
|
function Set-WinUtilTweaksProgressIndicator {
|
||||||
param($Visible, $Label, $Percent)
|
param($Visible, $Label, $Percent)
|
||||||
}
|
}
|
||||||
|
function Invoke-WPFRunspace {
|
||||||
|
param($ArgumentList, $ParameterList, [scriptblock]$ScriptBlock)
|
||||||
|
}
|
||||||
|
function Invoke-WPFUIThread {
|
||||||
|
param([scriptblock]$ScriptBlock)
|
||||||
|
}
|
||||||
|
function Invoke-WinUtilCurrentSystem {
|
||||||
|
param($CheckBox)
|
||||||
|
}
|
||||||
|
function Set-WinUtilTaskbaritem {
|
||||||
|
param($state)
|
||||||
|
}
|
||||||
|
function Test-WinUtilPackageManager {
|
||||||
|
param([switch]$winget)
|
||||||
|
}
|
||||||
|
function Write-WinUtilLog {
|
||||||
|
param($Message, $Level, $Component)
|
||||||
|
}
|
||||||
|
|
||||||
function script:New-WinUtilFakeCheckBox {
|
function script:New-WinUtilFakeCheckBox {
|
||||||
param([bool]$IsChecked = $false)
|
param([bool]$IsChecked = $false)
|
||||||
@@ -184,6 +199,9 @@ Describe "Invoke-WPFSelectedCheckboxesUpdate" {
|
|||||||
@($script:sync.selectedToggles) | Should -Be @("WPFToggleDarkMode")
|
@($script:sync.selectedToggles) | Should -Be @("WPFToggleDarkMode")
|
||||||
@($script:sync.selectedFeatures) | Should -Be @("WPFFeatureSandbox")
|
@($script:sync.selectedFeatures) | Should -Be @("WPFFeatureSandbox")
|
||||||
@($script:sync.selectedAppx) | Should -Be @("WPFAppxExample")
|
@($script:sync.selectedAppx) | Should -Be @("WPFAppxExample")
|
||||||
|
$script:sync.WPFselectedAppsButton.Content | Should -Be "Selected Apps: 1"
|
||||||
|
$script:sync.selectedAppsstackPanel.Children.Count | Should -Be 1
|
||||||
|
$script:sync.selectedAppsstackPanel.Children[0].Key | Should -Be "WPFInstallGit"
|
||||||
}
|
}
|
||||||
|
|
||||||
It "removes checkbox keys from the matching selected lists" {
|
It "removes checkbox keys from the matching selected lists" {
|
||||||
@@ -204,6 +222,94 @@ Describe "Invoke-WPFSelectedCheckboxesUpdate" {
|
|||||||
$script:sync.selectedToggles.Count | Should -Be 0
|
$script:sync.selectedToggles.Count | Should -Be 0
|
||||||
$script:sync.selectedFeatures.Count | Should -Be 0
|
$script:sync.selectedFeatures.Count | Should -Be 0
|
||||||
$script:sync.selectedAppx.Count | Should -Be 0
|
$script:sync.selectedAppx.Count | Should -Be 0
|
||||||
|
$script:sync.WPFselectedAppsButton.Content | Should -Be "Selected Apps: 0"
|
||||||
|
$script:sync.selectedAppsstackPanel.Children.Count | Should -Be 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Invoke-WPFGetInstalled selection state" {
|
||||||
|
BeforeEach {
|
||||||
|
New-WinUtilUiStateTestContext
|
||||||
|
|
||||||
|
$script:sync.ProcessRunning = $false
|
||||||
|
$script:sync.ChocoRadioButton = [pscustomobject]@{ IsChecked = $false }
|
||||||
|
$script:sync.preferences = [pscustomobject]@{ packagemanager = "Winget" }
|
||||||
|
$script:sync.WPFInstallGit = New-WinUtilFakeCheckBox
|
||||||
|
$dispatcher = [pscustomobject]@{}
|
||||||
|
$dispatcher | Add-Member -MemberType ScriptMethod -Name BeginInvoke -Value {
|
||||||
|
param($Action, [object[]]$Arguments)
|
||||||
|
$Action.DynamicInvoke($Arguments)
|
||||||
|
}
|
||||||
|
$script:sync.Form = [pscustomobject]@{ Dispatcher = $dispatcher }
|
||||||
|
$script:capturedGetInstalledScriptBlock = $null
|
||||||
|
$script:capturedGetInstalledParameters = @{}
|
||||||
|
|
||||||
|
Mock Test-WinUtilPackageManager { "installed" }
|
||||||
|
Mock Invoke-WinUtilCurrentSystem { @("WPFInstallGit") }
|
||||||
|
Mock Set-WinUtilTaskbaritem { }
|
||||||
|
Mock Write-WinUtilLog { }
|
||||||
|
Mock Write-Warning { }
|
||||||
|
Mock Invoke-WPFRunspace {
|
||||||
|
$script:capturedGetInstalledScriptBlock = $ScriptBlock
|
||||||
|
foreach ($parameter in $ParameterList) {
|
||||||
|
$script:capturedGetInstalledParameters[$parameter[0]] = $parameter[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterEach {
|
||||||
|
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name sync -Scope Global -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name capturedGetInstalledScriptBlock -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name capturedGetInstalledParameters -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
It "updates the selected app model, checkbox, count, and popup" {
|
||||||
|
Invoke-WPFGetInstalled -CheckBox "winget"
|
||||||
|
& $script:capturedGetInstalledScriptBlock `
|
||||||
|
-checkbox "winget" `
|
||||||
|
-managerPreference "Winget" `
|
||||||
|
-operation $script:capturedGetInstalledParameters.operation `
|
||||||
|
-completeAction $script:capturedGetInstalledParameters.completeAction
|
||||||
|
|
||||||
|
@($script:sync.selectedApps) | Should -Be @("WPFInstallGit")
|
||||||
|
$script:sync.WPFInstallGit.IsChecked | Should -BeTrue
|
||||||
|
$script:sync.WPFselectedAppsButton.Content | Should -Be "Selected Apps: 1"
|
||||||
|
$script:sync.selectedAppsstackPanel.Children.Count | Should -Be 1
|
||||||
|
$script:sync.selectedAppsstackPanel.Children[0].Key | Should -Be "WPFInstallGit"
|
||||||
|
}
|
||||||
|
|
||||||
|
It "clears the running state when detection fails" {
|
||||||
|
Mock Invoke-WinUtilCurrentSystem { throw "detection failed" }
|
||||||
|
|
||||||
|
Invoke-WPFGetInstalled -CheckBox "winget"
|
||||||
|
& $script:capturedGetInstalledScriptBlock `
|
||||||
|
-checkbox "winget" `
|
||||||
|
-managerPreference "Winget" `
|
||||||
|
-operation $script:capturedGetInstalledParameters.operation `
|
||||||
|
-completeAction $script:capturedGetInstalledParameters.completeAction
|
||||||
|
|
||||||
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
|
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Level -eq "ERROR" -and
|
||||||
|
$Component -eq "Install" -and
|
||||||
|
$Message -eq "Get installed state failed: detection failed"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTaskbaritem -Times 1 -Exactly -ParameterFilter { $state -eq "None" }
|
||||||
|
}
|
||||||
|
|
||||||
|
It "clears the running state when the worker cannot be queued" {
|
||||||
|
Mock Invoke-WPFRunspace { throw "queue failed" }
|
||||||
|
|
||||||
|
Invoke-WPFGetInstalled -CheckBox "winget"
|
||||||
|
|
||||||
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
|
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Level -eq "ERROR" -and
|
||||||
|
$Component -eq "Install" -and
|
||||||
|
$Message -eq "Get installed state failed: queue failed"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTaskbaritem -Times 1 -Exactly -ParameterFilter { $state -eq "None" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +409,6 @@ Describe "Invoke-WPFToggleAllCategories" {
|
|||||||
Describe "Invoke-WPFButton progress cleanup" {
|
Describe "Invoke-WPFButton progress cleanup" {
|
||||||
BeforeEach {
|
BeforeEach {
|
||||||
New-WinUtilUiStateTestContext
|
New-WinUtilUiStateTestContext
|
||||||
Mock Set-WinUtilProgressBar { }
|
|
||||||
Mock Set-WinUtilTweaksProgressIndicator { }
|
Mock Set-WinUtilTweaksProgressIndicator { }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,9 +422,6 @@ Describe "Invoke-WPFButton progress cleanup" {
|
|||||||
|
|
||||||
Invoke-WPFButton -Button "WPFNoOp"
|
Invoke-WPFButton -Button "WPFNoOp"
|
||||||
|
|
||||||
Should -Invoke Set-WinUtilProgressBar -Times 1 -Exactly -ParameterFilter {
|
|
||||||
$Label -eq "" -and $Percent -eq 0
|
|
||||||
}
|
|
||||||
Should -Invoke Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
$Visible -eq $false
|
$Visible -eq $false
|
||||||
}
|
}
|
||||||
@@ -330,7 +432,15 @@ Describe "Invoke-WPFButton progress cleanup" {
|
|||||||
|
|
||||||
Invoke-WPFButton -Button "WPFNoOp"
|
Invoke-WPFButton -Button "WPFNoOp"
|
||||||
|
|
||||||
Should -Not -Invoke Set-WinUtilProgressBar
|
Should -Not -Invoke Set-WinUtilTweaksProgressIndicator
|
||||||
|
}
|
||||||
|
|
||||||
|
It "leaves progress visible while a Win11 ISO process is running" {
|
||||||
|
$script:sync.ProcessRunning = $false
|
||||||
|
$script:sync.Win11ISOProcessRunning = $true
|
||||||
|
|
||||||
|
Invoke-WPFButton -Button "WPFNoOp"
|
||||||
|
|
||||||
Should -Not -Invoke Set-WinUtilTweaksProgressIndicator
|
Should -Not -Invoke Set-WinUtilTweaksProgressIndicator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,11 @@ BeforeAll {
|
|||||||
function Write-WinUtilLog {
|
function Write-WinUtilLog {
|
||||||
param($Message, $Level, $Component)
|
param($Message, $Level, $Component)
|
||||||
}
|
}
|
||||||
|
function Show-WinUtilMessage {
|
||||||
|
param($Message, $Title, $Button, $Icon)
|
||||||
|
}
|
||||||
function Get-ScheduledTask {
|
function Get-ScheduledTask {
|
||||||
param($TaskPath)
|
param($TaskPath, $ErrorAction)
|
||||||
}
|
}
|
||||||
function Disable-ScheduledTask {
|
function Disable-ScheduledTask {
|
||||||
param(
|
param(
|
||||||
@@ -51,6 +54,7 @@ Describe "Invoke-WPFUpdatesdisable" {
|
|||||||
BeforeEach {
|
BeforeEach {
|
||||||
Mock Write-Host { }
|
Mock Write-Host { }
|
||||||
Mock Write-WinUtilLog { }
|
Mock Write-WinUtilLog { }
|
||||||
|
Mock Show-WinUtilMessage { "Yes" }
|
||||||
Mock New-Item { }
|
Mock New-Item { }
|
||||||
Mock Set-ItemProperty { }
|
Mock Set-ItemProperty { }
|
||||||
Mock Set-Service { }
|
Mock Set-Service { }
|
||||||
@@ -88,25 +92,23 @@ Describe "Invoke-WPFUpdatesdisable" {
|
|||||||
$Type -eq "DWord" -and
|
$Type -eq "DWord" -and
|
||||||
$Value -eq 0
|
$Value -eq 0
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
|
||||||
$Path -eq "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" -and
|
|
||||||
$Name -eq "SettingsPageVisibility" -and
|
|
||||||
$Value -eq "hide:windowsupdate"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
It "disables update services and clears the SoftwareDistribution folder" {
|
It "disables update services and clears the SoftwareDistribution folder" {
|
||||||
Invoke-WPFUpdatesdisable
|
Invoke-WPFUpdatesdisable
|
||||||
|
|
||||||
|
foreach ($expectedServiceName in @("BITS", "wuauserv", "UsoSvc")) {
|
||||||
|
$expected = $expectedServiceName
|
||||||
|
Should -Invoke -CommandName Stop-Service -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Name -eq $expected -and $Force -eq $true
|
||||||
|
}
|
||||||
|
}
|
||||||
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
||||||
$Name -eq "BITS" -and $StartupType -eq "Disabled"
|
$Name -eq "BITS" -and $StartupType -eq "Disabled"
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
||||||
$Name -eq "wuauserv" -and $StartupType -eq "Disabled"
|
$Name -eq "wuauserv" -and $StartupType -eq "Disabled"
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Stop-Service -Times 1 -Exactly -ParameterFilter {
|
|
||||||
$Name -eq "UsoSvc" -and $Force -eq $true
|
|
||||||
}
|
|
||||||
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
||||||
$Name -eq "UsoSvc" -and $StartupType -eq "Disabled"
|
$Name -eq "UsoSvc" -and $StartupType -eq "Disabled"
|
||||||
}
|
}
|
||||||
@@ -128,6 +130,21 @@ Describe "Invoke-WPFUpdatesdisable" {
|
|||||||
}
|
}
|
||||||
Should -Invoke -CommandName Disable-ScheduledTask -Times $script:updateTaskPaths.Count -Exactly
|
Should -Invoke -CommandName Disable-ScheduledTask -Times $script:updateTaskPaths.Count -Exactly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "requires confirmation before disabling updates" {
|
||||||
|
Mock Show-WinUtilMessage { "No" }
|
||||||
|
|
||||||
|
Invoke-WPFUpdatesdisable
|
||||||
|
|
||||||
|
Should -Invoke Show-WinUtilMessage -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Title -eq "Disable Windows Update?" -and
|
||||||
|
$Button -eq "YesNo" -and
|
||||||
|
$Icon -eq "Warning"
|
||||||
|
}
|
||||||
|
Should -Not -Invoke Set-ItemProperty
|
||||||
|
Should -Not -Invoke Set-Service
|
||||||
|
Should -Not -Invoke Remove-Item
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Describe "Invoke-WPFUpdatesdefault" {
|
Describe "Invoke-WPFUpdatesdefault" {
|
||||||
@@ -136,6 +153,11 @@ Describe "Invoke-WPFUpdatesdefault" {
|
|||||||
Mock Write-WinUtilLog { }
|
Mock Write-WinUtilLog { }
|
||||||
Mock Remove-Item { }
|
Mock Remove-Item { }
|
||||||
Mock Remove-ItemProperty { }
|
Mock Remove-ItemProperty { }
|
||||||
|
Mock Get-ItemProperty {
|
||||||
|
[pscustomobject]@{
|
||||||
|
SettingsPageVisibility = "hide:windowsupdate"
|
||||||
|
}
|
||||||
|
}
|
||||||
Mock Set-Service { }
|
Mock Set-Service { }
|
||||||
Mock Start-Service { }
|
Mock Start-Service { }
|
||||||
Mock Get-ScheduledTask {
|
Mock Get-ScheduledTask {
|
||||||
@@ -147,30 +169,49 @@ Describe "Invoke-WPFUpdatesdefault" {
|
|||||||
Mock secedit { }
|
Mock secedit { }
|
||||||
}
|
}
|
||||||
|
|
||||||
It "removes update policy registry paths and shows the Windows Update settings page" {
|
It "removes only registry values managed by WinUtil" {
|
||||||
Invoke-WPFUpdatesdefault
|
Invoke-WPFUpdatesdefault
|
||||||
|
|
||||||
$expectedPaths = @(
|
$expectedRegistryValues = @(
|
||||||
"HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU",
|
@("HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU", "NoAutoUpdate", "AUOptions", "NoAutoRebootWithLoggedOnUsers", "AUPowerManagement"),
|
||||||
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization",
|
@("HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate", "ExcludeWUDriversInQualityUpdate", "DeferFeatureUpdates", "DeferFeatureUpdatesPeriodInDays", "DeferQualityUpdates", "DeferQualityUpdatesPeriodInDays"),
|
||||||
"HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings",
|
@("HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings", "BranchReadinessLevel", "DeferFeatureUpdatesPeriodInDays", "DeferQualityUpdatesPeriodInDays"),
|
||||||
"HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata",
|
@("HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata", "PreventDeviceMetadataFromNetwork"),
|
||||||
"HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching",
|
@("HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching", "DontPromptForWindowsUpdate", "DontSearchWindowsUpdate", "DriverUpdateWizardWuSearchEnabled"),
|
||||||
"HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
|
@("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config", "DODownloadMode")
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach ($expectedRegistryPath in $expectedPaths) {
|
foreach ($expectedEntry in $expectedRegistryValues) {
|
||||||
$expected = $expectedRegistryPath
|
$expectedPath = $expectedEntry[0]
|
||||||
Should -Invoke -CommandName Remove-Item -Times 1 -Exactly -ParameterFilter {
|
foreach ($expectedName in $expectedEntry[1..($expectedEntry.Count - 1)]) {
|
||||||
$Path -eq $expected -and $Recurse -eq $true -and $Force -eq $true
|
$valueName = $expectedName
|
||||||
|
Should -Invoke -CommandName Remove-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Path -eq $expectedPath -and $Name -eq $valueName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Should -Not -Invoke Remove-Item
|
||||||
Should -Invoke -CommandName Remove-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Remove-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
$Path -eq "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" -and
|
$Path -eq "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" -and
|
||||||
$Name -eq "SettingsPageVisibility"
|
$Name -eq "SettingsPageVisibility"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "preserves unrelated Settings page visibility policy" {
|
||||||
|
Mock Get-ItemProperty {
|
||||||
|
[pscustomobject]@{
|
||||||
|
SettingsPageVisibility = "hide:privacy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Invoke-WPFUpdatesdefault
|
||||||
|
|
||||||
|
Should -Not -Invoke Remove-ItemProperty -ParameterFilter {
|
||||||
|
$Path -eq "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" -and
|
||||||
|
$Name -eq "SettingsPageVisibility"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
It "restores update service startup types" {
|
It "restores update service startup types" {
|
||||||
Invoke-WPFUpdatesdefault
|
Invoke-WPFUpdatesdefault
|
||||||
|
|
||||||
@@ -186,12 +227,12 @@ Describe "Invoke-WPFUpdatesdefault" {
|
|||||||
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
||||||
$Name -eq "UsoSvc" -and $StartupType -eq "Automatic"
|
$Name -eq "UsoSvc" -and $StartupType -eq "Automatic"
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
Should -Not -Invoke Set-Service -ParameterFilter {
|
||||||
$Name -eq "WaaSMedicSvc" -and $StartupType -eq "Manual"
|
$Name -eq "WaaSMedicSvc"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
It "enables update scheduled task paths and resets local policy defaults" {
|
It "enables update scheduled task paths without resetting unrelated local security policy" {
|
||||||
Invoke-WPFUpdatesdefault
|
Invoke-WPFUpdatesdefault
|
||||||
|
|
||||||
foreach ($expectedTaskPath in $script:updateTaskPaths) {
|
foreach ($expectedTaskPath in $script:updateTaskPaths) {
|
||||||
@@ -201,13 +242,7 @@ Describe "Invoke-WPFUpdatesdefault" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Enable-ScheduledTask -Times $script:updateTaskPaths.Count -Exactly
|
Should -Invoke -CommandName Enable-ScheduledTask -Times $script:updateTaskPaths.Count -Exactly
|
||||||
Should -Invoke -CommandName secedit -Times 1 -Exactly -ParameterFilter {
|
Should -Not -Invoke secedit
|
||||||
$Arguments[0] -eq "/configure" -and
|
|
||||||
$Arguments[1] -eq "/cfg" -and
|
|
||||||
$Arguments[2] -like "*\inf\defltbase.inf" -and
|
|
||||||
$Arguments[3] -eq "/db" -and
|
|
||||||
$Arguments[4] -eq "defltbase.sdb"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +252,47 @@ Describe "Invoke-WPFUpdatessecurity" {
|
|||||||
Mock Write-WinUtilLog { }
|
Mock Write-WinUtilLog { }
|
||||||
Mock New-Item { }
|
Mock New-Item { }
|
||||||
Mock Set-ItemProperty { }
|
Mock Set-ItemProperty { }
|
||||||
|
Mock Remove-ItemProperty { }
|
||||||
|
Mock Set-Service { }
|
||||||
|
Mock Start-Service { }
|
||||||
|
Mock Get-ScheduledTask {
|
||||||
|
[pscustomobject]@{
|
||||||
|
TaskPath = $TaskPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mock Enable-ScheduledTask { }
|
||||||
|
}
|
||||||
|
|
||||||
|
It "restores update availability before applying recommended settings" {
|
||||||
|
Invoke-WPFUpdatessecurity
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Remove-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Path -eq "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -and
|
||||||
|
$Name -eq "NoAutoUpdate"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Remove-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Path -eq "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config" -and
|
||||||
|
$Name -eq "DODownloadMode"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Name -eq "BITS" -and $StartupType -eq "Manual"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Name -eq "wuauserv" -and $StartupType -eq "Manual"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-Service -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Name -eq "UsoSvc" -and $StartupType -eq "Automatic"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Start-Service -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Name -eq "UsoSvc"
|
||||||
|
}
|
||||||
|
foreach ($expectedTaskPath in $script:updateTaskPaths) {
|
||||||
|
$expected = $expectedTaskPath
|
||||||
|
Should -Invoke -CommandName Get-ScheduledTask -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$TaskPath -eq $expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Enable-ScheduledTask -Times $script:updateTaskPaths.Count -Exactly
|
||||||
}
|
}
|
||||||
|
|
||||||
It "disables driver metadata and Windows Update driver search" {
|
It "disables driver metadata and Windows Update driver search" {
|
||||||
@@ -261,23 +337,35 @@ Describe "Invoke-WPFUpdatessecurity" {
|
|||||||
Invoke-WPFUpdatessecurity
|
Invoke-WPFUpdatessecurity
|
||||||
|
|
||||||
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
$Path -eq "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -and
|
$Path -eq "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -and
|
||||||
$Name -eq "BranchReadinessLevel" -and
|
$Name -eq "DeferFeatureUpdates" -and
|
||||||
$Type -eq "DWord" -and
|
$Type -eq "DWord" -and
|
||||||
$Value -eq 20
|
$Value -eq 1
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
$Path -eq "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -and
|
$Path -eq "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -and
|
||||||
$Name -eq "DeferFeatureUpdatesPeriodInDays" -and
|
$Name -eq "DeferFeatureUpdatesPeriodInDays" -and
|
||||||
$Type -eq "DWord" -and
|
$Type -eq "DWord" -and
|
||||||
$Value -eq 365
|
$Value -eq 365
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
$Path -eq "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -and
|
$Path -eq "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -and
|
||||||
|
$Name -eq "DeferQualityUpdates" -and
|
||||||
|
$Type -eq "DWord" -and
|
||||||
|
$Value -eq 1
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Path -eq "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -and
|
||||||
$Name -eq "DeferQualityUpdatesPeriodInDays" -and
|
$Name -eq "DeferQualityUpdatesPeriodInDays" -and
|
||||||
$Type -eq "DWord" -and
|
$Type -eq "DWord" -and
|
||||||
$Value -eq 4
|
$Value -eq 4
|
||||||
}
|
}
|
||||||
|
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Path -eq "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -and
|
||||||
|
$Name -eq "AUOptions" -and
|
||||||
|
$Type -eq "DWord" -and
|
||||||
|
$Value -eq 4
|
||||||
|
}
|
||||||
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
$Path -eq "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -and
|
$Path -eq "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -and
|
||||||
$Name -eq "NoAutoRebootWithLoggedOnUsers" -and
|
$Name -eq "NoAutoRebootWithLoggedOnUsers" -and
|
||||||
@@ -291,4 +379,16 @@ Describe "Invoke-WPFUpdatessecurity" {
|
|||||||
$Value -eq 0
|
$Value -eq 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "removes legacy WinUtil deferral values from the unsupported UX settings path" {
|
||||||
|
Invoke-WPFUpdatessecurity
|
||||||
|
|
||||||
|
foreach ($expectedValueName in @("BranchReadinessLevel", "DeferFeatureUpdatesPeriodInDays", "DeferQualityUpdatesPeriodInDays")) {
|
||||||
|
$expected = $expectedValueName
|
||||||
|
Should -Invoke Remove-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Path -eq "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -and
|
||||||
|
$Name -eq $expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Describe "Win11 Creator setup media" {
|
|||||||
BeforeAll {
|
BeforeAll {
|
||||||
$script:repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
|
$script:repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
|
||||||
$script:isoWorkflowPath = Join-Path $script:repoRoot "functions\private\Invoke-WinUtilISO.ps1"
|
$script:isoWorkflowPath = Join-Path $script:repoRoot "functions\private\Invoke-WinUtilISO.ps1"
|
||||||
|
$script:isoUsbWorkflowPath = Join-Path $script:repoRoot "functions\private\Invoke-WinUtilISOUSB.ps1"
|
||||||
$script:isoScriptPath = Join-Path $script:repoRoot "functions\private\Invoke-WinUtilISOScript.ps1"
|
$script:isoScriptPath = Join-Path $script:repoRoot "functions\private\Invoke-WinUtilISOScript.ps1"
|
||||||
$script:autoUnattendPath = Join-Path $script:repoRoot "tools\autounattend.xml"
|
$script:autoUnattendPath = Join-Path $script:repoRoot "tools\autounattend.xml"
|
||||||
|
|
||||||
@@ -36,6 +37,9 @@ Describe "Win11 Creator setup media" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$script:modifyFunction = Get-WinUtilFunctionText -Path $script:isoWorkflowPath -FunctionName "Invoke-WinUtilISOModify"
|
$script:modifyFunction = Get-WinUtilFunctionText -Path $script:isoWorkflowPath -FunctionName "Invoke-WinUtilISOModify"
|
||||||
|
$script:cleanAndResetFunction = Get-WinUtilFunctionText -Path $script:isoWorkflowPath -FunctionName "Invoke-WinUtilISOCleanAndReset"
|
||||||
|
$script:exportFunction = Get-WinUtilFunctionText -Path $script:isoWorkflowPath -FunctionName "Invoke-WinUtilISOExport"
|
||||||
|
$script:writeUsbFunction = Get-WinUtilFunctionText -Path $script:isoUsbWorkflowPath -FunctionName "Invoke-WinUtilISOWriteUSB"
|
||||||
$script:editionIdFunction = Get-WinUtilFunctionText -Path $script:isoWorkflowPath -FunctionName "Get-WinUtilEditionIdFromName"
|
$script:editionIdFunction = Get-WinUtilFunctionText -Path $script:isoWorkflowPath -FunctionName "Get-WinUtilEditionIdFromName"
|
||||||
$script:addDriversFunction = Get-WinUtilFunctionText -Path $script:isoScriptPath -FunctionName "Add-DriversToImage"
|
$script:addDriversFunction = Get-WinUtilFunctionText -Path $script:isoScriptPath -FunctionName "Add-DriversToImage"
|
||||||
$script:answerFileChildElementFunction = Get-WinUtilFunctionText -Path $script:isoScriptPath -FunctionName "Get-WinUtilISOScriptChildElement"
|
$script:answerFileChildElementFunction = Get-WinUtilFunctionText -Path $script:isoScriptPath -FunctionName "Get-WinUtilISOScriptChildElement"
|
||||||
@@ -81,6 +85,18 @@ Describe "Win11 Creator setup media" {
|
|||||||
$script:modifyFunction | Should -Not -Match ([regex]::Escape("Reusing existing temp directory"))
|
$script:modifyFunction | Should -Not -Match ([regex]::Escape("Reusing existing temp directory"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "tracks every background ISO workflow with the shared busy state" {
|
||||||
|
foreach ($functionText in @(
|
||||||
|
$script:modifyFunction,
|
||||||
|
$script:cleanAndResetFunction,
|
||||||
|
$script:exportFunction,
|
||||||
|
$script:writeUsbFunction
|
||||||
|
)) {
|
||||||
|
$functionText | Should -Match ([regex]::Escape('$sync["Win11ISOProcessRunning"] = $true'))
|
||||||
|
$functionText | Should -Match ([regex]::Escape('$sync["Win11ISOProcessRunning"] = $false'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
It "mounts the copied image file that was verified from the ISO" {
|
It "mounts the copied image file that was verified from the ISO" {
|
||||||
foreach ($expectedText in @(
|
foreach ($expectedText in @(
|
||||||
'$sourceImageFileName = Split-Path $wimPath -Leaf',
|
'$sourceImageFileName = Split-Path $wimPath -Leaf',
|
||||||
|
|||||||
+18
-8
@@ -152,7 +152,6 @@ Describe "XAML document" {
|
|||||||
"appspanel",
|
"appspanel",
|
||||||
"tweakspanel",
|
"tweakspanel",
|
||||||
"featurespanel",
|
"featurespanel",
|
||||||
"updatespanel",
|
|
||||||
"appxpanel",
|
"appxpanel",
|
||||||
"WPFstandard",
|
"WPFstandard",
|
||||||
"WPFminimal",
|
"WPFminimal",
|
||||||
@@ -180,6 +179,23 @@ Describe "XAML document" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "presents the three Updates profiles with accurate action labels" {
|
||||||
|
$updatesTab = $script:xaml.SelectSingleNode('//*[local-name()="TabItem"][@Name="WPFTab4"]')
|
||||||
|
$profileGrid = $updatesTab.SelectSingleNode('.//*[local-name()="UniformGrid"]')
|
||||||
|
$expectedButtons = @{
|
||||||
|
WPFUpdatessecurity = "Apply Recommended"
|
||||||
|
WPFUpdatesdefault = "Restore Defaults"
|
||||||
|
WPFUpdatesdisable = "Disable Updates"
|
||||||
|
}
|
||||||
|
|
||||||
|
$profileGrid.GetAttribute("Columns") | Should -Be "3"
|
||||||
|
foreach ($buttonName in $expectedButtons.Keys) {
|
||||||
|
$button = $updatesTab.SelectSingleNode(".//*[local-name()='Button'][@Name='$buttonName']")
|
||||||
|
$button.GetAttribute("Content") | Should -Be $expectedButtons[$buttonName]
|
||||||
|
}
|
||||||
|
$updatesTab.SelectSingleNode('.//*[@Name="updatespanel"]') | Should -BeNullOrEmpty
|
||||||
|
}
|
||||||
|
|
||||||
It "contains Win11 Creator controls used by the ISO workflow" {
|
It "contains Win11 Creator controls used by the ISO workflow" {
|
||||||
$xamlNames = @(Get-WinUtilXamlRuntimeNamedControls | ForEach-Object { $_.Name })
|
$xamlNames = @(Get-WinUtilXamlRuntimeNamedControls | ForEach-Object { $_.Name })
|
||||||
$requiredControls = @(
|
$requiredControls = @(
|
||||||
@@ -419,7 +435,6 @@ Describe "XAML and sync wiring" {
|
|||||||
"appPopup",
|
"appPopup",
|
||||||
"appPopupSelectedApp",
|
"appPopupSelectedApp",
|
||||||
"ItemsControl",
|
"ItemsControl",
|
||||||
"InstalledPrograms",
|
|
||||||
"ImportInProgress",
|
"ImportInProgress",
|
||||||
"ScriptsInstallPrograms",
|
"ScriptsInstallPrograms",
|
||||||
"keys",
|
"keys",
|
||||||
@@ -432,20 +447,15 @@ Describe "XAML and sync wiring" {
|
|||||||
"InitializedTabs",
|
"InitializedTabs",
|
||||||
"RenderedAssetCache",
|
"RenderedAssetCache",
|
||||||
"ToggleStatusCache",
|
"ToggleStatusCache",
|
||||||
"InstallAppAreaBorder",
|
|
||||||
"InstallAppAreaScrollViewer",
|
|
||||||
"InstallAppAreaOverlay",
|
|
||||||
"InstallAppAreaOverlayText",
|
|
||||||
"InstallAppRenderQueue",
|
"InstallAppRenderQueue",
|
||||||
"InstallAppEntriesRendered",
|
"InstallAppEntriesRendered",
|
||||||
"ProgressBar",
|
|
||||||
"progressBarTextBlock",
|
|
||||||
"FontScaleFactor",
|
"FontScaleFactor",
|
||||||
"Win11ISOImageInfo",
|
"Win11ISOImageInfo",
|
||||||
"Win11ISODriveLetter",
|
"Win11ISODriveLetter",
|
||||||
"Win11ISOWimPath",
|
"Win11ISOWimPath",
|
||||||
"Win11ISOImagePath",
|
"Win11ISOImagePath",
|
||||||
"Win11ISOModifying",
|
"Win11ISOModifying",
|
||||||
|
"Win11ISOProcessRunning",
|
||||||
"Win11ISOWorkDir",
|
"Win11ISOWorkDir",
|
||||||
"Win11ISOContentsDir",
|
"Win11ISOContentsDir",
|
||||||
"Win11ISOUSBDisks"
|
"Win11ISOUSBDisks"
|
||||||
|
|||||||
@@ -128,9 +128,6 @@ Invoke-WinutilThemeChange -theme $sync.preferences.theme
|
|||||||
$sync.InitializedTabs = @{}
|
$sync.InitializedTabs = @{}
|
||||||
Initialize-WinUtilTabContent -TabName "Install"
|
Initialize-WinUtilTabContent -TabName "Install"
|
||||||
|
|
||||||
# Future implementation: Add Windows Version to updates panel
|
|
||||||
#Invoke-WPFUIElements -configVariable $sync.configs.updates -targetGridName "updatespanel" -columncount 1
|
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Store Form Objects In PowerShell
|
# Store Form Objects In PowerShell
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
@@ -171,15 +168,6 @@ $sync.keys | ForEach-Object {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($($sync["$psitem"].GetType() | Select-Object -ExpandProperty Name) -eq "TextBlock") {
|
|
||||||
if ($sync["$psitem"].Name.EndsWith("Link")) {
|
|
||||||
$sync["$psitem"].Add_MouseUp({
|
|
||||||
[System.Object]$Sender = $args[0]
|
|
||||||
Start-Process $Sender.ToolTip -ErrorAction Stop
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ $sync.configs = @{}
|
|||||||
$sync.Buttons = [System.Collections.Generic.List[PSObject]]::new()
|
$sync.Buttons = [System.Collections.Generic.List[PSObject]]::new()
|
||||||
$sync.preferences = @{}
|
$sync.preferences = @{}
|
||||||
$sync.ProcessRunning = $false
|
$sync.ProcessRunning = $false
|
||||||
|
$sync.Win11ISOProcessRunning = $false
|
||||||
$sync.selectedAppx = [System.Collections.Generic.List[string]]::new()
|
$sync.selectedAppx = [System.Collections.Generic.List[string]]::new()
|
||||||
$sync.selectedApps = [System.Collections.Generic.List[string]]::new()
|
$sync.selectedApps = [System.Collections.Generic.List[string]]::new()
|
||||||
$sync.selectedTweaks = [System.Collections.Generic.List[string]]::new()
|
$sync.selectedTweaks = [System.Collections.Generic.List[string]]::new()
|
||||||
|
|||||||
+180
-91
@@ -964,6 +964,39 @@
|
|||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
<!-- Filter Chip Style — used by the Install tab category filter buttons -->
|
||||||
|
<Style x:Key="FilterChipStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||||
|
<Setter Property="Margin" Value="2"/>
|
||||||
|
<Setter Property="Padding" Value="12,0,12,0"/>
|
||||||
|
<Setter Property="Width" Value="Auto"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border Name="ChipBorder"
|
||||||
|
Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{DynamicResource ButtonBorderThickness}"
|
||||||
|
CornerRadius="{DynamicResource ButtonCornerRadius}"
|
||||||
|
Padding="{TemplateBinding Padding}">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter TargetName="ChipBorder" Property="Background" Value="{DynamicResource ButtonBackgroundPressedColor}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter TargetName="ChipBorder" Property="Background" Value="{DynamicResource ButtonBackgroundMouseoverColor}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsEnabled" Value="False">
|
||||||
|
<Setter TargetName="ChipBorder" Property="Background" Value="{DynamicResource ButtonBackgroundSelectedColor}"/>
|
||||||
|
<Setter Property="Foreground" Value="DimGray"/>
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
<Grid Background="{DynamicResource MainBackgroundColor}" ShowGridLines="False" Name="WPFMainGrid" Width="Auto" Height="Auto" HorizontalAlignment="Stretch">
|
<Grid Background="{DynamicResource MainBackgroundColor}" ShowGridLines="False" Name="WPFMainGrid" Width="Auto" Height="Auto" HorizontalAlignment="Stretch">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
@@ -1282,16 +1315,23 @@
|
|||||||
|
|
||||||
<!-- Quick Category Search Chips -->
|
<!-- Quick Category Search Chips -->
|
||||||
<WrapPanel Grid.Row="0" Orientation="Horizontal" Margin="5,5,5,5" Name="WPFSearchChips">
|
<WrapPanel Grid.Row="0" Orientation="Horizontal" Margin="5,5,5,5" Name="WPFSearchChips">
|
||||||
<Button Name="WPFSearchChipAll" Content="All" Width="Auto" Height="Auto" Margin="2"/>
|
<TextBlock Text="Filters"
|
||||||
<Button Name="WPFSearchChipBrowsers" Content="Browsers" Width="Auto" Height="Auto" Margin="2"/>
|
FontSize="{DynamicResource HeaderFontSize}"
|
||||||
<Button Name="WPFSearchChipCommunications" Content="Communications" Width="Auto" Height="Auto" Margin="2"/>
|
FontFamily="{DynamicResource HeaderFontFamily}"
|
||||||
<Button Name="WPFSearchChipDevelopment" Content="Development" Width="Auto" Height="Auto" Margin="2"/>
|
Foreground="{DynamicResource LabelboxForegroundColor}"
|
||||||
<Button Name="WPFSearchChipGames" Content="Games" Width="Auto" Height="Auto" Margin="2"/>
|
Background="Transparent"
|
||||||
<Button Name="WPFSearchChipMicrosoftTools" Content="Microsoft Tools" Width="Auto" Height="Auto" Margin="2"/>
|
VerticalAlignment="Center"
|
||||||
<Button Name="WPFSearchChipMultimediaTools" Content="Multimedia Tools" Width="Auto" Height="Auto" Margin="2"/>
|
Margin="15,0,8,0"/>
|
||||||
<Button Name="WPFSearchChipProTools" Content="Pro Tools" Width="Auto" Height="Auto" Margin="2"/>
|
<Button Name="WPFSearchChipAll" Content="All" Style="{StaticResource FilterChipStyle}"/>
|
||||||
<Button Name="WPFSearchChipSelfhostedTools" Content="Selfhosted Tools" Width="Auto" Height="Auto" Margin="2"/>
|
<Button Name="WPFSearchChipBrowsers" Content="Browsers" Style="{StaticResource FilterChipStyle}"/>
|
||||||
<Button Name="WPFSearchChipUtilities" Content="Utilities" Width="Auto" Height="Auto" Margin="2"/>
|
<Button Name="WPFSearchChipCommunications" Content="Communications" Style="{StaticResource FilterChipStyle}"/>
|
||||||
|
<Button Name="WPFSearchChipDevelopment" Content="Development" Style="{StaticResource FilterChipStyle}"/>
|
||||||
|
<Button Name="WPFSearchChipGames" Content="Games" Style="{StaticResource FilterChipStyle}"/>
|
||||||
|
<Button Name="WPFSearchChipMicrosoftTools" Content="Microsoft Tools" Style="{StaticResource FilterChipStyle}"/>
|
||||||
|
<Button Name="WPFSearchChipMultimediaTools" Content="Multimedia Tools" Style="{StaticResource FilterChipStyle}"/>
|
||||||
|
<Button Name="WPFSearchChipProTools" Content="Pro Tools" Style="{StaticResource FilterChipStyle}"/>
|
||||||
|
<Button Name="WPFSearchChipSelfhostedTools" Content="Selfhosted Tools" Style="{StaticResource FilterChipStyle}"/>
|
||||||
|
<Button Name="WPFSearchChipUtilities" Content="Utilities" Style="{StaticResource FilterChipStyle}"/>
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
|
|
||||||
<Grid Grid.Row="1" Margin="{DynamicResource TabContentMargin}">
|
<Grid Grid.Row="1" Margin="{DynamicResource TabContentMargin}">
|
||||||
@@ -1326,14 +1366,14 @@
|
|||||||
|
|
||||||
<StackPanel Background="{DynamicResource MainBackgroundColor}" Orientation="Vertical" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5">
|
<StackPanel Background="{DynamicResource MainBackgroundColor}" Orientation="Vertical" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5">
|
||||||
<Label Content="Recommended Selections:" FontSize="{DynamicResource FontSize}" VerticalAlignment="Center" Margin="2"/>
|
<Label Content="Recommended Selections:" FontSize="{DynamicResource FontSize}" VerticalAlignment="Center" Margin="2"/>
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,2,0,0">
|
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,2,0,0">
|
||||||
<Button Name="WPFstandard" Content=" Standard " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
<Button Name="WPFstandard" Content=" Standard " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
||||||
<Button Name="WPFminimal" Content=" Minimal " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
<Button Name="WPFminimal" Content=" Minimal " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
||||||
<Button Name="WPFAdvanced" Content=" Advanced " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
<Button Name="WPFAdvanced" Content=" Advanced " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
||||||
<Button Name="WPFClearTweaksSelection" Content=" Clear " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
<Button Name="WPFClearTweaksSelection" Content=" Clear " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
||||||
<Button Name="WPFGetInstalledTweaks" Content=" Get Installed Tweaks " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
<Button Name="WPFGetInstalledTweaks" Content=" Get Installed Tweaks " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
||||||
<Button Name="WPFAppxRemoval" Content=" AppX Removal " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
<Button Name="WPFAppxRemoval" Content=" AppX Removal " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
||||||
</StackPanel>
|
</WrapPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Grid Name="tweakspanel" Grid.Row="1">
|
<Grid Name="tweakspanel" Grid.Row="1">
|
||||||
@@ -1366,99 +1406,148 @@
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Header="Updates" Visibility="Collapsed" Name="WPFTab4">
|
<TabItem Header="Updates" Visibility="Collapsed" Name="WPFTab4">
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="{DynamicResource TabContentMargin}">
|
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="{DynamicResource TabContentMargin}">
|
||||||
<Grid Background="Transparent" MaxWidth="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=ScrollViewer}}">
|
<Grid Background="Transparent" MaxWidth="1250" HorizontalAlignment="Center">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/> <!-- Row for the 3 columns -->
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/> <!-- Row for Windows Version -->
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Three columns container -->
|
<StackPanel Grid.Row="0" Margin="10,10,10,14">
|
||||||
<Grid Grid.Row="0">
|
<TextBlock Text="Windows Update Profiles"
|
||||||
<Grid.ColumnDefinitions>
|
FontSize="24"
|
||||||
<ColumnDefinition Width="*"/>
|
FontWeight="Bold"
|
||||||
<ColumnDefinition Width="*"/>
|
Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<TextBlock Text="Choose how Windows receives updates. Each profile replaces the Windows Update settings managed by WinUtil."
|
||||||
</Grid.ColumnDefinitions>
|
Margin="0,6,0,0"
|
||||||
|
FontSize="13"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Default Settings -->
|
<UniformGrid Grid.Row="1" Columns="3">
|
||||||
<Border Grid.Column="0" Style="{StaticResource BorderStyle}">
|
<Border Style="{StaticResource BorderStyle}"
|
||||||
<StackPanel>
|
BorderBrush="{DynamicResource ProgressBarForegroundColor}"
|
||||||
<Button Name="WPFUpdatesdefault"
|
BorderThickness="2"
|
||||||
FontSize="{DynamicResource ConfigTabButtonFontSize}"
|
Padding="16"
|
||||||
Content="Default Settings"
|
MinHeight="300">
|
||||||
Margin="10,5"
|
<Grid>
|
||||||
Padding="10"/>
|
<Grid.RowDefinitions>
|
||||||
<TextBlock Margin="10"
|
<RowDefinition Height="Auto"/>
|
||||||
TextWrapping="Wrap"
|
<RowDefinition Height="*"/>
|
||||||
Foreground="{DynamicResource MainForegroundColor}">
|
<RowDefinition Height="Auto"/>
|
||||||
<Run FontWeight="Bold">Default Windows Update Configuration</Run>
|
</Grid.RowDefinitions>
|
||||||
<LineBreak/>
|
<StackPanel Grid.Row="0" Margin="0,0,0,14">
|
||||||
- No modifications to Windows defaults
|
<TextBlock Text="Recommended"
|
||||||
<LineBreak/>
|
FontSize="20"
|
||||||
- Removes any custom update settings
|
FontWeight="Bold"
|
||||||
<LineBreak/><LineBreak/>
|
Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
<Run FontStyle="Italic" FontSize="11">Note: This resets your Windows Update settings to default out of the box settings. It removes ANY policy or customization that has been done to Windows Update.</Run>
|
<TextBlock Text="Balanced security and stability"
|
||||||
</TextBlock>
|
Margin="0,4,0,0"
|
||||||
</StackPanel>
|
FontSize="13"
|
||||||
</Border>
|
Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
</StackPanel>
|
||||||
<!-- Security Settings -->
|
<StackPanel Grid.Row="1">
|
||||||
<Border Grid.Column="1" Style="{StaticResource BorderStyle}">
|
<TextBlock Text="- Defers feature updates for 365 days" TextWrapping="Wrap" Margin="0,0,0,7" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
<StackPanel>
|
<TextBlock Text="- Defers quality updates for 4 days" TextWrapping="Wrap" Margin="0,0,0,7" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="- Excludes drivers from quality updates" TextWrapping="Wrap" Margin="0,0,0,7" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="- Prevents automatic restarts while a user is signed in" TextWrapping="Wrap" Margin="0,0,0,12" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="Available on Windows Pro, Enterprise, and Education editions."
|
||||||
|
FontSize="11"
|
||||||
|
FontStyle="Italic"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
</StackPanel>
|
||||||
<Button Name="WPFUpdatessecurity"
|
<Button Name="WPFUpdatessecurity"
|
||||||
|
Grid.Row="2"
|
||||||
|
Content="Apply Recommended"
|
||||||
FontSize="{DynamicResource ConfigTabButtonFontSize}"
|
FontSize="{DynamicResource ConfigTabButtonFontSize}"
|
||||||
Content="Security Settings"
|
Margin="0,16,0,0"
|
||||||
Margin="10,5"
|
|
||||||
Padding="10"/>
|
Padding="10"/>
|
||||||
<TextBlock Margin="10"
|
</Grid>
|
||||||
TextWrapping="Wrap"
|
|
||||||
Foreground="{DynamicResource MainForegroundColor}">
|
|
||||||
<Run FontWeight="Bold">Balanced Security Configuration</Run>
|
|
||||||
<LineBreak/>
|
|
||||||
- Feature updates delayed by 365 days
|
|
||||||
<LineBreak/>
|
|
||||||
- Security updates installed after 4 days
|
|
||||||
<LineBreak/>
|
|
||||||
- Prevents Windows Update from installing drivers
|
|
||||||
<LineBreak/><LineBreak/>
|
|
||||||
<Run FontWeight="SemiBold">Feature Updates:</Run> New features and potential bugs
|
|
||||||
<LineBreak/>
|
|
||||||
<Run FontWeight="SemiBold">Security Updates:</Run> Critical security patches
|
|
||||||
<LineBreak/><LineBreak/>
|
|
||||||
<Run FontStyle="Italic" FontSize="11">Note: This only applies to Pro systems that can use group policy.</Run>
|
|
||||||
</TextBlock>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- Disable Updates -->
|
<Border Style="{StaticResource BorderStyle}" Padding="16" MinHeight="300">
|
||||||
<Border Grid.Column="2" Style="{StaticResource BorderStyle}">
|
<Grid>
|
||||||
<StackPanel>
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel Grid.Row="0" Margin="0,0,0,14">
|
||||||
|
<TextBlock Text="Windows Default"
|
||||||
|
FontSize="20"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="Return control to Windows"
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
FontSize="13"
|
||||||
|
Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="1">
|
||||||
|
<TextBlock Text="- Removes Windows Update policies applied by WinUtil" TextWrapping="Wrap" Margin="0,0,0,7" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="- Restores update service startup settings" TextWrapping="Wrap" Margin="0,0,0,7" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="- Re-enables update scheduled tasks" TextWrapping="Wrap" Margin="0,0,0,12" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="Use this to undo the Recommended or Disable profile."
|
||||||
|
FontSize="11"
|
||||||
|
FontStyle="Italic"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<Button Name="WPFUpdatesdefault"
|
||||||
|
Grid.Row="2"
|
||||||
|
Content="Restore Defaults"
|
||||||
|
FontSize="{DynamicResource ConfigTabButtonFontSize}"
|
||||||
|
Margin="0,16,0,0"
|
||||||
|
Padding="10"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Style="{StaticResource BorderStyle}" Padding="16" MinHeight="300">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel Grid.Row="0" Margin="0,0,0,14">
|
||||||
|
<TextBlock Text="Disable Updates"
|
||||||
|
FontSize="20"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="Red"/>
|
||||||
|
<TextBlock Text="Advanced use only"
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
FontSize="13"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="Red"/>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="1">
|
||||||
|
<TextBlock Text="- Disables automatic update policy" TextWrapping="Wrap" Margin="0,0,0,7" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="- Stops update services and scheduled tasks" TextWrapping="Wrap" Margin="0,0,0,7" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="- Clears downloaded update files" TextWrapping="Wrap" Margin="0,0,0,12" Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
<TextBlock Text="Security updates will not be installed while this profile is active."
|
||||||
|
FontSize="11"
|
||||||
|
FontStyle="Italic"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="Red"/>
|
||||||
|
</StackPanel>
|
||||||
<Button Name="WPFUpdatesdisable"
|
<Button Name="WPFUpdatesdisable"
|
||||||
|
Grid.Row="2"
|
||||||
|
Content="Disable Updates"
|
||||||
FontSize="{DynamicResource ConfigTabButtonFontSize}"
|
FontSize="{DynamicResource ConfigTabButtonFontSize}"
|
||||||
Content="Disable All Updates"
|
|
||||||
Foreground="Red"
|
Foreground="Red"
|
||||||
Margin="10,5"
|
Margin="0,16,0,0"
|
||||||
Padding="10"/>
|
Padding="10"/>
|
||||||
<TextBlock Margin="10"
|
</Grid>
|
||||||
TextWrapping="Wrap"
|
|
||||||
Foreground="{DynamicResource MainForegroundColor}">
|
|
||||||
<Run FontWeight="Bold" Foreground="Red">!! Not Recommended !!</Run>
|
|
||||||
<LineBreak/>
|
|
||||||
- Disables ALL Windows Updates
|
|
||||||
<LineBreak/>
|
|
||||||
- Increases security risks
|
|
||||||
<LineBreak/>
|
|
||||||
- Only use for isolated systems
|
|
||||||
<LineBreak/><LineBreak/>
|
|
||||||
<Run FontStyle="Italic" FontSize="11">Warning: Your system will be vulnerable without security updates.</Run>
|
|
||||||
</TextBlock>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</UniformGrid>
|
||||||
|
|
||||||
<!-- Future Implementation: Add Windows Version to updates panel -->
|
<Border Grid.Row="2" Style="{StaticResource BorderStyle}" Margin="8,14,8,8" Padding="12">
|
||||||
<Grid Name="updatespanel" Grid.Row="1" Background="Transparent">
|
<TextBlock Text="Changes apply system-wide. Restart Windows after switching profiles. Use Restore Defaults to undo WinUtil update policies."
|
||||||
</Grid>
|
TextWrapping="Wrap"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Foreground="{DynamicResource MainForegroundColor}"/>
|
||||||
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@@ -1823,7 +1912,7 @@
|
|||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
|
|
||||||
<!-- Tweaks/Undo progress indicator - visible regardless of active tab -->
|
<!-- Window-level progress indicator - visible regardless of active tab -->
|
||||||
<Border Name="WPFTweaksProgressBar" Grid.Row="3" Background="{DynamicResource MainBackgroundColor}" Visibility="Collapsed" Padding="10,6">
|
<Border Name="WPFTweaksProgressBar" Grid.Row="3" Background="{DynamicResource MainBackgroundColor}" Visibility="Collapsed" Padding="10,6">
|
||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<TextBlock Name="WPFTweaksProgressLabel" Text="" Foreground="{DynamicResource MainForegroundColor}" FontSize="13" Background="Transparent" Margin="0,0,0,4"/>
|
<TextBlock Name="WPFTweaksProgressLabel" Text="" Foreground="{DynamicResource MainForegroundColor}" FontSize="13" Background="Transparent" Margin="0,0,0,4"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user