Compare commits

...

113 Commits

Author SHA1 Message Date
ChrisTitusTech
18de3d59ee Deploying to main from @ ChrisTitusTech/winutil@59d968e7c4 🚀 2025-06-14 15:32:56 +00:00
ChrisTitusTech
59d968e7c4 Deploying to main from @ ChrisTitusTech/winutil@afe85ad7f0 🚀 2025-06-06 15:33:48 +00:00
ChrisTitusTech
afe85ad7f0 Deploying to main from @ ChrisTitusTech/winutil@efb9e5bde6 🚀 2025-06-03 15:35:28 +00:00
Martin Wiethan
efb9e5bde6
correct uninstall variable (#3384) 2025-06-01 10:40:37 -05:00
ChrisTitusTech
56eba47a6c Deploying to main from @ ChrisTitusTech/winutil@e57cde423c 🚀 2025-05-30 15:34:17 +00:00
ChrisTitusTech
e57cde423c Deploying to main from @ ChrisTitusTech/winutil@de9b643129 🚀 2025-05-27 15:34:49 +00:00
Chris Titus
de9b643129 add signing shortcut 2025-05-23 11:26:48 -05:00
Chris Titus
e430e0aad0 revert single form window 2025-05-23 11:22:44 -05:00
Chris Titus
61fd4d2f91 update authors 2025-05-23 11:20:23 -05:00
Chris Titus
b72cd83189 Remove Old Code-Signing 2025-05-23 11:15:18 -05:00
Martin Wiethan
290292ec94
Refactor process termination for explorer.exe in tweaks.json (#3375) 2025-05-23 11:04:26 -05:00
Martin Wiethan
d22865d79b
Fix App references (#3374)
* Update winget reference

* Remove Samsung Magician entry from applications.json as it dosn't exist in winget anymore
2025-05-23 11:03:00 -05:00
Nilesh
5c5b999a09
Change WindowStyle to SingleBorderWindow (#3373) 2025-05-23 10:59:54 -05:00
Martin Wiethan
0c0e6bd243
Implement search bar debounce functionality to improve UI responsiveness (#3371)
* Implement search bar debounce functionality to improve UI responsiveness

* Enhance app search functionality to include description matching
2025-05-23 10:56:24 -05:00
Alice Lia Stapleton
dd06489d63
Windows Spotlight warning (#3354)
Adds a warning for the problem encountered in issue 3203
2025-05-23 10:53:33 -05:00
Martin Wiethan
41df9d3d88
Add Right-Click Action on App Install Page (#3367)
* Add right click context menu for app entries with install, uninstall, and info options

* Add hand cursor on mouse over for button in inputXML.xaml
2025-05-23 10:52:57 -05:00
Raphael Machado
63d56bcac9
remove spotube (#3372)
🚨 Spotube is banned from using "Spotify™ API" 🚨

The developer of Spotube has received a cease and desist letter from Spotify USA Inc. and Spotify AB, asserting a legal threat concerning the distribution and development of any application that utilizes Spotify’s data API in conjunction with content from YouTube® to facilitate ad-free playback of music tracks. The letter contends that this specific use of the Spotify™ APIs contravenes the Spotify™ Agreements and may also infringe upon the rights of music rights holders.

Consequently, as the official maintainer of Spotube, I will immediately cease all forms of official distribution and development of Spotube that continue to employ the aforementioned 'Spotify™ APIs'

Their exact reasoning: (any) "uses of Spotify’s data API in connection with content from YouTube to provide ad-free playback of music tracks. The use of the Spotify APIs in this manner violates the Spotify Agreements and may also violate the rights of music rights holders."

https://spotube.krtirtho.dev/
2025-05-23 10:37:14 -05:00
Martin Wiethan
962b18e8fa
Re-Redesign of the Install Tab (#3350)
* Initial Remove Expanded View

* more cleanup

* Add word wrapping for Tooltips

* Update tooltip colors in themes and XAML styles

* Rename Properties for consistency

* More Cleanup, and simplification. Also added support for screenreaders

* Remove unused variables and shorten window naming

* Rename Invoke-WPFUIApps to Initialize-WPFUI and update function calls for consistency

* Rename Invoke-WPFUIApps.ps1 to Initialize-WPFUI.ps1

* Add TODO comments for sidebar UI generation in Initialize-WPFUI function
2025-05-12 15:45:57 -05:00
ChrisTitusTech
14e761f438 Deploying to main from @ ChrisTitusTech/winutil@3e416f5c14 🚀 2025-05-12 15:35:26 +00:00
Chris Titus
3e416f5c14 format fixes 2025-05-05 10:56:32 -05:00
ChrisTitusTech
95d28ee25d Deploying to main from @ ChrisTitusTech/winutil@50071067b7 🚀 2025-05-05 15:34:04 +00:00
CodingWonders
50071067b7
[MicroWin] April Update (#3317)
* Better formatting

A bit cleaner

* Remove unused scripts

This gets rid of file not found errors during setup

* Have a fallback method for Recall fixes

Go back to the delayed disablement procedure if we fail at modifying the manifest

* Ignore Recall disablement when disabled, and more

- If Recall is disabled, don't disable it again. This may be a waste of time
- Disable certain notification sources that I think are quite annoying, like those from Suggested or the Startup App Notification

* Hopefully? Get rid of News and Interests on Win10

Based on PR #3289, add News and Interests removal to MicroWin. Hopefully Windows 10 gets to cooperate this time, compared to last time, where it was quite stubborn.

*This means that people never give up trying to fight against something they don't like*

* Revert "Refactor preferChocolatey system to handle other package managers eas…" (#3323)

This reverts commit 89919494e5030f700664cfe01e9ffe3a49d48cd8.

* Fixed all the things that could possibly break

* Get rid of extra parameter

Package removal fallback fails here. Quite likely a copy from feature disablement

---------

Co-authored-by: Chris Titus <contact@christitus.com>
2025-05-05 10:24:12 -05:00
Mr.k
3b7d707262
Update documentation links to the new website https://winutil.christitus.com/ (#3335) 2025-05-05 10:21:46 -05:00
Martin Wiethan
ea95dac426
Remove OpenOffice entry from applications.json (#3332) 2025-05-05 10:20:53 -05:00
Martin Wiethan
b4d3368680
Refactor Windows Repair (#3312)
* Refactor Invoke-WPFFixesUpdate and replace Invoke-WPFPanelDISM with Invoke-WPFSystemRepair. Streamline Windows Repair

* Refactor Invoke-WPFSystemRepair to improve function naming, scalablility and fix on english os

* Remove debug switches to minimize clutter and shorten the code

* Replace Write-Verbose with Write-Debug
2025-05-05 10:20:20 -05:00
Martin Wiethan
0b5c44cbcf
Optimize Preprocessor by Implementing File Hashing for Modified Files Detection (#3310)
* Modify preprocessor, to only process modified files

* Refactor Invoke-Preprocessing to remove ThrowExceptionOnEmptyFilesList parameter and switch to MD5 hashing

* Remove SkipExcludedFilesValidation parameter and update validation logic for ExcludedFiles
2025-05-05 10:18:29 -05:00
Nilesh
b8b16be24b
Fix: Searchbar not working (#3270) (#3306) 2025-05-05 10:15:51 -05:00
Martin Wiethan
14943e3c55
Refactor Hotkey Handling (#3299)
* Refactor Hotkey Handling to improve readability and fix a bug

* Remove unnecessary $_.Handled Properties
2025-05-05 10:12:57 -05:00
Chris Titus
91365d50b5 quick format update 2025-05-05 10:12:00 -05:00
Martin Wiethan
82b6c268b0
Refactor Startup Ascii Art (#3298)
Co-authored-by: Chris Titus <contact@christitus.com>
2025-05-05 10:07:51 -05:00
Martin Wiethan
d8c007d2db
Remove the need for inline C# to get the window dimensions (#3297) 2025-05-05 10:06:45 -05:00
CodingWonders
48f1c71584
[Tweaks] Remove trailing commas at the end (#3326) 2025-04-16 10:16:27 -05:00
Martin Wiethan
f770642a6a
Fix Gimp Winget Package (#3311) 2025-04-16 10:13:05 -05:00
Chris Titus
963c0a17aa Tidy up preference file changes 2025-04-16 08:56:22 -05:00
Martin Wiethan
20769f66a1
Switch default mode to compact view (#3327) 2025-04-16 08:40:43 -05:00
Chris Titus Tech
86459b7e24 fix alpha in apps 2025-04-14 14:30:09 -05:00
KamaleiZestri
89919494e5
Refactor preferChocolatey system to handle other package managers easier (#3296)
* Easier to add more package managers changes

* style fixes
2025-04-14 13:33:16 -05:00
Chris Titus Tech
5f6bdb2e48 Update tweaks.json 2025-04-14 13:27:02 -05:00
KamaleiZestri
f614eea435
Add "Disable news and interest" tweak (#3289) 2025-04-14 13:22:29 -05:00
Martin Wiethan
82447a1e7b
Remove Balena Etcher due to privacy concerns (#3268) 2025-04-14 13:19:19 -05:00
Chris Titus Tech
51424abfad Update preset.json 2025-04-14 13:08:55 -05:00
Chris Titus Tech
3caa3be9a3 Update tweaks.json 2025-04-14 13:08:01 -05:00
madkarma
7769a328bb
feat: disable explorer automatic folder discovery (#3262)
* feat: add tweak "Disable Explorer automatic folder discovery"

* refactor: add comments

* feat: add undo script

* refactor: add output comment

* fix: use correct registry key
2025-04-14 13:03:00 -05:00
Mr.k
425f11d787
Fix Double Click problem by using UIElement Names instead of Types (#3246)
* Fix Double Click problem by using UIElement Names instead of Types

* Use lower case 'or' to follow project's common conventions
2025-04-14 12:55:52 -05:00
Chris Titus Tech
6df94df594 Delete Invoke-WinUtilInteractiveNerdFontInstall.ps1 2025-04-14 12:49:59 -05:00
MyDrift
29e2c4d197
Action on application right click (#3243)
* implement right click logic

- right click clears selection and only selects right clicked app

* simplify logic
2025-04-14 12:40:20 -05:00
Joshua Taylor Keays
b63a17b7dd
Create Invoke-WinUtilInteractiveNerdFontInstall.ps1 (#3183)
Using this script, we could integrate inside of the XAML, a list of all current nerdfonts, and user can choose which to install.

https://raw.githubusercontent.com/jpawlowski/nerd-fonts-installer-PS/main/Invoke-NerdFontInstaller.ps1

I am not sure how to add it into xaml :  - (
2025-04-14 12:37:00 -05:00
Martin Wiethan
abe059917c
Optimize UI Performance (#3277)
* Optimize UI Load performance

* remove timers

* Formatting

* Remove unused Collapsed Checkbox Style from inputXML.xaml
2025-04-02 15:54:44 -05:00
MyDrift
698f1644c3
[Toggle] Hide Settings Homepage (#3245)
* addHideSettingsToggle

* set OriginalValue & DefaultState
2025-03-19 14:32:16 -05:00
zy
fd03f33c50
Correct description for Prism Launcher (#3256) 2025-03-19 14:07:21 -05:00
Martin Wiethan
8f9e7d1b7c
Correct the Header Font Size (#3257)
* Correct the Header Font Size naming and simplify the creation of the Selected Apps Button

* Adjust HeaderFontSize from 18 to 16 for improved readability
2025-03-19 14:05:55 -05:00
Martin Wiethan
b3dd1a1a50
Add God Mode panel to Legacy Windows Panels (#3264) 2025-03-19 14:00:30 -05:00
Martin Wiethan
4acad32a38
Add Badge to Link to the Documentation at the Top of the Readme (#3265) 2025-03-19 13:59:10 -05:00
Mr.k
0f4fca31b9
[DOCS] Remove old Announcement about not adding any new applications to the app list (#3269)
* Remove old Announcement about not adding any new applications to the app list

* Update '.gitignore' file

The generated 'site' folder, which contains the docs build result by 'mkdocs', in the same folder as 'mkdocs.yml' (i.e. under '.github' folder), so I've temporarily excluded with '.gitignore' file until we've fully migrated the docs site into another repo.
2025-03-19 13:56:00 -05:00
ChrisTitusTech
36c984b66c Deploying to main from @ ChrisTitusTech/winutil@d215d0fc2c 🚀 2025-03-19 15:33:49 +00:00
ChrisTitusTech
d215d0fc2c Deploying to main from @ ChrisTitusTech/winutil@52de4690ab 🚀 2025-03-07 15:32:54 +00:00
Emil Wójcik
52de4690ab
Update start.ps1 (#3223)
- use join method to parse $argList
- use $PSCommandPath instead of $MyInvocation.MyCommand.Path
- use ScriptBlock method to create request for latest winutil.ps1 with join $argList 
- condition for $processCmd because in case when wt.exe is not available, there was double/redundant declaration of shell which lead to code mishmash (incorrect interpretation of quotes from Start-Process ArgumentList parameters 
- changes in quotes and escape characters because command where not interpreted correctly in all possible cases of $powershellCmd and $processCmd
2025-03-05 12:15:13 -06:00
CodingWonders
ef97a8da24
[WinGet] Fix install loop (#3235)
Only this parameter was missing
2025-03-05 12:13:39 -06:00
MyDrift
18a7f17a0b
[APP addition] Zen Browser (#3231)
* add Zen to Browsers for Applications

* remove choco option since it currently needs the --pre flag
2025-03-04 14:31:28 -06:00
Chris Titus
5a8cf5deb6
Removing Github and Nuget method. Revamp of Version check to use DesktopAppInstaller (#3233) 2025-03-04 14:30:54 -06:00
Chris Titus Tech
e4b2a38372 fix a few tweak errors 2025-03-03 14:31:18 -06:00
Chris Titus
94c5d89430
fix winget for good (#3096) 2025-03-03 14:16:53 -06:00
MyDrift
8a0e0c7715
[UI/UX] Refractor Install Tab (#2859)
* initial visual implementation

- remove idiotic border logic from Invoke-WPFUIElements
- add "application" type & style
- add "radiobutton" type & style
- remove prefer choco checkbox (did not modify logic outside of xaml, so i currently get errors due to that)

* add image support via choco db

- add image support via choco db
- backup image should be taken from unigetui db
- backup backup image is some random package one rn

* add compatibility for every app

* performance improvements

- move get logo to runspace (not working rn)
- readd choco checkbox to mute errors

* add border name

* fix scrollviewer & reimplement logo logic into ui elements

* noimage fix

* add notes

* cleanup & remove nav from search effects

* add button action

* rename buttons

* add sort by options

* move scrollviewer & app buttons into uielements logic

* format logic for app action buttons

* fix app action button logic & move get & clear to sidepanel

* change category of new buttons

* add virtualisation & layouting fixes

- commented out prefer choco logic
- add virtualisation
- layouting improvements

* fix radiobuttons

* LETS GOOO  (#12)

* Add Selected Apps Label, Reshuffel the nesting of the checkbox and the label to be able to reference the name from the actual checkbox

* Add visual selection and allow click on the whole app section

* Fix Theme definition to work with theme change

* Fix Highlight on if label or icon is clicked

* change applications.json to powershell object list and refactor UI Creation logic

* Optimization and Add Collapsable Categories

* Add Button functionality for install, uninstall, info, install selected, uninstall selected, clear and implement search

* Rest application.json to Main

* Reset Compile to main

* Pretty much revamp_apps but without changes to applications.json

* Small fixes

* Add Get-Installed Loading Indicator + small fixes

* Re-Add Choco Preference

* Remove Logic from Invoke-WPFUIElements that is Moved to Invoke-WPFUIApps

* Remove Alphabetical List, Sort Apps inside Category Alphabetically

* Small fixes to the Get-Installed function and formatting stuff

* Style for Hidden Checkbox but visible Content

* Hotfix for Category Expansion during search

* Replace Category Label with ToggleButton, Fix Search Bugs

* First Try at implementing a Compact Mode for the App page

* Fix Whitespace when using Search

* Keep the search status when switching between compact and full view

* Fix weird buggy behaviour in regards to switching the Display Mode and using Show-SelectedOnly

* Improve Togglebutton

- add initial implementation of togglebutton style
- add togglebuttons to appnavigation.json
- refractor UI element creation for Togglebutton
- commit preprocessing changes

* Togglebutton fixes

- move dot to the right in style
- cleanup code
- fix arrangement of content

* Add logic to the new ToggleButtons in the sidebar of the install tab and remove old buttons

* reorder buttons & fix Togglebutton toggling if action not possible

- reorder getinstalled and clearselection
- set togglebutton back if no app is selected

* Slight modificatoin to togglebutton style & fix sidebar width

* Add hover effect for the app tiles

* ToggleButtonStyle animation

- add hover animation to white dot
- remove IsPressed trigger
- improve some comments

* disable show selected filter on clear selection

* Add a Popup Dropdown for Selected Apps with the ability to deselect them

* Split up the functions to seperate files like the rest of the repo

* Fix Bug where Scrollviewer dosnt work

* disable autofallback checkbox

* run preprocessing

* remove installation scope

- remove all 3 radiobuttons from appnavigation.json

* remove scrollviewer from WPFUIElements

* toggle showselected on GetInstalled

* remove unused autofallback

---------

Co-authored-by: Martin Wiethan <47688561+Marterich@users.noreply.github.com>
Co-authored-by: Chris Titus <contact@christitus.com>
2025-03-01 13:50:12 -06:00
bess
1ae16f6f38
Update dev docs table of contents links (#3181) 2025-02-28 10:59:42 -06:00
matthewkasiski
6038556e64
Feature/disable wpbt execution (#3188)
* add IDE

* add tweak
2025-02-28 10:56:45 -06:00
Kurt217432975
329a3de9a6
Fix winget command and update FxSound description (#3207) 2025-02-28 10:55:19 -06:00
ChrisTitusTech
f6e5d0e053 Deploying to main from @ ChrisTitusTech/winutil@364076c25e 🚀 2025-02-27 15:33:22 +00:00
MyDrift
364076c25e
[GHTemplates] Use new preview of Issue templates (#3202)
* use new issue preview

- convert existing issue templates to new template style
- move issue validation to start
- add important section at start
- improve checkbox UX
- improve wording a bit
- add config to link discord & remove blank issues

* remove description
2025-02-25 11:29:18 -06:00
ChrisTitusTech
a051e64a91 Deploying to main from @ ChrisTitusTech/winutil@dccda61ab4 🚀 2025-02-20 15:33:18 +00:00
ChrisTitusTech
dccda61ab4 Deploying to main from @ ChrisTitusTech/winutil@048f580a56 🚀 2025-02-06 15:32:52 +00:00
ChrisTitusTech
048f580a56 Deploying to main from @ ChrisTitusTech/winutil@bfb83ced79 🚀 2025-02-05 15:33:03 +00:00
ChrisTitusTech
bfb83ced79 Deploying to main from @ ChrisTitusTech/winutil@e2b37445f6 🚀 2025-02-01 15:31:03 +00:00
ChrisTitusTech
e2b37445f6 Deploying to main from @ ChrisTitusTech/winutil@c2fb98b0dc 🚀 2025-01-31 15:30:57 +00:00
ChrisTitusTech
c2fb98b0dc Deploying to main from @ ChrisTitusTech/winutil@cf8787a700 🚀 2025-01-30 15:32:01 +00:00
Matt Creekmore
cf8787a700
Fixed impartial nerd font uninstallation (#3171)
* fix: nerdfonts uninstall now deletes corresponding registry keys

* change ErrorAction to SilentlyContinue

* fix some code styling

* removed unused files/docs as per Cryostrixx advice

* restored portions of the feature.json
2025-01-28 13:59:00 -06:00
YusufKhalifadev
53b723fa11
update application.json (#3166) 2025-01-28 13:50:31 -06:00
CodingWonders
32cb94f392
[MicroWin] Fixed divide by zero error for fallback (#3174)
<Insert the never mind - misspelled a variable meme here>
2025-01-28 11:03:35 -06:00
ChrisTitusTech
5550e40270 Deploying to main from @ ChrisTitusTech/winutil@bcecf67c7d 🚀 2025-01-28 15:32:37 +00:00
ChrisTitusTech
bcecf67c7d Deploying to main from @ ChrisTitusTech/winutil@3b50ff813c 🚀 2025-01-27 15:30:51 +00:00
ChrisTitusTech
3b50ff813c Deploying to main from @ ChrisTitusTech/winutil@eba5b35978 🚀 2025-01-26 15:30:58 +00:00
ChrisTitusTech
eba5b35978 Deploying to main from @ ChrisTitusTech/winutil@254738a420 🚀 2025-01-20 15:32:07 +00:00
bvd0
254738a420
Use HTTPS instead of HTTP for URLs where supported. (#3161) 2025-01-17 08:42:42 -06:00
CodingWonders
bcc801683d
[Tweaks] Disable output for DISM for the Recall tweak (#3154)
* Fixed lock caused by expected input for DISM

This is the main event

* Miscellaneous file

Don't know why this file was modified by the compile preprocessor
2025-01-17 08:40:04 -06:00
ChrisTitusTech
72c23823b2 Deploying to main from @ ChrisTitusTech/winutil@4e1ce7e417 🚀 2025-01-11 15:30:55 +00:00
dependabot[bot]
4e1ce7e417
Bump jinja2 from 3.1.4 to 3.1.5 in /.github (#3126)
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.4...3.1.5)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 13:42:46 -06:00
maxi322
1dd0367417
Add timestamp server to code signature (#3139)
Co-authored-by: maxi322 <maxi322@users.noreply.github.com>
2025-01-10 13:41:54 -06:00
MyDrift
201f24c76e
[FEAT] Remove Start Menu Recommendations / Fix GetToggle Logic (#3089)
* add WPFToggleRemoveRecommended

- add WPFToggleStartMenuRecommendations
- add reg entrys to modify for toggle
- add non working link bc devdocs are broken in general

* add iseducationenvironment notice

* improve handling if entry does not exist

- add DefaultState property
- add handler for DefaultState in Get-WinUtilToggleStatus

* remove helper console logs

* fix search defaultstate

* added missing default states
2025-01-10 13:41:26 -06:00
CodingWonders
9183e92692
[MicroWin] Preparation for 2025 (#3066)
* Set Boot Manager entry timeout to 0

Fixes #2562

* Exclude Windows Hello stuff from package removal

* Obscure passwords with Base64 and fix indentation

Fixes #3064

* Fix name of excluded package

* Update comment

It reflects my feelings towards Microsoft when it comes to security a lot better

* Remove jargon of scratch directory options

* Package exclusion improvements

- Removed AppX packages from OS package exclusion list
- Added exclusion of PowerShell ISE (source: Discord server - yes, some people still use the PowerShell ISE)

* Exclude Windows Photo Viewer from dir removal

* Improve copy operation to Ventoy drives

This change may fix the issues where there's a conflict between both Ventoy's and MicroWin's unattended answer files, causing target images to stop working as expected during OOBE

* Add VirtIO functionality and more enhancements

- Added the ability to grab VirtIO Guest Tools
- Modified the description of the Copy ISO files function because it basically had nonsense

* Fix typo (#3104)

* Access specific property of ISO image object

Only show the ISO path. No one is interested in the storage type

* Add detections for expedited app removal

They only affect 24H2 and newer. Earlier releases don't have these expedited apps

* Update message

* Add VirtIO instructions to MicroWin page

* Add DISM command fallback

This fallback is triggered if an exception occurs while getting information with the cmdlets (I couldn't test this on my host as everything magically works now - sometimes it threw the Class not registered error)

* Exclude OpenSSH from package removal

Some people need this to avoid installing third-party programs like PuTTY

* Fixed some more indentation
2025-01-10 13:40:25 -06:00
DeveloperDurp
fa9dbcace4
Move Installer for OpenSSH to a runspace (#3117) 2025-01-10 13:39:21 -06:00
ChrisTitusTech
02f0f85c25 Deploying to main from @ ChrisTitusTech/winutil@83ae0579ba 🚀 2025-01-09 15:32:34 +00:00
ChrisTitusTech
83ae0579ba Deploying to main from @ ChrisTitusTech/winutil@5ebcacf404 🚀 2025-01-06 15:31:53 +00:00
ChrisTitusTech
5ebcacf404 Deploying to main from @ ChrisTitusTech/winutil@28bea518f0 🚀 2024-12-31 15:31:36 +00:00
DeveloperDurp
28bea518f0
Add exception catch for Unauthorized Access (#3114) 2024-12-28 15:38:40 -06:00
ChrisTitusTech
61c2e39ddb Deploying to main from @ ChrisTitusTech/winutil@0dfa9617fc 🚀 2024-12-27 15:31:18 +00:00
ChrisTitusTech
0dfa9617fc Deploying to main from @ ChrisTitusTech/winutil@2ce4f54b80 🚀 2024-12-26 15:31:44 +00:00
ChrisTitusTech
2ce4f54b80 Deploying to main from @ ChrisTitusTech/winutil@a05556a896 🚀 2024-12-17 15:34:08 +00:00
ChrisTitusTech
a05556a896 Deploying to main from @ ChrisTitusTech/winutil@985d415db1 🚀 2024-12-16 15:34:05 +00:00
ChrisTitusTech
985d415db1 Deploying to main from @ ChrisTitusTech/winutil@f4d4bdad3c 🚀 2024-12-12 15:34:22 +00:00
Chris Titus Tech
f4d4bdad3c move prefer ipv4 to advanced 2024-12-09 12:08:27 -06:00
Chris Titus Tech
9d47514190 move prefer ipv4 to advanced 2024-12-09 12:07:56 -06:00
ChrisTitusTech
4fc34e44b3 Deploying to main from @ ChrisTitusTech/winutil@c33946bde2 🚀 2024-12-09 15:34:30 +00:00
Chris Titus
c33946bde2 tweaks remove all 2024-12-09 00:21:45 -06:00
ChrisTitusTech
4466720493 Deploying to main from @ ChrisTitusTech/winutil@1d0e3bfd5c 🚀 2024-12-08 15:33:04 +00:00
MyDrift
1d0e3bfd5c
[FEAT] TweakToggles logik overhaul (#3014)
* move logic to json template

- remove Invoke-WPFToggle.ps1
- generalize Get-WinUtilToggleStatus
- add bingsearch reg key for testing
- use Invoke-WinUtilTweaks for actions
- replace Add-Click with checked & unchecked to make undo work

* add reg params for toggles into tweaks.json

- add all reg keys to tweaks.json into existing toggle entry
- remove unneeded scripts

* fix HKU

- load HKU if needed (for tweaks & GetToggleStatus)
- remove unneeded Invoke-WinUtilNumLock
- has loaded HKU does not load/not stay loaded

* add a lot of error handling

* Bugfix: New-PSDrive seems to return the "hku" itself so weirdly gets prepended to the return value so the result becomes ("hku", $false). In powershell pretty much every variable that exists is interpreted as $true so the toggle for numlock got incorrectly checked

* globally fix HKU error & minimize console feedback

- fix HKU issue globally
- remove some console logs, change some others to write-debug

* update Explorerrefresh

- change Invoke-WinUtilExplorerRefresh to handle refresh and restart
- add restart logic to window snapping Flyout & Suggestions
- rename Invoke-WinUtilExplorerRefresh to Invoke-WinUtilExplorerUpdate

* add explorer restart where needed to take effect

add explorer restart logic for hidden files + Fileextension toggles

* fix missing theme change logic in darkmode toggle

* fix window snapping

- fix issue defining WindowArrangementActive as dword instead of string

* fix bing search

- switch bing search enabled/disabled values

* add a little bit of error handling

- add error handling for Get-WinUtilToggleStatus

---------

Co-authored-by: Marterich <47688561+Marterich@users.noreply.github.com>
2024-12-05 21:24:36 -06:00
Mr.k
83450aef7b
[UI/UX] Update the look & feel of the GUI (#2884)
* Add @CodingWonders to the About page for his contribution and determination to make WinUtil (and MicroWin) the best software it can be!

* Remove the 'LogoSize' Parameter for About page - Make every sponsor in the sponsors list a link to ChrisTitusTech's Sponsors web link

* Change Theme Option name from 'ConfigTabButtonFontSize' to 'ConfigUpdateButtonFontSize' - Lower its value from 16 to 14

* Change Theme Option name from 'FontSizeHeading' to 'HeadingFontSize' for consistency

* Update 'LinkForegroundColor' for Light Theme to be lighter which'll make link hover color more noticeable

* Update 'Show-CustomDialog' Private Function

- Made a lot of theming/styling choices for Custom Dialogs exposed as parameters.
- Update the documentation for these new parameters in 'Show-CustomDialog' Function.
- Add a Link Hover Effect using 'Add_EVENT' methods (This can be tweaks/tuned-down if needed).
- Made use of 'Title' Parameter for 'Show-CustomDialog' Function inside 'scripts/main.ps1' script, to change Dialog Window Title.
- Now you can change the Logo Size of WinUtil through the 'LogoSize' Theming Option (the option was there, but not used in implementation).

* Preprocessing result

* Fix Settings Popup not closing after losing focus - Add trivial null checks for better debugging of UI code

* Remove unnecessary whitespace indentation in 'main.ps1' script

* Add a new 'Invoke-WPFPopup' Function to Better Handle Showing/Hiding/Toggling of Popups

* Improve 'Invoke-WPFPopup' by @MyDrift-user

Thanks for the improvements :)

---------

Co-authored-by: MyDrift <personal@mdiana.ch>
Co-authored-by: Chris Titus <contact@christitus.com>
2024-12-05 21:22:33 -06:00
Ed Blankenship
e2ce998426
Adding .NET 9.0 runtime to applications config (#3041) 2024-12-05 21:19:49 -06:00
Chris Titus
cf7f161a06
Fix language and Logic to Updates (#3087) 2024-12-05 21:18:46 -06:00
Chris Titus
d6c1fbe4a2
Change install to winget, nuget, msstore (#3088) 2024-12-05 21:18:28 -06:00
MyDrift
0779dd9096
[CI/CD] Update Issue Commands (#3052)
* update issue commands workflow

- remove existing workflow
- copy linutil's workflow into winutil
- add @CodingWonders as allowed user

* remove op from rights

- op could spam and create a ton of new labels, or spam workflow to close, reopen and so one
2024-12-01 14:30:10 -06:00
MyDrift
d48f212be4
[Issue Template] Add Validation (#3067)
* issue template update

- add  issue validation inspired by https://github.com/ChrisTitusTech/linutil/pull/459
- standardize capitalisation of characters in titles
- update feature request to use headers instead of bold text for titles

* use "I checked" for Issue validation
2024-12-01 14:29:04 -06:00
MyDrift
9c52f01204
remove redundant & outdated info in workflow (#3076)
- stale + closing message contains outdated time
- remove mention of how long it has been to simplify it.
2024-12-01 14:28:37 -06:00
Chris Titus Tech
d49b21f881 Fix onedrive remove for msapps 2024-11-25 10:07:43 -06:00
ChrisTitusTech
39ee4d53c0 Deploying to main from @ ChrisTitusTech/winutil@6e708bfe95 🚀 2024-11-16 15:32:42 +00:00
101 changed files with 3290 additions and 3101 deletions

View File

@ -1,26 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: 'bug'
assignees: ''
---
## Describe the bug
<!-- A clear and concise description of what the bug is. -->
## To Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
## Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
## Screenshots
<!-- If applicable, add screenshots to help explain your problem. -->
## Additional context
<!-- Add any other context about the problem here. -->

62
.github/ISSUE_TEMPLATE/bug_report.yaml vendored Normal file
View File

@ -0,0 +1,62 @@
name: "Bug report"
description: "Report a bug to help us identify and fix issues in the project."
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
# 🐞 **Issue Report**
Thank you for taking the time to report an issue! Please provide as much detail as possible to help us address the problem efficiently.
## ⚠️ **IMPORTANT**
- 🛠️ **Supported environments only:** We only support Windows 11. Custom ISOs that are not made using Microwin are not supported.
- 💡 For general questions, use the [Discussions section](https://github.com/Christitustech/winutil/discussions) or join our Community-driven [Discord Server](https://discord.gg/RUbZUZyByQ).
- type: checkboxes
attributes:
label: ⚙️ Issue Checklist
options:
- label: I have read the guidelines.
- label: I checked for duplicate issues.
- label: I searched for existing discussions.
- label: I checked for an existing pull request that addresses this issue.
validations:
required: true
- type: input
id: affected_part
attributes:
label: 📜 What part of Winutil are you having issues with?
placeholder: "e.g., Microwin, Tweaks, etc."
validations:
required: true
- type: textarea
id: issue_description
attributes:
label: 📝 Provide a clear and concise description of the issue.
validations:
required: true
- type: textarea
id: steps_to_reproduce
attributes:
label: 🔄 Steps to reproduce the issue.
placeholder: "e.g., Step 1: ..., Step 2: ..."
validations:
required: true
- type: textarea
id: error_output
attributes:
label: ❌ Paste the full error output (if available).
placeholder: "Include any relevant logs or error messages."
- type: textarea
id: additional_context
attributes:
label: 🖼️ Additional context.
placeholder: "Include screenshots, code blocks (use triple backticks ```), or any other relevant information."
validations:
required: false

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 💻 Community Discord
url: https://discord.gg/RUbZUZyByQ
about: Join our Community Discord server to chat with other users in the Winutil community.

View File

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'enhancement'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->

View File

@ -0,0 +1,57 @@
name: "Feature request"
description: "Suggest a new feature or improvement for the project."
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
# ✨ **Feature request**
Thank you for taking the time to suggest a feature! Please provide as much detail as possible to help us understand and evaluate your request.
## ⚠️ **IMPORTANT**
- 🛠️ **Supported environments only:** We only support Windows 11.
- 💡 For general questions, use the [Discussions section](https://github.com/Christitustech/winutil/discussions) or join our Community-driven [Discord Server](https://discord.gg/RUbZUZyByQ).
- type: checkboxes
attributes:
label: ⚙️ Issue Checklist
options:
- label: I have read the guidelines.
- label: I checked for duplicate issues.
- label: I searched for existing discussions.
- label: I checked for an existing pull request that addresses this request.
validations:
required: true
- type: textarea
id: problem_statement
attributes:
label: ❓ Is your feature request related to a problem?
placeholder: "Provide a clear and concise description of the issue you're facing. Example: 'I'm always frustrated when [...]'"
validations:
required: false
- type: textarea
id: proposed_solution
attributes:
label: 💡 Describe the solution you'd like
placeholder: "Provide a clear and concise description of what you want to happen."
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: 🔄 Describe alternatives you've considered
placeholder: "Provide details on any alternative solutions or features you've thought about."
validations:
required: false
- type: textarea
id: additional_context
attributes:
label: 🖼️ Additional context
placeholder: "Include screenshots, code blocks (use triple backticks ```), or any other relevant information."
validations:
required: false

View File

@ -15,7 +15,7 @@ gitdb==4.0.11
GitPython==3.1.43
htmlmin2==0.1.13
idna==3.7
Jinja2==3.1.4
Jinja2==3.1.5
jsmin==3.0.1
Markdown==3.6
MarkupSafe==2.1.5

View File

@ -28,8 +28,8 @@ jobs:
days-before-pr-stale: -1
days-before-pr-close: -1
# Sends a message for both the Stale and Close events of an issue.
stale-issue-message: "This issue was marked as stale because it has been inactive for 7 days"
close-issue-message: "This issue was closed because it has been inactive for 7 days since it was marked as stale"
stale-issue-message: "This issue was marked as stale due to inactivity."
close-issue-message: "This issue was closed after remaining stale without updates."
# Increase this value if the project receives a lot of
# PRs (yes.. apparently they're processed no matter what) & Issues.
# Default value for it (according to the docs) is 30

View File

@ -1,11 +1,11 @@
name: Close issue on /close
name: Issue slash commands
on:
issue_comment:
types: [created, edited]
jobs:
closeIssueOnClose:
issueCommands:
# Skip this job if the comment was created/edited on a PR
if: ${{ !github.event.issue.pull_request }}
runs-on: ubuntu-latest
@ -17,6 +17,30 @@ jobs:
steps:
- run: echo "command=false" >> $GITHUB_ENV
- name: Check for /label command
id: check_label_command
run: |
if [[ "${{ contains(github.event.comment.body, '/label') }}" == "true" ]]; then
echo "command=true" >> $GITHUB_ENV
LABEL_NAME=$(echo "${{ github.event.comment.body }}" | awk -F"/label" '/\/label/ { match($2, /'\''([^'\'']*)'\''/, arr); if (arr[1] != "") print arr[1] }')
echo "label_command=true" >> $GITHUB_ENV
echo "label_name=${LABEL_NAME}" >> $GITHUB_ENV
else
echo "label_command=false" >> $GITHUB_ENV
fi
- name: Check for /unlabel command
id: check_unlabel_command
run: |
if [[ "${{ contains(github.event.comment.body, '/unlabel') }}" == "true" ]]; then
echo "command=true" >> $GITHUB_ENV
UNLABEL_NAME=$(echo "${{ github.event.comment.body }}" | awk -F"/unlabel" '/\/unlabel/ { match($2, /'\''([^'\'']*)'\''/, arr); if (arr[1] != "") print arr[1] }')
echo "unlabel_command=true" >> $GITHUB_ENV
echo "unlabel_name=${UNLABEL_NAME}" >> $GITHUB_ENV
else
echo "unlabel_command=false" >> $GITHUB_ENV
fi
- name: Check for /close command
id: check_close_command
run: |
@ -43,15 +67,15 @@ jobs:
id: check_user
if: env.command == 'true'
run: |
ALLOWED_USERS=("ChrisTitusTech" "og-mrk" "Marterich" "MyDrift-user" "Real-MullaC")
ALLOWED_USERS=("ChrisTitusTech" "og-mrk" "Marterich" "MyDrift-user" "Real-MullaC" "CodingWonders")
if [[ " ${ALLOWED_USERS[@]} " =~ " ${{ github.event.comment.user.login }} " ]]; then
echo "user=true" >> $GITHUB_ENV
else
echo "user=false" >> $GITHUB_ENV
exit 0
fi
- name: Close issue if conditions are met
if: env.close_command == 'true' && env.user == 'true'
- name: Close issue
if: env.close_command == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
@ -63,11 +87,29 @@ jobs:
gh issue close $ISSUE_NUMBER --repo ${{ github.repository }}
fi
- name: Reopen issue if conditions are met
if: env.reopen_command == 'true' && env.user == 'true'
- name: Reopen issue
if: env.reopen_command == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
run: |
echo Reopening the issue...
gh issue reopen $ISSUE_NUMBER --repo ${{ github.repository }}
- name: Label issue
if: env.label_command == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
run: |
echo Labeling the issue...
gh issue edit $ISSUE_NUMBER --repo ${{ github.repository }} --add-label "${{ env.label_name }}"
- name: Remove labels
if: env.unlabel_command == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
run: |
echo Unlabeling the issue...
gh issue edit $ISSUE_NUMBER --repo ${{ github.repository }} --remove-label "${{ env.unlabel_name }}"

View File

@ -49,31 +49,6 @@ jobs:
}
shell: pwsh
- name: Create and import code signing certificate
shell: pwsh
run: |
[System.IO.File]::WriteAllBytes("$env:USERPROFILE\code-signing-cert.pfx", [System.Convert]::FromBase64String("$env:CERTIFICATE_BASE64"))
Import-PfxCertificate -FilePath "$env:USERPROFILE\code-signing-cert.pfx" -CertStoreLocation Cert:\CurrentUser\My
- name: Code sign winutil.ps1
shell: pwsh
run: |
$cert = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
if ($null -eq $cert) { throw "Code signing certificate not found" }
Set-AuthenticodeSignature -FilePath ./winutil.ps1 -Certificate $cert
- name: Verify code signature
shell: pwsh
run: |
$signature = Get-AuthenticodeSignature -FilePath ./winutil.ps1
if ($signature.Status -ne 'Valid') { throw "Code signing failed" }
- name: Upload winutil.ps1 as artifact
uses: actions/upload-artifact@v4
with:
name: winutil
path: ./winutil.ps1
- name: Generate Release Notes
id: generate_notes
uses: release-drafter/release-drafter@v6

7
.gitignore vendored
View File

@ -2,6 +2,7 @@
# Configuration folder
.vscode/
.idea/
### Visual Studio ###
@ -10,6 +11,9 @@
winutil.pdb
### Preprocessor Hashes ###
.preprocessor_hashes.json
### Windows ###
# Folder config file
@ -46,4 +50,7 @@ True
test.ps1
winutil.ps1
# temporary excludes for docs
.github/site/
binary/

View File

@ -1,7 +1,6 @@
param (
[switch]$Debug,
[switch]$Run,
[switch]$SkipPreprocessing,
[string]$Arguments
)
@ -45,17 +44,16 @@ $header = @"
################################################################################################################
"@
if (-NOT $SkipPreprocessing) {
Update-Progress "Pre-req: Running Preprocessor..." 0
# Dot source the 'Invoke-Preprocessing' Function from 'tools/Invoke-Preprocessing.ps1' Script
$preprocessingFilePath = ".\tools\Invoke-Preprocessing.ps1"
. $preprocessingFilePath
$excludedFiles = @('.\.git\', '.\.gitignore', '.\.gitattributes', '.\.github\CODEOWNERS', '.\LICENSE', "$preprocessingFilePath", '*.png', '*.exe')
$excludedFiles = @('.\.git\', '.\.gitignore', '.\.gitattributes', '.\.github\CODEOWNERS', '.\LICENSE', "$preprocessingFilePath", '*.png', '*.exe','.\.preprocessor_hashes.json')
$msg = "Pre-req: Code Formatting"
Invoke-Preprocessing -WorkingDir "$workingdir" -ExcludedFiles $excludedFiles -ProgressStatusMessage $msg -ThrowExceptionOnEmptyFilesList
}
Invoke-Preprocessing -WorkingDir "$workingdir" -ExcludedFiles $excludedFiles -ProgressStatusMessage $msg
# Create the script in memory.
Update-Progress "Pre-req: Allocating Memory" 0

View File

@ -3,6 +3,7 @@
[![Version](https://img.shields.io/github/v/release/ChrisTitusTech/winutil?color=%230567ff&label=Latest%20Release&style=for-the-badge)](https://github.com/ChrisTitusTech/winutil/releases/latest)
![GitHub Downloads (specific asset, all releases)](https://img.shields.io/github/downloads/ChrisTitusTech/winutil/winutil.ps1?label=Total%20Downloads&style=for-the-badge)
[![](https://dcbadge.limes.pink/api/server/https://discord.gg/RUbZUZyByQ?theme=default-inverted&style=for-the-badge)](https://discord.gg/RUbZUZyByQ)
[![Static Badge](https://img.shields.io/badge/Documentation-_?style=for-the-badge&logo=bookstack&color=grey)](https://winutil.christitus.com/)
This utility is a compilation of Windows tasks I perform on each Windows system I use. It is meant to streamline *installs*, debloat with *tweaks*, troubleshoot with *config*, and fix Windows *updates*. I am extremely picky about any contributions to keep this project clean and efficient.
@ -34,11 +35,11 @@ irm "https://christitus.com/win" | iex
irm "https://christitus.com/windev" | iex
```
If you have Issues, refer to [Known Issues](https://christitustech.github.io/winutil/KnownIssues/)
If you have Issues, refer to [Known Issues](https://winutil.christitus.com/knownissues/)
## 🎓 Documentation
### [WinUtil Official Documentation](https://christitustech.github.io/winutil/)
### [WinUtil Official Documentation](https://winutil.christitus.com/)
### [YouTube Tutorial](https://www.youtube.com/watch?v=6UQZ5oQg8XA)
@ -52,7 +53,7 @@ If you have Issues, refer to [Known Issues](https://christitustech.github.io/win
These are the sponsors that help keep this project alive with monthly contributions.
<!-- sponsors --><a href="https://github.com/ysaito8015"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;3502978?u&#x3D;ca98bf67f04d67080df0feeaa6f007fad51d273f&amp;v&#x3D;4" width="60px" alt="Yusuke Saito" /></a><a href="https://github.com/TriHydera"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;39857764?u&#x3D;5dbda638f45530582eee1703b4473f2a5e229e28&amp;v&#x3D;4" width="60px" alt="TriHydera" /></a><a href="https://github.com/jozozovko"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;3272468?u&#x3D;4391ed4655e4fd8b56e23b4169e44e2ac9b6cd97&amp;v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/DelDongo"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;127976398?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/markamos"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;9561861?u&#x3D;3cca179dcff0413538591e57a3abea116d65ce56&amp;v&#x3D;4" width="60px" alt="Mark Amos" /></a><a href="https://github.com/dwelfusius"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;54533224?u&#x3D;a49ea000a8f52adb31382ea69a1a7501b27fefdd&amp;v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/mews-se"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;58894405?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/jdiegmueller"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;18660571?u&#x3D;601d0a23040a271c86b5d40339f899a6dbf27086&amp;v&#x3D;4" width="60px" alt="Jason A. Diegmueller" /></a><a href="https://github.com/AlanTristar"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;105566568?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/zepled112"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;65176625?v&#x3D;4" width="60px" alt="wyatt" /></a><a href="https://github.com/altugtekiner"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;105917451?u&#x3D;ee73ff639c7bd9feb4708ab4ba7b14eff80196f7&amp;v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/robertsandrock"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;12015331?v&#x3D;4" width="60px" alt="RMS" /></a><a href="https://github.com/mmomega"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;71956566?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/KenichiQaz"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;31177857?u&#x3D;efdbae734a4c60a7bb95df4659d0535e60a6fd57&amp;v&#x3D;4" width="60px" alt="Stefan" /></a><a href="https://github.com/paulsheets"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;45240946?u&#x3D;d4db66f8e8d7a2606fe7a5521daf48ca9f097105&amp;v&#x3D;4" width="60px" alt="Paul" /></a><a href="https://github.com/djones369"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;4107092?v&#x3D;4" width="60px" alt="Dave Jones" /></a><a href="https://github.com/anthonymendez"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;19240897?u&#x3D;f82b4be098cac65c8421421b70ebd2d1da85c67e&amp;v&#x3D;4" width="60px" alt="Anthony Mendez" /></a><a href="https://github.com/claudemods"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;73653396?u&#x3D;d64c656fb8db24ef56bb000197532df9b618d06c&amp;v&#x3D;4" width="60px" alt="Claudemods" /></a><a href="https://github.com/FatBastard0"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;173957728?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/Ascent7910"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;118260621?v&#x3D;4" width="60px" alt="Max" /></a><a href="https://github.com/DursleyGuy"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;140165544?v&#x3D;4" width="60px" alt="DursleyGuy" /></a><a href="https://github.com/YamiSandman616"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;183505690?u&#x3D;c3bd20157058b6215e28f7568d4f8c4fbbe92838&amp;v&#x3D;4" width="60px" alt="Sandman616" /></a><a href="https://github.com/realmuddy"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;30978236?v&#x3D;4" width="60px" alt="Phillip Waters" /></a><a href="https://github.com/Tariq-Al-Zahrani"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;187593049?v&#x3D;4" width="60px" alt="" /></a><!-- sponsors -->
<!-- sponsors --><a href="https://github.com/TriHydera"><img src="https:&#x2F;&#x2F;github.com&#x2F;TriHydera.png" width="60px" alt="User avatar: TriHydera" /></a><a href="https://github.com/DelDongo"><img src="https:&#x2F;&#x2F;github.com&#x2F;DelDongo.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/markamos"><img src="https:&#x2F;&#x2F;github.com&#x2F;markamos.png" width="60px" alt="User avatar: Mark Amos" /></a><a href="https://github.com/dwelfusius"><img src="https:&#x2F;&#x2F;github.com&#x2F;dwelfusius.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/mews-se"><img src="https:&#x2F;&#x2F;github.com&#x2F;mews-se.png" width="60px" alt="User avatar: Martin Stockzell" /></a><a href="https://github.com/jdiegmueller"><img src="https:&#x2F;&#x2F;github.com&#x2F;jdiegmueller.png" width="60px" alt="User avatar: Jason A. Diegmueller" /></a><a href="https://github.com/robertsandrock"><img src="https:&#x2F;&#x2F;github.com&#x2F;robertsandrock.png" width="60px" alt="User avatar: RMS" /></a><a href="https://github.com/KenichiQaz"><img src="https:&#x2F;&#x2F;github.com&#x2F;KenichiQaz.png" width="60px" alt="User avatar: Stefan" /></a><a href="https://github.com/paulsheets"><img src="https:&#x2F;&#x2F;github.com&#x2F;paulsheets.png" width="60px" alt="User avatar: Paul" /></a><a href="https://github.com/djones369"><img src="https:&#x2F;&#x2F;github.com&#x2F;djones369.png" width="60px" alt="User avatar: Dave J. - WhamGeek" /></a><a href="https://github.com/anthonymendez"><img src="https:&#x2F;&#x2F;github.com&#x2F;anthonymendez.png" width="60px" alt="User avatar: Anthony Mendez" /></a><a href="https://github.com/FatBastard0"><img src="https:&#x2F;&#x2F;github.com&#x2F;FatBastard0.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/DursleyGuy"><img src="https:&#x2F;&#x2F;github.com&#x2F;DursleyGuy.png" width="60px" alt="User avatar: DursleyGuy" /></a><a href="https://github.com/realmuddy"><img src="https:&#x2F;&#x2F;github.com&#x2F;realmuddy.png" width="60px" alt="User avatar: Phillip Waters" /></a><a href="https://github.com/quaszi"><img src="https:&#x2F;&#x2F;github.com&#x2F;quaszi.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/DwayneTheRockLobster1"><img src="https:&#x2F;&#x2F;github.com&#x2F;DwayneTheRockLobster1.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/KieraKujisawa"><img src="https:&#x2F;&#x2F;github.com&#x2F;KieraKujisawa.png" width="60px" alt="User avatar: Kiera Meredith" /></a><a href="https://github.com/craigccfl"><img src="https:&#x2F;&#x2F;github.com&#x2F;craigccfl.png" width="60px" alt="User avatar: CraigW" /></a><a href="https://github.com/RoelCrabbe"><img src="https:&#x2F;&#x2F;github.com&#x2F;RoelCrabbe.png" width="60px" alt="User avatar: Roel Crabbé" /></a><a href="https://github.com/Data-Syd"><img src="https:&#x2F;&#x2F;github.com&#x2F;Data-Syd.png" width="60px" alt="User avatar: Data Syd" /></a><!-- sponsors -->
## 🏅 Thanks to all Contributors
Thanks a lot for spending your time helping Winutil grow. Thanks a lot! Keep rocking 🍻.

16
Test-WingetInstall.ps1 Normal file
View File

@ -0,0 +1,16 @@
# Import the function (adjust the path according to your setup)
. "./functions/private/Install-WinUtilWinget.ps1"
. "./functions/private/Test-WinUtilPackageManager.ps1"
# Set up Information stream to be visible
$InformationPreference = "Continue"
Write-Host "Starting Winget installation test..." -ForegroundColor Cyan
try {
Install-WinUtilWinget
} catch {
Write-Host "Error occurred during testing: $($_.Exception.Message)" -ForegroundColor Red
Write-Host "Stack Trace:" -ForegroundColor Red
$_.ScriptStackTrace
}

View File

@ -349,7 +349,7 @@
"content": "Display Driver Uninstaller",
"description": "Display Driver Uninstaller (DDU) is a tool for completely uninstalling graphics drivers from NVIDIA, AMD, and Intel. It is useful for troubleshooting graphics driver-related issues.",
"link": "https://www.wagnardsoft.com/display-driver-uninstaller-DDU-",
"winget": "ddu"
"winget": "Wagnardsoft.DisplayDriverUninstaller"
},
"deluge": {
"category": "Utilities",
@ -439,6 +439,14 @@
"link": "https://dotnet.microsoft.com/download/dotnet/8.0",
"winget": "Microsoft.DotNet.DesktopRuntime.8"
},
"dotnet9": {
"category": "Microsoft Tools",
"choco": "dotnet-9.0-runtime",
"content": ".NET Desktop Runtime 9",
"description": ".NET Desktop Runtime 9 is a runtime environment required for running applications developed with .NET 9.",
"link": "https://dotnet.microsoft.com/download/dotnet/9.0",
"winget": "Microsoft.DotNet.DesktopRuntime.9"
},
"dmt": {
"winget": "GNE.DualMonitorTools",
"choco": "dual-monitor-tools",
@ -519,14 +527,6 @@
"link": "https://espanso.org/",
"winget": "Espanso.Espanso"
},
"etcher": {
"category": "Utilities",
"choco": "etcher",
"content": "Etcher USB Creator",
"description": "Etcher is a powerful tool for creating bootable USB drives with ease.",
"link": "https://www.balena.io/etcher/",
"winget": "Balena.Etcher"
},
"falkon": {
"category": "Browsers",
"choco": "falkon",
@ -675,9 +675,9 @@
"category": "Multimedia Tools",
"choco": "fxsound",
"content": "FxSound",
"description": "FxSound is a cutting-edge audio enhancement software that elevates your listening experience across all media.",
"description": "FxSound is free open-source software to boost sound quality, volume, and bass. Including an equalizer, effects, and presets for customized audio.",
"link": "https://www.fxsound.com/",
"winget": "FxSoundLLC.FxSound"
"winget": "FxSound.FxSound"
},
"fzf": {
"category": "Utilities",
@ -701,7 +701,7 @@
"content": "GIMP (Image Editor)",
"description": "GIMP is a versatile open-source raster graphics editor used for tasks such as photo retouching, image editing, and image composition.",
"link": "https://www.gimp.org/",
"winget": "GIMP.GIMP"
"winget": "GIMP.GIMP.3"
},
"git": {
"category": "Development",
@ -908,7 +908,7 @@
"choco": "imgburn",
"content": "ImgBurn",
"description": "ImgBurn is a lightweight CD, DVD, HD-DVD, and Blu-ray burning application with advanced features for creating and burning disc images.",
"link": "http://www.imgburn.com/",
"link": "https://www.imgburn.com/",
"winget": "LIGHTNINGUK.ImgBurn"
},
"inkscape": {
@ -980,7 +980,7 @@
"choco": "jdownloader",
"content": "JDownloader",
"description": "JDownloader is a feature-rich download manager with support for various file hosting services.",
"link": "http://jdownloader.org/",
"link": "https://jdownloader.org/",
"winget": "AppWork.JDownloader"
},
"jellyfinmediaplayer": {
@ -1372,7 +1372,7 @@
"choco": "na",
"content": "nGlide (3dfx compatibility)",
"description": "nGlide is a 3Dfx Voodoo Glide wrapper. It allows you to play games that use Glide API on modern graphics cards without the need for a 3Dfx Voodoo graphics card.",
"link": "http://www.zeus-software.com/downloads/nglide",
"link": "https://www.zeus-software.com/downloads/nglide",
"winget": "ZeusSoftware.nGlide"
},
"nmap": {
@ -1503,14 +1503,6 @@
"link": "https://github.com/namazso/OpenHashTab/",
"winget": "namazso.OpenHashTab"
},
"openoffice": {
"category": "Document",
"choco": "openoffice",
"content": "Apache OpenOffice",
"description": "Apache OpenOffice is an open-source office software suite for word processing, spreadsheets, presentations, and more.",
"link": "https://www.openoffice.org/",
"winget": "Apache.OpenOffice"
},
"openrgb": {
"category": "Utilities",
"choco": "openrgb",
@ -1691,7 +1683,7 @@
"category": "Games",
"choco": "prismlauncher",
"content": "Prism Launcher",
"description": "Prism Launcher is a game launcher and manager designed to provide a clean and intuitive interface for organizing and launching your games.",
"description": "Prism Launcher is an Open Source Minecraft launcher with the ability to manage multiple instances, accounts and mods.",
"link": "https://prismlauncher.org/",
"winget": "PrismLauncher.PrismLauncher"
},
@ -1871,14 +1863,6 @@
"link": "https://sagethumbs.en.lo4d.com/windows",
"winget": "CherubicSoftware.SageThumbs"
},
"samsungmagician": {
"category": "Utilities",
"choco": "samsung-magician",
"content": "Samsung Magician",
"description": "Samsung Magician is a utility for managing and optimizing Samsung SSDs.",
"link": "https://semiconductor.samsung.com/consumer-storage/magician/",
"winget": "Samsung.SamsungMagician"
},
"sandboxie": {
"category": "Utilities",
"choco": "sandboxie",
@ -1991,14 +1975,6 @@
"link": "http://www.uderzo.it/main_products/space_sniffer/",
"winget": "UderzoSoftware.SpaceSniffer"
},
"spotube": {
"category": "Multimedia Tools",
"choco": "spotube",
"content": "Spotube",
"description": "Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile! ",
"link": "https://github.com/KRTirtho/spotube",
"winget": "KRTirtho.Spotube"
},
"starship": {
"category": "Development",
"choco": "starship",
@ -2196,7 +2172,7 @@
"choco": "na",
"content": "Thorium Browser AVX2",
"description": "Browser built for speed over vanilla chromium. It is built with AVX2 optimizations and is the fastest browser on the market.",
"link": "http://thorium.rocks/",
"link": "https://thorium.rocks/",
"winget": "Alex313031.Thorium.AVX2"
},
"thunderbird": {
@ -2453,7 +2429,7 @@
"content": "UniGetUI",
"description": "UniGetUI is a GUI for Winget, Chocolatey, and other Windows CLI package managers.",
"link": "https://www.marticliment.com/wingetui/",
"winget": "SomePythonThings.WingetUIStore"
"winget": "MartiCliment.UniGetUI"
},
"winmerge": {
"category": "Document",
@ -2926,5 +2902,13 @@
"description": "Fork - a fast and friendly git client.",
"link": "https://git-fork.com/",
"winget": "Fork.Fork"
},
"ZenBrowser": {
"category": "Browsers",
"choco": "na",
"content": "Zen Browser",
"description": "The modern, privacy-focused, performance-driven browser built on Firefox",
"link": "https://zen-browser.app/",
"winget": "Zen-Team.Zen-Browser"
}
}

62
config/appnavigation.json Normal file
View File

@ -0,0 +1,62 @@
{
"WPFInstall": {
"Content": "Install/Upgrade Applications",
"Category": "____Actions",
"Type": "Button",
"Order": "1",
"Description": "Install or upgrade the selected applications"
},
"WPFUninstall": {
"Content": "Uninstall Applications",
"Category": "____Actions",
"Type": "Button",
"Order": "2",
"Description": "Uninstall the selected applications"
},
"WPFInstallUpgrade": {
"Content": "Upgrade all Applications",
"Category": "____Actions",
"Type": "Button",
"Order": "3",
"Description": "Upgrade all applications to the latest version"
},
"WingetRadioButton": {
"Content": "Winget",
"Category": "__Package Manager",
"Type": "RadioButton",
"GroupName": "PackageManagerGroup",
"Checked": true,
"Order": "1",
"Description": "Use Winget for package management"
},
"ChocoRadioButton": {
"Content": "Chocolatey",
"Category": "__Package Manager",
"Type": "RadioButton",
"GroupName": "PackageManagerGroup",
"Checked": false,
"Order": "2",
"Description": "Use Chocolatey for package management"
},
"WPFClearInstallSelection": {
"Content": "Clear Selection",
"Category": "__Selection",
"Type": "Button",
"Order": "1",
"Description": "Clear the selection of applications"
},
"WPFGetInstalled": {
"Content": "Get Installed",
"Category": "__Selection",
"Type": "Button",
"Order": "2",
"Description": "Show installed applications"
},
"WPFselectedAppsButton": {
"Content": "Selected Apps: 0",
"Category": "__Selection",
"Type": "Button",
"Order": "3",
"Description": "Show the selected applications"
}
}

View File

@ -10,7 +10,7 @@
"NetFx3"
],
"InvokeScript": [],
"link": "https://christitustech.github.io/winutil/dev/features/Features/dotnet"
"link": "https://winutil.christitus.com/dev/features/features/dotnet"
},
"WPFFeatureshyperv": {
"Content": "HyperV Virtualization",
@ -31,7 +31,7 @@
"InvokeScript": [
"Start-Process -FilePath cmd.exe -ArgumentList '/c bcdedit /set hypervisorschedulertype classic' -Wait"
],
"link": "https://christitustech.github.io/winutil/dev/features/Features/hyperv"
"link": "https://winutil.christitus.com/dev/features/features/hyperv"
},
"WPFFeatureslegacymedia": {
"Content": "Legacy Media (WMP, DirectPlay)",
@ -46,7 +46,7 @@
"LegacyComponents"
],
"InvokeScript": [],
"link": "https://christitustech.github.io/winutil/dev/features/Features/legacymedia"
"link": "https://winutil.christitus.com/dev/features/features/legacymedia"
},
"WPFFeaturewsl": {
"Content": "Windows Subsystem for Linux",
@ -59,7 +59,7 @@
"Microsoft-Windows-Subsystem-Linux"
],
"InvokeScript": [],
"link": "https://christitustech.github.io/winutil/dev/features/Features/wsl"
"link": "https://winutil.christitus.com/dev/features/features/wsl"
},
"WPFFeaturenfs": {
"Content": "NFS - Network File System",
@ -79,7 +79,7 @@
"nfsadmin client start",
"nfsadmin client localhost config fileaccess=755 SecFlavors=+sys -krb5 -krb5i"
],
"link": "https://christitustech.github.io/winutil/dev/features/Features/nfs"
"link": "https://winutil.christitus.com/dev/features/features/nfs"
},
"WPFFeatureEnableSearchSuggestions": {
"Content": "Enable Search Box Web Suggestions in Registry(explorer restart)",
@ -97,7 +97,7 @@
Stop-Process -name explorer -force
"
],
"link": "https://christitustech.github.io/winutil/dev/features/Features/EnableSearchSuggestions"
"link": "https://winutil.christitus.com/dev/features/features/enablesearchsuggestions"
},
"WPFFeatureDisableSearchSuggestions": {
"Content": "Disable Search Box Web Suggestions in Registry(explorer restart)",
@ -115,7 +115,7 @@
Stop-Process -name explorer -force
"
],
"link": "https://christitustech.github.io/winutil/dev/features/Features/DisableSearchSuggestions"
"link": "https://winutil.christitus.com/dev/features/features/disablesearchsuggestions"
},
"WPFFeatureRegBackup": {
"Content": "Enable Daily Registry Backup Task 12.30am",
@ -133,7 +133,7 @@
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName 'AutoRegBackup' -Description 'Create System Registry Backups' -User 'System'
"
],
"link": "https://christitustech.github.io/winutil/dev/features/Features/RegBackup"
"link": "https://winutil.christitus.com/dev/features/features/regbackup"
},
"WPFFeatureEnableLegacyRecovery": {
"Content": "Enable Legacy F8 Boot Recovery",
@ -151,7 +151,7 @@
Start-Process -FilePath cmd.exe -ArgumentList '/c bcdedit /Set {Current} BootMenuPolicy Legacy' -Wait
"
],
"link": "https://christitustech.github.io/winutil/dev/features/Features/EnableLegacyRecovery"
"link": "https://winutil.christitus.com/dev/features/features/enablelegacyrecovery"
},
"WPFFeatureDisableLegacyRecovery": {
"Content": "Disable Legacy F8 Boot Recovery",
@ -169,7 +169,7 @@
Start-Process -FilePath cmd.exe -ArgumentList '/c bcdedit /Set {Current} BootMenuPolicy Standard' -Wait
"
],
"link": "https://christitustech.github.io/winutil/dev/features/Features/DisableLegacyRecovery"
"link": "https://winutil.christitus.com/dev/features/features/disablelegacyrecovery"
},
"WPFFeaturesSandbox": {
"Content": "Windows Sandbox",
@ -177,7 +177,7 @@
"panel": "1",
"Order": "a021_",
"Description": "Windows Sandbox is a lightweight virtual machine that provides a temporary desktop environment to safely run applications and programs in isolation.",
"link": "https://christitustech.github.io/winutil/dev/features/Features/Sandbox"
"link": "https://winutil.christitus.com/dev/features/features/sandbox"
},
"WPFFeatureInstall": {
"Content": "Install Features",
@ -186,7 +186,7 @@
"Order": "a060_",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Features/Install"
"link": "https://winutil.christitus.com/dev/features/features/install"
},
"WPFPanelAutologin": {
"Content": "Set Up Autologin",
@ -195,7 +195,7 @@
"panel": "1",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Fixes/Autologin"
"link": "https://winutil.christitus.com/dev/features/fixes/autologin"
},
"WPFFixesUpdate": {
"Content": "Reset Windows Update",
@ -204,7 +204,7 @@
"Order": "a041_",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Fixes/Update"
"link": "https://winutil.christitus.com/dev/features/fixes/update"
},
"WPFFixesNetwork": {
"Content": "Reset Network",
@ -213,7 +213,7 @@
"panel": "1",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Fixes/Network"
"link": "https://winutil.christitus.com/dev/features/fixes/network"
},
"WPFPanelDISM": {
"Content": "System Corruption Scan",
@ -222,7 +222,7 @@
"Order": "a043_",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Fixes/DISM"
"link": "https://winutil.christitus.com/dev/features/fixes/dism"
},
"WPFFixesWinget": {
"Content": "WinGet Reinstall",
@ -231,7 +231,7 @@
"Order": "a044_",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Fixes/Winget"
"link": "https://winutil.christitus.com/dev/features/fixes/winget"
},
"WPFRunAdobeCCCleanerTool": {
"Content": "Remove Adobe Creative Cloud",
@ -240,7 +240,7 @@
"Order": "a045_",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Fixes/RunAdobeCCCleanerTool"
"link": "https://winutil.christitus.com/dev/features/fixes/runadobecccleanertool"
},
"WPFPanelnetwork": {
"Content": "Network Connections",
@ -248,7 +248,7 @@
"panel": "2",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Legacy-Windows-Panels/network"
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/network"
},
"WPFPanelcontrol": {
"Content": "Control Panel",
@ -256,7 +256,7 @@
"panel": "2",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Legacy-Windows-Panels/control"
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/control"
},
"WPFPanelpower": {
"Content": "Power Panel",
@ -264,7 +264,7 @@
"panel": "2",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Legacy-Windows-Panels/power"
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/power"
},
"WPFPanelregion": {
"Content": "Region",
@ -272,7 +272,7 @@
"panel": "2",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Legacy-Windows-Panels/region"
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/region"
},
"WPFPanelsound": {
"Content": "Sound Settings",
@ -280,7 +280,7 @@
"panel": "2",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Legacy-Windows-Panels/sound"
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/sound"
},
"WPFPanelprinter": {
"Content": "Printer Panel",
@ -288,7 +288,7 @@
"panel": "2",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Legacy-Windows-Panels/printer"
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/printer"
},
"WPFPanelsystem": {
"Content": "System Properties",
@ -296,7 +296,7 @@
"panel": "2",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Legacy-Windows-Panels/system"
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/system"
},
"WPFPaneluser": {
"Content": "User Accounts",
@ -304,7 +304,14 @@
"panel": "2",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Legacy-Windows-Panels/user"
"link": "https://winutil.christitus.com/dev/features/legacy-windows-panels/user"
},
"WPFPanelGodMode": {
"Content": "God Mode",
"category": "Legacy Windows Panels",
"panel": "2",
"Type": "Button",
"ButtonWidth": "300"
},
"WPFWinUtilInstallPSProfile": {
"Content": "Install CTT PowerShell Profile",
@ -312,8 +319,7 @@
"panel": "2",
"Order": "a083_",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Powershell-Profile/PSProfileInstall"
"ButtonWidth": "300"
},
"WPFWinUtilUninstallPSProfile": {
"Content": "Uninstall CTT PowerShell Profile",
@ -321,8 +327,7 @@
"panel": "2",
"Order": "a084_",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Powershell-Profile/PSProfileUninstall"
"ButtonWidth": "300"
},
"WPFWinUtilSSHServer": {
"Content": "Enable OpenSSH Server",

View File

@ -2,6 +2,7 @@
"Standard": [
"WPFTweaksAH",
"WPFTweaksConsumerFeatures",
"WPFTweaksDisableExplorerAutoDiscovery",
"WPFTweaksDVR",
"WPFTweaksHiber",
"WPFTweaksHome",
@ -14,11 +15,11 @@
"WPFTweaksDeleteTempFiles",
"WPFTweaksEndTaskOnTaskbar",
"WPFTweaksRestorePoint",
"WPFTweaksIPv46",
"WPFTweaksPowershell7Tele"
],
"Minimal": [
"WPFTweaksConsumerFeatures",
"WPFTweaksDisableExplorerAutoDiscovery",
"WPFTweaksHome",
"WPFTweaksServices",
"WPFTweaksTele"

View File

@ -1,13 +1,17 @@
{
"shared":{
"AppEntryWidth": "130",
"AppEntryFontSize": "11",
"AppEntryMargin": "1,1,1,1",
"AppEntryBorderTickness": "0",
"CustomDialogFontSize": "12",
"CustomDialogFontSizeHeader": "14",
"CustomDialogIconSize": "25",
"CustomDialogLogoSize": "25",
"CustomDialogWidth": "400",
"CustomDialogHeight": "200",
"FontSize": "12",
"FontFamily": "Arial",
"FontSizeHeading": "16",
"HeaderFontSize": "16",
"HeaderFontFamily": "Consolas, Monaco",
"CheckBoxBulletDecoratorSize": "14",
"CheckBoxMargin": "15,0,0,2",
@ -16,6 +20,7 @@
"TabButtonWidth": "110",
"TabButtonHeight": "26",
"TabRowHeightInPixels": "50",
"ToolTipWidth": "300",
"IconFontSize": "14",
"IconButtonSize": "35",
"SettingsIconFontSize": "18",
@ -27,7 +32,7 @@
"ButtonFontFamily": "Arial",
"ButtonWidth": "200",
"ButtonHeight": "25",
"ConfigTabButtonFontSize": "16",
"ConfigUpdateButtonFontSize": "14",
"SearchBarWidth": "200",
"SearchBarHeight": "26",
"SearchBarTextBoxFontSize": "12",
@ -38,13 +43,16 @@
"ButtonCornerRadius": "2"
},
"Light": {
"AppInstallUnselectedColor": "#F7F7F7",
"AppInstallHighlightedColor": "#CFCFCF",
"AppInstallSelectedColor": "#C2C2C2",
"ComboBoxForegroundColor": "#232629",
"ComboBoxBackgroundColor": "#F7F7F7",
"LabelboxForegroundColor": "#232629",
"MainForegroundColor": "#232629",
"MainBackgroundColor": "#F7F7F7",
"LabelBackgroundColor": "#F7F7F7",
"LinkForegroundColor": "#232629",
"LinkForegroundColor": "#484848",
"LinkHoverForegroundColor": "#232629",
"ScrollBarBackgroundColor": "#4A4D52",
"ScrollBarHoverColor": "#5A5D62",
@ -68,11 +76,15 @@
"ButtonForegroundColor": "#232629",
"ToggleButtonOnColor": "#2e77ff",
"ToggleButtonOffColor": "#707070",
"ToolTipBackgroundColor": "#F7F7F7",
"BorderColor": "#232629",
"BorderOpacity": "0.2"
},
"Dark": {
"AppInstallUnselectedColor": "#232629",
"AppInstallHighlightedColor": "#3C3C3C",
"AppInstallSelectedColor": "#4C4C4C",
"ComboBoxForegroundColor": "#F7F7F7",
"ComboBoxBackgroundColor": "#1E3747",
"LabelboxForegroundColor": "#0567ff",
@ -103,6 +115,7 @@
"ButtonForegroundColor": "#F7F7F7",
"ToggleButtonOnColor": "#2e77ff",
"ToggleButtonOffColor": "#707070",
"ToolTipBackgroundColor": "#2F373D",
"BorderColor": "#2F373D",
"BorderOpacity": "0.2"
}

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
#### **Run the latest pre-release**
```ps1
irm christitus.com/windev | iex
irm https://christitus.com/windev | iex
```
!!! bug "Keep in mind"

View File

@ -6,7 +6,7 @@ Windows Security (formerly Defender) and other anti-virus software are known to
To resolve this, allow/whitelist the script in your anti-virus software settings, or temporarily disable real-time protection. Since the project is open source, you may audit the code if security is a concern.
### Download not working
If `christitus.com/win` is not working, or you want to download the code from GitHub directly, you can use the direct download link:
If `https://christitus.com/win` is not working, or you want to download the code from GitHub directly, you can use the direct download link:
```ps1
irm https://github.com/ChrisTitusTech/winutil/releases/latest/download/winutil.ps1 | iex
@ -34,7 +34,7 @@ If you are still having issues, try using a **VPN**, or changing your **DNS prov
2. In the PowerShell window, type this to allow unsigned code to execute and run the installation script:
```ps1
Set-ExecutionPolicy Unrestricted -Scope Process -Force
irm christitus.com/win | iex
irm https://christitus.com/win | iex
```
## Runtime Issues

View File

@ -1,38 +0,0 @@
# Install CTT PowerShell Profile
Last Updated: 2024-10-01
!!! info
The Development Documentation is auto generated for every compilation of WinUtil, meaning a part of it will always stay up-to-date. **Developers do have the ability to add custom content, which won't be updated automatically.**
<!-- BEGIN CUSTOM CONTENT -->
<!-- END CUSTOM CONTENT -->
<details>
<summary>Preview Code</summary>
```json
{
"Content": "Install CTT PowerShell Profile",
"category": "Powershell Profile",
"panel": "2",
"Order": "a083_",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Powershell-Profile/PSProfileInstall"
}
```
</details>
<!-- BEGIN SECOND CUSTOM CONTENT -->
<!-- END SECOND CUSTOM CONTENT -->
[View the JSON file](https://github.com/ChrisTitusTech/winutil/tree/main/config/feature.json)

View File

@ -1,38 +0,0 @@
# Uninstall CTT PowerShell Profile
Last Updated: 2024-10-01
!!! info
The Development Documentation is auto generated for every compilation of WinUtil, meaning a part of it will always stay up-to-date. **Developers do have the ability to add custom content, which won't be updated automatically.**
<!-- BEGIN CUSTOM CONTENT -->
<!-- END CUSTOM CONTENT -->
<details>
<summary>Preview Code</summary>
```json
{
"Content": "Uninstall CTT PowerShell Profile",
"category": "Powershell Profile",
"panel": "2",
"Order": "a084_",
"Type": "Button",
"ButtonWidth": "300",
"link": "https://christitustech.github.io/winutil/dev/features/Powershell-Profile/PSProfileUninstall"
}
```
</details>
<!-- BEGIN SECOND CUSTOM CONTENT -->
<!-- END SECOND CUSTOM CONTENT -->
[View the JSON file](https://github.com/ChrisTitusTech/winutil/tree/main/config/feature.json)

View File

@ -5,104 +5,104 @@
### Essential-Tweaks
- [Change Windows Terminal default: PowerShell 5 -> PowerShell 7](../docs/dev/tweaks/Essential-Tweaks/Powershell7.md)
- [Create Restore Point](../docs/dev/tweaks/Essential-Tweaks/RestorePoint.md)
- [Debloat Edge](../docs/dev/tweaks/Essential-Tweaks/EdgeDebloat.md)
- [Delete Temporary Files](../docs/dev/tweaks/Essential-Tweaks/DeleteTempFiles.md)
- [Disable Activity History](../docs/dev/tweaks/Essential-Tweaks/AH.md)
- [Disable ConsumerFeatures](../docs/dev/tweaks/Essential-Tweaks/ConsumerFeatures.md)
- [Disable GameDVR](../docs/dev/tweaks/Essential-Tweaks/DVR.md)
- [Disable Hibernation](../docs/dev/tweaks/Essential-Tweaks/Hiber.md)
- [Disable Homegroup](../docs/dev/tweaks/Essential-Tweaks/Home.md)
- [Disable Location Tracking](../docs/dev/tweaks/Essential-Tweaks/Loc.md)
- [Disable Powershell 7 Telemetry](../docs/dev/tweaks/Essential-Tweaks/Powershell7Tele.md)
- [Disable Storage Sense](../docs/dev/tweaks/Essential-Tweaks/Storage.md)
- [Disable Telemetry](../docs/dev/tweaks/Essential-Tweaks/Tele.md)
- [Disable Wifi-Sense](../docs/dev/tweaks/Essential-Tweaks/Wifi.md)
- [Enable End Task With Right Click](../docs/dev/tweaks/Essential-Tweaks/EndTaskOnTaskbar.md)
- [Prefer IPv4 over IPv6](../docs/dev/tweaks/Essential-Tweaks/IPv46.md)
- [Run Disk Cleanup](../docs/dev/tweaks/Essential-Tweaks/DiskCleanup.md)
- [Set Hibernation as default (good for laptops)](../docs/dev/tweaks/Essential-Tweaks/LaptopHibernation.md)
- [Set Services to Manual](../docs/dev/tweaks/Essential-Tweaks/Services.md)
- [Change Windows Terminal default: PowerShell 5 -> PowerShell 7](../dev/tweaks/Essential-Tweaks/Powershell7/)
- [Create Restore Point](../dev/tweaks/Essential-Tweaks/RestorePoint/)
- [Debloat Edge](../dev/tweaks/Essential-Tweaks/EdgeDebloat/)
- [Delete Temporary Files](../dev/tweaks/Essential-Tweaks/DeleteTempFiles/)
- [Disable Activity History](../dev/tweaks/Essential-Tweaks/AH/)
- [Disable ConsumerFeatures](../dev/tweaks/Essential-Tweaks/ConsumerFeatures/)
- [Disable GameDVR](../dev/tweaks/Essential-Tweaks/DVR/)
- [Disable Hibernation](../dev/tweaks/Essential-Tweaks/Hiber/)
- [Disable Homegroup](../dev/tweaks/Essential-Tweaks/Home/)
- [Disable Location Tracking](../dev/tweaks/Essential-Tweaks/Loc/)
- [Disable Powershell 7 Telemetry](../dev/tweaks/Essential-Tweaks/Powershell7Tele/)
- [Disable Storage Sense](../dev/tweaks/Essential-Tweaks/Storage/)
- [Disable Telemetry](../dev/tweaks/Essential-Tweaks/Tele/)
- [Disable Wifi-Sense](../dev/tweaks/Essential-Tweaks/Wifi/)
- [Enable End Task With Right Click](../dev/tweaks/Essential-Tweaks/EndTaskOnTaskbar/)
- [Prefer IPv4 over IPv6](../dev/tweaks/Essential-Tweaks/IPv46/)
- [Run Disk Cleanup](../dev/tweaks/Essential-Tweaks/DiskCleanup/)
- [Set Hibernation as default (good for laptops)](../dev/tweaks/Essential-Tweaks/LaptopHibernation/)
- [Set Services to Manual](../dev/tweaks/Essential-Tweaks/Services/)
### Shortcuts
- [Create WinUtil Shortcut](../docs/dev/tweaks/Shortcuts/Shortcut.md)
- [Create WinUtil Shortcut](../dev/tweaks/Shortcuts/Shortcut/)
### z--Advanced-Tweaks---CAUTION
- [Adobe Debloat](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/DebloatAdobe.md)
- [Adobe Network Block](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/BlockAdobeNet.md)
- [Disable Background Apps](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/DisableBGapps.md)
- [Disable Fullscreen Optimizations](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/DisableFSO.md)
- [Disable Intel MM (vPro LMS)](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/DisableLMS1.md)
- [Disable IPv6](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/Disableipsix.md)
- [Disable Microsoft Copilot](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/RemoveCopilot.md)
- [Disable Notification Tray/Calendar](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/DisableNotifications.md)
- [Disable Teredo](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/Teredo.md)
- [DNS](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/changedns.md)
- [Remove ALL MS Store Apps - NOT RECOMMENDED](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/DeBloat.md)
- [Remove Home and Gallery from explorer](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/RemoveHomeGallery.md)
- [Remove Microsoft Edge](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/RemoveEdge.md)
- [Remove OneDrive](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/RemoveOnedrive.md)
- [Run OO Shutup 10](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/OOSUbutton.md)
- [Set Classic Right-Click Menu ](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/RightClickMenu.md)
- [Set Display for Performance](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/Display.md)
- [Set Time to UTC (Dual Boot)](../docs/dev/tweaks/z--Advanced-Tweaks---CAUTION/UTC.md)
- [Adobe Debloat](../dev/tweaks/z--Advanced-Tweaks---CAUTION/DebloatAdobe/)
- [Adobe Network Block](../dev/tweaks/z--Advanced-Tweaks---CAUTION/BlockAdobeNet/)
- [Disable Background Apps](../dev/tweaks/z--Advanced-Tweaks---CAUTION/DisableBGapps/)
- [Disable Fullscreen Optimizations](../dev/tweaks/z--Advanced-Tweaks---CAUTION/DisableFSO/)
- [Disable Intel MM (vPro LMS)](../dev/tweaks/z--Advanced-Tweaks---CAUTION/DisableLMS1/)
- [Disable IPv6](../dev/tweaks/z--Advanced-Tweaks---CAUTION/Disableipsix/)
- [Disable Microsoft Copilot](../dev/tweaks/z--Advanced-Tweaks---CAUTION/RemoveCopilot/)
- [Disable Notification Tray/Calendar](../dev/tweaks/z--Advanced-Tweaks---CAUTION/DisableNotifications/)
- [Disable Teredo](../dev/tweaks/z--Advanced-Tweaks---CAUTION/Teredo/)
- [DNS](../dev/tweaks/z--Advanced-Tweaks---CAUTION/changedns/)
- [Remove ALL MS Store Apps - NOT RECOMMENDED](../dev/tweaks/z--Advanced-Tweaks---CAUTION/DeBloat/)
- [Remove Home and Gallery from explorer](../dev/tweaks/z--Advanced-Tweaks---CAUTION/RemoveHomeGallery/)
- [Remove Microsoft Edge](../dev/tweaks/z--Advanced-Tweaks---CAUTION/RemoveEdge/)
- [Remove OneDrive](../dev/tweaks/z--Advanced-Tweaks---CAUTION/RemoveOnedrive/)
- [Run OO Shutup 10](../dev/tweaks/z--Advanced-Tweaks---CAUTION/OOSUbutton/)
- [Set Classic Right-Click Menu ](../dev/tweaks/z--Advanced-Tweaks---CAUTION/RightClickMenu/)
- [Set Display for Performance](../dev/tweaks/z--Advanced-Tweaks---CAUTION/Display/)
- [Set Time to UTC (Dual Boot)](../dev/tweaks/z--Advanced-Tweaks---CAUTION/UTC/)
### Customize-Preferences
- [Bing Search in Start Menu](../docs/dev/tweaks/Customize-Preferences/BingSearch.md)
- [Center Taskbar Items](../docs/dev/tweaks/Customize-Preferences/TaskbarAlignment.md)
- [Dark Theme for Windows](../docs/dev/tweaks/Customize-Preferences/DarkMode.md)
- [Detailed BSoD](../docs/dev/tweaks/Customize-Preferences/DetailedBSoD.md)
- [Mouse Acceleration](../docs/dev/tweaks/Customize-Preferences/MouseAcceleration.md)
- [NumLock on Startup](../docs/dev/tweaks/Customize-Preferences/NumLock.md)
- [Search Button in Taskbar](../docs/dev/tweaks/Customize-Preferences/TaskbarSearch.md)
- [Show File Extensions](../docs/dev/tweaks/Customize-Preferences/ShowExt.md)
- [Show Hidden Files](../docs/dev/tweaks/Customize-Preferences/HiddenFiles.md)
- [Snap Assist Flyout](../docs/dev/tweaks/Customize-Preferences/SnapFlyout.md)
- [Snap Assist Suggestion](../docs/dev/tweaks/Customize-Preferences/SnapSuggestion.md)
- [Snap Window](../docs/dev/tweaks/Customize-Preferences/SnapWindow.md)
- [Sticky Keys](../docs/dev/tweaks/Customize-Preferences/StickyKeys.md)
- [Task View Button in Taskbar](../docs/dev/tweaks/Customize-Preferences/TaskView.md)
- [Verbose Messages During Logon](../docs/dev/tweaks/Customize-Preferences/VerboseLogon.md)
- [Widgets Button in Taskbar](../docs/dev/tweaks/Customize-Preferences/TaskbarWidgets.md)
- [Bing Search in Start Menu](../dev/tweaks/Customize-Preferences/BingSearch/)
- [Center Taskbar Items](../dev/tweaks/Customize-Preferences/TaskbarAlignment/)
- [Dark Theme for Windows](../dev/tweaks/Customize-Preferences/DarkMode/)
- [Detailed BSoD](../dev/tweaks/Customize-Preferences/DetailedBSoD/)
- [Mouse Acceleration](../dev/tweaks/Customize-Preferences/MouseAcceleration/)
- [NumLock on Startup](../dev/tweaks/Customize-Preferences/NumLock/)
- [Search Button in Taskbar](../dev/tweaks/Customize-Preferences/TaskbarSearch/)
- [Show File Extensions](../dev/tweaks/Customize-Preferences/ShowExt/)
- [Show Hidden Files](../dev/tweaks/Customize-Preferences/HiddenFiles/)
- [Snap Assist Flyout](../dev/tweaks/Customize-Preferences/SnapFlyout/)
- [Snap Assist Suggestion](../dev/tweaks/Customize-Preferences/SnapSuggestion/)
- [Snap Window](../dev/tweaks/Customize-Preferences/SnapWindow/)
- [Sticky Keys](../dev/tweaks/Customize-Preferences/StickyKeys/)
- [Task View Button in Taskbar](../dev/tweaks/Customize-Preferences/TaskView/)
- [Verbose Messages During Logon](../dev/tweaks/Customize-Preferences/VerboseLogon/)
- [Widgets Button in Taskbar](../dev/tweaks/Customize-Preferences/TaskbarWidgets/)
### Performance-Plans
- [Add and Activate Ultimate Performance Profile](../docs/dev/tweaks/Performance-Plans/AddUltPerf.md)
- [Remove Ultimate Performance Profile](../docs/dev/tweaks/Performance-Plans/RemoveUltPerf.md)
- [Add and Activate Ultimate Performance Profile](../dev/tweaks/Performance-Plans/AddUltPerf/)
- [Remove Ultimate Performance Profile](../dev/tweaks/Performance-Plans/RemoveUltPerf/)
## Features
### Fixes
- [Remove Adobe Creative Cloud](../docs/dev/features/Fixes/RunAdobeCCCleanerTool.md)
- [Reset Network](../docs/dev/features/Fixes/Network.md)
- [Reset Windows Update](../docs/dev/features/Fixes/Update.md)
- [Set Up Autologin](../docs/dev/features/Fixes/Autologin.md)
- [System Corruption Scan](../docs/dev/features/Fixes/DISM.md)
- [WinGet Reinstall](../docs/dev/features/Fixes/Winget.md)
- [Remove Adobe Creative Cloud](../dev/features/Fixes/RunAdobeCCCleanerTool/)
- [Reset Network](../dev/features/Fixes/Network/)
- [Reset Windows Update](../dev/features/Fixes/Update/)
- [Set Up Autologin](../dev/features/Fixes/Autologin/)
- [System Corruption Scan](../dev/features/Fixes/DISM/)
- [WinGet Reinstall](../dev/features/Fixes/Winget/)
### Legacy-Windows-Panels
- [Control Panel](../docs/dev/features/Legacy-Windows-Panels/control.md)
- [Network Connections](../docs/dev/features/Legacy-Windows-Panels/network.md)
- [Power Panel](../docs/dev/features/Legacy-Windows-Panels/power.md)
- [Printer Settings](../docs/dev/features/Legacy-Windows-Panels/printer.md)
- [Region](../docs/dev/features/Legacy-Windows-Panels/region.md)
- [Sound Settings](../docs/dev/features/Legacy-Windows-Panels/sound.md)
- [System Properties](../docs/dev/features/Legacy-Windows-Panels/system.md)
- [User Accounts](../docs/dev/features/Legacy-Windows-Panels/user.md)
- [Control Panel](../dev/features/Legacy-Windows-Panels/control/)
- [Network Connections](../dev/features/Legacy-Windows-Panels/network/)
- [Power Panel](../dev/features/Legacy-Windows-Panels/power/)
- [Printer Settings](../dev/features/Legacy-Windows-Panels/printer/)
- [Region](../dev/features/Legacy-Windows-Panels/region/)
- [Sound Settings](../dev/features/Legacy-Windows-Panels/sound/)
- [System Properties](../dev/features/Legacy-Windows-Panels/system/)
- [User Accounts](../dev/features/Legacy-Windows-Panels/user/)
### Features
- [All .Net Framework (2,3,4)](../docs/dev/features/Features/dotnet.md)
- [Disable Legacy F8 Boot Recovery](../docs/dev/features/Features/DisableLegacyRecovery.md)
- [Disable Search Box Web Suggestions in Registry(explorer restart)](../docs/dev/features/Features/DisableSearchSuggestions.md)
- [Enable Daily Registry Backup Task 12.30am](../docs/dev/features/Features/RegBackup.md)
- [Enable Legacy F8 Boot Recovery](../docs/dev/features/Features/EnableLegacyRecovery.md)
- [Enable Search Box Web Suggestions in Registry(explorer restart)](../docs/dev/features/Features/EnableSearchSuggestions.md)
- [HyperV Virtualization](../docs/dev/features/Features/hyperv.md)
- [Install Features](../docs/dev/features/Features/Install.md)
- [Legacy Media (WMP, DirectPlay)](../docs/dev/features/Features/legacymedia.md)
- [NFS - Network File System](../docs/dev/features/Features/nfs.md)
- [Windows Sandbox](../docs/dev/features/Features/Sandbox.md)
- [Windows Subsystem for Linux](../docs/dev/features/Features/wsl.md)
- [All .Net Framework (2,3,4)](../dev/features/Features/dotnet/)
- [Disable Legacy F8 Boot Recovery](../dev/features/Features/DisableLegacyRecovery/)
- [Disable Search Box Web Suggestions in Registry(explorer restart)](../dev/features/Features/DisableSearchSuggestions/)
- [Enable Daily Registry Backup Task 12.30am](../dev/features/Features/RegBackup/)
- [Enable Legacy F8 Boot Recovery](../dev/features/Features/EnableLegacyRecovery/)
- [Enable Search Box Web Suggestions in Registry(explorer restart)](../dev/features/Features/EnableSearchSuggestions/)
- [HyperV Virtualization](../dev/features/Features/hyperv/)
- [Install Features](../dev/features/Features/Install/)
- [Legacy Media (WMP, DirectPlay)](../dev/features/Features/legacymedia/)
- [NFS - Network File System](../dev/features/Features/nfs/)
- [Windows Sandbox](../dev/features/Features/Sandbox/)
- [Windows Subsystem for Linux](../dev/features/Features/wsl/)

View File

@ -11,7 +11,7 @@ Welcome to the official documentation for WinUtil, your go-to utility for optimi
* You will first need to start a Powershell terminal **as Admin**.
* Now you can run the following command:
```ps1
irm christitus.com/win | iex
irm https://christitus.com/win | iex
```
!!! info

View File

@ -258,6 +258,6 @@ With MicroWin, you can also configure your user before proceeding if you don't w
* On any supported Windows machine, open PowerShell **as Admin** and run the following command to automatically apply tweaks and install apps from the config file.
```ps1
iex "& { $(irm christitus.com/win) } -Config [path-to-your-config] -Run"
iex "& { $(irm https://christitus.com/win) } -Config [path-to-your-config] -Run"
```
* Have a cup of coffee! Come back when it's done.

View File

@ -55,6 +55,8 @@ public class PowerManagement {
$injectDrivers = $sync.MicrowinInjectDrivers.IsChecked
$importDrivers = $sync.MicrowinImportDrivers.IsChecked
$importVirtIO = $sync.MicrowinCopyVirtIO.IsChecked
$mountDir = $sync.MicrowinMountDir.Text
$scratchDir = $sync.MicrowinScratchDir.Text
@ -109,7 +111,7 @@ public class PowerManagement {
Write-Host "Mounting Windows image. This may take a while."
Mount-WindowsImage -ImagePath "$mountDir\sources\install.wim" -Index $index -Path "$scratchDir"
if ($?) {
Write-Host "Mounting complete! Performing removal of applications..."
Write-Host "The Windows image has been mounted successfully. Continuing processing..."
} else {
Write-Host "Could not mount image. Exiting..."
Set-WinUtilTaskbaritem -state "Error" -value 1 -overlay "warning"
@ -155,13 +157,18 @@ public class PowerManagement {
}
}
if ($importVirtIO) {
Write-Host "Copying VirtIO drivers..."
Microwin-CopyVirtIO
}
Write-Host "Remove Features from the image"
Microwin-RemoveFeatures
Microwin-RemoveFeatures -UseCmdlets $true
Write-Host "Removing features complete!"
Write-Host "Removing OS packages"
Microwin-RemovePackages
Microwin-RemovePackages -UseCmdlets $true
Write-Host "Removing Appx Bloat"
Microwin-RemoveProvisionedPackages
Microwin-RemoveProvisionedPackages -UseCmdlets $true
# Detect Windows 11 24H2 and add dependency to FileExp to prevent Explorer look from going back - thanks @WitherOrNot and @thecatontheceiling
if ((Microwin-TestCompatibleImage $imgVersion $([System.Version]::new(10,0,26100,1))) -eq $true) {
@ -181,7 +188,8 @@ public class PowerManagement {
}
}
catch {
# Do nothing
# Fall back to what we used to do: delayed disablement
Enable-WindowsOptionalFeature -Path "$scratchDir" -FeatureName "Recall"
}
}
@ -189,8 +197,6 @@ public class PowerManagement {
Microwin-RemoveFileOrDirectory -pathToDelete "$($scratchDir)\Windows\DiagTrack" -Directory
Microwin-RemoveFileOrDirectory -pathToDelete "$($scratchDir)\Windows\InboxApps" -Directory
Microwin-RemoveFileOrDirectory -pathToDelete "$($scratchDir)\Windows\System32\LocationNotificationWindows.exe"
Microwin-RemoveFileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Photo Viewer" -Directory
Microwin-RemoveFileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Photo Viewer" -Directory
Microwin-RemoveFileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Media Player" -Directory
Microwin-RemoveFileOrDirectory -pathToDelete "$($scratchDir)\Program Files\Windows Media Player" -Directory
Microwin-RemoveFileOrDirectory -pathToDelete "$($scratchDir)\Program Files (x86)\Windows Mail" -Directory
@ -280,7 +286,8 @@ public class PowerManagement {
reg add "HKLM\zSYSTEM\Setup\LabConfig" /v "BypassTPMCheck" /t REG_DWORD /d 1 /f
reg add "HKLM\zSYSTEM\Setup\MoSetup" /v "AllowUpgradesWithUnsupportedTPMOrCPU" /t REG_DWORD /d 1 /f
# Prevent Windows Update Installing so called Expedited Apps
# Prevent Windows Update Installing so called Expedited Apps - 24H2 and newer
if ((Microwin-TestCompatibleImage $imgVersion $([System.Version]::new(10,0,26100,1))) -eq $true) {
@(
'EdgeUpdate',
'DevHomeUpdate',
@ -295,6 +302,7 @@ public class PowerManagement {
# When in Offline Image
reg delete "HKLM\zSOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\$_" /f | Out-Null
}
}
reg add "HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\Search" /v "SearchboxTaskbarMode" /t REG_DWORD /d 0 /f
Write-Host "Setting all services to start manually"
@ -330,6 +338,7 @@ public class PowerManagement {
reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\SearchSettings" /v "IsDynamicSearchBoxEnabled" /t REG_DWORD /d 0 /f
reg add "HKLM\zSOFTWARE\Policies\Microsoft\Dsh" /v "AllowNewsAndInterests" /t REG_DWORD /d 0 /f
reg add "HKLM\zNTUSER\SOFTWARE\Microsoft\Windows\CurrentVersion\Search" /v "TraySearchBoxVisible" /t REG_DWORD /d 1 /f
reg add "HKLM\zSOFTWARE\Policies\Microsoft\Windows\Windows Feeds" /v "EnableFeeds" /t REG_DWORD /d 0 /f
}
} catch {

View File

@ -169,7 +169,7 @@ function Invoke-MicrowinGetIso {
try {
Write-Host "Mounting Iso. Please wait."
$mountedISO = Mount-DiskImage -PassThru "$filePath"
Write-Host "Done mounting Iso $mountedISO"
Write-Host "Done mounting Iso `"$($mountedISO.ImagePath)`""
$driveLetter = (Get-Volume -DiskImage $mountedISO).DriveLetter
Write-Host "Iso mounted to '$driveLetter'"
} catch {
@ -223,7 +223,7 @@ function Invoke-MicrowinGetIso {
$mountDir = Join-Path $env:TEMP $randomMicrowin
$scratchDir = Join-Path $env:TEMP $randomMicrowinScratch
} else {
$scratchDir = $sync.MicrowinScratchDirBox.Text+"Scrach"
$scratchDir = $sync.MicrowinScratchDirBox.Text+"Scratch"
$mountDir = $sync.MicrowinScratchDirBox.Text+"micro"
}
@ -242,8 +242,8 @@ function Invoke-MicrowinGetIso {
# xcopy we can verify files and also not copy files that already exist, but hard to measure
# xcopy.exe /E /I /H /R /Y /J $DriveLetter":" $mountDir >$null
$totalTime = Measure-Command { Copy-Files "$($driveLetter):" $mountDir -Recurse -Force }
Write-Host "Copy complete! Total Time: $($totalTime.Minutes)m$($totalTime.Seconds)s"
$totalTime = Measure-Command { Copy-Files "$($driveLetter):" "$mountDir" -Recurse -Force }
Write-Host "Copy complete! Total Time: $($totalTime.Minutes) minutes, $($totalTime.Seconds) seconds"
$wimFile = "$mountDir\sources\install.wim"
Write-Host "Getting image information $wimFile"

View File

@ -16,6 +16,54 @@ function Microwin-CopyToUSB([string]$fileToCopy) {
}
Write-Host "File copied to Ventoy drive $($volume.DriveLetter)"
# Detect if config files are present, move them if they are, and configure the Ventoy drive to not bypass the requirements
$customVentoyConfig = @'
{
"control":[
{ "VTOY_WIN11_BYPASS_CHECK": "0" },
{ "VTOY_WIN11_BYPASS_NRO": "0" }
],
"control_legacy":[
{ "VTOY_WIN11_BYPASS_CHECK": "0" },
{ "VTOY_WIN11_BYPASS_NRO": "0" }
],
"control_uefi":[
{ "VTOY_WIN11_BYPASS_CHECK": "0" },
{ "VTOY_WIN11_BYPASS_NRO": "0" }
],
"control_ia32":[
{ "VTOY_WIN11_BYPASS_CHECK": "0" },
{ "VTOY_WIN11_BYPASS_NRO": "0" }
],
"control_aa64":[
{ "VTOY_WIN11_BYPASS_CHECK": "0" },
{ "VTOY_WIN11_BYPASS_NRO": "0" }
],
"control_mips":[
{ "VTOY_WIN11_BYPASS_CHECK": "0" },
{ "VTOY_WIN11_BYPASS_NRO": "0" }
]
}
'@
try {
Write-Host "Writing custom Ventoy configuration. Please wait..."
if (Test-Path -Path "$($volume.DriveLetter):\ventoy\ventoy.json" -PathType Leaf) {
Write-Host "A Ventoy configuration file exists. Moving it..."
Move-Item -Path "$($volume.DriveLetter):\ventoy\ventoy.json" -Destination "$($volume.DriveLetter):\ventoy\ventoy.json.old" -Force
Write-Host "Existing Ventoy configuration has been moved to `"ventoy.json.old`". Feel free to put your config back into the `"ventoy.json`" file."
}
if (-not (Test-Path -Path "$($volume.DriveLetter):\ventoy")) {
New-Item -Path "$($volume.DriveLetter):\ventoy" -ItemType Directory -Force | Out-Null
}
$customVentoyConfig | Out-File -FilePath "$($volume.DriveLetter):\ventoy\ventoy.json" -Encoding utf8 -Force
Write-Host "The Ventoy drive has been successfully configured."
} catch {
Write-Host "Could not configure Ventoy drive. Error: $($_.Exception.Message)`n"
Write-Host "Be sure to add the following configuration to the Ventoy drive by either creating a `"ventoy.json`" file in the `"ventoy`" directory (create it if it doesn't exist) or by editing an existing one: `n`n$customVentoyConfig`n"
Write-Host "Failure to do this will cause conflicts with your target ISO file."
}
return
}
}

View File

@ -0,0 +1,40 @@
function Microwin-CopyVirtIO {
<#
.SYNOPSIS
Downloads and copies the VirtIO Guest Tools drivers to the target MicroWin ISO
.NOTES
A network connection must be available and the servers of Fedora People must be up. Automatic driver installation will not be added yet - I want this implementation to be reliable.
#>
try {
Write-Host "Checking existing files..."
if (Test-Path -Path "$($env:TEMP)\virtio.iso" -PathType Leaf) {
Write-Host "VirtIO ISO has been detected. Deleting..."
Remove-Item -Path "$($env:TEMP)\virtio.iso" -Force
}
Write-Host "Getting latest VirtIO drivers. Please wait. This can take some time, depending on your network connection speed and the speed of the servers..."
Start-BitsTransfer -Source "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso" -Destination "$($env:TEMP)\virtio.iso" -DisplayName "Downloading VirtIO drivers..."
# Do everything else if the VirtIO ISO exists
if (Test-Path -Path "$($env:TEMP)\virtio.iso" -PathType Leaf) {
Write-Host "Mounting ISO. Please wait."
$virtIO_ISO = Mount-DiskImage -PassThru "$($env:TEMP)\virtio.iso"
$driveLetter = (Get-Volume -DiskImage $virtIO_ISO).DriveLetter
# Create new directory for VirtIO on ISO
New-Item -Path "$mountDir\VirtIO" -ItemType Directory | Out-Null
$totalTime = Measure-Command { Copy-Files "$($driveLetter):" "$mountDir\VirtIO" -Recurse -Force }
Write-Host "VirtIO contents have been successfully copied. Time taken: $($totalTime.Minutes) minutes, $($totalTime.Seconds) seconds`n"
Get-Volume $driveLetter | Get-DiskImage | Dismount-DiskImage
Remove-Item -Path "$($env:TEMP)\virtio.iso" -Force -ErrorAction SilentlyContinue
Write-Host "To proceed with installation of the MicroWin image in QEMU/Proxmox VE:"
Write-Host "1. Proceed with Setup until you reach the disk selection screen, in which you won't see any drives"
Write-Host "2. Click `"Load Driver`" and click Browse"
Write-Host "3. In the folder selection dialog, point to this path:`n`n `"D:\VirtIO\vioscsi\w11\amd64`" (replace amd64 with ARM64 if you are using Windows on ARM, and `"D:`" with the drive letter of the ISO)`n"
Write-Host "4. Select all drivers that will appear in the list box and click OK"
} else {
throw "Could not download VirtIO drivers"
}
} catch {
Write-Host "We could not download and/or prepare the VirtIO drivers. Error information: $_`n"
Write-Host "You will need to download these drivers manually. Location: https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso"
}
}

View File

@ -54,7 +54,7 @@ function Microwin-NewFirstRun {
try
{
if ((Get-WindowsOptionalFeature -Online | Where-Object { $_.FeatureName -like "Recall" }).Count -gt 0)
if ((Get-WindowsOptionalFeature -Online | Where-Object { $_.State -eq 'Enabled' -and $_.FeatureName -like "Recall" }).Count -gt 0)
{
Disable-WindowsOptionalFeature -Online -FeatureName "Recall" -Remove
}
@ -63,6 +63,29 @@ function Microwin-NewFirstRun {
{
}
# Get BCD entries and set bootmgr timeout accordingly
try
{
# Check if the number of occurrences of "path" is 2 - this fixes the Boot Manager screen issue (#2562)
if ((bcdedit | Select-String "path").Count -eq 2)
{
# Set bootmgr timeout to 0
bcdedit /set `{bootmgr`} timeout 0
}
}
catch
{
}
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.Suggested" /f
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.Suggested" /v Enabled /t REG_DWORD /d 0 /f
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.StartupApp" /f
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.SystemToast.StartupApp" /v Enabled /t REG_DWORD /d 0 /f
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Microsoft.SkyDrive.Desktop" /f
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Microsoft.SkyDrive.Desktop" /v Enabled /t REG_DWORD /d 0 /f
'@
$firstRun | Out-File -FilePath "$env:temp\FirstStartup.ps1" -Force
}

View File

@ -31,7 +31,7 @@ function Microwin-NewUnattend {
<Group>Administrators</Group>
<Password>
<Value>PW-REPLACEME</Value>
<PlainText>true</PlainText>
<PlainText>PT-STATUS</PlainText>
</Password>
</LocalAccount>
</LocalAccounts>
@ -42,7 +42,7 @@ function Microwin-NewUnattend {
<LogonCount>1</LogonCount>
<Password>
<Value>PW-REPLACEME</Value>
<PlainText>true</PlainText>
<PlainText>PT-STATUS</PlainText>
</Password>
</AutoLogon>
<OOBE>
@ -160,134 +160,126 @@ function Microwin-NewUnattend {
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>19</Order>
<Path>powershell.exe -NoProfile -Command "Get-Content -LiteralPath 'C:\Windows\Temp\Microwin-RemovePackages.ps1' -Raw | Invoke-Expression;"</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>20</Order>
<Path>powershell.exe -NoProfile -Command "Get-Content -LiteralPath 'C:\Windows\Temp\remove-caps.ps1' -Raw | Invoke-Expression;"</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>21</Order>
<Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\current\device\Start" /v ConfigureStartPins /t REG_SZ /d "{ \"pinnedList\": [] }" /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>22</Order>
<Order>20</Order>
<Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\current\device\Start" /v ConfigureStartPins_ProviderSet /t REG_DWORD /d 1 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>23</Order>
<Order>21</Order>
<Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\current\device\Start" /v ConfigureStartPins_WinningProvider /t REG_SZ /d B5292708-1619-419B-9923-E5D9F3925E71 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>24</Order>
<Order>22</Order>
<Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\providers\B5292708-1619-419B-9923-E5D9F3925E71\default\Device\Start" /v ConfigureStartPins /t REG_SZ /d "{ \"pinnedList\": [] }" /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>25</Order>
<Order>23</Order>
<Path>reg.exe add "HKLM\SOFTWARE\Microsoft\PolicyManager\providers\B5292708-1619-419B-9923-E5D9F3925E71\default\Device\Start" /v ConfigureStartPins_LastWrite /t REG_DWORD /d 1 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>26</Order>
<Order>24</Order>
<Path>net.exe accounts /maxpwage:UNLIMITED</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>27</Order>
<Order>25</Order>
<Path>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>28</Order>
<Order>26</Order>
<Path>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Power" /v HiberbootEnabled /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>29</Order>
<Order>27</Order>
<Path>reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Dsh" /v AllowNewsAndInterests /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>30</Order>
<Order>28</Order>
<Path>reg.exe load "HKU\DefaultUser" "C:\Users\Default\NTUSER.DAT"</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>31</Order>
<Order>29</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "ContentDeliveryAllowed" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>32</Order>
<Order>30</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "FeatureManagementEnabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>33</Order>
<Order>31</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "OEMPreInstalledAppsEnabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>34</Order>
<Order>32</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEnabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>35</Order>
<Order>33</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEverEnabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>36</Order>
<Order>34</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SilentInstalledAppsEnabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>37</Order>
<Order>35</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SoftLandingEnabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>38</Order>
<Order>36</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContentEnabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>39</Order>
<Order>37</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-310093Enabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>40</Order>
<Order>38</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338387Enabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>41</Order>
<Order>39</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338388Enabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>42</Order>
<Order>40</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338389Enabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>43</Order>
<Order>41</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338393Enabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>44</Order>
<Order>42</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-353698Enabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>45</Order>
<Order>43</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SystemPaneSuggestionsEnabled" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>46</Order>
<Order>44</Order>
<Path>reg.exe unload "HKU\DefaultUser"</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>47</Order>
<Order>45</Order>
<Path>reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableWindowsConsumerFeatures" /t REG_DWORD /d 0 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>48</Order>
<Order>46</Order>
<Path>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\BitLocker" /v "PreventDeviceEncryption" /t REG_DWORD /d 1 /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>49</Order>
<Order>47</Order>
<Path>reg.exe load "HKU\DefaultUser" "C:\Users\Default\NTUSER.DAT"</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>50</Order>
<Order>48</Order>
<Path>reg.exe add "HKU\DefaultUser\Software\Microsoft\Windows\CurrentVersion\Runonce" /v "ClassicContextMenu" /t REG_SZ /d "reg.exe add \"HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32\" /ve /f" /f</Path>
</RunSynchronousCommand>
<RunSynchronousCommand wcm:action="add">
<Order>51</Order>
<Order>49</Order>
<Path>reg.exe unload "HKU\DefaultUser"</Path>
</RunSynchronousCommand>
</RunSynchronous>
@ -301,9 +293,34 @@ function Microwin-NewUnattend {
# Replace the placeholder text with the Specialize pass
$unattend = $unattend.Replace("<#REPLACEME#>", $specPass).Trim()
}
# User password in Base64. According to Microsoft, this is the way you can hide this sensitive information.
# More information can be found here: https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/wsim/hide-sensitive-data-in-an-answer-file
# Yeah, I know this is not the best way to protect this kind of data, but we all know how Microsoft is - "the Apple of security" (in a sense, it takes them
# an eternity to implement basic security features right. Just look at the NTLM and Kerberos situation!)
$b64pass = ""
# Replace default User and Password values with the provided parameters
$unattend = $unattend.Replace("USER-REPLACEME", $userName).Trim()
try {
# I want to play it safe here - I don't want encoding mismatch problems like last time
# NOTE: "Password" needs to be appended to the password specified by the user. Otherwise, a parse error will occur when processing oobeSystem.
# This will not be added to the actual password stored in the target system's SAM file - only the provided password
$b64pass = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes("$($userPassword)Password"))
} catch {
$b64pass = ""
}
if ($b64pass -ne "") {
# If we could encode the password with Base64, put it in the answer file and indicate that it's NOT in plain text
$unattend = $unattend.Replace("PW-REPLACEME", $b64pass).Trim()
$unattend = $unattend.Replace("PT-STATUS", "false").Trim()
$b64pass = ""
} else {
$unattend = $unattend.Replace("PW-REPLACEME", $userPassword).Trim()
$unattend = $unattend.Replace("PT-STATUS", "true").Trim()
}
# Save unattended answer file with UTF-8 encoding
$unattend | Out-File -FilePath "$env:temp\unattend.xml" -Force -Encoding utf8

View File

@ -3,14 +3,21 @@ function Microwin-RemoveFeatures() {
.SYNOPSIS
Removes certain features from ISO image
.PARAMETER Name
No Params
.PARAMETER UseCmdlets
Determines whether or not to use the DISM cmdlets for processing.
- If true, DISM cmdlets will be used
- If false, calls to the DISM executable will be made whilst selecting bits and pieces from the output as a string (that was how MicroWin worked before
the DISM conversion to cmdlets)
.EXAMPLE
Microwin-RemoveFeatures
Microwin-RemoveFeatures -UseCmdlets $true
#>
param (
[Parameter(Mandatory = $true, Position = 0)] [bool]$UseCmdlets
)
try {
$featlist = (Get-WindowsOptionalFeature -Path $scratchDir)
if ($UseCmdlets) {
$featlist = (Get-WindowsOptionalFeature -Path "$scratchDir")
$featlist = $featlist | Where-Object {
$_.FeatureName -NotLike "*Defender*" -AND
@ -24,17 +31,52 @@ function Microwin-RemoveFeatures() {
$_.FeatureName -NotLike "*RemoteDesktop*" -AND
$_.State -ne "Disabled"
}
} else {
$featList = dism /english /image="$scratchDir" /get-features | Select-String -Pattern "Feature Name : " -CaseSensitive -SimpleMatch
if ($?) {
$featList = $featList -split "Feature Name : " | Where-Object {$_}
# Exclude the same items. Note: for now, this doesn't exclude those features that are disabled.
# This will appear in the future
$featList = $featList | Where-Object {
$_ -NotLike "*Defender*" -AND
$_ -NotLike "*Printing*" -AND
$_ -NotLike "*TelnetClient*" -AND
$_ -NotLike "*PowerShell*" -AND
$_ -NotLike "*NetFx*" -AND
$_ -NotLike "*Media*" -AND
$_ -NotLike "*NFS*" -AND
$_ -NotLike "*SearchEngine*" -AND
$_ -NotLike "*RemoteDesktop*"
}
} else {
Write-Host "Features could not be obtained with DISM. MicroWin processing will continue, but features will be skipped."
return
}
}
foreach($feature in $featlist) {
if ($UseCmdlets) {
foreach ($feature in $featList) {
$status = "Removing feature $($feature.FeatureName)"
Write-Progress -Activity "Removing features" -Status $status -PercentComplete ($counter++/$featlist.Count*100)
Write-Debug "Removing feature $($feature.FeatureName)"
Disable-WindowsOptionalFeature -Path "$scratchDir" -FeatureName $($feature.FeatureName) -Remove -ErrorAction SilentlyContinue -NoRestart
}
} else {
foreach ($feature in $featList) {
$status = "Removing feature $feature"
Write-Progress -Activity "Removing features" -Status $status -PercentComplete ($counter++/$featlist.Count*100)
Write-Debug "Removing feature $feature"
dism /english /image="$scratchDir" /disable-feature /featurename=$feature /remove /quiet /norestart | Out-Null
if ($? -eq $false) {
Write-Host "Feature $feature could not be disabled."
}
}
}
Write-Progress -Activity "Removing features" -Status "Ready" -Completed
Write-Host "You can re-enable the disabled features at any time, using either Windows Update or the SxS folder in <installation media>\Sources."
} catch {
Write-Host "Unable to get information about the features. MicroWin processing will continue, but features will not be processed"
Write-Host "Unable to get information about the features. A fallback will be used..."
Write-Host "Error information: $($_.Exception.Message)" -ForegroundColor Yellow
Microwin-RemoveFeatures -UseCmdlets $false
}
}

View File

@ -12,7 +12,11 @@ function Microwin-RemoveFileOrDirectory([string]$pathToDelete, [string]$mask = "
[void]$itemsToDelete.Add($pathToDelete)
} else {
Write-Debug "Adding $($pathToDelete) to array and mask is $($mask)"
if ($Directory) { $itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse -Directory } else { $itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse }
if ($Directory) {
$itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse -Directory
} else {
$itemsToDelete = Get-ChildItem $pathToDelete -Include $mask -Recurse
}
}
foreach($itemToDelete in $itemsToDelete) {

View File

@ -1,5 +1,22 @@
function Microwin-RemovePackages {
<#
.SYNOPSIS
Removes certain packages from ISO image
.PARAMETER UseCmdlets
Determines whether or not to use the DISM cmdlets for processing.
- If true, DISM cmdlets will be used
- If false, calls to the DISM executable will be made whilst selecting bits and pieces from the output as a string (that was how MicroWin worked before
the DISM conversion to cmdlets)
.EXAMPLE
Microwin-RemovePackages -UseCmdlets $true
#>
param (
[Parameter(Mandatory = $true, Position = 0)] [bool]$UseCmdlets
)
try {
if ($useCmdlets) {
$pkglist = (Get-WindowsPackage -Path "$scratchDir").PackageName
$pkglist = $pkglist | Where-Object {
@ -7,47 +24,51 @@ function Microwin-RemovePackages {
$_ -NotLike "*indows-Client-LanguagePack*" -AND
$_ -NotLike "*LanguageFeatures-Basic*" -AND
$_ -NotLike "*Package_for_ServicingStack*" -AND
$_ -NotLike "*.NET*" -AND
$_ -NotLike "*Store*" -AND
$_ -NotLike "*VCLibs*" -AND
$_ -NotLike "*AAD.BrokerPlugin",
$_ -NotLike "*LockApp*" -AND
$_ -NotLike "*DotNet*" -AND
$_ -NotLike "*Notepad*" -AND
$_ -NotLike "*immersivecontrolpanel*" -AND
$_ -NotLike "*ContentDeliveryManager*" -AND
$_ -NotLike "*PinningConfirMationDialog*" -AND
$_ -NotLike "*SecHealthUI*" -AND
$_ -NotLike "*SecureAssessmentBrowser*" -AND
$_ -NotLike "*PrintDialog*" -AND
$_ -NotLike "*AssignedAccessLockApp*" -AND
$_ -NotLike "*OOBENetworkConnectionFlow*" -AND
$_ -NotLike "*Apprep.ChxApp*" -AND
$_ -NotLike "*CBS*" -AND
$_ -NotLike "*OOBENetworkCaptivePortal*" -AND
$_ -NotLike "*PeopleExperienceHost*" -AND
$_ -NotLike "*ParentalControls*" -AND
$_ -NotLike "*Win32WebViewHost*" -AND
$_ -NotLike "*InputApp*" -AND
$_ -NotLike "*DirectPlay*" -AND
$_ -NotLike "*AccountsControl*" -AND
$_ -NotLike "*AsyncTextService*" -AND
$_ -NotLike "*CapturePicker*" -AND
$_ -NotLike "*CredDialogHost*" -AND
$_ -NotLike "*BioEnrollMent*" -AND
$_ -NotLike "*ShellExperienceHost*" -AND
$_ -NotLike "*DesktopAppInstaller*" -AND
$_ -NotLike "*WebMediaExtensions*" -AND
$_ -NotLike "*WMIC*" -AND
$_ -NotLike "*UI.XaML*" -AND
$_ -NotLike "*Ethernet*" -AND
$_ -NotLike "*Wifi*" -AND
$_ -NotLike "*FodMetadata*" -AND
$_ -NotLike "*Foundation*" -AND
$_ -NotLike "*LanguageFeatures*" -AND
$_ -NotLike "*VBSCRIPT*" -AND
$_ -NotLike "*License*"
$_ -NotLike "*License*" -AND
$_ -NotLike "*Hello-Face*" -AND
$_ -NotLike "*ISE*" -AND
$_ -NotLike "*OpenSSH*"
}
} else {
$pkgList = dism /english /image="$scratchDir" /get-packages | Select-String -Pattern "Package Identity : " -CaseSensitive -SimpleMatch
if ($?) {
$pkgList = $pkgList -split "Package Identity : " | Where-Object {$_}
# Exclude the same items.
$pkgList = $pkgList | Where-Object {
$_ -NotLike "*ApplicationModel*" -AND
$_ -NotLike "*indows-Client-LanguagePack*" -AND
$_ -NotLike "*LanguageFeatures-Basic*" -AND
$_ -NotLike "*Package_for_ServicingStack*" -AND
$_ -NotLike "*DotNet*" -AND
$_ -NotLike "*Notepad*" -AND
$_ -NotLike "*WMIC*" -AND
$_ -NotLike "*Ethernet*" -AND
$_ -NotLike "*Wifi*" -AND
$_ -NotLike "*FodMetadata*" -AND
$_ -NotLike "*Foundation*" -AND
$_ -NotLike "*LanguageFeatures*" -AND
$_ -NotLike "*VBSCRIPT*" -AND
$_ -NotLike "*License*" -AND
$_ -NotLike "*Hello-Face*" -AND
$_ -NotLike "*ISE*" -AND
$_ -NotLike "*OpenSSH*"
}
} else {
Write-Host "Packages could not be obtained with DISM. MicroWin processing will continue, but packages will be skipped."
return
}
}
if ($UseCmdlets) {
$failedCount = 0
$erroredPackages = [System.Collections.Generic.List[ErroredPackage]]::new()
@ -64,8 +85,19 @@ function Microwin-RemovePackages {
continue
}
}
} else {
foreach ($package in $pkgList) {
$status = "Removing package $package"
Write-Progress -Activity "Removing Packages" -Status $status -PercentComplete ($counter++/$pkglist.Count*100)
Write-Debug "Removing package $package"
dism /english /image="$scratchDir" /remove-package /packagename=$package /quiet /norestart | Out-Null
if ($? -eq $false) {
Write-Host "Package $package could not be removed."
}
}
}
Write-Progress -Activity "Removing Packages" -Status "Ready" -Completed
if ($failedCount -gt 0)
if ($UseCmdlets -and $failedCount -gt 0)
{
Write-Host "$failedCount package(s) could not be removed. Your image will still work fine, however. Below is information on what packages failed to be removed and why."
if ($erroredPackages.Count -gt 0)
@ -90,7 +122,8 @@ function Microwin-RemovePackages {
}
}
} catch {
Write-Host "Unable to get information about the packages. MicroWin processing will continue, but packages will not be processed"
Write-Host "Unable to get information about the packages. A fallback will be used..."
Write-Host "Error information: $($_.Exception.Message)" -ForegroundColor Yellow
Microwin-RemovePackages -UseCmdlets $false
}
}

View File

@ -3,14 +3,21 @@ function Microwin-RemoveProvisionedPackages() {
.SYNOPSIS
Removes AppX packages from a Windows image during MicroWin processing
.PARAMETER Name
No Params
.PARAMETER UseCmdlets
Determines whether or not to use the DISM cmdlets for processing.
- If true, DISM cmdlets will be used
- If false, calls to the DISM executable will be made whilst selecting bits and pieces from the output as a string (that was how MicroWin worked before
the DISM conversion to cmdlets)
.EXAMPLE
Microwin-RemoveProvisionedPackages
#>
param (
[Parameter(Mandatory = $true, Position = 0)] [bool]$UseCmdlets
)
try
{
if ($UseCmdlets) {
$appxProvisionedPackages = Get-AppxProvisionedPackage -Path "$($scratchDir)" | Where-Object {
$_.PackageName -NotLike "*AppInstaller*" -AND
$_.PackageName -NotLike "*Store*" -and
@ -28,8 +35,36 @@ function Microwin-RemoveProvisionedPackages() {
$_.PackageName -NotLike "*SecHealthUI*" -and
$_.PackageName -NotLike "*ScreenSketch*"
}
} else {
$appxProvisionedPackages = dism /english /image="$scratchDir" /get-provisionedappxpackages | Select-String -Pattern "PackageName : " -CaseSensitive -SimpleMatch
if ($?) {
$appxProvisionedPackages = $appxProvisionedPackages -split "PackageName : " | Where-Object {$_}
# Exclude the same items.
$appxProvisionedPackages = $appxProvisionedPackages | Where-Object {
$_ -NotLike "*AppInstaller*" -AND
$_ -NotLike "*Store*" -and
$_ -NotLike "*Notepad*" -and
$_ -NotLike "*Printing*" -and
$_ -NotLike "*YourPhone*" -and
$_ -NotLike "*Xbox*" -and
$_ -NotLike "*WindowsTerminal*" -and
$_ -NotLike "*Calculator*" -and
$_ -NotLike "*Photos*" -and
$_ -NotLike "*VCLibs*" -and
$_ -NotLike "*Paint*" -and
$_ -NotLike "*Gaming*" -and
$_ -NotLike "*Extension*" -and
$_ -NotLike "*SecHealthUI*" -and
$_ -NotLike "*ScreenSketch*"
}
} else {
Write-Host "AppX packages could not be obtained with DISM. MicroWin processing will continue, but AppX packages will be skipped."
return
}
}
$counter = 0
if ($UseCmdlets) {
foreach ($appx in $appxProvisionedPackages) {
$status = "Removing Provisioned $($appx.PackageName)"
Write-Progress -Activity "Removing Provisioned Apps" -Status $status -PercentComplete ($counter++/$appxProvisionedPackages.Count*100)
@ -40,12 +75,22 @@ function Microwin-RemoveProvisionedPackages() {
continue
}
}
} else {
foreach ($appx in $appxProvisionedPackages) {
$status = "Removing Provisioned $appx"
Write-Progress -Activity "Removing Provisioned Apps" -Status $status -PercentComplete ($counter++/$appxProvisionedPackages.Count*100)
dism /english /image="$scratchDir" /remove-provisionedappxpackage /packagename=$appx /quiet /norestart | Out-Null
if ($? -eq $false) {
Write-Host "AppX package $appx could not be removed."
}
}
}
Write-Progress -Activity "Removing Provisioned Apps" -Status "Ready" -Completed
}
catch
{
# This can happen if getting AppX packages fails
Write-Host "Unable to get information about the AppX packages. MicroWin processing will continue, but AppX packages will not be processed"
Write-Host "Unable to get information about the AppX packages. A fallback will be used..."
Write-Host "Error information: $($_.Exception.Message)" -ForegroundColor Yellow
Microwin-RemoveProvisionedPackages -UseCmdlets $false
}
}

View File

@ -0,0 +1,50 @@
function Add-SelectedAppsMenuItem {
<#
.SYNOPSIS
This is a helper function that generates and adds the Menu Items to the Selected Apps Popup.
.Parameter name
The actual Name of an App like "Chrome" or "Brave"
This name is contained in the "Content" property inside the applications.json
.PARAMETER key
The key which identifies an app object in applications.json
For Chrome this would be "WPFInstallchrome" because "WPFInstall" is prepended automatically for each key in applications.json
#>
param ([string]$name, [string]$key)
$selectedAppGrid = New-Object Windows.Controls.Grid
$selectedAppGrid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition -Property @{Width = "*"}))
$selectedAppGrid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition -Property @{Width = "30"}))
# Sets the name to the Content as well as the Tooltip, because the parent Popup Border has a fixed width and text could "overflow".
# With the tooltip, you can still read the whole entry on hover
$selectedAppLabel = New-Object Windows.Controls.Label
$selectedAppLabel.Content = $name
$selectedAppLabel.ToolTip = $name
$selectedAppLabel.HorizontalAlignment = "Left"
$selectedAppLabel.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
[System.Windows.Controls.Grid]::SetColumn($selectedAppLabel, 0)
$selectedAppGrid.Children.Add($selectedAppLabel)
$selectedAppRemoveButton = New-Object Windows.Controls.Button
$selectedAppRemoveButton.FontFamily = "Segoe MDL2 Assets"
$selectedAppRemoveButton.Content = [string]([char]0xE711)
$selectedAppRemoveButton.HorizontalAlignment = "Center"
$selectedAppRemoveButton.Tag = $key
$selectedAppRemoveButton.ToolTip = "Remove the App from Selection"
$selectedAppRemoveButton.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$selectedAppRemoveButton.SetResourceReference([Windows.Controls.Control]::StyleProperty, "HoverButtonStyle")
# Highlight the Remove icon on Hover
$selectedAppRemoveButton.Add_MouseEnter({ $this.Foreground = "Red" })
$selectedAppRemoveButton.Add_MouseLeave({ $this.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor") })
$selectedAppRemoveButton.Add_Click({
$sync.($this.Tag).isChecked = $false # On click of the remove button, we only have to uncheck the corresponding checkbox. This will kick of all neccessary changes to update the UI
})
[System.Windows.Controls.Grid]::SetColumn($selectedAppRemoveButton, 1)
$selectedAppGrid.Children.Add($selectedAppRemoveButton)
# Add new Element to Popup
$sync.selectedAppsstackPanel.Children.Add($selectedAppGrid)
}

View File

@ -2,11 +2,17 @@ function Copy-Files {
<#
.DESCRIPTION
This function will make all modifications to the registry
Copies the contents of a given ISO file to a given destination
.PARAMETER Path
The source of the files to copy
.PARAMETER Destination
The destination to copy the files to
.PARAMETER Recurse
Determines whether or not to copy all files of the ISO file, including those in subdirectories
.PARAMETER Force
Determines whether or not to overwrite existing files
.EXAMPLE
Set-WinUtilRegistry -Name "PublishUserActivities" -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Type "DWord" -Value "0"
Copy-Files "D:" "C:\ISOFile" -Recurse -Force
#>
param (
@ -23,7 +29,7 @@ function Copy-Files {
foreach ($file in $files) {
$status = "Copying file {0} of {1}: {2}" -f $counter, $files.Count, $file.Name
Write-Progress -Activity "Copy Windows files" -Status $status -PercentComplete ($counter++/$files.count*100)
Write-Progress -Activity "Copy disc image files" -Status $status -PercentComplete ($counter++/$files.count*100)
$restpath = $file.FullName -Replace $path, ''
if ($file.PSIsContainer -eq $true) {
@ -35,7 +41,7 @@ function Copy-Files {
Set-ItemProperty -Path ($destination+$restpath) -Name IsReadOnly -Value $false
}
}
Write-Progress -Activity "Copy Windows files" -Status "Ready" -Completed
Write-Progress -Activity "Copy disc image files" -Status "Ready" -Completed
} catch {
Write-Host "Unable to Copy all the files due to an unhandled exception" -ForegroundColor Yellow
Write-Host "Error information: $($_.Exception.Message)`n" -ForegroundColor Yellow

View File

@ -0,0 +1,49 @@
function Find-AppsByNameOrDescription {
<#
.SYNOPSIS
Searches through the Apps on the Install Tab and hides all entries that do not match the string
.PARAMETER SearchString
The string to be searched for
#>
param(
[Parameter(Mandatory=$false)]
[string]$SearchString = ""
)
# Reset the visibility if the search string is empty or the search is cleared
if ([string]::IsNullOrWhiteSpace($SearchString)) {
$sync.ItemsControl.Items | ForEach-Object {
$_.Visibility = [Windows.Visibility]::Visible
$_.Children | ForEach-Object {
if ($null -ne $_) {
$_.Visibility = [Windows.Visibility]::Visible
}
}
}
return
}
$sync.ItemsControl.Items | ForEach-Object {
# Ensure ToggleButtons remain visible
if ($_.Tag -like "CategoryToggleButton") {
$_.Visibility = [Windows.Visibility]::Visible
return
}
# Hide all CategoryWrapPanel and ToggleButton
$_.Visibility = [Windows.Visibility]::Collapsed
if ($_.Tag -like "CategoryWrapPanel_*") {
# Search for Apps that match the search string
$_.Children | Foreach-Object {
$appEntry = $sync.configs.applicationsHashtable.$($_.Tag)
if ($appEntry.Content -like "*$SearchString*" -or $appEntry.Description -like "*$SearchString*") {
# Show the App and the parent CategoryWrapPanel if the string is found
$_.Visibility = [Windows.Visibility]::Visible
$_.parent.Visibility = [Windows.Visibility]::Visible
}
else {
$_.Visibility = [Windows.Visibility]::Collapsed
}
}
}
}
}

View File

@ -0,0 +1,100 @@
function Find-TweaksByNameOrDescription {
<#
.SYNOPSIS
Searches through the Tweaks on the Tweaks Tab and hides all entries that do not match the search string
.PARAMETER SearchString
The string to be searched for
#>
param(
[Parameter(Mandatory=$false)]
[string]$SearchString = ""
)
# Reset the visibility if the search string is empty or the search is cleared
if ([string]::IsNullOrWhiteSpace($SearchString)) {
# Show all categories
$tweakspanel = $sync.Form.FindName("tweakspanel")
$tweakspanel.Children | ForEach-Object {
$_.Visibility = [Windows.Visibility]::Visible
# Foreach category section, show all items
if ($_ -is [Windows.Controls.Border]) {
$_.Visibility = [Windows.Visibility]::Visible
# Find ItemsControl
$dockPanel = $_.Child
if ($dockPanel -is [Windows.Controls.DockPanel]) {
$itemsControl = $dockPanel.Children | Where-Object { $_ -is [Windows.Controls.ItemsControl] }
if ($itemsControl) {
# Show items in the category
foreach ($item in $itemsControl.Items) {
if ($item -is [Windows.Controls.Label]) {
$item.Visibility = [Windows.Visibility]::Visible
} elseif ($item -is [Windows.Controls.DockPanel] -or
$item -is [Windows.Controls.StackPanel]) {
$item.Visibility = [Windows.Visibility]::Visible
}
}
}
}
}
}
return
}
# Search for matching tweaks when search string is not null
$tweakspanel = $sync.Form.FindName("tweakspanel")
$tweakspanel.Children | ForEach-Object {
$categoryBorder = $_
$categoryVisible = $false
if ($_ -is [Windows.Controls.Border]) {
# Find the ItemsControl
$dockPanel = $_.Child
if ($dockPanel -is [Windows.Controls.DockPanel]) {
$itemsControl = $dockPanel.Children | Where-Object { $_ -is [Windows.Controls.ItemsControl] }
if ($itemsControl) {
$categoryLabel = $null
# Process all items in the ItemsControl
for ($i = 0; $i -lt $itemsControl.Items.Count; $i++) {
$item = $itemsControl.Items[$i]
if ($item -is [Windows.Controls.Label]) {
$categoryLabel = $item
$item.Visibility = [Windows.Visibility]::Collapsed
} elseif ($item -is [Windows.Controls.DockPanel]) {
$checkbox = $item.Children | Where-Object { $_ -is [Windows.Controls.CheckBox] } | Select-Object -First 1
$label = $item.Children | Where-Object { $_ -is [Windows.Controls.Label] } | Select-Object -First 1
if ($label -and ($label.Content -like "*$SearchString*" -or $label.ToolTip -like "*$SearchString*")) {
$item.Visibility = [Windows.Visibility]::Visible
if ($categoryLabel) { $categoryLabel.Visibility = [Windows.Visibility]::Visible }
$categoryVisible = $true
} else {
$item.Visibility = [Windows.Visibility]::Collapsed
}
} elseif ($item -is [Windows.Controls.StackPanel]) {
# StackPanel which contain checkboxes or other elements
$checkbox = $item.Children | Where-Object { $_ -is [Windows.Controls.CheckBox] } | Select-Object -First 1
if ($checkbox -and ($checkbox.Content -like "*$SearchString*" -or $checkbox.ToolTip -like "*$SearchString*")) {
$item.Visibility = [Windows.Visibility]::Visible
if ($categoryLabel) { $categoryLabel.Visibility = [Windows.Visibility]::Visible }
$categoryVisible = $true
} else {
$item.Visibility = [Windows.Visibility]::Collapsed
}
}
}
}
}
# Set the visibility based on if any item matched
$categoryBorder.Visibility = if ($categoryVisible) { [Windows.Visibility]::Visible } else { [Windows.Visibility]::Collapsed }
}
}
}

View File

@ -0,0 +1,59 @@
function Get-WinUtilSelectedPackages
{
<#
.SYNOPSIS
Sorts given packages based on installer preference and availability.
.OUTPUTS
Hashtable. Key = Package Manager, Value = ArrayList of packages to install
#>
param (
[Parameter(Mandatory=$true)]
$PackageList,
[Parameter(Mandatory=$true)]
[PackageManagers]$Preference
)
if ($PackageList.count -eq 1) {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" })
} else {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" })
}
$packages = [System.Collections.Hashtable]::new()
$packagesWinget = [System.Collections.ArrayList]::new()
$packagesChoco = [System.Collections.ArrayList]::new()
$packages[[PackageManagers]::Winget] = $packagesWinget
$packages[[PackageManagers]::Choco] = $packagesChoco
Write-Debug "Checking packages using Preference '$($Preference)'"
foreach ($package in $PackageList) {
switch ($Preference) {
"Choco" {
if ($package.choco -eq "na") {
Write-Debug "$($package.content) has no Choco value."
$packagesWinget.add($package.winget)
Write-Host "Queueing $($package.winget) for Winget"
} else {
$null = $packagesChoco.add($package.choco)
Write-Host "Queueing $($package.choco) for Chocolatey"
}
break
}
"Winget" {
if ($package.winget -eq "na") {
Write-Debug "$($package.content) has no Winget value."
$packagesChoco.add($package.choco)
Write-Host "Queueing $($package.choco) for Chocolatey"
} else {
$null = $packagesWinget.add($($package.winget))
Write-Host "Queueing $($package.winget) for Winget"
}
break
}
}
}
return $packages
}

View File

@ -13,75 +13,66 @@ Function Get-WinUtilToggleStatus {
#>
Param($ToggleSwitch)
if($ToggleSwitch -eq "WPFToggleDarkMode") {
$app = (Get-ItemProperty -path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize').AppsUseLightTheme
$system = (Get-ItemProperty -path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize').SystemUsesLightTheme
return $app -eq 0 -and $system -eq 0
}
if($ToggleSwitch -eq "WPFToggleBingSearch") {
$bingsearch = (Get-ItemProperty -path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Search').BingSearchEnabled
return $bingsearch -ne 0
}
if($ToggleSwitch -eq "WPFToggleNumLock") {
$numlockvalue = (Get-ItemProperty -path 'HKCU:\Control Panel\Keyboard').InitialKeyboardIndicators
return $numlockvalue -eq 2
}
if($ToggleSwitch -eq "WPFToggleVerboseLogon") {
$VerboseStatusvalue = (Get-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System').VerboseStatus
return $VerboseStatusvalue -eq 1
}
if($ToggleSwitch -eq "WPFToggleShowExt") {
$hideextvalue = (Get-ItemProperty -path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced').HideFileExt
return $hideextvalue -eq 0
}
if($ToggleSwitch -eq "WPFToggleSnapWindow") {
$hidesnap = (Get-ItemProperty -path 'HKCU:\Control Panel\Desktop').WindowArrangementActive
return $hidesnap -ne 0
}
if($ToggleSwitch -eq "WPFToggleSnapFlyout") {
$hidesnap = (Get-ItemProperty -path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced').EnableSnapAssistFlyout
return $hidesnap -ne 0
}
if($ToggleSwitch -eq "WPFToggleSnapSuggestion") {
$hidesnap = (Get-ItemProperty -path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced').SnapAssist
return $hidesnap -ne 0
}
if($ToggleSwitch -eq "WPFToggleMouseAcceleration") {
$MouseSpeed = (Get-ItemProperty -path 'HKCU:\Control Panel\Mouse').MouseSpeed
$MouseThreshold1 = (Get-ItemProperty -path 'HKCU:\Control Panel\Mouse').MouseThreshold1
$MouseThreshold2 = (Get-ItemProperty -path 'HKCU:\Control Panel\Mouse').MouseThreshold2
return $MouseSpeed -eq 1 -and $MouseThreshold1 -eq 6 -and $MouseThreshold2 -eq 10
$ToggleSwitchReg = $sync.configs.tweaks.$ToggleSwitch.registry
try {
if (($ToggleSwitchReg.path -imatch "hku") -and !(Get-PSDrive -Name HKU -ErrorAction SilentlyContinue)) {
$null = (New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS)
if (Get-PSDrive -Name HKU -ErrorAction SilentlyContinue) {
Write-Debug "HKU drive created successfully"
} else {
Write-Debug "Failed to create HKU drive"
}
if($ToggleSwitch -eq "WPFToggleTaskbarSearch") {
$SearchButton = (Get-ItemProperty -path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Search").SearchboxTaskbarMode
return $SearchButton -ne 0
}
if ($ToggleSwitch -eq "WPFToggleStickyKeys") {
$StickyKeys = (Get-ItemProperty -path 'HKCU:\Control Panel\Accessibility\StickyKeys').Flags
return $StickyKeys -ne 58
}
if ($ToggleSwitch -eq "WPFToggleTaskView") {
$TaskView = (Get-ItemProperty -path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced').ShowTaskViewButton
return $TaskView -ne 0
} catch {
Write-Error "An error occurred regarding the HKU Drive: $_"
return $false
}
if ($ToggleSwitch -eq "WPFToggleHiddenFiles") {
$HiddenFiles = (Get-ItemProperty -path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced').Hidden
return $HiddenFiles -ne 0
if ($ToggleSwitchReg) {
$count = 0
foreach ($regentry in $ToggleSwitchReg) {
try {
if (!(Test-Path $regentry.Path)) {
New-Item -Path $regentry.Path -Force | Out-Null
}
$regstate = (Get-ItemProperty -path $regentry.Path).$($regentry.Name)
if ($regstate -eq $regentry.Value) {
$count += 1
Write-Debug "$($regentry.Name) is true (state: $regstate, value: $($regentry.Value), original: $($regentry.OriginalValue))"
} else {
Write-Debug "$($regentry.Name) is false (state: $regstate, value: $($regentry.Value), original: $($regentry.OriginalValue))"
}
if (!$regstate) {
switch ($regentry.DefaultState) {
"true" {
$regstate = $regentry.Value
$count += 1
}
"false" {
$regstate = $regentry.OriginalValue
}
default {
Write-Error "Entry for $($regentry.Name) does not exist and no DefaultState is defined."
$regstate = $regentry.OriginalValue
}
}
}
} catch {
Write-Error "An unexpected error occurred: $_"
}
}
if ($ToggleSwitch -eq "WPFToggleTaskbarWidgets") {
$TaskbarWidgets = (Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced").TaskBarDa
return $TaskbarWidgets -ne 0
if ($count -eq $ToggleSwitchReg.Count) {
Write-Debug "$($ToggleSwitchReg.Name) is true (count: $count)"
return $true
} else {
Write-Debug "$($ToggleSwitchReg.Name) is false (count: $count)"
return $false
}
if ($ToggleSwitch -eq "WPFToggleTaskbarAlignment") {
$TaskbarAlignment = (Get-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced").TaskbarAl
return $TaskbarAlignment -ne 0
}
if ($ToggleSwitch -eq "WPFToggleDetailedBSoD") {
$DetailedBSoD1 = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl').DisplayParameters
$DetailedBSoD2 = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl').DisableEmoticon
return !(($DetailedBSoD1 -eq 0) -or ($DetailedBSoD2 -eq 0) -or !$DetailedBSoD1 -or !$DetailedBSoD2)
} else {
return $false
}
}

View File

@ -1,26 +0,0 @@
function Get-WinUtilWingetLatest {
<#
.SYNOPSIS
Uses GitHub API to check for the latest release of Winget.
.DESCRIPTION
This function grabs the latest version of Winget and returns the download path to Install-WinUtilWinget for installation.
#>
# Invoke-WebRequest is notoriously slow when the byte progress is displayed. The following lines disable the progress bar and reset them at the end of the function
$PreviousProgressPreference = $ProgressPreference
$ProgressPreference = "silentlyContinue"
try {
# Grabs the latest release of Winget from the Github API for the install process.
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/microsoft/Winget-cli/releases/latest" -Method Get -ErrorAction Stop
$latestVersion = $response.tag_name #Stores version number of latest release.
$licenseWingetUrl = $response.assets.browser_download_url | Where-Object {$_ -like "*License1.xml"} #Index value for License file.
Write-Host "Latest Version:`t$($latestVersion)`n"
Write-Host "Downloading..."
$assetUrl = $response.assets.browser_download_url | Where-Object {$_ -like "*Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"}
Invoke-WebRequest -Uri $licenseWingetUrl -OutFile $ENV:TEMP\License1.xml
# The only pain is that the msixbundle for winget-cli is 246MB. In some situations this can take a bit, with slower connections.
Invoke-WebRequest -Uri $assetUrl -OutFile $ENV:TEMP\Microsoft.DesktopAppInstaller.msixbundle
} catch {
throw [WingetFailedInstall]::new('Failed to get latest Winget release and license')
}
$ProgressPreference = $PreviousProgressPreference
}

View File

@ -1,28 +0,0 @@
function Get-WinUtilWingetPrerequisites {
<#
.SYNOPSIS
Downloads the Winget Prereqs.
.DESCRIPTION
Downloads Prereqs for Winget. Version numbers are coded as variables and can be updated as uncommonly as Microsoft updates the prereqs.
#>
# I don't know of a way to detect the prereqs automatically, so if someone has a better way of defining these, that would be great.
# Microsoft.VCLibs version rarely changes, but for future compatibility I made it a variable.
$versionVCLibs = "14.00"
$fileVCLibs = "https://aka.ms/Microsoft.VCLibs.x64.${versionVCLibs}.Desktop.appx"
# Write-Host "$fileVCLibs"
# Microsoft.UI.Xaml version changed recently, so I made the version numbers variables.
$versionUIXamlMinor = "2.8"
$versionUIXamlPatch = "2.8.6"
$fileUIXaml = "https://github.com/microsoft/microsoft-ui-xaml/releases/download/v${versionUIXamlPatch}/Microsoft.UI.Xaml.${versionUIXamlMinor}.x64.appx"
# Write-Host "$fileUIXaml"
try {
Write-Host "Downloading Microsoft.VCLibs Dependency..."
Invoke-WebRequest -Uri $fileVCLibs -OutFile $ENV:TEMP\Microsoft.VCLibs.x64.Desktop.appx
Write-Host "Downloading Microsoft.UI.Xaml Dependency...`n"
Invoke-WebRequest -Uri $fileUIXaml -OutFile $ENV:TEMP\Microsoft.UI.Xaml.x64.appx
} catch {
throw [WingetFailedInstall]::new('Failed to install prerequsites')
}
}

View File

@ -0,0 +1,74 @@
function Initialize-InstallAppEntry {
<#
.SYNOPSIS
Creates the app entry to be placed on the isntall tab for a given app
Used to as part of the Install Tab UI generation
.PARAMETER TargetElement
The Element into which the Apps should be placed
.PARAMETER appKey
The Key of the app inside the $sync.configs.applicationsHashtable
#>
param(
[Windows.Controls.WrapPanel]$TargetElement,
$appKey
)
# Create the outer Border for the application type
$border = New-Object Windows.Controls.Border
$border.Style = $sync.Form.Resources.AppEntryBorderStyle
$border.Tag = $appKey
$border.ToolTip = $Apps.$appKey.description
$border.Add_MouseLeftButtonUp({
$childCheckbox = ($this.Child | Where-Object {$_.Template.TargetType -eq [System.Windows.Controls.Checkbox]})[0]
$childCheckBox.isChecked = -not $childCheckbox.IsChecked
})
$border.Add_MouseEnter({
if (($sync.$($this.Tag).IsChecked) -eq $false) {
$this.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallHighlightedColor")
}
})
$border.Add_MouseLeave({
if (($sync.$($this.Tag).IsChecked) -eq $false) {
$this.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor")
}
})
$border.Add_MouseRightButtonUp({
# Store the selected app in a global variable so it can be used in the popup
$sync.appPopupSelectedApp = $this.Tag
# Set the popup position to the current mouse position
$sync.appPopup.PlacementTarget = $this
$sync.appPopup.IsOpen = $true
})
$checkBox = New-Object Windows.Controls.CheckBox
$checkBox.Name = $appKey
$checkbox.Style = $sync.Form.Resources.AppEntryCheckboxStyle
$checkbox.Add_Checked({
Invoke-WPFSelectedAppsUpdate -type "Add" -checkbox $this
$borderElement = $this.Parent
$borderElement.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallSelectedColor")
})
$checkbox.Add_Unchecked({
Invoke-WPFSelectedAppsUpdate -type "Remove" -checkbox $this
$borderElement = $this.Parent
$borderElement.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor")
})
# Create the TextBlock for the application name
$appName = New-Object Windows.Controls.TextBlock
$appName.Style = $sync.Form.Resources.AppEntryNameStyle
$appName.Text = $Apps.$appKey.content
# Add the name to the Checkbox
$checkBox.Content = $appName
# Add accessibility properties to make the elements screen reader friendly
$checkBox.SetValue([Windows.Automation.AutomationProperties]::NameProperty, $Apps.$appKey.content)
$border.SetValue([Windows.Automation.AutomationProperties]::NameProperty, $Apps.$appKey.content)
$border.Child = $checkBox
# Add the border to the corresponding Category
$TargetElement.Children.Add($border) | Out-Null
return $checkbox
}

View File

@ -0,0 +1,45 @@
function Initialize-InstallAppArea {
<#
.SYNOPSIS
Creates a [Windows.Controls.ScrollViewer] containing a [Windows.Controls.ItemsControl] which is setup to use Virtualization to only load the visible elements for performance reasons.
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
.PARAMETER TargetElement
The element to which the AppArea shoud be added
#>
param($TargetElement)
$targetGrid = $sync.Form.FindName($TargetElement)
$null = $targetGrid.Children.Clear()
# Create the outer Border for the aren where the apps will be placed
$Border = New-Object Windows.Controls.Border
$Border.VerticalAlignment = "Stretch"
$Border.SetResourceReference([Windows.Controls.Control]::StyleProperty, "BorderStyle")
# Add a ScrollViewer, because the ItemsControl does not support scrolling by itself
$scrollViewer = New-Object Windows.Controls.ScrollViewer
$scrollViewer.VerticalScrollBarVisibility = 'Auto'
$scrollViewer.HorizontalAlignment = 'Stretch'
$scrollViewer.VerticalAlignment = 'Stretch'
$scrollViewer.CanContentScroll = $true
## Create the ItemsControl, which will be the parent of all the app entries
$itemsControl = New-Object Windows.Controls.ItemsControl
$itemsControl.HorizontalAlignment = 'Stretch'
$itemsControl.VerticalAlignment = 'Stretch'
# Enable virtualization for the ItemsControl to improve performance (It's hard to test if this is actually working, so if you know what you're doing, please check this)
$itemsPanelTemplate = New-Object Windows.Controls.ItemsPanelTemplate
$factory = New-Object Windows.FrameworkElementFactory ([Windows.Controls.VirtualizingStackPanel])
$itemsPanelTemplate.VisualTree = $factory
$itemsControl.ItemsPanel = $itemsPanelTemplate
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::IsVirtualizingProperty, $true)
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::VirtualizationModeProperty, [Windows.Controls.VirtualizationMode]::Recycling)
$scrollViewer.Content = $itemsControl
$Border.Child = $scrollViewer
$null = $targetGrid.Children.Add($Border)
return $itemsControl
}

View File

@ -0,0 +1,56 @@
function Initialize-InstallCategoryAppList {
<#
.SYNOPSIS
Clears the Target Element and sets up a "Loading" message. This is done, because loading of all apps can take a bit of time in some scenarios
Iterates through all Categories and Apps and adds them to the UI
Used to as part of the Install Tab UI generation
.PARAMETER TargetElement
The Element into which the Categories and Apps should be placed
.PARAMETER Apps
The Hashtable of Apps to be added to the UI
The Categories are also extracted from the Apps Hashtable
#>
param(
$TargetElement,
$Apps
)
function Add-Category {
param(
[string]$Category,
[Windows.Controls.ItemsControl]$TargetElement
)
$toggleButton = New-Object Windows.Controls.Label
$toggleButton.Content = "$Category"
$toggleButton.Tag = "CategoryToggleButton"
$sync.$Category = $Category
$null = $TargetElement.Items.Add($toggleButton)
}
# Pre-group apps by category
$appsByCategory = @{}
foreach ($appKey in $Apps.Keys) {
$category = $Apps.$appKey.Category
if (-not $appsByCategory.ContainsKey($category)) {
$appsByCategory[$category] = @()
}
$appsByCategory[$category] += $appKey
}
foreach ($category in $($appsByCategory.Keys | Sort-Object)) {
Add-Category -Category $category -TargetElement $TargetElement
$wrapPanel = New-Object Windows.Controls.WrapPanel
$wrapPanel.Orientation = "Horizontal"
$wrapPanel.HorizontalAlignment = "Stretch"
$wrapPanel.VerticalAlignment = "Center"
$wrapPanel.Margin = New-Object Windows.Thickness(0, 0, 0, 20)
$wrapPanel.Visibility = [Windows.Visibility]::Visible
$wrapPanel.Tag = "CategoryWrapPanel_$category"
$null = $TargetElement.Items.Add($wrapPanel)
$appsByCategory[$category] |Sort-Object | ForEach-Object {
$sync.$_ = $(Initialize-InstallAppEntry -TargetElement $wrapPanel -AppKey $_)
}
}
}

View File

@ -33,36 +33,44 @@ function Install-WinUtilWinget {
return
}
# Install Winget via GitHub method.
# Used part of my own script with some modification: ruxunderscore/windows-initialization
Write-Host "Downloading Winget Prerequsites`n"
Get-WinUtilWingetPrerequisites
Write-Host "Downloading Winget and License File`r"
Get-WinUtilWingetLatest
Write-Host "Installing Winget w/ Prerequsites`r"
Add-AppxProvisionedPackage -Online -PackagePath $ENV:TEMP\Microsoft.DesktopAppInstaller.msixbundle -DependencyPackagePath $ENV:TEMP\Microsoft.VCLibs.x64.Desktop.appx, $ENV:TEMP\Microsoft.UI.Xaml.x64.appx -LicensePath $ENV:TEMP\License1.xml
Write-Host "Manually adding Winget Sources, from Winget CDN."
Add-AppxPackage -Path https://cdn.winget.microsoft.com/cache/source.msix #Seems some installs of Winget don't add the repo source, this should makes sure that it's installed every time.
Write-Host "Winget Installed" -ForegroundColor Green
Write-Host "Enabling NuGet and Module..."
Install-PackageProvider -Name NuGet -Force
Install-Module -Name Microsoft.WinGet.Client -Force
# Winget only needs a refresh of the environment variables to be used.
Write-Output "Refreshing Environment Variables...`n"
$ENV:PATH = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
} catch {
Write-Host "Failure detected while installing via GitHub method. Continuing with Chocolatey method as fallback." -ForegroundColor Red
# In case install fails via GitHub method.
Write-Host "Attempting to install/update Winget`r"
try {
# Install Choco if not already present
Install-WinUtilChoco
Start-Process -Verb runas -FilePath powershell.exe -ArgumentList "choco install winget-cli"
Write-Host "Winget Installed" -ForegroundColor Green
$wingetCmd = Get-Command winget -ErrorAction Stop
Write-Information "Attempting to update WinGet using WinGet..."
$result = Start-Process -FilePath "`"$($wingetCmd.Source)`"" -ArgumentList "install -e --accept-source-agreements --accept-package-agreements Microsoft.AppInstaller" -Wait -NoNewWindow -PassThru
if ($result.ExitCode -ne 0) {
throw "WinGet update failed with exit code: $($result.ExitCode)"
}
Write-Output "Refreshing Environment Variables...`n"
$ENV:PATH = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
return
} catch {
throw [WingetFailedInstall]::new('Failed to install!')
Write-Information "WinGet not found or update failed. Attempting to install from Microsoft Store..."
}
try {
Write-Host "Attempting to repair WinGet using Repair-WinGetPackageManager..." -ForegroundColor Yellow
# Check if Windows version supports Repair-WinGetPackageManager (24H2 and above)
if ([System.Environment]::OSVersion.Version.Build -ge 26100) {
Repair-WinGetPackageManager -Force -Latest -Verbose
# Verify if repair was successful
$wingetCmd = Get-Command winget -ErrorAction Stop
Write-Host "WinGet repair successful!" -ForegroundColor Green
} else {
Write-Host "Repair-WinGetPackageManager is only available on Windows 24H2 and above. Your version doesn't support this method." -ForegroundColor Yellow
throw "Windows version not supported for repair method"
}
Write-Output "Refreshing Environment Variables...`n"
$ENV:PATH = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
return
} catch {
Write-Error "All installation methods failed. Unable to install WinGet."
throw
}
} catch {
Write-Error "An error occurred during WinGet installation: $_"
throw
}
}

View File

@ -1,30 +0,0 @@
function Invoke-WinUtilBingSearch {
<#
.SYNOPSIS
Disables/Enables Bing Search
.PARAMETER Enabled
Indicates whether to enable or disable Bing Search
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Bing Search"
$value = 1
} else {
Write-Host "Disabling Bing Search"
$value = 0
}
$Path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Search"
Set-ItemProperty -Path $Path -Name BingSearchEnabled -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -43,7 +43,7 @@ Function Invoke-WinUtilCurrentSystem {
if($CheckBox -eq "tweaks") {
if(!(Test-Path 'HKU:\')) {New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS}
if(!(Test-Path 'HKU:\')) {$null = (New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS)}
$ScheduledTasks = Get-ScheduledTask
$sync.configs.tweaks | Get-Member -MemberType NoteProperty | ForEach-Object {

View File

@ -1,37 +0,0 @@
Function Invoke-WinUtilDarkMode {
<#
.SYNOPSIS
Enables/Disables Dark Mode
.PARAMETER DarkMoveEnabled
Indicates the current dark mode state
#>
Param($DarkMoveEnabled)
try {
if ($DarkMoveEnabled -eq $false) {
Write-Host "Enabling Dark Mode"
$DarkMoveValue = 0
} else {
Write-Host "Disabling Dark Mode"
$DarkMoveValue = 1
}
$Path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize"
Set-ItemProperty -Path $Path -Name AppsUseLightTheme -Value $DarkMoveValue
Set-ItemProperty -Path $Path -Name SystemUsesLightTheme -Value $DarkMoveValue
Invoke-WinUtilExplorerRefresh
# Update Winutil Theme if the Theme Button shows the Icon for Auto
if ($sync.ThemeButton.Content -eq [char]0xF08C) {
Invoke-WinutilThemeChange -theme "Auto"
}
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,34 +0,0 @@
Function Invoke-WinUtilDetailedBSoD {
<#
.SYNOPSIS
Enables/Disables Detailed BSoD
(Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' -Name 'DisplayParameters').DisplayParameters
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Detailed BSoD"
$value = 1
} else {
Write-Host "Disabling Detailed BSoD"
$value =0
}
$Path = "HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl"
$dwords = ("DisplayParameters", "DisableEmoticon")
foreach ($name in $dwords) {
Set-ItemProperty -Path $Path -Name $name -Value $value
}
Set-ItemProperty -Path $Path -Name DisplayParameters -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,33 +0,0 @@
function Invoke-WinUtilExplorerRefresh {
<#
.SYNOPSIS
Refreshes the Windows Explorer
#>
Invoke-WPFRunspace -DebugPreference $DebugPreference -ScriptBlock {
# Send the WM_SETTINGCHANGE message to all windows
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
uint Msg,
IntPtr wParam,
string lParam,
uint fuFlags,
uint uTimeout,
out IntPtr lpdwResult);
}
"@
$HWND_BROADCAST = [IntPtr]0xffff
$WM_SETTINGCHANGE = 0x1A
$SMTO_ABORTIFHUNG = 0x2
$timeout = 100
# Send the broadcast message to all windows
[Win32]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [IntPtr]::Zero, "ImmersiveColorSet", $SMTO_ABORTIFHUNG, $timeout, [ref]([IntPtr]::Zero))
}
}

View File

@ -0,0 +1,43 @@
function Invoke-WinUtilExplorerUpdate {
<#
.SYNOPSIS
Refreshes the Windows Explorer
#>
param (
[string]$action = "refresh"
)
if ($action -eq "refresh") {
Invoke-WPFRunspace -DebugPreference $DebugPreference -ScriptBlock {
# Send the WM_SETTINGCHANGE message to all windows
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
uint Msg,
IntPtr wParam,
string lParam,
uint fuFlags,
uint uTimeout,
out IntPtr lpdwResult);
}
"@
$HWND_BROADCAST = [IntPtr]0xffff
$WM_SETTINGCHANGE = 0x1A
$SMTO_ABORTIFHUNG = 0x2
$timeout = 100
# Send the broadcast message to all windows
[Win32]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [IntPtr]::Zero, "ImmersiveColorSet", $SMTO_ABORTIFHUNG, $timeout, [ref]([IntPtr]::Zero))
}
} elseif ($action -eq "restart") {
# Restart the Windows Explorer
taskkill.exe /F /IM "explorer.exe"
Start-Process "explorer.exe"
}
}

View File

@ -1,30 +0,0 @@
function Invoke-WinUtilHiddenFiles {
<#
.SYNOPSIS
Enable/Disable Hidden Files
.PARAMETER Enabled
Indicates whether to enable or disable Hidden Files
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Hidden Files"
$value = 1
} else {
Write-Host "Disabling Hidden Files"
$value = 0
}
$Path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
Set-ItemProperty -Path $Path -Name Hidden -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,38 +0,0 @@
Function Invoke-WinUtilMouseAcceleration {
<#
.SYNOPSIS
Enables/Disables Mouse Acceleration
.PARAMETER DarkMoveEnabled
Indicates the current Mouse Acceleration State
#>
Param($MouseAccelerationEnabled)
try {
if ($MouseAccelerationEnabled -eq $false) {
Write-Host "Enabling Mouse Acceleration"
$MouseSpeed = 1
$MouseThreshold1 = 6
$MouseThreshold2 = 10
} else {
Write-Host "Disabling Mouse Acceleration"
$MouseSpeed = 0
$MouseThreshold1 = 0
$MouseThreshold2 = 0
}
$Path = "HKCU:\Control Panel\Mouse"
Set-ItemProperty -Path $Path -Name MouseSpeed -Value $MouseSpeed
Set-ItemProperty -Path $Path -Name MouseThreshold1 -Value $MouseThreshold1
Set-ItemProperty -Path $Path -Name MouseThreshold2 -Value $MouseThreshold2
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,31 +0,0 @@
function Invoke-WinUtilNumLock {
<#
.SYNOPSIS
Disables/Enables NumLock on startup
.PARAMETER Enabled
Indicates whether to enable or disable Numlock on startup
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Numlock on startup"
$value = 2
} else {
Write-Host "Disabling Numlock on startup"
$value = 0
}
New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS
$HKUPath = "HKU:\.Default\Control Panel\Keyboard"
$HKCUPath = "HKCU:\Control Panel\Keyboard"
Set-ItemProperty -Path $HKUPath -Name InitialKeyboardIndicators -Value $value
Set-ItemProperty -Path $HKCUPath -Name InitialKeyboardIndicators -Value $value
}
Catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,27 +0,0 @@
function Invoke-WinUtilShowExt {
<#
.SYNOPSIS
Disables/Enables Show file Extentions
.PARAMETER Enabled
Indicates whether to enable or disable Show file extentions
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Showing file extentions"
$value = 0
} else {
Write-Host "hiding file extensions"
$value = 1
}
$Path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
Set-ItemProperty -Path $Path -Name HideFileExt -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,30 +0,0 @@
function Invoke-WinUtilSnapFlyout {
<#
.SYNOPSIS
Disables/Enables Snap Assist Flyout on startup
.PARAMETER Enabled
Indicates whether to enable or disable Snap Assist Flyout on startup
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Snap Assist Flyout On startup"
$value = 1
} else {
Write-Host "Disabling Snap Assist Flyout On startup"
$value = 0
}
$Path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
taskkill.exe /F /IM "explorer.exe"
Set-ItemProperty -Path $Path -Name EnableSnapAssistFlyout -Value $value
Start-Process "explorer.exe"
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,30 +0,0 @@
function Invoke-WinUtilSnapSuggestion {
<#
.SYNOPSIS
Disables/Enables Snap Assist Suggestions on startup
.PARAMETER Enabled
Indicates whether to enable or disable Snap Assist Suggestions on startup
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Snap Assist Suggestion On startup"
$value = 1
} else {
Write-Host "Disabling Snap Assist Suggestion On startup"
$value = 0
}
# taskkill.exe /F /IM "explorer.exe"
$Path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
taskkill.exe /F /IM "explorer.exe"
Set-ItemProperty -Path $Path -Name SnapAssist -Value $value
Start-Process "explorer.exe"
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,27 +0,0 @@
function Invoke-WinUtilSnapWindow {
<#
.SYNOPSIS
Disables/Enables Snapping Windows on startup
.PARAMETER Enabled
Indicates whether to enable or disable Snapping Windows on startup
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Snap Windows On startup | Relogin Required"
$value = 1
} else {
Write-Host "Disabling Snap Windows On startup | Relogin Required"
$value = 0
}
$Path = "HKCU:\Control Panel\Desktop"
Set-ItemProperty -Path $Path -Name WindowArrangementActive -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,27 +0,0 @@
Function Invoke-WinUtilStickyKeys {
<#
.SYNOPSIS
Disables/Enables Sticky Keyss on startup
.PARAMETER Enabled
Indicates whether to enable or disable Sticky Keys on startup
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Sticky Keys On startup"
$value = 510
} else {
Write-Host "Disabling Sticky Keys On startup"
$value = 58
}
$Path = "HKCU:\Control Panel\Accessibility\StickyKeys"
Set-ItemProperty -Path $Path -Name Flags -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,30 +0,0 @@
function Invoke-WinUtilTaskView {
<#
.SYNOPSIS
Enable/Disable Task View
.PARAMETER Enabled
Indicates whether to enable or disable Task View
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Task View"
$value = 1
} else {
Write-Host "Disabling Task View"
$value = 0
}
$Path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
Set-ItemProperty -Path $Path -Name ShowTaskViewButton -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,30 +0,0 @@
function Invoke-WinUtilTaskbarAlignment {
<#
.SYNOPSIS
Switches between Center & Left Taskbar Alignment
.PARAMETER Enabled
Indicates whether to make Taskbar Alignment Center or Left
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Making Taskbar Alignment to the Center"
$value = 1
} else {
Write-Host "Making Taskbar Alignment to the Left"
$value = 0
}
$Path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
Set-ItemProperty -Path $Path -Name "TaskbarAl" -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,30 +0,0 @@
function Invoke-WinUtilTaskbarSearch {
<#
.SYNOPSIS
Enable/Disable Taskbar Search Button.
.PARAMETER Enabled
Indicates whether to enable or disable Taskbar Search Button.
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Search Button"
$value = 1
} else {
Write-Host "Disabling Search Button"
$value = 0
}
$Path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Search\"
Set-ItemProperty -Path $Path -Name SearchboxTaskbarMode -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,30 +0,0 @@
function Invoke-WinUtilTaskbarWidgets {
<#
.SYNOPSIS
Enable/Disable Taskbar Widgets
.PARAMETER Enabled
Indicates whether to enable or disable Taskbar Widgets
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Taskbar Widgets"
$value = 1
} else {
Write-Host "Disabling Taskbar Widgets"
$value = 0
}
$Path = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
Set-ItemProperty -Path $Path -Name TaskbarDa -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -21,6 +21,10 @@ function Invoke-WinUtilTweaks {
$KeepServiceStartup = $true
)
if ($Checkbox -contains "Toggle") {
$CheckBox = $sync.configs.tweaks.$CheckBox
}
Write-Debug "Tweaks: $($CheckBox)"
if($undo) {
$Values = @{
@ -73,6 +77,14 @@ function Invoke-WinUtilTweaks {
if($sync.configs.tweaks.$CheckBox.registry) {
$sync.configs.tweaks.$CheckBox.registry | ForEach-Object {
Write-Debug "$($psitem.Name) and state is $($psitem.$($values.registry))"
if (($psitem.Path -imatch "hku") -and !(Get-PSDrive -Name HKU -ErrorAction SilentlyContinue)) {
$null = (New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS)
if (Get-PSDrive -Name HKU -ErrorAction SilentlyContinue) {
Write-Debug "HKU drive created successfully"
} else {
Write-Debug "Failed to create HKU drive"
}
}
Set-WinUtilRegistry -Name $psitem.Name -Path $psitem.Path -Type $psitem.Type -Value $psitem.$($values.registry)
}
}

View File

@ -38,6 +38,32 @@ function Invoke-WinUtilUninstallPSProfile {
if (-not $Fonts) {
Write-Host "===> Successfully Uninstalled: Nerd Fonts. <===" -ForegroundColor Yellow
}
}
# Helper function used to uninstall a specific Nerd Fonts font corresponding registry keys.
function Uninstall-NerdFontRegKeys {
# Define the parameters block for the Uninstall-NerdFontsRegKey function.
param (
[string]$FontsRegPath = "HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts",
[string]$FontFamilyName = "CaskaydiaCove"
)
try {
# Get all properties (font registrations) from the registry path
$registryProperties = Get-ItemProperty -Path $FontsRegPath
# Filter and remove properties that match the font family name
$registryProperties.PSObject.Properties |
Where-Object { $_.Name -match $FontFamilyName } |
ForEach-Object {
If ($_.Name -like "*$FontFamilyName*") {
Remove-ItemProperty -path $FontsRegPath -Name $_.Name -ErrorAction SilentlyContinue
}
}
} catch {
Write-Host "Error removing registry keys: $($_.exception.message)" -ForegroundColor Red
}
}
# Check if Chris Titus Tech's PowerShell profile is currently available in the PowerShell profile folder.
@ -87,11 +113,28 @@ function Invoke-WinUtilUninstallPSProfile {
# Call the function used to uninstall the specified Nerd Fonts package from the system.
Uninstall-NerdFonts -FontsPath $FontsPath -FontFamilyName $FontFamilyName
} catch {
# Let the user know that an error was encountered when uninstalling Nerd Fonts.
Write-Host "Failed to uninstall Nerd Fonts. Error: $_" -ForegroundColor Red
}
# Attempt to uninstall the specified Nerd Fonts registry keys from the system.
try {
# Specify the registry path that the specified font registry keys will be uninstalled from.
[string]$FontsRegPath = "HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"
# Specify the name of the font registry keys that is to be uninstalled from the system.
[string]$FontFamilyName = "CaskaydiaCove"
# Call the function used to uninstall the specified Nerd Fonts registry keys from the system.
Uninstall-NerdFontRegKeys -FontsPath $FontsRegPath -FontFamilyName $FontFamilyName
} catch {
# Let the user know that an error was encountered when uninstalling Nerd Font registry keys.
Write-Host "Failed to uninstall Nerd Font Registry Keys. Error: $_" -ForegroundColor Red
}
# Attempt to uninstall the Terminal-Icons PowerShell module from the system.
try {
# Get the content of the backup PowerShell profile and store it in-memory.
@ -185,3 +228,4 @@ function Invoke-WinUtilUninstallPSProfile {
}
}
}

View File

@ -1,27 +0,0 @@
function Invoke-WinUtilVerboseLogon {
<#
.SYNOPSIS
Disables/Enables VerboseLogon Messages
.PARAMETER Enabled
Indicates whether to enable or disable VerboseLogon messages
#>
Param($Enabled)
try {
if ($Enabled -eq $false) {
Write-Host "Enabling Verbose Logon Messages"
$value = 1
} else {
Write-Host "Disabling Verbose Logon Messages"
$value = 0
}
$Path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
Set-ItemProperty -Path $Path -Name VerboseStatus -Value $value
} catch [System.Security.SecurityException] {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace
}
}

View File

@ -1,50 +0,0 @@
function Invoke-WinUtilpsProfile {
<#
.SYNOPSIS
Installs & applies the CTT Powershell Profile
#>
Invoke-WPFRunspace -Argumentlist $PROFILE -DebugPreference $DebugPreference -ScriptBlock {
param ( $psprofile)
function Invoke-PSSetup {
$url = "https://raw.githubusercontent.com/ChrisTitusTech/powershell-profile/main/Microsoft.PowerShell_profile.ps1"
$oldhash = Get-FileHash $psprofile -ErrorAction SilentlyContinue
Invoke-RestMethod $url -OutFile "$env:temp/Microsoft.PowerShell_profile.ps1"
$newhash = Get-FileHash "$env:temp/Microsoft.PowerShell_profile.ps1"
if ($newhash.Hash -ne $oldhash.Hash) {
write-host "===> Installing Profile.. <===" -ForegroundColor Yellow
# Starting new hidden shell process bc setup does not work in a runspace
Start-Process -FilePath "pwsh" -ArgumentList "-ExecutionPolicy Bypass -NoProfile -Command `"Invoke-Expression (Invoke-WebRequest `'https://github.com/ChrisTitusTech/powershell-profile/raw/main/setup.ps1`')`"" -WindowStyle Hidden -Wait
Write-Host "Profile has been installed. Please restart your shell to reflect changes!" -ForegroundColor Magenta
write-host "===> Finished <===" -ForegroundColor Yellow
} else {
Write-Host "Profile is up to date" -ForegroundColor Green
}
}
if (Get-Command "pwsh" -ErrorAction SilentlyContinue) {
if ($PSVersionTable.PSVersion.Major -ge 7) {
Invoke-PSSetup
}
else {
write-host "Profile requires Powershell 7, which is currently installed but not used!" -ForegroundColor Red
# Load the necessary assembly for Windows Forms
Add-Type -AssemblyName System.Windows.Forms
# Display the Yes/No message box
$question = [System.Windows.Forms.MessageBox]::Show("Profile requires Powershell 7, which is currently installed but not used! Do you want to install Profile for Powershell 7?", "Question",
[System.Windows.Forms.MessageBoxButtons]::YesNo,
[System.Windows.Forms.MessageBoxIcon]::Question)
# Check the result
if ($question -eq [System.Windows.Forms.DialogResult]::Yes) {
Invoke-PSSetup
}
else {
Write-Host "Not proceeding with the profile setup!"
}
}
}
else {
write-host "Profile requires Powershell 7, which is not installed!" -ForegroundColor Red
}
}
}

View File

@ -0,0 +1,43 @@
function Set-PackageManagerPreference {
<#
.SYNOPSIS
Sets the currently selected package manager to global "ManagerPreference" in sync.
Also persists preference across Winutil restarts via preference.ini.
Reads from preference.ini if no argument sent.
.PARAMETER preferedPackageManager
The PackageManager that was selected.
#>
param(
[Parameter(Position=0, Mandatory=$false)]
[PackageManagers]$preferedPackageManager
)
$preferencePath = "$env:LOCALAPPDATA\winutil\preferences.ini"
$oldChocoPath = "$env:LOCALAPPDATA\winutil\preferChocolatey.ini"
#Try loading from file if no argument given.
if ($null -eq $preferedPackageManager) {
# Backwards compat for preferChocolatey.ini
if (Test-Path -Path $oldChocoPath) {
$preferedPackageManager = [PackageManagers]::Choco
Remove-Item -Path $oldChocoPath
}
elseif (Test-Path -Path $preferencePath) {
$potential = Get-Content -Path $preferencePath -TotalCount 1
$preferedPackageManager = [PackageManagers]$potential
}
else {
Write-Debug "Creating new preference file, defaulting to winget."
$preferedPackageManager = [PackageManagers]::Winget
}
}
$sync["ManagerPreference"] = [PackageManagers]::$preferedPackageManager
Write-Debug "Manager Preference changed to '$($sync["ManagerPreference"])'"
# Write preference to file to persist across restarts.
Out-File -FilePath $preferencePath -InputObject $sync["ManagerPreference"]
}

View File

@ -47,6 +47,8 @@ function Set-WinUtilRegistry {
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
} catch [System.Management.Automation.ItemNotFoundException] {
Write-Warning $psitem.Exception.ErrorRecord
} catch [System.UnauthorizedAccessException] {
Write-Warning $psitem.Exception.Message
} catch {
Write-Warning "Unable to set $Name due to unhandled exception"
Write-Warning $psitem.Exception.StackTrace

View File

@ -6,6 +6,9 @@ function Show-CustomDialog {
.DESCRIPTION
This function creates a custom dialog box with the specified message and additional elements such as an image, heading, and an OK button. The dialog box is designed with a green border, rounded corners, and a black background.
.PARAMETER Title
The Title to use for the dialog window's Title Bar, this will not be visible by the user, as window styling is set to None.
.PARAMETER Message
The message to be displayed in the dialog box.
@ -16,60 +19,102 @@ function Show-CustomDialog {
The height of the custom dialog window.
.PARAMETER FontSize
The Font Size for text shown inside the custom dialog window.
The Font Size of message shown inside custom dialog window.
.PARAMETER HeaderFontSize
The Font Size for the Header of the custom dialog window.
The Font Size for the Header of custom dialog window.
.PARAMETER IconSize
The Size to use for Icon inside the custom dialog window.
.PARAMETER LogoSize
The Size of the Logo used inside the custom dialog window.
.PARAMETER ForegroundColor
The Foreground Color of dialog window title & message.
.PARAMETER BackgroundColor
The Background Color of dialog window.
.PARAMETER BorderColor
The Color for dialog window border.
.PARAMETER ButtonBackgroundColor
The Background Color for Buttons in dialog window.
.PARAMETER ButtonForegroundColor
The Foreground Color for Buttons in dialog window.
.PARAMETER ShadowColor
The Color used when creating the Drop-down Shadow effect for dialog window.
.PARAMETER LogoColor
The Color of WinUtil Text found next to WinUtil's Logo inside dialog window.
.PARAMETER LinkForegroundColor
The Foreground Color for Links inside dialog window.
.PARAMETER LinkHoverForegroundColor
The Foreground Color for Links when the mouse pointer hovers over them inside dialog window.
.PARAMETER EnableScroll
A flag indicating whether to enable scrolling if the content exceeds the window size.
.EXAMPLE
Show-CustomDialog -Message "This is a custom dialog with a message and an image above." -Width 300 -Height 200
Show-CustomDialog -Title "My Custom Dialog" -Message "This is a custom dialog with a message and an image above." -Width 300 -Height 200
Makes a new Custom Dialog with the title 'My Custom Dialog' and a message 'This is a custom dialog with a message and an image above.', with dimensions of 300 by 200 pixels.
Other styling options are grabbed from '$sync.Form.Resources' global variable.
.EXAMPLE
$foregroundColor = New-Object System.Windows.Media.SolidColorBrush("#0088e5")
$backgroundColor = New-Object System.Windows.Media.SolidColorBrush("#1e1e1e")
$linkForegroundColor = New-Object System.Windows.Media.SolidColorBrush("#0088e5")
$linkHoverForegroundColor = New-Object System.Windows.Media.SolidColorBrush("#005289")
Show-CustomDialog -Title "My Custom Dialog" -Message "This is a custom dialog with a message and an image above." -Width 300 -Height 200 -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor -LinkForegroundColor $linkForegroundColor -LinkHoverForegroundColor $linkHoverForegroundColor
Makes a new Custom Dialog with the title 'My Custom Dialog' and a message 'This is a custom dialog with a message and an image above.', with dimensions of 300 by 200 pixels, with a link foreground (and general foreground) colors of '#0088e5', background color of '#1e1e1e', and Link Color on Hover of '005289', all of which are in Hexadecimal (the '#' Symbol is required by SolidColorBrush Constructor).
Other styling options are grabbed from '$sync.Form.Resources' global variable.
#>
param(
[string]$Title,
[string]$Message,
[int]$Width = $sync.Form.Resources.CustomDialogWidth,
[int]$Height = $sync.Form.Resources.CustomDialogHeight,
[System.Windows.Media.FontFamily]$FontFamily = $sync.Form.Resources.FontFamily,
[int]$FontSize = $sync.Form.Resources.CustomDialogFontSize,
[int]$HeaderFontSize = $sync.Form.Resources.CustomDialogFontSizeHeader,
[int]$IconSize = $sync.Form.Resources.CustomDialogLogoSize,
[int]$LogoSize = $sync.Form.Resources.CustomDialogLogoSize,
[System.Windows.Media.Color]$ShadowColor = "#AAAAAAAA",
[System.Windows.Media.SolidColorBrush]$LogoColor = $sync.Form.Resources.LabelboxForegroundColor,
[System.Windows.Media.SolidColorBrush]$BorderColor = $sync.Form.Resources.BorderColor,
[System.Windows.Media.SolidColorBrush]$ForegroundColor = $sync.Form.Resources.MainForegroundColor,
[System.Windows.Media.SolidColorBrush]$BackgroundColor = $sync.Form.Resources.MainBackgroundColor,
[System.Windows.Media.SolidColorBrush]$ButtonForegroundColor = $sync.Form.Resources.ButtonInstallForegroundColor,
[System.Windows.Media.SolidColorBrush]$ButtonBackgroundColor = $sync.Form.Resources.ButtonInstallBackgroundColor,
[System.Windows.Media.SolidColorBrush]$LinkForegroundColor = $sync.Form.Resources.LinkForegroundColor,
[System.Windows.Media.SolidColorBrush]$LinkHoverForegroundColor = $sync.Form.Resources.LinkHoverForegroundColor,
[bool]$EnableScroll = $false
)
Add-Type -AssemblyName PresentationFramework
# Define theme colors
$foregroundColor = $sync.Form.Resources.MainForegroundColor
$backgroundColor = $sync.Form.Resources.MainBackgroundColor
$font = New-Object Windows.Media.FontFamily("Consolas")
$borderColor = $sync.Form.Resources.BorderColor # ButtonInstallBackgroundColor
$buttonBackgroundColor = $sync.Form.Resources.ButtonInstallBackgroundColor
$buttonForegroundColor = $sync.Form.Resources.ButtonInstallForegroundColor
$shadowColor = [Windows.Media.ColorConverter]::ConvertFromString("#AAAAAAAA")
$logocolor = $sync.Form.Resources.LabelboxForegroundColor
# Create a custom dialog window
$dialog = New-Object Windows.Window
$dialog.Title = "About"
$dialog.Title = $Title
$dialog.Height = $Height
$dialog.Width = $Width
$dialog.Margin = New-Object Windows.Thickness(10) # Add margin to the entire dialog box
$dialog.WindowStyle = [Windows.WindowStyle]::None # Remove title bar and window controls
$dialog.ResizeMode = [Windows.ResizeMode]::NoResize # Disable resizing
$dialog.WindowStartupLocation = [Windows.WindowStartupLocation]::CenterScreen # Center the window
$dialog.Foreground = $foregroundColor
$dialog.Background = $backgroundColor
$dialog.FontFamily = $font
$dialog.Foreground = $ForegroundColor
$dialog.Background = $BackgroundColor
$dialog.FontFamily = $FontFamily
$dialog.FontSize = $FontSize
# Create a Border for the green edge with rounded corners
$border = New-Object Windows.Controls.Border
$border.BorderBrush = $borderColor
$border.BorderBrush = $BorderColor
$border.BorderThickness = New-Object Windows.Thickness(1) # Adjust border thickness as needed
$border.CornerRadius = New-Object Windows.CornerRadius(10) # Adjust the radius for rounded corners
@ -89,7 +134,7 @@ function Show-CustomDialog {
$grid = New-Object Windows.Controls.Grid
$border.Child = $grid
# Add the following line to show gridlines
# Uncomment the following line to show gridlines
#$grid.ShowGridLines = $true
# Add the following line to set the background color of the grid
@ -102,7 +147,6 @@ function Show-CustomDialog {
$border.HorizontalAlignment = [Windows.HorizontalAlignment]::Stretch
$border.VerticalAlignment = [Windows.VerticalAlignment]::Stretch
# Set up Row Definitions
$row0 = New-Object Windows.Controls.RowDefinition
$row0.Height = [Windows.GridLength]::Auto
@ -129,17 +173,18 @@ function Show-CustomDialog {
[Windows.Controls.Grid]::SetRow($stackPanel, 0) # Set the row to the second row (0-based index)
# Add SVG path to the stack panel
$stackPanel.Children.Add((Invoke-WinUtilAssets -Type "logo" -Size 25))
$stackPanel.Children.Add((Invoke-WinUtilAssets -Type "logo" -Size $LogoSize))
# Add "Winutil" text
$winutilTextBlock = New-Object Windows.Controls.TextBlock
$winutilTextBlock.Text = "Winutil"
$winutilTextBlock.FontSize = $HeaderFontSize
$winutilTextBlock.Foreground = $logocolor
$winutilTextBlock.Foreground = $LogoColor
$winutilTextBlock.Margin = New-Object Windows.Thickness(10, 10, 10, 5) # Add margins around the text block
$stackPanel.Children.Add($winutilTextBlock)
# Add TextBlock for information with text wrapping and margins
$messageTextBlock = New-Object Windows.Controls.TextBlock
$messageTextBlock.FontSize = $FontSize
$messageTextBlock.TextWrapping = [Windows.TextWrapping]::Wrap # Enable text wrapping
$messageTextBlock.HorizontalAlignment = [Windows.HorizontalAlignment]::Left
$messageTextBlock.VerticalAlignment = [Windows.VerticalAlignment]::Top
@ -162,7 +207,7 @@ function Show-CustomDialog {
$hyperlink.NavigateUri = New-Object System.Uri($match.Groups[1].Value)
$hyperlink.Inlines.Add($match.Groups[2].Value)
$hyperlink.TextDecorations = [Windows.TextDecorations]::None # Remove underline
$hyperlink.Foreground = $sync.Form.Resources.LinkForegroundColor
$hyperlink.Foreground = $LinkForegroundColor
$hyperlink.Add_Click({
param($sender, $args)
@ -170,11 +215,15 @@ function Show-CustomDialog {
})
$hyperlink.Add_MouseEnter({
param($sender, $args)
$sender.Foreground = $sync.Form.Resources.LinkHoverForegroundColor
$sender.Foreground = $LinkHoverForegroundColor
$sender.FontSize = ($FontSize + ($FontSize / 4))
$sender.FontWeight = "SemiBold"
})
$hyperlink.Add_MouseLeave({
param($sender, $args)
$sender.Foreground = $sync.Form.Resources.LinkForegroundColor
$sender.Foreground = $LinkForegroundColor
$sender.FontSize = $FontSize
$sender.FontWeight = "Normal"
})
$messageTextBlock.Inlines.Add($hyperlink)
@ -218,7 +267,7 @@ function Show-CustomDialog {
$okButton.Margin = New-Object Windows.Thickness(0, 0, 0, 10)
$okButton.Background = $buttonBackgroundColor
$okButton.Foreground = $buttonForegroundColor
$okButton.BorderBrush = $borderColor
$okButton.BorderBrush = $BorderColor
$okButton.Add_Click({
$dialog.Close()
})

View File

@ -23,7 +23,15 @@ function Test-WinUtilPackageManager {
# Check if Winget is available while getting it's Version if it's available
$wingetExists = $true
try {
$wingetVersionFull = winget --version
$wingetInfo = winget --info
# Extract the package version from the output
$wingetVersionFull = ($wingetInfo | Select-String -Pattern 'Microsoft\.DesktopAppInstaller v\d+\.\d+\.\d+\.\d+').Matches.Value
if ($wingetVersionFull) {
$wingetVersionFull = $wingetVersionFull.Split(' ')[-1].TrimStart('v')
} else {
# Fallback in case the pattern isn't found
$wingetVersionFull = ($wingetInfo | Select-String -Pattern 'Package Manager v\d+\.\d+\.\d+').Matches.Value.Split(' ')[-1]
}
} catch [System.Management.Automation.CommandNotFoundException], [System.Management.Automation.ApplicationFailedException] {
Write-Warning "Winget was not found due to un-availablity reasons"
$wingetExists = $false
@ -48,13 +56,14 @@ function Test-WinUtilPackageManager {
# Check if Winget's Version is too old.
$wingetCurrentVersion = [System.Version]::Parse($wingetVersion.Trim('v'))
# Grabs the latest release of Winget from the Github API for version check process.
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/microsoft/Winget-cli/releases/latest" -Method Get -ErrorAction Stop
$wingetLatestVersion = [System.Version]::Parse(($response.tag_name).Trim('v')) #Stores version number of latest release.
$wingetOutdated = $wingetCurrentVersion -lt $wingetLatestVersion
$response = winget search -e Microsoft.AppInstaller --accept-source-agreements
$wingetLatestVersion = ($response | Select-String -Pattern '\d+\.\d+\.\d+\.\d+').Matches.Value
Write-Host "Latest Search Version: $wingetLatestVersion" -ForegroundColor White
Write-Host "Current Installed Version: $wingetCurrentVersion" -ForegroundColor White
$wingetOutdated = $wingetCurrentVersion -lt [System.Version]::Parse($wingetLatestVersion)
Write-Host "===========================================" -ForegroundColor Green
Write-Host "--- Winget is installed ---" -ForegroundColor Green
Write-Host "===========================================" -ForegroundColor Green
Write-Host "Version: $wingetVersionFull" -ForegroundColor White
if (!$wingetPreview) {
Write-Host " - Winget is a release version." -ForegroundColor Green

View File

@ -0,0 +1,120 @@
function Initialize-WPFUI {
[OutputType([void])]
param(
[Parameter(Mandatory)]
[string]$TargetGridName
)
switch ($TargetGridName) {
"appscategory"{
# TODO
# Switch UI generation of the sidebar to this function
# $sync.ItemsControl = Initialize-InstallAppArea -TargetElement $TargetGridName
# ...
# Create and configure a popup for displaying selected apps
$selectedAppsPopup = New-Object Windows.Controls.Primitives.Popup
$selectedAppsPopup.IsOpen = $false
$selectedAppsPopup.PlacementTarget = $sync.WPFselectedAppsButton
$selectedAppsPopup.Placement = [System.Windows.Controls.Primitives.PlacementMode]::Bottom
$selectedAppsPopup.AllowsTransparency = $true
# Style the popup with a border and background
$selectedAppsBorder = New-Object Windows.Controls.Border
$selectedAppsBorder.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "MainBackgroundColor")
$selectedAppsBorder.SetResourceReference([Windows.Controls.Control]::BorderBrushProperty, "MainForegroundColor")
$selectedAppsBorder.SetResourceReference([Windows.Controls.Control]::BorderThicknessProperty, "ButtonBorderThickness")
$selectedAppsBorder.Width = 200
$selectedAppsBorder.Padding = 5
$selectedAppsPopup.Child = $selectedAppsBorder
$sync.selectedAppsPopup = $selectedAppsPopup
# Add a stack panel inside the popup's border to organize its child elements
$sync.selectedAppsstackPanel = New-Object Windows.Controls.StackPanel
$selectedAppsBorder.Child = $sync.selectedAppsstackPanel
# Close selectedAppsPopup when mouse leaves both button and selectedAppsPopup
$sync.WPFselectedAppsButton.Add_MouseLeave({
if (-not $sync.selectedAppsPopup.IsMouseOver) {
$sync.selectedAppsPopup.IsOpen = $false
}
})
$selectedAppsPopup.Add_MouseLeave({
if (-not $sync.WPFselectedAppsButton.IsMouseOver) {
$sync.selectedAppsPopup.IsOpen = $false
}
})
# Creates the popup that is displayed when the user right-clicks on an app entry
# This popup contains buttons for installing, uninstalling, and viewing app information
$appPopup = New-Object Windows.Controls.Primitives.Popup
$appPopup.StaysOpen = $false
$appPopup.Placement = [System.Windows.Controls.Primitives.PlacementMode]::Bottom
$appPopup.AllowsTransparency = $true
# Store the popup globally so the position can be set later
$sync.appPopup = $appPopup
$appPopupStackPanel = New-Object Windows.Controls.StackPanel
$appPopupStackPanel.Orientation = "Horizontal"
$appPopupStackPanel.Add_MouseLeave({
$sync.appPopup.IsOpen = $false
})
$appPopup.Child = $appPopupStackPanel
$appButtons = @(
[PSCustomObject]@{ Name = "Install"; Icon = [char]0xE118 },
[PSCustomObject]@{ Name = "Uninstall"; Icon = [char]0xE74D },
[PSCustomObject]@{ Name = "Info"; Icon = [char]0xE946 }
)
foreach ($button in $appButtons) {
$newButton = New-Object Windows.Controls.Button
$newButton.Style = $sync.Form.Resources.AppEntryButtonStyle
$newButton.Content = $button.Icon
$appPopupStackPanel.Children.Add($newButton) | Out-Null
# Dynamically load the selected app object so the buttons can be reused and do not need to be created for each app
switch ($button.Name) {
"Install" {
$newButton.Add_MouseEnter({
$appObject = $sync.configs.applicationsHashtable.$($sync.appPopupSelectedApp)
$this.ToolTip = "Install or Upgrade $($appObject.content)"
})
$newButton.Add_Click({
$appObject = $sync.configs.applicationsHashtable.$($sync.appPopupSelectedApp)
Invoke-WPFInstall -PackagesToInstall $appObject
})
}
"Uninstall" {
$newButton.Add_MouseEnter({
$appObject = $sync.configs.applicationsHashtable.$($sync.appPopupSelectedApp)
$this.ToolTip = "Uninstall $($appObject.content)"
})
$newButton.Add_Click({
$appObject = $sync.configs.applicationsHashtable.$($sync.appPopupSelectedApp)
Invoke-WPFUnInstall -PackagesToUninstall $appObject
})
}
"Info" {
$newButton.Add_MouseEnter({
$appObject = $sync.configs.applicationsHashtable.$($sync.appPopupSelectedApp)
$this.ToolTip = "Open the application's website in your default browser`n$($appObject.link)"
})
$newButton.Add_Click({
$appObject = $sync.configs.applicationsHashtable.$($sync.appPopupSelectedApp)
Start-Process $appObject.link
})
}
}
}
}
"appspanel" {
$sync.ItemsControl = Initialize-InstallAppArea -TargetElement $TargetGridName
Initialize-InstallCategoryAppList -TargetElement $sync.ItemsControl -Apps $sync.configs.applicationsHashtable
}
default {
Write-Output "$TargetGridName not yet implemented"
}
}
}

View File

@ -33,7 +33,7 @@ function Invoke-WPFButton {
"WPFRemoveUltPerf" {Invoke-WPFUltimatePerformance -State "Disable"}
"WPFundoall" {Invoke-WPFundoall}
"WPFFeatureInstall" {Invoke-WPFFeatureInstall}
"WPFPanelDISM" {Invoke-WPFPanelDISM}
"WPFPanelDISM" {Invoke-WPFSystemRepair}
"WPFPanelAutologin" {Invoke-WPFPanelAutologin}
"WPFPanelcontrol" {Invoke-WPFControlPanel -Panel $button}
"WPFPanelnetwork" {Invoke-WPFControlPanel -Panel $button}
@ -43,7 +43,8 @@ function Invoke-WPFButton {
"WPFPanelprinter" {Invoke-WPFControlPanel -Panel $button}
"WPFPanelsystem" {Invoke-WPFControlPanel -Panel $button}
"WPFPaneluser" {Invoke-WPFControlPanel -Panel $button}
"WPFUpdatesdefault" {Invoke-WPFUpdatesdefault}
"WPFPanelGodMode" {Invoke-WPFControlPanel -Panel $button}
"WPFUpdatesdefault" {Invoke-WPFFixesUpdate}
"WPFFixesUpdate" {Invoke-WPFFixesUpdate}
"WPFFixesWinget" {Invoke-WPFFixesWinget}
"WPFRunAdobeCCCleanerTool" {Invoke-WPFRunAdobeCCCleanerTool}
@ -59,6 +60,7 @@ function Invoke-WPFButton {
"MicrowinScratchDirBT" {Invoke-ScratchDialog}
"WPFWinUtilInstallPSProfile" {Invoke-WinUtilInstallPSProfile}
"WPFWinUtilUninstallPSProfile" {Invoke-WinUtilUninstallPSProfile}
"WPFWinUtilSSHServer" {Invoke-WinUtilSSHServer}
"WPFWinUtilSSHServer" {Invoke-WPFSSHServer}
"WPFselectedAppsButton" {$sync.selectedAppsPopup.IsOpen = -not $sync.selectedAppsPopup.IsOpen}
}
}

View File

@ -19,5 +19,6 @@ function Invoke-WPFControlPanel {
"WPFPanelprinter" {Start-Process "shell:::{A8A91A66-3A7D-4424-8D24-04E180695C7A}"}
"WPFPanelsystem" {cmd /c sysdm.cpl}
"WPFPaneluser" {cmd /c "control userpasswords2"}
"WPFPanelGodMode" {Start-Process "shell:::{ED7BA470-8E54-465E-825C-99712043E01C}"}
}
}

View File

@ -6,19 +6,7 @@ function Invoke-WPFFixesUpdate {
Performs various tasks in an attempt to repair Windows Update
.DESCRIPTION
1. (Aggressive Only) Scans the system for corruption using chkdsk, SFC, and DISM
Steps:
1. Runs chkdsk /scan /perf
/scan - Runs an online scan on the volume
/perf - Uses more system resources to complete a scan as fast as possible
2. Runs SFC /scannow
/scannow - Scans integrity of all protected system files and repairs files with problems when possible
3. Runs DISM /Online /Cleanup-Image /RestoreHealth
/Online - Targets the running operating system
/Cleanup-Image - Performs cleanup and recovery operations on the image
/RestoreHealth - Scans the image for component store corruption and attempts to repair the corruption using Windows Update
4. Runs SFC /scannow
Ran twice in case DISM repaired SFC
1. (Aggressive Only) Scans the system for corruption using the Invoke-WPFSystemRepair function
2. Stops Windows Update Services
3. Remove the QMGR Data file, which stores BITS jobs
4. (Aggressive Only) Renames the DataStore and CatRoot2 folders
@ -46,104 +34,7 @@ function Invoke-WPFFixesUpdate {
Start-Sleep -Milliseconds 200
if ($Aggressive) {
# Scan system for corruption
Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Scanning for corruption..." -PercentComplete 0
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running chkdsk..." -PercentComplete 0
# 2>&1 redirects stdout, alowing iteration over the output
chkdsk.exe /scan /perf 2>&1 | ForEach-Object {
# Write stdout to the Verbose stream
Write-Verbose $_
# Get the index of the total percentage
$index = $_.IndexOf("Total:")
if (
# If the percent is found
($percent = try {(
$_.Substring(
$index + 6,
$_.IndexOf("%", $index) - $index - 6
)
).Trim()} catch {0}) `
<# And the current percentage is greater than the previous one #>`
-and $percent -gt $oldpercent
) {
# Update the progress bar
$oldpercent = $percent
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running chkdsk... ($percent%)" -PercentComplete $percent
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC..." -PercentComplete 0
$oldpercent = 0
# SFC has a bug when redirected which causes it to output only when the stdout buffer is full, causing the progress bar to move in chunks
sfc /scannow 2>&1 | ForEach-Object {
# Write stdout to the Verbose stream
Write-Verbose $_
# Filter for lines that contain a percentage that is greater than the previous one
if (
(
# Use a different method to get the percentage that accounts for SFC's Unicode output
[int]$percent = try {(
(
$_.Substring(
$_.IndexOf("n") + 2,
$_.IndexOf("%") - $_.IndexOf("n") - 2
).ToCharArray() | Where-Object {$_}
) -join ''
).TrimStart()} catch {0}
) -and $percent -gt $oldpercent
) {
# Update the progress bar
$oldpercent = $percent
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC... ($percent%)" -PercentComplete $percent
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running DISM..." -PercentComplete 0
$oldpercent = 0
DISM /Online /Cleanup-Image /RestoreHealth | ForEach-Object {
# Write stdout to the Verbose stream
Write-Verbose $_
# Filter for lines that contain a percentage that is greater than the previous one
if (
($percent = try {
[int]($_ -replace "\[" -replace "=" -replace " " -replace "%" -replace "\]")
} catch {0}) `
-and $percent -gt $oldpercent
) {
# Update the progress bar
$oldpercent = $percent
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running DISM... ($percent%)" -PercentComplete $percent
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC again..." -PercentComplete 0
$oldpercent = 0
sfc /scannow 2>&1 | ForEach-Object {
# Write stdout to the Verbose stream
Write-Verbose $_
# Filter for lines that contain a percentage that is greater than the previous one
if (
(
[int]$percent = try {(
(
$_.Substring(
$_.IndexOf("n") + 2,
$_.IndexOf("%") - $_.IndexOf("n") - 2
).ToCharArray() | Where-Object {$_}
) -join ''
).TrimStart()} catch {0}
) -and $percent -gt $oldpercent
) {
# Update the progress bar
$oldpercent = $percent
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC... ($percent%)" -PercentComplete $percent
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Completed" -PercentComplete 100
Invoke-WPFSystemRepair
}
@ -187,9 +78,9 @@ function Invoke-WPFFixesUpdate {
# Reset the Security Descriptors on the Windows Update Services
Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Resetting the WU Service Security Descriptors..." -PercentComplete 25
Write-Progress -Id 4 -ParentId 0 -Activity "Resetting the WU Service Security Descriptors" -Status "Resetting the BITS Security Descriptor..." -PercentComplete 0
Start-Process -NoNewWindow -FilePath "sc.exe" -ArgumentList "sdset", "bits", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)"
Start-Process -NoNewWindow -FilePath "sc.exe" -ArgumentList "sdset", "bits", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)" -Wait
Write-Progress -Id 4 -ParentId 0 -Activity "Resetting the WU Service Security Descriptors" -Status "Resetting the wuauserv Security Descriptor..." -PercentComplete 50
Start-Process -NoNewWindow -FilePath "sc.exe" -ArgumentList "sdset", "wuauserv", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)"
Start-Process -NoNewWindow -FilePath "sc.exe" -ArgumentList "sdset", "wuauserv", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)" -Wait
Write-Progress -Id 4 -ParentId 0 -Activity "Resetting the WU Service Security Descriptors" -Status "Completed" -PercentComplete 100
}
@ -221,19 +112,53 @@ function Invoke-WPFFixesUpdate {
if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate") {
Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Removing WSUS client settings..." -PercentComplete 60
Write-Progress -Id 6 -ParentId 0 -Activity "Removing WSUS client settings" -PercentComplete 0
Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "AccountDomainSid", "/f" -RedirectStandardError $true
Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "PingID", "/f" -RedirectStandardError $true
Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "SusClientId", "/f" -RedirectStandardError $true
Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "AccountDomainSid", "/f" -RedirectStandardError "NUL"
Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "PingID", "/f" -RedirectStandardError "NUL"
Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "SusClientId", "/f" -RedirectStandardError "NUL"
Write-Progress -Id 6 -ParentId 0 -Activity "Removing WSUS client settings" -Status "Completed" -PercentComplete 100
}
# Remove Group Policy Windows Update settings
Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Removing Group Policy Windows Update settings..." -PercentComplete 60
Write-Progress -Id 7 -ParentId 0 -Activity "Removing Group Policy Windows Update settings" -PercentComplete 0
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -Name "ExcludeWUDriversInQualityUpdate" -ErrorAction SilentlyContinue
Write-Host "Defaulting driver offering through Windows Update..."
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Device Metadata" -Name "PreventDeviceMetadataFromNetwork" -ErrorAction SilentlyContinue
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching" -Name "DontPromptForWindowsUpdate" -ErrorAction SilentlyContinue
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching" -Name "DontSearchWindowsUpdate" -ErrorAction SilentlyContinue
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DriverSearching" -Name "DriverUpdateWizardWuSearchEnabled" -ErrorAction SilentlyContinue
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" -Name "ExcludeWUDriversInQualityUpdate" -ErrorAction SilentlyContinue
Write-Host "Defaulting Windows Update automatic restart..."
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "NoAutoRebootWithLoggedOnUsers" -ErrorAction SilentlyContinue
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "AUPowerManagement" -ErrorAction SilentlyContinue
Write-Host "Clearing ANY Windows Update Policy settings..."
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Name "BranchReadinessLevel" -ErrorAction SilentlyContinue
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Name "DeferFeatureUpdatesPeriodInDays" -ErrorAction SilentlyContinue
Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" -Name "DeferQualityUpdatesPeriodInDays" -ErrorAction SilentlyContinue
Remove-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Policies" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKCU:\Software\Microsoft\WindowsSelfHost" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKCU:\Software\Policies" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\Software\Microsoft\Policies" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\WindowsStore\WindowsUpdate" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\Software\Microsoft\WindowsSelfHost" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\Software\Policies" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\Software\WOW6432Node\Microsoft\Policies" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Policies" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\WindowsStore\WindowsUpdate" -Recurse -Force -ErrorAction SilentlyContinue
Start-Process -NoNewWindow -FilePath "secedit" -ArgumentList "/configure", "/cfg", "$env:windir\inf\defltbase.inf", "/db", "defltbase.sdb", "/verbose" -Wait
Start-Process -NoNewWindow -FilePath "cmd.exe" -ArgumentList "/c RD /S /Q $env:WinDir\System32\GroupPolicyUsers" -Wait
Start-Process -NoNewWindow -FilePath "cmd.exe" -ArgumentList "/c RD /S /Q $env:WinDir\System32\GroupPolicy" -Wait
Start-Process -NoNewWindow -FilePath "gpupdate" -ArgumentList "/force" -Wait
Write-Progress -Id 7 -ParentId 0 -Activity "Removing Group Policy Windows Update settings" -Status "Completed" -PercentComplete 100
# Reset WinSock
Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Resetting WinSock..." -PercentComplete 65
Write-Progress -Id 7 -ParentId 0 -Activity "Resetting WinSock" -Status "Resetting WinSock..." -PercentComplete 0
Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winsock", "reset" -RedirectStandardOutput $true
Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winhttp", "reset", "proxy" -RedirectStandardOutput $true
Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "int", "ip", "reset" -RedirectStandardOutput $true
Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winsock", "reset"
Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winhttp", "reset", "proxy"
Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "int", "ip", "reset"
Write-Progress -Id 7 -ParentId 0 -Activity "Resetting WinSock" -Status "Completed" -PercentComplete 100
@ -262,7 +187,11 @@ function Invoke-WPFFixesUpdate {
# Force Windows Update to check for updates
Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Forcing discovery..." -PercentComplete 95
Write-Progress -Id 10 -ParentId 0 -Activity "Forcing discovery" -Status "Forcing discovery..." -PercentComplete 0
try {
(New-Object -ComObject Microsoft.Update.AutoUpdate).DetectNow()
} catch {
Write-Warning "Failed to create Windows Update COM object: $_"
}
Start-Process -NoNewWindow -FilePath "wuauclt" -ArgumentList "/resetauthorization", "/detectnow"
Write-Progress -Id 10 -ParentId 0 -Activity "Forcing discovery" -Status "Completed" -PercentComplete 100
Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Completed" -PercentComplete 100
@ -284,7 +213,7 @@ function Invoke-WPFFixesUpdate {
Write-Progress -Id 3 -Activity "Renaming/Removing Files" -Completed
Write-Progress -Id 4 -Activity "Resetting the WU Service Security Descriptors" -Completed
Write-Progress -Id 5 -Activity "Reregistering DLLs" -Completed
Write-Progress -Id 6 -Activity "Removing WSUS client settings" -Completed
Write-Progress -Id 6 -Activity "Removing Group Policy Windows Update settings" -Completed
Write-Progress -Id 7 -Activity "Resetting WinSock" -Completed
Write-Progress -Id 8 -Activity "Deleting BITS jobs" -Completed
Write-Progress -Id 9 -Activity "Starting Windows Update Services" -Completed

View File

@ -1,36 +0,0 @@
Function Invoke-WPFFormVariables {
<#
.SYNOPSIS
Prints the logo
#>
#If ($global:ReadmeDisplay -ne $true) { Write-Host "If you need to reference this display again, run Get-FormVariables" -ForegroundColor Yellow; $global:ReadmeDisplay = $true }
Write-Host ""
Write-Host " CCCCCCCCCCCCCTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT "
Write-Host " CCC::::::::::::CT:::::::::::::::::::::TT:::::::::::::::::::::T "
Write-Host "CC:::::::::::::::CT:::::::::::::::::::::TT:::::::::::::::::::::T "
Write-Host "C:::::CCCCCCCC::::CT:::::TT:::::::TT:::::TT:::::TT:::::::TT:::::T "
Write-Host "C:::::C CCCCCCTTTTTT T:::::T TTTTTTTTTTTT T:::::T TTTTTT"
Write-Host "C:::::C T:::::T T:::::T "
Write-Host "C:::::C T:::::T T:::::T "
Write-Host "C:::::C T:::::T T:::::T "
Write-Host "C:::::C T:::::T T:::::T "
Write-Host "C:::::C T:::::T T:::::T "
Write-Host "C:::::C T:::::T T:::::T "
Write-Host "C:::::C CCCCCC T:::::T T:::::T "
Write-Host "C:::::CCCCCCCC::::C TT:::::::TT TT:::::::TT "
Write-Host "CC:::::::::::::::C T:::::::::T T:::::::::T "
Write-Host "CCC::::::::::::C T:::::::::T T:::::::::T "
Write-Host " CCCCCCCCCCCCC TTTTTTTTTTT TTTTTTTTTTT "
Write-Host ""
Write-Host "====Chris Titus Tech====="
Write-Host "=====Windows Toolbox====="
#====DEBUG GUI Elements====
#Write-Host "Found the following interactable elements from our form" -ForegroundColor Cyan
#get-variable WPF*
}

View File

@ -9,33 +9,34 @@ function Invoke-WPFGetInstalled {
#>
param($checkbox)
if ($sync.ProcessRunning) {
$msg = "[Invoke-WPFGetInstalled] Install process is currently running."
[System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
return
}
if(($sync.WPFpreferChocolatey.IsChecked -eq $false) -and ((Test-WinUtilPackageManager -winget) -eq "not-installed") -and $checkbox -eq "winget") {
if (($sync.ChocoRadioButton.IsChecked -eq $false) -and ((Test-WinUtilPackageManager -winget) -eq "not-installed") -and $checkbox -eq "winget") {
return
}
$preferChoco = $sync.WPFpreferChocolatey.IsChecked
Invoke-WPFRunspace -ArgumentList $checkbox, $preferChoco -DebugPreference $DebugPreference -ScriptBlock {
param($checkbox, $preferChoco, $DebugPreference)
$managerPreference = $sync["ManagerPreference"]
Invoke-WPFRunspace -ParameterList @(("managerPreference", $managerPreference),("checkbox", $checkbox)) -DebugPreference $DebugPreference -ScriptBlock {
param (
[string]$checkbox,
[PackageManagers]$managerPreference
)
$sync.ProcessRunning = $true
$sync.form.Dispatcher.Invoke([action] { Set-WinUtilTaskbaritem -state "Indeterminate" })
if ($checkbox -eq "winget") {
Write-Host "Getting Installed Programs..."
switch ($managerPreference) {
"Choco"{$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox "choco"; break}
"Winget"{$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox; break}
}
if($checkbox -eq "tweaks") {
}
elseif ($checkbox -eq "tweaks") {
Write-Host "Getting Installed Tweaks..."
}
if ($preferChoco -and $checkbox -eq "winget") {
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox "choco"
}
else{
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox
}

View File

@ -46,7 +46,7 @@ function Invoke-WPFImpex {
if ($Config) {
$jsonFile = Get-WinUtilCheckBoxes -unCheck $false | ConvertTo-Json
$jsonFile | Out-File $Config -Force
"iex ""& { `$(irm christitus.com/win) } -Config '$Config'""" | Set-Clipboard
"iex ""& { `$(irm https://christitus.com/win) } -Config '$Config'""" | Set-Clipboard
}
} catch {
Write-Error "An error occurred while exporting: $_"

View File

@ -1,4 +1,8 @@
function Invoke-WPFInstall {
param (
[Parameter(Mandatory=$false)]
[PSObject[]]$PackagesToInstall = $($sync.selectedApps | Foreach-Object { $sync.configs.applicationsHashtable.$_ })
)
<#
.SYNOPSIS
@ -12,51 +16,24 @@ function Invoke-WPFInstall {
return
}
$PackagesToInstall = (Get-WinUtilCheckBoxes)["Install"]
Write-Host $PackagesToInstall
if ($PackagesToInstall.Count -eq 0) {
$WarningMsg = "Please select the program(s) to install or upgrade"
[System.Windows.MessageBox]::Show($WarningMsg, $AppTitle, [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
return
}
$ChocoPreference = $($sync.WPFpreferChocolatey.IsChecked)
$installHandle = Invoke-WPFRunspace -ParameterList @(("PackagesToInstall", $PackagesToInstall),("ChocoPreference", $ChocoPreference)) -DebugPreference $DebugPreference -ScriptBlock {
param($PackagesToInstall, $ChocoPreference, $DebugPreference)
if ($PackagesToInstall.count -eq 1) {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" })
} else {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" })
}
$packagesWinget, $packagesChoco = {
$packagesWinget = [System.Collections.ArrayList]::new()
$packagesChoco = [System.Collections.ArrayList]::new()
foreach ($package in $PackagesToInstall) {
if ($ChocoPreference) {
if ($package.choco -eq "na") {
$packagesWinget.add($package.winget)
Write-Host "Queueing $($package.winget) for Winget install"
} else {
$null = $packagesChoco.add($package.choco)
Write-Host "Queueing $($package.choco) for Chocolatey install"
}
}
else {
if ($package.winget -eq "na") {
$packagesChoco.add($package.choco)
Write-Host "Queueing $($package.choco) for Chocolatey install"
} else {
$null = $packagesWinget.add($($package.winget))
Write-Host "Queueing $($package.winget) for Winget install"
}
}
}
return $packagesWinget, $packagesChoco
}.Invoke($PackagesToInstall)
$ManagerPreference = $sync["ManagerPreference"]
Invoke-WPFRunspace -ParameterList @(("PackagesToInstall", $PackagesToInstall),("ManagerPreference", $ManagerPreference)) -DebugPreference $DebugPreference -ScriptBlock {
param($PackagesToInstall, $ManagerPreference, $DebugPreference)
$packagesSorted = Get-WinUtilSelectedPackages -PackageList $PackagesToInstall -Preference $ManagerPreference
$packagesWinget = $packagesSorted[[PackageManagers]::Winget]
$packagesChoco = $packagesSorted[[PackageManagers]::Choco]
try {
$sync.ProcessRunning = $true
$errorPackages = @()
if($packagesWinget.Count -gt 0) {
Install-WinUtilWinget
Install-WinUtilProgramWinget -Action Install -Programs $packagesWinget

View File

@ -5,7 +5,7 @@ function Invoke-WPFInstallUpgrade {
Invokes the function that upgrades all installed programs
#>
if ($sync.WPFpreferChocolatey.IsChecked) {
if ($sync.ChocoRadioButton.IsChecked) {
Install-WinUtilChoco
$chocoUpgradeStatus = (Start-Process "choco" -ArgumentList "upgrade all -y" -Wait -PassThru -NoNewWindow).ExitCode
if ($chocoUpgradeStatus -eq 0) {

View File

@ -1,30 +0,0 @@
function Invoke-WPFPanelDISM {
<#
.SYNOPSIS
Checks for system corruption using Chkdsk, SFC, and DISM
.DESCRIPTION
1. Chkdsk - Fixes disk and filesystem corruption
2. SFC Run 1 - Fixes system file corruption, and fixes DISM if it was corrupted
3. DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted
4. SFC Run 2 - Fixes system file corruption, this time with an almost guaranteed uncorrupted system image
.NOTES
Command Arguments:
1. Chkdsk
/Scan - Runs an online scan on the system drive, attempts to fix any corruption, and queues other corruption for fixing on reboot
2. SFC
/ScanNow - Performs a scan of the system files and fixes any corruption
3. DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted
/Online - Fixes the currently running system image
/Cleanup-Image - Performs cleanup operations on the image, could remove some unneeded temporary files
/Restorehealth - Performs a scan of the image and fixes any corruption
#>
Start-Process PowerShell -ArgumentList "Write-Host '(1/4) Chkdsk' -ForegroundColor Green; Chkdsk /scan;
Write-Host '`n(2/4) SFC - 1st scan' -ForegroundColor Green; sfc /scannow;
Write-Host '`n(3/4) DISM' -ForegroundColor Green; DISM /Online /Cleanup-Image /Restorehealth;
Write-Host '`n(4/4) SFC - 2nd scan' -ForegroundColor Green; sfc /scannow;
Read-Host '`nPress Enter to Continue'" -verb runas
}

View File

@ -0,0 +1,54 @@
function Invoke-WPFPopup {
param (
[ValidateSet("Show", "Hide", "Toggle")]
[string]$Action = "",
[string[]]$Popups = @(),
[ValidateScript({
$invalid = $_.GetEnumerator() | Where-Object { $_.Value -notin @("Show", "Hide", "Toggle") }
if ($invalid) {
throw "Found invalid Popup-Action pair(s): " + ($invalid | ForEach-Object { "$($_.Key) = $($_.Value)" } -join "; ")
}
$true
})]
[hashtable]$PopupActionTable = @{}
)
if (-not $PopupActionTable.Count -and (-not $Action -or -not $Popups.Count)) {
throw "Provide either 'PopupActionTable' or both 'Action' and 'Popups'."
}
if ($PopupActionTable.Count -and ($Action -or $Popups.Count)) {
throw "Use 'PopupActionTable' on its own, or 'Action' with 'Popups'."
}
# Collect popups and actions
$PopupsToProcess = if ($PopupActionTable.Count) {
$PopupActionTable.GetEnumerator() | ForEach-Object { [PSCustomObject]@{ Name = "$($_.Key)Popup"; Action = $_.Value } }
} else {
$Popups | ForEach-Object { [PSCustomObject]@{ Name = "$_`Popup"; Action = $Action } }
}
$PopupsNotFound = @()
# Apply actions
foreach ($popupEntry in $PopupsToProcess) {
$popupName = $popupEntry.Name
if (-not $sync.$popupName) {
$PopupsNotFound += $popupName
continue
}
$sync.$popupName.IsOpen = switch ($popupEntry.Action) {
"Show" { $true }
"Hide" { $false }
"Toggle" { -not $sync.$popupName.IsOpen }
}
}
if ($PopupsNotFound.Count -gt 0) {
throw "Could not find the following popups: $($PopupsNotFound -join ', ')"
}
}

View File

@ -0,0 +1,17 @@
function Invoke-WPFSSHServer {
<#
.SYNOPSIS
Invokes the OpenSSH Server install in a runspace
#>
Invoke-WPFRunspace -DebugPreference $DebugPreference -ScriptBlock {
Invoke-WinUtilSSHServer
Write-Host "======================================="
Write-Host "-- OpenSSH Server installed! ---"
Write-Host "======================================="
}
}

View File

@ -0,0 +1,43 @@
function Invoke-WPFSelectedAppsUpdate {
<#
.SYNOPSIS
This is a helper function that is called by the Checked and Unchecked events of the Checkboxes on the install tab.
It Updates the "Selected Apps" selectedAppLabel on the Install Tab to represent the current collection
.PARAMETER type
Eigther: Add | Remove
.PARAMETER checkbox
should contain the current instance of the checkbox that triggered the Event.
Most of the time will be the automatic variable $this
.EXAMPLE
$checkbox.Add_Unchecked({Invoke-WPFSelectedAppsUpdate -type "Remove" -checkbox $this})
OR
Invoke-WPFSelectedAppsUpdate -type "Add" -checkbox $specificCheckbox
#>
param (
$type,
$checkbox
)
$selectedAppsButton = $sync.WPFselectedAppsButton
# Get the actual Name from the selectedAppLabel inside the Checkbox
$appKey = $checkbox.Parent.Tag
if ($type -eq "Add") {
$sync.selectedApps.Add($appKey)
# The List type needs to be specified again, because otherwise Sort-Object will convert the list to a string if there is only a single entry
[System.Collections.Generic.List[pscustomobject]]$sync.selectedApps = $sync.SelectedApps | Sort-Object
}
elseif ($type -eq "Remove") {
$sync.SelectedApps.Remove($appKey)
}
else{
Write-Error "Type: $type not implemented"
}
$count = $sync.SelectedApps.Count
$selectedAppsButton.Content = "Selected Apps: $count"
# On every change, remove all entries inside the Popup Menu. This is done, so we can keep the alphabetical order even if elements are selected in a random way
$sync.selectedAppsstackPanel.Children.Clear()
$sync.SelectedApps | Foreach-Object { Add-SelectedAppsMenuItem -name $($sync.configs.applicationsHashtable.$_.Content) -key $_ }
}

View File

@ -0,0 +1,124 @@
function Invoke-WPFSystemRepair {
<#
.SYNOPSIS
Checks for system corruption using Chkdsk, SFC, and DISM
.DESCRIPTION
1. Chkdsk - Fixes disk and filesystem corruption
2. SFC Run 1 - Fixes system file corruption, and fixes DISM if it was corrupted
3. DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted
4. SFC Run 2 - Fixes system file corruption, this time with an almost guaranteed uncorrupted system image
#>
function Invoke-Chkdsk {
<#
.SYNOPSIS
Runs chkdsk on the system drive
.DESCRIPTION
Chkdsk /Scan - Runs an online scan on the system drive, attempts to fix any corruption, and queues other corruption for fixing on reboot
#>
param(
[int]$parentProgressId = 0
)
Write-Progress -Id 1 -ParentId $parentProgressId -Activity $childProgressBarActivity -Status "Running chkdsk..." -PercentComplete 0
$oldpercent = 0
# 2>&1 redirects stdout, allowing iteration over the output
chkdsk.exe /scan /perf 2>&1 | ForEach-Object {
Write-Debug $_
# Regex to match the total percentage regardless of windows locale (it's always the second percentage in the status output)
if ($_ -match "%.*?(\d+)%") {
[int]$percent = $matches[1]
if ($percent -gt $oldpercent) {
Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "Running chkdsk... ($percent%)" -PercentComplete $percent
$oldpercent = $percent
}
}
}
Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "chkdsk Completed" -PercentComplete 100 -Completed
}
function Invoke-SFC {
<#
.SYNOPSIS
Runs sfc on the system drive
.DESCRIPTION
SFC /ScanNow - Performs a scan of the system files and fixes any corruption
.NOTES
ErrorActionPreference is set locally within a script block & {...} to isolate their effects.
ErrorActionPreference suppresses false errors caused by sfc.exe output redirection.
A bug in SFC output buffering causes progress updates to appear in chunks when redirecting output
#>
param(
[int]$parentProgressId = 0
)
& {
$ErrorActionPreference = "SilentlyContinue"
Write-Progress -Id 1 -ParentId $parentProgressId -Activity $childProgressBarActivity -Status "Running SFC..." -PercentComplete 0
$oldpercent = 0
sfc.exe /scannow 2>&1 | ForEach-Object {
Write-Debug $_
if ($_ -ne "") {
# sfc.exe /scannow outputs unicode characters, so we directly remove null characters for optimization
$utf8line = $_ -replace "`0", ""
if ($utf8line -match "(\d+)\s*%") {
[int]$percent = $matches[1]
if ($percent -gt $oldpercent) {
Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "Running SFC... ($percent%)" -PercentComplete $percent
$oldpercent = $percent
}
}
}
}
Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "SFC Completed" -PercentComplete 100 -Completed
}
}
function Invoke-DISM {
<#
.SYNOPSIS
Runs DISM on the system drive
.DESCRIPTION
DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted
/Online - Fixes the currently running system image
/Cleanup-Image - Performs cleanup operations on the image, could remove some unneeded temporary files
/Restorehealth - Performs a scan of the image and fixes any corruption
#>
param(
[int]$parentProgressId = 0
)
Write-Progress -Id 1 -ParentId $parentProgressId -Activity $childProgressBarActivity -Status "Running DISM..." -PercentComplete 0
$oldpercent = 0
DISM /Online /Cleanup-Image /RestoreHealth | ForEach-Object {
Write-Debug $_
# Filter for lines that contain a percentage that is greater than the previous one
if ($_ -match "(\d+)[.,]\d+%") {
[int]$percent = $matches[1]
if ($percent -gt $oldpercent) {
# Update the progress bar
Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "Running DISM... ($percent%)" -PercentComplete $percent
$oldpercent = $percent
}
}
}
Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "DISM Completed" -PercentComplete 100 -Completed
}
$childProgressBarActivity = "Scanning for corruption"
Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 0
# Step 1: Run chkdsk to fix disk and filesystem corruption before proceeding with system file repairs
Invoke-Chkdsk
Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 25
# Step 2: Run SFC to fix system file corruption and ensure DISM can operate correctly
Invoke-SFC
Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 50
# Step 3: Run DISM to repair the system image, which SFC relies on for accurate repairs
Invoke-DISM
Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 75
# Step 4: Run SFC again to ensure system files are repaired using the now-fixed system image
Invoke-SFC
Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 100 -Completed
}

View File

@ -28,4 +28,31 @@ function Invoke-WPFTab {
$sync.$tabNav.Items[$tabNumber].IsSelected = $true
}
}
$sync.currentTab = $sync.$tabNav.Items[$tabNumber].Header
# Always reset the filter for the current tab
if ($sync.currentTab -eq "Install") {
# Reset Install tab filter
Find-AppsByNameOrDescription -SearchString ""
} elseif ($sync.currentTab -eq "Tweaks") {
# Reset Tweaks tab filter
Find-TweaksByNameOrDescription -SearchString ""
}
# Show search bar in Install and Tweaks tabs
if ($tabNumber -eq 0 -or $tabNumber -eq 1) {
$sync.SearchBar.Visibility = "Visible"
$searchIcon = ($sync.Form.FindName("SearchBar").Parent.Children | Where-Object { $_ -is [System.Windows.Controls.TextBlock] -and $_.Text -eq [char]0xE721 })[0]
if ($searchIcon) {
$searchIcon.Visibility = "Visible"
}
} else {
$sync.SearchBar.Visibility = "Collapsed"
$searchIcon = ($sync.Form.FindName("SearchBar").Parent.Children | Where-Object { $_ -is [System.Windows.Controls.TextBlock] -and $_.Text -eq [char]0xE721 })[0]
if ($searchIcon) {
$searchIcon.Visibility = "Collapsed"
}
# Hide the clear button if it's visible
$sync.SearchBarClearButton.Visibility = "Collapsed"
}
}

View File

@ -1,39 +0,0 @@
function Invoke-WPFToggle {
<#
.SYNOPSIS
Invokes the scriptblock for the given toggle
.PARAMETER Button
The name of the toggle to invoke
#>
Param ([string]$Button)
# Use this to get the name of the button
#[System.Windows.MessageBox]::Show("$Button","Chris Titus Tech's Windows Utility","OK","Info")
$ToggleStatus = (Get-WinUtilToggleStatus $Button)
Switch -Wildcard ($Button) {
"WPFToggleDarkMode" {Invoke-WinUtilDarkMode $ToggleStatus}
"WPFToggleBingSearch" {Invoke-WinUtilBingSearch $ToggleStatus}
"WPFToggleNumLock" {Invoke-WinUtilNumLock $ToggleStatus}
"WPFToggleVerboseLogon" {Invoke-WinUtilVerboseLogon $ToggleStatus}
"WPFToggleShowExt" {Invoke-WinUtilShowExt $ToggleStatus}
"WPFToggleSnapWindow" {Invoke-WinUtilSnapWindow $ToggleStatus}
"WPFToggleSnapFlyout" {Invoke-WinUtilSnapFlyout $ToggleStatus}
"WPFToggleSnapSuggestion" {Invoke-WinUtilSnapSuggestion $ToggleStatus}
"WPFToggleMouseAcceleration" {Invoke-WinUtilMouseAcceleration $ToggleStatus}
"WPFToggleStickyKeys" {Invoke-WinUtilStickyKeys $ToggleStatus}
"WPFToggleTaskbarWidgets" {Invoke-WinUtilTaskbarWidgets $ToggleStatus}
"WPFToggleTaskbarSearch" {Invoke-WinUtilTaskbarSearch $ToggleStatus}
"WPFToggleTaskView" {Invoke-WinUtilTaskView $ToggleStatus}
"WPFToggleHiddenFiles" {Invoke-WinUtilHiddenFiles $ToggleStatus}
"WPFToggleTaskbarAlignment" {Invoke-WinUtilTaskbarAlignment $ToggleStatus}
"WPFToggleDetailedBSoD" {Invoke-WinUtilDetailedBSoD $ToggleStatus}
}
}

View File

@ -11,26 +11,26 @@ function Invoke-WPFUIElements {
.EXAMPLE
Invoke-WPFUIElements -configVariable $sync.configs.applications -targetGridName "install" -columncount 5
.NOTES
Future me/contributer: If possible please wrap this into a runspace to make it load all panels at the same time.
Future me/contributor: If possible, please wrap this into a runspace to make it load all panels at the same time.
#>
param(
[Parameter(Mandatory, position=0)]
[Parameter(Mandatory, Position = 0)]
[PSCustomObject]$configVariable,
[Parameter(Mandatory, position=1)]
[Parameter(Mandatory, Position = 1)]
[string]$targetGridName,
[Parameter(Mandatory, position=2)]
[Parameter(Mandatory, Position = 2)]
[int]$columncount
)
$window = $sync["Form"]
$window = $sync.form
$theme = $sync.Form.Resources
$borderstyle = $window.FindResource("BorderStyle")
$HoverTextBlockStyle = $window.FindResource("HoverTextBlockStyle")
$ColorfulToggleSwitchStyle = $window.FindResource("ColorfulToggleSwitchStyle")
$ToggleButtonStyle = $window.FindResource("ToggleButtonStyle")
if (!$borderstyle -or !$HoverTextBlockStyle -or !$ColorfulToggleSwitchStyle) {
throw "Failed to retrieve Styles using 'FindResource' from main window element."
@ -59,6 +59,8 @@ function Invoke-WPFUIElements {
$configHashtable[$_] = $configVariable.$_
}
$radioButtonGroups = @{}
$organizedData = @{}
# Iterate through JSON data and organize by panel and category
foreach ($entry in $configHashtable.Keys) {
@ -70,8 +72,6 @@ function Invoke-WPFUIElements {
Order = $entryInfo.order
Category = $entryInfo.Category
Content = $entryInfo.Content
Choco = $entryInfo.choco
Winget = $entryInfo.winget
Panel = if ($entryInfo.Panel) { $entryInfo.Panel } else { "0" }
Link = $entryInfo.link
Description = $entryInfo.description
@ -79,6 +79,7 @@ function Invoke-WPFUIElements {
ComboItems = $entryInfo.ComboItems
Checked = $entryInfo.Checked
ButtonWidth = $entryInfo.ButtonWidth
GroupName = $entryInfo.GroupName # Added for RadioButton groupings
}
if (-not $organizedData.ContainsKey($entryObject.Panel)) {
@ -92,86 +93,61 @@ function Invoke-WPFUIElements {
# Store application data in an array under the category
$organizedData[$entryObject.Panel][$entryObject.Category] += $entryObject
# Only apply the logic for distributing entries across columns if the targetGridName is "appspanel"
if ($targetGridName -eq "appspanel") {
}
# Initialize panel count
$panelcount = 0
$entrycount = $configHashtable.Keys.Count + $organizedData["0"].Keys.Count
$maxcount = [Math]::Round($entrycount / $columncount + 0.5)
}
}
# Iterate through 'organizedData' by panel, category, and application
$count = 0
foreach ($panelKey in ($organizedData.Keys | Sort-Object)) {
# Create a Border for each column
$border = New-Object Windows.Controls.Border
$border.VerticalAlignment = "Stretch" # Ensure the border stretches vertically
$border.VerticalAlignment = "Stretch"
[System.Windows.Controls.Grid]::SetColumn($border, $panelcount)
$border.style = $borderstyle
$targetGrid.Children.Add($border) | Out-Null
# Create a StackPanel inside the Border
$stackPanel = New-Object Windows.Controls.StackPanel
$stackPanel.Background = [Windows.Media.Brushes]::Transparent
$stackPanel.SnapsToDevicePixels = $true
$stackPanel.VerticalAlignment = "Stretch" # Ensure the stack panel stretches vertically
$border.Child = $stackPanel
# Use a DockPanel to contain the content
$dockPanelContainer = New-Object Windows.Controls.DockPanel
$border.Child = $dockPanelContainer
# Create an ItemsControl for application content
$itemsControl = New-Object Windows.Controls.ItemsControl
$itemsControl.HorizontalAlignment = 'Stretch'
$itemsControl.VerticalAlignment = 'Stretch'
# Set the ItemsPanel to a VirtualizingStackPanel
$itemsPanelTemplate = New-Object Windows.Controls.ItemsPanelTemplate
$factory = New-Object Windows.FrameworkElementFactory ([Windows.Controls.VirtualizingStackPanel])
$itemsPanelTemplate.VisualTree = $factory
$itemsControl.ItemsPanel = $itemsPanelTemplate
# Set virtualization properties
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::IsVirtualizingProperty, $true)
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::VirtualizationModeProperty, [Windows.Controls.VirtualizationMode]::Recycling)
# Add the ItemsControl directly to the DockPanel
[Windows.Controls.DockPanel]::SetDock($itemsControl, [Windows.Controls.Dock]::Bottom)
$dockPanelContainer.Children.Add($itemsControl) | Out-Null
$panelcount++
# Now proceed with adding category labels and entries to $itemsControl
foreach ($category in ($organizedData[$panelKey].Keys | Sort-Object)) {
$count++
if ($targetGridName -eq "appspanel" -and $columncount -gt 0) {
$panelcount2 = [Int](($count) / $maxcount - 0.5)
if ($panelcount -eq $panelcount2) {
# Create a new Border for the new column
$border = New-Object Windows.Controls.Border
$border.VerticalAlignment = "Stretch" # Ensure the border stretches vertically
[System.Windows.Controls.Grid]::SetColumn($border, $panelcount)
$border.style = $borderstyle
$targetGrid.Children.Add($border) | Out-Null
# Create a new StackPanel inside the Border
$stackPanel = New-Object Windows.Controls.StackPanel
$stackPanel.Background = [Windows.Media.Brushes]::Transparent
$stackPanel.SnapsToDevicePixels = $true
$stackPanel.VerticalAlignment = "Stretch" # Ensure the stack panel stretches vertically
$border.Child = $stackPanel
$panelcount++
}
}
$label = New-Object Windows.Controls.Label
$label.Content = $category -replace ".*__", ""
$label.FontSize = $theme.FontSizeHeading
$label.FontFamily = $theme.HeaderFontFamily
$stackPanel.Children.Add($label) | Out-Null
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "HeaderFontSize")
$label.SetResourceReference([Windows.Controls.Control]::FontFamilyProperty, "HeaderFontFamily")
$itemsControl.Items.Add($label) | Out-Null
$sync[$category] = $label
# Sort entries by Order and then by Name, but only display Name
# Sort entries by Order and then by Name
$entries = $organizedData[$panelKey][$category] | Sort-Object Order, Name
foreach ($entryInfo in $entries) {
$count++
if ($targetGridName -eq "appspanel" -and $columncount -gt 0) {
$panelcount2 = [Int](($count) / $maxcount - 0.5)
if ($panelcount -eq $panelcount2) {
# Create a new Border for the new column
$border = New-Object Windows.Controls.Border
$border.VerticalAlignment = "Stretch" # Ensure the border stretches vertically
[System.Windows.Controls.Grid]::SetColumn($border, $panelcount)
$border.style = $borderstyle
$targetGrid.Children.Add($border) | Out-Null
# Create a new StackPanel inside the Border
$stackPanel = New-Object Windows.Controls.StackPanel
$stackPanel.Background = [Windows.Media.Brushes]::Transparent
$stackPanel.SnapsToDevicePixels = $true
$stackPanel.VerticalAlignment = "Stretch" # Ensure the stack panel stretches vertically
$border.Child = $stackPanel
$panelcount++
}
}
# Create the UI elements based on the entry type
switch ($entryInfo.Type) {
"Toggle" {
$dockPanel = New-Object Windows.Controls.DockPanel
@ -185,51 +161,50 @@ function Invoke-WPFUIElements {
$label.Content = $entryInfo.Content
$label.ToolTip = $entryInfo.Description
$label.HorizontalAlignment = "Left"
$label.FontSize = $theme.FontSize
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSize")
$label.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$dockPanel.Children.Add($label) | Out-Null
$stackPanel.Children.Add($dockPanel) | Out-Null
$itemsControl.Items.Add($dockPanel) | Out-Null
$sync[$entryInfo.Name] = $checkBox
$sync[$entryInfo.Name].IsChecked = Get-WinUtilToggleStatus $sync[$entryInfo.Name].Name
$sync[$entryInfo.Name].IsChecked = (Get-WinUtilToggleStatus $entryInfo.Name)
$sync[$entryInfo.Name].Add_Click({
$sync[$entryInfo.Name].Add_Checked({
[System.Object]$Sender = $args[0]
Invoke-WPFToggle $Sender.name
Invoke-WinUtilTweaks $sender.name
})
$sync[$entryInfo.Name].Add_Unchecked({
[System.Object]$Sender = $args[0]
Invoke-WinUtiltweaks $sender.name -undo $true
})
}
"ToggleButton" {
$toggleButton = New-Object Windows.Controls.ToggleButton
$toggleButton = New-Object Windows.Controls.Primitives.ToggleButton
$toggleButton.Name = $entryInfo.Name
$toggleButton.Name = "WPFTab" + ($stackPanel.Children.Count + 1) + "BT"
$toggleButton.Content = $entryInfo.Content[1]
$toggleButton.ToolTip = $entryInfo.Description
$toggleButton.HorizontalAlignment = "Left"
$toggleButton.Height = $theme.TabButtonHeight
$toggleButton.Width = $theme.TabButtonWidth
$toggleButton.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "ButtonInstallBackgroundColor")
$toggleButton.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$toggleButton.FontWeight = [Windows.FontWeights]::Bold
$toggleButton.Style = $ToggleButtonStyle
$textBlock = New-Object Windows.Controls.TextBlock
$textBlock.FontSize = $theme.TabButtonFontSize
$textBlock.Background = [Windows.Media.Brushes]::Transparent
$textBlock.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "ButtonInstallForegroundColor")
$toggleButton.Tag = @{
contentOn = if ($entryInfo.Content.Count -ge 1) { $entryInfo.Content[0] } else { "" }
contentOff = if ($entryInfo.Content.Count -ge 2) { $entryInfo.Content[1] } else { $contentOn }
}
$underline = New-Object Windows.Documents.Underline
$underline.Inlines.Add($entryInfo.name -replace "(.).*", "`$1")
$run = New-Object Windows.Documents.Run
$run.Text = $entryInfo.name -replace "^.", ""
$textBlock.Inlines.Add($underline)
$textBlock.Inlines.Add($run)
$toggleButton.Content = $textBlock
$stackPanel.Children.Add($toggleButton) | Out-Null
$itemsControl.Items.Add($toggleButton) | Out-Null
$sync[$entryInfo.Name] = $toggleButton
$sync[$entryInfo.Name].Add_Checked({
$this.Content = $this.Tag.contentOn
})
$sync[$entryInfo.Name].Add_Unchecked({
$this.Content = $this.Tag.contentOff
})
}
"Combobox" {
@ -241,26 +216,26 @@ function Invoke-WPFUIElements {
$label.Content = $entryInfo.Content
$label.HorizontalAlignment = "Left"
$label.VerticalAlignment = "Center"
$label.FontSize = $theme.ButtonFontSize
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
$horizontalStackPanel.Children.Add($label) | Out-Null
$comboBox = New-Object Windows.Controls.ComboBox
$comboBox.Name = $entryInfo.Name
$comboBox.Height = $theme.ButtonHeight
$comboBox.Width = $theme.ButtonWidth
$comboBox.SetResourceReference([Windows.Controls.Control]::HeightProperty, "ButtonHeight")
$comboBox.SetResourceReference([Windows.Controls.Control]::WidthProperty, "ButtonWidth")
$comboBox.HorizontalAlignment = "Left"
$comboBox.VerticalAlignment = "Center"
$comboBox.Margin = $theme.ButtonMargin
$comboBox.SetResourceReference([Windows.Controls.Control]::MarginProperty, "ButtonMargin")
foreach ($comboitem in ($entryInfo.ComboItems -split " ")) {
$comboBoxItem = New-Object Windows.Controls.ComboBoxItem
$comboBoxItem.Content = $comboitem
$comboBoxItem.FontSize = $theme.ButtonFontSize
$comboBoxItem.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
$comboBox.Items.Add($comboBoxItem) | Out-Null
}
$horizontalStackPanel.Children.Add($comboBox) | Out-Null
$stackPanel.Children.Add($horizontalStackPanel) | Out-Null
$itemsControl.Items.Add($horizontalStackPanel) | Out-Null
$comboBox.SelectedIndex = 0
@ -272,16 +247,50 @@ function Invoke-WPFUIElements {
$button.Name = $entryInfo.Name
$button.Content = $entryInfo.Content
$button.HorizontalAlignment = "Left"
$button.Margin = $theme.ButtonMargin
$button.FontSize = $theme.ButtonFontSize
$button.SetResourceReference([Windows.Controls.Control]::MarginProperty, "ButtonMargin")
$button.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
if ($entryInfo.ButtonWidth) {
$button.Width = $entryInfo.ButtonWidth
}
$stackPanel.Children.Add($button) | Out-Null
$itemsControl.Items.Add($button) | Out-Null
$sync[$entryInfo.Name] = $button
}
"RadioButton" {
# Check if a container for this GroupName already exists
if (-not $radioButtonGroups.ContainsKey($entryInfo.GroupName)) {
# Create a StackPanel for this group
$groupStackPanel = New-Object Windows.Controls.StackPanel
$groupStackPanel.Orientation = "Vertical"
# Add the group container to the ItemsControl
$itemsControl.Items.Add($groupStackPanel) | Out-Null
}
else {
# Retrieve the existing group container
$groupStackPanel = $radioButtonGroups[$entryInfo.GroupName]
}
# Create the RadioButton
$radioButton = New-Object Windows.Controls.RadioButton
$radioButton.Name = $entryInfo.Name
$radioButton.GroupName = $entryInfo.GroupName
$radioButton.Content = $entryInfo.Content
$radioButton.HorizontalAlignment = "Left"
$radioButton.SetResourceReference([Windows.Controls.Control]::MarginProperty, "CheckBoxMargin")
$radioButton.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
$radioButton.ToolTip = $entryInfo.Description
if ($entryInfo.Checked -eq $true) {
$radioButton.IsChecked = $true
}
# Add the RadioButton to the group container
$groupStackPanel.Children.Add($radioButton) | Out-Null
$sync[$entryInfo.Name] = $radioButton
}
default {
$horizontalStackPanel = New-Object Windows.Controls.StackPanel
$horizontalStackPanel.Orientation = "Horizontal"
@ -289,9 +298,9 @@ function Invoke-WPFUIElements {
$checkBox = New-Object Windows.Controls.CheckBox
$checkBox.Name = $entryInfo.Name
$checkBox.Content = $entryInfo.Content
$checkBox.FontSize = $theme.FontSize
$checkBox.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSize")
$checkBox.ToolTip = $entryInfo.Description
$checkBox.Margin = $theme.CheckBoxMargin
$checkBox.SetResourceReference([Windows.Controls.Control]::MarginProperty, "CheckBoxMargin")
if ($entryInfo.Checked -eq $true) {
$checkBox.IsChecked = $entryInfo.Checked
}
@ -309,7 +318,7 @@ function Invoke-WPFUIElements {
$sync[$textBlock.Name] = $textBlock
}
$stackPanel.Children.Add($horizontalStackPanel) | Out-Null
$itemsControl.Items.Add($horizontalStackPanel) | Out-Null
$sync[$entryInfo.Name] = $checkBox
}
}

View File

@ -1,9 +1,12 @@
function Invoke-WPFUnInstall {
param(
[Parameter(Mandatory=$false)]
[PSObject[]]$PackagesToUninstall = $($sync.selectedApps | Foreach-Object { $sync.configs.applicationsHashtable.$_ })
)
<#
.SYNOPSIS
Uninstalls the selected programs
#>
if($sync.ProcessRunning) {
@ -12,9 +15,7 @@ function Invoke-WPFUnInstall {
return
}
$PackagesToInstall = (Get-WinUtilCheckBoxes)["Install"]
if ($PackagesToInstall.Count -eq 0) {
if ($PackagesToUninstall.Count -eq 0) {
$WarningMsg = "Please select the program(s) to uninstall"
[System.Windows.MessageBox]::Show($WarningMsg, $AppTitle, [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
return
@ -22,52 +23,26 @@ function Invoke-WPFUnInstall {
$ButtonType = [System.Windows.MessageBoxButton]::YesNo
$MessageboxTitle = "Are you sure?"
$Messageboxbody = ("This will uninstall the following applications: `n $($PackagesToInstall | Format-Table | Out-String)")
$Messageboxbody = ("This will uninstall the following applications: `n $($PackagesToUninstall | Select-Object Name, Description| Out-String)")
$MessageIcon = [System.Windows.MessageBoxImage]::Information
$confirm = [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon)
if($confirm -eq "No") {return}
$ChocoPreference = $($sync.WPFpreferChocolatey.IsChecked)
Invoke-WPFRunspace -ArgumentList @(("PackagesToInstall", $PackagesToInstall),("ChocoPreference", $ChocoPreference)) -DebugPreference $DebugPreference -ScriptBlock {
param($PackagesToInstall, $ChocoPreference, $DebugPreference)
if ($PackagesToInstall.count -eq 1) {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" })
} else {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" })
}
$packagesWinget, $packagesChoco = {
$packagesWinget = [System.Collections.ArrayList]::new()
$packagesChoco = [System.Collections.ArrayList]::new()
$ManagerPreference = $sync["ManagerPreference"]
foreach ($package in $PackagesToInstall) {
if ($ChocoPreference) {
if ($package.choco -eq "na") {
$packagesWinget.add($package.winget)
Write-Host "Queueing $($package.winget) for Winget uninstall"
} else {
$null = $packagesChoco.add($package.choco)
Write-Host "Queueing $($package.choco) for Chocolatey uninstall"
}
}
else {
if ($package.winget -eq "na") {
$packagesChoco.add($package.choco)
Write-Host "Queueing $($package.choco) for Chocolatey uninstall"
} else {
$null = $packagesWinget.add($($package.winget))
Write-Host "Queueing $($package.winget) for Winget uninstall"
}
}
}
return $packagesWinget, $packagesChoco
}.Invoke($PackagesToInstall)
Invoke-WPFRunspace -ArgumentList @(("PackagesToUninstall", $PackagesToUninstall),("ManagerPreference", $ManagerPreference)) -DebugPreference $DebugPreference -ScriptBlock {
param($PackagesToUninstall, $ManagerPreference, $DebugPreference)
$packagesSorted = Get-WinUtilSelectedPackages -PackageList $PackagesToUninstall -Preference $ManagerPreference
$packagesWinget = $packagesSorted[[PackageManagers]::Winget]
$packagesChoco = $packagesSorted[[PackageManagers]::Choco]
try {
$sync.ProcessRunning = $true
# Install all selected programs in new window
# Uninstall all selected programs in new window
if($packagesWinget.Count -gt 0) {
Install-WinUtilProgramWinget -Action Uninstall -Programs $packagesWinget
}

View File

@ -25,7 +25,7 @@ function Invoke-WPFtweaksbutton {
Write-Debug "Number of tweaks to process: $($Tweaks.Count)"
# The leading "," in the ParameterList is nessecary because we only provide one argument and powershell cannot be convinced that we want a nested loop with only one argument otherwise
$tweaksHandle = Invoke-WPFRunspace -ParameterList @(,("tweaks",$tweaks)) -DebugPreference $DebugPreference -ScriptBlock {
Invoke-WPFRunspace -ParameterList @(,("tweaks",$tweaks)) -DebugPreference $DebugPreference -ScriptBlock {
param(
$tweaks,
$DebugPreference

View File

@ -0,0 +1,38 @@
Function Show-CTTLogo {
<#
.SYNOPSIS
Displays the CTT logo in ASCII art.
.DESCRIPTION
This function displays the CTT logo in ASCII art format.
.PARAMETER None
No parameters are required for this function.
.EXAMPLE
Show-CTTLogo
Prints the CTT logo in ASCII art format to the console.
#>
$asciiArt = @"
CCCCCCCCCCCCCTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
CCC::::::::::::CT:::::::::::::::::::::TT:::::::::::::::::::::T
CC:::::::::::::::CT:::::::::::::::::::::TT:::::::::::::::::::::T
C:::::CCCCCCCC::::CT:::::TT:::::::TT:::::TT:::::TT:::::::TT:::::T
C:::::C CCCCCCTTTTTT T:::::T TTTTTTTTTTTT T:::::T TTTTTT
C:::::C T:::::T T:::::T
C:::::C T:::::T T:::::T
C:::::C T:::::T T:::::T
C:::::C T:::::T T:::::T
C:::::C T:::::T T:::::T
C:::::C T:::::T T:::::T
C:::::C CCCCCC T:::::T T:::::T
C:::::CCCCCCCC::::C TT:::::::TT TT:::::::TT
CC:::::::::::::::C T:::::::::T T:::::::::T
CCC::::::::::::C T:::::::::T T:::::::::T
CCCCCCCCCCCCC TTTTTTTTTTT TTTTTTTTTTT
====Chris Titus Tech=====
=====Windows Toolbox=====
"@
Write-Host $asciiArt
}

View File

@ -3,7 +3,6 @@
{% block header %}
{{ super() }}
<div style="color: red; text-align: center; padding: 10px; font-size: 20px;">
<strong>Announcement:</strong> We are currently not adding any applications to WinUtil and any apps that will be added through a PR will be declined by the maintainer.
<strong>Announcement:</strong> We are currently reworking the docs to use Hugo rather then mkdocs.
</div>
{% endblock %}

View File

@ -1,3 +1,12 @@
# Create enums
Add-Type @"
public enum PackageManagers
{
Winget,
Choco
}
"@
# SPDX-License-Identifier: MIT
# Set the maximum number of threads for the RunspacePool to the number of threads on the machine
$maxthreads = [int]$env:NUMBER_OF_PROCESSORS
@ -33,23 +42,19 @@ $sync.runspace.Open()
class WingetFailedInstall : Exception {
[string]$additionalData
WingetFailedInstall($Message) : base($Message) {}
}
class ChocoFailedInstall : Exception {
[string]$additionalData
ChocoFailedInstall($Message) : base($Message) {}
}
class GenericException : Exception {
[string]$additionalData
GenericException($Message) : base($Message) {}
}
$inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace '^<Win.*', '<Window'
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
@ -111,23 +116,39 @@ $sync.Form.Add_Loaded({
Invoke-WinutilThemeChange -init $true
# Load the configuration files
#Invoke-WPFUIElements -configVariable $sync.configs.nav -targetGridName "WPFMainGrid"
Invoke-WPFUIElements -configVariable $sync.configs.applications -targetGridName "appspanel" -columncount 5
$sync.configs.applicationsHashtable = @{}
$sync.configs.applications.PSObject.Properties | ForEach-Object {
$sync.configs.applicationsHashtable[$_.Name] = $_.Value
}
# Now call the function with the final merged config
Invoke-WPFUIElements -configVariable $sync.configs.appnavigation -targetGridName "appscategory" -columncount 1
Initialize-WPFUI -targetGridName "appscategory"
Initialize-WPFUI -targetGridName "appspanel"
Invoke-WPFUIElements -configVariable $sync.configs.tweaks -targetGridName "tweakspanel" -columncount 2
Invoke-WPFUIElements -configVariable $sync.configs.feature -targetGridName "featurespanel" -columncount 2
# Future implementation: Add Windows Version to updates panel
#Invoke-WPFUIElements -configVariable $sync.configs.updates -targetGridName "updatespanel" -columncount 1
#===========================================================================
# Store Form Objects In PowerShell
#===========================================================================
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {$sync["$("$($psitem.Name)")"] = $sync["Form"].FindName($psitem.Name)}
#Persist the Chocolatey preference across winutil restarts
$ChocoPreferencePath = "$env:LOCALAPPDATA\winutil\preferChocolatey.ini"
$sync.WPFpreferChocolatey.Add_Checked({New-Item -Path $ChocoPreferencePath -Force })
$sync.WPFpreferChocolatey.Add_Unchecked({Remove-Item $ChocoPreferencePath -Force})
if (Test-Path $ChocoPreferencePath) {
$sync.WPFpreferChocolatey.IsChecked = $true
#Persist Package Manager preference across winutil restarts
$sync.ChocoRadioButton.Add_Checked({Set-PackageManagerPreference Choco})
$sync.WingetRadioButton.Add_Checked({Set-PackageManagerPreference Winget})
Set-PackageManagerPreference
switch ($sync["ManagerPreference"]) {
"Choco" {$sync.ChocoRadioButton.IsChecked = $true; break}
"Winget" {$sync.WingetRadioButton.IsChecked = $true; break}
}
$sync.keys | ForEach-Object {
@ -166,14 +187,13 @@ $sync.keys | ForEach-Object {
# Load computer information in the background
Invoke-WPFRunspace -ScriptBlock {
try {
$oldProgressPreference = $ProgressPreference
$ProgressPreference = "SilentlyContinue"
$sync.ConfigLoaded = $False
$sync.ComputerInfo = Get-ComputerInfo
$sync.ConfigLoaded = $True
}
finally{
$ProgressPreference = "Continue"
$ProgressPreference = $oldProgressPreference
}
} | Out-Null
@ -183,7 +203,7 @@ Invoke-WPFRunspace -ScriptBlock {
#===========================================================================
# Print the logo
Invoke-WPFFormVariables
Show-CTTLogo
# Progress bar in taskbaritem > Set-WinUtilProgressbar
$sync["Form"].TaskbarItemInfo = New-Object System.Windows.Shell.TaskbarItemInfo
@ -202,70 +222,52 @@ $sync["Form"].Add_Closing({
$sync.SearchBarClearButton.Add_Click({
$sync.SearchBar.Text = ""
$sync.SearchBarClearButton.Visibility = "Collapsed"
# Focus the search bar after clearing the text
$sync.SearchBar.Focus()
$sync.SearchBar.SelectAll()
})
# add some shortcuts for people that don't like clicking
$commonKeyEvents = {
# Prevent shortcuts from executing if a process is already running
if ($sync.ProcessRunning -eq $true) {
return
}
if ($_.Key -eq "Escape") {
$sync.SearchBar.SelectAll()
$sync.SearchBar.Text = ""
$sync.SearchBarClearButton.Visibility = "Collapsed"
return
}
# don't ask, I know what I'm doing, just go...
if (($_.Key -eq "Q" -and $_.KeyboardDevice.Modifiers -eq "Ctrl")) {
$this.Close()
# Handle key presses of single keys
switch ($_.Key) {
"Escape" { $sync.SearchBar.Text = "" }
}
# Handle Alt key combinations for navigation
if ($_.KeyboardDevice.Modifiers -eq "Alt") {
if ($_.SystemKey -eq "I") {
Invoke-WPFButton "WPFTab1BT"
}
if ($_.SystemKey -eq "T") {
Invoke-WPFButton "WPFTab2BT"
}
if ($_.SystemKey -eq "C") {
Invoke-WPFButton "WPFTab3BT"
}
if ($_.SystemKey -eq "U") {
Invoke-WPFButton "WPFTab4BT"
}
if ($_.SystemKey -eq "M") {
Invoke-WPFButton "WPFTab5BT"
}
if ($_.SystemKey -eq "P") {
Write-Host "Your Windows Product Key: $((Get-WmiObject -query 'select * from SoftwareLicensingService').OA3xOriginalProductKey)"
$keyEventArgs = $_
switch ($_.SystemKey) {
"I" { Invoke-WPFButton "WPFTab1BT"; $keyEventArgs.Handled = $true } # Navigate to Install tab and suppress Windows Warning Sound
"T" { Invoke-WPFButton "WPFTab2BT"; $keyEventArgs.Handled = $true } # Navigate to Tweaks tab
"C" { Invoke-WPFButton "WPFTab3BT"; $keyEventArgs.Handled = $true } # Navigate to Config tab
"U" { Invoke-WPFButton "WPFTab4BT"; $keyEventArgs.Handled = $true } # Navigate to Updates tab
"M" { Invoke-WPFButton "WPFTab5BT"; $keyEventArgs.Handled = $true } # Navigate to MicroWin tab
}
}
# shortcut for the filter box
if ($_.Key -eq "F" -and $_.KeyboardDevice.Modifiers -eq "Ctrl") {
if ($sync.SearchBar.Text -eq "Ctrl-F to filter") {
$sync.SearchBar.SelectAll()
$sync.SearchBar.Text = ""
}
$sync.SearchBar.Focus()
# Handle Ctrl key combinations for specific actions
if ($_.KeyboardDevice.Modifiers -eq "Ctrl") {
switch ($_.Key) {
"F" { $sync.SearchBar.Focus() } # Focus on the search bar
"Q" { $this.Close() } # Close the application
}
}
}
$sync["Form"].Add_PreViewKeyDown($commonKeyEvents)
$sync["Form"].Add_MouseLeftButtonDown({
# Hide Settings and Theme Popup on click anywhere else
if ($sync.SettingsButton.IsOpen -or
$sync.ThemePopup.IsOpen) {
$sync.SettingsPopup.IsOpen = $false
$sync.ThemePopup.IsOpen = $false
}
Invoke-WPFPopup -Action "Hide" -Popups @("Settings", "Theme")
$sync["Form"].DragMove()
})
$sync["Form"].Add_MouseDoubleClick({
if ($_.OriginalSource -is [System.Windows.Controls.Grid] -or
$_.OriginalSource -is [System.Windows.Controls.StackPanel]) {
if ($_.OriginalSource.Name -eq "NavDockPanel" -or
$_.OriginalSource.Name -eq "GridBesideNavDockPanel") {
if ($sync["Form"].WindowState -eq [Windows.WindowState]::Normal) {
$sync["Form"].WindowState = [Windows.WindowState]::Maximized
}
@ -277,64 +279,10 @@ $sync["Form"].Add_MouseDoubleClick({
$sync["Form"].Add_Deactivated({
Write-Debug "WinUtil lost focus"
# Hide Settings and Theme Popup on Winutil Focus Loss
if ($sync.SettingsButton.IsOpen -or
$sync.ThemePopup.IsOpen) {
$sync.SettingsPopup.IsOpen = $false
$sync.ThemePopup.IsOpen = $false
}
Invoke-WPFPopup -Action "Hide" -Popups @("Settings", "Theme")
})
$sync["Form"].Add_ContentRendered({
try {
[void][Window]
} catch {
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class Window {
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);
[DllImport("user32.dll")]
public static extern int GetSystemMetrics(int nIndex);
};
public struct RECT {
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
"@
}
foreach ($proc in (Get-Process).where{ $_.MainWindowTitle -and $_.MainWindowTitle -like "*titus*" }) {
# Check if the process's MainWindowHandle is valid
if ($proc.MainWindowHandle -ne [System.IntPtr]::Zero) {
Write-Debug "MainWindowHandle: $($proc.Id) $($proc.MainWindowTitle) $($proc.MainWindowHandle)"
$windowHandle = $proc.MainWindowHandle
} else {
Write-Warning "Process found, but no MainWindowHandle: $($proc.Id) $($proc.MainWindowTitle)"
}
}
$rect = New-Object RECT
[Window]::GetWindowRect($windowHandle, [ref]$rect)
$width = $rect.Right - $rect.Left
$height = $rect.Bottom - $rect.Top
Write-Debug "UpperLeft:$($rect.Left),$($rect.Top) LowerBottom:$($rect.Right),$($rect.Bottom). Width:$($width) Height:$($height)"
# Load the Windows Forms assembly
Add-Type -AssemblyName System.Windows.Forms
$primaryScreen = [System.Windows.Forms.Screen]::PrimaryScreen
@ -349,9 +297,12 @@ Add-Type @"
Write-Debug "Primary Monitor Height: $screenHeight pixels"
# Compare with the primary monitor size
if ($width -gt $screenWidth -or $height -gt $screenHeight) {
if ($sync.Form.ActualWidth -gt $screenWidth -or $sync.Form.ActualHeight -gt $screenHeight) {
Write-Debug "The specified width and/or height is greater than the primary monitor size."
[void][Window]::MoveWindow($windowHandle, 0, 0, $screenWidth, $screenHeight, $True)
$sync.Form.Left = 0
$sync.Form.Top = 0
$sync.Form.Width = $screenWidth
$sync.Form.Height = $screenHeight
} else {
Write-Debug "The specified width and height are within the primary monitor size limits."
}
@ -425,73 +376,39 @@ if ($sync["ISOLanguage"].Items.Count -eq 1) {
}
$sync["ISOLanguage"].SelectedIndex = 0
# The SearchBarTimer is used to delay the search operation until the user has stopped typing for a short period
# This prevents the ui from stuttering when the user types quickly as it dosnt need to update the ui for every keystroke
# Load Checkboxes and Labels outside of the Filter function only once on startup for performance reasons
$filter = Get-WinUtilVariables -Type CheckBox
$CheckBoxes = ($sync.GetEnumerator()).where{ $psitem.Key -in $filter }
$filter = Get-WinUtilVariables -Type Label
$labels = @{}
($sync.GetEnumerator()).where{$PSItem.Key -in $filter} | ForEach-Object {$labels[$_.Key] = $_.Value}
$allCategories = $checkBoxes.Name | ForEach-Object {$sync.configs.applications.$_} | Select-Object -Unique -ExpandProperty category
$searchBarTimer = New-Object System.Windows.Threading.DispatcherTimer
$searchBarTimer.Interval = [TimeSpan]::FromMilliseconds(300)
$searchBarTimer.IsEnabled = $false
$searchBarTimer.add_Tick({
$searchBarTimer.Stop()
switch ($sync.currentTab) {
"Install" {
Find-AppsByNameOrDescription -SearchString $sync.SearchBar.Text
}
"Tweaks" {
Find-TweaksByNameOrDescription -SearchString $sync.SearchBar.Text
}
}
})
$sync["SearchBar"].Add_TextChanged({
if ($sync.SearchBar.Text -ne "") {
$sync.SearchBarClearButton.Visibility = "Visible"
} else {
$sync.SearchBarClearButton.Visibility = "Collapsed"
}
$activeApplications = @()
$textToSearch = $sync.SearchBar.Text.ToLower()
foreach ($CheckBox in $CheckBoxes) {
# Skip if the checkbox is null, it doesn't have content or it is the prefer Choco checkbox
if ($CheckBox -eq $null -or $CheckBox.Value -eq $null -or $CheckBox.Value.Content -eq $null -or $CheckBox.Name -eq "WPFpreferChocolatey") {
continue
}
$checkBoxName = $CheckBox.Key
$textBlockName = $checkBoxName + "Link"
# Retrieve the corresponding text block based on the generated name
$textBlock = $sync[$textBlockName]
if ($CheckBox.Value.Content.ToString().ToLower().Contains($textToSearch)) {
$CheckBox.Value.Visibility = "Visible"
$activeApplications += $sync.configs.applications.$checkboxName
# Set the corresponding text block visibility
if ($textBlock -ne $null -and $textBlock -is [System.Windows.Controls.TextBlock]) {
$textBlock.Visibility = "Visible"
}
} else {
$CheckBox.Value.Visibility = "Collapsed"
# Set the corresponding text block visibility
if ($textBlock -ne $null -and $textBlock -is [System.Windows.Controls.TextBlock]) {
$textBlock.Visibility = "Collapsed"
}
}
}
$activeCategories = $activeApplications | Select-Object -ExpandProperty category -Unique
foreach ($category in $activeCategories) {
$sync[$category].Visibility = "Visible"
}
if ($activeCategories) {
$inactiveCategories = Compare-Object -ReferenceObject $allCategories -DifferenceObject $activeCategories -PassThru
} else {
$inactiveCategories = $allCategories
}
foreach ($category in $inactiveCategories) {
$sync[$category].Visibility = "Collapsed"
if ($searchBarTimer.IsEnabled) {
$searchBarTimer.Stop()
}
$searchBarTimer.Start()
})
$sync["Form"].Add_Loaded({
param($e)
$sync.Form.MinWidth = "1000"
$sync["Form"].MaxWidth = [Double]::PositiveInfinity
$sync["Form"].MaxHeight = [Double]::PositiveInfinity
})
@ -521,101 +438,72 @@ Set-WinUtilTaskbaritem -overlay "logo"
$sync["Form"].Add_Activated({
Set-WinUtilTaskbaritem -overlay "logo"
})
# Define event handler for ThemeButton click
$sync["ThemeButton"].Add_Click({
if ($sync.ThemePopup.IsOpen) {
$sync.ThemePopup.IsOpen = $false
}
else{
$sync.ThemePopup.IsOpen = $true
}
$sync.SettingsPopup.IsOpen = $false
Write-Debug "ThemeButton clicked"
Invoke-WPFPopup -PopupActionTable @{ "Settings" = "Hide"; "Theme" = "Toggle" }
})
# Define event handlers for menu items
$sync["AutoThemeMenuItem"].Add_Click({
$sync.ThemePopup.IsOpen = $false
Write-Debug "About clicked"
Invoke-WPFPopup -Action "Hide" -Popups @("Theme")
Invoke-WinutilThemeChange -theme "Auto"
$_.Handled = $false
})
# Define event handlers for menu items
$sync["DarkThemeMenuItem"].Add_Click({
$sync.ThemePopup.IsOpen = $false
Write-Debug "Dark Theme clicked"
Invoke-WPFPopup -Action "Hide" -Popups @("Theme")
Invoke-WinutilThemeChange -theme "Dark"
$_.Handled = $false
})
# Define event handlers for menu items
$sync["LightThemeMenuItem"].Add_Click({
$sync.ThemePopup.IsOpen = $false
Write-Debug "Light Theme clicked"
Invoke-WPFPopup -Action "Hide" -Popups @("Theme")
Invoke-WinutilThemeChange -theme "Light"
$_.Handled = $false
})
# Define event handler for button click
$sync["SettingsButton"].Add_Click({
Write-Debug "SettingsButton clicked"
if ($sync.SettingsPopup.IsOpen) {
$sync.SettingsPopup.IsOpen = $false
}
else{
$sync.SettingsPopup.IsOpen = $true
}
$sync.ThemePopup.IsOpen = $false
$_.Handled = $false
Invoke-WPFPopup -PopupActionTable @{ "Settings" = "Toggle"; "Theme" = "Hide" }
})
# Define event handlers for menu items
$sync["ImportMenuItem"].Add_Click({
# Handle Import menu item click
Write-Debug "Import clicked"
$sync["SettingsPopup"].IsOpen = $false
Invoke-WPFPopup -Action "Hide" -Popups @("Settings")
Invoke-WPFImpex -type "import"
$_.Handled = $false
})
$sync["ExportMenuItem"].Add_Click({
# Handle Export menu item click
Write-Debug "Export clicked"
$sync["SettingsPopup"].IsOpen = $false
Invoke-WPFPopup -Action "Hide" -Popups @("Settings")
Invoke-WPFImpex -type "export"
$_.Handled = $false
})
$sync["AboutMenuItem"].Add_Click({
# Handle Export menu item click
Write-Debug "About clicked"
$sync["SettingsPopup"].IsOpen = $false
Invoke-WPFPopup -Action "Hide" -Popups @("Settings")
$authorInfo = @"
Author : <a href="https://github.com/ChrisTitusTech">@christitustech</a>
Runspace : <a href="https://github.com/DeveloperDurp">@DeveloperDurp</a>
MicroWin : <a href="https://github.com/KonTy">@KonTy</a>
UI : <a href="https://github.com/MyDrift-user">@MyDrift-user</a>, <a href="https://github.com/Marterich">@Marterich</a>
Runspace : <a href="https://github.com/DeveloperDurp">@DeveloperDurp</a>, <a href="https://github.com/Marterich">@Marterich</a>
MicroWin : <a href="https://github.com/KonTy">@KonTy</a>, <a href="https://github.com/CodingWonders">@CodingWonders</a>
GitHub : <a href="https://github.com/ChrisTitusTech/winutil">ChrisTitusTech/winutil</a>
Version : <a href="https://github.com/ChrisTitusTech/winutil/releases/tag/$($sync.version)">$($sync.version)</a>
"@
Show-CustomDialog -Message $authorInfo -LogoSize $LogoSize
Show-CustomDialog -Title "About" -Message $authorInfo
})
$sync["SponsorMenuItem"].Add_Click({
# Handle Export menu item click
Write-Debug "Sponsors clicked"
$sync["SettingsPopup"].IsOpen = $false
Invoke-WPFPopup -Action "Hide" -Popups @("Settings")
$authorInfo = @"
<a href="https://github.com/sponsors/ChrisTitusTech">Current sponsors for ChrisTitusTech:</a>
"@
$authorInfo += "`n"
try {
# Call the function to get the sponsors
$sponsors = Invoke-WinUtilSponsors
# Append the sponsors to the authorInfo
$sponsors | ForEach-Object { $authorInfo += "$_`n" }
foreach ($sponsor in $sponsors) {
$authorInfo += "<a href=`"https://github.com/sponsors/ChrisTitusTech`">$sponsor</a>`n"
}
} catch {
$authorInfo += "An error occurred while fetching or processing the sponsors: $_`n"
}
Show-CustomDialog -Message $authorInfo -EnableScroll $true
Show-CustomDialog -Title "Sponsors" -Message $authorInfo -EnableScroll $true
})
$sync["Form"].ShowDialog() | out-null

View File

@ -37,7 +37,13 @@ $sync = [Hashtable]::Synchronized(@{})
$sync.PSScriptRoot = $PSScriptRoot
$sync.version = "#{replaceme}"
$sync.configs = @{}
$sync.Buttons = [System.Collections.Generic.List[PSObject]]::new()
$sync.ProcessRunning = $false
$sync.selectedApps = [System.Collections.Generic.List[string]]::new()
$sync.currentTab = "Install"
$sync.selectedAppsStackPanel
$sync.selectedAppsPopup
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Output "Winutil needs to be run as Administrator. Attempting to relaunch."
@ -46,21 +52,27 @@ if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]:
$PSBoundParameters.GetEnumerator() | ForEach-Object {
$argList += if ($_.Value -is [switch] -and $_.Value) {
"-$($_.Key)"
} elseif ($_.Value -is [array]) {
"-$($_.Key) $($_.Value -join ',')"
} elseif ($_.Value) {
"-$($_.Key) `"$($_.Value)`""
"-$($_.Key) '$($_.Value)'"
}
}
$script = if ($MyInvocation.MyCommand.Path) {
"& { & '$($MyInvocation.MyCommand.Path)' $argList }"
$script = if ($PSCommandPath) {
"& { & `'$($PSCommandPath)`' $($argList -join ' ') }"
} else {
"iex '& { $(irm https://github.com/ChrisTitusTech/winutil/releases/latest/download/winutil.ps1) } $argList'"
"&([ScriptBlock]::Create((irm https://github.com/ChrisTitusTech/winutil/releases/latest/download/winutil.ps1))) $($argList -join ' ')"
}
$powershellcmd = if (Get-Command pwsh -ErrorAction SilentlyContinue) { "pwsh" } else { "powershell" }
$processCmd = if (Get-Command wt.exe -ErrorAction SilentlyContinue) { "wt.exe" } else { $powershellcmd }
$powershellCmd = if (Get-Command pwsh -ErrorAction SilentlyContinue) { "pwsh" } else { "powershell" }
$processCmd = if (Get-Command wt.exe -ErrorAction SilentlyContinue) { "wt.exe" } else { "$powershellCmd" }
Start-Process $processCmd -ArgumentList "$powershellcmd -ExecutionPolicy Bypass -NoProfile -Command $script" -Verb RunAs
if ($processCmd -eq "wt.exe") {
Start-Process $processCmd -ArgumentList "$powershellCmd -ExecutionPolicy Bypass -NoProfile -Command `"$script`"" -Verb RunAs
} else {
Start-Process $processCmd -ArgumentList "-ExecutionPolicy Bypass -NoProfile -Command `"$script`"" -Verb RunAs
}
break
}
@ -72,5 +84,5 @@ $logdir = "$env:localappdata\winutil\logs"
Start-Transcript -Path "$logdir\winutil_$dateTime.log" -Append -NoClobber | Out-Null
# Set PowerShell window title
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Admin)"
$Host.UI.RawUI.WindowTitle = "WinUtil (Admin)"
clear-host

1
sign.bat Normal file
View File

@ -0,0 +1 @@
signtool.exe sign /td sha256 /tr http://timestamp.digicert.com /fd sha256 /n "CT Tech Group LLC" .\winutil.ps1

View File

@ -3,15 +3,9 @@ function Invoke-Preprocessing {
.SYNOPSIS
A function that does Code Formatting using RegEx, useful when trying to force specific coding standard(s) to a project.
.PARAMETER ThrowExceptionOnEmptyFilesList
A switch which'll throw an exception upon not finding any files inside the provided 'WorkingDir'.
.PARAMETER SkipExcludedFilesValidation
A switch to stop file path validation on 'ExcludedFiles' list.
.PARAMETER ExcludedFiles
A list of file paths which're *relative to* 'WorkingDir' Folder, every item in the list can be pointing to File (doesn't end with '\') or Directory (ends with '\') or None-Existing File/Directory.
By default, it checks if everyitem exists, and throws an exception if one or more are not found (None-Existing), if you want to skip this validation, please consider providing the '-SkipExcludedFilesValidation' switch to skip this check.
By default, it checks if everyitem exists, and throws an exception if one or more are not found (None-Existing).
.PARAMETER WorkingDir
The folder to search inside recursively for files which're going to be Preprocessed (Code Formatted), unless they're found in 'ExcludedFiles' List.
@ -36,35 +30,23 @@ function Invoke-Preprocessing {
Same as Example No. 1, but uses 'ProgressActivity' which's used in Progress Bar.
.EXAMPLE
Invoke-Preprocessing -ThrowExceptionOnEmptyFilesList -WorkingDir "DRIVE:\Path\To\Folder\" -ExcludedFiles @('file.txt', '.\.git\', '*.png') -ProgressStatusMessage "Doing Preprocessing"
Same as Example No. 1, but uses '-ThrowExceptionOnEmptyFilesList', which's an optional parameter that'll make 'Invoke-Preprocessing' throw an exception when no files are found in 'WorkingDir' (not including the ExcludedFiles, of course), useful when you want to double check your parameters & you're sure there's files to process in the 'WorkingDir'.
.EXAMPLE
Invoke-Preprocessing -Skip -WorkingDir "DRIVE:\Path\To\Folder\" -ExcludedFiles @('file.txt', '.\.git\', '*.png') -ProgressStatusMessage "Doing Preprocessing"
Same as Example No. 1, but uses '-SkipExcludedFilesValidation', which'll skip the validation step for 'ExcludedFiles' list. This can be useful when 'ExcludedFiles' list is generated from another function, or from unreliable source (you can't guarantee every item in list is a valid path), but you want to silently continue through the function.
#>
param (
[Parameter(position=0)]
[switch]$SkipExcludedFilesValidation,
[Parameter(position=1)]
[switch]$ThrowExceptionOnEmptyFilesList,
[Parameter(Mandatory, position=2)]
[Parameter(Mandatory, position=1)]
[ValidateScript({[System.IO.Path]::IsPathRooted($_)})]
[string]$WorkingDir,
[Parameter(position=3)]
[Parameter(position=2)]
[string[]]$ExcludedFiles,
[Parameter(Mandatory, position=4)]
[Parameter(Mandatory, position=3)]
[string]$ProgressStatusMessage,
[Parameter(position=5)]
[Parameter(position=4)]
[string]$ProgressActivity = "Preprocessing"
)
@ -77,8 +59,7 @@ function Invoke-Preprocessing {
$InternalExcludedFiles.Add($excludedFile) | Out-Null
}
# Validate the ExcludedItems List before continuing on,
# that's if there's a list in the first place, and '-SkipInternalExcludedFilesValidation' was not provided.
# Validate the ExcludedItems List before continuing on
if ($ExcludedFiles.Count -gt 0) {
ForEach ($excludedFile in $ExcludedFiles) {
$filePath = "$(($WorkingDir -replace ('\\$', '')) + '\' + ($excludedFile -replace ('\.\\', '')))"
@ -90,8 +71,8 @@ function Invoke-Preprocessing {
} else { $failedFilesList += "'$filePath', " }
}
$failedFilesList = $failedFilesList -replace (',\s*$', '')
if ((-not $failedFilesList -eq "") -and (-not $SkipExcludedFilesValidation)) {
throw "[Invoke-Preprocessing] One or more File Paths and/or File Patterns were not found, you can use '-SkipExcludedFilesValidation' switch to skip this check, the failed to validate are: $failedFilesList"
if ((-not $failedFilesList -eq "")) {
Write-Warning "[Invoke-Preprocessing] One or more File Paths and/or File Patterns were not found: $failedFilesList"
}
}
@ -111,14 +92,45 @@ function Invoke-Preprocessing {
if ($index -ge 0) { $files.RemoveAt($index) }
}
# Define a path to store the file hashes
$hashFilePath = Join-Path -Path $WorkingDir -ChildPath ".preprocessor_hashes.json"
# Load existing hashes if the file exists
$existingHashes = @{}
if (Test-Path -Path $hashFilePath) {
# intentionally dosn't use ConvertFrom-Json -AsHashtable as it isn't supported on old powershell versions
$file_content = Get-Content -Path $hashFilePath | ConvertFrom-Json
foreach ($property in $file_content.PSObject.Properties) {
$existingHashes[$property.Name] = $property.Value
}
}
$newHashes = @{}
$changedFiles = @()
$hashingAlgorithm = "MD5"
foreach ($file in $files){
# Calculate the hash of the file
$hash = Get-FileHash -Path $file -Algorithm $hashingAlgorithm | Select-Object -ExpandProperty Hash
$newHashes[$file] = $hash
# Check if the hash already exists in the existing hashes
if (($existingHashes.ContainsKey($file) -and $existingHashes[$file] -eq $hash)) {
# Skip processing this file as it hasn't changed
continue;
}
else {
# If the hash doesn't exist or has changed, add it to the changed files list
$changedFiles += $file
}
}
$files = $changedFiles
$numOfFiles = $files.Count
Write-Debug "[Invoke-Preprocessing] Files Changed: $numOfFiles"
if ($numOfFiles -eq 0){
if ($ThrowExceptionOnEmptyFilesList) {
throw "[Invoke-Preprocessing] Found 0 Files to Preprocess inside 'WorkingDir' Directory and '-ThrowExceptionOnEmptyFilesList' Switch is provided, value of 'WorkingDir': '$WorkingDir'."
} else {
return # Do an early return, there's nothing else to do
}
Write-Debug "[Invoke-Preprocessing] Found 0 Files to Preprocess inside 'WorkingDir' Directory : '$WorkingDir'."
return
}
for ($i = 0; $i -lt $numOfFiles; $i++) {
@ -139,9 +151,13 @@ function Invoke-Preprocessing {
-replace ('\}\s*Catch\s*(?<exceptions>\[.*?\])\s*\{', '} catch ${exceptions} {') `
-replace ('(?<parameter_type>\[[^$0-9]+\])\s*(?<str_after_type>\$.*?)', '${parameter_type}${str_after_type}') `
| Set-Content "$fullFileName"
$newHashes[$fullFileName] = Get-FileHash -Path $fullFileName -Algorithm $hashingAlgorithm | Select-Object -ExpandProperty Hash
Write-Progress -Activity $ProgressActivity -Status "$ProgressStatusMessage - Finished $i out of $numOfFiles" -PercentComplete (($i/$numOfFiles)*100)
}
Write-Progress -Activity $ProgressActivity -Status "$ProgressStatusMessage - Finished Task Successfully" -Completed
# Save the new hashes to the file
$newHashes | ConvertTo-Json -Depth 10 | Set-Content -Path $hashFilePath
}

View File

@ -1,925 +0,0 @@
<#PSScriptInfo
.VERSION 3.0.1
.GUID 3b581edb-5d90-4fa1-ba15-4f2377275463
.AUTHOR asheroto, 1ckov, MisterZeus, ChrisTitusTech
.COMPANYNAME asheroto
.TAGS PowerShell Windows winget win get install installer fix script setup
.PROJECTURI https://github.com/asheroto/winget-install
.RELEASENOTES
[Version 0.0.1] - Initial Release.
[Version 0.0.2] - Implemented function to get the latest version of winget and its license.
[Version 0.0.3] - Signed file for PSGallery.
[Version 0.0.4] - Changed URI to grab latest release instead of releases and preleases.
[Version 0.0.5] - Updated version number of dependencies.
[Version 1.0.0] - Major refactor code, see release notes for more information.
[Version 1.0.1] - Fixed minor bug where version 2.8 was hardcoded in URL.
[Version 1.0.2] - Hardcoded UI Xaml version 2.8.4 as a failsafe in case the API fails. Added CheckForUpdates, Version, Help functions. Various bug fixes.
[Version 1.0.3] - Added error message to catch block. Fixed bug where appx package was not being installed.
[Version 1.0.4] - MisterZeus optimized code for readability.
[Version 2.0.0] - Major refactor. Reverted to UI.Xaml 2.7.3 for stability. Adjusted script to fix install issues due to winget changes (thank you ChrisTitusTech). Added in all architecture support.
[Version 2.0.1] - Renamed repo and URL references from winget-installer to winget-install. Added extra space after the last line of output.
[Version 2.0.2] - Adjusted CheckForUpdates to include Install-Script instructions and extra spacing.
[Version 2.1.0] - Added alternate method/URL for dependencies in case the main URL is down. Fixed licensing issue when winget is installed on Server 2022.
[Version 2.1.1] - Switched primary/alternate methods. Added Cleanup function to avoid errors when cleaning up temp files. Added output of URL for alternate method. Suppressed Add-AppxProvisionedPackage output. Improved success message. Improved verbiage. Improve PS script comments. Added check if the URL is empty. Moved display of URL beneath the check.
[Version 3.0.0] - Major changes. Added OS version detection checks - detects OS version, release ID, ensures compatibility. Forces older file installation for Server 2022 to avoid issues after installing. Added DebugMode, DisableCleanup, Force. Renamed CheckForUpdates to CheckForUpdate. Improved output. Improved error handling. Improved comments. Improved code readability. Moved CheckForUpdate into function. Added PowerShellGalleryName. Renamed Get-OSVersion to Get-OSInfo. Moved architecture detection into Get-OSInfo. Renamed Get-NewestLink to Get-WingetDownloadUrl. Have Get-WingetDownloadUrl not get preview releases.
[Version 3.0.1] - Updated Get-OSInfo function to fix issues when used on non-English systems. Improved error handling of "resources in use" error.
#>
<#
.SYNOPSIS
Downloads and installs the latest version of winget and its dependencies. Updates the PATH variable if needed.
.DESCRIPTION
Downloads and installs the latest version of winget and its dependencies. Updates the PATH variable if needed.
This script is designed to be straightforward and easy to use, removing the hassle of manually downloading, installing, and configuring winget. To make the newly installed winget available for use, a system reboot may be required after running the script.
This function should be run with administrative privileges.
.EXAMPLE
winget-install
.PARAMETER DebugMode
Enables debug mode, which shows additional information for debugging.
.PARAMETER DisableCleanup
Disables cleanup of the script and prerequisites after installation.
.PARAMETER Force
Ensures installation of winget and its dependencies, even if already present.
.PARAMETER CheckForUpdate
Checks if there is an update available for the script.
.PARAMETER Version
Displays the version of the script.
.PARAMETER Help
Displays the full help information for the script.
.NOTES
Version : 3.0.1
Created by : asheroto
.LINK
Project Site: https://github.com/asheroto/winget-install
#>
[CmdletBinding()]
param (
[switch]$Version,
[switch]$Help,
[switch]$CheckForUpdate,
[switch]$DisableCleanup,
[switch]$DebugMode,
[switch]$Force
)
# Version
$CurrentVersion = '3.0.1'
$RepoOwner = 'asheroto'
$RepoName = 'winget-install'
$PowerShellGalleryName = 'winget-install'
# Versions
$ProgressPreference = 'SilentlyContinue' # Suppress progress bar (makes downloading super fast)
$ConfirmPreference = 'None' # Suppress confirmation prompts
# Display version if -Version is specified
if ($Version.IsPresent) {
$CurrentVersion
exit 0
}
# Display full help if -Help is specified
if ($Help) {
Get-Help -Name $MyInvocation.MyCommand.Source -Full
exit 0
}
# Display $PSVersionTable and Get-Host if -Verbose is specified
if ($PSBoundParameters.ContainsKey('Verbose') -and $PSBoundParameters['Verbose']) {
$PSVersionTable
Get-Host
}
function Get-TempFolder {
<#
.SYNOPSIS
Gets the path of the current user's temp folder.
.DESCRIPTION
This function retrieves the path of the current user's temp folder.
.EXAMPLE
Get-TempFolder
#>
return [System.IO.Path]::GetTempPath()
}
function Get-OSInfo {
<#
.SYNOPSIS
Retrieves detailed information about the operating system version and architecture.
.DESCRIPTION
This function queries both the Windows registry and the Win32_OperatingSystem class to gather comprehensive information about the operating system. It returns details such as the release ID, display version, name, type (Workstation/Server), numeric version, edition ID, version (object that includes major, minor, and build numbers), and architecture (OS architecture, not processor architecture).
.EXAMPLE
Get-OSInfo
This example retrieves the OS version details of the current system and returns an object with properties like ReleaseId, DisplayVersion, Name, Type, NumericVersion, EditionId, Version, and Architecture.
.EXAMPLE
(Get-OSInfo).Version.Major
This example retrieves the major version number of the operating system. The Get-OSInfo function returns an object with a Version property, which itself is an object containing Major, Minor, and Build properties. You can access these sub-properties using dot notation.
.EXAMPLE
$osDetails = Get-OSInfo
Write-Output "OS Name: $($osDetails.Name)"
Write-Output "OS Type: $($osDetails.Type)"
Write-Output "OS Architecture: $($osDetails.Architecture)"
This example stores the result of Get-OSInfo in a variable and then accesses various properties to print details about the operating system.
#>
[CmdletBinding()]
param ()
try {
# Get registry values
$registryValues = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
$releaseIdValue = $registryValues.ReleaseId
$displayVersionValue = $registryValues.DisplayVersion
$nameValue = $registryValues.ProductName
$editionIdValue = $registryValues.EditionId
# Strip out "Server" from the $editionIdValue if it exists
$editionIdValue = $editionIdValue -replace "Server", ""
# Get OS details using Get-CimInstance because the registry key for Name is not always correct with Windows 11
$osDetails = Get-CimInstance -ClassName Win32_OperatingSystem
$nameValue = $osDetails.Caption
# Get architecture details of the OS (not the processor)
# Get only the numbers
$architecture = ($osDetails.OSArchitecture -replace "[^\d]").Trim()
# If 32-bit or 64-bit replace with x32 and x64
if ($architecture -eq "32") {
$architecture = "x32"
} elseif ($architecture -eq "64") {
$architecture = "x64"
}
# Get OS version details (as version object)
$versionValue = [System.Environment]::OSVersion.Version
# Determine product type
# Reference: https://learn.microsoft.com/en-us/dotnet/api/microsoft.powershell.commands.producttype?view=powershellsdk-1.1.0
if ($osDetails.ProductType -eq 1) {
$typeValue = "Workstation"
} elseif ($osDetails.ProductType -eq 2 -or $osDetails.ProductType -eq 3) {
$typeValue = "Server"
} else {
$typeValue = "Unknown"
}
# Extract numerical value from Name
$numericVersion = ($nameValue -replace "[^\d]").Trim()
# Create and return custom object with the required properties
$result = [PSCustomObject]@{
ReleaseId = $releaseIdValue
DisplayVersion = $displayVersionValue
Name = $nameValue
Type = $typeValue
NumericVersion = $numericVersion
EditionId = $editionIdValue
Version = $versionValue
Architecture = $architecture
}
return $result
} catch {
Write-Error "Unable to get OS version details.`nError: $_"
exit 1
}
}
function Get-GitHubRelease {
<#
.SYNOPSIS
Fetches the latest release information of a GitHub repository.
.DESCRIPTION
This function uses the GitHub API to get information about the latest release of a specified repository, including its version and the date it was published.
.PARAMETER Owner
The GitHub username of the repository owner.
.PARAMETER Repo
The name of the repository.
.EXAMPLE
Get-GitHubRelease -Owner "asheroto" -Repo "winget-install"
This command retrieves the latest release version and published datetime of the winget-install repository owned by asheroto.
#>
[CmdletBinding()]
param (
[string]$Owner,
[string]$Repo
)
try {
$url = "https://api.github.com/repos/$Owner/$Repo/releases/latest"
$response = Invoke-RestMethod -Uri $url -ErrorAction Stop
$latestVersion = $response.tag_name
$publishedAt = $response.published_at
# Convert UTC time string to local time
$UtcDateTime = [DateTime]::Parse($publishedAt, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::RoundtripKind)
$PublishedLocalDateTime = $UtcDateTime.ToLocalTime()
[PSCustomObject]@{
LatestVersion = $latestVersion
PublishedDateTime = $PublishedLocalDateTime
}
} catch {
Write-Error "Unable to check for updates.`nError: $_"
exit 1
}
}
function CheckForUpdate {
param (
[string]$RepoOwner,
[string]$RepoName,
[version]$CurrentVersion,
[string]$PowerShellGalleryName
)
$Data = Get-GitHubRelease -Owner $RepoOwner -Repo $RepoName
if ($Data.LatestVersion -gt $CurrentVersion) {
Write-Output "`nA new version of $RepoName is available.`n"
Write-Output "Current version: $CurrentVersion."
Write-Output "Latest version: $($Data.LatestVersion)."
Write-Output "Published at: $($Data.PublishedDateTime).`n"
Write-Output "You can download the latest version from https://github.com/$RepoOwner/$RepoName/releases`n"
if ($PowerShellGalleryName) {
Write-Output "Or you can run the following command to update:"
Write-Output "Install-Script $PowerShellGalleryName -Force`n"
}
} else {
Write-Output "`n$RepoName is up to date.`n"
Write-Output "Current version: $CurrentVersion."
Write-Output "Latest version: $($Data.LatestVersion)."
Write-Output "Published at: $($Data.PublishedDateTime)."
Write-Output "`nRepository: https://github.com/$RepoOwner/$RepoName/releases`n"
}
exit 0
}
function Write-Section($text) {
<#
.SYNOPSIS
Prints a text block surrounded by a section divider for enhanced output readability.
.DESCRIPTION
This function takes a string input and prints it to the console, surrounded by a section divider made of hash characters.
It is designed to enhance the readability of console output.
.PARAMETER text
The text to be printed within the section divider.
.EXAMPLE
Write-Section "Downloading Files..."
This command prints the text "Downloading Files..." surrounded by a section divider.
#>
Write-Output ""
Write-Output ("#" * ($text.Length + 4))
Write-Output "# $text #"
Write-Output ("#" * ($text.Length + 4))
Write-Output ""
}
function Get-WingetDownloadUrl {
<#
.SYNOPSIS
Retrieves the download URL of the latest release asset that matches a specified pattern from the GitHub repository.
.DESCRIPTION
This function uses the GitHub API to get information about the latest release of the winget-cli repository.
It then retrieves the download URL for the release asset that matches a specified pattern.
.PARAMETER Match
The pattern to match in the asset names.
.EXAMPLE
Get-WingetDownloadUrl "msixbundle"
This command retrieves the download URL for the latest release asset with a name that contains "msixbundle".
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]$Match
)
$uri = "https://api.github.com/repos/microsoft/winget-cli/releases"
Write-Debug "Getting information from $uri"
$releases = Invoke-RestMethod -uri $uri -Method Get -ErrorAction stop
Write-Debug "Getting latest release..."
foreach ($release in $releases) {
if ($release.name -match "preview") {
continue
}
$data = $release.assets | Where-Object name -Match $Match
if ($data) {
return $data.browser_download_url
}
}
Write-Debug "Falling back to the latest release..."
$latestRelease = $releases | Select-Object -First 1
$data = $latestRelease.assets | Where-Object name -Match $Match
return $data.browser_download_url
}
function Get-WingetStatus {
<#
.SYNOPSIS
Checks if winget is installed.
.DESCRIPTION
This function checks if winget is installed.
.EXAMPLE
Get-WingetStatus
#>
# Check if winget is installed
$winget = Get-Command -Name winget -ErrorAction SilentlyContinue
# If winget is installed, return $true
if ($null -ne $winget) {
return $true
}
# If winget is not installed, return $false
return $false
}
function Update-PathEnvironmentVariable {
<#
.SYNOPSIS
Updates the PATH environment variable with a new path for both the User and Machine levels.
.DESCRIPTION
The function will add a new path to the PATH environment variable, making sure it is not a duplicate.
If the new path is already in the PATH variable, the function will skip adding it.
This function operates at both User and Machine levels.
.PARAMETER NewPath
The new directory path to be added to the PATH environment variable.
.EXAMPLE
Update-PathEnvironmentVariable -NewPath "C:\NewDirectory"
This command will add the directory "C:\NewDirectory" to the PATH variable at both the User and Machine levels.
#>
param(
[string]$NewPath
)
foreach ($Level in "Machine", "User") {
# Get the current PATH variable
$path = [Environment]::GetEnvironmentVariable("PATH", $Level)
# Check if the new path is already in the PATH variable
if (!$path.Contains($NewPath)) {
if ($DebugMode) {
Write-Output "Adding $NewPath to PATH variable for $Level..."
} else {
Write-Output "Adding PATH variable for $Level..."
}
# Add the new path to the PATH variable
$path = ($path + ";" + $NewPath).Split(';') | Select-Object -Unique
$path = $path -join ';'
# Set the new PATH variable
[Environment]::SetEnvironmentVariable("PATH", $path, $Level)
} else {
if ($DebugMode) {
Write-Output "$NewPath already present in PATH variable for $Level, skipping."
} else {
Write-Output "PATH variable already present for $Level, skipping."
}
}
}
}
function Handle-Error {
<#
.SYNOPSIS
Handles common errors that may occur during an installation process.
.DESCRIPTION
This function takes an ErrorRecord object and checks for certain known error codes.
Depending on the error code, it writes appropriate warning messages or throws the error.
.PARAMETER ErrorRecord
The ErrorRecord object that represents the error that was caught. This object contains
information about the error, including the exception that was thrown.
.EXAMPLE
try {
# Some code that may throw an error...
} catch {
Handle-Error $_
}
This example shows how you might use the Handle-Error function in a try-catch block.
If an error occurs in the try block, the catch block catches it and calls Handle-Error,
passing the error (represented by the $_ variable) to the function.
#>
param($ErrorRecord)
# Store current value
$OriginalErrorActionPreference = $ErrorActionPreference
# Set to silently continue
$ErrorActionPreference = 'SilentlyContinue'
if ($ErrorRecord.Exception.Message -match '0x80073D06') {
Write-Warning "Higher version already installed."
Write-Warning "That's okay, continuing..."
} elseif ($ErrorRecord.Exception.Message -match '0x80073CF0') {
Write-Warning "Same version already installed."
Write-Warning "That's okay, continuing..."
} elseif ($ErrorRecord.Exception.Message -match '0x80073D02') {
# Stop execution and return the ErrorRecord so that the calling try/catch block throws the error
Write-Warning "Resources modified are in-use. Try closing Windows Terminal / PowerShell / Command Prompt and try again."
Write-Warning "If the problem persists, restart your computer."
return $ErrorRecord
} elseif ($ErrorRecord.Exception.Message -match 'Unable to connect to the remote server') {
Write-Warning "Cannot connect to the Internet to download the required files."
Write-Warning "Try running the script again and make sure you are connected to the Internet."
Write-Warning "Sometimes the nuget.org server is down, so you may need to try again later."
return $ErrorRecord
} elseif ($ErrorRecord.Exception.Message -match "The remote name could not be resolved") {
Write-Warning "Cannot connect to the Internet to download the required files."
Write-Warning "Try running the script again and make sure you are connected to the Internet."
Write-Warning "Make sure DNS is working correctly on your computer."
} else {
# For other errors, we should stop the execution and return the ErrorRecord so that the calling try/catch block throws the error
return $ErrorRecord
}
# Reset to original value
$ErrorActionPreference = $OriginalErrorActionPreference
}
function Cleanup {
<#
.SYNOPSIS
Deletes a file or directory specified without prompting for confirmation or displaying errors.
.DESCRIPTION
This function takes a path to a file or directory and deletes it without prompting for confirmation or displaying errors.
If the path is a directory, the function will delete the directory and all its contents.
.PARAMETER Path
The path of the file or directory to be deleted.
.PARAMETER Recurse
If the path is a directory, this switch specifies whether to delete the directory and all its contents.
.EXAMPLE
Cleanup -Path "C:\Temp"
This example deletes the directory "C:\Temp" and all its contents.
.EXAMPLE
Cleanup -Path "C:\Temp" -Recurse
This example deletes the directory "C:\Temp" and all its contents.
.EXAMPLE
Cleanup -Path "C:\Temp\file.txt"
This example deletes the file "C:\Temp\file.txt".
#>
param (
[string]$Path,
[switch]$Recurse
)
try {
if (Test-Path -Path $Path) {
if ($Recurse -and (Get-Item -Path $Path) -is [System.IO.DirectoryInfo]) {
Get-ChildItem -Path $Path -Recurse | Remove-Item -Force -Recurse
Remove-Item -Path $Path -Force -Recurse
} else {
Remove-Item -Path $Path -Force
}
}
if ($DebugMode) {
Write-Output "Deleted: $Path"
}
} catch {
# Errors are ignored
}
}
function Install-Prerequisite {
<#
.SYNOPSIS
Downloads and installs a prerequisite for winget.
.DESCRIPTION
This function takes a name, version, URL, alternate URL, content type, and body and downloads and installs the prerequisite.
.PARAMETER Name
The name of the prerequisite.
.PARAMETER Version
The version of the prerequisite.
.PARAMETER Url
The URL of the prerequisite.
.PARAMETER AlternateUrl
The alternate URL of the prerequisite.
.PARAMETER ContentType
The content type of the prerequisite.
.PARAMETER Body
The body of the prerequisite.
.PARAMETER NupkgVersion
The nupkg version of the prerequisite.
.PARAMETER AppxFileVersion
The appx file version of the prerequisite.
.EXAMPLE
Install-Prerequisite -Name "VCLibs" -Version "14.00" -Url "https://store.rg-adguard.net/api/GetFiles" -AlternateUrl "https://aka.ms/Microsoft.VCLibs.$arch.14.00.Desktop.appx" -ContentType "application/x-www-form-urlencoded" -Body "type=PackageFamilyName&url=Microsoft.VCLibs.140.00_8wekyb3d8bbwe&ring=RP&lang=en-US"
Where $arch is the architecture type of the current system.
#>
param (
[string]$Name,
[string]$Url,
[string]$AlternateUrl,
[string]$ContentType,
[string]$Body,
[string]$NupkgVersion,
[string]$AppxFileVersion
)
$osVersion = Get-OSInfo
$arch = $osVersion.Architecture
Write-Section "Downloading & installing ${arch} ${Name}..."
$ThrowReason = @{
Message = ""
Code = 0
}
try {
# ============================================================================ #
# Windows 10 / Server 2022 detection
# ============================================================================ #
# Function to extract domain from URL
function Get-DomainFromUrl($url) {
$uri = [System.Uri]$url
$domain = $uri.Host -replace "^www\."
return $domain
}
# If Server 2022 or Windows 10, force non-store version of VCLibs (return true)
$messageTemplate = "{OS} detected. Using {DOMAIN} version of {NAME}."
# Determine the OS-specific information
$osType = $osVersion.Type
$osNumericVersion = $osVersion.NumericVersion
if (($osType -eq "Server" -and $osNumericVersion -eq 2022) -or ($osType -eq "Workstation" -and $osNumericVersion -eq 10)) {
if ($osType -eq "Server") {
$osName = "Server 2022"
} else {
$osName = "Windows 10"
}
$domain = Get-DomainFromUrl $AlternateUrl
$ThrowReason.Message = ($messageTemplate -replace "{OS}", $osName) -replace "{NAME}", $Name -replace "{DOMAIN}", $domain
$ThrowReason.Code = 1
throw
}
# ============================================================================ #
# Primary method
# ============================================================================ #
$url = Invoke-WebRequest -Uri $Url -Method "POST" -ContentType $ContentType -Body $Body -UseBasicParsing | ForEach-Object Links | Where-Object outerHTML -match "$Name.+_${arch}__8wekyb3d8bbwe.appx" | ForEach-Object href
# If the URL is empty, try the alternate method
if ($url -eq "") {
$ThrowReason.Message = "URL is empty"
$ThrowReason.Code = 2
throw
}
if ($DebugMode) {
Write-Output "URL: ${url}`n"
}
Write-Output "Installing ${arch} ${Name}..."
Add-AppxPackage $url -ErrorAction Stop
Write-Output "`n$Name installed successfully."
} catch {
# Alternate method
if ($_.Exception.Message -match '0x80073D02') {
# If resources in use exception, fail immediately
Handle-Error $_
throw
}
try {
$url = $AlternateUrl
# Throw reason if alternate method is required
if ($ThrowReason.Code -eq 0) {
Write-Warning "Error when trying to download or install $Name. Trying alternate method..."
} else {
Write-Warning $ThrowReason.Message
}
Write-Output ""
# If the URL is empty, throw error
if ($url -eq "") {
throw "URL is empty"
}
# Specific logic for VCLibs alternate method
if ($Name -eq "VCLibs") {
if ($DebugMode) {
Write-Output "URL: $($url)`n"
}
Write-Output "Installing ${arch} ${Name}..."
Add-AppxPackage $url -ErrorAction Stop
Write-Output "`n$Name installed successfully."
}
# Specific logic for UI.Xaml
if ($Name -eq "UI.Xaml") {
$TempFolder = Get-TempFolder
$uiXaml = @{
url = $url
appxFolder = "tools/AppX/$arch/Release/"
appxFilename = "Microsoft.UI.Xaml.$AppxFileVersion.appx"
nupkgFilename = Join-Path -Path $TempFolder -ChildPath "Microsoft.UI.Xaml.$NupkgVersion.nupkg"
nupkgFolder = Join-Path -Path $TempFolder -ChildPath "Microsoft.UI.Xaml.$NupkgVersion"
}
# Debug
if ($DebugMode) {
$formattedDebugOutput = ($uiXaml | ConvertTo-Json -Depth 10 -Compress) -replace '\\\\', '\'
Write-Output "uiXaml:"
Write-Output $formattedDebugOutput
Write-Output ""
}
# Downloading
Write-Output "Downloading UI.Xaml..."
if ($DebugMode) {
Write-Output "URL: $($uiXaml.url)"
}
Invoke-WebRequest -Uri $uiXaml.url -OutFile $uiXaml.nupkgFilename
# Check if folder exists and delete if needed (will occur whether DisableCleanup is $true or $false)
Cleanup -Path $uiXaml.nupkgFolder -Recurse
# Extracting
Write-Output "Extracting...`n"
if ($DebugMode) {
Write-Output "Into folder: $($uiXaml.nupkgFolder)`n"
}
Add-Type -Assembly System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::ExtractToDirectory($uiXaml.nupkgFilename, $uiXaml.nupkgFolder)
# Prep for install
Write-Output "Installing ${arch} ${Name}..."
$XamlAppxFolder = Join-Path -Path $uiXaml.nupkgFolder -ChildPath $uiXaml.appxFolder
$XamlAppxPath = Join-Path -Path $XamlAppxFolder -ChildPath $uiXaml.appxFilename
# Debugging
if ($DebugMode) { Write-Output "Installing appx Packages in: $XamlAppxFolder" }
# Install
Get-ChildItem -Path $XamlAppxPath -Filter *.appx | ForEach-Object {
if ($DebugMode) { Write-Output "Installing appx Package: $($_.Name)" }
Add-AppxPackage $_.FullName -ErrorAction Stop
}
Write-Output "`nUI.Xaml installed successfully."
# Cleanup
if ($DisableCleanup -eq $false) {
if ($DebugMode) { Write-Output "" } # Extra line break for readability if DebugMode is enabled
Cleanup -Path $uiXaml.nupkgFilename
Cleanup -Path $uiXaml.nupkgFolder -Recurse $true
}
}
} catch {
# If unable to connect to remote server and Windows 10 or Server 2022, display warning message
$ShowOldVersionMessage = $False
if ($_.Exception.Message -match "Unable to connect to the remote server") {
# Determine the correct Windows caption and set $ShowOutput to $True if conditions are met
if ($osVersion.Type -eq "Workstation" -and $osVersion.NumericVersion -eq 10) {
$WindowsCaption = "Windows 10"
$ShowOldVersionMessage = $True
} elseif ($osVersion.Type -eq "Server" -and $osVersion.NumericVersion -eq 2022) {
$WindowsCaption = "Server 2022"
$ShowOldVersionMessage = $True
}
# Output the warning message if $ShowOldVersionMessage is $True, otherwise output the generic error message
if ($ShowOldVersionMessage) {
$OldVersionMessage = "There is an issue connecting to the server to download $Name. Unfortunately this is a known issue with the prerequisite server URLs - sometimes they are down. Since you're using $WindowsCaption you must use the non-store versions of the prerequisites, the prerequisites from the Windows store will not work, so you may need to try again later or install manually."
Write-Warning $OldVersionMessage
} else {
Write-Warning "Error when trying to download or install $Name. Please try again later or manually install $Name."
}
}
$errorHandled = Handle-Error $_
if ($null -ne $errorHandled) {
throw $errorHandled
}
$errorHandled = $null
}
}
}
# ============================================================================ #
# Initial checks
# ============================================================================ #
# Check for updates if -CheckForUpdate is specified
if ($CheckForUpdate) {
CheckForUpdate -RepoOwner $RepoOwner -RepoName $RepoName -CurrentVersion $CurrentVersion -PowerShellGalleryName $PowerShellGalleryName
}
# Heading
Write-Output "winget-install $CurrentVersion"
Write-Output "To check for updates, run winget-install -CheckForUpdate"
# Set OS version
$osVersion = Get-OSInfo
# Set architecture type
$arch = $osVersion.Architecture
# If it's a workstation, make sure it is Windows 10+
if ($osVersion.Type -eq "Workstation" -and $osVersion.NumericVersion -lt 10) {
Write-Error "winget is only compatible with Windows 10 or greater."
exit 1
}
# If it's a workstation with Windows 10, make sure it's version 1809 or greater
if ($osVersion.Type -eq "Workstation" -and $osVersion.NumericVersion -eq 10 -and $osVersion.ReleaseId -lt 1809) {
Write-Error "winget is only compatible with Windows 10 version 1809 or greater."
exit 1
}
# If it's a server, it needs to be 2022+
if ($osVersion.Type -eq "Server" -and $osVersion.NumericVersion -lt 2022) {
Write-Error "winget is only compatible with Windows Server 2022+."
exit 1
}
# Check if winget is already installed
if (Get-WingetStatus) {
if ($Force -eq $false) {
Write-Output "winget is already installed, exiting..."
exit 0
}
}
# ============================================================================ #
# Beginning of installation process
# ============================================================================ #
try {
# ============================================================================ #
# Install prerequisites
# ============================================================================ #
# VCLibs
Install-Prerequisite -Name "VCLibs" -Version "14.00" -Url "https://store.rg-adguard.net/api/GetFiles" -AlternateUrl "https://aka.ms/Microsoft.VCLibs.$arch.14.00.Desktop.appx" -ContentType "application/x-www-form-urlencoded" -Body "type=PackageFamilyName&url=Microsoft.VCLibs.140.00_8wekyb3d8bbwe&ring=RP&lang=en-US"
# UI.Xaml
Install-Prerequisite -Name "UI.Xaml" -Version "2.7.3" -Url "https://store.rg-adguard.net/api/GetFiles" -AlternateUrl "https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3" -ContentType "application/x-www-form-urlencoded" -Body "type=ProductId&url=9P5VK8KZB5QZ&ring=RP&lang=en-US" -NupkgVersion "2.7.3" -AppxFileVersion "2.7"
# ============================================================================ #
# Install winget
# ============================================================================ #
$TempFolder = Get-TempFolder
# Output
Write-Section "Downloading & installing winget..."
Write-Output "Retrieving download URL for winget from GitHub..."
$wingetUrl = Get-WingetDownloadUrl -Match "msixbundle"
$wingetPath = Join-Path -Path $tempFolder -ChildPath "winget.msixbundle"
$wingetLicenseUrl = Get-WingetDownloadUrl -Match "License1.xml"
$wingetLicensePath = Join-Path -Path $tempFolder -ChildPath "license1.xml"
# If the URL is empty, throw error
if ($wingetUrl -eq "") {
throw "URL is empty"
}
Write-Output "Downloading winget..."
if ($DebugMode) {
Write-Output "`nURL: $wingetUrl"
Write-Output "Saving as: $wingetPath"
}
Invoke-WebRequest -Uri $wingetUrl -OutFile $wingetPath
Write-Output "Downloading license..."
if ($DebugMode) {
Write-Output "`nURL: $wingetLicenseUrl"
Write-Output "Saving as: $wingetLicensePath"
}
Invoke-WebRequest -Uri $wingetLicenseUrl -OutFile $wingetLicensePath
Write-Output "`nInstalling winget..."
# Debugging
if ($DebugMode) {
Write-Output "wingetPath: $wingetPath"
Write-Output "wingetLicensePath: $wingetLicensePath"
}
# Try to install winget
try {
# Add-AppxPackage will throw an error if the app is already installed or higher version installed, so we need to catch it and continue
Add-AppxProvisionedPackage -Online -PackagePath $wingetPath -LicensePath $wingetLicensePath -ErrorAction SilentlyContinue | Out-Null
Write-Output "`nwinget installed successfully."
} catch {
$errorHandled = Handle-Error $_
if ($null -ne $errorHandled) {
throw $errorHandled
}
$errorHandled = $null
}
# Cleanup
if ($DisableCleanup -eq $false) {
if ($DebugMode) { Write-Output "" } # Extra line break for readability if DebugMode is enabled
Cleanup -Path $wingetPath
Cleanup -Path $wingetLicensePath
}
# ============================================================================ #
# PATH environment variable
# ============================================================================ #
# Add the WindowsApps directory to the PATH variable
Write-Section "Checking and adding WindowsApps directory to PATH variable for current user if not present..."
$WindowsAppsPath = [IO.Path]::Combine([Environment]::GetEnvironmentVariable("LOCALAPPDATA"), "Microsoft", "WindowsApps")
Update-PathEnvironmentVariable -NewPath $WindowsAppsPath
# ============================================================================ #
# Finished
# ============================================================================ #
Write-Section "Installation complete!"
# Timeout for 5 seconds to check winget
Write-Output "Checking if winget is installed and working..."
Start-Sleep -Seconds 3
# Check if winget is installed
if (Get-WingetStatus -eq $true) {
Write-Output "winget is installed and working now, you can go ahead and use it."
} else {
Write-Warning "winget is installed but is not detected as a command. Try using winget now. If it doesn't work, wait about 1 minute and try again (it is sometimes delayed). Also try restarting your computer."
Write-Warning "If you restart your computer and the command still isn't recognized, please read the Troubleshooting section`nof the README: https://github.com/asheroto/winget-install#troubleshooting`n"
Write-Warning "Make sure you have the latest version of the script by running this command: $PowerShellGalleryName -CheckForUpdate"
}
} catch {
# ============================================================================ #
# Error handling
# ============================================================================ #
Write-Section "WARNING! An error occurred during installation!"
Write-Warning "If messages above don't help and the problem persists, please read the Troubleshooting section`nof the README: https://github.com/asheroto/winget-install#troubleshooting"
Write-Warning "Make sure you have the latest version of the script by running this command: $PowerShellGalleryName -CheckForUpdate"
# If it's not 0x80073D02 (resources in use), show error
if ($_.Exception.Message -notmatch '0x80073D02') {
if ($DebugMode) {
Write-Warning "Line number : $($_.InvocationInfo.ScriptLineNumber)"
}
Write-Warning "Error: $($_.Exception.Message)`n"
}
}

Some files were not shown because too many files have changed in this diff Show More