mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-08-10 01:51:18 +10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70f1c50bdd | ||
|
|
2e5df82979 | ||
|
|
29595f90e2 | ||
|
|
9ed06e793a | ||
|
|
51cb3811dd | ||
|
|
975616b58f | ||
|
|
11783c75a8 | ||
|
|
13a18eeeb2 | ||
|
|
822003d87f | ||
|
|
c8c3c7869f | ||
|
|
157a66b14d | ||
|
|
9791386f53 | ||
|
|
c8e756dc11 | ||
|
|
9e21c8f4a7 | ||
|
|
8cd8679512 | ||
|
|
ac11c73b64 | ||
|
|
9d67514bf9 | ||
|
|
fea9f4e869 | ||
|
|
1aa0dd90ef | ||
|
|
90a19685f5 | ||
|
|
007995c112 | ||
|
|
0dcd361c51 | ||
|
|
aeaef46e30 | ||
|
|
e0dfeb4f4d | ||
|
|
1c7ee06bbe | ||
|
|
ed6de94c46 | ||
|
|
640b02868a | ||
|
|
29b269201d |
@@ -71,6 +71,7 @@ jobs:
|
|||||||
labels: |
|
labels: |
|
||||||
automated
|
automated
|
||||||
documentation
|
documentation
|
||||||
|
skip-changelog
|
||||||
|
|
||||||
- name: Check outputs
|
- name: Check outputs
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
name: Issue slash commands
|
|
||||||
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [created, edited]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
issueCommands:
|
|
||||||
# Skip this job if the comment was created/edited on a PR
|
|
||||||
if: ${{ !github.event.issue.pull_request }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
pull-requests: none
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Process slash command
|
|
||||||
uses: actions/github-script@v9
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const allowedUsers = ["ChrisTitusTech", "og-mrk", "Marterich", "MyDrift-user", "Real-MullaC", "CodingWonders", "GabiNun2", "FluffyPunk"];
|
|
||||||
const commenter = context.payload.comment.user.login;
|
|
||||||
|
|
||||||
// Authorization check first — before any parsing of comment content
|
|
||||||
if (!allowedUsers.includes(commenter)) {
|
|
||||||
console.log(`User ${commenter} is not in the allowlist. Skipping.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read comment body as data, never interpolated into shell
|
|
||||||
const body = context.payload.comment.body;
|
|
||||||
const issueNumber = context.issue.number;
|
|
||||||
const owner = context.repo.owner;
|
|
||||||
const repo = context.repo.repo;
|
|
||||||
|
|
||||||
// /label 'name' or /label name
|
|
||||||
const labelMatch = body.match(/\/label\s+'([^']+)'|\/label\s+(\S+?)(?:\s|$)/);
|
|
||||||
if (labelMatch) {
|
|
||||||
const labelName = (labelMatch[1] || labelMatch[2]).trim();
|
|
||||||
console.log(`Adding label: ${labelName}`);
|
|
||||||
await github.rest.issues.addLabels({
|
|
||||||
owner, repo, issue_number: issueNumber,
|
|
||||||
labels: [labelName],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// /unlabel 'name' or /unlabel name
|
|
||||||
const unlabelMatch = body.match(/\/unlabel\s+'([^']+)'|\/unlabel\s+(\S+?)(?:\s|$)/);
|
|
||||||
if (unlabelMatch) {
|
|
||||||
const labelName = (unlabelMatch[1] || unlabelMatch[2]).trim();
|
|
||||||
console.log(`Removing label: ${labelName}`);
|
|
||||||
await github.rest.issues.removeLabel({
|
|
||||||
owner, repo, issue_number: issueNumber,
|
|
||||||
name: labelName,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// /close (optionally with 'not planned')
|
|
||||||
if (body.includes('/close')) {
|
|
||||||
const stateReason = body.includes('not planned') ? 'not_planned' : 'completed';
|
|
||||||
console.log(`Closing issue (reason: ${stateReason})`);
|
|
||||||
await github.rest.issues.update({
|
|
||||||
owner, repo, issue_number: issueNumber,
|
|
||||||
state: 'closed',
|
|
||||||
state_reason: stateReason,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// /open or /reopen
|
|
||||||
if (body.includes('/open') || body.includes('/reopen')) {
|
|
||||||
console.log('Reopening issue');
|
|
||||||
await github.rest.issues.update({
|
|
||||||
owner, repo, issue_number: issueNumber,
|
|
||||||
state: 'open',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -32,7 +32,9 @@ jobs:
|
|||||||
body: 'Automated update of sponsors section'
|
body: 'Automated update of sponsors section'
|
||||||
branch: sponsors-update
|
branch: sponsors-update
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
labels: automated
|
labels: |
|
||||||
|
automated
|
||||||
|
skip-changelog
|
||||||
|
|
||||||
- name: Check outputs
|
- name: Check outputs
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -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/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><!-- 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 -->
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -530,6 +530,15 @@
|
|||||||
"winget": "TechPowerUp.GPU-Z",
|
"winget": "TechPowerUp.GPU-Z",
|
||||||
"foss": false
|
"foss": false
|
||||||
},
|
},
|
||||||
|
"gsudo": {
|
||||||
|
"category": "Pro Tools",
|
||||||
|
"choco": "gsudo",
|
||||||
|
"content": "gsudo",
|
||||||
|
"description": "gsudo is a sudo equivalent for Windows. It allows you to run commands with elevated administrative privileges directly within the current console window.",
|
||||||
|
"link": "https://github.com/gerardog/gsudo",
|
||||||
|
"winget": "gerardog.gsudo",
|
||||||
|
"foss": true
|
||||||
|
},
|
||||||
"helium": {
|
"helium": {
|
||||||
"category": "Browsers",
|
"category": "Browsers",
|
||||||
"choco": "helium",
|
"choco": "helium",
|
||||||
@@ -719,15 +728,6 @@
|
|||||||
"winget": "XBMCFoundation.Kodi",
|
"winget": "XBMCFoundation.Kodi",
|
||||||
"foss": true
|
"foss": true
|
||||||
},
|
},
|
||||||
"lightshot": {
|
|
||||||
"category": "Multimedia Tools",
|
|
||||||
"choco": "lightshot",
|
|
||||||
"content": "Lightshot",
|
|
||||||
"description": "The fastest way to take a customizable screenshot.",
|
|
||||||
"link": "https://app.prntscr.com/",
|
|
||||||
"winget": "Skillbrains.Lightshot",
|
|
||||||
"foss": false
|
|
||||||
},
|
|
||||||
"lazygit": {
|
"lazygit": {
|
||||||
"category": "Development",
|
"category": "Development",
|
||||||
"choco": "lazygit",
|
"choco": "lazygit",
|
||||||
@@ -1207,7 +1207,7 @@
|
|||||||
"processmonitor": {
|
"processmonitor": {
|
||||||
"category": "Microsoft Tools",
|
"category": "Microsoft Tools",
|
||||||
"choco": "procexp",
|
"choco": "procexp",
|
||||||
"content": "SysInternals Process Monitor",
|
"content": "Process Monitor",
|
||||||
"description": "SysInternals Process Monitor is an advanced monitoring tool that shows real-time file system, registry, and process/thread activity.",
|
"description": "SysInternals Process Monitor is an advanced monitoring tool that shows real-time file system, registry, and process/thread activity.",
|
||||||
"link": "https://docs.microsoft.com/en-us/sysinternals/downloads/procmon",
|
"link": "https://docs.microsoft.com/en-us/sysinternals/downloads/procmon",
|
||||||
"winget": "Microsoft.Sysinternals.ProcessMonitor",
|
"winget": "Microsoft.Sysinternals.ProcessMonitor",
|
||||||
@@ -1396,7 +1396,7 @@
|
|||||||
"tcpview": {
|
"tcpview": {
|
||||||
"category": "Microsoft Tools",
|
"category": "Microsoft Tools",
|
||||||
"choco": "tcpview",
|
"choco": "tcpview",
|
||||||
"content": "SysInternals TCPView",
|
"content": "TCPView",
|
||||||
"description": "SysInternals TCPView is a network monitoring tool that displays a detailed list of all TCP and UDP endpoints on your system.",
|
"description": "SysInternals TCPView is a network monitoring tool that displays a detailed list of all TCP and UDP endpoints on your system.",
|
||||||
"link": "https://docs.microsoft.com/en-us/sysinternals/downloads/tcpview",
|
"link": "https://docs.microsoft.com/en-us/sysinternals/downloads/tcpview",
|
||||||
"winget": "Microsoft.Sysinternals.TCPView",
|
"winget": "Microsoft.Sysinternals.TCPView",
|
||||||
@@ -1513,7 +1513,7 @@
|
|||||||
"ungoogled": {
|
"ungoogled": {
|
||||||
"category": "Browsers",
|
"category": "Browsers",
|
||||||
"choco": "ungoogled-chromium",
|
"choco": "ungoogled-chromium",
|
||||||
"content": "Ungoogled",
|
"content": "Ungoogled Chromium",
|
||||||
"description": "Ungoogled Chromium is a version of Chromium without Google's integration for enhanced privacy and control.",
|
"description": "Ungoogled Chromium is a version of Chromium without Google's integration for enhanced privacy and control.",
|
||||||
"link": "https://github.com/Eloston/ungoogled-chromium",
|
"link": "https://github.com/Eloston/ungoogled-chromium",
|
||||||
"winget": "eloston.ungoogled-chromium",
|
"winget": "eloston.ungoogled-chromium",
|
||||||
|
|||||||
+60
-30
@@ -4,203 +4,232 @@
|
|||||||
"Content": "Feedback Hub",
|
"Content": "Feedback Hub",
|
||||||
"Description": "Allows users to submit bug reports, feature suggestions, and diagnostic data directly to Microsoft.",
|
"Description": "Allows users to submit bug reports, feature suggestions, and diagnostic data directly to Microsoft.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.WindowsFeedbackHub"
|
"PackageId": "Microsoft.WindowsFeedbackHub",
|
||||||
|
"StoreId": "9NBLGGH4R32N"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_GetHelp": {
|
"WPFAppxMicrosoft_GetHelp": {
|
||||||
"Category": "Microsoft Apps",
|
"Category": "Microsoft Apps",
|
||||||
"Content": "Get Help",
|
"Content": "Get Help",
|
||||||
"Description": "Provides access to automated troubleshooting guides, support documentation, and direct Microsoft customer assistance.",
|
"Description": "Provides access to automated troubleshooting guides, support documentation, and direct Microsoft customer assistance.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.GetHelp"
|
"PackageId": "Microsoft.GetHelp",
|
||||||
|
"StoreId": "9PKDZBMV1H3T"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_OutlookForWindows": {
|
"WPFAppxMicrosoft_OutlookForWindows": {
|
||||||
"Category": "Microsoft Apps",
|
"Category": "Microsoft Apps",
|
||||||
"Content": "Outlook for Windows",
|
"Content": "Outlook for Windows",
|
||||||
"Description": "Provides modern email management, calendar scheduling, and contact organization features.",
|
"Description": "Provides modern email management, calendar scheduling, and contact organization features.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.OutlookForWindows"
|
"PackageId": "Microsoft.OutlookForWindows",
|
||||||
|
"StoreId": "9NRX63209R7B"
|
||||||
},
|
},
|
||||||
"WPFAppxMSTeams": {
|
"WPFAppxMSTeams": {
|
||||||
"Category": "Microsoft Apps",
|
"Category": "Microsoft Apps",
|
||||||
"Content": "Microsoft Teams",
|
"Content": "Microsoft Teams",
|
||||||
"Description": "Facilitates instant messaging, video conferencing, file sharing, and workspace collaboration.",
|
"Description": "Facilitates instant messaging, video conferencing, file sharing, and workspace collaboration.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "MSTeams"
|
"PackageId": "MSTeams",
|
||||||
|
"StoreId": "XP8BT8DW290MPQ"
|
||||||
},
|
},
|
||||||
"WPFAppxClipchamp_Clipchamp": {
|
"WPFAppxClipchamp_Clipchamp": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Clipchamp",
|
"Content": "Clipchamp",
|
||||||
"Description": "Provides a user-friendly video editor with built-in templates, effects, and timeline editing tools.",
|
"Description": "Provides a user-friendly video editor with built-in templates, effects, and timeline editing tools.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Clipchamp.Clipchamp"
|
"PackageId": "Clipchamp.Clipchamp",
|
||||||
|
"StoreId": "9P1J8S7CCWWT"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_MicrosoftOfficeHub": {
|
"WPFAppxMicrosoft_MicrosoftOfficeHub": {
|
||||||
"Category": "Microsoft Apps",
|
"Category": "Microsoft Apps",
|
||||||
"Content": "Microsoft 365",
|
"Content": "Microsoft 365",
|
||||||
"Description": "Serves as a centralized launcher and dashboard for accessing cloud-based Microsoft 365 apps and recent documents.",
|
"Description": "Serves as a centralized launcher and dashboard for accessing cloud-based Microsoft 365 apps and recent documents.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.MicrosoftOfficeHub"
|
"PackageId": "Microsoft.MicrosoftOfficeHub",
|
||||||
|
"StoreId": "9WZDNCRD29V9"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_ZuneMusic": {
|
"WPFAppxMicrosoft_ZuneMusic": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Media Player",
|
"Content": "Media Player",
|
||||||
"Description": "Plays local audio and video files with modern playlist management and casting capabilities.",
|
"Description": "Plays local audio and video files with modern playlist management and casting capabilities.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.ZuneMusic"
|
"PackageId": "Microsoft.ZuneMusic",
|
||||||
|
"StoreId": "9WZDNCRFJ3PT"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_BingSearch": {
|
"WPFAppxMicrosoft_BingSearch": {
|
||||||
"Category": "Bing & Web Services",
|
"Category": "Bing & Web Services",
|
||||||
"Content": "Bing Search",
|
"Content": "Bing Search",
|
||||||
"Description": "Integrates Microsoft Bing search capabilities and web services directly into the operating system.",
|
"Description": "Integrates Microsoft Bing search capabilities and web services directly into the operating system.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.BingSearch"
|
"PackageId": "Microsoft.BingSearch",
|
||||||
|
"StoreId": "9NZBF4GT040C"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoftCorporationII_QuickAssist": {
|
"WPFAppxMicrosoftCorporationII_QuickAssist": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Quick Assist",
|
"Content": "Quick Assist",
|
||||||
"Description": "Enables secure remote technical support and screen sharing over an internet connection.",
|
"Description": "Enables secure remote technical support and screen sharing over an internet connection.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "MicrosoftCorporationII.QuickAssist"
|
"PackageId": "MicrosoftCorporationII.QuickAssist",
|
||||||
|
"StoreId": "9P7BP5VNWKX5"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_WindowsDevHome": {
|
"WPFAppxMicrosoft_WindowsDevHome": {
|
||||||
"Category": "Developer Tools",
|
"Category": "Developer Tools",
|
||||||
"Content": "Dev Home",
|
"Content": "Dev Home",
|
||||||
"Description": "Provides a specialized dashboard for software developer environment setups, repository syncing, and hardware widgets.",
|
"Description": "Provides a specialized dashboard for software developer environment setups, repository syncing, and hardware widgets.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.Windows.DevHome"
|
"PackageId": "Microsoft.Windows.DevHome",
|
||||||
|
"StoreId": "9N8MHTPHNGVV"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_WindowsCrossDevice": {
|
"WPFAppxMicrosoft_WindowsCrossDevice": {
|
||||||
"Category": "Microsoft Ecosystem",
|
"Category": "Microsoft Ecosystem",
|
||||||
"Content": "Mobile Devices",
|
"Content": "Mobile Devices",
|
||||||
"Description": "Manages system-level background connectivity with paired mobile devices. Removing this may disable cross-device features such as phone screen mirroring, file transfer, and mobile hotspot handoff integrated into Windows Settings.",
|
"Description": "Manages system-level background connectivity with paired mobile devices. Removing this may disable cross-device features such as phone screen mirroring, file transfer, and mobile hotspot handoff integrated into Windows Settings.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "MicrosoftWindows.CrossDevice"
|
"PackageId": "MicrosoftWindows.CrossDevice",
|
||||||
|
"StoreId": "9NTXGKQ8P7N0"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_Todos": {
|
"WPFAppxMicrosoft_Todos": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "To Do",
|
"Content": "To Do",
|
||||||
"Description": "Creates, tracks, and synchronizes personal tasks, smart lists, and daily reminders.",
|
"Description": "Creates, tracks, and synchronizes personal tasks, smart lists, and daily reminders.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.Todos"
|
"PackageId": "Microsoft.Todos",
|
||||||
|
"StoreId": "9NBLGGH5R558"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_PowerAutomateDesktop": {
|
"WPFAppxMicrosoft_PowerAutomateDesktop": {
|
||||||
"Category": "Developer Tools",
|
"Category": "Developer Tools",
|
||||||
"Content": "Power Automate",
|
"Content": "Power Automate",
|
||||||
"Description": "Automates repetitive workflows and desktop tasks using low-code visual scripting.",
|
"Description": "Automates repetitive workflows and desktop tasks using low-code visual scripting.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.PowerAutomateDesktop"
|
"PackageId": "Microsoft.PowerAutomateDesktop",
|
||||||
|
"StoreId": "9NFTCH6J7FHV"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_YourPhone": {
|
"WPFAppxMicrosoft_YourPhone": {
|
||||||
"Category": "Microsoft Ecosystem",
|
"Category": "Microsoft Ecosystem",
|
||||||
"Content": "Phone Link",
|
"Content": "Phone Link",
|
||||||
"Description": "Synchronizes text messages, phone notifications, photos, and calls from a mobile device to the desktop.",
|
"Description": "Synchronizes text messages, phone notifications, photos, and calls from a mobile device to the desktop.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.YourPhone"
|
"PackageId": "Microsoft.YourPhone",
|
||||||
|
"StoreId": "9NMPJ99VJBWV"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_MicrosoftStickyNotes": {
|
"WPFAppxMicrosoft_MicrosoftStickyNotes": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Sticky Notes",
|
"Content": "Sticky Notes",
|
||||||
"Description": "Creates quick, floating text notes on the desktop that automatically sync across devices.",
|
"Description": "Creates quick, floating text notes on the desktop that automatically sync across devices.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.MicrosoftStickyNotes"
|
"PackageId": "Microsoft.MicrosoftStickyNotes",
|
||||||
|
"StoreId": "9NBLGGH4QGHW"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_WindowsSoundRecorder": {
|
"WPFAppxMicrosoft_WindowsSoundRecorder": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Sound Recorder",
|
"Content": "Sound Recorder",
|
||||||
"Description": "Records and trims live audio inputs with simple microphone adjustment controls.",
|
"Description": "Records and trims live audio inputs with simple microphone adjustment controls.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.WindowsSoundRecorder"
|
"PackageId": "Microsoft.WindowsSoundRecorder",
|
||||||
|
"StoreId": "9WZDNCRFHWKN"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_WindowsAlarms": {
|
"WPFAppxMicrosoft_WindowsAlarms": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Clock",
|
"Content": "Clock",
|
||||||
"Description": "Features world clocks, alarms, countdown timers, stopwatches, and dedicated focus session tracking.",
|
"Description": "Features world clocks, alarms, countdown timers, stopwatches, and dedicated focus session tracking.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.WindowsAlarms"
|
"PackageId": "Microsoft.WindowsAlarms",
|
||||||
|
"StoreId": "9WZDNCRFJ3PR"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_Paint": {
|
"WPFAppxMicrosoft_Paint": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Paint",
|
"Content": "Paint",
|
||||||
"Description": "Provides built-in digital sketching, basic image editing, and pixel-level graphic manipulation tools.",
|
"Description": "Provides built-in digital sketching, basic image editing, and pixel-level graphic manipulation tools.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.Paint"
|
"PackageId": "Microsoft.Paint",
|
||||||
|
"StoreId": "9PCFS5B6T72H"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_WindowsNotepad": {
|
"WPFAppxMicrosoft_WindowsNotepad": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Notepad",
|
"Content": "Notepad",
|
||||||
"Description": "Provides a lightweight text editor with multi-tab support for plain text files and code snippets.",
|
"Description": "Provides a lightweight text editor with multi-tab support for plain text files and code snippets.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.WindowsNotepad"
|
"PackageId": "Microsoft.WindowsNotepad",
|
||||||
|
"StoreId": "9MSMLRH6LZF3"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_ScreenSketch": {
|
"WPFAppxMicrosoft_ScreenSketch": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Snipping Tool",
|
"Content": "Snipping Tool",
|
||||||
"Description": "Captures screenshots or screen recordings with built-in markup, image cropping, and optical character recognition (OCR).",
|
"Description": "Captures screenshots or screen recordings with built-in markup, image cropping, and optical character recognition (OCR).",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.ScreenSketch"
|
"PackageId": "Microsoft.ScreenSketch",
|
||||||
|
"StoreId": "9MZ95KL8MR0L"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_Copilot": {
|
"WPFAppxMicrosoft_Copilot": {
|
||||||
"Category": "Bing & Web Services",
|
"Category": "Bing & Web Services",
|
||||||
"Content": "Copilot",
|
"Content": "Copilot",
|
||||||
"Description": "Launches the Microsoft AI companion for contextual answers, creative writing assistance, and intelligent web search.",
|
"Description": "Launches the Microsoft AI companion for contextual answers, creative writing assistance, and intelligent web search.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.Copilot"
|
"PackageId": "Microsoft.Copilot",
|
||||||
|
"StoreId": "9NHT9RB2F4HD"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_WindowsCalculator": {
|
"WPFAppxMicrosoft_WindowsCalculator": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Calculator",
|
"Content": "Calculator",
|
||||||
"Description": "Performs standard arithmetic, scientific operations, programming calculations, and unit conversions.",
|
"Description": "Performs standard arithmetic, scientific operations, programming calculations, and unit conversions.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.WindowsCalculator"
|
"PackageId": "Microsoft.WindowsCalculator",
|
||||||
|
"StoreId": "9WZDNCRFHVN5"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_WindowsCamera": {
|
"WPFAppxMicrosoft_WindowsCamera": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Camera",
|
"Content": "Camera",
|
||||||
"Description": "Captures photographs and records video files via connected webcams or imaging hardware.",
|
"Description": "Captures photographs and records video files via connected webcams or imaging hardware.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.WindowsCamera"
|
"PackageId": "Microsoft.WindowsCamera",
|
||||||
|
"StoreId": "9WZDNCRFJBBG"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_WindowsPhotos": {
|
"WPFAppxMicrosoft_WindowsPhotos": {
|
||||||
"Category": "Utilities & Productivity",
|
"Category": "Utilities & Productivity",
|
||||||
"Content": "Photos",
|
"Content": "Photos",
|
||||||
"Description": "Organizes, views, and crops local images with basic color adjustment and album creation tools.",
|
"Description": "Organizes, views, and crops local images with basic color adjustment and album creation tools.",
|
||||||
"Panel": "0",
|
"Panel": "0",
|
||||||
"PackageId": "Microsoft.Windows.Photos"
|
"PackageId": "Microsoft.Windows.Photos",
|
||||||
|
"StoreId": "9WZDNCRFJBH4"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_BingNews": {
|
"WPFAppxMicrosoft_BingNews": {
|
||||||
"Category": "Bing & Web Services",
|
"Category": "Bing & Web Services",
|
||||||
"Content": "News",
|
"Content": "News",
|
||||||
"Description": "Aggregates breaking news headlines, personalized article feeds, and world current events.",
|
"Description": "Aggregates breaking news headlines, personalized article feeds, and world current events.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.BingNews"
|
"PackageId": "Microsoft.BingNews",
|
||||||
|
"StoreId": "9WZDNCRFHVFW"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_BingWeather": {
|
"WPFAppxMicrosoft_BingWeather": {
|
||||||
"Category": "Bing & Web Services",
|
"Category": "Bing & Web Services",
|
||||||
"Content": "Weather",
|
"Content": "Weather",
|
||||||
"Description": "Displays local real-time weather tracking, radar maps, and historical meteorological forecasts.",
|
"Description": "Displays local real-time weather tracking, radar maps, and historical meteorological forecasts.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.BingWeather"
|
"PackageId": "Microsoft.BingWeather",
|
||||||
|
"StoreId": "9WZDNCRFJ3Q2"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_GamingApp": {
|
"WPFAppxMicrosoft_GamingApp": {
|
||||||
"Category": "Xbox & Gaming",
|
"Category": "Xbox & Gaming",
|
||||||
"Content": "Xbox App",
|
"Content": "Xbox App",
|
||||||
"Description": "Serves as the primary gaming library manager, social community interface, and PC Game Pass dashboard.",
|
"Description": "Serves as the primary gaming library manager, social community interface, and PC Game Pass dashboard.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.GamingApp"
|
"PackageId": "Microsoft.GamingApp",
|
||||||
|
"StoreId": "9MV0B5HZVK9Z"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_XboxGamingOverlay": {
|
"WPFAppxMicrosoft_XboxGamingOverlay": {
|
||||||
"Category": "Xbox & Gaming",
|
"Category": "Xbox & Gaming",
|
||||||
"Content": "Xbox Game Bar",
|
"Content": "Xbox Game Bar",
|
||||||
"Description": "Provides customizable in-game status widgets, audio balancing sliders, system monitoring tools, and gameplay recording.",
|
"Description": "Provides customizable in-game status widgets, audio balancing sliders, system monitoring tools, and gameplay recording.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.XboxGamingOverlay"
|
"PackageId": "Microsoft.XboxGamingOverlay",
|
||||||
|
"StoreId": "9NZKPSTSNW4P"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_XboxIdentityProvider": {
|
"WPFAppxMicrosoft_XboxIdentityProvider": {
|
||||||
"Category": "Xbox & Gaming",
|
"Category": "Xbox & Gaming",
|
||||||
"Content": "Xbox Identity Provider",
|
"Content": "Xbox Identity Provider",
|
||||||
"Description": "Manages Xbox network user authentication and background account validation for connected titles. Warning: removing this may break Microsoft account sign-in for non-Xbox games and apps that rely on this authentication pipeline.",
|
"Description": "Manages Xbox network user authentication and background account validation for connected titles. Warning: removing this may break Microsoft account sign-in for non-Xbox games and apps that rely on this authentication pipeline.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.XboxIdentityProvider"
|
"PackageId": "Microsoft.XboxIdentityProvider",
|
||||||
|
"StoreId": "9WZDNCRD1HKW"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_XboxSpeechToTextOverlay": {
|
"WPFAppxMicrosoft_XboxSpeechToTextOverlay": {
|
||||||
"Category": "Xbox & Gaming",
|
"Category": "Xbox & Gaming",
|
||||||
@@ -221,7 +250,8 @@
|
|||||||
"Content": "Start Experiences App",
|
"Content": "Start Experiences App",
|
||||||
"Description": "Powers the Windows Widgets board, delivering a personalized feed of news, weather, sports, and finance content.",
|
"Description": "Powers the Windows Widgets board, delivering a personalized feed of news, weather, sports, and finance content.",
|
||||||
"Panel": "1",
|
"Panel": "1",
|
||||||
"PackageId": "Microsoft.StartExperiencesApp"
|
"PackageId": "Microsoft.StartExperiencesApp",
|
||||||
|
"StoreId": "9PC1H9VN18CM"
|
||||||
},
|
},
|
||||||
"WPFAppxMicrosoft_MicrosoftSolitaireCollection": {
|
"WPFAppxMicrosoft_MicrosoftSolitaireCollection": {
|
||||||
"Category": "Xbox & Gaming",
|
"Category": "Xbox & Gaming",
|
||||||
|
|||||||
+52
-8
@@ -179,6 +179,17 @@
|
|||||||
"function": "Invoke-WPFFixesWinget",
|
"function": "Invoke-WPFFixesWinget",
|
||||||
"link": "https://winutil.christitus.com/dev/features/fixes/winget"
|
"link": "https://winutil.christitus.com/dev/features/fixes/winget"
|
||||||
},
|
},
|
||||||
|
"WPFPanelComputer": {
|
||||||
|
"Content": "Computer Management",
|
||||||
|
"category": "Legacy Windows Panels",
|
||||||
|
"panel": "2",
|
||||||
|
"Type": "Button",
|
||||||
|
"ButtonWidth": "300",
|
||||||
|
"InvokeScript": [
|
||||||
|
"compmgmt.msc"
|
||||||
|
],
|
||||||
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/computer"
|
||||||
|
},
|
||||||
"WPFPanelControl": {
|
"WPFPanelControl": {
|
||||||
"Content": "Control Panel",
|
"Content": "Control Panel",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
@@ -190,16 +201,16 @@
|
|||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/control"
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/control"
|
||||||
},
|
},
|
||||||
"WPFPanelComputer": {
|
"WPFPanelMouse": {
|
||||||
"Content": "Computer Management",
|
"Content": "Mouse Properties",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Button",
|
"Type": "Button",
|
||||||
"ButtonWidth": "300",
|
"ButtonWidth": "300",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
"compmgmt.msc"
|
"main.cpl"
|
||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/computer"
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/mouse"
|
||||||
},
|
},
|
||||||
"WPFPanelNetwork": {
|
"WPFPanelNetwork": {
|
||||||
"Content": "Network Connections",
|
"Content": "Network Connections",
|
||||||
@@ -234,6 +245,17 @@
|
|||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/printer"
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/printer"
|
||||||
},
|
},
|
||||||
|
"WPFPanelPrograms": {
|
||||||
|
"Content": "Programs and Features",
|
||||||
|
"category": "Legacy Windows Panels",
|
||||||
|
"panel": "2",
|
||||||
|
"Type": "Button",
|
||||||
|
"ButtonWidth": "300",
|
||||||
|
"InvokeScript": [
|
||||||
|
"appwiz.cpl"
|
||||||
|
],
|
||||||
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/programs"
|
||||||
|
},
|
||||||
"WPFPanelRegion": {
|
"WPFPanelRegion": {
|
||||||
"Content": "Region",
|
"Content": "Region",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
@@ -245,16 +267,16 @@
|
|||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/region"
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/region"
|
||||||
},
|
},
|
||||||
"WPFPanelRestore": {
|
"WPFPanelSecurity": {
|
||||||
"Content": "Windows Restore",
|
"Content": "Security and Maintenance",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Button",
|
"Type": "Button",
|
||||||
"ButtonWidth": "300",
|
"ButtonWidth": "300",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
"rstrui.exe"
|
"wscui.cpl"
|
||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/restore"
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/security"
|
||||||
},
|
},
|
||||||
"WPFPanelSound": {
|
"WPFPanelSound": {
|
||||||
"Content": "Sound Settings",
|
"Content": "Sound Settings",
|
||||||
@@ -289,6 +311,28 @@
|
|||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/timedate"
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/timedate"
|
||||||
},
|
},
|
||||||
|
"WPFPanelFirewall": {
|
||||||
|
"Content": "Windows Defender Firewall",
|
||||||
|
"category": "Legacy Windows Panels",
|
||||||
|
"panel": "2",
|
||||||
|
"Type": "Button",
|
||||||
|
"ButtonWidth": "300",
|
||||||
|
"InvokeScript": [
|
||||||
|
"firewall.cpl"
|
||||||
|
],
|
||||||
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/firewall"
|
||||||
|
},
|
||||||
|
"WPFPanelRestore": {
|
||||||
|
"Content": "Windows Restore",
|
||||||
|
"category": "Legacy Windows Panels",
|
||||||
|
"panel": "2",
|
||||||
|
"Type": "Button",
|
||||||
|
"ButtonWidth": "300",
|
||||||
|
"InvokeScript": [
|
||||||
|
"rstrui.exe"
|
||||||
|
],
|
||||||
|
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/restore"
|
||||||
|
},
|
||||||
"WPFWinUtilInstallPSProfile": {
|
"WPFWinUtilInstallPSProfile": {
|
||||||
"Content": "CTT PowerShell Profile - Install",
|
"Content": "CTT PowerShell Profile - Install",
|
||||||
"category": "Powershell Profile Powershell 7+ Only",
|
"category": "Powershell Profile Powershell 7+ Only",
|
||||||
|
|||||||
+7
-10
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"shared": {
|
"shared": {
|
||||||
"AppEntryWidth": "200",
|
"AppEntryWidth": "220",
|
||||||
"AppEntryFontSize": "11",
|
"AppEntryFontSize": "13.2",
|
||||||
"AppEntryMargin": "1,0,1,0",
|
"AppEntryIconSize": "28",
|
||||||
"AppEntryBorderThickness": "0",
|
"AppEntryMargin": "3",
|
||||||
|
"AppEntryBorderThickness": "1",
|
||||||
"CustomDialogFontSize": "12",
|
"CustomDialogFontSize": "12",
|
||||||
"CustomDialogFontSizeHeader": "14",
|
"CustomDialogFontSizeHeader": "14",
|
||||||
"CustomDialogLogoSize": "25",
|
"CustomDialogLogoSize": "25",
|
||||||
@@ -24,7 +25,7 @@
|
|||||||
"IconFontSize": "14",
|
"IconFontSize": "14",
|
||||||
"IconButtonSize": "35",
|
"IconButtonSize": "35",
|
||||||
"SettingsIconFontSize": "18",
|
"SettingsIconFontSize": "18",
|
||||||
"CloseIconFontSize": "18",
|
"CloseIconFontSize": "12",
|
||||||
"GroupBorderBackgroundColor": "#232629",
|
"GroupBorderBackgroundColor": "#232629",
|
||||||
"ButtonFontSize": "12",
|
"ButtonFontSize": "12",
|
||||||
"ButtonFontFamily": "Arial",
|
"ButtonFontFamily": "Arial",
|
||||||
@@ -45,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",
|
||||||
@@ -59,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",
|
||||||
@@ -87,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",
|
||||||
@@ -99,9 +97,8 @@
|
|||||||
"ScrollBarBackgroundColor": "#2E3135",
|
"ScrollBarBackgroundColor": "#2E3135",
|
||||||
"ScrollBarHoverColor": "#3B4252",
|
"ScrollBarHoverColor": "#3B4252",
|
||||||
"ScrollBarDraggingColor": "#5E81AC",
|
"ScrollBarDraggingColor": "#5E81AC",
|
||||||
"ProgressBarForegroundColor": "#222222",
|
"ProgressBarForegroundColor": "#6EFF72",
|
||||||
"ProgressBarBackgroundColor": "Transparent",
|
"ProgressBarBackgroundColor": "Transparent",
|
||||||
"ProgressBarTextColor": "#232629",
|
|
||||||
"ButtonInstallBackgroundColor": "#222222",
|
"ButtonInstallBackgroundColor": "#222222",
|
||||||
"ButtonTweaksBackgroundColor": "#333333",
|
"ButtonTweaksBackgroundColor": "#333333",
|
||||||
"ButtonConfigBackgroundColor": "#444444",
|
"ButtonConfigBackgroundColor": "#444444",
|
||||||
|
|||||||
+17
-1
@@ -429,7 +429,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksConsumerFeatures": {
|
"WPFTweaksConsumerFeatures": {
|
||||||
"Content": "ConsumerFeatures - Disable",
|
"Content": "ConsumerFeatures - Disable",
|
||||||
"Description": "Windows will not automatically install any games, third-party apps, or application links from the Windows Store for the signed-in user. Some default Apps will be inaccessible (e.g. Phone Link).",
|
"Description": "Stops promoted app installs and reduces app suggestions from Microsoft Store content.",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -944,6 +944,22 @@
|
|||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/dev/tweaks/essential-tweaks/wpbt"
|
"link": "https://winutil.christitus.com/dev/tweaks/essential-tweaks/wpbt"
|
||||||
},
|
},
|
||||||
|
"WPFTweaksPreventDeviceMetadataFromNetwork": {
|
||||||
|
"Content": "Prevent Device Companion Apps",
|
||||||
|
"Description": "Prevents additional software from being installed when plugging in devices (e.g. Ads when plugging in a monitor). Poses potential security risk.",
|
||||||
|
"category": "Essential Tweaks",
|
||||||
|
"panel": "1",
|
||||||
|
"registry": [
|
||||||
|
{
|
||||||
|
"Path": "HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\Device Metadata",
|
||||||
|
"Name": "PreventDeviceMetadataFromNetwork",
|
||||||
|
"Value": "1",
|
||||||
|
"Type": "DWord",
|
||||||
|
"OriginalValue": "<RemoveEntry>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"link": "https://winutil.christitus.com/dev/tweaks/essential-tweaks/preventdevicemetadatafromnetwork"
|
||||||
|
},
|
||||||
"WPFTweaksRazerBlock": {
|
"WPFTweaksRazerBlock": {
|
||||||
"Content": "Razer Software Auto-Install - Disable",
|
"Content": "Razer Software Auto-Install - Disable",
|
||||||
"Description": "Blocks ALL Razer Software installations. The hardware works fine without any software.",
|
"Description": "Blocks ALL Razer Software installations. The hardware works fine without any software.",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ toc: false
|
|||||||
---
|
---
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> This section contains technical documentation for developers. For end-user documentation, see the [User Guide](../userguide/).
|
> This section contains code-only references. For end-user documentation, see the [User Guide](../userguide/).
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Computer Management"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=193}
|
```json {filename="config/feature.json",linenos=inline,linenostart=182}
|
||||||
"WPFPanelComputer": {
|
"WPFPanelComputer": {
|
||||||
"Content": "Computer Management",
|
"Content": "Computer Management",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Control Panel"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=182}
|
```json {filename="config/feature.json",linenos=inline,linenostart=193}
|
||||||
"WPFPanelControl": {
|
"WPFPanelControl": {
|
||||||
"Content": "Control Panel",
|
"Content": "Control Panel",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: "Windows Defender Firewall"
|
||||||
|
description: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
```json {filename="config/feature.json",linenos=inline,linenostart=314}
|
||||||
|
"WPFPanelFirewall": {
|
||||||
|
"Content": "Windows Defender Firewall",
|
||||||
|
"category": "Legacy Windows Panels",
|
||||||
|
"panel": "2",
|
||||||
|
"Type": "Button",
|
||||||
|
"ButtonWidth": "300",
|
||||||
|
"InvokeScript": [
|
||||||
|
"firewall.cpl"
|
||||||
|
],
|
||||||
|
```
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: "Mouse Properties"
|
||||||
|
description: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
```json {filename="config/feature.json",linenos=inline,linenostart=204}
|
||||||
|
"WPFPanelMouse": {
|
||||||
|
"Content": "Mouse Properties",
|
||||||
|
"category": "Legacy Windows Panels",
|
||||||
|
"panel": "2",
|
||||||
|
"Type": "Button",
|
||||||
|
"ButtonWidth": "300",
|
||||||
|
"InvokeScript": [
|
||||||
|
"main.cpl"
|
||||||
|
],
|
||||||
|
```
|
||||||
@@ -3,7 +3,7 @@ title: "Network Connections"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=204}
|
```json {filename="config/feature.json",linenos=inline,linenostart=215}
|
||||||
"WPFPanelNetwork": {
|
"WPFPanelNetwork": {
|
||||||
"Content": "Network Connections",
|
"Content": "Network Connections",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Power Panel"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=215}
|
```json {filename="config/feature.json",linenos=inline,linenostart=226}
|
||||||
"WPFPanelPower": {
|
"WPFPanelPower": {
|
||||||
"Content": "Power Panel",
|
"Content": "Power Panel",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Printer Panel"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=226}
|
```json {filename="config/feature.json",linenos=inline,linenostart=237}
|
||||||
"WPFPanelPrinter": {
|
"WPFPanelPrinter": {
|
||||||
"Content": "Printer Panel",
|
"Content": "Printer Panel",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: "Programs and Features"
|
||||||
|
description: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
```json {filename="config/feature.json",linenos=inline,linenostart=248}
|
||||||
|
"WPFPanelPrograms": {
|
||||||
|
"Content": "Programs and Features",
|
||||||
|
"category": "Legacy Windows Panels",
|
||||||
|
"panel": "2",
|
||||||
|
"Type": "Button",
|
||||||
|
"ButtonWidth": "300",
|
||||||
|
"InvokeScript": [
|
||||||
|
"appwiz.cpl"
|
||||||
|
],
|
||||||
|
```
|
||||||
@@ -3,7 +3,7 @@ title: "Region"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=237}
|
```json {filename="config/feature.json",linenos=inline,linenostart=259}
|
||||||
"WPFPanelRegion": {
|
"WPFPanelRegion": {
|
||||||
"Content": "Region",
|
"Content": "Region",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Windows Restore"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=248}
|
```json {filename="config/feature.json",linenos=inline,linenostart=325}
|
||||||
"WPFPanelRestore": {
|
"WPFPanelRestore": {
|
||||||
"Content": "Windows Restore",
|
"Content": "Windows Restore",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: "Security and Maintenance"
|
||||||
|
description: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
```json {filename="config/feature.json",linenos=inline,linenostart=270}
|
||||||
|
"WPFPanelSecurity": {
|
||||||
|
"Content": "Security and Maintenance",
|
||||||
|
"category": "Legacy Windows Panels",
|
||||||
|
"panel": "2",
|
||||||
|
"Type": "Button",
|
||||||
|
"ButtonWidth": "300",
|
||||||
|
"InvokeScript": [
|
||||||
|
"wscui.cpl"
|
||||||
|
],
|
||||||
|
```
|
||||||
@@ -3,7 +3,7 @@ title: "Sound Settings"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=259}
|
```json {filename="config/feature.json",linenos=inline,linenostart=281}
|
||||||
"WPFPanelSound": {
|
"WPFPanelSound": {
|
||||||
"Content": "Sound Settings",
|
"Content": "Sound Settings",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "System Properties"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=270}
|
```json {filename="config/feature.json",linenos=inline,linenostart=292}
|
||||||
"WPFPanelSystem": {
|
"WPFPanelSystem": {
|
||||||
"Content": "System Properties",
|
"Content": "System Properties",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Time and Date"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/feature.json",linenos=inline,linenostart=281}
|
```json {filename="config/feature.json",linenos=inline,linenostart=303}
|
||||||
"WPFPanelTimedate": {
|
"WPFPanelTimedate": {
|
||||||
"Content": "Time and Date",
|
"Content": "Time and Date",
|
||||||
"category": "Legacy Windows Panels",
|
"category": "Legacy Windows Panels",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "System Tray Battery Percentage"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1252}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1268}
|
||||||
"WPFToggleBatteryPercentage": {
|
"WPFToggleBatteryPercentage": {
|
||||||
"Content": "System Tray Battery Percentage",
|
"Content": "System Tray Battery Percentage",
|
||||||
"Description": "Shows numeric battery percentage next to the battery icon in the system tray.",
|
"Description": "Shows numeric battery percentage next to the battery icon in the system tray.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Start Menu Bing Search"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1605}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1621}
|
||||||
"WPFToggleBingSearch": {
|
"WPFToggleBingSearch": {
|
||||||
"Content": "Start Menu Bing Search",
|
"Content": "Start Menu Bing Search",
|
||||||
"Description": "Toggles Bing web search results in Windows Search.",
|
"Description": "Toggles Bing web search results in Windows Search.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Dark Theme for Windows"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1270}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1286}
|
||||||
"WPFToggleDarkMode": {
|
"WPFToggleDarkMode": {
|
||||||
"Content": "Dark Theme for Windows",
|
"Content": "Dark Theme for Windows",
|
||||||
"Description": "Dark Mode for the system and applications.",
|
"Description": "Dark Mode for the system and applications.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "BSoD Verbose Mode"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1226}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1242}
|
||||||
"WPFToggleDetailedBSoD": {
|
"WPFToggleDetailedBSoD": {
|
||||||
"Content": "BSoD Verbose Mode",
|
"Content": "BSoD Verbose Mode",
|
||||||
"Description": "Gives more information when you blue screen.",
|
"Description": "Gives more information when you blue screen.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Lock Screen - Disable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1641}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1657}
|
||||||
"WPFTweaksDisableLockscreen": {
|
"WPFTweaksDisableLockscreen": {
|
||||||
"Content": "Lock Screen - Disable",
|
"Content": "Lock Screen - Disable",
|
||||||
"Description": "Skips the lock screen entirely and goes directly to the sign-in screen on boot and wake.",
|
"Description": "Skips the lock screen entirely and goes directly to the sign-in screen on boot and wake.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Game Mode"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1784}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1800}
|
||||||
"WPFToggleGameMode": {
|
"WPFToggleGameMode": {
|
||||||
"Content": "Game Mode",
|
"Content": "Game Mode",
|
||||||
"Description": "Toggles Windows prioritizes gaming performance by allocating system resources to games.",
|
"Description": "Toggles Windows prioritizes gaming performance by allocating system resources to games.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "File Explorer Hidden Files"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1340}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1356}
|
||||||
"WPFToggleHiddenFiles": {
|
"WPFToggleHiddenFiles": {
|
||||||
"Content": "File Explorer Hidden Files",
|
"Content": "File Explorer Hidden Files",
|
||||||
"Description": "Reveals hidden files in Explorer.",
|
"Description": "Reveals hidden files in Explorer.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Settings Home Page"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1587}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1603}
|
||||||
"WPFToggleHideSettingsHome": {
|
"WPFToggleHideSettingsHome": {
|
||||||
"Content": "Settings Home Page",
|
"Content": "Settings Home Page",
|
||||||
"Description": "Toggles the Home Page in the Windows Settings app.",
|
"Description": "Toggles the Home Page in the Windows Settings app.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Logon Screen Acrylic Blur"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1623}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1639}
|
||||||
"WPFToggleLoginBlur": {
|
"WPFToggleLoginBlur": {
|
||||||
"Content": "Logon Screen Acrylic Blur",
|
"Content": "Logon Screen Acrylic Blur",
|
||||||
"Description": "Toggles the acrylic blur effect on login screen background.",
|
"Description": "Toggles the acrylic blur effect on login screen background.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Enable Long Paths"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1810}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1826}
|
||||||
"WPFToggleLongPaths": {
|
"WPFToggleLongPaths": {
|
||||||
"Content": "Enable Long Paths",
|
"Content": "Enable Long Paths",
|
||||||
"Description": "Toggles support for file paths longer than 260 characters in Explorer.",
|
"Description": "Toggles support for file paths longer than 260 characters in Explorer.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Mouse Acceleration"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1473}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1489}
|
||||||
"WPFToggleMouseAcceleration": {
|
"WPFToggleMouseAcceleration": {
|
||||||
"Content": "Mouse Acceleration",
|
"Content": "Mouse Acceleration",
|
||||||
"Description": "Makes it so Cursor movement is affected by the speed of your physical mouse movements.",
|
"Description": "Makes it so Cursor movement is affected by the speed of your physical mouse movements.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Multiplane Overlay"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1447}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1463}
|
||||||
"WPFToggleMultiplaneOverlay": {
|
"WPFToggleMultiplaneOverlay": {
|
||||||
"Content": "Multiplane Overlay",
|
"Content": "Multiplane Overlay",
|
||||||
"Description": "Multiplane Overlay compose multiple image layers, which can sometimes cause issues with graphics cards.",
|
"Description": "Multiplane Overlay compose multiple image layers, which can sometimes cause issues with graphics cards.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Microsoft Outlook New Version"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1386}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1402}
|
||||||
"WPFToggleNewOutlook": {
|
"WPFToggleNewOutlook": {
|
||||||
"Content": "Microsoft Outlook New Version",
|
"Content": "Microsoft Outlook New Version",
|
||||||
"Description": "This will ensures the classic Outlook application is used.",
|
"Description": "This will ensures the classic Outlook application is used.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Num Lock on Startup"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1507}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1523}
|
||||||
"WPFToggleNumLock": {
|
"WPFToggleNumLock": {
|
||||||
"Content": "Num Lock on Startup",
|
"Content": "Num Lock on Startup",
|
||||||
"Description": "Toggle the Num Lock key state when your computer starts.",
|
"Description": "Toggle the Num Lock key state when your computer starts.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "S3 Sleep"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1569}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1585}
|
||||||
"WPFToggleS3Sleep": {
|
"WPFToggleS3Sleep": {
|
||||||
"Content": "S3 Sleep",
|
"Content": "S3 Sleep",
|
||||||
"Description": "Toggles between Modern Standby and S3 Sleep, which cuts off power to the CPU while continuing to refresh the memory.",
|
"Description": "Toggles between Modern Standby and S3 Sleep, which cuts off power to the CPU while continuing to refresh the memory.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Scrollbars Always Visible"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1428}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1444}
|
||||||
"WPFToggleScrollbars": {
|
"WPFToggleScrollbars": {
|
||||||
"Content": "Scrollbars Always Visible",
|
"Content": "Scrollbars Always Visible",
|
||||||
"Description": "If enabled, scrollbars will always be visible. If disabled, Windows will automatically hide scrollbars when not in use.",
|
"Description": "If enabled, scrollbars will always be visible. If disabled, Windows will automatically hide scrollbars when not in use.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "File Explorer File Extensions"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1312}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1328}
|
||||||
"WPFToggleShowExt": {
|
"WPFToggleShowExt": {
|
||||||
"Content": "File Explorer File Extensions",
|
"Content": "File Explorer File Extensions",
|
||||||
"Description": "Shows .file extensions in Explorer (.exe, .png, etc.)",
|
"Description": "Shows .file extensions in Explorer (.exe, .png, etc.)",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "S0 Sleep Network Connectivity"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1551}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1567}
|
||||||
"WPFToggleStandbyFix": {
|
"WPFToggleStandbyFix": {
|
||||||
"Content": "S0 Sleep Network Connectivity",
|
"Content": "S0 Sleep Network Connectivity",
|
||||||
"Description": "Toggles network connectivity during S0 Sleep which is low power idle in modern laptops.",
|
"Description": "Toggles network connectivity during S0 Sleep which is low power idle in modern laptops.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Start Menu Recommendations"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1658}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1674}
|
||||||
"WPFToggleStartMenuRecommendations": {
|
"WPFToggleStartMenuRecommendations": {
|
||||||
"Content": "Start Menu Recommendations",
|
"Content": "Start Menu Recommendations",
|
||||||
"Description": "Toggles the recommendations section in the Start Menu. WARNING: This will also disable Windows Spotlight on your Lock Screen as a side effect.",
|
"Description": "Toggles the recommendations section in the Start Menu. WARNING: This will also disable Windows Spotlight on your Lock Screen as a side effect.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Sticky Keys"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1702}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1718}
|
||||||
"WPFToggleStickyKeys": {
|
"WPFToggleStickyKeys": {
|
||||||
"Content": "Sticky Keys",
|
"Content": "Sticky Keys",
|
||||||
"Description": "Toggles the Sticky Keys, which activate when clicking shift rapidly.",
|
"Description": "Toggles the Sticky Keys, which activate when clicking shift rapidly.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Taskbar Task View Icon"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1766}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1782}
|
||||||
"WPFToggleTaskView": {
|
"WPFToggleTaskView": {
|
||||||
"Content": "Taskbar Task View Icon",
|
"Content": "Taskbar Task View Icon",
|
||||||
"Description": "Toggles the Task View Button in the Taskbar.",
|
"Description": "Toggles the Task View Button in the Taskbar.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Taskbar Centered Icons"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1720}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1736}
|
||||||
"WPFToggleTaskbarAlignment": {
|
"WPFToggleTaskbarAlignment": {
|
||||||
"Content": "Taskbar Centered Icons",
|
"Content": "Taskbar Centered Icons",
|
||||||
"Description": "Toggles the Taskbar alignment either to the left or center.",
|
"Description": "Toggles the Taskbar alignment either to the left or center.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Taskbar Search Icon"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1748}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1764}
|
||||||
"WPFToggleTaskbarSearch": {
|
"WPFToggleTaskbarSearch": {
|
||||||
"Content": "Taskbar Search Icon",
|
"Content": "Taskbar Search Icon",
|
||||||
"Description": "Toggles the Search Button on the Taskbar.",
|
"Description": "Toggles the Search Button on the Taskbar.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Logon Verbose Mode"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1368}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1384}
|
||||||
"WPFToggleVerboseLogon": {
|
"WPFToggleVerboseLogon": {
|
||||||
"Content": "Logon Verbose Mode",
|
"Content": "Logon Verbose Mode",
|
||||||
"Description": "Show detailed messages during startup/shutdown.",
|
"Description": "Show detailed messages during startup/shutdown.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Window Snapping"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1533}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1549}
|
||||||
"WPFToggleWindowSnapping": {
|
"WPFToggleWindowSnapping": {
|
||||||
"Content": "Window Snapping",
|
"Content": "Window Snapping",
|
||||||
"Description": "Toggles the window snapping feature when dragging windows.",
|
"Description": "Toggles the window snapping feature when dragging windows.",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=430}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=430}
|
||||||
"WPFTweaksConsumerFeatures": {
|
"WPFTweaksConsumerFeatures": {
|
||||||
"Content": "ConsumerFeatures - Disable",
|
"Content": "ConsumerFeatures - Disable",
|
||||||
"Description": "Windows will not automatically install any games, third-party apps, or application links from the Windows Store for the signed-in user. Some default Apps will be inaccessible (e.g. Phone Link).",
|
"Description": "Stops promoted app installs and reduces app suggestions from Microsoft Store content.",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Temporary Files - Remove"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1066}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1082}
|
||||||
"WPFTweaksDeleteTempFiles": {
|
"WPFTweaksDeleteTempFiles": {
|
||||||
"Content": "Temporary Files - Remove",
|
"Content": "Temporary Files - Remove",
|
||||||
"Description": "Erases TEMP Folders.",
|
"Description": "Erases TEMP Folders.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "File Explorer Automatic Folder Discovery - Disable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1171}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1187}
|
||||||
"WPFTweaksDisableExplorerAutoDiscovery": {
|
"WPFTweaksDisableExplorerAutoDiscovery": {
|
||||||
"Content": "File Explorer Automatic Folder Discovery - Disable",
|
"Content": "File Explorer Automatic Folder Discovery - Disable",
|
||||||
"Description": "Windows Explorer automatically tries to guess the type of the folder based on its contents, slowing down the browsing experience. WARNING! Will disable File Explorer grouping.",
|
"Description": "Windows Explorer automatically tries to guess the type of the folder based on its contents, slowing down the browsing experience. WARNING! Will disable File Explorer grouping.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Disk Cleanup - Run"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1053}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1069}
|
||||||
"WPFTweaksDiskCleanup": {
|
"WPFTweaksDiskCleanup": {
|
||||||
"Content": "Disk Cleanup - Run",
|
"Content": "Disk Cleanup - Run",
|
||||||
"Description": "Runs Disk Cleanup on Drive C: and removes old Windows Updates.",
|
"Description": "Runs Disk Cleanup on Drive C: and removes old Windows Updates.",
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
title: "Prevent Device Companion Apps"
|
||||||
|
description: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=947}
|
||||||
|
"WPFTweaksPreventDeviceMetadataFromNetwork": {
|
||||||
|
"Content": "Prevent Device Companion Apps",
|
||||||
|
"Description": "Prevents additional software from being installed when plugging in devices (e.g. Ads when plugging in a monitor). Poses potential security risk.",
|
||||||
|
"category": "Essential Tweaks",
|
||||||
|
"panel": "1",
|
||||||
|
"registry": [
|
||||||
|
{
|
||||||
|
"Path": "HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\Device Metadata",
|
||||||
|
"Name": "PreventDeviceMetadataFromNetwork",
|
||||||
|
"Value": "1",
|
||||||
|
"Type": "DWord",
|
||||||
|
"OriginalValue": "<RemoveEntry>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
## Registry Changes
|
||||||
|
|
||||||
|
Applications and System Components store and retrieve configuration data to modify Windows settings, so we can use the registry to change many settings in one place.
|
||||||
|
|
||||||
|
You can find information about the registry on [Wikipedia](https://en.wikipedia.org/wiki/Windows_Registry) and [Microsoft's Website](https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry).
|
||||||
@@ -3,7 +3,7 @@ title: "Adobe URL Block List - Enable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1011}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1027}
|
||||||
"WPFTweaksBlockAdobeNet": {
|
"WPFTweaksBlockAdobeNet": {
|
||||||
"Content": "Adobe URL Block List - Enable",
|
"Content": "Adobe URL Block List - Enable",
|
||||||
"Description": "Reduces user interruptions by selectively blocking connections to Adobe's activation and telemetry servers. Credit: Ruddernation-Designs",
|
"Description": "Reduces user interruptions by selectively blocking connections to Adobe's activation and telemetry servers. Credit: Ruddernation-Designs",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Background Apps - Disable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1139}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1155}
|
||||||
"WPFTweaksDisableBGapps": {
|
"WPFTweaksDisableBGapps": {
|
||||||
"Content": "Background Apps - Disable",
|
"Content": "Background Apps - Disable",
|
||||||
"Description": "Disables all Microsoft Store apps from running in the background, which has to be done individually since Windows 11.",
|
"Description": "Disables all Microsoft Store apps from running in the background, which has to be done individually since Windows 11.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Fullscreen Optimizations - Disable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1155}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1171}
|
||||||
"WPFTweaksDisableFSO": {
|
"WPFTweaksDisableFSO": {
|
||||||
"Content": "Fullscreen Optimizations - Disable",
|
"Content": "Fullscreen Optimizations - Disable",
|
||||||
"Description": "Disables FSO in all applications. NOTE: This will disable Color Management in Exclusive Fullscreen.",
|
"Description": "Disables FSO in all applications. NOTE: This will disable Color Management in Exclusive Fullscreen.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "IPv6 - Disable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1117}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1133}
|
||||||
"WPFTweaksDisableIPv6": {
|
"WPFTweaksDisableIPv6": {
|
||||||
"Content": "IPv6 - Disable",
|
"Content": "IPv6 - Disable",
|
||||||
"Description": "Disables IPv6.",
|
"Description": "Disables IPv6.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "System Tray Notifications & Calendar - Disable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=988}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1004}
|
||||||
"WPFTweaksDisableNotifications": {
|
"WPFTweaksDisableNotifications": {
|
||||||
"Content": "System Tray Notifications & Calendar - Disable",
|
"Content": "System Tray Notifications & Calendar - Disable",
|
||||||
"Description": "Disables all Notifications INCLUDING Calendar.",
|
"Description": "Disables all Notifications INCLUDING Calendar.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "IPv6 - Set IPv4 as Preferred"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1079}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1095}
|
||||||
"WPFTweaksIPv46": {
|
"WPFTweaksIPv46": {
|
||||||
"Content": "IPv6 - Set IPv4 as Preferred",
|
"Content": "IPv6 - Set IPv4 as Preferred",
|
||||||
"Description": "Setting the IPv4 preference can have latency and security benefits on private networks where IPv6 is not configured.",
|
"Description": "Setting the IPv4 preference can have latency and security benefits on private networks where IPv6 is not configured.",
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
if ($sync.ProcessRunning) {
|
||||||
|
Show-WinUtilMessage -Message "Another process is currently running." -Title "WinUtil" -Button "OK" -Icon "Warning"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$downloadPath = Join-Path $sync.winutildir "ooshutup10.exe"
|
||||||
|
$sync.ProcessRunning = $true
|
||||||
|
|
||||||
|
Invoke-WPFRunspace -ParameterList @(,("downloadPath", $downloadPath)) -ScriptBlock {
|
||||||
|
param($downloadPath)
|
||||||
|
|
||||||
|
$hasUI = $null -ne $sync.Form -and $null -ne $sync.Form.Dispatcher
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$ProgressPreference = 'SilentlyContinue'
|
Write-WinUtilLog -Component "OOSU" -Message "Downloading O&O ShutUp10++."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Downloading O&O ShutUp10++ (0%)" -Percent 0
|
||||||
|
}
|
||||||
|
|
||||||
Invoke-WebRequest -Uri https://dl5.oo-software.com/files/ooshutup10/OOSU10.exe -OutFile "$winutildir\ooshutup10.exe"
|
Save-WinUtilFile -Uri "https://dl5.oo-software.com/files/ooshutup10/OOSU10.exe" -DestinationPath $downloadPath -ProgressCallback {
|
||||||
Start-Process -FilePath "$winutildir\ooshutup10.exe"
|
param($percent)
|
||||||
|
|
||||||
$ProgressPreference = 'Continue'
|
if ($hasUI) {
|
||||||
} catch {
|
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."
|
Write-Error "Couldn't download O&O ShutUp10. Please make sure you have an active Internet connection."
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
$sync.ProcessRunning = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Razer Software Auto-Install - Disable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=947}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=963}
|
||||||
"WPFTweaksRazerBlock": {
|
"WPFTweaksRazerBlock": {
|
||||||
"Content": "Razer Software Auto-Install - Disable",
|
"Content": "Razer Software Auto-Install - Disable",
|
||||||
"Description": "Blocks ALL Razer Software installations. The hardware works fine without any software.",
|
"Description": "Blocks ALL Razer Software installations. The hardware works fine without any software.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Right-Click Menu Previous Layout - Enable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1037}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1053}
|
||||||
"WPFTweaksRightClickMenu": {
|
"WPFTweaksRightClickMenu": {
|
||||||
"Content": "Right-Click Menu Previous Layout - Enable",
|
"Content": "Right-Click Menu Previous Layout - Enable",
|
||||||
"Description": "Restores the classic context menu when right-clicking in File Explorer, replacing the simplified Windows 11 version.",
|
"Description": "Restores the classic context menu when right-clicking in File Explorer, replacing the simplified Windows 11 version.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Teredo - Disable"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1095}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1111}
|
||||||
"WPFTweaksTeredo": {
|
"WPFTweaksTeredo": {
|
||||||
"Content": "Teredo - Disable",
|
"Content": "Teredo - Disable",
|
||||||
"Description": "Teredo network tunneling is an IPv6 feature that can cause additional latency, but may cause problems with some games.",
|
"Description": "Teredo network tunneling is an IPv6 feature that can cause additional latency, but may cause problems with some games.",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "DNS - Set to:"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1835}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1851}
|
||||||
"WPFchangedns": {
|
"WPFchangedns": {
|
||||||
"Content": "DNS - Set to:",
|
"Content": "DNS - Set to:",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,14 @@ Use the quick-selection buttons at the top of the Tweaks tab to speed up setup:
|
|||||||
* **Select Tweaks to Remove**: Choose the tweaks you want to disable or remove.
|
* **Select Tweaks to Remove**: Choose the tweaks you want to disable or remove.
|
||||||
* **Undo Tweaks**: Click **Undo Selected Tweaks** at the bottom of the screen to apply the changes.
|
* **Undo Tweaks**: Click **Undo Selected Tweaks** at the bottom of the screen to apply the changes.
|
||||||
|
|
||||||
|
### AppX Packages
|
||||||
|
|
||||||
|
Open **AppX Removal** from the Tweaks tab to manage the listed Windows apps. Select one or more packages, then choose **Install Selected** or **Remove Selected**.
|
||||||
|
|
||||||
|
When installing a selected package, WinUtil first registers an existing local `AppxManifest.xml`. If no usable local manifest remains, WinUtil installs the package from the Microsoft Store through WinGet when a Store product ID is available.
|
||||||
|
|
||||||
|
During AppX installation or removal, the window-level progress bar shows the current package, completed package count, and overall progress. The Windows taskbar also reflects progress and the final success or failure state.
|
||||||
|
|
||||||
### Essential Tweaks
|
### Essential Tweaks
|
||||||
Essential Tweaks are the safest starting point for most systems. They focus on lower-risk changes that improve usability, reduce noise, and avoid the more invasive changes found in advanced options.
|
Essential Tweaks are the safest starting point for most systems. They focus on lower-risk changes that improve usability, reduce noise, and avoid the more invasive changes found in advanced options.
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ function Find-AppsByNameOrDescription {
|
|||||||
.PARAMETER SearchString
|
.PARAMETER SearchString
|
||||||
The string to be searched for. Wildcards are treated as literal characters.
|
The string to be searched for. Wildcards are treated as literal characters.
|
||||||
|
|
||||||
|
.PARAMETER Category
|
||||||
|
When provided, only applications in this exact category are shown.
|
||||||
|
|
||||||
.NOTES
|
.NOTES
|
||||||
- Uses module-scope $sync (no parameter needed; inherits from caller's scope)
|
- Uses module-scope $sync (no parameter needed; inherits from caller's scope)
|
||||||
- Performs literal matching (no wildcard expansion)
|
- Performs literal matching (no wildcard expansion)
|
||||||
@@ -18,7 +21,10 @@ function Find-AppsByNameOrDescription {
|
|||||||
#>
|
#>
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $false)]
|
[Parameter(Mandatory = $false)]
|
||||||
[string]$SearchString = ""
|
[string]$SearchString = "",
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $false)]
|
||||||
|
[string]$Category = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validate that $sync exists and has required structure
|
# Validate that $sync exists and has required structure
|
||||||
@@ -39,7 +45,7 @@ function Find-AppsByNameOrDescription {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
# Reset the visibility if the search string is empty or the search is cleared
|
# Reset the visibility if the search string is empty or the search is cleared
|
||||||
if ([string]::IsNullOrWhiteSpace($SearchString)) {
|
if ([string]::IsNullOrWhiteSpace($SearchString) -and [string]::IsNullOrWhiteSpace($Category)) {
|
||||||
$sync.ItemsControl.Items | ForEach-Object {
|
$sync.ItemsControl.Items | ForEach-Object {
|
||||||
# Each item is a StackPanel container
|
# Each item is a StackPanel container
|
||||||
$_.Visibility = [Windows.Visibility]::Visible
|
$_.Visibility = [Windows.Visibility]::Visible
|
||||||
@@ -94,10 +100,11 @@ function Find-AppsByNameOrDescription {
|
|||||||
|
|
||||||
# Check if app matches search criteria
|
# Check if app matches search criteria
|
||||||
if ($null -ne $appEntry) {
|
if ($null -ne $appEntry) {
|
||||||
$contentMatch = $appEntry.Content -like "*$escapedSearchString*"
|
$categoryMatch = -not [string]::IsNullOrWhiteSpace($Category) -and $appEntry.Category -eq $Category
|
||||||
$descriptionMatch = $appEntry.Description -like "*$escapedSearchString*"
|
$contentMatch = [string]::IsNullOrWhiteSpace($Category) -and $appEntry.Content -like "*$escapedSearchString*"
|
||||||
|
$descriptionMatch = [string]::IsNullOrWhiteSpace($Category) -and $appEntry.Description -like "*$escapedSearchString*"
|
||||||
|
|
||||||
if ($contentMatch -or $descriptionMatch) {
|
if ($categoryMatch -or $contentMatch -or $descriptionMatch) {
|
||||||
# Show the App and mark that this category has a match
|
# Show the App and mark that this category has a match
|
||||||
$appControl.Visibility = [Windows.Visibility]::Visible
|
$appControl.Visibility = [Windows.Visibility]::Visible
|
||||||
$categoryHasMatch = $true
|
$categoryHasMatch = $true
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
function Get-WinUtilInstalledAPPX {
|
||||||
|
<#
|
||||||
|
|
||||||
|
.SYNOPSIS
|
||||||
|
Gets the names of AppX packages installed for all users
|
||||||
|
|
||||||
|
#>
|
||||||
|
|
||||||
|
# AppX module auto-loading can leave PowerShell 7 dependent on a temporary Windows PowerShell
|
||||||
|
# compatibility proxy. Run the query in Windows PowerShell 5.1 so it remains available after
|
||||||
|
# those temporary proxy files are removed.
|
||||||
|
$ps5Command = {
|
||||||
|
Get-AppxPackage -AllUsers -ErrorAction Stop | Select-Object -ExpandProperty Name
|
||||||
|
}
|
||||||
|
|
||||||
|
$packageOutput = powershell.exe -NoProfile -NonInteractive -Command $ps5Command 2>&1
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
$failureDetails = ($packageOutput | Out-String).Trim()
|
||||||
|
Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message "Failed to get installed AppX packages: $failureDetails"
|
||||||
|
return @()
|
||||||
|
}
|
||||||
|
|
||||||
|
return @($packageOutput)
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,30 @@ function Initialize-InstallAppEntry {
|
|||||||
$borderElement.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor")
|
$borderElement.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$contentPanel = New-Object Windows.Controls.StackPanel
|
||||||
|
$contentPanel.Orientation = "Horizontal"
|
||||||
|
$contentPanel.VerticalAlignment = [Windows.VerticalAlignment]::Center
|
||||||
|
|
||||||
|
$icon = New-Object Windows.Controls.Grid
|
||||||
|
$icon.SetResourceReference([Windows.FrameworkElement]::WidthProperty, "AppEntryIconSize")
|
||||||
|
$icon.SetResourceReference([Windows.FrameworkElement]::HeightProperty, "AppEntryIconSize")
|
||||||
|
$icon.Margin = New-Object Windows.Thickness(0, 0, 8, 0)
|
||||||
|
$fallback = New-Object Windows.Controls.TextBlock
|
||||||
|
$fallback.Text = $app.content.TrimStart(".").Substring(0, 1).ToUpper()
|
||||||
|
$fallback.FontWeight = "Bold"; $fallback.HorizontalAlignment = "Center"; $fallback.VerticalAlignment = "Center"
|
||||||
|
if ($app.link) { $fallback.Visibility = "Collapsed" }
|
||||||
|
$fallback.SetResourceReference([Windows.Controls.TextBlock]::FontSizeProperty, "AppEntryFontSize")
|
||||||
|
$fallback.SetResourceReference([Windows.Controls.TextBlock]::ForegroundProperty, "ToggleButtonOnColor")
|
||||||
|
[void]$icon.Children.Add($fallback)
|
||||||
|
if ($app.link) {
|
||||||
|
$logo = New-Object Windows.Controls.Image
|
||||||
|
$logo.Stretch = [Windows.Media.Stretch]::Uniform
|
||||||
|
$logo.Source = "https://www.google.com/s2/favicons?sz=64&domain_url=$([uri]::EscapeDataString($app.link))"
|
||||||
|
$logo.Add_ImageFailed({ $this.Visibility = "Collapsed"; $this.Parent.Children[0].Visibility = "Visible" })
|
||||||
|
[void]$icon.Children.Add($logo)
|
||||||
|
}
|
||||||
|
[void]$contentPanel.Children.Add($icon)
|
||||||
|
|
||||||
# Create the TextBlock for the application name
|
# Create the TextBlock for the application name
|
||||||
$appName = New-Object Windows.Controls.TextBlock
|
$appName = New-Object Windows.Controls.TextBlock
|
||||||
$appName.Style = $sync.Form.Resources.AppEntryNameStyle
|
$appName.Style = $sync.Form.Resources.AppEntryNameStyle
|
||||||
@@ -73,7 +97,8 @@ function Initialize-InstallAppEntry {
|
|||||||
|
|
||||||
[void]$appName.Inlines.Add($fossRun)
|
[void]$appName.Inlines.Add($fossRun)
|
||||||
}
|
}
|
||||||
$checkBox.Content = $appName
|
[void]$contentPanel.Children.Add($appName)
|
||||||
|
$checkBox.Content = $contentPanel
|
||||||
|
|
||||||
# Add accessibility properties to make the elements screen reader friendly
|
# Add accessibility properties to make the elements screen reader friendly
|
||||||
$checkBox.SetValue([Windows.Automation.AutomationProperties]::NameProperty, $app.content)
|
$checkBox.SetValue([Windows.Automation.AutomationProperties]::NameProperty, $app.content)
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
function Install-WinUtilAPPX {
|
||||||
|
<#
|
||||||
|
|
||||||
|
.SYNOPSIS
|
||||||
|
Registers a local AppX package or installs it from the Microsoft Store
|
||||||
|
|
||||||
|
.PARAMETER Name
|
||||||
|
The AppX package name to install
|
||||||
|
|
||||||
|
.PARAMETER StoreId
|
||||||
|
The optional Microsoft Store product ID used when no local manifest is available
|
||||||
|
|
||||||
|
#>
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Name,
|
||||||
|
|
||||||
|
[string]$StoreId
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-WinUtilLog -Component "AppX" -Message "Installing AppX package: $Name"
|
||||||
|
|
||||||
|
# AppX and DISM cmdlets are more reliable in Windows PowerShell 5.1. Query both installed and
|
||||||
|
# provisioned package metadata because either can expose a local manifest that can be registered.
|
||||||
|
$ps5Command = {
|
||||||
|
$packageName = $args[0]
|
||||||
|
$manifestPaths = [System.Collections.Generic.List[string]]::new()
|
||||||
|
|
||||||
|
Get-AppxPackage -AllUsers -Name $packageName -ErrorAction SilentlyContinue |
|
||||||
|
Sort-Object -Property Version -Descending |
|
||||||
|
ForEach-Object {
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($_.InstallLocation)) {
|
||||||
|
$manifestPaths.Add((Join-Path $_.InstallLocation "AppxManifest.xml"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object DisplayName -EQ $packageName |
|
||||||
|
ForEach-Object {
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($_.InstallLocation)) {
|
||||||
|
$manifestPaths.Add((Join-Path $_.InstallLocation "AppxManifest.xml"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$manifestPath = $manifestPaths |
|
||||||
|
Select-Object -Unique |
|
||||||
|
Where-Object { Test-Path -LiteralPath $_ } |
|
||||||
|
Select-Object -First 1
|
||||||
|
|
||||||
|
if ($null -ne $manifestPath) {
|
||||||
|
Add-AppxPackage -Register $manifestPath -DisableDevelopmentMode -ErrorAction Stop
|
||||||
|
Write-Output $manifestPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$manifestOutput = powershell.exe -NoProfile -NonInteractive -Command $ps5Command -args $Name 2>&1
|
||||||
|
if ($LASTEXITCODE -eq 0 -and $null -ne $manifestOutput) {
|
||||||
|
$manifestPath = ($manifestOutput | Select-Object -Last 1).ToString().Trim()
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($manifestPath)) {
|
||||||
|
Write-WinUtilLog -Component "AppX" -Message "Registered local AppX manifest for $Name`: $manifestPath"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
$failureDetails = ($manifestOutput | Out-String).Trim()
|
||||||
|
Write-WinUtilLog -Level "WARN" -Component "AppX" -Message "Local AppX registration failed for $Name`: $failureDetails"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($StoreId)) {
|
||||||
|
$errorMessage = "Unable to install $Name because no local manifest or Microsoft Store ID is available."
|
||||||
|
Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message $errorMessage
|
||||||
|
throw $errorMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-WinUtilLog -Component "AppX" -Message "No usable local manifest found for $Name. Installing Microsoft Store product $StoreId."
|
||||||
|
Install-WinUtilWinget
|
||||||
|
Install-WinUtilProgramWinget -Action Install -Programs @("msstore:$StoreId")
|
||||||
|
}
|
||||||
@@ -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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ function Invoke-WinUtilTweaks {
|
|||||||
$sync.configs.tweaks.$CheckBox.appx | ForEach-Object {
|
$sync.configs.tweaks.$CheckBox.appx | ForEach-Object {
|
||||||
Remove-WinUtilAPPX -Name $psitem
|
Remove-WinUtilAPPX -Name $psitem
|
||||||
}
|
}
|
||||||
|
Remove-WinUtilProvisionedAPPX -PackageList $sync.configs.tweaks.$CheckBox.appx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Write-WinUtilLog -Component "Tweaks" -Message "$action tweak completed: $CheckBox"
|
Write-WinUtilLog -Component "Tweaks" -Message "$action tweak completed: $CheckBox"
|
||||||
|
|||||||
@@ -17,7 +17,20 @@ function Remove-WinUtilAPPX {
|
|||||||
|
|
||||||
Write-Host "Removing $Name"
|
Write-Host "Removing $Name"
|
||||||
Write-WinUtilLog -Component "AppX" -Message "Removing AppX package pattern: $Name"
|
Write-WinUtilLog -Component "AppX" -Message "Removing AppX package pattern: $Name"
|
||||||
Get-AppxPackage $Name -AllUsers | Remove-AppxPackage -AllUsers
|
|
||||||
Get-AppxProvisionedPackage -Online | Where-Object DisplayName -like $Name | Remove-AppxProvisionedPackage -Online
|
# We explicitly loop through packages instead of using the pipeline because PowerShell 7 pipeline binding
|
||||||
|
# for Remove-AppxPackage fails silently, and Get-AppxPackage -AllUsers returns duplicate objects for each user profile.
|
||||||
|
$pkgs = Get-AppxPackage "*$Name*" -AllUsers | Sort-Object -Property PackageFullName -Unique
|
||||||
|
if ($null -ne $pkgs) {
|
||||||
|
foreach ($pkg in $pkgs) {
|
||||||
|
try {
|
||||||
|
Remove-AppxPackage -Package $pkg.PackageFullName -AllUsers -ErrorAction Stop
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message "Failed to remove AppX package $($pkg.PackageFullName): $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Write-WinUtilLog -Component "AppX" -Message "AppX removal completed for package pattern: $Name"
|
Write-WinUtilLog -Component "AppX" -Message "AppX removal completed for package pattern: $Name"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
function Remove-WinUtilProvisionedAPPX {
|
||||||
|
<#
|
||||||
|
|
||||||
|
.SYNOPSIS
|
||||||
|
Removes all AppX provisioned packages that match the given names
|
||||||
|
|
||||||
|
.PARAMETER PackageList
|
||||||
|
An array of names of the APPX packages to remove
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Remove-WinUtilProvisionedAPPX -PackageList @("Microsoft.Microsoft3DViewer", "Microsoft.WindowsCalculator")
|
||||||
|
|
||||||
|
#>
|
||||||
|
param (
|
||||||
|
[string[]]$PackageList
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($null -eq $PackageList -or $PackageList.Count -eq 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`nRemoving provisioned packages..."
|
||||||
|
Write-WinUtilLog -Component "AppX" -Message "Removing AppX provisioned packages: $($PackageList -join ', ')"
|
||||||
|
|
||||||
|
# DISM cmdlets like Get-AppxProvisionedPackage often fail with "Class not registered" or hang in PowerShell 7.
|
||||||
|
# We shell out to Windows PowerShell 5.1 (powershell.exe) to reliably remove the provisioned packages.
|
||||||
|
$ps5Command = {
|
||||||
|
$pkgs = $args
|
||||||
|
$provisionedPackages = Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue
|
||||||
|
$failures = [System.Collections.Generic.List[string]]::new()
|
||||||
|
|
||||||
|
foreach ($Package in $pkgs) {
|
||||||
|
$provs = $provisionedPackages |
|
||||||
|
Where-Object DisplayName -Like "*$Package*"
|
||||||
|
|
||||||
|
if ($null -ne $provs) {
|
||||||
|
foreach ($prov in $provs) {
|
||||||
|
try {
|
||||||
|
Remove-AppxProvisionedPackage -Online -PackageName $prov.PackageName -ErrorAction Stop | Out-Null
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$failures.Add("Failed to remove provisioned AppX package $($prov.PackageName): $($_.Exception.Message)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($failures.Count -gt 0) {
|
||||||
|
throw ($failures -join [Environment]::NewLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$removalOutput = powershell.exe -NoProfile -NonInteractive -Command $ps5Command -args $PackageList 2>&1
|
||||||
|
if ($LASTEXITCODE -ne 0 -or $null -ne $removalOutput) {
|
||||||
|
$failureDetails = ($removalOutput | Out-String).Trim()
|
||||||
|
$errorMessage = "AppX provisioned package removal failed: $failureDetails"
|
||||||
|
Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message $errorMessage
|
||||||
|
throw $errorMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-WinUtilLog -Component "AppX" -Message "AppX provisioned package removal completed."
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
function Set-WinUtilAppCategoryFilter {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Applies an exact application category filter from an Install tab search chip.
|
||||||
|
|
||||||
|
.PARAMETER Category
|
||||||
|
The application category to show. An empty value clears the filter.
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $false)]
|
||||||
|
[string]$Category = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
$sync.SearchBar.Tag = $Category
|
||||||
|
$sync.SearchBar.Text = $Category
|
||||||
|
Find-AppsByNameOrDescription -SearchString $Category -Category $Category
|
||||||
|
}
|
||||||
@@ -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}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
function Set-WinUtilTweaksProgressIndicator {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Shows, updates, or hides the window-level progress indicator used by long-running
|
||||||
|
workflows such as app management, Tweaks, AppX management, and Win11 Creator.
|
||||||
|
It lives outside the TabControl, so it stays visible no matter which tab is active.
|
||||||
|
.PARAMETER Visible
|
||||||
|
Whether the indicator should be shown or hidden.
|
||||||
|
.PARAMETER Label
|
||||||
|
The text to display above the progress bar.
|
||||||
|
.PARAMETER Percent
|
||||||
|
The percentage of the progress bar that should be filled (0-100).
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[bool]$Visible,
|
||||||
|
[string]$Label,
|
||||||
|
[ValidateRange(0,100)]
|
||||||
|
[int]$Percent
|
||||||
|
)
|
||||||
|
|
||||||
|
$indicatorVisible = if ($Visible) { [Windows.Visibility]::Visible } else { [Windows.Visibility]::Collapsed }
|
||||||
|
$indicatorLabel = $Label
|
||||||
|
$hasLabel = $PSBoundParameters.ContainsKey('Label')
|
||||||
|
$hasPercent = $PSBoundParameters.ContainsKey('Percent')
|
||||||
|
|
||||||
|
Invoke-WPFUIThread -ScriptBlock {
|
||||||
|
$sync.WPFTweaksProgressBar.Visibility = $indicatorVisible
|
||||||
|
if ($hasLabel) {
|
||||||
|
$sync.WPFTweaksProgressLabel.Text = $indicatorLabel
|
||||||
|
}
|
||||||
|
if ($hasPercent) {
|
||||||
|
$sync.WPFTweaksProgressValue.Value = $Percent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ function Invoke-WinUtilInstallAppRenderBatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($sync.currentTab -eq "Install" -and $sync.SearchBar -and -not [string]::IsNullOrWhiteSpace($sync.SearchBar.Text)) {
|
if ($sync.currentTab -eq "Install" -and $sync.SearchBar -and -not [string]::IsNullOrWhiteSpace($sync.SearchBar.Text)) {
|
||||||
Find-AppsByNameOrDescription -SearchString $sync.SearchBar.Text
|
Find-AppsByNameOrDescription -SearchString $sync.SearchBar.Text -Category $sync.SearchBar.Tag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
function Invoke-WPFAppxInstall {
|
||||||
|
if ($sync.ProcessRunning) {
|
||||||
|
Show-WinUtilMessage -Message "An AppX process is currently running." -Title "WinUtil" -Button "OK" -Icon "Warning"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($null -eq $sync.selectedAppx -or $sync.selectedAppx.Count -eq 0) {
|
||||||
|
Show-WinUtilMessage -Message "No AppX Package selected" -Title "Error" -Button "OK" -Icon "Error"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$selected = @($sync.selectedAppx)
|
||||||
|
$apps = $sync.configs.appxHashtable
|
||||||
|
|
||||||
|
$sync.ProcessRunning = $true
|
||||||
|
Invoke-WPFRunspace -ParameterList @(("selected", $selected), ("apps", $apps)) -ScriptBlock {
|
||||||
|
param($selected, $apps)
|
||||||
|
|
||||||
|
$totalPackages = @($selected).Count
|
||||||
|
$hasUI = $null -ne $sync.Form -and $null -ne $sync.Form.Dispatcher
|
||||||
|
|
||||||
|
try {
|
||||||
|
Write-WinUtilLog -Component "AppX" -Message "Starting AppX install for $totalPackages selected package(s)."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Preparing AppX install (0/$totalPackages)" -Percent 0
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" }
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($index = 0; $index -lt $totalPackages; $index++) {
|
||||||
|
$key = $selected[$index]
|
||||||
|
$app = $apps[$key]
|
||||||
|
$position = $index + 1
|
||||||
|
$startPercent = [int](($index / $totalPackages) * 100)
|
||||||
|
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Installing $($app.Content) ($position/$totalPackages)" -Percent $startPercent
|
||||||
|
}
|
||||||
|
Write-Host "Installing $($app.Content)"
|
||||||
|
Install-WinUtilAPPX -Name $app.PackageId -StoreId $app.StoreId
|
||||||
|
|
||||||
|
$completedPercent = [int](($position / $totalPackages) * 100)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Installed $($app.Content) ($position/$totalPackages)" -Percent $completedPercent
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($completedPercent / 100) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "================================="
|
||||||
|
Write-Host "-- AppX Install Finished ---"
|
||||||
|
Write-Host "================================="
|
||||||
|
Write-WinUtilLog -Component "AppX" -Message "AppX install finished."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "AppX install finished" -Percent 100
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message "AppX install failed: $($_.Exception.Message)"
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "AppX install failed" -Percent 100
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$sync.ProcessRunning = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,23 +1,45 @@
|
|||||||
function Invoke-WPFAppxRemoval {
|
function Invoke-WPFAppxRemoval {
|
||||||
|
if ($sync.ProcessRunning) {
|
||||||
|
Show-WinUtilMessage -Message "An AppX process is currently running." -Title "WinUtil" -Button "OK" -Icon "Warning"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if ($null -eq $sync.selectedAppx -or $sync.selectedAppx.Count -eq 0) {
|
if ($null -eq $sync.selectedAppx -or $sync.selectedAppx.Count -eq 0) {
|
||||||
Show-WinUtilMessage -Message "No AppX Package selected" -Title "Error" -Button "OK" -Icon "Error"
|
Show-WinUtilMessage -Message "No AppX Package selected" -Title "Error" -Button "OK" -Icon "Error"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
$selected = $sync.selectedAppx
|
$selected = @($sync.selectedAppx)
|
||||||
$apps = $sync.configs.appxHashtable
|
$apps = $sync.configs.appxHashtable
|
||||||
|
|
||||||
|
$sync.ProcessRunning = $true
|
||||||
Invoke-WPFRunspace -ParameterList @(("selected", $selected), ("apps", $apps)) -ScriptBlock {
|
Invoke-WPFRunspace -ParameterList @(("selected", $selected), ("apps", $apps)) -ScriptBlock {
|
||||||
param($selected, $apps)
|
param($selected, $apps)
|
||||||
|
|
||||||
$sync.ProcessRunning = $true
|
$totalPackages = @($selected).Count
|
||||||
Write-WinUtilLog -Component "AppX" -Message "Starting AppX removal for $(@($selected).Count) selected package(s)."
|
$hasUI = $null -ne $sync.Form -and $null -ne $sync.Form.Dispatcher
|
||||||
|
$packageList = [System.Collections.Generic.List[string]]::new()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Write-WinUtilLog -Component "AppX" -Message "Starting AppX removal for $totalPackages selected package(s)."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Preparing AppX removal (0/$totalPackages)" -Percent 0
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" }
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($index = 0; $index -lt $totalPackages; $index++) {
|
||||||
|
$key = $selected[$index]
|
||||||
|
$app = $apps[$key]
|
||||||
|
$position = $index + 1
|
||||||
|
$startPercent = [int](($index / $totalPackages) * 90)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Removing $($app.Content) ($position/$totalPackages)" -Percent $startPercent
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($key in $selected) {
|
|
||||||
if ($key -eq "WPFAppxMicrosoft_XboxGamingOverlay") {
|
if ($key -eq "WPFAppxMicrosoft_XboxGamingOverlay") {
|
||||||
# Making sure Game Bar isn't running
|
# Making sure Game Bar isn't running
|
||||||
Write-WinUtilLog -Component "AppX" -Message "Stopping GameBarFTServer before removing Xbox Gaming Overlay."
|
Write-WinUtilLog -Component "AppX" -Message "Stopping GameBarFTServer before removing Xbox Gaming Overlay."
|
||||||
Stop-Process -Name GameBarFTServer
|
Stop-Process -Name GameBarFTServer -Force -Confirm:$false -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
# This stops annoying ms-gamebar popup when launching games.
|
# This stops annoying ms-gamebar popup when launching games.
|
||||||
Write-WinUtilLog -Component "AppX" -Message "Disabling Game DVR capture before removing Xbox Gaming Overlay."
|
Write-WinUtilLog -Component "AppX" -Message "Disabling Game DVR capture before removing Xbox Gaming Overlay."
|
||||||
@@ -25,27 +47,54 @@ function Invoke-WPFAppxRemoval {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($key -eq "WPFAppxMicrosoft_WindowsNotepad") {
|
if ($key -eq "WPFAppxMicrosoft_WindowsNotepad") {
|
||||||
# i hope your having fun reading this
|
|
||||||
Write-WinUtilLog -Component "AppX" -Message "Stopping dllhost before removing Notepad."
|
Write-WinUtilLog -Component "AppX" -Message "Stopping dllhost before removing Notepad."
|
||||||
Stop-Process -Name dllhost
|
Stop-Process -Name dllhost -Force -Confirm:$false -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "Removing $($apps[$key].Content)"
|
Write-Host "Removing $($app.Content)"
|
||||||
Write-WinUtilLog -Component "AppX" -Message "Removing $($apps[$key].Content) ($($apps[$key].PackageId))."
|
Write-WinUtilLog -Component "AppX" -Message "Removing $($app.Content) ($($app.PackageId))."
|
||||||
Get-AppxPackage -Name $apps[$key].PackageId -AllUsers | Remove-AppxPackage -AllUsers
|
Remove-WinUtilAPPX -Name $app.PackageId
|
||||||
|
$packageList.Add($app.PackageId)
|
||||||
|
|
||||||
if ($key -eq "WPFAppxMSTeams") {
|
if ($key -eq "WPFAppxMSTeams") {
|
||||||
# Uninstalls Microsoft Teams Meeting Add-in for Microsoft Office
|
# Uninstalls Microsoft Teams Meeting Add-in for Microsoft Office
|
||||||
Write-WinUtilLog -Component "AppX" -Message "Uninstalling Microsoft Teams meeting add-in package."
|
Write-WinUtilLog -Component "AppX" -Message "Uninstalling Microsoft Teams meeting add-in package."
|
||||||
Get-Package -Name "Microsoft Teams*" -ErrorAction SilentlyContinue | Uninstall-Package -Force
|
Get-Package -Name "Microsoft Teams*" -ErrorAction SilentlyContinue | Uninstall-Package -Force
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$completedPercent = [int](($position / $totalPackages) * 90)
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Removed $($app.Content) ($position/$totalPackages)" -Percent $completedPercent
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($completedPercent / 100) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($packageList.Count -gt 0) {
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Removing provisioned AppX packages" -Percent 90
|
||||||
|
}
|
||||||
|
Remove-WinUtilProvisionedAPPX -PackageList $packageList.ToArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "================================="
|
Write-Host "================================="
|
||||||
Write-Host "-- AppX Removal Finished ---"
|
Write-Host "-- AppX Removal Finished ---"
|
||||||
Write-Host "================================="
|
Write-Host "================================="
|
||||||
Write-WinUtilLog -Component "AppX" -Message "AppX removal finished."
|
Write-WinUtilLog -Component "AppX" -Message "AppX removal finished."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "AppX removal finished" -Percent 100
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message "AppX removal failed: $($_.Exception.Message)"
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "AppX removal failed" -Percent 100
|
||||||
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
$sync.ProcessRunning = $false
|
$sync.ProcessRunning = $false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check if button is defined in feature config with function or InvokeScript
|
# Check if button is defined in feature config with function or InvokeScript
|
||||||
@@ -65,6 +65,9 @@ function Invoke-WPFButton {
|
|||||||
"WPFUpdatessecurity" {Invoke-WPFUpdatessecurity}
|
"WPFUpdatessecurity" {Invoke-WPFUpdatessecurity}
|
||||||
"WPFGetInstalled" {Invoke-WPFGetInstalled -CheckBox "winget"}
|
"WPFGetInstalled" {Invoke-WPFGetInstalled -CheckBox "winget"}
|
||||||
"WPFGetInstalledTweaks" {Invoke-WPFGetInstalled -CheckBox "tweaks"}
|
"WPFGetInstalledTweaks" {Invoke-WPFGetInstalled -CheckBox "tweaks"}
|
||||||
|
"WPFAppxRemoval" {Invoke-WPFTab "WPFTab6BT"}
|
||||||
|
"WPFBackToTweaks" {Invoke-WPFTab "WPFTab2BT"}
|
||||||
|
"WPFInstallSelectedAppx" {Invoke-WPFAppxInstall}
|
||||||
"WPFRemoveSelectedAppx" {Invoke-WPFAppxRemoval}
|
"WPFRemoveSelectedAppx" {Invoke-WPFAppxRemoval}
|
||||||
"WPFDefaultAppxSelection" {Invoke-WPFPresets "AppxDefault" -checkboxfilterpattern "WPFAppx*"}
|
"WPFDefaultAppxSelection" {Invoke-WPFPresets "AppxDefault" -checkboxfilterpattern "WPFAppx*"}
|
||||||
"WPFSelectAllAppx" {
|
"WPFSelectAllAppx" {
|
||||||
@@ -74,7 +77,7 @@ function Invoke-WPFButton {
|
|||||||
$sync.configs.appxHashtable.Keys | ForEach-Object {$sync.$_.IsChecked = $false}
|
$sync.configs.appxHashtable.Keys | ForEach-Object {$sync.$_.IsChecked = $false}
|
||||||
}
|
}
|
||||||
"WPFGetInstalledAppx" {
|
"WPFGetInstalledAppx" {
|
||||||
$installedAppxPackages = Get-AppxPackage -AllUsers | Select-Object -ExpandProperty Name
|
$installedAppxPackages = Get-WinUtilInstalledAPPX
|
||||||
foreach ($appx in $sync.configs.appxHashtable.GetEnumerator()) {
|
foreach ($appx in $sync.configs.appxHashtable.GetEnumerator()) {
|
||||||
if ($appx.Value.PackageId -in $installedAppxPackages) {
|
if ($appx.Value.PackageId -in $installedAppxPackages) {
|
||||||
$sync.$($appx.Key).IsChecked = $true
|
$sync.$($appx.Key).IsChecked = $true
|
||||||
@@ -83,6 +86,13 @@ function Invoke-WPFButton {
|
|||||||
}
|
}
|
||||||
"WPFCloseButton" {$sync.Form.Close(); Write-Host "Bye bye!"}
|
"WPFCloseButton" {$sync.Form.Close(); Write-Host "Bye bye!"}
|
||||||
"WPFMinimizeButton" {$sync.Form.WindowState = [Windows.WindowState]::Minimized}
|
"WPFMinimizeButton" {$sync.Form.WindowState = [Windows.WindowState]::Minimized}
|
||||||
|
"WPFMaximizeButton" {
|
||||||
|
if ($sync.Form.WindowState -eq [Windows.WindowState]::Normal) {
|
||||||
|
$sync.Form.WindowState = [Windows.WindowState]::Maximized
|
||||||
|
} else {
|
||||||
|
$sync.Form.WindowState = [Windows.WindowState]::Normal
|
||||||
|
}
|
||||||
|
}
|
||||||
"WPFselectedAppsButton" {$sync.selectedAppsPopup.IsOpen = -not $sync.selectedAppsPopup.IsOpen}
|
"WPFselectedAppsButton" {$sync.selectedAppsPopup.IsOpen = -not $sync.selectedAppsPopup.IsOpen}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "App install finished" -Percent 100
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
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)"
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "App install failed" -Percent 100
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }
|
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 {
|
||||||
|
if ($sync.ProcessRunning) {
|
||||||
|
Show-WinUtilMessage -Message "Another process is currently running." -Title "WinUtil" -Button "OK" -Icon "Warning"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$downloadPath = Join-Path $sync.winutildir "ooshutup10.exe"
|
||||||
|
$sync.ProcessRunning = $true
|
||||||
|
|
||||||
|
Invoke-WPFRunspace -ParameterList @(,("downloadPath", $downloadPath)) -ScriptBlock {
|
||||||
|
param($downloadPath)
|
||||||
|
|
||||||
|
$hasUI = $null -ne $sync.Form -and $null -ne $sync.Form.Dispatcher
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$ProgressPreference = 'SilentlyContinue'
|
Write-WinUtilLog -Component "OOSU" -Message "Downloading O&O ShutUp10++."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Downloading O&O ShutUp10++ (0%)" -Percent 0
|
||||||
|
}
|
||||||
|
|
||||||
Invoke-WebRequest -Uri https://dl5.oo-software.com/files/ooshutup10/OOSU10.exe -OutFile "$winutildir\ooshutup10.exe"
|
Save-WinUtilFile -Uri "https://dl5.oo-software.com/files/ooshutup10/OOSU10.exe" -DestinationPath $downloadPath -ProgressCallback {
|
||||||
Start-Process -FilePath "$winutildir\ooshutup10.exe"
|
param($percent)
|
||||||
|
|
||||||
$ProgressPreference = 'Continue'
|
if ($hasUI) {
|
||||||
} catch {
|
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."
|
Write-Error "Couldn't download O&O ShutUp10. Please make sure you have an active Internet connection."
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
$sync.ProcessRunning = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,13 +19,12 @@ function Invoke-WPFTab {
|
|||||||
$tabNumber = [int]($ClickedTab -replace "WPFTab","" -replace "BT","") - 1
|
$tabNumber = [int]($ClickedTab -replace "WPFTab","" -replace "BT","") - 1
|
||||||
|
|
||||||
$filter = Get-WinUtilVariables -Type ToggleButton | Where-Object {$psitem -like "WPFTab?BT"}
|
$filter = Get-WinUtilVariables -Type ToggleButton | Where-Object {$psitem -like "WPFTab?BT"}
|
||||||
|
$sync.$tabNav.Items[$tabNumber].IsSelected = $true
|
||||||
($sync.GetEnumerator()).where{$psitem.Key -in $filter} | ForEach-Object {
|
($sync.GetEnumerator()).where{$psitem.Key -in $filter} | ForEach-Object {
|
||||||
if ($ClickedTab -ne $PSItem.name) {
|
if ($ClickedTab -ne $PSItem.name) {
|
||||||
$sync[$PSItem.Name].IsChecked = $false
|
$sync[$PSItem.Name].IsChecked = $false
|
||||||
} else {
|
} else {
|
||||||
$sync["$ClickedTab"].IsChecked = $true
|
$sync["$ClickedTab"].IsChecked = $true
|
||||||
$tabNumber = [int]($ClickedTab-replace "WPFTab","" -replace "BT","") - 1
|
|
||||||
$sync.$tabNav.Items[$tabNumber].IsSelected = $true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$sync.currentTab = $sync.$tabNav.Items[$tabNumber].Header
|
$sync.currentTab = $sync.$tabNav.Items[$tabNumber].Header
|
||||||
|
|||||||
@@ -409,6 +409,11 @@ function Invoke-WPFUIElements {
|
|||||||
$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
|
||||||
@@ -441,7 +446,7 @@ function Invoke-WPFUIElements {
|
|||||||
|
|
||||||
$sync[$entryInfo.Name].Add_Unchecked({
|
$sync[$entryInfo.Name].Add_Unchecked({
|
||||||
[System.Object]$Sender = $args[0]
|
[System.Object]$Sender = $args[0]
|
||||||
Invoke-WPFSelectedCheckboxesUpdate -type "Remove" -checkbox $Sender.name
|
Invoke-WPFSelectedCheckboxesUpdate -type "Remove" -checkboxName $Sender.name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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."
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "App uninstall finished" -Percent 100
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
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)"
|
||||||
|
if ($hasUI) {
|
||||||
|
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "App uninstall failed" -Percent 100
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" -overlay "warning" }
|
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,13 +39,13 @@ 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
|
||||||
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
|
||||||
$sync.ProcessRunning = $false
|
$sync.ProcessRunning = $false
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
Write-Host "================================="
|
Write-Host "================================="
|
||||||
@@ -75,13 +75,13 @@ 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)
|
||||||
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
|
||||||
$sync.ProcessRunning = $false
|
$sync.ProcessRunning = $false
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
Write-Host "================================="
|
Write-Host "================================="
|
||||||
|
|||||||
@@ -33,12 +33,12 @@ 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)
|
||||||
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
|
||||||
$sync.ProcessRunning = $false
|
$sync.ProcessRunning = $false
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
|
||||||
Write-Host "=================================="
|
Write-Host "=================================="
|
||||||
|
|||||||
+500
-20
@@ -1,11 +1,38 @@
|
|||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Tests - AppX Removal
|
# Tests - AppX Management
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
||||||
BeforeAll {
|
BeforeAll {
|
||||||
$script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
$script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
|
||||||
|
. (Join-Path $script:repoRoot "functions\private\Get-WinUtilInstalledAPPX.ps1")
|
||||||
|
. (Join-Path $script:repoRoot "functions\private\Install-WinUtilAPPX.ps1")
|
||||||
. (Join-Path $script:repoRoot "functions\private\Remove-WinUtilAPPX.ps1")
|
. (Join-Path $script:repoRoot "functions\private\Remove-WinUtilAPPX.ps1")
|
||||||
|
. (Join-Path $script:repoRoot "functions\private\Remove-WinUtilProvisionedAPPX.ps1")
|
||||||
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFAppxInstall.ps1")
|
||||||
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFAppxRemoval.ps1")
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFAppxRemoval.ps1")
|
||||||
|
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFButton.ps1")
|
||||||
|
|
||||||
|
$tokens = $null
|
||||||
|
$parseErrors = $null
|
||||||
|
$provisionedSourcePath = Join-Path $script:repoRoot "functions\private\Remove-WinUtilProvisionedAPPX.ps1"
|
||||||
|
$provisionedSourceAst = [System.Management.Automation.Language.Parser]::ParseFile($provisionedSourcePath, [ref]$tokens, [ref]$parseErrors)
|
||||||
|
$ps5CommandAssignment = $provisionedSourceAst.Find({
|
||||||
|
param($node)
|
||||||
|
$node -is [System.Management.Automation.Language.AssignmentStatementAst] -and
|
||||||
|
$node.Left -is [System.Management.Automation.Language.VariableExpressionAst] -and
|
||||||
|
$node.Left.VariablePath.UserPath -eq "ps5Command"
|
||||||
|
}, $true)
|
||||||
|
$script:provisionedRemovalScriptBlock = $ps5CommandAssignment.Right.Expression.ScriptBlock.GetScriptBlock()
|
||||||
|
|
||||||
|
$installSourcePath = Join-Path $script:repoRoot "functions\private\Install-WinUtilAPPX.ps1"
|
||||||
|
$installSourceAst = [System.Management.Automation.Language.Parser]::ParseFile($installSourcePath, [ref]$tokens, [ref]$parseErrors)
|
||||||
|
$installCommandAssignment = $installSourceAst.Find({
|
||||||
|
param($node)
|
||||||
|
$node -is [System.Management.Automation.Language.AssignmentStatementAst] -and
|
||||||
|
$node.Left -is [System.Management.Automation.Language.VariableExpressionAst] -and
|
||||||
|
$node.Left.VariablePath.UserPath -eq "ps5Command"
|
||||||
|
}, $true)
|
||||||
|
$script:appxInstallScriptBlock = $installCommandAssignment.Right.Expression.ScriptBlock.GetScriptBlock()
|
||||||
|
|
||||||
function Write-WinUtilLog {
|
function Write-WinUtilLog {
|
||||||
param($Message, $Level, $Component)
|
param($Message, $Level, $Component)
|
||||||
@@ -16,25 +43,46 @@ BeforeAll {
|
|||||||
function Invoke-WPFRunspace {
|
function Invoke-WPFRunspace {
|
||||||
param($ArgumentList, $ParameterList, [scriptblock]$ScriptBlock)
|
param($ArgumentList, $ParameterList, [scriptblock]$ScriptBlock)
|
||||||
}
|
}
|
||||||
|
function Invoke-WPFUIThread {
|
||||||
|
param([scriptblock]$ScriptBlock)
|
||||||
|
}
|
||||||
|
function Set-WinUtilTweaksProgressIndicator {
|
||||||
|
param($Visible, $Label, $Percent)
|
||||||
|
}
|
||||||
|
function powershell.exe { }
|
||||||
function Get-AppxPackage {
|
function Get-AppxPackage {
|
||||||
param($Name, [switch]$AllUsers)
|
param($Name, [switch]$AllUsers, $ErrorAction)
|
||||||
|
}
|
||||||
|
function Add-AppxPackage {
|
||||||
|
param($Register, [switch]$DisableDevelopmentMode, $ErrorAction)
|
||||||
|
}
|
||||||
|
function Install-WinUtilWinget { }
|
||||||
|
function Install-WinUtilProgramWinget {
|
||||||
|
param($Action, $Programs)
|
||||||
}
|
}
|
||||||
function Remove-AppxPackage {
|
function Remove-AppxPackage {
|
||||||
param(
|
param(
|
||||||
[Parameter(ValueFromPipeline = $true)]
|
[Parameter(ValueFromPipeline = $true)]
|
||||||
$InputObject,
|
$InputObject,
|
||||||
[switch]$AllUsers
|
$Package,
|
||||||
|
[switch]$AllUsers,
|
||||||
|
$ErrorAction
|
||||||
)
|
)
|
||||||
process { }
|
process { }
|
||||||
}
|
}
|
||||||
|
function Remove-WinUtilProvisionedAPPX {
|
||||||
|
param($PackageList)
|
||||||
|
}
|
||||||
function Get-AppxProvisionedPackage {
|
function Get-AppxProvisionedPackage {
|
||||||
param([switch]$Online)
|
param([switch]$Online, $ErrorAction)
|
||||||
}
|
}
|
||||||
function Remove-AppxProvisionedPackage {
|
function Remove-AppxProvisionedPackage {
|
||||||
param(
|
param(
|
||||||
[Parameter(ValueFromPipeline = $true)]
|
[Parameter(ValueFromPipeline = $true)]
|
||||||
$InputObject,
|
$InputObject,
|
||||||
[switch]$Online
|
[switch]$Online,
|
||||||
|
$PackageName,
|
||||||
|
$ErrorAction
|
||||||
)
|
)
|
||||||
process { }
|
process { }
|
||||||
}
|
}
|
||||||
@@ -53,40 +101,360 @@ BeforeAll {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Describe "Get-WinUtilInstalledAPPX" {
|
||||||
|
BeforeEach {
|
||||||
|
Mock Write-WinUtilLog { }
|
||||||
|
Mock powershell.exe {
|
||||||
|
$global:LASTEXITCODE = 0
|
||||||
|
@("Example.One", "Example.Two")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "queries installed package names through Windows PowerShell" {
|
||||||
|
$result = Get-WinUtilInstalledAPPX
|
||||||
|
|
||||||
|
$result | Should -Be @("Example.One", "Example.Two")
|
||||||
|
Should -Invoke -CommandName powershell.exe -Times 1 -Exactly
|
||||||
|
Should -Invoke -CommandName Write-WinUtilLog -Times 0 -Exactly
|
||||||
|
}
|
||||||
|
|
||||||
|
It "logs query failures and returns no package names" {
|
||||||
|
Mock powershell.exe {
|
||||||
|
$global:LASTEXITCODE = 1
|
||||||
|
"AppX query failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = @(Get-WinUtilInstalledAPPX)
|
||||||
|
|
||||||
|
$result | Should -HaveCount 0
|
||||||
|
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Level -eq "ERROR" -and
|
||||||
|
$Component -eq "AppX" -and
|
||||||
|
$Message -eq "Failed to get installed AppX packages: AppX query failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Install-WinUtilAPPX" {
|
||||||
|
BeforeEach {
|
||||||
|
Mock Write-WinUtilLog { }
|
||||||
|
Mock Install-WinUtilWinget { }
|
||||||
|
Mock Install-WinUtilProgramWinget { }
|
||||||
|
Mock powershell.exe {
|
||||||
|
$global:LASTEXITCODE = 0
|
||||||
|
"C:\Program Files\WindowsApps\Example.Package\AppxManifest.xml"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "uses a local manifest without contacting the Microsoft Store" {
|
||||||
|
Install-WinUtilAPPX -Name "Example.Package" -StoreId "9EXAMPLE1234"
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Install-WinUtilWinget -Times 0 -Exactly
|
||||||
|
Should -Invoke -CommandName Install-WinUtilProgramWinget -Times 0 -Exactly
|
||||||
|
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Component -eq "AppX" -and
|
||||||
|
$Message -like "Registered local AppX manifest for Example.Package*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "falls back to the Microsoft Store when no local manifest is available" {
|
||||||
|
Mock powershell.exe { $global:LASTEXITCODE = 0 }
|
||||||
|
|
||||||
|
Install-WinUtilAPPX -Name "Example.Package" -StoreId "9EXAMPLE1234"
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Install-WinUtilWinget -Times 1 -Exactly
|
||||||
|
Should -Invoke -CommandName Install-WinUtilProgramWinget -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Action -eq "Install" -and $Programs.Count -eq 1 -and $Programs[0] -eq "msstore:9EXAMPLE1234"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "logs local registration failures before using the Microsoft Store" {
|
||||||
|
Mock powershell.exe {
|
||||||
|
$global:LASTEXITCODE = 1
|
||||||
|
"Registration failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
Install-WinUtilAPPX -Name "Example.Package" -StoreId "9EXAMPLE1234"
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Level -eq "WARN" -and
|
||||||
|
$Component -eq "AppX" -and
|
||||||
|
$Message -eq "Local AppX registration failed for Example.Package: Registration failed"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Install-WinUtilProgramWinget -Times 1 -Exactly
|
||||||
|
}
|
||||||
|
|
||||||
|
It "throws after logging an error when neither install method is available" {
|
||||||
|
Mock powershell.exe { $global:LASTEXITCODE = 0 }
|
||||||
|
|
||||||
|
{ Install-WinUtilAPPX -Name "Example.Package" } |
|
||||||
|
Should -Throw "Unable to install Example.Package because no local manifest or Microsoft Store ID is available."
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Install-WinUtilProgramWinget -Times 0 -Exactly
|
||||||
|
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Level -eq "ERROR" -and
|
||||||
|
$Component -eq "AppX" -and
|
||||||
|
$Message -eq "Unable to install Example.Package because no local manifest or Microsoft Store ID is available."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "registers an installed package manifest through Windows PowerShell" {
|
||||||
|
Mock Get-AppxPackage {
|
||||||
|
[pscustomobject]@{
|
||||||
|
InstallLocation = "C:\Program Files\WindowsApps\Example.Package"
|
||||||
|
Version = [version]"2.0.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mock Get-AppxProvisionedPackage { }
|
||||||
|
Mock Test-Path { $LiteralPath -eq "C:\Program Files\WindowsApps\Example.Package\AppxManifest.xml" }
|
||||||
|
Mock Add-AppxPackage { }
|
||||||
|
|
||||||
|
$result = & $script:appxInstallScriptBlock "Example.Package"
|
||||||
|
|
||||||
|
$result | Should -Be "C:\Program Files\WindowsApps\Example.Package\AppxManifest.xml"
|
||||||
|
Should -Invoke -CommandName Get-AppxPackage -Times 1 -Exactly
|
||||||
|
Should -Invoke -CommandName Add-AppxPackage -Times 1 -Exactly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Get installed AppX selection" {
|
||||||
|
BeforeEach {
|
||||||
|
$script:sync = [Hashtable]::Synchronized(@{
|
||||||
|
ProcessRunning = $false
|
||||||
|
configs = @{
|
||||||
|
feature = @{}
|
||||||
|
appxHashtable = @{
|
||||||
|
WPFAppxExample = [pscustomobject]@{ PackageId = "Example.Package" }
|
||||||
|
WPFAppxMissing = [pscustomobject]@{ PackageId = "Missing.Package" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WPFAppxExample = [pscustomobject]@{ IsChecked = $false }
|
||||||
|
WPFAppxMissing = [pscustomobject]@{ IsChecked = $false }
|
||||||
|
})
|
||||||
|
|
||||||
|
Mock Set-WinUtilTweaksProgressIndicator { }
|
||||||
|
Mock Get-WinUtilInstalledAPPX { @("Example.Package") }
|
||||||
|
Mock Invoke-WPFAppxInstall { }
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterEach {
|
||||||
|
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
It "selects configured packages returned by the compatibility-safe query" {
|
||||||
|
Invoke-WPFButton -Button "WPFGetInstalledAppx"
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Get-WinUtilInstalledAPPX -Times 1 -Exactly
|
||||||
|
$script:sync.WPFAppxExample.IsChecked | Should -BeTrue
|
||||||
|
$script:sync.WPFAppxMissing.IsChecked | Should -BeFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
It "routes the install button to the AppX install workflow" {
|
||||||
|
Invoke-WPFButton -Button "WPFInstallSelectedAppx"
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Invoke-WPFAppxInstall -Times 1 -Exactly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Describe "Remove-WinUtilAPPX" {
|
Describe "Remove-WinUtilAPPX" {
|
||||||
BeforeEach {
|
BeforeEach {
|
||||||
Mock Write-Host { }
|
Mock Write-Host { }
|
||||||
Mock Write-WinUtilLog { }
|
Mock Write-WinUtilLog { }
|
||||||
Mock Get-AppxPackage {
|
Mock Get-AppxPackage {
|
||||||
|
@(
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = $Name
|
Name = $Name
|
||||||
|
PackageFullName = "$Name.FullName"
|
||||||
}
|
}
|
||||||
|
[pscustomobject]@{
|
||||||
|
Name = $Name
|
||||||
|
PackageFullName = "$Name.FullName"
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Mock Remove-AppxPackage { }
|
Mock Remove-AppxPackage { }
|
||||||
|
}
|
||||||
|
|
||||||
|
It "removes matching installed AppX packages" {
|
||||||
|
Remove-WinUtilAPPX -Name "Microsoft.Xbox*"
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Get-AppxPackage -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Name -eq "*Microsoft.Xbox**" -and $AllUsers -eq $true
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Remove-AppxPackage -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Package -eq "*Microsoft.Xbox**.FullName" -and
|
||||||
|
$AllUsers -eq $true -and
|
||||||
|
$ErrorAction -eq "Stop"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "logs installed AppX removal failures" {
|
||||||
|
Mock Remove-AppxPackage { throw "Removal failed" }
|
||||||
|
|
||||||
|
{ Remove-WinUtilAPPX -Name "Example.Package" } | Should -Not -Throw
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Level -eq "ERROR" -and
|
||||||
|
$Component -eq "AppX" -and
|
||||||
|
$Message -eq "Failed to remove AppX package *Example.Package*.FullName: Removal failed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Remove-WinUtilProvisionedAPPX" {
|
||||||
|
BeforeEach {
|
||||||
Mock Get-AppxProvisionedPackage {
|
Mock Get-AppxProvisionedPackage {
|
||||||
@(
|
@(
|
||||||
[pscustomobject]@{ DisplayName = "Microsoft.XboxGamingOverlay" }
|
[pscustomobject]@{ DisplayName = "Example.One"; PackageName = "Example.One_1.0" }
|
||||||
[pscustomobject]@{ DisplayName = "Microsoft.WindowsCalculator" }
|
[pscustomobject]@{ DisplayName = "Example.Two"; PackageName = "Example.Two_1.0" }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Mock Remove-AppxProvisionedPackage { }
|
Mock Remove-AppxProvisionedPackage { }
|
||||||
}
|
}
|
||||||
|
|
||||||
It "removes matching installed and provisioned AppX packages" {
|
It "queries provisioned packages once for all selected package names" {
|
||||||
Remove-WinUtilAPPX -Name "Microsoft.Xbox*"
|
& $script:provisionedRemovalScriptBlock "Example.One" "Example.Two"
|
||||||
|
|
||||||
Should -Invoke -CommandName Get-AppxPackage -Times 1 -Exactly -ParameterFilter {
|
|
||||||
$Name -eq "Microsoft.Xbox*" -and $AllUsers -eq $true
|
|
||||||
}
|
|
||||||
Should -Invoke -CommandName Remove-AppxPackage -Times 1 -Exactly -ParameterFilter {
|
|
||||||
$InputObject.Name -eq "Microsoft.Xbox*" -and $AllUsers -eq $true
|
|
||||||
}
|
|
||||||
Should -Invoke -CommandName Get-AppxProvisionedPackage -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Get-AppxProvisionedPackage -Times 1 -Exactly -ParameterFilter {
|
||||||
$Online -eq $true
|
$Online -eq $true
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Remove-AppxProvisionedPackage -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Remove-AppxProvisionedPackage -Times 1 -Exactly -ParameterFilter {
|
||||||
$InputObject.DisplayName -eq "Microsoft.XboxGamingOverlay" -and $Online -eq $true
|
$PackageName -eq "Example.One_1.0" -and $Online -eq $true
|
||||||
}
|
}
|
||||||
|
Should -Invoke -CommandName Remove-AppxProvisionedPackage -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$PackageName -eq "Example.Two_1.0" -and $Online -eq $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "surfaces provisioned package removal failures from the child process" {
|
||||||
|
Mock Remove-AppxProvisionedPackage { throw "DISM failed" }
|
||||||
|
|
||||||
|
{ & $script:provisionedRemovalScriptBlock "Example.One" } |
|
||||||
|
Should -Throw "*Failed to remove provisioned AppX package Example.One_1.0: DISM failed*"
|
||||||
|
Should -Invoke -CommandName Remove-AppxProvisionedPackage -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$PackageName -eq "Example.One_1.0" -and
|
||||||
|
$Online -eq $true -and
|
||||||
|
$ErrorAction -eq "Stop"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
It "throws after logging child process failures" {
|
||||||
|
$source = Get-Content -Path $provisionedSourcePath -Raw
|
||||||
|
|
||||||
|
$source | Should -Match '\$removalOutput = powershell\.exe .* 2>&1'
|
||||||
|
$source | Should -Match 'Write-WinUtilLog -Level "ERROR" -Component "AppX" -Message \$errorMessage'
|
||||||
|
$source | Should -Match '(?s)AppX provisioned package removal failed:.*throw \$errorMessage.*AppX provisioned package removal completed\.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Describe "Invoke-WPFAppxInstall" {
|
||||||
|
BeforeEach {
|
||||||
|
$script:sync = [Hashtable]::Synchronized(@{
|
||||||
|
ProcessRunning = $false
|
||||||
|
Form = [pscustomobject]@{ Dispatcher = [pscustomobject]@{} }
|
||||||
|
selectedAppx = [System.Collections.Generic.List[string]]::new()
|
||||||
|
configs = @{
|
||||||
|
appxHashtable = @{
|
||||||
|
WPFAppxExample = [pscustomobject]@{
|
||||||
|
Content = "Example App"
|
||||||
|
PackageId = "Example.Package"
|
||||||
|
StoreId = "9EXAMPLE1234"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$script:capturedAppxInstallScriptBlock = $null
|
||||||
|
$script:capturedAppxInstallParameterList = $null
|
||||||
|
$script:appxInstallProcessRunningAtLaunch = $null
|
||||||
|
|
||||||
|
Mock Show-WinUtilMessage { "OK" }
|
||||||
|
Mock Write-Host { }
|
||||||
|
Mock Write-WinUtilLog { }
|
||||||
|
Mock Set-WinUtilTweaksProgressIndicator { }
|
||||||
|
Mock Invoke-WPFUIThread { }
|
||||||
|
Mock Install-WinUtilAPPX { }
|
||||||
|
Mock Invoke-WPFRunspace {
|
||||||
|
$script:appxInstallProcessRunningAtLaunch = $script:sync.ProcessRunning
|
||||||
|
$script:capturedAppxInstallScriptBlock = $ScriptBlock
|
||||||
|
$script:capturedAppxInstallParameterList = $ParameterList
|
||||||
|
[pscustomobject]@{ MockHandle = $true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterEach {
|
||||||
|
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name capturedAppxInstallScriptBlock -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name capturedAppxInstallParameterList -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name appxInstallProcessRunningAtLaunch -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
It "prompts and exits when no AppX packages are selected for install" {
|
||||||
|
Invoke-WPFAppxInstall
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Show-WinUtilMessage -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Message -eq "No AppX Package selected" -and
|
||||||
|
$Title -eq "Error" -and
|
||||||
|
$Button -eq "OK" -and
|
||||||
|
$Icon -eq "Error"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFRunspace -Times 0 -Exactly
|
||||||
|
}
|
||||||
|
|
||||||
|
It "prevents overlapping AppX install operations" {
|
||||||
|
$script:sync.ProcessRunning = $true
|
||||||
|
$script:sync.selectedAppx.Add("WPFAppxExample")
|
||||||
|
|
||||||
|
Invoke-WPFAppxInstall
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Show-WinUtilMessage -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Message -eq "An AppX process is currently running." -and
|
||||||
|
$Title -eq "WinUtil" -and
|
||||||
|
$Button -eq "OK" -and
|
||||||
|
$Icon -eq "Warning"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFRunspace -Times 0 -Exactly
|
||||||
|
}
|
||||||
|
|
||||||
|
It "installs selected AppX packages with their Store IDs" {
|
||||||
|
$script:sync.selectedAppx.Add("WPFAppxExample")
|
||||||
|
|
||||||
|
Invoke-WPFAppxInstall
|
||||||
|
$script:appxInstallProcessRunningAtLaunch | Should -BeTrue
|
||||||
|
& $script:capturedAppxInstallScriptBlock -selected @("WPFAppxExample") -apps $script:sync.configs.appxHashtable
|
||||||
|
|
||||||
|
$script:capturedAppxInstallParameterList[0][1][0] | Should -Be "WPFAppxExample"
|
||||||
|
Should -Invoke -CommandName Install-WinUtilAPPX -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Name -eq "Example.Package" -and $StoreId -eq "9EXAMPLE1234"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Installing Example App (1/1)" -and $Percent -eq 0
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Installed Example App (1/1)" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "AppX install finished" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "None" -overlay "checkmark"*'
|
||||||
|
}
|
||||||
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
It "shows failure feedback and clears ProcessRunning when install fails" {
|
||||||
|
$script:sync.selectedAppx.Add("WPFAppxExample")
|
||||||
|
Mock Install-WinUtilAPPX { throw "Install failed" }
|
||||||
|
|
||||||
|
Invoke-WPFAppxInstall
|
||||||
|
& $script:capturedAppxInstallScriptBlock -selected @("WPFAppxExample") -apps $script:sync.configs.appxHashtable
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "AppX install failed" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "Error" -overlay "warning"*'
|
||||||
|
}
|
||||||
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,9 +469,11 @@ Describe "Invoke-WPFAppxRemoval entrypoint" {
|
|||||||
})
|
})
|
||||||
$script:capturedAppxScriptBlock = $null
|
$script:capturedAppxScriptBlock = $null
|
||||||
$script:capturedAppxParameterList = $null
|
$script:capturedAppxParameterList = $null
|
||||||
|
$script:appxRemovalProcessRunningAtLaunch = $null
|
||||||
|
|
||||||
Mock Show-WinUtilMessage { "OK" }
|
Mock Show-WinUtilMessage { "OK" }
|
||||||
Mock Invoke-WPFRunspace {
|
Mock Invoke-WPFRunspace {
|
||||||
|
$script:appxRemovalProcessRunningAtLaunch = $script:sync.ProcessRunning
|
||||||
$script:capturedAppxScriptBlock = $ScriptBlock
|
$script:capturedAppxScriptBlock = $ScriptBlock
|
||||||
$script:capturedAppxParameterList = $ParameterList
|
$script:capturedAppxParameterList = $ParameterList
|
||||||
[pscustomobject]@{ MockHandle = $true }
|
[pscustomobject]@{ MockHandle = $true }
|
||||||
@@ -114,6 +484,7 @@ Describe "Invoke-WPFAppxRemoval entrypoint" {
|
|||||||
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
|
||||||
Remove-Variable -Name capturedAppxScriptBlock -Scope Script -ErrorAction SilentlyContinue
|
Remove-Variable -Name capturedAppxScriptBlock -Scope Script -ErrorAction SilentlyContinue
|
||||||
Remove-Variable -Name capturedAppxParameterList -Scope Script -ErrorAction SilentlyContinue
|
Remove-Variable -Name capturedAppxParameterList -Scope Script -ErrorAction SilentlyContinue
|
||||||
|
Remove-Variable -Name appxRemovalProcessRunningAtLaunch -Scope Script -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
It "prompts and exits when no AppX packages are selected" {
|
It "prompts and exits when no AppX packages are selected" {
|
||||||
@@ -128,6 +499,21 @@ Describe "Invoke-WPFAppxRemoval entrypoint" {
|
|||||||
Should -Invoke -CommandName Invoke-WPFRunspace -Times 0 -Exactly
|
Should -Invoke -CommandName Invoke-WPFRunspace -Times 0 -Exactly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
It "prevents overlapping AppX removal operations" {
|
||||||
|
$script:sync.ProcessRunning = $true
|
||||||
|
$script:sync.selectedAppx.Add("WPFAppxExample")
|
||||||
|
|
||||||
|
Invoke-WPFAppxRemoval
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Show-WinUtilMessage -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Message -eq "An AppX process is currently running." -and
|
||||||
|
$Title -eq "WinUtil" -and
|
||||||
|
$Button -eq "OK" -and
|
||||||
|
$Icon -eq "Warning"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFRunspace -Times 0 -Exactly
|
||||||
|
}
|
||||||
|
|
||||||
It "passes selected AppX keys and app metadata to the removal runspace" {
|
It "passes selected AppX keys and app metadata to the removal runspace" {
|
||||||
$script:sync.selectedAppx.Add("WPFAppxExample")
|
$script:sync.selectedAppx.Add("WPFAppxExample")
|
||||||
$script:sync.configs.appxHashtable["WPFAppxExample"] = [pscustomobject]@{
|
$script:sync.configs.appxHashtable["WPFAppxExample"] = [pscustomobject]@{
|
||||||
@@ -136,7 +522,10 @@ Describe "Invoke-WPFAppxRemoval entrypoint" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Invoke-WPFAppxRemoval
|
Invoke-WPFAppxRemoval
|
||||||
|
$script:sync.selectedAppx.Add("WPFAppxChangedAfterLaunch")
|
||||||
|
|
||||||
|
$script:appxRemovalProcessRunningAtLaunch | Should -BeTrue
|
||||||
|
$script:capturedAppxParameterList[0][1] | Should -HaveCount 1
|
||||||
Should -Invoke -CommandName Show-WinUtilMessage -Times 0 -Exactly
|
Should -Invoke -CommandName Show-WinUtilMessage -Times 0 -Exactly
|
||||||
Should -Invoke -CommandName Invoke-WPFRunspace -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Invoke-WPFRunspace -Times 1 -Exactly -ParameterFilter {
|
||||||
$ScriptBlock -is [scriptblock] -and
|
$ScriptBlock -is [scriptblock] -and
|
||||||
@@ -153,6 +542,7 @@ Describe "Invoke-WPFAppxRemoval runspace body" {
|
|||||||
BeforeEach {
|
BeforeEach {
|
||||||
$script:sync = [Hashtable]::Synchronized(@{
|
$script:sync = [Hashtable]::Synchronized(@{
|
||||||
ProcessRunning = $false
|
ProcessRunning = $false
|
||||||
|
Form = [pscustomobject]@{ Dispatcher = [pscustomobject]@{} }
|
||||||
selectedAppx = [System.Collections.Generic.List[string]]::new()
|
selectedAppx = [System.Collections.Generic.List[string]]::new()
|
||||||
configs = @{
|
configs = @{
|
||||||
appxHashtable = @{}
|
appxHashtable = @{}
|
||||||
@@ -185,14 +575,18 @@ Describe "Invoke-WPFAppxRemoval runspace body" {
|
|||||||
Mock Show-WinUtilMessage { "OK" }
|
Mock Show-WinUtilMessage { "OK" }
|
||||||
Mock Write-Host { }
|
Mock Write-Host { }
|
||||||
Mock Write-WinUtilLog { }
|
Mock Write-WinUtilLog { }
|
||||||
|
Mock Set-WinUtilTweaksProgressIndicator { }
|
||||||
|
Mock Invoke-WPFUIThread { }
|
||||||
Mock Stop-Process { }
|
Mock Stop-Process { }
|
||||||
Mock Set-ItemProperty { }
|
Mock Set-ItemProperty { }
|
||||||
Mock Get-AppxPackage {
|
Mock Get-AppxPackage {
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = $Name
|
Name = $Name
|
||||||
|
PackageFullName = "$Name.FullName"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mock Remove-AppxPackage { }
|
Mock Remove-AppxPackage { }
|
||||||
|
Mock Remove-WinUtilProvisionedAPPX { }
|
||||||
Mock Get-Package {
|
Mock Get-Package {
|
||||||
[pscustomobject]@{
|
[pscustomobject]@{
|
||||||
Name = "Microsoft Teams Meeting Add-in"
|
Name = "Microsoft Teams Meeting Add-in"
|
||||||
@@ -216,10 +610,84 @@ Describe "Invoke-WPFAppxRemoval runspace body" {
|
|||||||
& $script:capturedAppxScriptBlock -selected $selected -apps $script:apps
|
& $script:capturedAppxScriptBlock -selected $selected -apps $script:apps
|
||||||
|
|
||||||
Should -Invoke -CommandName Get-AppxPackage -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Get-AppxPackage -Times 1 -Exactly -ParameterFilter {
|
||||||
$Name -eq "Example.Package" -and $AllUsers -eq $true
|
$Name -eq "*Example.Package*" -and $AllUsers -eq $true
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Remove-AppxPackage -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Remove-AppxPackage -Times 1 -Exactly -ParameterFilter {
|
||||||
$InputObject.Name -eq "Example.Package" -and $AllUsers -eq $true
|
$Package -eq "*Example.Package*.FullName"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Remove-WinUtilProvisionedAPPX -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$PackageList.Count -eq 1 -and $PackageList[0] -eq "Example.Package"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Removing Example App (1/1)" -and $Percent -eq 0
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "Removed Example App (1/1)" -and $Percent -eq 90
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "AppX removal finished" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "None" -overlay "checkmark"*'
|
||||||
|
}
|
||||||
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
It "shows failure feedback and clears ProcessRunning when removal fails" {
|
||||||
|
$selected = @("WPFAppxExample")
|
||||||
|
$script:sync.selectedAppx.Add("WPFAppxExample")
|
||||||
|
$script:sync.configs.appxHashtable = $script:apps
|
||||||
|
Mock Remove-WinUtilAPPX { throw "Removal failed" }
|
||||||
|
|
||||||
|
Invoke-WPFAppxRemoval
|
||||||
|
& $script:capturedAppxScriptBlock -selected $selected -apps $script:apps
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "AppX removal failed" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "Error" -overlay "warning"*'
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Remove-WinUtilProvisionedAPPX -Times 0 -Exactly
|
||||||
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
It "removes packages without UI progress during headless autorun" {
|
||||||
|
$selected = @("WPFAppxExample")
|
||||||
|
$script:sync.Remove("Form")
|
||||||
|
$script:sync.selectedAppx.Add("WPFAppxExample")
|
||||||
|
$script:sync.configs.appxHashtable = $script:apps
|
||||||
|
|
||||||
|
Invoke-WPFAppxRemoval
|
||||||
|
& $script:capturedAppxScriptBlock -selected $selected -apps $script:apps
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Remove-AppxPackage -Times 1 -Exactly
|
||||||
|
Should -Invoke -CommandName Remove-WinUtilProvisionedAPPX -Times 1 -Exactly
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 0 -Exactly
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 0 -Exactly
|
||||||
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
|
}
|
||||||
|
|
||||||
|
It "shows failure feedback when provisioned package removal fails" {
|
||||||
|
$selected = @("WPFAppxExample")
|
||||||
|
$script:sync.selectedAppx.Add("WPFAppxExample")
|
||||||
|
$script:sync.configs.appxHashtable = $script:apps
|
||||||
|
Mock Remove-WinUtilProvisionedAPPX { throw "Provisioned removal failed" }
|
||||||
|
|
||||||
|
Invoke-WPFAppxRemoval
|
||||||
|
& $script:capturedAppxScriptBlock -selected $selected -apps $script:apps
|
||||||
|
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$Visible -eq $true -and $Label -eq "AppX removal failed" -and $Percent -eq 100
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Set-WinUtilTweaksProgressIndicator -Times 0 -Exactly -ParameterFilter {
|
||||||
|
$Label -eq "AppX removal finished"
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "Error" -overlay "warning"*'
|
||||||
|
}
|
||||||
|
Should -Invoke -CommandName Invoke-WPFUIThread -Times 0 -Exactly -ParameterFilter {
|
||||||
|
$ScriptBlock.ToString() -like '*Set-WinUtilTaskbaritem -state "None" -overlay "checkmark"*'
|
||||||
}
|
}
|
||||||
$script:sync.ProcessRunning | Should -BeFalse
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
}
|
}
|
||||||
@@ -239,7 +707,10 @@ Describe "Invoke-WPFAppxRemoval runspace body" {
|
|||||||
& $script:capturedAppxScriptBlock -selected $selected -apps $script:apps
|
& $script:capturedAppxScriptBlock -selected $selected -apps $script:apps
|
||||||
|
|
||||||
Should -Invoke -CommandName Stop-Process -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Stop-Process -Times 1 -Exactly -ParameterFilter {
|
||||||
$Name -eq "GameBarFTServer"
|
$Name -eq "GameBarFTServer" -and
|
||||||
|
$Force -eq $true -and
|
||||||
|
$Confirm -eq $false -and
|
||||||
|
$ErrorAction -eq "SilentlyContinue"
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Set-ItemProperty -Times 1 -Exactly -ParameterFilter {
|
||||||
$Path -eq "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\GameDVR" -and
|
$Path -eq "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\GameDVR" -and
|
||||||
@@ -247,7 +718,10 @@ Describe "Invoke-WPFAppxRemoval runspace body" {
|
|||||||
$Value -eq 0
|
$Value -eq 0
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Stop-Process -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Stop-Process -Times 1 -Exactly -ParameterFilter {
|
||||||
$Name -eq "dllhost"
|
$Name -eq "dllhost" -and
|
||||||
|
$Force -eq $true -and
|
||||||
|
$Confirm -eq $false -and
|
||||||
|
$ErrorAction -eq "SilentlyContinue"
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Get-Package -Times 1 -Exactly -ParameterFilter {
|
Should -Invoke -CommandName Get-Package -Times 1 -Exactly -ParameterFilter {
|
||||||
$Name -eq "Microsoft Teams*"
|
$Name -eq "Microsoft Teams*"
|
||||||
@@ -256,6 +730,12 @@ Describe "Invoke-WPFAppxRemoval runspace body" {
|
|||||||
$InputObject.Name -eq "Microsoft Teams Meeting Add-in" -and $Force -eq $true
|
$InputObject.Name -eq "Microsoft Teams Meeting Add-in" -and $Force -eq $true
|
||||||
}
|
}
|
||||||
Should -Invoke -CommandName Remove-AppxPackage -Times 3 -Exactly
|
Should -Invoke -CommandName Remove-AppxPackage -Times 3 -Exactly
|
||||||
|
Should -Invoke -CommandName Remove-WinUtilProvisionedAPPX -Times 1 -Exactly -ParameterFilter {
|
||||||
|
$PackageList.Count -eq 3 -and
|
||||||
|
$PackageList[0] -eq "Microsoft.XboxGamingOverlay" -and
|
||||||
|
$PackageList[1] -eq "Microsoft.WindowsNotepad" -and
|
||||||
|
$PackageList[2] -eq "MSTeams"
|
||||||
|
}
|
||||||
$script:sync.ProcessRunning | Should -BeFalse
|
$script:sync.ProcessRunning | Should -BeFalse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user