mirror of
https://github.com/ChrisTitusTech/winutil
synced 2026-04-06 14:48:31 +00:00
Compare commits
11 Commits
nullsafe-i
...
d0012449ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0012449ad | ||
|
|
18594f6d2d | ||
|
|
50c4398394 | ||
|
|
ed5ec52767 | ||
|
|
319ee4e555 | ||
|
|
2ef7f2deb9 | ||
|
|
cca9bee107 | ||
|
|
669ecd9c64 | ||
|
|
64ea075727 | ||
|
|
773ea3a950 | ||
|
|
410d3c5056 |
32
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
32
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -6,6 +6,9 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
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**
|
## ⚠️ **IMPORTANT**
|
||||||
- 🛠️ **Supported environments only:** We only support Windows 11.
|
- 🛠️ **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).
|
- 💡 For general questions, use the [Discussions section](https://github.com/Christitustech/winutil/discussions) or join our Community-driven [Discord Server](https://discord.gg/RUbZUZyByQ).
|
||||||
@@ -21,16 +24,11 @@ body:
|
|||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
- type: dropdown
|
- type: input
|
||||||
id: affected_part
|
id: affected_part
|
||||||
attributes:
|
attributes:
|
||||||
label: What part of Winutil are you having issues with?
|
label: 📜 What part of Winutil are you having issues with?
|
||||||
options:
|
placeholder: "e.g., Tweaks, etc."
|
||||||
- Program Install Tab
|
|
||||||
- Tweaks Tab
|
|
||||||
- Config Tab
|
|
||||||
- Updates Tab
|
|
||||||
- Win11 Creator Tab
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@@ -41,8 +39,24 @@ body:
|
|||||||
validations:
|
validations:
|
||||||
required: true
|
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
|
- type: textarea
|
||||||
id: error_output
|
id: error_output
|
||||||
attributes:
|
attributes:
|
||||||
label: ❌ Paste the full error output (if available) or Screenshot.
|
label: ❌ Paste the full error output (if available).
|
||||||
placeholder: "Include any relevant logs or error messages."
|
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
|
||||||
|
|||||||
37
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
37
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@@ -13,10 +13,45 @@ body:
|
|||||||
- 🛠️ **Supported environments only:** We only support Windows 11.
|
- 🛠️ **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).
|
- 💡 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
|
- type: textarea
|
||||||
id: proposed_solution
|
id: proposed_solution
|
||||||
attributes:
|
attributes:
|
||||||
label: 💡 Describe the solution you'd like
|
label: 💡 Describe the solution you'd like
|
||||||
placeholder: "Provide a clear and concise description."
|
placeholder: "Provide a clear and concise description of what you want to happen."
|
||||||
validations:
|
validations:
|
||||||
required: true
|
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
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
"category": "Document",
|
"category": "Document",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "AFFiNE",
|
"content": "AFFiNE",
|
||||||
"description": "AFFiNE is an open-source alternative to Notion. Write, draw, plan all at once. Selfhost it to sync across devices.",
|
"description": "AFFiNE is an open source alternative to Notion. Write, draw, plan all at once. Selfhost it to sync across devices.",
|
||||||
"link": "https://affine.pro/",
|
"link": "https://affine.pro/",
|
||||||
"winget": "ToEverything.AFFiNE",
|
"winget": "ToEverything.AFFiNE",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
"category": "Microsoft Tools",
|
"category": "Microsoft Tools",
|
||||||
"choco": "autoruns",
|
"choco": "autoruns",
|
||||||
"content": "Autoruns",
|
"content": "Autoruns",
|
||||||
"description": "This utility shows you what programs are configured to run during system bootup or login.",
|
"description": "This utility shows you what programs are configured to run during system bootup or login",
|
||||||
"link": "https://learn.microsoft.com/en-us/sysinternals/downloads/autoruns",
|
"link": "https://learn.microsoft.com/en-us/sysinternals/downloads/autoruns",
|
||||||
"winget": "Microsoft.Sysinternals.Autoruns"
|
"winget": "Microsoft.Sysinternals.Autoruns"
|
||||||
},
|
},
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
"category": "Communications",
|
"category": "Communications",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "Beeper",
|
"content": "Beeper",
|
||||||
"description": "All your chats in one app.",
|
"description": "All your chats in one app",
|
||||||
"link": "https://www.beeper.com/",
|
"link": "https://www.beeper.com/",
|
||||||
"winget": "Beeper.Beeper"
|
"winget": "Beeper.Beeper"
|
||||||
},
|
},
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "bleachbit",
|
"choco": "bleachbit",
|
||||||
"content": "BleachBit",
|
"content": "BleachBit",
|
||||||
"description": "Clean Your System and Free Disk Space.",
|
"description": "Clean Your System and Free Disk Space",
|
||||||
"link": "https://www.bleachbit.org/",
|
"link": "https://www.bleachbit.org/",
|
||||||
"winget": "BleachBit.BleachBit",
|
"winget": "BleachBit.BleachBit",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -593,7 +593,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "espanso",
|
"choco": "espanso",
|
||||||
"content": "Espanso",
|
"content": "Espanso",
|
||||||
"description": "Cross-platform and open-source Text Expander written in Rust.",
|
"description": "Cross-platform and open-source Text Expander written in Rust",
|
||||||
"link": "https://espanso.org/",
|
"link": "https://espanso.org/",
|
||||||
"winget": "Espanso.Espanso",
|
"winget": "Espanso.Espanso",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -620,7 +620,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "Fastfetch",
|
"content": "Fastfetch",
|
||||||
"description": "Fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way.",
|
"description": "Fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way",
|
||||||
"link": "https://github.com/fastfetch-cli/fastfetch/",
|
"link": "https://github.com/fastfetch-cli/fastfetch/",
|
||||||
"winget": "Fastfetch-cli.Fastfetch",
|
"winget": "Fastfetch-cli.Fastfetch",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -646,7 +646,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "file-converter",
|
"choco": "file-converter",
|
||||||
"content": "File-Converter",
|
"content": "File-Converter",
|
||||||
"description": "File Converter is a very simple tool which allows you to convert and compress one or several file(s) using the context menu in Windows Explorer.",
|
"description": "File Converter is a very simple tool which allows you to convert and compress one or several file(s) using the context menu in windows explorer.",
|
||||||
"link": "https://file-converter.io/",
|
"link": "https://file-converter.io/",
|
||||||
"winget": "AdrienAllard.FileConverter",
|
"winget": "AdrienAllard.FileConverter",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -699,7 +699,7 @@
|
|||||||
"category": "Multimedia Tools",
|
"category": "Multimedia Tools",
|
||||||
"choco": "lightshot",
|
"choco": "lightshot",
|
||||||
"content": "Lightshot (Screenshots)",
|
"content": "Lightshot (Screenshots)",
|
||||||
"description": "Ligthshot is an easy-to-use, light-weight screenshot software tool, where you can optionally edit your screenshots using different tools, share them via Internet and/or save to disk, and customize the available options.",
|
"description": "Ligthshot is an Easy-to-use, light-weight screenshot software tool, where you can optionally edit your screenshots using different tools, share them via Internet and/or save to disk, and customize the available options.",
|
||||||
"link": "https://app.prntscr.com/",
|
"link": "https://app.prntscr.com/",
|
||||||
"winget": "Skillbrains.Lightshot"
|
"winget": "Skillbrains.Lightshot"
|
||||||
},
|
},
|
||||||
@@ -775,7 +775,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "fzf",
|
"choco": "fzf",
|
||||||
"content": "Fzf",
|
"content": "Fzf",
|
||||||
"description": "A command-line fuzzy finder.",
|
"description": "A command-line fuzzy finder",
|
||||||
"link": "https://github.com/junegunn/fzf/",
|
"link": "https://github.com/junegunn/fzf/",
|
||||||
"winget": "junegunn.fzf",
|
"winget": "junegunn.fzf",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -895,7 +895,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "googledrive",
|
"choco": "googledrive",
|
||||||
"content": "Google Drive",
|
"content": "Google Drive",
|
||||||
"description": "File syncing across devices all tied to your Google account.",
|
"description": "File syncing across devices all tied to your google account",
|
||||||
"link": "https://www.google.com/drive/",
|
"link": "https://www.google.com/drive/",
|
||||||
"winget": "Google.GoogleDrive"
|
"winget": "Google.GoogleDrive"
|
||||||
},
|
},
|
||||||
@@ -955,7 +955,7 @@
|
|||||||
"category": "Development",
|
"category": "Development",
|
||||||
"choco": "helix",
|
"choco": "helix",
|
||||||
"content": "Helix",
|
"content": "Helix",
|
||||||
"description": "Helix is a neovim alternative built in Rust.",
|
"description": "Helix is a neovim alternative built in rust.",
|
||||||
"link": "https://helix-editor.com/",
|
"link": "https://helix-editor.com/",
|
||||||
"winget": "Helix.Helix",
|
"winget": "Helix.Helix",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -1147,7 +1147,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "jpegview",
|
"choco": "jpegview",
|
||||||
"content": "JPEG View",
|
"content": "JPEG View",
|
||||||
"description": "JPEGView is a lean, fast and highly configurable viewer/editor for JPEG, BMP, PNG, WEBP, TGA, GIF, JXL, HEIC, HEIF, AVIF and TIFF images with a minimal GUI.",
|
"description": "JPEGView is a lean, fast and highly configurable viewer/editor for JPEG, BMP, PNG, WEBP, TGA, GIF, JXL, HEIC, HEIF, AVIF and TIFF images with a minimal GUI",
|
||||||
"link": "https://github.com/sylikc/jpegview",
|
"link": "https://github.com/sylikc/jpegview",
|
||||||
"winget": "sylikc.JPEGView",
|
"winget": "sylikc.JPEGView",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -1209,7 +1209,7 @@
|
|||||||
"category": "Development",
|
"category": "Development",
|
||||||
"choco": "lazygit",
|
"choco": "lazygit",
|
||||||
"content": "Lazygit",
|
"content": "Lazygit",
|
||||||
"description": "Simple terminal UI for git commands.",
|
"description": "Simple terminal UI for git commands",
|
||||||
"link": "https://github.com/jesseduffield/lazygit/",
|
"link": "https://github.com/jesseduffield/lazygit/",
|
||||||
"winget": "JesseDuffield.lazygit",
|
"winget": "JesseDuffield.lazygit",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -1262,7 +1262,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "localsend.install",
|
"choco": "localsend.install",
|
||||||
"content": "LocalSend",
|
"content": "LocalSend",
|
||||||
"description": "An open-source cross-platform alternative to AirDrop.",
|
"description": "An open source cross-platform alternative to AirDrop.",
|
||||||
"link": "https://localsend.org/",
|
"link": "https://localsend.org/",
|
||||||
"winget": "LocalSend.LocalSend",
|
"winget": "LocalSend.LocalSend",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -1323,7 +1323,7 @@
|
|||||||
"category": "Multimedia Tools",
|
"category": "Multimedia Tools",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "Modern Flyouts",
|
"content": "Modern Flyouts",
|
||||||
"description": "An open-source, modern, Fluent Design-based set of flyouts for Windows.",
|
"description": "An open source, modern, Fluent Design-based set of flyouts for Windows.",
|
||||||
"link": "https://github.com/ModernFlyouts-Community/ModernFlyouts/",
|
"link": "https://github.com/ModernFlyouts-Community/ModernFlyouts/",
|
||||||
"winget": "ModernFlyouts.ModernFlyouts",
|
"winget": "ModernFlyouts.ModernFlyouts",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -1377,7 +1377,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "msedgeredirect",
|
"choco": "msedgeredirect",
|
||||||
"content": "MSEdgeRedirect",
|
"content": "MSEdgeRedirect",
|
||||||
"description": "A Tool to Redirect News, Search, Widgets, Weather, and More to your default browser.",
|
"description": "A Tool to Redirect News, Search, Widgets, Weather, and More to Your Default Browser.",
|
||||||
"link": "https://github.com/rcmaehl/MSEdgeRedirect",
|
"link": "https://github.com/rcmaehl/MSEdgeRedirect",
|
||||||
"winget": "rcmaehl.MSEdgeRedirect",
|
"winget": "rcmaehl.MSEdgeRedirect",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -1473,7 +1473,7 @@
|
|||||||
"category": "Multimedia Tools",
|
"category": "Multimedia Tools",
|
||||||
"choco": "tagscanner",
|
"choco": "tagscanner",
|
||||||
"content": "TagScanner (Tag Scanner)",
|
"content": "TagScanner (Tag Scanner)",
|
||||||
"description": "TagScanner is a powerful tool for organizing and managing your music collection.",
|
"description": "TagScanner is a powerful tool for organizing and managing your music collection",
|
||||||
"link": "https://www.xdlab.ru/en/",
|
"link": "https://www.xdlab.ru/en/",
|
||||||
"winget": "SergeySerkov.TagScanner"
|
"winget": "SergeySerkov.TagScanner"
|
||||||
},
|
},
|
||||||
@@ -1490,7 +1490,7 @@
|
|||||||
"category": "Pro Tools",
|
"category": "Pro Tools",
|
||||||
"choco": "netbird",
|
"choco": "netbird",
|
||||||
"content": "NetBird",
|
"content": "NetBird",
|
||||||
"description": "NetBird is a open-source alternative comparable to TailScale that can be connected to a selfhosted Server.",
|
"description": "NetBird is a Open Source alternative comparable to TailScale that can be connected to a selfhosted Server.",
|
||||||
"link": "https://netbird.io/",
|
"link": "https://netbird.io/",
|
||||||
"winget": "netbird",
|
"winget": "netbird",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -1895,7 +1895,7 @@
|
|||||||
"category": "Games",
|
"category": "Games",
|
||||||
"choco": "prismlauncher",
|
"choco": "prismlauncher",
|
||||||
"content": "Prism Launcher",
|
"content": "Prism Launcher",
|
||||||
"description": "Prism Launcher is an open-source Minecraft launcher with the ability to manage multiple instances, accounts and mods.",
|
"description": "Prism Launcher is an Open Source Minecraft launcher with the ability to manage multiple instances, accounts and mods.",
|
||||||
"link": "https://prismlauncher.org/",
|
"link": "https://prismlauncher.org/",
|
||||||
"winget": "PrismLauncher.PrismLauncher",
|
"winget": "PrismLauncher.PrismLauncher",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -1929,7 +1929,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "orcaslicer",
|
"choco": "orcaslicer",
|
||||||
"content": "OrcaSlicer",
|
"content": "OrcaSlicer",
|
||||||
"description": "G-code generator for 3D printers (Bambu, Prusa, Voron, VzBot, RatRig, Creality, etc.).",
|
"description": "G-code generator for 3D printers (Bambu, Prusa, Voron, VzBot, RatRig, Creality, etc.)",
|
||||||
"link": "https://github.com/SoftFever/OrcaSlicer",
|
"link": "https://github.com/SoftFever/OrcaSlicer",
|
||||||
"winget": "SoftFever.OrcaSlicer",
|
"winget": "SoftFever.OrcaSlicer",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -1982,7 +1982,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "transmission",
|
"choco": "transmission",
|
||||||
"content": "Transmission",
|
"content": "Transmission",
|
||||||
"description": "Transmission is a cross-platform BitTorrent client that is open-source, easy, powerful, and lean.",
|
"description": "Transmission is a cross-platform BitTorrent client that is open source, easy, powerful, and lean.",
|
||||||
"link": "https://transmissionbt.com/",
|
"link": "https://transmissionbt.com/",
|
||||||
"winget": "Transmission.Transmission",
|
"winget": "Transmission.Transmission",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2008,7 +2008,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "quicklook",
|
"choco": "quicklook",
|
||||||
"content": "Quicklook",
|
"content": "Quicklook",
|
||||||
"description": "Bring macOS \u201cQuick Look\u201d feature to Windows.",
|
"description": "Bring macOS \u201cQuick Look\u201d feature to Windows",
|
||||||
"link": "https://github.com/QL-Win/QuickLook",
|
"link": "https://github.com/QL-Win/QuickLook",
|
||||||
"winget": "QL-Win.QuickLook",
|
"winget": "QL-Win.QuickLook",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2051,7 +2051,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "ripgrep",
|
"choco": "ripgrep",
|
||||||
"content": "Ripgrep",
|
"content": "Ripgrep",
|
||||||
"description": "Fast and powerful commandline search tool.",
|
"description": "Fast and powerful commandline search tool",
|
||||||
"link": "https://github.com/BurntSushi/ripgrep/",
|
"link": "https://github.com/BurntSushi/ripgrep/",
|
||||||
"winget": "BurntSushi.ripgrep.MSVC",
|
"winget": "BurntSushi.ripgrep.MSVC",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2209,7 +2209,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "spacesniffer",
|
"choco": "spacesniffer",
|
||||||
"content": "SpaceSniffer",
|
"content": "SpaceSniffer",
|
||||||
"description": "A tool application that lets you understand how folders and files are structured on your disks.",
|
"description": "A tool application that lets you understand how folders and files are structured on your disks",
|
||||||
"link": "http://www.uderzo.it/main_products/space_sniffer/",
|
"link": "http://www.uderzo.it/main_products/space_sniffer/",
|
||||||
"winget": "UderzoSoftware.SpaceSniffer"
|
"winget": "UderzoSoftware.SpaceSniffer"
|
||||||
},
|
},
|
||||||
@@ -2277,7 +2277,7 @@
|
|||||||
"category": "Document",
|
"category": "Document",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "PDFgear",
|
"content": "PDFgear",
|
||||||
"description": "PDFgear is a piece of full-featured PDF management software for Windows, macOS, and mobile, and it's completely free to use.",
|
"description": "PDFgear is a piece of full-featured PDF management software for Windows, Mac, and mobile, and it's completely free to use.",
|
||||||
"link": "https://www.pdfgear.com/",
|
"link": "https://www.pdfgear.com/",
|
||||||
"winget": "PDFgear.PDFgear"
|
"winget": "PDFgear.PDFgear"
|
||||||
},
|
},
|
||||||
@@ -2312,7 +2312,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "synctrayzor",
|
"choco": "synctrayzor",
|
||||||
"content": "SyncTrayzor",
|
"content": "SyncTrayzor",
|
||||||
"description": "Windows tray utility / filesystem watcher / launcher for Syncthing.",
|
"description": "Windows tray utility / filesystem watcher / launcher for Syncthing",
|
||||||
"link": "https://github.com/GermanCoding/SyncTrayzor",
|
"link": "https://github.com/GermanCoding/SyncTrayzor",
|
||||||
"winget": "GermanCoding.SyncTrayzor",
|
"winget": "GermanCoding.SyncTrayzor",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2329,7 +2329,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "tabby",
|
"choco": "tabby",
|
||||||
"content": "Tabby.sh",
|
"content": "Tabby.sh",
|
||||||
"description": "Tabby is a highly configurable terminal emulator, SSH and serial client for Windows, macOS and Linux.",
|
"description": "Tabby is a highly configurable terminal emulator, SSH and serial client for Windows, macOS and Linux",
|
||||||
"link": "https://tabby.sh/",
|
"link": "https://tabby.sh/",
|
||||||
"winget": "Eugeny.Tabby",
|
"winget": "Eugeny.Tabby",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2389,7 +2389,7 @@
|
|||||||
"category": "Communications",
|
"category": "Communications",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "Unigram",
|
"content": "Unigram",
|
||||||
"description": "Unigram - Telegram for Windows.",
|
"description": "Unigram - Telegram for Windows",
|
||||||
"link": "https://unigramdev.github.io/",
|
"link": "https://unigramdev.github.io/",
|
||||||
"winget": "Telegram.Unigram",
|
"winget": "Telegram.Unigram",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2416,7 +2416,7 @@
|
|||||||
"category": "Development",
|
"category": "Development",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "Code With Mu (Mu Editor)",
|
"content": "Code With Mu (Mu Editor)",
|
||||||
"description": "Mu is a Python code editor for beginner programmers.",
|
"description": "Mu is a Python code editor for beginner programmers",
|
||||||
"link": "https://codewith.mu/",
|
"link": "https://codewith.mu/",
|
||||||
"winget": "Mu.Mu",
|
"winget": "Mu.Mu",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2425,7 +2425,7 @@
|
|||||||
"category": "Browsers",
|
"category": "Browsers",
|
||||||
"choco": "thorium",
|
"choco": "thorium",
|
||||||
"content": "Thorium Browser AVX2",
|
"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.",
|
"description": "Browser built for speed over vanilla chromium. It is built with AVX2 optimizations and is the fastest browser on the market.",
|
||||||
"link": "https://thorium.rocks/",
|
"link": "https://thorium.rocks/",
|
||||||
"winget": "Alex313031.Thorium.AVX2",
|
"winget": "Alex313031.Thorium.AVX2",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2485,7 +2485,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "translucenttb",
|
"choco": "translucenttb",
|
||||||
"content": "TranslucentTB",
|
"content": "TranslucentTB",
|
||||||
"description": "TranslucentTB is a tool that allows you to customize the transparency of the Windows Taskbar.",
|
"description": "TranslucentTB is a tool that allows you to customize the transparency of the Windows taskbar.",
|
||||||
"link": "https://github.com/TranslucentTB/TranslucentTB",
|
"link": "https://github.com/TranslucentTB/TranslucentTB",
|
||||||
"winget": "9PF4KZ2VN4W9",
|
"winget": "9PF4KZ2VN4W9",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2673,7 +2673,7 @@
|
|||||||
"category": "Development",
|
"category": "Development",
|
||||||
"choco": "wezterm",
|
"choco": "wezterm",
|
||||||
"content": "Wezterm",
|
"content": "Wezterm",
|
||||||
"description": "WezTerm is a powerful cross-platform terminal emulator and multiplexer.",
|
"description": "WezTerm is a powerful cross-platform terminal emulator and multiplexer",
|
||||||
"link": "https://wezfurlong.org/wezterm/index.html",
|
"link": "https://wezfurlong.org/wezterm/index.html",
|
||||||
"winget": "wez.wezterm",
|
"winget": "wez.wezterm",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2768,7 +2768,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "TeraCopy",
|
"choco": "TeraCopy",
|
||||||
"content": "TeraCopy",
|
"content": "TeraCopy",
|
||||||
"description": "Copy your files faster and more securely.",
|
"description": "Copy your files faster and more securely",
|
||||||
"link": "https://codesector.com/teracopy",
|
"link": "https://codesector.com/teracopy",
|
||||||
"winget": "CodeSector.TeraCopy"
|
"winget": "CodeSector.TeraCopy"
|
||||||
},
|
},
|
||||||
@@ -2792,7 +2792,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "xdm",
|
"choco": "xdm",
|
||||||
"content": "Xtreme Download Manager",
|
"content": "Xtreme Download Manager",
|
||||||
"description": "Xtreme Download Manager is an advanced download manager with support for various protocols and browsers. *Browser integration deprecated by google store. No official release.*",
|
"description": "Xtreme Download Manager is an advanced download manager with support for various protocols and browsers.*Browser integration deprecated by google store. No official release.*",
|
||||||
"link": "https://xtremedownloadmanager.com/",
|
"link": "https://xtremedownloadmanager.com/",
|
||||||
"winget": "subhra74.XtremeDownloadManager",
|
"winget": "subhra74.XtremeDownloadManager",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2896,7 +2896,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "ZoomIt",
|
"content": "ZoomIt",
|
||||||
"description": "A screen zoom, annotation, and recording tool for technical presentations and demos.",
|
"description": "A screen zoom, annotation, and recording tool for technical presentations and demos",
|
||||||
"link": "https://learn.microsoft.com/en-us/sysinternals/downloads/zoomit",
|
"link": "https://learn.microsoft.com/en-us/sysinternals/downloads/zoomit",
|
||||||
"winget": "Microsoft.Sysinternals.ZoomIt"
|
"winget": "Microsoft.Sysinternals.ZoomIt"
|
||||||
},
|
},
|
||||||
@@ -2931,7 +2931,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "syncthingtray",
|
"choco": "syncthingtray",
|
||||||
"content": "Syncthingtray",
|
"content": "Syncthingtray",
|
||||||
"description": "Might be the alternative for Synctrayzor. Windows tray utility / filesystem watcher / launcher for Syncthing.",
|
"description": "Might be the alternative for Synctrayzor. Windows tray utility / filesystem watcher / launcher for Syncthing",
|
||||||
"link": "https://github.com/Martchus/syncthingtray",
|
"link": "https://github.com/Martchus/syncthingtray",
|
||||||
"winget": "Martchus.syncthingtray",
|
"winget": "Martchus.syncthingtray",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2958,7 +2958,7 @@
|
|||||||
"category": "Development",
|
"category": "Development",
|
||||||
"choco": "temurin",
|
"choco": "temurin",
|
||||||
"content": "Eclipse Temurin",
|
"content": "Eclipse Temurin",
|
||||||
"description": "Eclipse Temurin is the open-source Java SE build based upon OpenJDK.",
|
"description": "Eclipse Temurin is the open source Java SE build based upon OpenJDK.",
|
||||||
"link": "https://adoptium.net/temurin/",
|
"link": "https://adoptium.net/temurin/",
|
||||||
"winget": "EclipseAdoptium.Temurin.21.JDK",
|
"winget": "EclipseAdoptium.Temurin.21.JDK",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -2985,7 +2985,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "TightVNC",
|
"choco": "TightVNC",
|
||||||
"content": "TightVNC",
|
"content": "TightVNC",
|
||||||
"description": "TightVNC is a free and open-source remote desktop software that lets you access and control a computer over the network. With its intuitive interface, you can interact with the remote screen as if you were sitting in front of it. You can open files, launch applications, and perform other actions on the remote desktop almost as if you were physically there.",
|
"description": "TightVNC is a free and Open Source remote desktop software that lets you access and control a computer over the network. With its intuitive interface, you can interact with the remote screen as if you were sitting in front of it. You can open files, launch applications, and perform other actions on the remote desktop almost as if you were physically there",
|
||||||
"link": "https://www.tightvnc.com/",
|
"link": "https://www.tightvnc.com/",
|
||||||
"winget": "GlavSoft.TightVNC",
|
"winget": "GlavSoft.TightVNC",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3019,7 +3019,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "auto-dark-mode",
|
"choco": "auto-dark-mode",
|
||||||
"content": "Windows Auto Dark Mode",
|
"content": "Windows Auto Dark Mode",
|
||||||
"description": "Automatically switches between the dark and light theme of Windows 10 and Windows 11.",
|
"description": "Automatically switches between the dark and light theme of Windows 10 and Windows 11",
|
||||||
"link": "https://github.com/AutoDarkMode/Windows-Auto-Night-Mode",
|
"link": "https://github.com/AutoDarkMode/Windows-Auto-Night-Mode",
|
||||||
"winget": "Armin2208.WindowsAutoNightMode",
|
"winget": "Armin2208.WindowsAutoNightMode",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3037,7 +3037,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "magic-wormhole",
|
"choco": "magic-wormhole",
|
||||||
"content": "Magic Wormhole",
|
"content": "Magic Wormhole",
|
||||||
"description": "get things from one computer to another, safely.",
|
"description": "get things from one computer to another, safely",
|
||||||
"link": "https://github.com/magic-wormhole/magic-wormhole",
|
"link": "https://github.com/magic-wormhole/magic-wormhole",
|
||||||
"winget": "magic-wormhole.magic-wormhole",
|
"winget": "magic-wormhole.magic-wormhole",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3055,7 +3055,7 @@
|
|||||||
"category": "Multimedia Tools",
|
"category": "Multimedia Tools",
|
||||||
"choco": "qgis",
|
"choco": "qgis",
|
||||||
"content": "QGIS",
|
"content": "QGIS",
|
||||||
"description": "QGIS (Quantum GIS) is an open-source Geographic Information System (GIS) software that enables users to create, edit, visualize, analyze, and publish geospatial information on Windows, macOS, and Linux platforms.",
|
"description": "QGIS (Quantum GIS) is an open-source Geographic Information System (GIS) software that enables users to create, edit, visualize, analyze, and publish geospatial information on Windows, Mac, and Linux platforms.",
|
||||||
"link": "https://qgis.org/en/site/",
|
"link": "https://qgis.org/en/site/",
|
||||||
"winget": "OSGeo.QGIS",
|
"winget": "OSGeo.QGIS",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3073,7 +3073,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "GlazeWM",
|
"content": "GlazeWM",
|
||||||
"description": "GlazeWM is a tiling window manager for Windows inspired by i3 and Polybar.",
|
"description": "GlazeWM is a tiling window manager for Windows inspired by i3 and Polybar",
|
||||||
"link": "https://github.com/glzr-io/glazewm",
|
"link": "https://github.com/glzr-io/glazewm",
|
||||||
"winget": "glzr-io.glazewm",
|
"winget": "glzr-io.glazewm",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3091,7 +3091,7 @@
|
|||||||
"category": "Development",
|
"category": "Development",
|
||||||
"choco": "fnm",
|
"choco": "fnm",
|
||||||
"content": "Fast Node Manager",
|
"content": "Fast Node Manager",
|
||||||
"description": "Fast Node Manager (fnm) allows you to switch your Node version by using the terminal.",
|
"description": "Fast Node Manager (fnm) allows you to switch your Node version by using the Terminal",
|
||||||
"link": "https://github.com/Schniz/fnm",
|
"link": "https://github.com/Schniz/fnm",
|
||||||
"winget": "Schniz.fnm",
|
"winget": "Schniz.fnm",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3100,7 +3100,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "windhawk",
|
"choco": "windhawk",
|
||||||
"content": "Windhawk",
|
"content": "Windhawk",
|
||||||
"description": "The customization marketplace for Windows programs.",
|
"description": "The customization marketplace for Windows programs",
|
||||||
"link": "https://windhawk.net",
|
"link": "https://windhawk.net",
|
||||||
"winget": "RamenSoftware.Windhawk"
|
"winget": "RamenSoftware.Windhawk"
|
||||||
},
|
},
|
||||||
@@ -3108,7 +3108,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "ForceAutoHDR",
|
"content": "ForceAutoHDR",
|
||||||
"description": "ForceAutoHDR simplifies the process of adding games to the AutoHDR list in the Windows Registry.",
|
"description": "ForceAutoHDR simplifies the process of adding games to the AutoHDR list in the Windows Registry",
|
||||||
"link": "https://github.com/7gxycn08/ForceAutoHDR",
|
"link": "https://github.com/7gxycn08/ForceAutoHDR",
|
||||||
"winget": "ForceAutoHDR.7gxycn08",
|
"winget": "ForceAutoHDR.7gxycn08",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3117,7 +3117,7 @@
|
|||||||
"category": "Utilities",
|
"category": "Utilities",
|
||||||
"choco": "joytokey",
|
"choco": "joytokey",
|
||||||
"content": "JoyToKey",
|
"content": "JoyToKey",
|
||||||
"description": "Enables PC game controllers to emulate the keyboard and mouse input.",
|
"description": "enables PC game controllers to emulate the keyboard and mouse input",
|
||||||
"link": "https://joytokey.net/en/",
|
"link": "https://joytokey.net/en/",
|
||||||
"winget": "JTKsoftware.JoyToKey"
|
"winget": "JTKsoftware.JoyToKey"
|
||||||
},
|
},
|
||||||
@@ -3159,7 +3159,7 @@
|
|||||||
"category": "Browsers",
|
"category": "Browsers",
|
||||||
"choco": "paleMoon",
|
"choco": "paleMoon",
|
||||||
"content": "PaleMoon",
|
"content": "PaleMoon",
|
||||||
"description": "Pale Moon is an open-source, Goanna-based web browser available for Microsoft Windows and Linux (with other operating systems in development), focusing on efficiency and ease of use.",
|
"description": "Pale Moon is an Open Source, Goanna-based web browser available for Microsoft Windows and Linux (with other operating systems in development), focusing on efficiency and ease of use.",
|
||||||
"link": "https://www.palemoon.org/download.shtml",
|
"link": "https://www.palemoon.org/download.shtml",
|
||||||
"winget": "MoonchildProductions.PaleMoon",
|
"winget": "MoonchildProductions.PaleMoon",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3168,7 +3168,7 @@
|
|||||||
"category": "Multimedia Tools",
|
"category": "Multimedia Tools",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "Shotcut",
|
"content": "Shotcut",
|
||||||
"description": "Shotcut is a free, open-source, cross-platform video editor.",
|
"description": "Shotcut is a free, open source, cross-platform video editor.",
|
||||||
"link": "https://shotcut.org/",
|
"link": "https://shotcut.org/",
|
||||||
"winget": "Meltytech.Shotcut",
|
"winget": "Meltytech.Shotcut",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3195,7 +3195,7 @@
|
|||||||
"category": "Development",
|
"category": "Development",
|
||||||
"choco": "aegisub",
|
"choco": "aegisub",
|
||||||
"content": "Aegisub",
|
"content": "Aegisub",
|
||||||
"description": "Aegisub is a free, cross-platform open-source tool for creating and modifying subtitles. Aegisub makes it quick and easy to time subtitles to audio, and features many powerful tools for styling them, including a built-in real-time video preview.",
|
"description": "Aegisub is a free, cross-platform open source tool for creating and modifying subtitles. Aegisub makes it quick and easy to time subtitles to audio, and features many powerful tools for styling them, including a built-in real-time video preview.",
|
||||||
"link": "https://github.com/Aegisub/Aegisub",
|
"link": "https://github.com/Aegisub/Aegisub",
|
||||||
"winget": "Aegisub.Aegisub",
|
"winget": "Aegisub.Aegisub",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3204,7 +3204,7 @@
|
|||||||
"category": "Multimedia Tools",
|
"category": "Multimedia Tools",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "Subtitle Edit",
|
"content": "Subtitle Edit",
|
||||||
"description": "Subtitle Edit is a free and open-source editor for video subtitles.",
|
"description": "Subtitle Edit is a free and open source editor for video subtitles.",
|
||||||
"link": "https://github.com/SubtitleEdit/subtitleedit",
|
"link": "https://github.com/SubtitleEdit/subtitleedit",
|
||||||
"winget": "Nikse.SubtitleEdit",
|
"winget": "Nikse.SubtitleEdit",
|
||||||
"foss": true
|
"foss": true
|
||||||
@@ -3221,7 +3221,7 @@
|
|||||||
"category": "Browsers",
|
"category": "Browsers",
|
||||||
"choco": "na",
|
"choco": "na",
|
||||||
"content": "Zen Browser",
|
"content": "Zen Browser",
|
||||||
"description": "The modern, privacy-focused, performance-driven browser built on Firefox.",
|
"description": "The modern, privacy-focused, performance-driven browser built on Firefox",
|
||||||
"link": "https://zen-browser.app/",
|
"link": "https://zen-browser.app/",
|
||||||
"winget": "Zen-Team.Zen-Browser",
|
"winget": "Zen-Team.Zen-Browser",
|
||||||
"foss": true
|
"foss": true
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
},
|
},
|
||||||
"WPFFeatureslegacymedia": {
|
"WPFFeatureslegacymedia": {
|
||||||
"Content": "Legacy Media (WMP, DirectPlay)",
|
"Content": "Legacy Media (WMP, DirectPlay)",
|
||||||
"Description": "Enables legacy programs from previous versions of Windows.",
|
"Description": "Enables legacy programs from previous versions of windows",
|
||||||
"category": "Features",
|
"category": "Features",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"feature": [
|
"feature": [
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"WPFTweaksActivity": {
|
"WPFTweaksActivity": {
|
||||||
"Content": "Disable Activity History",
|
"Content": "Disable Activity History",
|
||||||
"Description": "Erases recent docs, clipboard, and run history.",
|
"Description": "This erases recent docs, clipboard, and run history.",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksHiber": {
|
"WPFTweaksHiber": {
|
||||||
"Content": "Disable Hibernation",
|
"Content": "Disable Hibernation",
|
||||||
"Description": "Hibernation is really meant for laptops as it saves what's in memory before turning the PC off. It really should never be used.",
|
"Description": "Hibernation is really meant for laptops as it saves what's in memory before turning the pc off. It really should never be used",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksWidget": {
|
"WPFTweaksWidget": {
|
||||||
"Content": "Remove Widgets",
|
"Content": "Remove Widgets",
|
||||||
"Description": "Removes the annoying widgets in the bottom left of the Taskbar.",
|
"Description": "Removes the annoying widgets in the bottom left of the taskbar",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksRevertStartMenu": {
|
"WPFTweaksRevertStartMenu": {
|
||||||
"Content": "Revert the new start menu",
|
"Content": "Revert the new start menu",
|
||||||
"Description": "Uses vivetool to revert to the original start menu from 24H2.",
|
"Description": "Uses vivetool to revert the the original start menu from 24h2",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksLocation": {
|
"WPFTweaksLocation": {
|
||||||
"Content": "Disable Location Tracking",
|
"Content": "Disable Location Tracking",
|
||||||
"Description": "Disables Location Tracking.",
|
"Description": "Disables Location Tracking...DUH!",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -1125,7 +1125,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksBraveDebloat": {
|
"WPFTweaksBraveDebloat": {
|
||||||
"Content": "Brave Debloat",
|
"Content": "Brave Debloat",
|
||||||
"Description": "Disables various annoyances like Brave Rewards, Leo AI, Crypto Wallet and VPN.",
|
"Description": "Disables various annoyances like Brave Rewards,Leo AI,Crypto Wallet and VPN",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -1290,7 +1290,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksConsumerFeatures": {
|
"WPFTweaksConsumerFeatures": {
|
||||||
"Content": "Disable ConsumerFeatures",
|
"Content": "Disable ConsumerFeatures",
|
||||||
"Description": "Windows will not automatically install any games, third-party apps, or application links from the Windows Store for the signed-in user. Some default Apps will be inaccessible (eg. Phone Link).",
|
"Description": "Windows will not automatically install any games, third-party apps, or application links from the Windows Store for the signed-in user. Some default Apps will be inaccessible (eg. Phone Link)",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -1306,7 +1306,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksTelemetry": {
|
"WPFTweaksTelemetry": {
|
||||||
"Content": "Disable Telemetry",
|
"Content": "Disable Telemetry",
|
||||||
"Description": "Disables Microsoft Telemetry.",
|
"Description": "Disables Microsoft Telemetry...Duh",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -1428,7 +1428,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksRemoveEdge": {
|
"WPFTweaksRemoveEdge": {
|
||||||
"Content": "Remove Microsoft Edge",
|
"Content": "Remove Microsoft Edge",
|
||||||
"Description": "Unblocks Microsoft Edge uninstaller restrictions then uses that uninstaller to remove Microsoft Edge.",
|
"Description": "Unblocks Microsoft Edge uninstaller restrictions than uses that uninstaller to remove Microsoft Edge",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -1460,7 +1460,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksRemoveOneDrive": {
|
"WPFTweaksRemoveOneDrive": {
|
||||||
"Content": "Remove OneDrive",
|
"Content": "Remove OneDrive",
|
||||||
"Description": "Denies permission to remove OneDrive user files, then uses its own uninstaller to remove it and restores the original permission afterward.",
|
"Description": "Denys permission to remove onedrive user files than uses its own uninstaller to remove it than brings back permissions",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -1497,7 +1497,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksRemoveHome": {
|
"WPFTweaksRemoveHome": {
|
||||||
"Content": "Remove Home from Explorer",
|
"Content": "Remove Home from Explorer",
|
||||||
"Description": "Removes the Home from Explorer and sets This PC as default.",
|
"Description": "Removes the Home from Explorer and sets This PC as default",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -1516,7 +1516,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksRemoveGallery": {
|
"WPFTweaksRemoveGallery": {
|
||||||
"Content": "Remove Gallery from explorer",
|
"Content": "Remove Gallery from explorer",
|
||||||
"Description": "Removes the Gallery from Explorer and sets This PC as default.",
|
"Description": "Removes the Gallery from Explorer and sets This PC as default",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -1646,7 +1646,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksDeBloat": {
|
"WPFTweaksDeBloat": {
|
||||||
"Content": "Remove ALL MS Store Apps - NOT RECOMMENDED",
|
"Content": "Remove ALL MS Store Apps - NOT RECOMMENDED",
|
||||||
"Description": "USE WITH CAUTION!!! This will remove ALL Microsoft Store apps.",
|
"Description": "USE WITH CAUTION!!! This will remove ALL Microsoft store apps.",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"appx": [
|
"appx": [
|
||||||
@@ -1735,7 +1735,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksRestorePoint": {
|
"WPFTweaksRestorePoint": {
|
||||||
"Content": "Create Restore Point",
|
"Content": "Create Restore Point",
|
||||||
"Description": "Creates a restore point at runtime in case a revert is needed from WinUtil modifications.",
|
"Description": "Creates a restore point at runtime in case a revert is needed from WinUtil modifications",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"Checked": "False",
|
"Checked": "False",
|
||||||
@@ -1762,7 +1762,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksEndTaskOnTaskbar": {
|
"WPFTweaksEndTaskOnTaskbar": {
|
||||||
"Content": "Enable End Task With Right Click",
|
"Content": "Enable End Task With Right Click",
|
||||||
"Description": "Enables option to end task when right clicking a program in the taskbar.",
|
"Description": "Enables option to end task when right clicking a program in the taskbar",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -1778,7 +1778,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksPowershell7Tele": {
|
"WPFTweaksPowershell7Tele": {
|
||||||
"Content": "Disable Powershell 7 Telemetry",
|
"Content": "Disable Powershell 7 Telemetry",
|
||||||
"Description": "Creates an Environment Variable called 'POWERSHELL_TELEMETRY_OPTOUT' with a value of '1' which will tell PowerShell 7 to not send Telemetry Data.",
|
"Description": "This will create an Environment Variable called 'POWERSHELL_TELEMETRY_OPTOUT' with a value of '1' which will tell Powershell 7 to not send Telemetry Data.",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -1891,7 +1891,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksWPBT": {
|
"WPFTweaksWPBT": {
|
||||||
"Content": "Disable Windows Platform Binary Table (WPBT)",
|
"Content": "Disable Windows Platform Binary Table (WPBT)",
|
||||||
"Description": "If enabled, WPBT allows your computer vendor to execute programs at boot time, such as anti-theft software, software drivers, as well as force install software without user consent. Poses potential security risk.",
|
"Description": "If enabled then allows your computer vendor to execute a program each time it boots. It enables computer vendors to force install anti-theft software, software drivers, or a software program conveniently. This could also be a security risk.",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -1949,7 +1949,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksDisableNotifications": {
|
"WPFTweaksDisableNotifications": {
|
||||||
"Content": "Disable Notification Tray/Calendar",
|
"Content": "Disable Notification Tray/Calendar",
|
||||||
"Description": "Disables all Notifications INCLUDING Calendar.",
|
"Description": "Disables all Notifications INCLUDING Calendar",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -1972,7 +1972,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksBlockAdobeNet": {
|
"WPFTweaksBlockAdobeNet": {
|
||||||
"Content": "Adobe Network Block",
|
"Content": "Adobe Network Block",
|
||||||
"Description": "Reduces user interruptions by selectively blocking connections to Adobe's activation and telemetry servers. Credit: Ruddernation-Designs",
|
"Description": "Reduce user interruptions by selectively blocking connections to Adobe's activation and telemetry servers. Credit: Ruddernation-Designs",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -2001,8 +2001,8 @@
|
|||||||
"link": "https://winutil.christitus.com/dev/tweaks/z--advanced-tweaks---caution/blockadobenet"
|
"link": "https://winutil.christitus.com/dev/tweaks/z--advanced-tweaks---caution/blockadobenet"
|
||||||
},
|
},
|
||||||
"WPFTweaksRightClickMenu": {
|
"WPFTweaksRightClickMenu": {
|
||||||
"Content": "Set Classic Right-Click Menu",
|
"Content": "Set Classic Right-Click Menu ",
|
||||||
"Description": "Restores the classic context menu when right-clicking in File Explorer, replacing the simplified Windows 11 version.",
|
"Description": "Great Windows 11 tweak to bring back good context menus when right clicking things in explorer.",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -2037,7 +2037,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksDeleteTempFiles": {
|
"WPFTweaksDeleteTempFiles": {
|
||||||
"Content": "Delete Temporary Files",
|
"Content": "Delete Temporary Files",
|
||||||
"Description": "Erases TEMP Folders.",
|
"Description": "Erases TEMP Folders",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
@@ -2050,7 +2050,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksIPv46": {
|
"WPFTweaksIPv46": {
|
||||||
"Content": "Prefer IPv4 over IPv6",
|
"Content": "Prefer IPv4 over IPv6",
|
||||||
"Description": "Setting the IPv4 preference can have latency and security benefits on private networks where IPv6 is not configured.",
|
"Description": "To set the IPv4 preference can have latency and security benefits on private networks where IPv6 is not configured.",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -2066,7 +2066,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksTeredo": {
|
"WPFTweaksTeredo": {
|
||||||
"Content": "Disable Teredo",
|
"Content": "Disable Teredo",
|
||||||
"Description": "Teredo network tunneling is a IPv6 feature that can cause additional latency, but may cause problems with some games.",
|
"Description": "Teredo network tunneling is a ipv6 feature that can cause additional latency, but may cause problems with some games",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -2110,7 +2110,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksDisableBGapps": {
|
"WPFTweaksDisableBGapps": {
|
||||||
"Content": "Disable Background Apps",
|
"Content": "Disable Background Apps",
|
||||||
"Description": "Disables all Microsoft Store apps from running in the background, which has to be done individually since Windows 11.",
|
"Description": "Disables all Microsoft Store apps from running in the background, which has to be done individually since Win11",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -2126,7 +2126,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksDisableFSO": {
|
"WPFTweaksDisableFSO": {
|
||||||
"Content": "Disable Fullscreen Optimizations",
|
"Content": "Disable Fullscreen Optimizations",
|
||||||
"Description": "Disables FSO in all applications. NOTE: This will disable Color Management in Exclusive Fullscreen.",
|
"Description": "Disables FSO in all applications. NOTE: This will disable Color Management in Exclusive Fullscreen",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
@@ -2184,7 +2184,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleBingSearch": {
|
"WPFToggleBingSearch": {
|
||||||
"Content": "Bing Search in Start Menu",
|
"Content": "Bing Search in Start Menu",
|
||||||
"Description": "If enabled, Bing web search results will be included in your Start Menu search.",
|
"Description": "If enable then includes web search results from Bing in your Start Menu search.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2200,26 +2200,8 @@
|
|||||||
],
|
],
|
||||||
"link": "https://winutil.christitus.com/dev/tweaks/customize-preferences/bingsearch"
|
"link": "https://winutil.christitus.com/dev/tweaks/customize-preferences/bingsearch"
|
||||||
},
|
},
|
||||||
"WPFToggleStandbyFix": {
|
|
||||||
"Content": "Modern Standby fix",
|
|
||||||
"Description": "Disable network connection during S0 sleep. If network connectivity is turned on during S0 sleep it could cause overheating on modern laptops",
|
|
||||||
"category": "Customize Preferences",
|
|
||||||
"panel": "2",
|
|
||||||
"Type": "Toggle",
|
|
||||||
"registry": [
|
|
||||||
{
|
|
||||||
"Path": "HKCU:\\SOFTWARE\\Policies\\Microsoft\\Power\\PowerSettings\\f15576e8-98b7-4186-b944-eafa664402d9",
|
|
||||||
"Name": "ACSettingIndex",
|
|
||||||
"Value": "0",
|
|
||||||
"Type": "DWord",
|
|
||||||
"OriginalValue": "<RemoveEntry>",
|
|
||||||
"DefaultState": "true"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"link": "https://winutil.christitus.com/dev/tweaks/customize-preferences/standbyfix"
|
|
||||||
},
|
|
||||||
"WPFToggleNumLock": {
|
"WPFToggleNumLock": {
|
||||||
"Content": "Num Lock on Startup",
|
"Content": "NumLock on Startup",
|
||||||
"Description": "Toggle the Num Lock key state when your computer starts.",
|
"Description": "Toggle the Num Lock key state when your computer starts.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
@@ -2264,7 +2246,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleStartMenuRecommendations": {
|
"WPFToggleStartMenuRecommendations": {
|
||||||
"Content": "Recommendations in Start Menu",
|
"Content": "Recommendations in Start Menu",
|
||||||
"Description": "If disabled, then you will not see recommendations in the Start Menu. WARNING: This will also disable Windows Spotlight on your Lock Screen as a side effect.",
|
"Description": "If disabled then you will not see recommendations in the Start Menu. WARNING: This will also disable Windows Spotlight on your Lock Screen as a side effect.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2308,7 +2290,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleHideSettingsHome": {
|
"WPFToggleHideSettingsHome": {
|
||||||
"Content": "Remove Settings Home Page",
|
"Content": "Remove Settings Home Page",
|
||||||
"Description": "Removes the Home Page in the Windows Settings app.",
|
"Description": "Removes the Home page in the Windows Settings app.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2326,7 +2308,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleMouseAcceleration": {
|
"WPFToggleMouseAcceleration": {
|
||||||
"Content": "Mouse Acceleration",
|
"Content": "Mouse Acceleration",
|
||||||
"Description": "If enabled, the Cursor movement is affected by the speed of your physical mouse movements.",
|
"Description": "If Enabled then Cursor movement is affected by the speed of your physical mouse movements.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2360,7 +2342,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleStickyKeys": {
|
"WPFToggleStickyKeys": {
|
||||||
"Content": "Sticky Keys",
|
"Content": "Sticky Keys",
|
||||||
"Description": "If enabled, Sticky Keys is activated. Sticky keys is an accessibility feature of some graphical user interfaces which assists users who have physical disabilities or help users reduce repetitive strain injury.",
|
"Description": "If Enabled then Sticky Keys is activated - Sticky keys is an accessibility feature of some graphical user interfaces which assists users who have physical disabilities or help users reduce repetitive strain injury.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2378,7 +2360,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleNewOutlook": {
|
"WPFToggleNewOutlook": {
|
||||||
"Content": "New Outlook",
|
"Content": "New Outlook",
|
||||||
"Description": "If disabled, it removes the new Outlook toggle, disables the new Outlook migration, and ensures the classic Outlook application is used.",
|
"Description": "If disabled it removes the toggle for new Outlook, disables the new Outlook migration and makes sure the Outlook Application actually uses the old Outlook.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2438,7 +2420,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleHiddenFiles": {
|
"WPFToggleHiddenFiles": {
|
||||||
"Content": "Show Hidden Files",
|
"Content": "Show Hidden Files",
|
||||||
"Description": "If enabled, Hidden Files will be shown.",
|
"Description": "If Enabled then Hidden Files will be shown.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2466,7 +2448,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleShowExt": {
|
"WPFToggleShowExt": {
|
||||||
"Content": "Show File Extensions",
|
"Content": "Show File Extensions",
|
||||||
"Description": "If enabled, File extensions (e.g., .txt, .jpg) are visible.",
|
"Description": "If enabled then File extensions (e.g., .txt, .jpg) are visible.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2494,7 +2476,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleTaskbarSearch": {
|
"WPFToggleTaskbarSearch": {
|
||||||
"Content": "Search Button in Taskbar",
|
"Content": "Search Button in Taskbar",
|
||||||
"Description": "If enabled, Search Button will be on the Taskbar.",
|
"Description": "If Enabled Search Button will be on the taskbar.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2512,7 +2494,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleTaskView": {
|
"WPFToggleTaskView": {
|
||||||
"Content": "Task View Button in Taskbar",
|
"Content": "Task View Button in Taskbar",
|
||||||
"Description": "If enabled, Task View Button in Taskbar will be shown.",
|
"Description": "If Enabled then Task View Button in Taskbar will be shown.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2530,7 +2512,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleTaskbarAlignment": {
|
"WPFToggleTaskbarAlignment": {
|
||||||
"Content": "Center Taskbar Items",
|
"Content": "Center Taskbar Items",
|
||||||
"Description": "[Windows 11] If enabled, the Taskbar Items will be shown on the Center, otherwise the Taskbar Items will be shown on the Left.",
|
"Description": "[Windows 11] If Enabled then the Taskbar Items will be shown on the Center, otherwise the Taskbar Items will be shown on the Left.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2558,7 +2540,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleDetailedBSoD": {
|
"WPFToggleDetailedBSoD": {
|
||||||
"Content": "Detailed BSoD",
|
"Content": "Detailed BSoD",
|
||||||
"Description": "If enabled, you will see a detailed Blue Screen of Death (BSOD) with more information.",
|
"Description": "If Enabled then you will see a detailed Blue Screen of Death (BSOD) with more information.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2584,7 +2566,7 @@
|
|||||||
},
|
},
|
||||||
"WPFToggleS3Sleep": {
|
"WPFToggleS3Sleep": {
|
||||||
"Content": "S3 Sleep",
|
"Content": "S3 Sleep",
|
||||||
"Description": "Toggles between Modern Standby and S3 Sleep.",
|
"Description": "Toggles between Modern Standby and S3 sleep.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
@@ -2633,7 +2615,7 @@
|
|||||||
},
|
},
|
||||||
"WPFTweaksDisableExplorerAutoDiscovery": {
|
"WPFTweaksDisableExplorerAutoDiscovery": {
|
||||||
"Content": "Disable Explorer Automatic Folder Discovery",
|
"Content": "Disable Explorer Automatic Folder Discovery",
|
||||||
"Description": "Windows Explorer automatically tries to guess the type of the folder based on its contents, slowing down the browsing experience. WARNING! Will disable File Explorer grouping.",
|
"Description": "Windows Explorer automatically tries to guess the type of the folder based on its contents, slowing down the browsing experience. WARNING! Will disable file explorer grouping",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -128,154 +128,6 @@ winutil/
|
|||||||
- CheckBoxes for options
|
- CheckBoxes for options
|
||||||
- ListBoxes for selections
|
- ListBoxes for selections
|
||||||
|
|
||||||
## Win11 Creator Architecture
|
|
||||||
|
|
||||||
The **Win11 Creator** is a specialized subsystem within Winutil that creates customized Windows 11 ISOs. It operates independently from the main package installation and tweak system.
|
|
||||||
|
|
||||||
### Win11 Creator Components
|
|
||||||
|
|
||||||
**Core Functions** (`functions/private/`):
|
|
||||||
- `Invoke-WinUtilISO.ps1`: Main orchestrator containing all Win11 Creator functions
|
|
||||||
- `Invoke-WinUtilISOBrowse`: ISO file selection dialog
|
|
||||||
- `Invoke-WinUtilISOMountAndVerify`: Validates and mounts ISO, verifies it's official Windows 11
|
|
||||||
- `Invoke-WinUtilISOModify`: Launches modification in background runspace
|
|
||||||
- `Invoke-WinUtilISOExport`: Handles ISO and USB export
|
|
||||||
- `Invoke-WinUtilISOCheckExistingWork`: Recovers incomplete work sessions
|
|
||||||
- `Invoke-WinUtilISOCleanAndReset`: Cleans up temp directories and resets UI
|
|
||||||
|
|
||||||
- `Invoke-WinUtilISOScript.ps1`: Applies modifications to mounted install.wim
|
|
||||||
- Removes provisioned AppX packages (40+ bloatware apps)
|
|
||||||
- Injects drivers (optional) from current system
|
|
||||||
- Removes OneDrive setup files
|
|
||||||
- Applies offline registry tweaks (hardware bypass, privacy, telemetry, OOBE)
|
|
||||||
- Deletes telemetry scheduled task definitions
|
|
||||||
- Pre-stages setup scripts from autounattend.xml
|
|
||||||
- Removes unused Windows editions
|
|
||||||
- Cleans component store via DISM
|
|
||||||
|
|
||||||
### Win11 Creator Data Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
User selects official Windows 11 ISO
|
|
||||||
↓
|
|
||||||
Invoke-WinUtilISOBrowse → OpenFileDialog, validates file size
|
|
||||||
↓
|
|
||||||
Invoke-WinUtilISOMountAndVerify
|
|
||||||
├─ Mount ISO via Mount-DiskImage
|
|
||||||
├─ Verify install.wim or install.esd exists
|
|
||||||
├─ Check for "Windows 11" in image metadata
|
|
||||||
├─ Extract available editions (Home, Pro, Enterprise, etc.)
|
|
||||||
└─ Store ISO path, drive letter, WIM path, image info in $sync
|
|
||||||
↓
|
|
||||||
User optionally enables Driver Injection checkbox
|
|
||||||
↓
|
|
||||||
Invoke-WinUtilISOModify (runs in background runspace)
|
|
||||||
├─ Create work directory: ~WinUtil_Win11ISO_[timestamp]
|
|
||||||
├─ Copy ISO contents to disk (~5-6 GB)
|
|
||||||
├─ Mount install.wim at selected edition/index
|
|
||||||
├─ Invoke-WinUtilISOScript:
|
|
||||||
│ ├─ Remove 40+ bloat AppX packages
|
|
||||||
│ ├─ Export and inject drivers (if enabled)
|
|
||||||
│ ├─ Remove OneDrive setup
|
|
||||||
│ ├─ Load offline registry hives
|
|
||||||
│ ├─ Apply 50+ registry tweaks (hardware bypass, privacy, telemetry, OOBE, etc.)
|
|
||||||
│ ├─ Delete telemetry scheduled task files
|
|
||||||
│ ├─ Pre-stage setup scripts from autounattend.xml to C:\Windows\Setup\Scripts\
|
|
||||||
│ └─ Unload registry hives
|
|
||||||
├─ DISM /Cleanup-Image /StartComponentCleanup /ResetBase (saves 300-800 MB)
|
|
||||||
├─ Dismount and save modified install.wim (~10+ minutes, slowest step)
|
|
||||||
├─ Export selected edition only (removes all other editions, saves 1-2 GB each)
|
|
||||||
├─ Dismount source ISO
|
|
||||||
└─ Report completion, enable export options
|
|
||||||
↓
|
|
||||||
Invoke-WinUtilISOExport (user chooses output)
|
|
||||||
├─ Option 1: Save as ISO
|
|
||||||
│ ├─ Build bootable ISO via oscdimg.exe (BIOS/UEFI dual-boot)
|
|
||||||
│ └─ Output: Win11_Modified_[date].iso (2.5-3.5 GB)
|
|
||||||
│
|
|
||||||
└─ Option 2: Write to USB
|
|
||||||
├─ Format USB as GPT
|
|
||||||
├─ Create 512 MB EFI partition
|
|
||||||
├─ Copy modified ISO contents
|
|
||||||
└─ Output: Bootable USB (minimum 8 GB)
|
|
||||||
↓
|
|
||||||
Invoke-WinUtilISOCleanAndReset (optional)
|
|
||||||
└─ Delete temp working directory (~10-15 GB)
|
|
||||||
└─ Reset UI to initial state
|
|
||||||
```
|
|
||||||
|
|
||||||
### Win11 Creator Validation & Safety
|
|
||||||
|
|
||||||
**ISO Validation**:
|
|
||||||
- Only accepts official Microsoft Windows 11 ISOs
|
|
||||||
- Validates presence of install.wim or install.esd
|
|
||||||
- Checks image metadata for "Windows 11" string
|
|
||||||
- Rejects custom, modified, or non-Windows 11 ISOs
|
|
||||||
|
|
||||||
**Work Session Recovery**:
|
|
||||||
- Auto-detects incomplete work from previous sessions
|
|
||||||
- Allows resuming Step 4 (export) without re-running Steps 1-3
|
|
||||||
- Prevents redundant modifications
|
|
||||||
|
|
||||||
**Modification Safety**:
|
|
||||||
- All registry changes are documented in script (reversible)
|
|
||||||
- Original ISO never modified; only working copy
|
|
||||||
- Logged to `WinUtil_Win11ISO.log` for debugging
|
|
||||||
- DISM handles image dismount with automatic cleanup on error
|
|
||||||
|
|
||||||
### Win11 Creator Registry Tweaks
|
|
||||||
|
|
||||||
The `Invoke-WinUtilISOScript` function applies **50+ offline registry tweaks**:
|
|
||||||
|
|
||||||
**Hardware Bypass**:
|
|
||||||
- TPM 2.0 check bypass
|
|
||||||
- Secure Boot requirement bypass
|
|
||||||
- CPU compatibility bypass
|
|
||||||
- RAM requirement bypass
|
|
||||||
- Storage check bypass
|
|
||||||
|
|
||||||
**Privacy & Telemetry**:
|
|
||||||
- Disable advertising ID
|
|
||||||
- Disable tailored experiences
|
|
||||||
- Disable input personalization
|
|
||||||
- Disable speech online privacy
|
|
||||||
- Disable cloud content suggestions
|
|
||||||
- Disable app suggestion subscriptions
|
|
||||||
- Remove CEIP, Appraiser, WaaSMedic, etc.
|
|
||||||
|
|
||||||
**OOBE & Setup**:
|
|
||||||
- Enable local account setup
|
|
||||||
- Skip Microsoft account requirement
|
|
||||||
- Dark mode by default
|
|
||||||
- Empty taskbar and Start Menu
|
|
||||||
|
|
||||||
**Post-Setup Installations**:
|
|
||||||
- Prevent DevHome auto-installation
|
|
||||||
- Prevent new Outlook Mail app installation
|
|
||||||
- Prevent Teams auto-installation
|
|
||||||
|
|
||||||
**System Features**:
|
|
||||||
- Disable BitLocker and device encryption
|
|
||||||
- Disable Chat icon from taskbar
|
|
||||||
- Disable OneDrive folder backup
|
|
||||||
- Disable Copilot
|
|
||||||
- Disable Windows Update during OOBE (re-enabled at first login)
|
|
||||||
|
|
||||||
### Driver Injection Feature
|
|
||||||
|
|
||||||
**Optional Enhancement**: When enabled, exports all drivers from the running system and injects them into both:
|
|
||||||
- `install.wim` (main OS image)
|
|
||||||
- `boot.wim` index 2 (Windows Setup PE environment)
|
|
||||||
|
|
||||||
**Use Case**: Enables offline installation on systems with missing drivers.
|
|
||||||
|
|
||||||
### Disk Space Requirements
|
|
||||||
|
|
||||||
- **Temporary working directory**: ~10-15 GB
|
|
||||||
- **Original ISO**: 4-6 GB
|
|
||||||
- **Modified ISO**: 2.5-3.5 GB
|
|
||||||
- **Total needed**: ~25 GB for safe operation
|
|
||||||
|
|
||||||
## Data Flow
|
## Data Flow
|
||||||
|
|
||||||
### Application Installation Flow
|
### Application Installation Flow
|
||||||
@@ -662,7 +514,6 @@ Outputs `winutil.ps1` in the root directory.
|
|||||||
|
|
||||||
- [Contributing Guide](../../contributing/) - How to contribute code
|
- [Contributing Guide](../../contributing/) - How to contribute code
|
||||||
- [User Guide](../../userguide/) - End-user documentation
|
- [User Guide](../../userguide/) - End-user documentation
|
||||||
- [Win11 Creator Guide](../../userguide/win11Creator/) - Building customized Windows 11 ISOs
|
|
||||||
- [FAQ](../../faq/) - Common questions
|
- [FAQ](../../faq/) - Common questions
|
||||||
|
|
||||||
## Additional Resources
|
## Additional Resources
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/feature.json",linenos=inline,linenostart=27}
|
```json {filename="config/feature.json",linenos=inline,linenostart=27}
|
||||||
"WPFFeatureslegacymedia": {
|
"WPFFeatureslegacymedia": {
|
||||||
"Content": "Legacy Media (WMP, DirectPlay)",
|
"Content": "Legacy Media (WMP, DirectPlay)",
|
||||||
"Description": "Enables legacy programs from previous versions of Windows.",
|
"Description": "Enables legacy programs from previous versions of windows",
|
||||||
"category": "Features",
|
"category": "Features",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"feature": [
|
"feature": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2185}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2185}
|
||||||
"WPFToggleBingSearch": {
|
"WPFToggleBingSearch": {
|
||||||
"Content": "Bing Search in Start Menu",
|
"Content": "Bing Search in Start Menu",
|
||||||
"Description": "If enabled, Bing web search results will be included in your Start Menu search.",
|
"Description": "If enable then includes web search results from Bing in your Start Menu search.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Detailed BSoD"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2559}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2541}
|
||||||
"WPFToggleDetailedBSoD": {
|
"WPFToggleDetailedBSoD": {
|
||||||
"Content": "Detailed BSoD",
|
"Content": "Detailed BSoD",
|
||||||
"Description": "If enabled, you will see a detailed Blue Screen of Death (BSOD) with more information.",
|
"Description": "If Enabled then you will see a detailed Blue Screen of Death (BSOD) with more information.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Cross-Device Resume"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2689}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2671}
|
||||||
"WPFToggleDisableCrossDeviceResume": {
|
"WPFToggleDisableCrossDeviceResume": {
|
||||||
"Content": "Cross-Device Resume",
|
"Content": "Cross-Device Resume",
|
||||||
"Description": "This tweak controls the Resume function in Windows 11 24H2 and later, which allows you to resume an activity from a mobile device and vice-versa.",
|
"Description": "This tweak controls the Resume function in Windows 11 24H2 and later, which allows you to resume an activity from a mobile device and vice-versa.",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Show Hidden Files"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2439}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2421}
|
||||||
"WPFToggleHiddenFiles": {
|
"WPFToggleHiddenFiles": {
|
||||||
"Content": "Show Hidden Files",
|
"Content": "Show Hidden Files",
|
||||||
"Description": "If enabled, Hidden Files will be shown.",
|
"Description": "If Enabled then Hidden Files will be shown.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Remove Settings Home Page"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2309}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2291}
|
||||||
"WPFToggleHideSettingsHome": {
|
"WPFToggleHideSettingsHome": {
|
||||||
"Content": "Remove Settings Home Page",
|
"Content": "Remove Settings Home Page",
|
||||||
"Description": "Removes the Home Page in the Windows Settings app.",
|
"Description": "Removes the Home page in the Windows Settings app.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Mouse Acceleration"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2327}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2309}
|
||||||
"WPFToggleMouseAcceleration": {
|
"WPFToggleMouseAcceleration": {
|
||||||
"Content": "Mouse Acceleration",
|
"Content": "Mouse Acceleration",
|
||||||
"Description": "If enabled, the Cursor movement is affected by the speed of your physical mouse movements.",
|
"Description": "If Enabled then Cursor movement is affected by the speed of your physical mouse movements.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Disable Multiplane Overlay"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2421}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2403}
|
||||||
"WPFToggleMultiplaneOverlay": {
|
"WPFToggleMultiplaneOverlay": {
|
||||||
"Content": "Disable Multiplane Overlay",
|
"Content": "Disable Multiplane Overlay",
|
||||||
"Description": "Disable the Multiplane Overlay which can sometimes cause issues with Graphics Cards.",
|
"Description": "Disable the Multiplane Overlay which can sometimes cause issues with Graphics Cards.",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "New Outlook"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2379}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2361}
|
||||||
"WPFToggleNewOutlook": {
|
"WPFToggleNewOutlook": {
|
||||||
"Content": "New Outlook",
|
"Content": "New Outlook",
|
||||||
"Description": "If disabled, it removes the new Outlook toggle, disables the new Outlook migration, and ensures the classic Outlook application is used.",
|
"Description": "If disabled it removes the toggle for new Outlook, disables the new Outlook migration and makes sure the Outlook Application actually uses the old Outlook.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
title: "Num Lock on Startup"
|
title: "NumLock on Startup"
|
||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2221}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2203}
|
||||||
"WPFToggleNumLock": {
|
"WPFToggleNumLock": {
|
||||||
"Content": "Num Lock on Startup",
|
"Content": "NumLock on Startup",
|
||||||
"Description": "Toggle the Num Lock key state when your computer starts.",
|
"Description": "Toggle the Num Lock key state when your computer starts.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "S3 Sleep"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2585}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2567}
|
||||||
"WPFToggleS3Sleep": {
|
"WPFToggleS3Sleep": {
|
||||||
"Content": "S3 Sleep",
|
"Content": "S3 Sleep",
|
||||||
"Description": "Toggles between Modern Standby and S3 Sleep.",
|
"Description": "Toggles between Modern Standby and S3 sleep.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Show File Extensions"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2467}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2449}
|
||||||
"WPFToggleShowExt": {
|
"WPFToggleShowExt": {
|
||||||
"Content": "Show File Extensions",
|
"Content": "Show File Extensions",
|
||||||
"Description": "If enabled, File extensions (e.g., .txt, .jpg) are visible.",
|
"Description": "If enabled then File extensions (e.g., .txt, .jpg) are visible.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
---
|
|
||||||
title: "Modern Standby fix"
|
|
||||||
description: ""
|
|
||||||
---
|
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2203}
|
|
||||||
"WPFToggleStandbyFix": {
|
|
||||||
"Content": "Modern Standby fix",
|
|
||||||
"Description": "Disable network connection during S0 sleep. If network connectivity is turned on during S0 sleep it could cause overheating on modern laptops",
|
|
||||||
"category": "Customize Preferences",
|
|
||||||
"panel": "2",
|
|
||||||
"Type": "Toggle",
|
|
||||||
"registry": [
|
|
||||||
{
|
|
||||||
"Path": "HKCU:\\SOFTWARE\\Policies\\Microsoft\\Power\\PowerSettings\\f15576e8-98b7-4186-b944-eafa664402d9",
|
|
||||||
"Name": "ACSettingIndex",
|
|
||||||
"Value": "0",
|
|
||||||
"Type": "DWord",
|
|
||||||
"OriginalValue": "<RemoveEntry>",
|
|
||||||
"DefaultState": "true"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
```
|
|
||||||
|
|
||||||
## Registry Changes
|
|
||||||
|
|
||||||
Applications and System Components store and retrieve configuration data to modify windows settings, so we can use the registry to change many settings in one place.
|
|
||||||
|
|
||||||
You can find information about the registry on [Wikipedia](https://www.wikiwand.com/en/Windows_Registry) and [Microsoft's Website](https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry).
|
|
||||||
@@ -3,10 +3,10 @@ title: "Recommendations in Start Menu"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2265}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2247}
|
||||||
"WPFToggleStartMenuRecommendations": {
|
"WPFToggleStartMenuRecommendations": {
|
||||||
"Content": "Recommendations in Start Menu",
|
"Content": "Recommendations in Start Menu",
|
||||||
"Description": "If disabled, then you will not see recommendations in the Start Menu. WARNING: This will also disable Windows Spotlight on your Lock Screen as a side effect.",
|
"Description": "If disabled then you will not see recommendations in the Start Menu. WARNING: This will also disable Windows Spotlight on your Lock Screen as a side effect.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Sticky Keys"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2361}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2343}
|
||||||
"WPFToggleStickyKeys": {
|
"WPFToggleStickyKeys": {
|
||||||
"Content": "Sticky Keys",
|
"Content": "Sticky Keys",
|
||||||
"Description": "If enabled, Sticky Keys is activated. Sticky keys is an accessibility feature of some graphical user interfaces which assists users who have physical disabilities or help users reduce repetitive strain injury.",
|
"Description": "If Enabled then Sticky Keys is activated - Sticky keys is an accessibility feature of some graphical user interfaces which assists users who have physical disabilities or help users reduce repetitive strain injury.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Task View Button in Taskbar"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2513}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2495}
|
||||||
"WPFToggleTaskView": {
|
"WPFToggleTaskView": {
|
||||||
"Content": "Task View Button in Taskbar",
|
"Content": "Task View Button in Taskbar",
|
||||||
"Description": "If enabled, Task View Button in Taskbar will be shown.",
|
"Description": "If Enabled then Task View Button in Taskbar will be shown.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Center Taskbar Items"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2531}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2513}
|
||||||
"WPFToggleTaskbarAlignment": {
|
"WPFToggleTaskbarAlignment": {
|
||||||
"Content": "Center Taskbar Items",
|
"Content": "Center Taskbar Items",
|
||||||
"Description": "[Windows 11] If enabled, the Taskbar Items will be shown on the Center, otherwise the Taskbar Items will be shown on the Left.",
|
"Description": "[Windows 11] If Enabled then the Taskbar Items will be shown on the Center, otherwise the Taskbar Items will be shown on the Left.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Search Button in Taskbar"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2495}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2477}
|
||||||
"WPFToggleTaskbarSearch": {
|
"WPFToggleTaskbarSearch": {
|
||||||
"Content": "Search Button in Taskbar",
|
"Content": "Search Button in Taskbar",
|
||||||
"Description": "If enabled, Search Button will be on the Taskbar.",
|
"Description": "If Enabled Search Button will be on the taskbar.",
|
||||||
"category": "Customize Preferences",
|
"category": "Customize Preferences",
|
||||||
"panel": "2",
|
"panel": "2",
|
||||||
"Type": "Toggle",
|
"Type": "Toggle",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "Verbose Messages During Logon"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2247}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2229}
|
||||||
"WPFToggleVerboseLogon": {
|
"WPFToggleVerboseLogon": {
|
||||||
"Content": "Verbose Messages During Logon",
|
"Content": "Verbose Messages During Logon",
|
||||||
"Description": "Show detailed messages during the login process for troubleshooting and diagnostics.",
|
"Description": "Show detailed messages during the login process for troubleshooting and diagnostics.",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2}
|
||||||
"WPFTweaksActivity": {
|
"WPFTweaksActivity": {
|
||||||
"Content": "Disable Activity History",
|
"Content": "Disable Activity History",
|
||||||
"Description": "Erases recent docs, clipboard, and run history.",
|
"Description": "This erases recent docs, clipboard, and run history.",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1291}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1291}
|
||||||
"WPFTweaksConsumerFeatures": {
|
"WPFTweaksConsumerFeatures": {
|
||||||
"Content": "Disable ConsumerFeatures",
|
"Content": "Disable ConsumerFeatures",
|
||||||
"Description": "Windows will not automatically install any games, third-party apps, or application links from the Windows Store for the signed-in user. Some default Apps will be inaccessible (eg. Phone Link).",
|
"Description": "Windows will not automatically install any games, third-party apps, or application links from the Windows Store for the signed-in user. Some default Apps will be inaccessible (eg. Phone Link)",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2038}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2038}
|
||||||
"WPFTweaksDeleteTempFiles": {
|
"WPFTweaksDeleteTempFiles": {
|
||||||
"Content": "Delete Temporary Files",
|
"Content": "Delete Temporary Files",
|
||||||
"Description": "Erases TEMP Folders.",
|
"Description": "Erases TEMP Folders",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ title: "Disable Explorer Automatic Folder Discovery"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2634}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2616}
|
||||||
"WPFTweaksDisableExplorerAutoDiscovery": {
|
"WPFTweaksDisableExplorerAutoDiscovery": {
|
||||||
"Content": "Disable Explorer Automatic Folder Discovery",
|
"Content": "Disable Explorer Automatic Folder Discovery",
|
||||||
"Description": "Windows Explorer automatically tries to guess the type of the folder based on its contents, slowing down the browsing experience. WARNING! Will disable File Explorer grouping.",
|
"Description": "Windows Explorer automatically tries to guess the type of the folder based on its contents, slowing down the browsing experience. WARNING! Will disable file explorer grouping",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1763}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1763}
|
||||||
"WPFTweaksEndTaskOnTaskbar": {
|
"WPFTweaksEndTaskOnTaskbar": {
|
||||||
"Content": "Enable End Task With Right Click",
|
"Content": "Enable End Task With Right Click",
|
||||||
"Description": "Enables option to end task when right clicking a program in the taskbar.",
|
"Description": "Enables option to end task when right clicking a program in the taskbar",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=32}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=32}
|
||||||
"WPFTweaksHiber": {
|
"WPFTweaksHiber": {
|
||||||
"Content": "Disable Hibernation",
|
"Content": "Disable Hibernation",
|
||||||
"Description": "Hibernation is really meant for laptops as it saves what's in memory before turning the PC off. It really should never be used.",
|
"Description": "Hibernation is really meant for laptops as it saves what's in memory before turning the pc off. It really should never be used",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=125}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=125}
|
||||||
"WPFTweaksLocation": {
|
"WPFTweaksLocation": {
|
||||||
"Content": "Disable Location Tracking",
|
"Content": "Disable Location Tracking",
|
||||||
"Description": "Disables Location Tracking.",
|
"Description": "Disables Location Tracking...DUH!",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1779}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1779}
|
||||||
"WPFTweaksPowershell7Tele": {
|
"WPFTweaksPowershell7Tele": {
|
||||||
"Content": "Disable Powershell 7 Telemetry",
|
"Content": "Disable Powershell 7 Telemetry",
|
||||||
"Description": "Creates an Environment Variable called 'POWERSHELL_TELEMETRY_OPTOUT' with a value of '1' which will tell PowerShell 7 to not send Telemetry Data.",
|
"Description": "This will create an Environment Variable called 'POWERSHELL_TELEMETRY_OPTOUT' with a value of '1' which will tell Powershell 7 to not send Telemetry Data.",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1736}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1736}
|
||||||
"WPFTweaksRestorePoint": {
|
"WPFTweaksRestorePoint": {
|
||||||
"Content": "Create Restore Point",
|
"Content": "Create Restore Point",
|
||||||
"Description": "Creates a restore point at runtime in case a revert is needed from WinUtil modifications.",
|
"Description": "Creates a restore point at runtime in case a revert is needed from WinUtil modifications",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"Checked": "False",
|
"Checked": "False",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1307}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1307}
|
||||||
"WPFTweaksTelemetry": {
|
"WPFTweaksTelemetry": {
|
||||||
"Content": "Disable Telemetry",
|
"Content": "Disable Telemetry",
|
||||||
"Description": "Disables Microsoft Telemetry.",
|
"Description": "Disables Microsoft Telemetry...Duh",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1892}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1892}
|
||||||
"WPFTweaksWPBT": {
|
"WPFTweaksWPBT": {
|
||||||
"Content": "Disable Windows Platform Binary Table (WPBT)",
|
"Content": "Disable Windows Platform Binary Table (WPBT)",
|
||||||
"Description": "If enabled, WPBT allows your computer vendor to execute programs at boot time, such as anti-theft software, software drivers, as well as force install software without user consent. Poses potential security risk.",
|
"Description": "If enabled then allows your computer vendor to execute a program each time it boots. It enables computer vendors to force install anti-theft software, software drivers, or a software program conveniently. This could also be a security risk.",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=61}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=61}
|
||||||
"WPFTweaksWidget": {
|
"WPFTweaksWidget": {
|
||||||
"Content": "Remove Widgets",
|
"Content": "Remove Widgets",
|
||||||
"Description": "Removes the annoying widgets in the bottom left of the Taskbar.",
|
"Description": "Removes the annoying widgets in the bottom left of the taskbar",
|
||||||
"category": "Essential Tweaks",
|
"category": "Essential Tweaks",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1973}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1973}
|
||||||
"WPFTweaksBlockAdobeNet": {
|
"WPFTweaksBlockAdobeNet": {
|
||||||
"Content": "Adobe Network Block",
|
"Content": "Adobe Network Block",
|
||||||
"Description": "Reduces user interruptions by selectively blocking connections to Adobe's activation and telemetry servers. Credit: Ruddernation-Designs",
|
"Description": "Reduce user interruptions by selectively blocking connections to Adobe's activation and telemetry servers. Credit: Ruddernation-Designs",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1126}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1126}
|
||||||
"WPFTweaksBraveDebloat": {
|
"WPFTweaksBraveDebloat": {
|
||||||
"Content": "Brave Debloat",
|
"Content": "Brave Debloat",
|
||||||
"Description": "Disables various annoyances like Brave Rewards, Leo AI, Crypto Wallet and VPN.",
|
"Description": "Disables various annoyances like Brave Rewards,Leo AI,Crypto Wallet and VPN",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1647}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1647}
|
||||||
"WPFTweaksDeBloat": {
|
"WPFTweaksDeBloat": {
|
||||||
"Content": "Remove ALL MS Store Apps - NOT RECOMMENDED",
|
"Content": "Remove ALL MS Store Apps - NOT RECOMMENDED",
|
||||||
"Description": "USE WITH CAUTION!!! This will remove ALL Microsoft Store apps.",
|
"Description": "USE WITH CAUTION!!! This will remove ALL Microsoft store apps.",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"appx": [
|
"appx": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2111}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2111}
|
||||||
"WPFTweaksDisableBGapps": {
|
"WPFTweaksDisableBGapps": {
|
||||||
"Content": "Disable Background Apps",
|
"Content": "Disable Background Apps",
|
||||||
"Description": "Disables all Microsoft Store apps from running in the background, which has to be done individually since Windows 11.",
|
"Description": "Disables all Microsoft Store apps from running in the background, which has to be done individually since Win11",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2127}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2127}
|
||||||
"WPFTweaksDisableFSO": {
|
"WPFTweaksDisableFSO": {
|
||||||
"Content": "Disable Fullscreen Optimizations",
|
"Content": "Disable Fullscreen Optimizations",
|
||||||
"Description": "Disables FSO in all applications. NOTE: This will disable Color Management in Exclusive Fullscreen.",
|
"Description": "Disables FSO in all applications. NOTE: This will disable Color Management in Exclusive Fullscreen",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1950}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1950}
|
||||||
"WPFTweaksDisableNotifications": {
|
"WPFTweaksDisableNotifications": {
|
||||||
"Content": "Disable Notification Tray/Calendar",
|
"Content": "Disable Notification Tray/Calendar",
|
||||||
"Description": "Disables all Notifications INCLUDING Calendar.",
|
"Description": "Disables all Notifications INCLUDING Calendar",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2051}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2051}
|
||||||
"WPFTweaksIPv46": {
|
"WPFTweaksIPv46": {
|
||||||
"Content": "Prefer IPv4 over IPv6",
|
"Content": "Prefer IPv4 over IPv6",
|
||||||
"Description": "Setting the IPv4 preference can have latency and security benefits on private networks where IPv6 is not configured.",
|
"Description": "To set the IPv4 preference can have latency and security benefits on private networks where IPv6 is not configured.",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1429}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1429}
|
||||||
"WPFTweaksRemoveEdge": {
|
"WPFTweaksRemoveEdge": {
|
||||||
"Content": "Remove Microsoft Edge",
|
"Content": "Remove Microsoft Edge",
|
||||||
"Description": "Unblocks Microsoft Edge uninstaller restrictions then uses that uninstaller to remove Microsoft Edge.",
|
"Description": "Unblocks Microsoft Edge uninstaller restrictions than uses that uninstaller to remove Microsoft Edge",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1517}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1517}
|
||||||
"WPFTweaksRemoveGallery": {
|
"WPFTweaksRemoveGallery": {
|
||||||
"Content": "Remove Gallery from explorer",
|
"Content": "Remove Gallery from explorer",
|
||||||
"Description": "Removes the Gallery from Explorer and sets This PC as default.",
|
"Description": "Removes the Gallery from Explorer and sets This PC as default",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1498}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1498}
|
||||||
"WPFTweaksRemoveHome": {
|
"WPFTweaksRemoveHome": {
|
||||||
"Content": "Remove Home from Explorer",
|
"Content": "Remove Home from Explorer",
|
||||||
"Description": "Removes the Home from Explorer and sets This PC as default.",
|
"Description": "Removes the Home from Explorer and sets This PC as default",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=1461}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=1461}
|
||||||
"WPFTweaksRemoveOneDrive": {
|
"WPFTweaksRemoveOneDrive": {
|
||||||
"Content": "Remove OneDrive",
|
"Content": "Remove OneDrive",
|
||||||
"Description": "Denies permission to remove OneDrive user files, then uses its own uninstaller to remove it and restores the original permission afterward.",
|
"Description": "Denys permission to remove onedrive user files than uses its own uninstaller to remove it than brings back permissions",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=90}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=90}
|
||||||
"WPFTweaksRevertStartMenu": {
|
"WPFTweaksRevertStartMenu": {
|
||||||
"Content": "Revert the new start menu",
|
"Content": "Revert the new start menu",
|
||||||
"Description": "Uses vivetool to revert to the original start menu from 24H2.",
|
"Description": "Uses vivetool to revert the the original start menu from 24h2",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
title: "Set Classic Right-Click Menu"
|
title: "Set Classic Right-Click Menu "
|
||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2003}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2003}
|
||||||
"WPFTweaksRightClickMenu": {
|
"WPFTweaksRightClickMenu": {
|
||||||
"Content": "Set Classic Right-Click Menu",
|
"Content": "Set Classic Right-Click Menu ",
|
||||||
"Description": "Restores the classic context menu when right-clicking in File Explorer, replacing the simplified Windows 11 version.",
|
"Description": "Great Windows 11 tweak to bring back good context menus when right clicking things in explorer.",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"InvokeScript": [
|
"InvokeScript": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: ""
|
|||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2067}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2067}
|
||||||
"WPFTweaksTeredo": {
|
"WPFTweaksTeredo": {
|
||||||
"Content": "Disable Teredo",
|
"Content": "Disable Teredo",
|
||||||
"Description": "Teredo network tunneling is a IPv6 feature that can cause additional latency, but may cause problems with some games.",
|
"Description": "Teredo network tunneling is a ipv6 feature that can cause additional latency, but may cause problems with some games",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
"panel": "1",
|
"panel": "1",
|
||||||
"registry": [
|
"registry": [
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: "DNS"
|
|||||||
description: ""
|
description: ""
|
||||||
---
|
---
|
||||||
|
|
||||||
```json {filename="config/tweaks.json",linenos=inline,linenostart=2610}
|
```json {filename="config/tweaks.json",linenos=inline,linenostart=2592}
|
||||||
"WPFchangedns": {
|
"WPFchangedns": {
|
||||||
"Content": "DNS",
|
"Content": "DNS",
|
||||||
"category": "z__Advanced Tweaks - CAUTION",
|
"category": "z__Advanced Tweaks - CAUTION",
|
||||||
|
|||||||
@@ -31,10 +31,9 @@ Winutil is designed for:
|
|||||||
New to Winutil? Start here:
|
New to Winutil? Start here:
|
||||||
|
|
||||||
1. **[Getting Started Guide](getting-started/)** - Installation and first steps
|
1. **[Getting Started Guide](getting-started/)** - Installation and first steps
|
||||||
2. **[Application Store](application/)** - Learn to install software easily
|
2. **[Application Store](store/)** - Learn to install software easily
|
||||||
3. **[Tweaks Guide](tweaks/)** - Optimize your system
|
3. **[Tweaks Guide](tweaks/)** - Optimize your system
|
||||||
4. **[Features & Fixes](features/)** - Troubleshoot common issues
|
4. **[Features & Fixes](features/)** - Troubleshoot common issues
|
||||||
5. **[Win11 Creator](win11Creator/)** - Build a custom debloated Windows 11 ISO
|
|
||||||
|
|
||||||
## Main Features
|
## Main Features
|
||||||
|
|
||||||
@@ -42,7 +41,7 @@ New to Winutil? Start here:
|
|||||||
|
|
||||||
Browse and install hundreds of popular applications with a single click. No more hunting for download links or dealing with installer bloat.
|
Browse and install hundreds of popular applications with a single click. No more hunting for download links or dealing with installer bloat.
|
||||||
|
|
||||||
**[Read the Store Guide →](application/)**
|
**[Read the Store Guide →](store/)**
|
||||||
|
|
||||||
### ⚙️ System Tweaks
|
### ⚙️ System Tweaks
|
||||||
|
|
||||||
@@ -80,23 +79,16 @@ Automate Winutil configurations for:
|
|||||||
|
|
||||||
**[Read the Automation Guide →](automation/)**
|
**[Read the Automation Guide →](automation/)**
|
||||||
|
|
||||||
### 💿 Windows 11 Creator
|
|
||||||
|
|
||||||
Build a custom Windows 11 ISO with bloatware removed, telemetry disabled, and hardware requirement checks bypassed — then export it as an ISO file or write it directly to a USB drive.
|
|
||||||
|
|
||||||
**[Read the Win11 Creator Guide →](win11Creator/)**
|
|
||||||
|
|
||||||
## Quick Links
|
## Quick Links
|
||||||
|
|
||||||
| I want to... | Go to... |
|
| I want to... | Go to... |
|
||||||
|--------------|----------|
|
|--------------|----------|
|
||||||
| Install Winutil for the first time | [Getting Started](getting-started/) |
|
| Install Winutil for the first time | [Getting Started](getting-started/) |
|
||||||
| Install applications quickly | [Application Store](application/) |
|
| Install applications quickly | [Application Store](store/) |
|
||||||
| Speed up my computer | [Tweaks Guide](tweaks/) |
|
| Speed up my computer | [Tweaks Guide](tweaks/) |
|
||||||
| Fix Windows Update problems | [Features - Fixes](features/) |
|
| Fix Windows Update problems | [Features - Fixes](features/) |
|
||||||
| Automate setup for multiple PCs | [Automation](automation/) |
|
| Automate setup for multiple PCs | [Automation](automation/) |
|
||||||
| Understand what tweaks do | [Tweaks Guide](tweaks/) |
|
| Understand what tweaks do | [Tweaks Guide](tweaks/) |
|
||||||
| Build a custom Windows 11 ISO | [Win11 Creator](win11Creator/) |
|
|
||||||
|
|
||||||
## Safety and Best Practices
|
## Safety and Best Practices
|
||||||
|
|
||||||
@@ -151,10 +143,9 @@ Want to help improve Winutil?
|
|||||||
This User Guide covers everything you need to know:
|
This User Guide covers everything you need to know:
|
||||||
|
|
||||||
1. **[Getting Started](getting-started/)** - Installation, first run, basic usage
|
1. **[Getting Started](getting-started/)** - Installation, first run, basic usage
|
||||||
2. **[Application Store](application/)** - Installing software, using presets
|
2. **[Application Store](store/)** - Installing software, using presets
|
||||||
3. **[Tweaks](tweaks/)** - System optimizations and customizations
|
3. **[Tweaks](tweaks/)** - System optimizations and customizations
|
||||||
4. **[Features & Fixes](features/)** - Troubleshooting tools and utilities
|
4. **[Features & Fixes](features/)** - Troubleshooting tools and utilities
|
||||||
5. **[Win11 Creator](win11Creator/)** - Build a custom debloated Windows 11 ISO
|
|
||||||
6. **[Updates](updates/)** - Managing Windows Update behavior
|
6. **[Updates](updates/)** - Managing Windows Update behavior
|
||||||
7. **[Automation](automation/)** - Scripting and batch deployments
|
7. **[Automation](automation/)** - Scripting and batch deployments
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: Getting Started
|
title: Getting Started with Winutil
|
||||||
weight: 1
|
weight: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -258,7 +258,7 @@ If Winutil downloads but doesn't open:
|
|||||||
|
|
||||||
Now that you're set up, explore these guides:
|
Now that you're set up, explore these guides:
|
||||||
|
|
||||||
- [Application Installation Guide](../application/) - Learn about installing software
|
- [Application Installation Guide](../store/) - Learn about installing software
|
||||||
- [Tweaks Guide](../tweaks/) - Understand system optimizations
|
- [Tweaks Guide](../tweaks/) - Understand system optimizations
|
||||||
- [FAQ](../../faq/) - Common questions and answers
|
- [FAQ](../../faq/) - Common questions and answers
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: Applications
|
title: Store
|
||||||
weight: 2
|
weight: 2
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
---
|
|
||||||
title: Win 11 Creator
|
|
||||||
weight: 5
|
|
||||||
---
|
|
||||||
|
|
||||||
## Using Winutil's Win11 Creator
|
|
||||||
|
|
||||||
Winutil includes a built-in **Win11 Creator** tool that lets you take any official Windows 11 ISO and produce a customized, debloated version — with telemetry removed, hardware requirement checks bypassed, and local account setup enabled out of the box. You can export the result as a new ISO file or write it directly to a USB drive.
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
|
||||||
> You need an **official Windows 11 ISO** from [Microsoft's website](https://www.microsoft.com/en-us/software-download/windows11) before starting. Custom, modified, or non-official ISOs are not supported. The process uses ~10–15 GB of temporary disk space, so make sure you have room.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Step 1 — Select Your Official Windows 11 ISO
|
|
||||||
|
|
||||||
1. Open Winutil and go to the **Win11 Creator** tab.
|
|
||||||
2. Click **Browse** and select your **official Windows 11 ISO file** from Microsoft (must be 4 GB or larger). Custom or modified ISOs are not supported.
|
|
||||||
3. The file path and size will appear on screen once selected.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Step 2 — Mount & Verify
|
|
||||||
|
|
||||||
1. Click **Mount & Verify ISO**.
|
|
||||||
2. Winutil mounts the ISO, checks for a valid `install.wim` or `install.esd`, and reads the available editions (Home, Pro, Enterprise, etc.).
|
|
||||||
3. Once verified, select your desired **edition** from the dropdown — Pro is selected by default if available.
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> This step takes around 10–30 seconds depending on your drive speed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Step 3 — Run the Modification
|
|
||||||
|
|
||||||
Click **Run Windows ISO Modification and Creator** to start the customization process. Winutil will:
|
|
||||||
|
|
||||||
**App & Component Removal:**
|
|
||||||
- **Remove 40+ bloat apps** — Clipchamp, Teams, Copilot, Dev Home, new Outlook, Bing apps, Solitaire, and more
|
|
||||||
- **Delete OneDrive setup** from the image
|
|
||||||
|
|
||||||
**System Customization:**
|
|
||||||
- **Bypass hardware checks** — removes TPM, Secure Boot, CPU, and RAM requirement enforcement so the ISO installs on unsupported hardware
|
|
||||||
- **Enable local account setup** — injects an `autounattend.xml` that skips the Microsoft account screen during OOBE
|
|
||||||
- **Disable BitLocker and device encryption** — removes startup overhead
|
|
||||||
- **Disable Chat icon** — removes chat taskbar button
|
|
||||||
- **Strip unused editions** — keeps only your selected edition, saving 1–2 GB per removed edition
|
|
||||||
- **Clean the component store** — runs DISM cleanup to reclaim another 300–800 MB
|
|
||||||
|
|
||||||
**Privacy & Telemetry Tweaks:**
|
|
||||||
- **Disable telemetry** — advertising ID, tailored experiences, input personalization, speech online privacy
|
|
||||||
- **Disable cloud content features** — app suggestions, Microsoft Store recommendations
|
|
||||||
- **Remove telemetry scheduled tasks** — CEIP, Appraiser, WaaSMedic, and others
|
|
||||||
- **Disable OneDrive folder backup** — prevents automatic backups to cloud
|
|
||||||
- **Prevent DevHome and Outlook post-setup installation**
|
|
||||||
- **Prevent Teams installation** — blocks auto-install after OOBE
|
|
||||||
- **Prevent new Outlook Mail app installation**
|
|
||||||
- **Disable Windows Update during OOBE** — re-enabled automatically on first login
|
|
||||||
- **Disable Copilot and search box suggestions**
|
|
||||||
|
|
||||||
**Optional: Driver Injection**
|
|
||||||
- If enabled, injects all drivers from your current system into the install.wim and boot.wim — useful for offline installations on machines with missing drivers. This is an optional checkbox in Step 3.
|
|
||||||
|
|
||||||
A live log shows progress as each step completes. This stage takes **10–30 minutes** depending on your disk speed — the WIM dismount near the end is the slowest part, so don't close Winutil while it's running.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Step 4 — Export Your Result
|
|
||||||
|
|
||||||
Once modification is complete, choose how to save your image:
|
|
||||||
|
|
||||||
{{< tabs items="Save as ISO,Write to USB" defaultIndex="0" >}}
|
|
||||||
|
|
||||||
{{< tab >}}
|
|
||||||
1. Click **Save as an ISO File**.
|
|
||||||
2. Choose a save location (defaults to your Desktop as `Win11_Modified_yyyyMMdd.iso`).
|
|
||||||
3. Winutil builds a dual BIOS/UEFI bootable ISO using `oscdimg.exe`.
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> `oscdimg.exe` (part of the Windows ADK) is required. If it's not found, Winutil will attempt to install it automatically via winget. If that fails, install it manually: `winget install -e --id Microsoft.OSCDIMG`
|
|
||||||
|
|
||||||
**Typical output size:** 2.5–3.5 GB (down from 5–6 GB original)
|
|
||||||
{{< /tab >}}
|
|
||||||
|
|
||||||
{{< tab >}}
|
|
||||||
1. Click **Write Directly to a USB Drive**.
|
|
||||||
2. Select your USB drive from the dropdown (click **Refresh** if it doesn't appear).
|
|
||||||
3. Click **Erase & Write to USB** and confirm the warning — **all data on the drive will be permanently erased**.
|
|
||||||
4. Winutil formats the drive as GPT with a 512 MB EFI partition and copies the modified Windows files.
|
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
> Double-check you have selected the correct drive before confirming. This operation cannot be undone.
|
|
||||||
|
|
||||||
**Minimum USB size:** 8 GB recommended. Writing takes 10–20 minutes.
|
|
||||||
{{< /tab >}}
|
|
||||||
|
|
||||||
{{< /tabs >}}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Step 5 — Clean Up (Optional)
|
|
||||||
|
|
||||||
Click **Clean & Reset** to delete the temporary working directory (~10–15 GB) and reset the tool back to its initial state, ready for a new ISO. You'll be asked to confirm before anything is deleted.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### What the Modified ISO Does Differently
|
|
||||||
|
|
||||||
When you install Windows 11 from your modified ISO:
|
|
||||||
|
|
||||||
- **No Microsoft account required** — create a local account directly during setup
|
|
||||||
- **No hardware checks** — installs on machines without TPM 2.0, Secure Boot, or supported CPUs
|
|
||||||
- **Dark mode enabled by default**
|
|
||||||
- **Empty taskbar and Start Menu** — no pinned apps, Chat icon removed
|
|
||||||
- **Windows Update disabled during OOBE** — automatically re-enabled on first login to prevent setup interruptions
|
|
||||||
- **BitLocker disabled** — removes startup overhead on first boot
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Troubleshooting
|
|
||||||
|
|
||||||
| Problem | Fix |
|
|
||||||
|---------|-----|
|
|
||||||
| "install.wim not found" | Not a valid Windows 11 ISO — download a fresh one from Microsoft |
|
|
||||||
| "oscdimg.exe not found" | Run `winget install -e --id Microsoft.OSCDIMG` then retry |
|
|
||||||
| USB drive not showing up | Plug it in, wait a few seconds, then click **Refresh** |
|
|
||||||
| Modification seems stuck | The WIM dismount step is slow — wait at least 10 minutes before assuming it's frozen |
|
|
||||||
| "Access Denied" error | Make sure Winutil is running as Administrator |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
A list of the best free and open source tools for downloading, creating and flashing Windows ISOs.
|
|
||||||
|
|
||||||
## Download Windows ISOs
|
|
||||||
|
|
||||||
| Tool | Description | Website |
|
|
||||||
|------|-------------|---------|
|
|
||||||
| **[UUP Dump](https://uupdump.net/)** | Download Windows UUP files directly from Microsoft's servers and convert them into a clean ISO — great for getting the latest builds | [uupdump.net](https://uupdump.net/) |
|
|
||||||
| **[Microsoft Media Creation Tool](https://www.microsoft.com/en-us/software-download/windows11)** | Microsoft's official tool for downloading and creating Windows 10/11 installation media | [microsoft.com](https://www.microsoft.com/en-us/software-download/windows11) |
|
|
||||||
|
|
||||||
|
|
||||||
## Customize Windows ISOs
|
|
||||||
|
|
||||||
| Tool | Description | Website |
|
|
||||||
|------|-------------|---------|
|
|
||||||
| **[MicroWin](https://github.com/CodingWonders/microwin)** | A C# desktop app for building stripped-down, customized Windows ISOs — the original predecessor to Winutil's old MicroWin feature | [github.com](https://github.com/CodingWonders/microwin) |
|
|
||||||
| **[Tiny11 Builder](https://github.com/ntdevlabs/tiny11builder)** | PowerShell script that strips a Windows 11 ISO down to the bare minimum — removes bloatware and bypasses hardware requirements | [github.com](https://github.com/ntdevlabs/tiny11builder) |
|
|
||||||
| **[NTLite](https://www.ntlite.com/)** | Remove Windows components, integrate drivers and updates, and build a custom ISO before installation | [ntlite.com](https://www.ntlite.com/) |
|
|
||||||
|
|
||||||
|
|
||||||
## Flash ISOs to USB
|
|
||||||
|
|
||||||
| Tool | Description | Website |
|
|
||||||
|------|-------------|---------|
|
|
||||||
| **[Rufus](https://rufus.ie/)** | The go-to tool for creating bootable Windows USB drives. Supports bypassing Windows 11 TPM/Secure Boot requirements and downloading ISOs directly | [rufus.ie](https://rufus.ie/) |
|
|
||||||
| **[Ventoy](https://www.ventoy.net/)** | Install once, then just copy any ISO files onto the USB — supports booting multiple ISOs from a single drive without re-flashing | [ventoy.net](https://www.ventoy.net/) |
|
|
||||||
| **[balenaEtcher](https://etcher.balena.io/)** | Simple, beginner-friendly ISO flasher with a clean interface | [etcher.balena.io](https://etcher.balena.io/) |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> Already have a Windows 11 ISO? Skip the third-party tools and use Winutil's built-in **[Win11 Creator](#using-winutilss-win11-creator)** at the top of this page.
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> Always download Windows ISOs from official Microsoft sources or trusted tools like Rufus/UUP Dump to avoid tampered images.
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> Newer Windows 11 ISOs may not boot correctly on older versions of Ventoy — make sure Ventoy is up to date before use. If issues persist after updating, this is a Ventoy compatibility limitation outside of Winutil's control.
|
|
||||||
@@ -16,20 +16,13 @@ function Invoke-WinUtilFeatureInstall {
|
|||||||
Write-Host "Installing $feature"
|
Write-Host "Installing $feature"
|
||||||
Enable-WindowsOptionalFeature -Online -FeatureName $feature -All -NoRestart
|
Enable-WindowsOptionalFeature -Online -FeatureName $feature -All -NoRestart
|
||||||
} catch {
|
} catch {
|
||||||
if ($_.Exception -and $_.Exception.Message -like "*requires elevation*") {
|
if ($CheckBox.Exception.Message -like "*requires elevation*") {
|
||||||
Write-Warning "Unable to Install $feature due to permissions. Are you running as admin?"
|
Write-Warning "Unable to Install $feature due to permissions. Are you running as admin?"
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" }
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Write-Warning "Unable to Install $feature due to unhandled exception"
|
Write-Warning "Unable to Install $feature due to unhandled exception"
|
||||||
if ($_.Exception) {
|
Write-Warning $CheckBox.Exception.StackTrace
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.StackTrace)) {
|
|
||||||
Write-Warning $_.Exception.StackTrace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,20 +35,13 @@ function Invoke-WinUtilFeatureInstall {
|
|||||||
Write-Host "Running Script for $CheckBox"
|
Write-Host "Running Script for $CheckBox"
|
||||||
Invoke-Command $scriptblock -ErrorAction stop
|
Invoke-Command $scriptblock -ErrorAction stop
|
||||||
} catch {
|
} catch {
|
||||||
if ($_.Exception -and $_.Exception.Message -like "*requires elevation*") {
|
if ($CheckBox.Exception.Message -like "*requires elevation*") {
|
||||||
Write-Warning "Unable to Install $feature due to permissions. Are you running as admin?"
|
Write-Warning "Unable to Install $feature due to permissions. Are you running as admin?"
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" }
|
||||||
} else {
|
} else {
|
||||||
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" }
|
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Error" }
|
||||||
Write-Warning "Unable to Install $feature due to unhandled exception"
|
Write-Warning "Unable to Install $feature due to unhandled exception"
|
||||||
if ($_.Exception) {
|
Write-Warning $CheckBox.Exception.StackTrace
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.StackTrace)) {
|
|
||||||
Write-Warning $_.Exception.StackTrace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
function Write-Win11ISOLog {
|
function Write-Win11ISOLog {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Appends a timestamped message to the Win11ISO status log TextBox.
|
||||||
|
.PARAMETER Message
|
||||||
|
The message to append.
|
||||||
|
#>
|
||||||
param([string]$Message)
|
param([string]$Message)
|
||||||
$ts = (Get-Date).ToString("HH:mm:ss")
|
$timestamp = (Get-Date).ToString("HH:mm:ss")
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$current = $sync["WPFWin11ISOStatusLog"].Text
|
$current = $sync["WPFWin11ISOStatusLog"].Text
|
||||||
if ($current -eq "Ready. Please select a Windows 11 ISO to begin.") {
|
if ($current -eq "Ready. Please select a Windows 11 ISO to begin.") {
|
||||||
$sync["WPFWin11ISOStatusLog"].Text = "[$ts] $Message"
|
$sync["WPFWin11ISOStatusLog"].Text = "[$timestamp] $Message"
|
||||||
} else {
|
} else {
|
||||||
$sync["WPFWin11ISOStatusLog"].Text += "`n[$ts] $Message"
|
$sync["WPFWin11ISOStatusLog"].Text += "`n[$timestamp] $Message"
|
||||||
}
|
}
|
||||||
$sync["WPFWin11ISOStatusLog"].CaretIndex = $sync["WPFWin11ISOStatusLog"].Text.Length
|
$sync["WPFWin11ISOStatusLog"].CaretIndex = $sync["WPFWin11ISOStatusLog"].Text.Length
|
||||||
$sync["WPFWin11ISOStatusLog"].ScrollToEnd()
|
$sync["WPFWin11ISOStatusLog"].ScrollToEnd()
|
||||||
@@ -14,34 +20,52 @@ function Write-Win11ISOLog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-WinUtilISOBrowse {
|
function Invoke-WinUtilISOBrowse {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Opens an OpenFileDialog so the user can choose a Windows 11 ISO file.
|
||||||
|
Populates WPFWin11ISOPath and reveals the Mount & Verify section (Step 2).
|
||||||
|
#>
|
||||||
Add-Type -AssemblyName System.Windows.Forms
|
Add-Type -AssemblyName System.Windows.Forms
|
||||||
|
|
||||||
$dlg = [System.Windows.Forms.OpenFileDialog]::new()
|
$dlg = [System.Windows.Forms.OpenFileDialog]::new()
|
||||||
$dlg.Title = "Select Windows 11 ISO"
|
$dlg.Title = "Select Windows 11 ISO"
|
||||||
$dlg.Filter = "ISO files (*.iso)|*.iso|All files (*.*)|*.*"
|
$dlg.Filter = "ISO files (*.iso)|*.iso|All files (*.*)|*.*"
|
||||||
$dlg.InitialDirectory = [System.Environment]::GetFolderPath("Desktop")
|
$dlg.InitialDirectory = [System.Environment]::GetFolderPath("Desktop")
|
||||||
|
|
||||||
if ($dlg.ShowDialog() -ne [System.Windows.Forms.DialogResult]::OK) { return }
|
if ($dlg.ShowDialog() -ne [System.Windows.Forms.DialogResult]::OK) { return }
|
||||||
|
|
||||||
$isoPath = $dlg.FileName
|
$isoPath = $dlg.FileName
|
||||||
|
|
||||||
|
# ── Basic size sanity-check (a Win11 ISO is typically > 4 GB) ──
|
||||||
$fileSizeGB = [math]::Round((Get-Item $isoPath).Length / 1GB, 2)
|
$fileSizeGB = [math]::Round((Get-Item $isoPath).Length / 1GB, 2)
|
||||||
|
|
||||||
$sync["WPFWin11ISOPath"].Text = $isoPath
|
$sync["WPFWin11ISOPath"].Text = $isoPath
|
||||||
$sync["WPFWin11ISOFileInfo"].Text = "File size: $fileSizeGB GB"
|
$sync["WPFWin11ISOFileInfo"].Text = "File size: $fileSizeGB GB"
|
||||||
$sync["WPFWin11ISOFileInfo"].Visibility = "Visible"
|
$sync["WPFWin11ISOFileInfo"].Visibility = "Visible"
|
||||||
$sync["WPFWin11ISOMountSection"].Visibility = "Visible"
|
|
||||||
$sync["WPFWin11ISOVerifyResultPanel"].Visibility = "Collapsed"
|
# Reveal Step 2
|
||||||
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOMountSection"].Visibility = "Visible"
|
||||||
$sync["WPFWin11ISOOutputSection"].Visibility = "Collapsed"
|
|
||||||
|
# Collapse all later steps whenever a new ISO is chosen
|
||||||
|
$sync["WPFWin11ISOVerifyResultPanel"].Visibility = "Collapsed"
|
||||||
|
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
|
||||||
|
$sync["WPFWin11ISOOutputSection"].Visibility = "Collapsed"
|
||||||
|
|
||||||
Write-Win11ISOLog "ISO selected: $isoPath ($fileSizeGB GB)"
|
Write-Win11ISOLog "ISO selected: $isoPath ($fileSizeGB GB)"
|
||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-WinUtilISOMountAndVerify {
|
function Invoke-WinUtilISOMountAndVerify {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Mounts the selected ISO, verifies it is a valid Windows 11 image,
|
||||||
|
and populates the edition list. Reveals Step 3 on success.
|
||||||
|
#>
|
||||||
$isoPath = $sync["WPFWin11ISOPath"].Text
|
$isoPath = $sync["WPFWin11ISOPath"].Text
|
||||||
|
|
||||||
if ([string]::IsNullOrWhiteSpace($isoPath) -or $isoPath -eq "No ISO selected...") {
|
if ([string]::IsNullOrWhiteSpace($isoPath) -or $isoPath -eq "No ISO selected...") {
|
||||||
[System.Windows.MessageBox]::Show("Please select an ISO file first.", "No ISO Selected", "OK", "Warning")
|
[System.Windows.MessageBox]::Show(
|
||||||
|
"Please select an ISO file first.",
|
||||||
|
"No ISO Selected", "OK", "Warning")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,12 +73,14 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
Set-WinUtilProgressBar -Label "Mounting ISO..." -Percent 10
|
Set-WinUtilProgressBar -Label "Mounting ISO..." -Percent 10
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$diskImage = Mount-DiskImage -ImagePath $isoPath -PassThru -ErrorAction Stop
|
# Mount the ISO
|
||||||
|
$diskImage = Mount-DiskImage -ImagePath $isoPath -PassThru -ErrorAction Stop
|
||||||
$driveLetter = ($diskImage | Get-Volume).DriveLetter + ":"
|
$driveLetter = ($diskImage | Get-Volume).DriveLetter + ":"
|
||||||
Write-Win11ISOLog "Mounted at drive $driveLetter"
|
Write-Win11ISOLog "Mounted at drive $driveLetter"
|
||||||
|
|
||||||
Set-WinUtilProgressBar -Label "Verifying ISO contents..." -Percent 30
|
Set-WinUtilProgressBar -Label "Verifying ISO contents..." -Percent 30
|
||||||
|
|
||||||
|
# ── Verify install.wim / install.esd presence ──
|
||||||
$wimPath = Join-Path $driveLetter "sources\install.wim"
|
$wimPath = Join-Path $driveLetter "sources\install.wim"
|
||||||
$esdPath = Join-Path $driveLetter "sources\install.esd"
|
$esdPath = Join-Path $driveLetter "sources\install.esd"
|
||||||
|
|
||||||
@@ -70,10 +96,14 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
|
|
||||||
$activeWim = if (Test-Path $wimPath) { $wimPath } else { $esdPath }
|
$activeWim = if (Test-Path $wimPath) { $wimPath } else { $esdPath }
|
||||||
|
|
||||||
|
# ── Read edition / architecture info ──
|
||||||
Set-WinUtilProgressBar -Label "Reading image metadata..." -Percent 55
|
Set-WinUtilProgressBar -Label "Reading image metadata..." -Percent 55
|
||||||
|
|
||||||
$imageInfo = Get-WindowsImage -ImagePath $activeWim | Select-Object ImageIndex, ImageName
|
$imageInfo = Get-WindowsImage -ImagePath $activeWim | Select-Object ImageIndex, ImageName
|
||||||
|
|
||||||
if (-not ($imageInfo | Where-Object { $_.ImageName -match "Windows 11" })) {
|
# ── Verify at least one Win11 edition is present ──
|
||||||
|
$isWin11 = $imageInfo | Where-Object { $_.ImageName -match "Windows 11" }
|
||||||
|
if (-not $isWin11) {
|
||||||
Dismount-DiskImage -ImagePath $isoPath | Out-Null
|
Dismount-DiskImage -ImagePath $isoPath | Out-Null
|
||||||
Write-Win11ISOLog "ERROR: No 'Windows 11' edition found in the image."
|
Write-Win11ISOLog "ERROR: No 'Windows 11' edition found in the image."
|
||||||
[System.Windows.MessageBox]::Show(
|
[System.Windows.MessageBox]::Show(
|
||||||
@@ -83,8 +113,10 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Store edition info for later index lookup
|
||||||
$sync["Win11ISOImageInfo"] = $imageInfo
|
$sync["Win11ISOImageInfo"] = $imageInfo
|
||||||
|
|
||||||
|
# ── Populate UI ──
|
||||||
$sync["WPFWin11ISOMountDriveLetter"].Text = "Mounted at: $driveLetter | Image file: $(Split-Path $activeWim -Leaf)"
|
$sync["WPFWin11ISOMountDriveLetter"].Text = "Mounted at: $driveLetter | Image file: $(Split-Path $activeWim -Leaf)"
|
||||||
$sync["WPFWin11ISOEditionComboBox"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOEditionComboBox"].Dispatcher.Invoke([action]{
|
||||||
$sync["WPFWin11ISOEditionComboBox"].Items.Clear()
|
$sync["WPFWin11ISOEditionComboBox"].Items.Clear()
|
||||||
@@ -92,10 +124,12 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
[void]$sync["WPFWin11ISOEditionComboBox"].Items.Add("$($img.ImageIndex): $($img.ImageName)")
|
[void]$sync["WPFWin11ISOEditionComboBox"].Items.Add("$($img.ImageIndex): $($img.ImageName)")
|
||||||
}
|
}
|
||||||
if ($sync["WPFWin11ISOEditionComboBox"].Items.Count -gt 0) {
|
if ($sync["WPFWin11ISOEditionComboBox"].Items.Count -gt 0) {
|
||||||
|
# Default to Windows 11 Pro; fall back to first item if not found
|
||||||
$proIndex = -1
|
$proIndex = -1
|
||||||
for ($i = 0; $i -lt $sync["WPFWin11ISOEditionComboBox"].Items.Count; $i++) {
|
for ($i = 0; $i -lt $sync["WPFWin11ISOEditionComboBox"].Items.Count; $i++) {
|
||||||
if ($sync["WPFWin11ISOEditionComboBox"].Items[$i] -match "Windows 11 Pro(?![\w ])") {
|
if ($sync["WPFWin11ISOEditionComboBox"].Items[$i] -match "Windows 11 Pro(?![\w ])") {
|
||||||
$proIndex = $i; break
|
$proIndex = $i
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$sync["WPFWin11ISOEditionComboBox"].SelectedIndex = if ($proIndex -ge 0) { $proIndex } else { 0 }
|
$sync["WPFWin11ISOEditionComboBox"].SelectedIndex = if ($proIndex -ge 0) { $proIndex } else { 0 }
|
||||||
@@ -103,28 +137,43 @@ function Invoke-WinUtilISOMountAndVerify {
|
|||||||
})
|
})
|
||||||
$sync["WPFWin11ISOVerifyResultPanel"].Visibility = "Visible"
|
$sync["WPFWin11ISOVerifyResultPanel"].Visibility = "Visible"
|
||||||
|
|
||||||
|
# Store for later steps
|
||||||
$sync["Win11ISODriveLetter"] = $driveLetter
|
$sync["Win11ISODriveLetter"] = $driveLetter
|
||||||
$sync["Win11ISOWimPath"] = $activeWim
|
$sync["Win11ISOWimPath"] = $activeWim
|
||||||
$sync["Win11ISOImagePath"] = $isoPath
|
$sync["Win11ISOImagePath"] = $isoPath
|
||||||
|
|
||||||
|
# Reveal Step 3
|
||||||
$sync["WPFWin11ISOModifySection"].Visibility = "Visible"
|
$sync["WPFWin11ISOModifySection"].Visibility = "Visible"
|
||||||
|
|
||||||
Set-WinUtilProgressBar -Label "ISO verified" -Percent 100
|
Set-WinUtilProgressBar -Label "ISO verified ✔" -Percent 100
|
||||||
Write-Win11ISOLog "ISO verified OK. Editions found: $($imageInfo.Count)"
|
Write-Win11ISOLog "ISO verified OK. Editions found: $($imageInfo.Count)"
|
||||||
} catch {
|
}
|
||||||
|
catch {
|
||||||
Write-Win11ISOLog "ERROR during mount/verify: $_"
|
Write-Win11ISOLog "ERROR during mount/verify: $_"
|
||||||
[System.Windows.MessageBox]::Show(
|
[System.Windows.MessageBox]::Show(
|
||||||
"An error occurred while mounting or verifying the ISO:`n`n$_",
|
"An error occurred while mounting or verifying the ISO:`n`n$_",
|
||||||
"Error", "OK", "Error")
|
"Error", "OK", "Error")
|
||||||
} finally {
|
}
|
||||||
|
finally {
|
||||||
Start-Sleep -Milliseconds 800
|
Start-Sleep -Milliseconds 800
|
||||||
Set-WinUtilProgressBar -Label "" -Percent 0
|
Set-WinUtilProgressBar -Label "" -Percent 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-WinUtilISOModify {
|
function Invoke-WinUtilISOModify {
|
||||||
$isoPath = $sync["Win11ISOImagePath"]
|
<#
|
||||||
$driveLetter = $sync["Win11ISODriveLetter"]
|
.SYNOPSIS
|
||||||
$wimPath = $sync["Win11ISOWimPath"]
|
Extracts ISO contents to a temp working directory, modifies install.wim,
|
||||||
|
then repackages the image. Reveals Step 4 (output options) on success.
|
||||||
|
|
||||||
|
.NOTES
|
||||||
|
This function runs inside a PowerShell runspace so the UI stays responsive.
|
||||||
|
Placeholder modification logic is provided; extend as needed.
|
||||||
|
#>
|
||||||
|
|
||||||
|
$isoPath = $sync["Win11ISOImagePath"]
|
||||||
|
$driveLetter= $sync["Win11ISODriveLetter"]
|
||||||
|
$wimPath = $sync["Win11ISOWimPath"]
|
||||||
|
|
||||||
if (-not $isoPath) {
|
if (-not $isoPath) {
|
||||||
[System.Windows.MessageBox]::Show(
|
[System.Windows.MessageBox]::Show(
|
||||||
@@ -133,8 +182,9 @@ function Invoke-WinUtilISOModify {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
$selectedItem = $sync["WPFWin11ISOEditionComboBox"].SelectedItem
|
# ── Resolve selected edition index from the ComboBox ──
|
||||||
$selectedWimIndex = 1
|
$selectedItem = $sync["WPFWin11ISOEditionComboBox"].SelectedItem
|
||||||
|
$selectedWimIndex = 1 # default fallback
|
||||||
if ($selectedItem -and $selectedItem -match '^(\d+):') {
|
if ($selectedItem -and $selectedItem -match '^(\d+):') {
|
||||||
$selectedWimIndex = [int]$Matches[1]
|
$selectedWimIndex = [int]$Matches[1]
|
||||||
} elseif ($sync["Win11ISOImageInfo"]) {
|
} elseif ($sync["Win11ISOImageInfo"]) {
|
||||||
@@ -143,10 +193,13 @@ function Invoke-WinUtilISOModify {
|
|||||||
$selectedEditionName = if ($selectedItem) { ($selectedItem -replace '^\d+:\s*', '') } else { "Unknown" }
|
$selectedEditionName = if ($selectedItem) { ($selectedItem -replace '^\d+:\s*', '') } else { "Unknown" }
|
||||||
Write-Win11ISOLog "Selected edition: $selectedEditionName (Index $selectedWimIndex)"
|
Write-Win11ISOLog "Selected edition: $selectedEditionName (Index $selectedWimIndex)"
|
||||||
|
|
||||||
|
# Disable the modify button to prevent double-click
|
||||||
$sync["WPFWin11ISOModifyButton"].IsEnabled = $false
|
$sync["WPFWin11ISOModifyButton"].IsEnabled = $false
|
||||||
|
|
||||||
$existingWorkDir = Get-Item -Path (Join-Path $env:TEMP "WinUtil_Win11ISO*") -ErrorAction SilentlyContinue |
|
$existingWorkDir = Get-Item -Path (Join-Path $env:TEMP "WinUtil_Win11ISO*") -ErrorAction SilentlyContinue |
|
||||||
Where-Object { $_.PSIsContainer } | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
Where-Object { $_.PSIsContainer } |
|
||||||
|
Sort-Object LastWriteTime -Descending |
|
||||||
|
Select-Object -First 1
|
||||||
|
|
||||||
$workDir = if ($existingWorkDir) {
|
$workDir = if ($existingWorkDir) {
|
||||||
Write-Win11ISOLog "Reusing existing temp directory: $($existingWorkDir.FullName)"
|
Write-Win11ISOLog "Reusing existing temp directory: $($existingWorkDir.FullName)"
|
||||||
@@ -155,6 +208,9 @@ function Invoke-WinUtilISOModify {
|
|||||||
Join-Path $env:TEMP "WinUtil_Win11ISO_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
Join-Path $env:TEMP "WinUtil_Win11ISO_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Resolve autounattend.xml content ──────────────────────────────────────
|
||||||
|
# Compiled winutil.ps1 sets $WinUtilAutounattendXml before main.ps1 runs.
|
||||||
|
# In dev/source mode fall back to reading tools\autounattend.xml directly.
|
||||||
$autounattendContent = if ($WinUtilAutounattendXml) {
|
$autounattendContent = if ($WinUtilAutounattendXml) {
|
||||||
$WinUtilAutounattendXml
|
$WinUtilAutounattendXml
|
||||||
} else {
|
} else {
|
||||||
@@ -162,12 +218,11 @@ function Invoke-WinUtilISOModify {
|
|||||||
if (Test-Path $toolsXml) { Get-Content $toolsXml -Raw } else { "" }
|
if (Test-Path $toolsXml) { Get-Content $toolsXml -Raw } else { "" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Run modification in a background runspace ──
|
||||||
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
||||||
$runspace.ApartmentState = "STA"
|
$runspace.ApartmentState = "STA"
|
||||||
$runspace.ThreadOptions = "ReuseThread"
|
$runspace.ThreadOptions = "ReuseThread"
|
||||||
$runspace.Open()
|
$runspace.Open()
|
||||||
$injectDrivers = $sync["WPFWin11ISOInjectDrivers"].IsChecked -eq $true
|
|
||||||
|
|
||||||
$runspace.SessionStateProxy.SetVariable("sync", $sync)
|
$runspace.SessionStateProxy.SetVariable("sync", $sync)
|
||||||
$runspace.SessionStateProxy.SetVariable("isoPath", $isoPath)
|
$runspace.SessionStateProxy.SetVariable("isoPath", $isoPath)
|
||||||
$runspace.SessionStateProxy.SetVariable("driveLetter", $driveLetter)
|
$runspace.SessionStateProxy.SetVariable("driveLetter", $driveLetter)
|
||||||
@@ -176,18 +231,28 @@ function Invoke-WinUtilISOModify {
|
|||||||
$runspace.SessionStateProxy.SetVariable("selectedWimIndex", $selectedWimIndex)
|
$runspace.SessionStateProxy.SetVariable("selectedWimIndex", $selectedWimIndex)
|
||||||
$runspace.SessionStateProxy.SetVariable("selectedEditionName", $selectedEditionName)
|
$runspace.SessionStateProxy.SetVariable("selectedEditionName", $selectedEditionName)
|
||||||
$runspace.SessionStateProxy.SetVariable("autounattendContent", $autounattendContent)
|
$runspace.SessionStateProxy.SetVariable("autounattendContent", $autounattendContent)
|
||||||
$runspace.SessionStateProxy.SetVariable("injectDrivers", $injectDrivers)
|
|
||||||
|
|
||||||
$isoScriptFuncDef = "function Invoke-WinUtilISOScript {`n" + ${function:Invoke-WinUtilISOScript}.ToString() + "`n}"
|
# Serialize functions so they are available inside the runspace
|
||||||
$win11ISOLogFuncDef = "function Write-Win11ISOLog {`n" + ${function:Write-Win11ISOLog}.ToString() + "`n}"
|
$isoScriptFuncDef = "function Invoke-WinUtilISOScript {`n" + `
|
||||||
$runspace.SessionStateProxy.SetVariable("isoScriptFuncDef", $isoScriptFuncDef)
|
${function:Invoke-WinUtilISOScript}.ToString() + "`n}"
|
||||||
|
$runspace.SessionStateProxy.SetVariable("isoScriptFuncDef", $isoScriptFuncDef)
|
||||||
|
|
||||||
|
$win11ISOLogFuncDef = "function Write-Win11ISOLog {`n" + `
|
||||||
|
${function:Write-Win11ISOLog}.ToString() + "`n}"
|
||||||
$runspace.SessionStateProxy.SetVariable("win11ISOLogFuncDef", $win11ISOLogFuncDef)
|
$runspace.SessionStateProxy.SetVariable("win11ISOLogFuncDef", $win11ISOLogFuncDef)
|
||||||
|
|
||||||
|
$refreshUSBFuncDef = "function Invoke-WinUtilISORefreshUSBDrives {`n" + `
|
||||||
|
${function:Invoke-WinUtilISORefreshUSBDrives}.ToString() + "`n}"
|
||||||
|
$runspace.SessionStateProxy.SetVariable("refreshUSBFuncDef", $refreshUSBFuncDef)
|
||||||
|
|
||||||
$script = [Management.Automation.PowerShell]::Create()
|
$script = [Management.Automation.PowerShell]::Create()
|
||||||
$script.Runspace = $runspace
|
$script.Runspace = $runspace
|
||||||
$script.AddScript({
|
$script.AddScript({
|
||||||
|
|
||||||
|
# Import helper functions into this runspace
|
||||||
. ([scriptblock]::Create($isoScriptFuncDef))
|
. ([scriptblock]::Create($isoScriptFuncDef))
|
||||||
. ([scriptblock]::Create($win11ISOLogFuncDef))
|
. ([scriptblock]::Create($win11ISOLogFuncDef))
|
||||||
|
. ([scriptblock]::Create($refreshUSBFuncDef))
|
||||||
|
|
||||||
function Log($msg) {
|
function Log($msg) {
|
||||||
$ts = (Get-Date).ToString("HH:mm:ss")
|
$ts = (Get-Date).ToString("HH:mm:ss")
|
||||||
@@ -208,111 +273,174 @@ function Invoke-WinUtilISOModify {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
# ── Hide Steps 1-3 while modification is running; expand log to fill screen ──
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync["WPFWin11ISOSelectSection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOSelectSection"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOMountSection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOMountSection"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
|
||||||
|
$expandedHeight = [Math]::Max(400, $sync["Form"].ActualHeight - 100)
|
||||||
|
$sync["WPFWin11ISOStatusLog"].Height = $expandedHeight
|
||||||
|
$sync["Win11ISOLogExpanded"] = $true
|
||||||
|
# Register the resize handler once so the log tracks window resizes
|
||||||
|
if (-not $sync["Win11ISOResizeHandlerAdded"]) {
|
||||||
|
$sync["Form"].add_SizeChanged({
|
||||||
|
if ($sync["Win11ISOLogExpanded"]) {
|
||||||
|
$sync["WPFWin11ISOStatusLog"].Height = [Math]::Max(400, $sync["Form"].ActualHeight - 100)
|
||||||
|
$sync["WPFWin11ISOStatusLog"].CaretIndex = $sync["WPFWin11ISOStatusLog"].Text.Length
|
||||||
|
$sync["WPFWin11ISOStatusLog"].ScrollToEnd()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$sync["Win11ISOResizeHandlerAdded"] = $true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# ── 1. Create working directory structure ──
|
||||||
Log "Creating working directory: $workDir"
|
Log "Creating working directory: $workDir"
|
||||||
$isoContents = Join-Path $workDir "iso_contents"
|
$isoContents = Join-Path $workDir "iso_contents"
|
||||||
$mountDir = Join-Path $workDir "wim_mount"
|
$mountDir = Join-Path $workDir "wim_mount"
|
||||||
New-Item -ItemType Directory -Path $isoContents, $mountDir -Force | Out-Null
|
New-Item -ItemType Directory -Path $isoContents, $mountDir -Force | Out-Null
|
||||||
SetProgress "Copying ISO contents..." 10
|
SetProgress "Copying ISO contents..." 10
|
||||||
|
|
||||||
|
# ── 2. Copy all ISO contents to the working directory ──
|
||||||
Log "Copying ISO contents from $driveLetter to $isoContents..."
|
Log "Copying ISO contents from $driveLetter to $isoContents..."
|
||||||
& robocopy $driveLetter $isoContents /E /NFL /NDL /NJH /NJS | Out-Null
|
$robocopyArgs = @($driveLetter, $isoContents, "/E", "/NFL", "/NDL", "/NJH", "/NJS")
|
||||||
|
& robocopy @robocopyArgs | Out-Null
|
||||||
Log "ISO contents copied."
|
Log "ISO contents copied."
|
||||||
SetProgress "Mounting install.wim..." 25
|
SetProgress "Mounting install.wim..." 25
|
||||||
|
|
||||||
|
# ── 3. Copy install.wim to working dir (it may be read-only on the DVD) ──
|
||||||
$localWim = Join-Path $isoContents "sources\install.wim"
|
$localWim = Join-Path $isoContents "sources\install.wim"
|
||||||
if (-not (Test-Path $localWim)) { $localWim = Join-Path $isoContents "sources\install.esd" }
|
if (-not (Test-Path $localWim)) {
|
||||||
|
# ESD path
|
||||||
|
$localWim = Join-Path $isoContents "sources\install.esd"
|
||||||
|
}
|
||||||
|
# Ensure the file is writable
|
||||||
Set-ItemProperty -Path $localWim -Name IsReadOnly -Value $false
|
Set-ItemProperty -Path $localWim -Name IsReadOnly -Value $false
|
||||||
|
|
||||||
|
# ── 4. Mount the selected edition of install.wim ──
|
||||||
Log "Mounting install.wim (Index ${selectedWimIndex}: $selectedEditionName) at $mountDir..."
|
Log "Mounting install.wim (Index ${selectedWimIndex}: $selectedEditionName) at $mountDir..."
|
||||||
Mount-WindowsImage -ImagePath $localWim -Index $selectedWimIndex -Path $mountDir -ErrorAction Stop | Out-Null
|
Mount-WindowsImage -ImagePath $localWim -Index $selectedWimIndex -Path $mountDir -ErrorAction Stop | Out-Null
|
||||||
SetProgress "Modifying install.wim..." 45
|
SetProgress "Modifying install.wim..." 45
|
||||||
|
|
||||||
|
# ── Apply all WinUtil modifications via Invoke-WinUtilISOScript ──
|
||||||
Log "Applying WinUtil modifications to install.wim..."
|
Log "Applying WinUtil modifications to install.wim..."
|
||||||
Invoke-WinUtilISOScript -ScratchDir $mountDir -ISOContentsDir $isoContents -AutoUnattendXml $autounattendContent -InjectCurrentSystemDrivers $injectDrivers -Log { param($m) Log $m }
|
Invoke-WinUtilISOScript -ScratchDir $mountDir -ISOContentsDir $isoContents -AutoUnattendXml $autounattendContent -Log { param($m) Log $m }
|
||||||
|
|
||||||
|
# ── 4b. DISM component store cleanup ──
|
||||||
|
# /ResetBase removes all superseded component versions from WinSxS,
|
||||||
|
# which is the single largest space saving possible (typically 300–800 MB).
|
||||||
|
# This must be done while the image is still mounted.
|
||||||
SetProgress "Cleaning up component store (WinSxS)..." 56
|
SetProgress "Cleaning up component store (WinSxS)..." 56
|
||||||
Log "Running DISM component store cleanup (/ResetBase)..."
|
Log "Running DISM component store cleanup (/ResetBase)..."
|
||||||
& dism /English "/image:$mountDir" /Cleanup-Image /StartComponentCleanup /ResetBase | ForEach-Object { Log $_ }
|
& dism /English "/image:$mountDir" /Cleanup-Image /StartComponentCleanup /ResetBase | ForEach-Object { Log $_ }
|
||||||
Log "Component store cleanup complete."
|
Log "Component store cleanup complete."
|
||||||
|
|
||||||
|
# ── 5. Save and dismount the WIM ──
|
||||||
SetProgress "Saving modified install.wim..." 65
|
SetProgress "Saving modified install.wim..." 65
|
||||||
Log "Dismounting and saving install.wim. This will take several minutes..."
|
Log "Dismounting and saving install.wim. This will take several minutes..."
|
||||||
Dismount-WindowsImage -Path $mountDir -Save -ErrorAction Stop | Out-Null
|
Dismount-WindowsImage -Path $mountDir -Save -ErrorAction Stop | Out-Null
|
||||||
Log "install.wim saved."
|
Log "install.wim saved."
|
||||||
|
|
||||||
|
# ── 5b. Strip unused editions — export only the selected index ──
|
||||||
|
# A standard multi-edition install.wim can be 4–5 GB; exporting a
|
||||||
|
# single index typically drops it to ~3 GB, saving 1–2 GB in the ISO.
|
||||||
SetProgress "Removing unused editions from install.wim..." 70
|
SetProgress "Removing unused editions from install.wim..." 70
|
||||||
Log "Exporting edition '$selectedEditionName' (Index $selectedWimIndex) to a single-edition install.wim..."
|
Log "Exporting edition '$selectedEditionName' (Index $selectedWimIndex) to a single-edition install.wim..."
|
||||||
$exportWim = Join-Path $isoContents "sources\install_export.wim"
|
$exportWim = Join-Path $isoContents "sources\install_export.wim"
|
||||||
Export-WindowsImage -SourceImagePath $localWim -SourceIndex $selectedWimIndex -DestinationImagePath $exportWim -ErrorAction Stop | Out-Null
|
Export-WindowsImage `
|
||||||
|
-SourceImagePath $localWim `
|
||||||
|
-SourceIndex $selectedWimIndex `
|
||||||
|
-DestinationImagePath $exportWim `
|
||||||
|
-ErrorAction Stop | Out-Null
|
||||||
Remove-Item -Path $localWim -Force
|
Remove-Item -Path $localWim -Force
|
||||||
Rename-Item -Path $exportWim -NewName "install.wim" -Force
|
Rename-Item -Path $exportWim -NewName "install.wim" -Force
|
||||||
|
# Update local path so later steps (e.g. ISO build) reference the new file
|
||||||
$localWim = Join-Path $isoContents "sources\install.wim"
|
$localWim = Join-Path $isoContents "sources\install.wim"
|
||||||
Log "Unused editions removed. install.wim now contains only '$selectedEditionName'."
|
Log "Unused editions removed. install.wim now contains only '$selectedEditionName'."
|
||||||
|
|
||||||
SetProgress "Dismounting source ISO..." 80
|
SetProgress "Dismounting source ISO..." 80
|
||||||
|
|
||||||
|
# ── 6. Dismount the original ISO ──
|
||||||
Log "Dismounting original ISO..."
|
Log "Dismounting original ISO..."
|
||||||
Dismount-DiskImage -ImagePath $isoPath | Out-Null
|
Dismount-DiskImage -ImagePath $isoPath | Out-Null
|
||||||
|
|
||||||
$sync["Win11ISOWorkDir"] = $workDir
|
# Store work directory for output steps
|
||||||
$sync["Win11ISOContentsDir"] = $isoContents
|
$sync["Win11ISOWorkDir"] = $workDir
|
||||||
|
$sync["Win11ISOContentsDir"] = $isoContents
|
||||||
|
|
||||||
SetProgress "Modification complete" 100
|
SetProgress "Modification complete ✔" 100
|
||||||
Log "install.wim modification complete. Choose an output option in Step 4."
|
Log "install.wim modification complete. Choose an output option in Step 4."
|
||||||
|
|
||||||
|
# ── Reveal Step 4 on the UI thread ──
|
||||||
|
# Note: USB drive enumeration (Get-Disk) is intentionally deferred to
|
||||||
|
# when the user explicitly selects the USB option, to avoid blocking
|
||||||
|
# the UI thread here.
|
||||||
$sync["WPFWin11ISOOutputSection"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOOutputSection"].Dispatcher.Invoke([action]{
|
||||||
$sync["WPFWin11ISOOutputSection"].Visibility = "Visible"
|
$sync["WPFWin11ISOOutputSection"].Visibility = "Visible"
|
||||||
|
$sync["WPFWin11ISOStatusLog"].Height = 300
|
||||||
})
|
})
|
||||||
} catch {
|
}
|
||||||
|
catch {
|
||||||
Log "ERROR during modification: $_"
|
Log "ERROR during modification: $_"
|
||||||
|
|
||||||
|
# ── Cleanup: dismount WIM if still mounted ──
|
||||||
try {
|
try {
|
||||||
if (Test-Path $mountDir) {
|
if (Test-Path $mountDir) {
|
||||||
$mountedImages = Get-WindowsImage -Mounted -ErrorAction SilentlyContinue | Where-Object { $_.Path -eq $mountDir }
|
$mountedImages = Get-WindowsImage -Mounted -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.Path -eq $mountDir }
|
||||||
if ($mountedImages) {
|
if ($mountedImages) {
|
||||||
Log "Cleaning up: dismounting install.wim (discarding changes)..."
|
Log "Cleaning up: dismounting install.wim (discarding changes)..."
|
||||||
Dismount-WindowsImage -Path $mountDir -Discard -ErrorAction SilentlyContinue | Out-Null
|
Dismount-WindowsImage -Path $mountDir -Discard -ErrorAction SilentlyContinue | Out-Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch { Log "Warning: could not dismount install.wim during cleanup: $_" }
|
} catch {
|
||||||
|
Log "Warning: could not dismount install.wim during cleanup: $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Cleanup: dismount the source ISO ──
|
||||||
try {
|
try {
|
||||||
$mountedISO = Get-DiskImage -ImagePath $isoPath -ErrorAction SilentlyContinue
|
$mountedISO = Get-DiskImage -ImagePath $isoPath -ErrorAction SilentlyContinue
|
||||||
if ($mountedISO -and $mountedISO.Attached) {
|
if ($mountedISO -and $mountedISO.Attached) {
|
||||||
Log "Cleaning up: dismounting source ISO..."
|
Log "Cleaning up: dismounting source ISO..."
|
||||||
Dismount-DiskImage -ImagePath $isoPath -ErrorAction SilentlyContinue | Out-Null
|
Dismount-DiskImage -ImagePath $isoPath -ErrorAction SilentlyContinue | Out-Null
|
||||||
}
|
}
|
||||||
} catch { Log "Warning: could not dismount ISO during cleanup: $_" }
|
} catch {
|
||||||
|
Log "Warning: could not dismount ISO during cleanup: $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Cleanup: remove temp working directory ──
|
||||||
try {
|
try {
|
||||||
if (Test-Path $workDir) {
|
if (Test-Path $workDir) {
|
||||||
Log "Cleaning up: removing temp directory $workDir..."
|
Log "Cleaning up: removing temp directory $workDir..."
|
||||||
Remove-Item -Path $workDir -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item -Path $workDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
} catch { Log "Warning: could not remove temp directory during cleanup: $_" }
|
} catch {
|
||||||
|
Log "Warning: could not remove temp directory during cleanup: $_"
|
||||||
|
}
|
||||||
|
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
[System.Windows.MessageBox]::Show(
|
[System.Windows.MessageBox]::Show(
|
||||||
"An error occurred during install.wim modification:`n`n$_",
|
"An error occurred during install.wim modification:`n`n$_",
|
||||||
"Modification Error", "OK", "Error")
|
"Modification Error", "OK", "Error")
|
||||||
})
|
})
|
||||||
} finally {
|
}
|
||||||
|
finally {
|
||||||
Start-Sleep -Milliseconds 800
|
Start-Sleep -Milliseconds 800
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = ""
|
$sync.progressBarTextBlock.Text = ""
|
||||||
$sync.progressBarTextBlock.ToolTip = ""
|
$sync.progressBarTextBlock.ToolTip = ""
|
||||||
$sync.ProgressBar.Value = 0
|
$sync.ProgressBar.Value = 0
|
||||||
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true
|
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true
|
||||||
|
# ── Only restore steps 1-3 if Step 4 was NOT successfully shown ──
|
||||||
|
# When modification succeeds, Step 4 is visible and steps 1-3 stay
|
||||||
|
# hidden until the user clicks Clean & Reset.
|
||||||
if ($sync["WPFWin11ISOOutputSection"].Visibility -ne "Visible") {
|
if ($sync["WPFWin11ISOOutputSection"].Visibility -ne "Visible") {
|
||||||
$sync["WPFWin11ISOSelectSection"].Visibility = "Visible"
|
$sync["WPFWin11ISOSelectSection"].Visibility = "Visible"
|
||||||
$sync["WPFWin11ISOMountSection"].Visibility = "Visible"
|
$sync["WPFWin11ISOMountSection"].Visibility = "Visible"
|
||||||
$sync["WPFWin11ISOModifySection"].Visibility = "Visible"
|
$sync["WPFWin11ISOModifySection"].Visibility = "Visible"
|
||||||
}
|
}
|
||||||
|
$sync["Win11ISOLogExpanded"] = $false
|
||||||
|
$sync["WPFWin11ISOStatusLog"].Height = 140
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}) | Out-Null
|
}) | Out-Null
|
||||||
@@ -321,24 +449,43 @@ function Invoke-WinUtilISOModify {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-WinUtilISOCheckExistingWork {
|
function Invoke-WinUtilISOCheckExistingWork {
|
||||||
if ($sync["Win11ISOContentsDir"] -and (Test-Path $sync["Win11ISOContentsDir"])) { return }
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Called when the Win11ISO tab is opened. Checks for a pre-existing
|
||||||
|
WinUtil_Win11ISO temp directory and, if found, restores the working-
|
||||||
|
directory state so the user can proceed directly to Step 4 (output
|
||||||
|
options) without repeating the modification.
|
||||||
|
#>
|
||||||
|
|
||||||
|
# If state is already loaded (e.g. user just switched tabs mid-session)
|
||||||
|
# do nothing so we don't overwrite in-progress work.
|
||||||
|
if ($sync["Win11ISOContentsDir"] -and (Test-Path $sync["Win11ISOContentsDir"])) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
$existingWorkDir = Get-Item -Path (Join-Path $env:TEMP "WinUtil_Win11ISO*") -ErrorAction SilentlyContinue |
|
$existingWorkDir = Get-Item -Path (Join-Path $env:TEMP "WinUtil_Win11ISO*") -ErrorAction SilentlyContinue |
|
||||||
Where-Object { $_.PSIsContainer } | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
Where-Object { $_.PSIsContainer } |
|
||||||
|
Sort-Object LastWriteTime -Descending |
|
||||||
|
Select-Object -First 1
|
||||||
|
|
||||||
if (-not $existingWorkDir) { return }
|
if (-not $existingWorkDir) { return }
|
||||||
|
|
||||||
$isoContents = Join-Path $existingWorkDir.FullName "iso_contents"
|
$isoContents = Join-Path $existingWorkDir.FullName "iso_contents"
|
||||||
if (-not (Test-Path $isoContents)) { return }
|
if (-not (Test-Path $isoContents)) { return }
|
||||||
|
|
||||||
|
# Restore state
|
||||||
$sync["Win11ISOWorkDir"] = $existingWorkDir.FullName
|
$sync["Win11ISOWorkDir"] = $existingWorkDir.FullName
|
||||||
$sync["Win11ISOContentsDir"] = $isoContents
|
$sync["Win11ISOContentsDir"] = $isoContents
|
||||||
|
|
||||||
|
# Show Step 4 and collapse steps 1-3 (modification already happened)
|
||||||
$sync["WPFWin11ISOSelectSection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOSelectSection"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOMountSection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOMountSection"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOOutputSection"].Visibility = "Visible"
|
$sync["WPFWin11ISOOutputSection"].Visibility = "Visible"
|
||||||
|
$sync["WPFWin11ISOStatusLog"].Height = 300
|
||||||
|
|
||||||
|
# Notify via the status log
|
||||||
|
$dirName = $existingWorkDir.Name
|
||||||
$modified = $existingWorkDir.LastWriteTime.ToString("yyyy-MM-dd HH:mm")
|
$modified = $existingWorkDir.LastWriteTime.ToString("yyyy-MM-dd HH:mm")
|
||||||
Write-Win11ISOLog "Existing working directory found: $($existingWorkDir.FullName)"
|
Write-Win11ISOLog "Existing working directory found: $($existingWorkDir.FullName)"
|
||||||
Write-Win11ISOLog "Last modified: $modified - Skipping Steps 1-3 and resuming at Step 4."
|
Write-Win11ISOLog "Last modified: $modified - Skipping Steps 1-3 and resuming at Step 4."
|
||||||
@@ -350,6 +497,14 @@ function Invoke-WinUtilISOCheckExistingWork {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-WinUtilISOCleanAndReset {
|
function Invoke-WinUtilISOCleanAndReset {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Deletes the temporary working directory created during ISO modification
|
||||||
|
and resets the entire ISO UI back to its initial state (Step 1 only).
|
||||||
|
Deletion runs in a background runspace so the UI stays responsive and
|
||||||
|
progress is reported to the user.
|
||||||
|
#>
|
||||||
|
|
||||||
$workDir = $sync["Win11ISOWorkDir"]
|
$workDir = $sync["Win11ISOWorkDir"]
|
||||||
|
|
||||||
if ($workDir -and (Test-Path $workDir)) {
|
if ($workDir -and (Test-Path $workDir)) {
|
||||||
@@ -359,6 +514,7 @@ function Invoke-WinUtilISOCleanAndReset {
|
|||||||
if ($confirm -ne "Yes") { return }
|
if ($confirm -ne "Yes") { return }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Disable button so it cannot be clicked twice
|
||||||
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $false
|
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $false
|
||||||
|
|
||||||
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
||||||
@@ -381,7 +537,6 @@ function Invoke-WinUtilISOCleanAndReset {
|
|||||||
})
|
})
|
||||||
Add-Content -Path (Join-Path $workDir "WinUtil_Win11ISO.log") -Value "[$ts] $msg" -ErrorAction SilentlyContinue
|
Add-Content -Path (Join-Path $workDir "WinUtil_Win11ISO.log") -Value "[$ts] $msg" -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
function SetProgress($label, $pct) {
|
function SetProgress($label, $pct) {
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = $label
|
$sync.progressBarTextBlock.Text = $label
|
||||||
@@ -391,56 +546,43 @@ function Invoke-WinUtilISOCleanAndReset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($workDir) {
|
|
||||||
$mountDir = Join-Path $workDir "wim_mount"
|
|
||||||
try {
|
|
||||||
$mountedImages = Get-WindowsImage -Mounted -ErrorAction SilentlyContinue |
|
|
||||||
Where-Object { $_.Path -like "$workDir*" }
|
|
||||||
if ($mountedImages) {
|
|
||||||
foreach ($img in $mountedImages) {
|
|
||||||
Log "Dismounting WIM at: $($img.Path) (discarding changes)..."
|
|
||||||
SetProgress "Dismounting WIM image..." 3
|
|
||||||
Dismount-WindowsImage -Path $img.Path -Discard -ErrorAction Stop | Out-Null
|
|
||||||
Log "WIM dismounted successfully."
|
|
||||||
}
|
|
||||||
} elseif (Test-Path $mountDir) {
|
|
||||||
Log "No mounted WIM reported by Get-WindowsImage, running DISM /Cleanup-Wim as a precaution..."
|
|
||||||
SetProgress "Running DISM cleanup..." 3
|
|
||||||
& dism /English /Cleanup-Wim 2>&1 | ForEach-Object { Log $_ }
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
Log "Warning: could not dismount WIM cleanly, attempting DISM /Cleanup-Wim fallback: $_"
|
|
||||||
try { & dism /English /Cleanup-Wim 2>&1 | ForEach-Object { Log $_ } }
|
|
||||||
catch { Log "Warning: DISM /Cleanup-Wim also failed: $_" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($workDir -and (Test-Path $workDir)) {
|
if ($workDir -and (Test-Path $workDir)) {
|
||||||
Log "Scanning files to delete in: $workDir"
|
Log "Scanning files to delete in: $workDir"
|
||||||
SetProgress "Scanning files..." 5
|
SetProgress "Scanning files..." 5
|
||||||
|
|
||||||
$allFiles = @(Get-ChildItem -Path $workDir -File -Recurse -Force -ErrorAction SilentlyContinue)
|
$allItems = @(Get-ChildItem -Path $workDir -Recurse -Force -ErrorAction SilentlyContinue)
|
||||||
$allDirs = @(Get-ChildItem -Path $workDir -Directory -Recurse -Force -ErrorAction SilentlyContinue |
|
$total = $allItems.Count
|
||||||
Sort-Object { $_.FullName.Length } -Descending)
|
$deleted = 0
|
||||||
$total = $allFiles.Count
|
|
||||||
$deleted = 0
|
|
||||||
|
|
||||||
Log "Found $total files to delete."
|
Log "Found $total items to delete."
|
||||||
|
|
||||||
foreach ($f in $allFiles) {
|
# Delete files first, then directories (deepest first)
|
||||||
try { Remove-Item -Path $f.FullName -Force -ErrorAction Stop } catch { Log "WARNING: could not delete $($f.FullName): $_" }
|
$files = $allItems | Where-Object { -not $_.PSIsContainer }
|
||||||
|
$dirs = $allItems | Where-Object { $_.PSIsContainer } |
|
||||||
|
Sort-Object { $_.FullName.Length } -Descending
|
||||||
|
|
||||||
|
foreach ($f in $files) {
|
||||||
|
try { Remove-Item -Path $f.FullName -Force -ErrorAction Stop } catch {}
|
||||||
$deleted++
|
$deleted++
|
||||||
if ($deleted % 100 -eq 0 -or $deleted -eq $total) {
|
if ($deleted % 100 -eq 0 -or $deleted -eq $files.Count) {
|
||||||
$pct = [math]::Round(($deleted / [Math]::Max($total, 1)) * 85) + 5
|
$pct = [math]::Round(($deleted / [Math]::Max($total,1)) * 85) + 5
|
||||||
SetProgress "Deleting files in $($f.Directory.Name)... ($deleted / $total)" $pct
|
SetProgress "Deleting files... ($deleted / $total)" $pct
|
||||||
|
Log "Deleting files... $deleted of $total"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($d in $allDirs) {
|
foreach ($d in $dirs) {
|
||||||
try { Remove-Item -Path $d.FullName -Force -ErrorAction SilentlyContinue } catch {}
|
try { Remove-Item -Path $d.FullName -Force -Recurse -ErrorAction Stop } catch {}
|
||||||
|
$deleted++
|
||||||
|
if ($deleted % 50 -eq 0 -or $deleted -eq $total) {
|
||||||
|
$pct = [math]::Round(($deleted / [Math]::Max($total,1)) * 85) + 5
|
||||||
|
SetProgress "Removing directories... ($deleted / $total)" $pct
|
||||||
|
Log "Removing directories... $deleted of $total"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try { Remove-Item -Path $workDir -Recurse -Force -ErrorAction Stop } catch {}
|
# Remove the root work directory itself
|
||||||
|
try { Remove-Item -Path $workDir -Force -Recurse -ErrorAction Stop } catch {}
|
||||||
|
|
||||||
if (Test-Path $workDir) {
|
if (Test-Path $workDir) {
|
||||||
Log "WARNING: some items could not be deleted in $workDir"
|
Log "WARNING: some items could not be deleted in $workDir"
|
||||||
@@ -454,7 +596,9 @@ function Invoke-WinUtilISOCleanAndReset {
|
|||||||
SetProgress "Resetting UI..." 95
|
SetProgress "Resetting UI..." 95
|
||||||
Log "Resetting interface..."
|
Log "Resetting interface..."
|
||||||
|
|
||||||
|
# ── Full UI reset on the dispatcher thread ──────────────────────
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
|
# Clear stored state
|
||||||
$sync["Win11ISOWorkDir"] = $null
|
$sync["Win11ISOWorkDir"] = $null
|
||||||
$sync["Win11ISOContentsDir"] = $null
|
$sync["Win11ISOContentsDir"] = $null
|
||||||
$sync["Win11ISOImagePath"] = $null
|
$sync["Win11ISOImagePath"] = $null
|
||||||
@@ -463,24 +607,27 @@ function Invoke-WinUtilISOCleanAndReset {
|
|||||||
$sync["Win11ISOImageInfo"] = $null
|
$sync["Win11ISOImageInfo"] = $null
|
||||||
$sync["Win11ISOUSBDisks"] = $null
|
$sync["Win11ISOUSBDisks"] = $null
|
||||||
|
|
||||||
$sync["WPFWin11ISOPath"].Text = "No ISO selected..."
|
# Reset UI elements
|
||||||
$sync["WPFWin11ISOFileInfo"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOPath"].Text = "No ISO selected..."
|
||||||
$sync["WPFWin11ISOVerifyResultPanel"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOFileInfo"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOOptionUSB"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOVerifyResultPanel"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOOutputSection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOOptionUSB"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOOutputSection"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOMountSection"].Visibility = "Collapsed"
|
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOSelectSection"].Visibility = "Visible"
|
$sync["WPFWin11ISOMountSection"].Visibility = "Collapsed"
|
||||||
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true
|
$sync["WPFWin11ISOSelectSection"].Visibility = "Visible"
|
||||||
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $true
|
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true
|
||||||
|
$sync["WPFWin11ISOCleanResetButton"].IsEnabled = $true
|
||||||
|
|
||||||
$sync.progressBarTextBlock.Text = ""
|
$sync.progressBarTextBlock.Text = ""
|
||||||
$sync.progressBarTextBlock.ToolTip = ""
|
$sync.progressBarTextBlock.ToolTip = ""
|
||||||
$sync.ProgressBar.Value = 0
|
$sync.ProgressBar.Value = 0
|
||||||
|
|
||||||
|
$sync["WPFWin11ISOStatusLog"].Height = 140
|
||||||
$sync["WPFWin11ISOStatusLog"].Text = "Ready. Please select a Windows 11 ISO to begin."
|
$sync["WPFWin11ISOStatusLog"].Text = "Ready. Please select a Windows 11 ISO to begin."
|
||||||
})
|
})
|
||||||
} catch {
|
}
|
||||||
|
catch {
|
||||||
Log "ERROR during Clean & Reset: $_"
|
Log "ERROR during Clean & Reset: $_"
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = ""
|
$sync.progressBarTextBlock.Text = ""
|
||||||
@@ -495,11 +642,17 @@ function Invoke-WinUtilISOCleanAndReset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-WinUtilISOExport {
|
function Invoke-WinUtilISOExport {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Saves the modified ISO contents as a new bootable ISO file.
|
||||||
|
Uses oscdimg.exe (part of the Windows ADK) if present; falls back
|
||||||
|
to a reminder message if not installed.
|
||||||
|
#>
|
||||||
$contentsDir = $sync["Win11ISOContentsDir"]
|
$contentsDir = $sync["Win11ISOContentsDir"]
|
||||||
|
|
||||||
if (-not $contentsDir -or -not (Test-Path $contentsDir)) {
|
if (-not $contentsDir -or -not (Test-Path $contentsDir)) {
|
||||||
[System.Windows.MessageBox]::Show(
|
[System.Windows.MessageBox]::Show(
|
||||||
"No modified ISO content found. Please complete Steps 1-3 first.",
|
"No modified ISO content found. Please complete Steps 1–3 first.",
|
||||||
"Not Ready", "OK", "Warning")
|
"Not Ready", "OK", "Warning")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -515,6 +668,9 @@ function Invoke-WinUtilISOExport {
|
|||||||
if ($dlg.ShowDialog() -ne [System.Windows.Forms.DialogResult]::OK) { return }
|
if ($dlg.ShowDialog() -ne [System.Windows.Forms.DialogResult]::OK) { return }
|
||||||
|
|
||||||
$outputISO = $dlg.FileName
|
$outputISO = $dlg.FileName
|
||||||
|
Write-Win11ISOLog "Exporting to ISO: $outputISO"
|
||||||
|
|
||||||
|
Set-WinUtilProgressBar -Label "Building ISO..." -Percent 10
|
||||||
|
|
||||||
# Locate oscdimg.exe (Windows ADK or winget per-user install)
|
# Locate oscdimg.exe (Windows ADK or winget per-user install)
|
||||||
$oscdimg = Get-ChildItem "C:\Program Files (x86)\Windows Kits" -Recurse -Filter "oscdimg.exe" -ErrorAction SilentlyContinue |
|
$oscdimg = Get-ChildItem "C:\Program Files (x86)\Windows Kits" -Recurse -Filter "oscdimg.exe" -ErrorAction SilentlyContinue |
|
||||||
@@ -526,11 +682,13 @@ function Invoke-WinUtilISOExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not $oscdimg) {
|
if (-not $oscdimg) {
|
||||||
Write-Win11ISOLog "oscdimg.exe not found. Attempting to install via winget..."
|
Write-Win11ISOLog "oscdimg.exe not found. Attempting to install via winget..."
|
||||||
|
Set-WinUtilProgressBar -Label "Installing oscdimg..." -Percent 5
|
||||||
try {
|
try {
|
||||||
$winget = Get-Command winget -ErrorAction Stop
|
$winget = Get-Command winget -ErrorAction Stop
|
||||||
$result = & $winget install -e --id Microsoft.OSCDIMG --accept-package-agreements --accept-source-agreements 2>&1
|
$result = & $winget install -e --id Microsoft.OSCDIMG --accept-package-agreements --accept-source-agreements 2>&1
|
||||||
Write-Win11ISOLog "winget output: $result"
|
Write-Win11ISOLog "winget output: $result"
|
||||||
|
# Re-scan after install
|
||||||
$oscdimg = Get-ChildItem "$env:LOCALAPPDATA\Microsoft\WinGet\Packages" -Recurse -Filter "oscdimg.exe" -ErrorAction SilentlyContinue |
|
$oscdimg = Get-ChildItem "$env:LOCALAPPDATA\Microsoft\WinGet\Packages" -Recurse -Filter "oscdimg.exe" -ErrorAction SilentlyContinue |
|
||||||
Where-Object { $_.FullName -match 'Microsoft\.OSCDIMG' } |
|
Where-Object { $_.FullName -match 'Microsoft\.OSCDIMG' } |
|
||||||
Select-Object -First 1 -ExpandProperty FullName
|
Select-Object -First 1 -ExpandProperty FullName
|
||||||
@@ -539,6 +697,7 @@ function Invoke-WinUtilISOExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not $oscdimg) {
|
if (-not $oscdimg) {
|
||||||
|
Set-WinUtilProgressBar -Label "" -Percent 0
|
||||||
Write-Win11ISOLog "oscdimg.exe still not found after install attempt."
|
Write-Win11ISOLog "oscdimg.exe still not found after install attempt."
|
||||||
[System.Windows.MessageBox]::Show(
|
[System.Windows.MessageBox]::Show(
|
||||||
"oscdimg.exe could not be found or installed automatically.`n`nPlease install it manually:`n winget install -e --id Microsoft.OSCDIMG`n`nOr install the Windows ADK from:`nhttps://learn.microsoft.com/windows-hardware/get-started/adk-install",
|
"oscdimg.exe could not be found or installed automatically.`n`nPlease install it manually:`n winget install -e --id Microsoft.OSCDIMG`n`nOr install the Windows ADK from:`nhttps://learn.microsoft.com/windows-hardware/get-started/adk-install",
|
||||||
@@ -548,97 +707,66 @@ function Invoke-WinUtilISOExport {
|
|||||||
Write-Win11ISOLog "oscdimg.exe installed successfully."
|
Write-Win11ISOLog "oscdimg.exe installed successfully."
|
||||||
}
|
}
|
||||||
|
|
||||||
$sync["WPFWin11ISOChooseISOButton"].IsEnabled = $false
|
# Build boot parameters (BIOS + UEFI dual-boot)
|
||||||
|
$bootData = "2#p0,e,b`"$contentsDir\boot\etfsboot.com`"#pEF,e,b`"$contentsDir\efi\microsoft\boot\efisys.bin`""
|
||||||
|
$oscdimgArgs = @(
|
||||||
|
"-m", # ignore source path max size
|
||||||
|
"-o", # optimise storage
|
||||||
|
"-u2", # UDF 2.01
|
||||||
|
"-udfver102",
|
||||||
|
"-bootdata:$bootData",
|
||||||
|
"-l`"CTOS_MODIFIED`"",
|
||||||
|
"`"$contentsDir`"",
|
||||||
|
"`"$outputISO`""
|
||||||
|
)
|
||||||
|
|
||||||
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
|
try {
|
||||||
$runspace.ApartmentState = "STA"
|
Write-Win11ISOLog "Running oscdimg..."
|
||||||
$runspace.ThreadOptions = "ReuseThread"
|
$psi = [System.Diagnostics.ProcessStartInfo]::new()
|
||||||
$runspace.Open()
|
$psi.FileName = $oscdimg
|
||||||
$runspace.SessionStateProxy.SetVariable("sync", $sync)
|
$psi.Arguments = $oscdimgArgs -join " "
|
||||||
$runspace.SessionStateProxy.SetVariable("contentsDir", $contentsDir)
|
$psi.RedirectStandardOutput = $true
|
||||||
$runspace.SessionStateProxy.SetVariable("outputISO", $outputISO)
|
$psi.RedirectStandardError = $true
|
||||||
$runspace.SessionStateProxy.SetVariable("oscdimg", $oscdimg)
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
|
||||||
$win11ISOLogFuncDef = "function Write-Win11ISOLog {`n" + ${function:Write-Win11ISOLog}.ToString() + "`n}"
|
$proc = [System.Diagnostics.Process]::new()
|
||||||
$runspace.SessionStateProxy.SetVariable("win11ISOLogFuncDef", $win11ISOLogFuncDef)
|
$proc.StartInfo = $psi
|
||||||
|
$proc.Start() | Out-Null
|
||||||
|
|
||||||
$script = [Management.Automation.PowerShell]::Create()
|
# Stream stdout and stderr line-by-line to the status log
|
||||||
$script.Runspace = $runspace
|
$stdoutTask = $proc.StandardOutput.ReadToEndAsync()
|
||||||
$script.AddScript({
|
$stderrTask = $proc.StandardError.ReadToEndAsync()
|
||||||
. ([scriptblock]::Create($win11ISOLogFuncDef))
|
$proc.WaitForExit()
|
||||||
|
[System.Threading.Tasks.Task]::WaitAll($stdoutTask, $stderrTask)
|
||||||
|
|
||||||
function SetProgress($label, $pct) {
|
foreach ($line in ($stdoutTask.Result -split "`r?`n")) {
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
if ($line.Trim()) { Write-Win11ISOLog $line }
|
||||||
$sync.progressBarTextBlock.Text = $label
|
}
|
||||||
$sync.progressBarTextBlock.ToolTip = $label
|
foreach ($line in ($stderrTask.Result -split "`r?`n")) {
|
||||||
$sync.ProgressBar.Value = [Math]::Max($pct, 5)
|
if ($line.Trim()) { Write-Win11ISOLog "[stderr]$line" }
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if ($proc.ExitCode -eq 0) {
|
||||||
Write-Win11ISOLog "Exporting to ISO: $outputISO"
|
Set-WinUtilProgressBar -Label "ISO exported" -Percent 100
|
||||||
SetProgress "Building ISO..." 10
|
Write-Win11ISOLog "ISO exported successfully: $outputISO"
|
||||||
|
[System.Windows.MessageBox]::Show(
|
||||||
$bootData = "2#p0,e,b`"$contentsDir\boot\etfsboot.com`"#pEF,e,b`"$contentsDir\efi\microsoft\boot\efisys.bin`""
|
"ISO exported successfully!`n`n$outputISO",
|
||||||
$oscdimgArgs = @("-m", "-o", "-u2", "-udfver102", "-bootdata:$bootData", "-l`"CTOS_MODIFIED`"", "`"$contentsDir`"", "`"$outputISO`"")
|
"Export Complete", "OK", "Info")
|
||||||
|
} else {
|
||||||
Write-Win11ISOLog "Running oscdimg..."
|
Write-Win11ISOLog "oscdimg exited with code $($proc.ExitCode)."
|
||||||
|
[System.Windows.MessageBox]::Show(
|
||||||
$psi = [System.Diagnostics.ProcessStartInfo]::new()
|
"oscdimg exited with code $($proc.ExitCode).`nCheck the status log for details.",
|
||||||
$psi.FileName = $oscdimg
|
"Export Error", "OK", "Error")
|
||||||
$psi.Arguments = $oscdimgArgs -join " "
|
|
||||||
$psi.RedirectStandardOutput = $true
|
|
||||||
$psi.RedirectStandardError = $true
|
|
||||||
$psi.UseShellExecute = $false
|
|
||||||
$psi.CreateNoWindow = $true
|
|
||||||
|
|
||||||
$proc = [System.Diagnostics.Process]::new()
|
|
||||||
$proc.StartInfo = $psi
|
|
||||||
$proc.Start() | Out-Null
|
|
||||||
|
|
||||||
# Stream stdout line-by-line as oscdimg runs
|
|
||||||
while (-not $proc.StandardOutput.EndOfStream) {
|
|
||||||
$line = $proc.StandardOutput.ReadLine()
|
|
||||||
if ($line.Trim()) { Write-Win11ISOLog $line }
|
|
||||||
}
|
|
||||||
|
|
||||||
$proc.WaitForExit()
|
|
||||||
|
|
||||||
# Flush any stderr after process exits
|
|
||||||
$stderr = $proc.StandardError.ReadToEnd()
|
|
||||||
foreach ($line in ($stderr -split "`r?`n")) {
|
|
||||||
if ($line.Trim()) { Write-Win11ISOLog "[stderr]$line" }
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($proc.ExitCode -eq 0) {
|
|
||||||
SetProgress "ISO exported" 100
|
|
||||||
Write-Win11ISOLog "ISO exported successfully: $outputISO"
|
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
|
||||||
[System.Windows.MessageBox]::Show("ISO exported successfully!`n`n$outputISO", "Export Complete", "OK", "Info")
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Write-Win11ISOLog "oscdimg exited with code $($proc.ExitCode)."
|
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
|
||||||
[System.Windows.MessageBox]::Show(
|
|
||||||
"oscdimg exited with code $($proc.ExitCode).`nCheck the status log for details.",
|
|
||||||
"Export Error", "OK", "Error")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
Write-Win11ISOLog "ERROR during ISO export: $_"
|
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
|
||||||
[System.Windows.MessageBox]::Show("ISO export failed:`n`n$_", "Error", "OK", "Error")
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
Start-Sleep -Milliseconds 800
|
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
|
||||||
$sync.progressBarTextBlock.Text = ""
|
|
||||||
$sync.progressBarTextBlock.ToolTip = ""
|
|
||||||
$sync.ProgressBar.Value = 0
|
|
||||||
$sync["WPFWin11ISOChooseISOButton"].IsEnabled = $true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}) | Out-Null
|
}
|
||||||
|
catch {
|
||||||
$script.BeginInvoke() | Out-Null
|
Write-Win11ISOLog "ERROR during ISO export: $_"
|
||||||
|
[System.Windows.MessageBox]::Show("ISO export failed:`n`n$_","Error","OK","Error")
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Start-Sleep -Milliseconds 800
|
||||||
|
Set-WinUtilProgressBar -Label "" -Percent 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,38 +4,34 @@ function Invoke-WinUtilISOScript {
|
|||||||
Applies WinUtil modifications to a mounted Windows 11 install.wim image.
|
Applies WinUtil modifications to a mounted Windows 11 install.wim image.
|
||||||
|
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
Removes AppX bloatware and OneDrive, optionally injects all drivers exported from
|
Removes AppX bloatware and OneDrive, injects hardware drivers (NVMe, Precision
|
||||||
the running system into install.wim and boot.wim (controlled by the
|
Touchpad/HID, and network) exported from the running system, optionally injects
|
||||||
-InjectCurrentSystemDrivers switch), applies offline registry tweaks (hardware
|
extended Storage & Network drivers from the ChrisTitusTech/storage-lan-drivers
|
||||||
bypass, privacy, OOBE, telemetry, update suppression), deletes CEIP/WU
|
repository (requires git, installed via winget if absent), applies offline registry
|
||||||
scheduled-task definition files, and optionally writes autounattend.xml to the ISO
|
tweaks (hardware bypass, privacy, OOBE, telemetry, update suppression), deletes
|
||||||
root and removes the support\ folder from the ISO contents directory.
|
CEIP/WU scheduled-task definition files, and optionally drops autounattend.xml and
|
||||||
|
removes the support\ folder from the ISO contents directory.
|
||||||
All setup scripts embedded in the autounattend.xml <Extensions><File> nodes are
|
|
||||||
written directly into the WIM at their target paths under C:\Windows\Setup\Scripts\
|
|
||||||
to ensure they survive Windows Setup stripping unrecognised-namespace XML elements
|
|
||||||
from the Panther copy of the answer file.
|
|
||||||
|
|
||||||
Mounting/dismounting the WIM is the caller's responsibility (e.g. Invoke-WinUtilISO).
|
Mounting/dismounting the WIM is the caller's responsibility (e.g. Invoke-WinUtilISO).
|
||||||
|
|
||||||
.PARAMETER ScratchDir
|
.PARAMETER ScratchDir
|
||||||
Mandatory. Full path to the directory where the Windows image is currently mounted.
|
Mandatory. Full path to the directory where the Windows image is currently mounted.
|
||||||
|
Example: C:\Users\USERNAME\AppData\Local\Temp\WinUtil_Win11ISO_20260222\wim_mount
|
||||||
|
|
||||||
.PARAMETER ISOContentsDir
|
.PARAMETER ISOContentsDir
|
||||||
Optional. Root directory of the extracted ISO contents. When supplied,
|
Optional. Root directory of the extracted ISO contents.
|
||||||
autounattend.xml is written here and the support\ folder is removed.
|
When supplied, autounattend.xml is also written here so Windows Setup picks it
|
||||||
|
up automatically at boot, and the support\ folder is deleted from that location.
|
||||||
|
|
||||||
.PARAMETER AutoUnattendXml
|
.PARAMETER AutoUnattendXml
|
||||||
Optional. Full XML content for autounattend.xml. If empty, the OOBE bypass
|
Optional. Full XML content for autounattend.xml.
|
||||||
file is skipped and a warning is logged.
|
In compiled winutil.ps1 this is the embedded $WinUtilAutounattendXml here-string;
|
||||||
|
in dev mode it is read from tools\autounattend.xml.
|
||||||
.PARAMETER InjectCurrentSystemDrivers
|
If empty, the OOBE bypass file is skipped and a warning is logged.
|
||||||
Optional. When $true, exports all drivers from the running system and injects
|
|
||||||
them into install.wim and boot.wim index 2 (Windows Setup PE).
|
|
||||||
Defaults to $false.
|
|
||||||
|
|
||||||
.PARAMETER Log
|
.PARAMETER Log
|
||||||
Optional ScriptBlock for progress/status logging. Receives a single [string] argument.
|
Optional ScriptBlock used for progress/status logging.
|
||||||
|
Receives a single [string] message argument.
|
||||||
|
Defaults to { param($m) Write-Output $m } when not supplied.
|
||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Invoke-WinUtilISOScript -ScratchDir "C:\Temp\wim_mount"
|
Invoke-WinUtilISOScript -ScratchDir "C:\Temp\wim_mount"
|
||||||
@@ -50,19 +46,20 @@ function Invoke-WinUtilISOScript {
|
|||||||
.NOTES
|
.NOTES
|
||||||
Author : Chris Titus @christitustech
|
Author : Chris Titus @christitustech
|
||||||
GitHub : https://github.com/ChrisTitusTech
|
GitHub : https://github.com/ChrisTitusTech
|
||||||
Version : 26.03.02
|
Version : 26.02.25b
|
||||||
#>
|
#>
|
||||||
param (
|
param (
|
||||||
[Parameter(Mandatory)][string]$ScratchDir,
|
[Parameter(Mandatory)][string]$ScratchDir,
|
||||||
[string]$ISOContentsDir = "",
|
[string]$ISOContentsDir = "",
|
||||||
[string]$AutoUnattendXml = "",
|
[string]$AutoUnattendXml = "",
|
||||||
[bool]$InjectCurrentSystemDrivers = $false,
|
|
||||||
[scriptblock]$Log = { param($m) Write-Output $m }
|
[scriptblock]$Log = { param($m) Write-Output $m }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ── Resolve admin group name (for takeown / icacls) ──────────────────────
|
||||||
$adminSID = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544')
|
$adminSID = New-Object System.Security.Principal.SecurityIdentifier('S-1-5-32-544')
|
||||||
$adminGroup = $adminSID.Translate([System.Security.Principal.NTAccount])
|
$adminGroup = $adminSID.Translate([System.Security.Principal.NTAccount])
|
||||||
|
|
||||||
|
# ── Local helpers ─────────────────────────────────────────────────────────
|
||||||
function Set-ISOScriptReg {
|
function Set-ISOScriptReg {
|
||||||
param ([string]$path, [string]$name, [string]$type, [string]$value)
|
param ([string]$path, [string]$name, [string]$type, [string]$value)
|
||||||
try {
|
try {
|
||||||
@@ -83,19 +80,56 @@ function Invoke-WinUtilISOScript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Copies driver package folders (one per exported .inf) whose online class
|
||||||
|
# matches any of the supplied class names into a new temp staging directory.
|
||||||
|
# Returns the staging directory path — caller must delete it when done.
|
||||||
|
# Using a staging dir lets DISM inject all drivers in a single /Recurse
|
||||||
|
# call instead of one DISM process launch per .inf file.
|
||||||
|
function New-DriverStagingDir {
|
||||||
|
param ([string]$ExportRoot, [string[]]$Classes)
|
||||||
|
$stagingDir = Join-Path $env:TEMP "WinUtil_DriverStage_$(Get-Random)"
|
||||||
|
New-Item -Path $stagingDir -ItemType Directory -Force | Out-Null
|
||||||
|
Get-WindowsDriver -Online |
|
||||||
|
Where-Object { $_.ClassName -in $Classes } |
|
||||||
|
ForEach-Object { [IO.Path]::GetFileNameWithoutExtension($_.OriginalFileName) } |
|
||||||
|
Select-Object -Unique |
|
||||||
|
ForEach-Object {
|
||||||
|
Get-ChildItem -Path $ExportRoot -Filter "$_.inf" -Recurse -ErrorAction SilentlyContinue |
|
||||||
|
Select-Object -ExpandProperty DirectoryName -Unique |
|
||||||
|
ForEach-Object {
|
||||||
|
# Each exported driver lives in its own sub-folder;
|
||||||
|
# copy that folder (with its binary files) into staging.
|
||||||
|
$dest = Join-Path $stagingDir (Split-Path $_ -Leaf)
|
||||||
|
Copy-Item -Path $_ -Destination $dest -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $stagingDir
|
||||||
|
}
|
||||||
|
|
||||||
|
# Injects all drivers from $DriverDir into a DISM-mounted image in one call.
|
||||||
function Add-DriversToImage {
|
function Add-DriversToImage {
|
||||||
param ([string]$MountPath, [string]$DriverDir, [string]$Label = "image", [scriptblock]$Logger)
|
param (
|
||||||
|
[string]$MountPath,
|
||||||
|
[string]$DriverDir,
|
||||||
|
[string]$Label = "image",
|
||||||
|
[scriptblock]$Logger
|
||||||
|
)
|
||||||
& dism /English "/image:$MountPath" /Add-Driver "/Driver:$DriverDir" /Recurse 2>&1 |
|
& dism /English "/image:$MountPath" /Add-Driver "/Driver:$DriverDir" /Recurse 2>&1 |
|
||||||
ForEach-Object { & $Logger " dism[$Label]: $_" }
|
ForEach-Object { & $Logger " dism[$Label]: $_" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Mounts boot.wim index 2, injects all drivers from $DriverDir, saves, dismounts.
|
||||||
function Invoke-BootWimInject {
|
function Invoke-BootWimInject {
|
||||||
param ([string]$BootWimPath, [string]$DriverDir, [scriptblock]$Logger)
|
param (
|
||||||
|
[string]$BootWimPath,
|
||||||
|
[string]$DriverDir,
|
||||||
|
[scriptblock]$Logger
|
||||||
|
)
|
||||||
Set-ItemProperty -Path $BootWimPath -Name IsReadOnly -Value $false -ErrorAction SilentlyContinue
|
Set-ItemProperty -Path $BootWimPath -Name IsReadOnly -Value $false -ErrorAction SilentlyContinue
|
||||||
$mountDir = Join-Path $env:TEMP "WinUtil_BootMount_$(Get-Random)"
|
$mountDir = Join-Path $env:TEMP "WinUtil_BootMount_$(Get-Random)"
|
||||||
New-Item -Path $mountDir -ItemType Directory -Force | Out-Null
|
New-Item -Path $mountDir -ItemType Directory -Force | Out-Null
|
||||||
try {
|
try {
|
||||||
& $Logger "Mounting boot.wim (index 2) for driver injection..."
|
& $Logger "Mounting boot.wim (index 2 — Windows Setup) for driver injection..."
|
||||||
Mount-WindowsImage -ImagePath $BootWimPath -Index 2 -Path $mountDir -ErrorAction Stop | Out-Null
|
Mount-WindowsImage -ImagePath $BootWimPath -Index 2 -Path $mountDir -ErrorAction Stop | Out-Null
|
||||||
Add-DriversToImage -MountPath $mountDir -DriverDir $DriverDir -Label "boot" -Logger $Logger
|
Add-DriversToImage -MountPath $mountDir -DriverDir $DriverDir -Label "boot" -Logger $Logger
|
||||||
& $Logger "Saving boot.wim..."
|
& $Logger "Saving boot.wim..."
|
||||||
@@ -109,11 +143,15 @@ function Invoke-WinUtilISOScript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── 1. Remove provisioned AppX packages ──────────────────────────────────
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
|
# 1. Remove provisioned AppX packages
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
& $Log "Removing provisioned AppX packages..."
|
& $Log "Removing provisioned AppX packages..."
|
||||||
|
|
||||||
$packages = & dism /English "/image:$ScratchDir" /Get-ProvisionedAppxPackages |
|
$packages = & dism /English "/image:$ScratchDir" /Get-ProvisionedAppxPackages |
|
||||||
ForEach-Object { if ($_ -match 'PackageName : (.*)') { $matches[1] } }
|
ForEach-Object {
|
||||||
|
if ($_ -match 'PackageName : (.*)') { $matches[1] }
|
||||||
|
}
|
||||||
|
|
||||||
$packagePrefixes = @(
|
$packagePrefixes = @(
|
||||||
'AppUp.IntelManagementandSecurityStatus',
|
'AppUp.IntelManagementandSecurityStatus',
|
||||||
@@ -160,46 +198,126 @@ function Invoke-WinUtilISOScript {
|
|||||||
'MicrosoftTeams'
|
'MicrosoftTeams'
|
||||||
)
|
)
|
||||||
|
|
||||||
$packages | Where-Object { $pkg = $_; $packagePrefixes | Where-Object { $pkg -like "*$_*" } } |
|
$packagesToRemove = $packages | Where-Object {
|
||||||
ForEach-Object { & dism /English "/image:$ScratchDir" /Remove-ProvisionedAppxPackage "/PackageName:$_" }
|
$pkg = $_
|
||||||
|
$packagePrefixes | Where-Object { $pkg -like "*$_*" }
|
||||||
# ── 2. Inject current system drivers (optional) ───────────────────────────
|
}
|
||||||
if ($InjectCurrentSystemDrivers) {
|
foreach ($package in $packagesToRemove) {
|
||||||
& $Log "Exporting all drivers from running system..."
|
& dism /English "/image:$ScratchDir" /Remove-ProvisionedAppxPackage "/PackageName:$package"
|
||||||
$driverExportRoot = Join-Path $env:TEMP "WinUtil_DriverExport_$(Get-Random)"
|
|
||||||
New-Item -Path $driverExportRoot -ItemType Directory -Force | Out-Null
|
|
||||||
try {
|
|
||||||
Export-WindowsDriver -Online -Destination $driverExportRoot | Out-Null
|
|
||||||
|
|
||||||
& $Log "Injecting current system drivers into install.wim..."
|
|
||||||
Add-DriversToImage -MountPath $ScratchDir -DriverDir $driverExportRoot -Label "install" -Logger $Log
|
|
||||||
& $Log "install.wim driver injection complete."
|
|
||||||
|
|
||||||
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
|
|
||||||
$bootWim = Join-Path $ISOContentsDir "sources\boot.wim"
|
|
||||||
if (Test-Path $bootWim) {
|
|
||||||
& $Log "Injecting current system drivers into boot.wim..."
|
|
||||||
Invoke-BootWimInject -BootWimPath $bootWim -DriverDir $driverExportRoot -Logger $Log
|
|
||||||
} else {
|
|
||||||
& $Log "Warning: boot.wim not found — skipping boot.wim driver injection."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
& $Log "Error during driver export/injection: $_"
|
|
||||||
} finally {
|
|
||||||
Remove-Item -Path $driverExportRoot -Recurse -Force -ErrorAction SilentlyContinue
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
& $Log "Driver injection skipped."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── 3. Remove OneDrive ────────────────────────────────────────────────────
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
|
# 2. Inject hardware drivers (NVMe / Trackpad / Network)
|
||||||
|
# Injected into BOTH install.wim (OS) AND boot.wim index 2 (Setup).
|
||||||
|
# Without storage drivers in boot.wim, Windows Setup cannot see the
|
||||||
|
# target disk on systems with unsupported NVMe / SATA controllers.
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
|
& $Log "Exporting hardware drivers from running system (NVMe, HID/Trackpad, Network)..."
|
||||||
|
|
||||||
|
$driverExportRoot = Join-Path $env:TEMP "WinUtil_DriverExport_$(Get-Random)"
|
||||||
|
New-Item -Path $driverExportRoot -ItemType Directory -Force | Out-Null
|
||||||
|
|
||||||
|
try {
|
||||||
|
Export-WindowsDriver -Online -Destination $driverExportRoot | Out-Null
|
||||||
|
|
||||||
|
# Stage matching driver folders then do a single DISM /Recurse call.
|
||||||
|
# install.wim: SCSIAdapter + HIDClass + Net
|
||||||
|
$installStage = New-DriverStagingDir -ExportRoot $driverExportRoot -Classes @('SCSIAdapter','HIDClass','Net')
|
||||||
|
& $Log "Injecting staged drivers into install.wim (single DISM call)..."
|
||||||
|
Add-DriversToImage -MountPath $ScratchDir -DriverDir $installStage -Label "install" -Logger $Log
|
||||||
|
Remove-Item -Path $installStage -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
& $Log "install.wim driver injection complete."
|
||||||
|
|
||||||
|
# boot.wim: SCSIAdapter + Net only (HID not needed in WinPE)
|
||||||
|
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
|
||||||
|
$bootWim = Join-Path $ISOContentsDir "sources\boot.wim"
|
||||||
|
if (Test-Path $bootWim) {
|
||||||
|
$bootStage = New-DriverStagingDir -ExportRoot $driverExportRoot -Classes @('SCSIAdapter','Net')
|
||||||
|
& $Log "Injecting staged drivers into boot.wim (single DISM call)..."
|
||||||
|
Invoke-BootWimInject -BootWimPath $bootWim -DriverDir $bootStage -Logger $Log
|
||||||
|
Remove-Item -Path $bootStage -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
} else {
|
||||||
|
& $Log "Warning: boot.wim not found — skipping boot.wim driver injection."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
& $Log "Error during driver export/injection: $_"
|
||||||
|
} finally {
|
||||||
|
Remove-Item -Path $driverExportRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── 2c. Optional: extended Storage & Network drivers from community repo ──
|
||||||
|
$extDriverChoice = [System.Windows.MessageBox]::Show(
|
||||||
|
"Would you like to add extended Storage and Network drivers?`n`n" +
|
||||||
|
"This installs EVERY Storage and Networking device driver " +
|
||||||
|
"in EXISTANCE into the image. (~1000 drivers)`n`n" +
|
||||||
|
"No Wireless drivers only Ethernet, use for stubborn systems " +
|
||||||
|
"with unsupported NVMe or Ethernet controllers.",
|
||||||
|
"Extended Drivers", "YesNo", "Question")
|
||||||
|
|
||||||
|
if ($extDriverChoice -eq 'Yes') {
|
||||||
|
& $Log "Extended driver injection requested."
|
||||||
|
|
||||||
|
# Ensure git is available
|
||||||
|
$gitCmd = Get-Command git -ErrorAction SilentlyContinue
|
||||||
|
if (-not $gitCmd) {
|
||||||
|
& $Log "Git not found — installing via winget..."
|
||||||
|
winget install --id Git.Git -e --source winget `
|
||||||
|
--accept-package-agreements --accept-source-agreements | Out-Null
|
||||||
|
# Refresh PATH so git is visible in this session
|
||||||
|
$env:PATH = [System.Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' +
|
||||||
|
[System.Environment]::GetEnvironmentVariable('PATH', 'User')
|
||||||
|
$gitCmd = Get-Command git -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $gitCmd) {
|
||||||
|
& $Log "Warning: git could not be found after install attempt — skipping extended drivers."
|
||||||
|
} else {
|
||||||
|
$extRepoDir = Join-Path $env:TEMP "WinUtil_ExtDrivers_$(Get-Random)"
|
||||||
|
try {
|
||||||
|
& $Log "Cloning storage-lan-drivers repository..."
|
||||||
|
& git clone --depth 1 `
|
||||||
|
"https://github.com/ChrisTitusTech/storage-lan-drivers" `
|
||||||
|
$extRepoDir 2>&1 | ForEach-Object { & $Log " git: $_" }
|
||||||
|
|
||||||
|
if (Test-Path $extRepoDir) {
|
||||||
|
& $Log "Injecting extended drivers into install.wim (this may take several minutes)..."
|
||||||
|
Add-DriversToImage -MountPath $ScratchDir -DriverDir $extRepoDir -Label "install" -Logger $Log
|
||||||
|
& $Log "Extended driver injection into install.wim complete."
|
||||||
|
|
||||||
|
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
|
||||||
|
$bootWimExt = Join-Path $ISOContentsDir "sources\boot.wim"
|
||||||
|
if (Test-Path $bootWimExt) {
|
||||||
|
& $Log "Injecting extended drivers into boot.wim..."
|
||||||
|
Invoke-BootWimInject -BootWimPath $bootWimExt -DriverDir $extRepoDir -Logger $Log
|
||||||
|
} else {
|
||||||
|
& $Log "Warning: boot.wim not found — skipping extended driver injection into boot.wim."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
& $Log "Warning: repository clone directory not found — skipping extended drivers."
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
& $Log "Error during extended driver injection: $_"
|
||||||
|
} finally {
|
||||||
|
Remove-Item -Path $extRepoDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
& $Log "Extended driver injection skipped."
|
||||||
|
}
|
||||||
|
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
|
# 3. Remove OneDrive
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
& $Log "Removing OneDrive..."
|
& $Log "Removing OneDrive..."
|
||||||
& takeown /f "$ScratchDir\Windows\System32\OneDriveSetup.exe" | Out-Null
|
& takeown /f "$ScratchDir\Windows\System32\OneDriveSetup.exe" | Out-Null
|
||||||
& icacls "$ScratchDir\Windows\System32\OneDriveSetup.exe" /grant "$($adminGroup.Value):(F)" /T /C | Out-Null
|
& icacls "$ScratchDir\Windows\System32\OneDriveSetup.exe" /grant "$($adminGroup.Value):(F)" /T /C | Out-Null
|
||||||
Remove-Item -Path "$ScratchDir\Windows\System32\OneDriveSetup.exe" -Force -ErrorAction SilentlyContinue
|
Remove-Item -Path "$ScratchDir\Windows\System32\OneDriveSetup.exe" -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
# ── 4. Registry tweaks ────────────────────────────────────────────────────
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
|
# 4. Registry tweaks
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
& $Log "Loading offline registry hives..."
|
& $Log "Loading offline registry hives..."
|
||||||
reg load HKLM\zCOMPONENTS "$ScratchDir\Windows\System32\config\COMPONENTS"
|
reg load HKLM\zCOMPONENTS "$ScratchDir\Windows\System32\config\COMPONENTS"
|
||||||
reg load HKLM\zDEFAULT "$ScratchDir\Windows\System32\config\default"
|
reg load HKLM\zDEFAULT "$ScratchDir\Windows\System32\config\default"
|
||||||
@@ -248,37 +366,14 @@ function Invoke-WinUtilISOScript {
|
|||||||
Set-ISOScriptReg 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\OOBE' 'BypassNRO' 'REG_DWORD' '1'
|
Set-ISOScriptReg 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\OOBE' 'BypassNRO' 'REG_DWORD' '1'
|
||||||
|
|
||||||
if ($AutoUnattendXml) {
|
if ($AutoUnattendXml) {
|
||||||
try {
|
# ── Place autounattend.xml inside the WIM (Sysprep) ──────────────────
|
||||||
$xmlDoc = [xml]::new()
|
$sysprepDest = "$ScratchDir\Windows\System32\Sysprep\autounattend.xml"
|
||||||
$xmlDoc.LoadXml($AutoUnattendXml)
|
Set-Content -Path $sysprepDest -Value $AutoUnattendXml -Encoding UTF8 -Force
|
||||||
|
& $Log "Written autounattend.xml to Sysprep directory."
|
||||||
$nsMgr = New-Object System.Xml.XmlNamespaceManager($xmlDoc.NameTable)
|
|
||||||
$nsMgr.AddNamespace("sg", "https://schneegans.de/windows/unattend-generator/")
|
|
||||||
|
|
||||||
$fileNodes = $xmlDoc.SelectNodes("//sg:File", $nsMgr)
|
|
||||||
if ($fileNodes -and $fileNodes.Count -gt 0) {
|
|
||||||
foreach ($fileNode in $fileNodes) {
|
|
||||||
$absPath = $fileNode.GetAttribute("path")
|
|
||||||
$relPath = $absPath -replace '^[A-Za-z]:[/\\]', ''
|
|
||||||
$destPath = Join-Path $ScratchDir $relPath
|
|
||||||
New-Item -Path (Split-Path $destPath -Parent) -ItemType Directory -Force -ErrorAction SilentlyContinue | Out-Null
|
|
||||||
|
|
||||||
$ext = [IO.Path]::GetExtension($destPath).ToLower()
|
|
||||||
$encoding = switch ($ext) {
|
|
||||||
{ $_ -in '.ps1', '.xml' } { [System.Text.Encoding]::UTF8 }
|
|
||||||
{ $_ -in '.reg', '.vbs', '.js' } { [System.Text.UnicodeEncoding]::new($false, $true) }
|
|
||||||
default { [System.Text.Encoding]::Default }
|
|
||||||
}
|
|
||||||
[System.IO.File]::WriteAllBytes($destPath, ($encoding.GetPreamble() + $encoding.GetBytes($fileNode.InnerText.Trim())))
|
|
||||||
& $Log "Pre-staged setup script: $relPath"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
& $Log "Warning: no <Extensions><File> nodes found in autounattend.xml — setup scripts not pre-staged."
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
& $Log "Warning: could not pre-stage setup scripts from autounattend.xml: $_"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
# ── Place autounattend.xml at the ISO / USB root ──────────────────────
|
||||||
|
# Windows Setup reads this file first (before booting into the OS),
|
||||||
|
# which is what drives the local-account / OOBE bypass at install time.
|
||||||
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
|
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
|
||||||
$isoDest = Join-Path $ISOContentsDir "autounattend.xml"
|
$isoDest = Join-Path $ISOContentsDir "autounattend.xml"
|
||||||
Set-Content -Path $isoDest -Value $AutoUnattendXml -Encoding UTF8 -Force
|
Set-Content -Path $isoDest -Value $AutoUnattendXml -Encoding UTF8 -Force
|
||||||
@@ -321,8 +416,8 @@ function Invoke-WinUtilISOScript {
|
|||||||
Remove-ISOScriptReg 'HKLM\zSOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\DevHomeUpdate'
|
Remove-ISOScriptReg 'HKLM\zSOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\DevHomeUpdate'
|
||||||
|
|
||||||
& $Log "Disabling Copilot..."
|
& $Log "Disabling Copilot..."
|
||||||
Set-ISOScriptReg 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\WindowsCopilot' 'TurnOffWindowsCopilot' 'REG_DWORD' '1'
|
Set-ISOScriptReg 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\WindowsCopilot' 'TurnOffWindowsCopilot' 'REG_DWORD' '1'
|
||||||
Set-ISOScriptReg 'HKLM\zSOFTWARE\Policies\Microsoft\Edge' 'HubsSidebarEnabled' 'REG_DWORD' '0'
|
Set-ISOScriptReg 'HKLM\zSOFTWARE\Policies\Microsoft\Edge' 'HubsSidebarEnabled' 'REG_DWORD' '0'
|
||||||
Set-ISOScriptReg 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\Explorer' 'DisableSearchBoxSuggestions' 'REG_DWORD' '1'
|
Set-ISOScriptReg 'HKLM\zSOFTWARE\Policies\Microsoft\Windows\Explorer' 'DisableSearchBoxSuggestions' 'REG_DWORD' '1'
|
||||||
|
|
||||||
& $Log "Disabling Windows Update during OOBE (re-enabled on first logon via FirstLogon.ps1)..."
|
& $Log "Disabling Windows Update during OOBE (re-enabled on first logon via FirstLogon.ps1)..."
|
||||||
@@ -353,9 +448,12 @@ function Invoke-WinUtilISOScript {
|
|||||||
reg unload HKLM\zSOFTWARE
|
reg unload HKLM\zSOFTWARE
|
||||||
reg unload HKLM\zSYSTEM
|
reg unload HKLM\zSYSTEM
|
||||||
|
|
||||||
# ── 5. Delete scheduled task definition files ─────────────────────────────
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
|
# 5. Delete scheduled task definition files
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
& $Log "Deleting scheduled task definition files..."
|
& $Log "Deleting scheduled task definition files..."
|
||||||
$tasksPath = "$ScratchDir\Windows\System32\Tasks"
|
$tasksPath = "$ScratchDir\Windows\System32\Tasks"
|
||||||
|
|
||||||
Remove-Item "$tasksPath\Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser" -Force -ErrorAction SilentlyContinue
|
Remove-Item "$tasksPath\Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser" -Force -ErrorAction SilentlyContinue
|
||||||
Remove-Item "$tasksPath\Microsoft\Windows\Customer Experience Improvement Program" -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item "$tasksPath\Microsoft\Windows\Customer Experience Improvement Program" -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
Remove-Item "$tasksPath\Microsoft\Windows\Application Experience\ProgramDataUpdater" -Force -ErrorAction SilentlyContinue
|
Remove-Item "$tasksPath\Microsoft\Windows\Application Experience\ProgramDataUpdater" -Force -ErrorAction SilentlyContinue
|
||||||
@@ -367,9 +465,12 @@ function Invoke-WinUtilISOScript {
|
|||||||
Remove-Item "$tasksPath\Microsoft\Windows\WaaSMedic" -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item "$tasksPath\Microsoft\Windows\WaaSMedic" -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
Remove-Item "$tasksPath\Microsoft\Windows\WindowsUpdate" -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item "$tasksPath\Microsoft\Windows\WindowsUpdate" -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
Remove-Item "$tasksPath\Microsoft\WindowsUpdate" -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item "$tasksPath\Microsoft\WindowsUpdate" -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
& $Log "Scheduled task files deleted."
|
& $Log "Scheduled task files deleted."
|
||||||
|
|
||||||
# ── 6. Remove ISO support folder ─────────────────────────────────────────
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
|
# 6. Remove ISO support folder (fresh-install only; not needed)
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════
|
||||||
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
|
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
|
||||||
& $Log "Removing ISO support\ folder..."
|
& $Log "Removing ISO support\ folder..."
|
||||||
Remove-Item -Path (Join-Path $ISOContentsDir "support") -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item -Path (Join-Path $ISOContentsDir "support") -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
|||||||
@@ -1,53 +1,57 @@
|
|||||||
function Invoke-WinUtilISORefreshUSBDrives {
|
function Invoke-WinUtilISORefreshUSBDrives {
|
||||||
$combo = $sync["WPFWin11ISOUSBDriveComboBox"]
|
<#
|
||||||
$removable = @(Get-Disk | Where-Object { $_.BusType -eq "USB" } | Sort-Object Number)
|
.SYNOPSIS
|
||||||
|
Populates the USB drive ComboBox with all currently attached removable drives.
|
||||||
|
#>
|
||||||
|
$combo = $sync["WPFWin11ISOUSBDriveComboBox"]
|
||||||
$combo.Items.Clear()
|
$combo.Items.Clear()
|
||||||
|
|
||||||
|
$removable = Get-Disk | Where-Object { $_.BusType -eq "USB" } | Sort-Object Number
|
||||||
|
|
||||||
if ($removable.Count -eq 0) {
|
if ($removable.Count -eq 0) {
|
||||||
$combo.Items.Add("No USB drives detected")
|
$combo.Items.Add("No USB drives detected")
|
||||||
$combo.SelectedIndex = 0
|
$combo.SelectedIndex = 0
|
||||||
$sync["Win11ISOUSBDisks"] = @()
|
|
||||||
Write-Win11ISOLog "No USB drives detected."
|
Write-Win11ISOLog "No USB drives detected."
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($disk in $removable) {
|
foreach ($disk in $removable) {
|
||||||
$sizeGB = [math]::Round($disk.Size / 1GB, 1)
|
$sizeGB = [math]::Round($disk.Size / 1GB, 1)
|
||||||
$combo.Items.Add("Disk $($disk.Number): $($disk.FriendlyName) [$sizeGB GB] - $($disk.PartitionStyle)")
|
$label = "Disk $($disk.Number): $($disk.FriendlyName) [$sizeGB GB] - $($disk.PartitionStyle)"
|
||||||
|
$combo.Items.Add($label)
|
||||||
}
|
}
|
||||||
$combo.SelectedIndex = 0
|
$combo.SelectedIndex = 0
|
||||||
Write-Win11ISOLog "Found $($removable.Count) USB drive(s)."
|
Write-Win11ISOLog "Found $($removable.Count) USB drive(s)."
|
||||||
|
|
||||||
|
# Store disk objects for later use
|
||||||
$sync["Win11ISOUSBDisks"] = $removable
|
$sync["Win11ISOUSBDisks"] = $removable
|
||||||
}
|
}
|
||||||
|
|
||||||
function Invoke-WinUtilISOWriteUSB {
|
function Invoke-WinUtilISOWriteUSB {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Erases the selected USB drive and writes the modified Windows 11 ISO
|
||||||
|
content as a bootable installation drive (using DISM / robocopy approach).
|
||||||
|
#>
|
||||||
$contentsDir = $sync["Win11ISOContentsDir"]
|
$contentsDir = $sync["Win11ISOContentsDir"]
|
||||||
$usbDisks = $sync["Win11ISOUSBDisks"]
|
$usbDisks = $sync["Win11ISOUSBDisks"]
|
||||||
|
|
||||||
if (-not $contentsDir -or -not (Test-Path $contentsDir)) {
|
if (-not $contentsDir -or -not (Test-Path $contentsDir)) {
|
||||||
[System.Windows.MessageBox]::Show("No modified ISO content found. Please complete Steps 1-3 first.", "Not Ready", "OK", "Warning")
|
[System.Windows.MessageBox]::Show(
|
||||||
|
"No modified ISO content found. Please complete Steps 1-3 first.",
|
||||||
|
"Not Ready", "OK", "Warning")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
$combo = $sync["WPFWin11ISOUSBDriveComboBox"]
|
$selectedIndex = $sync["WPFWin11ISOUSBDriveComboBox"].SelectedIndex
|
||||||
$selectedIndex = $combo.SelectedIndex
|
if ($selectedIndex -lt 0 -or -not $usbDisks -or $selectedIndex -ge $usbDisks.Count) {
|
||||||
$selectedItemText = [string]$combo.SelectedItem
|
[System.Windows.MessageBox]::Show(
|
||||||
$usbDisks = @($usbDisks)
|
"Please select a USB drive from the dropdown.",
|
||||||
|
"No Drive Selected", "OK", "Warning")
|
||||||
$targetDisk = $null
|
|
||||||
if ($selectedIndex -ge 0 -and $selectedIndex -lt $usbDisks.Count) {
|
|
||||||
$targetDisk = $usbDisks[$selectedIndex]
|
|
||||||
} elseif ($selectedItemText -match 'Disk\s+(\d+):') {
|
|
||||||
$selectedDiskNum = [int]$matches[1]
|
|
||||||
$targetDisk = $usbDisks | Where-Object { $_.Number -eq $selectedDiskNum } | Select-Object -First 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-not $targetDisk) {
|
|
||||||
[System.Windows.MessageBox]::Show("Please select a USB drive from the dropdown.", "No Drive Selected", "OK", "Warning")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$targetDisk = $usbDisks[$selectedIndex]
|
||||||
$diskNum = $targetDisk.Number
|
$diskNum = $targetDisk.Number
|
||||||
$sizeGB = [math]::Round($targetDisk.Size / 1GB, 1)
|
$sizeGB = [math]::Round($targetDisk.Size / 1GB, 1)
|
||||||
|
|
||||||
@@ -67,9 +71,9 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
$runspace.ApartmentState = "STA"
|
$runspace.ApartmentState = "STA"
|
||||||
$runspace.ThreadOptions = "ReuseThread"
|
$runspace.ThreadOptions = "ReuseThread"
|
||||||
$runspace.Open()
|
$runspace.Open()
|
||||||
$runspace.SessionStateProxy.SetVariable("sync", $sync)
|
$runspace.SessionStateProxy.SetVariable("sync", $sync)
|
||||||
$runspace.SessionStateProxy.SetVariable("diskNum", $diskNum)
|
$runspace.SessionStateProxy.SetVariable("diskNum", $diskNum)
|
||||||
$runspace.SessionStateProxy.SetVariable("contentsDir", $contentsDir)
|
$runspace.SessionStateProxy.SetVariable("contentsDir", $contentsDir)
|
||||||
|
|
||||||
$script = [Management.Automation.PowerShell]::Create()
|
$script = [Management.Automation.PowerShell]::Create()
|
||||||
$script.Runspace = $runspace
|
$script.Runspace = $runspace
|
||||||
@@ -83,7 +87,6 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
$sync["WPFWin11ISOStatusLog"].ScrollToEnd()
|
$sync["WPFWin11ISOStatusLog"].ScrollToEnd()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function SetProgress($label, $pct) {
|
function SetProgress($label, $pct) {
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = $label
|
$sync.progressBarTextBlock.Text = $label
|
||||||
@@ -92,36 +95,38 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-FreeDriveLetter {
|
|
||||||
$used = (Get-PSDrive -PSProvider FileSystem -ErrorAction SilentlyContinue).Name
|
|
||||||
foreach ($c in [char[]](68..90)) {
|
|
||||||
if ($used -notcontains [string]$c) { return $c }
|
|
||||||
}
|
|
||||||
return $null
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SetProgress "Formatting USB drive..." 10
|
SetProgress "Formatting USB drive..." 10
|
||||||
|
|
||||||
# Phase 1: Clean disk via diskpart (retry once if the drive is not yet ready)
|
# ── Helper: find a free drive letter (D-Z) ──────────────────────────
|
||||||
$dpFile1 = Join-Path $env:TEMP "winutil_diskpart_$(Get-Random).txt"
|
function Get-FreeDriveLetter {
|
||||||
"select disk $diskNum`nclean`nexit" | Set-Content -Path $dpFile1 -Encoding ASCII
|
$used = (Get-PSDrive -PSProvider FileSystem -ErrorAction SilentlyContinue).Name
|
||||||
Log "Running diskpart clean on Disk $diskNum..."
|
foreach ($c in [char[]](68..90)) { # D..Z
|
||||||
$dpCleanOut = diskpart /s $dpFile1 2>&1
|
if ($used -notcontains [string]$c) { return $c }
|
||||||
$dpCleanOut | Where-Object { $_ -match '\S' } | ForEach-Object { Log " diskpart: $_" }
|
}
|
||||||
Remove-Item $dpFile1 -Force -ErrorAction SilentlyContinue
|
return $null
|
||||||
|
|
||||||
if (($dpCleanOut -join ' ') -match 'device is not ready') {
|
|
||||||
Log "Disk $diskNum was not ready; waiting 5 seconds and retrying clean..."
|
|
||||||
Start-Sleep -Seconds 5
|
|
||||||
Update-Disk -Number $diskNum -ErrorAction SilentlyContinue
|
|
||||||
$dpFile1b = Join-Path $env:TEMP "winutil_diskpart_$(Get-Random).txt"
|
|
||||||
"select disk $diskNum`nclean`nexit" | Set-Content -Path $dpFile1b -Encoding ASCII
|
|
||||||
diskpart /s $dpFile1b 2>&1 | Where-Object { $_ -match '\S' } | ForEach-Object { Log " diskpart: $_" }
|
|
||||||
Remove-Item $dpFile1b -Force -ErrorAction SilentlyContinue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Phase 2: Initialize as GPT
|
# ── Phase 1: Clean the disk via diskpart ────────────────────────────
|
||||||
|
# Only run "clean" here. "convert gpt" in diskpart requires the disk to
|
||||||
|
# already be MBR; after a clean the disk is RAW, so convert gpt fails on
|
||||||
|
# many systems. We use Initialize-Disk (which accepts RAW disks) instead.
|
||||||
|
$dpScript1 = @"
|
||||||
|
select disk $diskNum
|
||||||
|
clean
|
||||||
|
exit
|
||||||
|
"@
|
||||||
|
$dpFile1 = Join-Path $env:TEMP "winutil_diskpart_$(Get-Random).txt"
|
||||||
|
$dpScript1 | Set-Content -Path $dpFile1 -Encoding ASCII
|
||||||
|
Log "Running diskpart clean on Disk $diskNum..."
|
||||||
|
$dpOut1 = diskpart /s $dpFile1 2>&1
|
||||||
|
Remove-Item $dpFile1 -Force -ErrorAction SilentlyContinue
|
||||||
|
$dpOut1 | Where-Object { $_ -match '\S' } | ForEach-Object { Log " diskpart: $_" }
|
||||||
|
|
||||||
|
# ── Phase 2: Initialize as GPT via PowerShell ────────────────────────
|
||||||
|
# After "clean", Windows may still see the disk as initialized (stale
|
||||||
|
# metadata). Initialize-Disk only accepts RAW disks; Set-Disk handles
|
||||||
|
# already-initialized (MBR/GPT) disks with no partitions. Try both.
|
||||||
Start-Sleep -Seconds 2
|
Start-Sleep -Seconds 2
|
||||||
Update-Disk -Number $diskNum -ErrorAction SilentlyContinue
|
Update-Disk -Number $diskNum -ErrorAction SilentlyContinue
|
||||||
$diskObj = Get-Disk -Number $diskNum -ErrorAction Stop
|
$diskObj = Get-Disk -Number $diskNum -ErrorAction Stop
|
||||||
@@ -133,53 +138,45 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
Log "Disk $diskNum converted to GPT (was $($diskObj.PartitionStyle))."
|
Log "Disk $diskNum converted to GPT (was $($diskObj.PartitionStyle))."
|
||||||
}
|
}
|
||||||
|
|
||||||
# Phase 3: Create FAT32 partition via diskpart, then format with Format-Volume
|
# ── Phase 3: Create partitions via diskpart ──────────────────────────
|
||||||
# (diskpart's 'format' command can fail with "no volume selected" on fresh/never-formatted drives)
|
# "create partition efi" is not supported on removable media.
|
||||||
|
# A single FAT32 primary partition is all that is needed for a UEFI-
|
||||||
|
# bootable Windows install USB - the firmware locates \EFI\Boot\bootx64.efi
|
||||||
|
# on any FAT32 volume regardless of GPT partition type.
|
||||||
|
# FAT32 label limit is 11 chars; "W11-yyMMdd" = 10, fits without trimming.
|
||||||
$volLabel = "W11-" + (Get-Date).ToString('yyMMdd')
|
$volLabel = "W11-" + (Get-Date).ToString('yyMMdd')
|
||||||
$dpFile2 = Join-Path $env:TEMP "winutil_diskpart2_$(Get-Random).txt"
|
$dpScript2 = @"
|
||||||
$maxFat32PartitionMB = 32768
|
select disk $diskNum
|
||||||
$diskSizeMB = [int][Math]::Floor((Get-Disk -Number $diskNum -ErrorAction Stop).Size / 1MB)
|
create partition primary
|
||||||
$createPartitionCommand = "create partition primary"
|
format quick fs=fat32 label="$volLabel"
|
||||||
if ($diskSizeMB -gt $maxFat32PartitionMB) {
|
exit
|
||||||
$createPartitionCommand = "create partition primary size=$maxFat32PartitionMB"
|
"@
|
||||||
Log "Disk $diskNum is $diskSizeMB MB; creating FAT32 partition capped at $maxFat32PartitionMB MB (32 GB)."
|
$dpFile2 = Join-Path $env:TEMP "winutil_diskpart2_$(Get-Random).txt"
|
||||||
}
|
$dpScript2 | Set-Content -Path $dpFile2 -Encoding ASCII
|
||||||
|
|
||||||
@(
|
|
||||||
"select disk $diskNum"
|
|
||||||
$createPartitionCommand
|
|
||||||
"exit"
|
|
||||||
) | Set-Content -Path $dpFile2 -Encoding ASCII
|
|
||||||
Log "Creating partitions on Disk $diskNum..."
|
Log "Creating partitions on Disk $diskNum..."
|
||||||
diskpart /s $dpFile2 2>&1 | Where-Object { $_ -match '\S' } | ForEach-Object { Log " diskpart: $_" }
|
$dpOut2 = diskpart /s $dpFile2 2>&1
|
||||||
Remove-Item $dpFile2 -Force -ErrorAction SilentlyContinue
|
Remove-Item $dpFile2 -Force -ErrorAction SilentlyContinue
|
||||||
|
$dpOut2 | Where-Object { $_ -match '\S' } | ForEach-Object { Log " diskpart: $_" }
|
||||||
|
|
||||||
SetProgress "Formatting USB partition..." 25
|
SetProgress "Assigning drive letters..." 30
|
||||||
Start-Sleep -Seconds 3
|
Start-Sleep -Seconds 3 # allow Windows to settle after partition creation
|
||||||
Update-Disk -Number $diskNum -ErrorAction SilentlyContinue
|
Update-Disk -Number $diskNum -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
# ── Explicitly assign drive letters via PowerShell ───────────────────
|
||||||
|
# This is reliable regardless of registry state, unlike diskpart assign.
|
||||||
$partitions = Get-Partition -DiskNumber $diskNum -ErrorAction Stop
|
$partitions = Get-Partition -DiskNumber $diskNum -ErrorAction Stop
|
||||||
Log "Partitions on Disk $diskNum after creation: $($partitions.Count)"
|
Log "Partitions on Disk $diskNum after format: $($partitions.Count)"
|
||||||
foreach ($p in $partitions) {
|
foreach ($p in $partitions) {
|
||||||
Log " Partition $($p.PartitionNumber) Type=$($p.Type) Letter=$($p.DriveLetter) Size=$([math]::Round($p.Size/1MB))MB"
|
Log " Partition $($p.PartitionNumber) Type=$($p.Type) Letter=$($p.DriveLetter) Size=$([math]::Round($p.Size/1MB))MB"
|
||||||
}
|
}
|
||||||
|
|
||||||
$winpePart = $partitions | Where-Object { $_.Type -eq "Basic" } | Select-Object -Last 1
|
$winpePart = $partitions | Where-Object { $_.Type -eq "Basic" } | Select-Object -Last 1
|
||||||
|
|
||||||
if (-not $winpePart) {
|
if (-not $winpePart) {
|
||||||
throw "Could not find the Basic partition on Disk $diskNum after creation."
|
throw "Could not find the WINPE (Basic) partition on Disk $diskNum after format."
|
||||||
}
|
}
|
||||||
|
|
||||||
# Format using Format-Volume (reliable on fresh drives; diskpart format fails
|
# Remove stale letter first (noops if none), then assign a fresh one
|
||||||
# with 'no volume selected' when the partition has never been formatted before)
|
|
||||||
Log "Formatting Partition $($winpePart.PartitionNumber) as FAT32 (label: $volLabel)..."
|
|
||||||
Get-Partition -DiskNumber $diskNum -PartitionNumber $winpePart.PartitionNumber |
|
|
||||||
Format-Volume -FileSystem FAT32 -NewFileSystemLabel $volLabel -Force -Confirm:$false | Out-Null
|
|
||||||
Log "Partition $($winpePart.PartitionNumber) formatted as FAT32."
|
|
||||||
|
|
||||||
SetProgress "Assigning drive letters..." 30
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
Update-Disk -Number $diskNum -ErrorAction SilentlyContinue
|
|
||||||
|
|
||||||
try { Remove-PartitionAccessPath -DiskNumber $diskNum -PartitionNumber $winpePart.PartitionNumber -AccessPath "$($winpePart.DriveLetter):" -ErrorAction SilentlyContinue } catch {}
|
try { Remove-PartitionAccessPath -DiskNumber $diskNum -PartitionNumber $winpePart.PartitionNumber -AccessPath "$($winpePart.DriveLetter):" -ErrorAction SilentlyContinue } catch {}
|
||||||
$usbLetter = Get-FreeDriveLetter
|
$usbLetter = Get-FreeDriveLetter
|
||||||
if (-not $usbLetter) { throw "No free drive letters (D-Z) available to assign to the USB data partition." }
|
if (-not $usbLetter) { throw "No free drive letters (D-Z) available to assign to the USB data partition." }
|
||||||
@@ -188,49 +185,30 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
Start-Sleep -Seconds 2
|
Start-Sleep -Seconds 2
|
||||||
|
|
||||||
$usbDrive = "${usbLetter}:"
|
$usbDrive = "${usbLetter}:"
|
||||||
$retries = 0
|
if (-not (Test-Path $usbDrive)) {
|
||||||
while (-not (Test-Path $usbDrive) -and $retries -lt 6) {
|
throw "Drive $usbDrive is not accessible after letter assignment."
|
||||||
$retries++
|
|
||||||
Log "Waiting for $usbDrive to become accessible (attempt $retries/6)..."
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
}
|
}
|
||||||
if (-not (Test-Path $usbDrive)) { throw "Drive $usbDrive is not accessible after letter assignment." }
|
|
||||||
Log "USB data partition: $usbDrive"
|
Log "USB data partition: $usbDrive"
|
||||||
|
|
||||||
$contentSizeBytes = (Get-ChildItem -LiteralPath $contentsDir -File -Recurse -Force -ErrorAction Stop | Measure-Object -Property Length -Sum).Sum
|
|
||||||
if (-not $contentSizeBytes) { $contentSizeBytes = 0 }
|
|
||||||
$usbVolume = Get-Volume -DriveLetter $usbLetter -ErrorAction Stop
|
|
||||||
$partitionCapacityBytes = [int64]$usbVolume.Size
|
|
||||||
$partitionFreeBytes = [int64]$usbVolume.SizeRemaining
|
|
||||||
|
|
||||||
$contentSizeGB = [math]::Round($contentSizeBytes / 1GB, 2)
|
|
||||||
$partitionCapacityGB = [math]::Round($partitionCapacityBytes / 1GB, 2)
|
|
||||||
$partitionFreeGB = [math]::Round($partitionFreeBytes / 1GB, 2)
|
|
||||||
|
|
||||||
Log "Source content size: $contentSizeGB GB. USB partition capacity: $partitionCapacityGB GB, free: $partitionFreeGB GB."
|
|
||||||
|
|
||||||
if ($contentSizeBytes -gt $partitionCapacityBytes) {
|
|
||||||
throw "ISO content ($contentSizeGB GB) is larger than the USB partition capacity ($partitionCapacityGB GB). Use a larger USB drive or reduce image size."
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($contentSizeBytes -gt $partitionFreeBytes) {
|
|
||||||
throw "Insufficient free space on USB partition. Required: $contentSizeGB GB, available: $partitionFreeGB GB."
|
|
||||||
}
|
|
||||||
|
|
||||||
SetProgress "Copying Windows 11 files to USB..." 45
|
SetProgress "Copying Windows 11 files to USB..." 45
|
||||||
|
|
||||||
# Copy files; split install.wim if > 4 GB (FAT32 limit)
|
# ── Copy files (split large install.wim if > 4 GB for FAT32) ──
|
||||||
$installWim = Join-Path $contentsDir "sources\install.wim"
|
$installWim = Join-Path $contentsDir "sources\install.wim"
|
||||||
if (Test-Path $installWim) {
|
if (Test-Path $installWim) {
|
||||||
$wimSizeMB = [math]::Round((Get-Item $installWim).Length / 1MB)
|
$wimSizeMB = [math]::Round((Get-Item $installWim).Length / 1MB)
|
||||||
if ($wimSizeMB -gt 3800) {
|
if ($wimSizeMB -gt 3800) {
|
||||||
Log "install.wim is $wimSizeMB MB - splitting for FAT32 compatibility... This will take several minutes."
|
# FAT32 limit – split with DISM
|
||||||
|
Log "install.wim is $wimSizeMB MB - splitting for FAT32 compatibility...This will take several minutes."
|
||||||
$splitDest = Join-Path $usbDrive "sources\install.swm"
|
$splitDest = Join-Path $usbDrive "sources\install.swm"
|
||||||
New-Item -ItemType Directory -Path (Split-Path $splitDest) -Force | Out-Null
|
New-Item -ItemType Directory -Path (Split-Path $splitDest) -Force | Out-Null
|
||||||
Split-WindowsImage -ImagePath $installWim -SplitImagePath $splitDest -FileSize 3800 -CheckIntegrity
|
Split-WindowsImage -ImagePath $installWim `
|
||||||
|
-SplitImagePath $splitDest `
|
||||||
|
-FileSize 3800 -CheckIntegrity
|
||||||
Log "install.wim split complete."
|
Log "install.wim split complete."
|
||||||
|
|
||||||
|
# Copy everything else (exclude install.wim)
|
||||||
Log "Copying remaining files to USB..."
|
Log "Copying remaining files to USB..."
|
||||||
& robocopy $contentsDir $usbDrive /E /XF install.wim /NFL /NDL /NJH /NJS
|
$robocopyArgs = @($contentsDir, $usbDrive, "/E", "/XF", "install.wim", "/NFL", "/NDL", "/NJH", "/NJS")
|
||||||
|
& robocopy @robocopyArgs
|
||||||
} else {
|
} else {
|
||||||
& robocopy $contentsDir $usbDrive /E /NFL /NDL /NJH /NJS
|
& robocopy $contentsDir $usbDrive /E /NFL /NDL /NJH /NJS
|
||||||
}
|
}
|
||||||
@@ -240,6 +218,7 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
|
|
||||||
SetProgress "Finalising USB drive..." 90
|
SetProgress "Finalising USB drive..." 90
|
||||||
Log "Files copied to USB."
|
Log "Files copied to USB."
|
||||||
|
|
||||||
SetProgress "USB write complete" 100
|
SetProgress "USB write complete" 100
|
||||||
Log "USB drive is ready for use."
|
Log "USB drive is ready for use."
|
||||||
|
|
||||||
@@ -248,17 +227,21 @@ function Invoke-WinUtilISOWriteUSB {
|
|||||||
"USB drive created successfully!`n`nYou can now boot from this drive to install Windows 11.",
|
"USB drive created successfully!`n`nYou can now boot from this drive to install Windows 11.",
|
||||||
"USB Ready", "OK", "Info")
|
"USB Ready", "OK", "Info")
|
||||||
})
|
})
|
||||||
} catch {
|
}
|
||||||
|
catch {
|
||||||
Log "ERROR during USB write: $_"
|
Log "ERROR during USB write: $_"
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
[System.Windows.MessageBox]::Show("USB write failed:`n`n$_", "USB Write Error", "OK", "Error")
|
[System.Windows.MessageBox]::Show(
|
||||||
|
"USB write failed:`n`n$_",
|
||||||
|
"USB Write Error", "OK", "Error")
|
||||||
})
|
})
|
||||||
} finally {
|
}
|
||||||
|
finally {
|
||||||
Start-Sleep -Milliseconds 800
|
Start-Sleep -Milliseconds 800
|
||||||
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
|
||||||
$sync.progressBarTextBlock.Text = ""
|
$sync.progressBarTextBlock.Text = ""
|
||||||
$sync.progressBarTextBlock.ToolTip = ""
|
$sync.progressBarTextBlock.ToolTip = ""
|
||||||
$sync.ProgressBar.Value = 0
|
$sync.ProgressBar.Value = 0
|
||||||
$sync["WPFWin11ISOWriteUSBButton"].IsEnabled = $true
|
$sync["WPFWin11ISOWriteUSBButton"].IsEnabled = $true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,35 +25,20 @@ function Invoke-WinUtilScript {
|
|||||||
Invoke-Command $scriptblock -ErrorAction Stop
|
Invoke-Command $scriptblock -ErrorAction Stop
|
||||||
} catch [System.Management.Automation.CommandNotFoundException] {
|
} catch [System.Management.Automation.CommandNotFoundException] {
|
||||||
Write-Warning "The specified command was not found."
|
Write-Warning "The specified command was not found."
|
||||||
if ($_.Exception -and -not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
Write-Warning $PSItem.Exception.message
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
} catch [System.Management.Automation.RuntimeException] {
|
} catch [System.Management.Automation.RuntimeException] {
|
||||||
Write-Warning "A runtime exception occurred."
|
Write-Warning "A runtime exception occurred."
|
||||||
if ($_.Exception -and -not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
Write-Warning $PSItem.Exception.message
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
} catch [System.Security.SecurityException] {
|
} catch [System.Security.SecurityException] {
|
||||||
Write-Warning "A security exception occurred."
|
Write-Warning "A security exception occurred."
|
||||||
if ($_.Exception -and -not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
Write-Warning $PSItem.Exception.message
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
} catch [System.UnauthorizedAccessException] {
|
} catch [System.UnauthorizedAccessException] {
|
||||||
Write-Warning "Access denied. You do not have permission to perform this operation."
|
Write-Warning "Access denied. You do not have permission to perform this operation."
|
||||||
if ($_.Exception -and -not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
Write-Warning $PSItem.Exception.message
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
# Generic catch block to handle any other type of exception
|
# Generic catch block to handle any other type of exception
|
||||||
Write-Warning "Unable to run script for $name due to unhandled exception"
|
Write-Warning "Unable to run script for $name due to unhandled exception"
|
||||||
if ($_.Exception) {
|
Write-Warning $psitem.Exception.StackTrace
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.StackTrace)) {
|
|
||||||
Write-Warning $_.Exception.StackTrace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,20 @@ function Invoke-WinutilThemeChange {
|
|||||||
modifying various UI elements such as colors, margins, corner radii, font families, etc.
|
modifying various UI elements such as colors, margins, corner radii, font families, etc.
|
||||||
If the '-init' switch is used, it initializes the theme based on the system's current dark mode setting.
|
If the '-init' switch is used, it initializes the theme based on the system's current dark mode setting.
|
||||||
|
|
||||||
|
.PARAMETER init
|
||||||
|
A switch parameter. If set to $true, the function initializes the theme based on the system’s current dark mode setting.
|
||||||
|
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Invoke-WinutilThemeChange
|
Invoke-WinutilThemeChange
|
||||||
# Toggles the theme between 'Light' and 'Dark'.
|
# Toggles the theme between 'Light' and 'Dark'.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
Invoke-WinutilThemeChange -init
|
||||||
|
# Initializes the theme based on the system's dark mode and applies the shared theme.
|
||||||
#>
|
#>
|
||||||
param (
|
param (
|
||||||
[string]$theme = "Auto"
|
[switch]$init = $false,
|
||||||
|
[string]$theme
|
||||||
)
|
)
|
||||||
|
|
||||||
function Set-WinutilTheme {
|
function Set-WinutilTheme {
|
||||||
@@ -123,30 +129,48 @@ function Invoke-WinutilThemeChange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sync.preferences.theme = $theme
|
$LightPreferencePath = "$winutildir\LightTheme.ini"
|
||||||
Set-Preferences -save
|
$DarkPreferencePath = "$winutildir\DarkTheme.ini"
|
||||||
Set-WinutilTheme -currentTheme "shared"
|
|
||||||
|
|
||||||
switch ($sync.preferences.theme) {
|
if ($init) {
|
||||||
|
Set-WinutilTheme -currentTheme "shared"
|
||||||
|
if (Test-Path $LightPreferencePath) {
|
||||||
|
$theme = "Light"
|
||||||
|
}
|
||||||
|
elseif (Test-Path $DarkPreferencePath) {
|
||||||
|
$theme = "Dark"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$theme = "Auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($theme) {
|
||||||
"Auto" {
|
"Auto" {
|
||||||
$systemUsesDarkMode = Get-WinUtilToggleStatus WPFToggleDarkMode
|
$systemUsesDarkMode = Get-WinUtilToggleStatus WPFToggleDarkMode
|
||||||
if ($systemUsesDarkMode) {
|
if ($systemUsesDarkMode) {
|
||||||
$theme = "Dark"
|
Set-WinutilTheme -currentTheme "Dark"
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$theme = "Light"
|
Set-WinutilTheme -currentTheme "Light"
|
||||||
}
|
}
|
||||||
|
|
||||||
Set-WinutilTheme -currentTheme $theme
|
|
||||||
$themeButtonIcon = [char]0xF08C
|
$themeButtonIcon = [char]0xF08C
|
||||||
|
Remove-Item $LightPreferencePath -Force -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item $DarkPreferencePath -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
"Dark" {
|
"Dark" {
|
||||||
Set-WinutilTheme -currentTheme $sync.preferences.theme
|
Set-WinutilTheme -currentTheme $theme
|
||||||
$themeButtonIcon = [char]0xE708
|
$themeButtonIcon = [char]0xE708
|
||||||
|
$null = New-Item $DarkPreferencePath -Force
|
||||||
|
Remove-Item $LightPreferencePath -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
"Light" {
|
"Light" {
|
||||||
Set-WinutilTheme -currentTheme $sync.preferences.theme
|
Set-WinutilTheme -currentTheme $theme
|
||||||
$themeButtonIcon = [char]0xE706
|
$themeButtonIcon = [char]0xE706
|
||||||
|
$null = New-Item $LightPreferencePath -Force
|
||||||
|
Remove-Item $DarkPreferencePath -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
43
functions/private/Set-PackageManagerPreference.ps1
Normal file
43
functions/private/Set-PackageManagerPreference.ps1
Normal 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 preferredPackageManager
|
||||||
|
The PackageManager that was selected.
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Position=0, Mandatory=$false)]
|
||||||
|
[PackageManagers]$preferredPackageManager
|
||||||
|
)
|
||||||
|
|
||||||
|
$preferencePath = "$winutildir\preferences.ini"
|
||||||
|
$oldChocoPath = "$winutildir\preferChocolatey.ini"
|
||||||
|
|
||||||
|
#Try loading from file if no argument given.
|
||||||
|
if ($null -eq $preferredPackageManager) {
|
||||||
|
# Backwards compat for preferChocolatey.ini
|
||||||
|
if (Test-Path -Path $oldChocoPath) {
|
||||||
|
$preferredPackageManager = [PackageManagers]::Choco
|
||||||
|
Remove-Item -Path $oldChocoPath
|
||||||
|
}
|
||||||
|
elseif (Test-Path -Path $preferencePath) {
|
||||||
|
$potential = Get-Content -Path $preferencePath -TotalCount 1
|
||||||
|
$preferredPackageManager = [PackageManagers]$potential
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Debug "Creating new preference file, defaulting to winget."
|
||||||
|
$preferredPackageManager = [PackageManagers]::Winget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sync["ManagerPreference"] = [PackageManagers]::$preferredPackageManager
|
||||||
|
Write-Debug "Manager Preference changed to '$($sync["ManagerPreference"])'"
|
||||||
|
|
||||||
|
|
||||||
|
# Write preference to file to persist across restarts.
|
||||||
|
Out-File -FilePath $preferencePath -InputObject $sync["ManagerPreference"]
|
||||||
|
}
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
function Set-Preferences{
|
|
||||||
|
|
||||||
param(
|
|
||||||
[switch]$save=$false
|
|
||||||
)
|
|
||||||
|
|
||||||
# TODO delete this function sometime later
|
|
||||||
function Clean-OldPrefs{
|
|
||||||
if (Test-Path -Path "$winutildir\LightTheme.ini") {
|
|
||||||
$sync.preferences.theme = "Light"
|
|
||||||
Remove-Item -Path "$winutildir\LightTheme.ini"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Test-Path -Path "$winutildir\DarkTheme.ini") {
|
|
||||||
$sync.preferences.theme = "Dark"
|
|
||||||
Remove-Item -Path "$winutildir\DarkTheme.ini"
|
|
||||||
}
|
|
||||||
|
|
||||||
# check old prefs, if its first line has no =, then absorb it as pm
|
|
||||||
if (Test-Path -Path $iniPath) {
|
|
||||||
$oldPM = Get-Content $iniPath
|
|
||||||
if ($oldPM -notlike "*=*") {
|
|
||||||
$sync.preferences.packagemanager = $oldPM
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Test-Path -Path "$winutildir\preferChocolatey.ini") {
|
|
||||||
$sync.preferences.packagemanager = "Choco"
|
|
||||||
Remove-Item -Path "$winutildir\preferChocolatey.ini"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Save-Preferences{
|
|
||||||
$ini = ""
|
|
||||||
foreach($key in $sync.preferences.Keys) {
|
|
||||||
$pref = "$($key)=$($sync.preferences.$key)"
|
|
||||||
Write-Debug "Saving pref: $($pref)"
|
|
||||||
$ini = $ini + $pref + "`r`n"
|
|
||||||
}
|
|
||||||
$ini | Out-File $iniPath
|
|
||||||
}
|
|
||||||
|
|
||||||
function Load-Preferences{
|
|
||||||
Clean-OldPrefs
|
|
||||||
if (Test-Path -Path $iniPath) {
|
|
||||||
$iniData = Get-Content "$winutildir\preferences.ini"
|
|
||||||
foreach ($line in $iniData) {
|
|
||||||
if ($line -like "*=*") {
|
|
||||||
$arr = $line -split "=",-2
|
|
||||||
$key = $arr[0] -replace "\s",""
|
|
||||||
$value = $arr[1] -replace "\s",""
|
|
||||||
Write-Debug "Preference: Key = '$($key)' Value ='$($value)'"
|
|
||||||
$sync.preferences.$key = $value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# write defaults in case preferences dont exist
|
|
||||||
if ($null -eq $sync.preferences.theme) {
|
|
||||||
$sync.preferences.theme = "Auto"
|
|
||||||
}
|
|
||||||
if ($null -eq $sync.preferences.packagemanager) {
|
|
||||||
$sync.preferences.packagemanager = "Winget"
|
|
||||||
}
|
|
||||||
|
|
||||||
# convert packagemanager to enum
|
|
||||||
if ($sync.preferences.packagemanager -eq "Choco") {
|
|
||||||
$sync.preferences.packagemanager = [PackageManagers]::Choco
|
|
||||||
}
|
|
||||||
elseif ($sync.preferences.packagemanager -eq "Winget") {
|
|
||||||
$sync.preferences.packagemanager = [PackageManagers]::Winget
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$iniPath = "$winutildir\preferences.ini"
|
|
||||||
|
|
||||||
if ($save) {
|
|
||||||
Save-Preferences
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Load-Preferences
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -28,13 +28,6 @@ function Set-WinUtilDNS {
|
|||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Write-Warning "Unable to set DNS Provider due to an unhandled exception"
|
Write-Warning "Unable to set DNS Provider due to an unhandled exception"
|
||||||
if ($_.Exception) {
|
Write-Warning $psitem.Exception.StackTrace
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.StackTrace)) {
|
|
||||||
Write-Warning $_.Exception.StackTrace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,22 +46,11 @@ function Set-WinUtilRegistry {
|
|||||||
} catch [System.Security.SecurityException] {
|
} catch [System.Security.SecurityException] {
|
||||||
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
|
Write-Warning "Unable to set $Path\$Name to $Value due to a Security Exception"
|
||||||
} catch [System.Management.Automation.ItemNotFoundException] {
|
} catch [System.Management.Automation.ItemNotFoundException] {
|
||||||
Write-Warning $_.Exception.ErrorRecord
|
Write-Warning $psitem.Exception.ErrorRecord
|
||||||
} catch [System.UnauthorizedAccessException] {
|
} catch [System.UnauthorizedAccessException] {
|
||||||
if ($_.Exception -and -not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
Write-Warning $psitem.Exception.Message
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
} else {
|
|
||||||
Write-Warning "Unauthorized access while setting $Path\$Name"
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
Write-Warning "Unable to set $Name due to unhandled exception"
|
Write-Warning "Unable to set $Name due to unhandled exception"
|
||||||
if ($_.Exception) {
|
Write-Warning $psitem.Exception.StackTrace
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.StackTrace)) {
|
|
||||||
Write-Warning $_.Exception.StackTrace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,23 +29,14 @@ function Set-WinUtilScheduledTask {
|
|||||||
Enable-ScheduledTask -TaskName $Name -ErrorAction Stop
|
Enable-ScheduledTask -TaskName $Name -ErrorAction Stop
|
||||||
}
|
}
|
||||||
} catch [System.Exception] {
|
} catch [System.Exception] {
|
||||||
if ($_.Exception -and $_.Exception.Message -like "*The system cannot find the file specified*") {
|
if($psitem.Exception.Message -like "*The system cannot find the file specified*") {
|
||||||
Write-Warning "Scheduled Task $name was not Found"
|
Write-Warning "Scheduled Task $name was not Found"
|
||||||
} else {
|
} else {
|
||||||
Write-Warning "Unable to set $Name due to unhandled exception"
|
Write-Warning "Unable to set $Name due to unhandled exception"
|
||||||
if ($_.Exception -and -not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
Write-Warning $psitem.Exception.Message
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Write-Warning "Unable to run script for $name due to unhandled exception"
|
Write-Warning "Unable to run script for $name due to unhandled exception"
|
||||||
if ($_.Exception) {
|
Write-Warning $psitem.Exception.StackTrace
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.StackTrace)) {
|
|
||||||
Write-Warning $_.Exception.StackTrace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,7 @@ Function Set-WinUtilService {
|
|||||||
Write-Warning "Service $Name was not found"
|
Write-Warning "Service $Name was not found"
|
||||||
} catch {
|
} catch {
|
||||||
Write-Warning "Unable to set $Name due to unhandled exception"
|
Write-Warning "Unable to set $Name due to unhandled exception"
|
||||||
if ($_.Exception) {
|
Write-Warning $_.Exception.Message
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.Message)) {
|
|
||||||
Write-Warning $_.Exception.Message
|
|
||||||
}
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($_.Exception.StackTrace)) {
|
|
||||||
Write-Warning $_.Exception.StackTrace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
26
functions/private/Test-WinUtilInternetConnection.ps1
Normal file
26
functions/private/Test-WinUtilInternetConnection.ps1
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
function Test-WinUtilInternetConnection {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Tests if the computer has internet connectivity
|
||||||
|
.OUTPUTS
|
||||||
|
Boolean - True if connected, False if offline
|
||||||
|
#>
|
||||||
|
try {
|
||||||
|
# Test multiple reliable endpoints
|
||||||
|
$testSites = @(
|
||||||
|
"8.8.8.8", # Google DNS
|
||||||
|
"1.1.1.1", # Cloudflare DNS
|
||||||
|
"208.67.222.222" # OpenDNS
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($site in $testSites) {
|
||||||
|
if (Test-Connection -ComputerName $site -Count 1 -Quiet -ErrorAction SilentlyContinue) {
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,9 +14,7 @@ function Update-WinUtilSelections {
|
|||||||
|
|
||||||
Write-Debug "JSON to import: $($flatJson)"
|
Write-Debug "JSON to import: $($flatJson)"
|
||||||
|
|
||||||
foreach ($item in $flatJson) {
|
foreach ($cbkey in $flatJson) {
|
||||||
# Ensure each item is treated as a string to handle PSCustomObject from JSON deserialization
|
|
||||||
$cbkey = [string]$item
|
|
||||||
$group = if ($cbkey.StartsWith("WPFInstall")) { "Install" }
|
$group = if ($cbkey.StartsWith("WPFInstall")) { "Install" }
|
||||||
elseif ($cbkey.StartsWith("WPFTweaks")) { "Tweaks" }
|
elseif ($cbkey.StartsWith("WPFTweaks")) { "Tweaks" }
|
||||||
elseif ($cbkey.StartsWith("WPFToggle")) { "Toggle" }
|
elseif ($cbkey.StartsWith("WPFToggle")) { "Toggle" }
|
||||||
@@ -28,7 +26,7 @@ function Update-WinUtilSelections {
|
|||||||
if (!$sync.selectedApps.Contains($cbkey)) {
|
if (!$sync.selectedApps.Contains($cbkey)) {
|
||||||
$sync.selectedApps.Add($cbkey)
|
$sync.selectedApps.Add($cbkey)
|
||||||
# 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
|
# 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[string]]$sync.selectedApps = $sync.SelectedApps | Sort-Object
|
[System.Collections.Generic.List[pscustomobject]]$sync.selectedApps = $sync.SelectedApps | Sort-Object
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"Tweaks" {
|
"Tweaks" {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ function Invoke-WPFFixesWinget {
|
|||||||
try {
|
try {
|
||||||
Set-WinUtilTaskbaritem -state "Indeterminate" -overlay "logo"
|
Set-WinUtilTaskbaritem -state "Indeterminate" -overlay "logo"
|
||||||
Write-Host "==> Starting Winget Repair"
|
Write-Host "==> Starting Winget Repair"
|
||||||
Install-WinUtilWinget
|
Install-WinUtilWinget -Force
|
||||||
} catch {
|
} catch {
|
||||||
Write-Error "Failed to install winget: $_"
|
Write-Error "Failed to install winget: $_"
|
||||||
Set-WinUtilTaskbaritem -state "Error" -overlay "warning"
|
Set-WinUtilTaskbaritem -state "Error" -overlay "warning"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ function Invoke-WPFGetInstalled {
|
|||||||
if (($sync.ChocoRadioButton.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
|
return
|
||||||
}
|
}
|
||||||
$managerPreference = $sync.preferences.packagemanager
|
$managerPreference = $sync["ManagerPreference"]
|
||||||
|
|
||||||
Invoke-WPFRunspace -ParameterList @(("managerPreference", $managerPreference),("checkbox", $checkbox)) -ScriptBlock {
|
Invoke-WPFRunspace -ParameterList @(("managerPreference", $managerPreference),("checkbox", $checkbox)) -ScriptBlock {
|
||||||
param (
|
param (
|
||||||
|
|||||||
@@ -44,13 +44,7 @@ function Invoke-WPFImpex {
|
|||||||
try {
|
try {
|
||||||
$Config = ConfigDialog
|
$Config = ConfigDialog
|
||||||
if ($Config) {
|
if ($Config) {
|
||||||
$allConfs = ($sync.selectedApps + $sync.selectedTweaks + $sync.selectedToggles + $sync.selectedFeatures) | ForEach-Object { [string]$_ }
|
$allConfs = $sync.selectedApps + $sync.selectedTweaks + $sync.selectedToggles + $sync.selectedFeatures
|
||||||
if (-not $allConfs) {
|
|
||||||
[System.Windows.MessageBox]::Show(
|
|
||||||
"No settings are selected to export. Please select at least one app, tweak, toggle, or feature before exporting.",
|
|
||||||
"Nothing to Export", "OK", "Warning")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
$jsonFile = $allConfs | ConvertTo-Json
|
$jsonFile = $allConfs | ConvertTo-Json
|
||||||
$jsonFile | Out-File $Config -Force
|
$jsonFile | Out-File $Config -Force
|
||||||
"iex ""& { `$(irm https://christitus.com/win) } -Config '$Config'""" | Set-Clipboard
|
"iex ""& { `$(irm https://christitus.com/win) } -Config '$Config'""" | Set-Clipboard
|
||||||
@@ -76,21 +70,6 @@ function Invoke-WPFImpex {
|
|||||||
# TODO how to handle old style? detected json type then flatten it in a func?
|
# TODO how to handle old style? detected json type then flatten it in a func?
|
||||||
# $flattenedJson = $jsonFile.PSObject.Properties.Where({ $_.Name -ne "Install" }).ForEach({ $_.Value })
|
# $flattenedJson = $jsonFile.PSObject.Properties.Where({ $_.Name -ne "Install" }).ForEach({ $_.Value })
|
||||||
$flattenedJson = $jsonFile
|
$flattenedJson = $jsonFile
|
||||||
|
|
||||||
if (-not $flattenedJson) {
|
|
||||||
[System.Windows.MessageBox]::Show(
|
|
||||||
"The selected file contains no settings to import. No changes have been made.",
|
|
||||||
"Empty Configuration", "OK", "Warning")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
# Clear all existing selections before importing so the import replaces
|
|
||||||
# the current state rather than merging with it
|
|
||||||
$sync.selectedApps = [System.Collections.Generic.List[string]]::new()
|
|
||||||
$sync.selectedTweaks = [System.Collections.Generic.List[string]]::new()
|
|
||||||
$sync.selectedToggles = [System.Collections.Generic.List[string]]::new()
|
|
||||||
$sync.selectedFeatures = [System.Collections.Generic.List[string]]::new()
|
|
||||||
|
|
||||||
Update-WinUtilSelections -flatJson $flattenedJson
|
Update-WinUtilSelections -flatJson $flattenedJson
|
||||||
|
|
||||||
if (!$PARAM_NOUI) {
|
if (!$PARAM_NOUI) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ function Invoke-WPFInstall {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
$ManagerPreference = $sync.preferences.packagemanager
|
$ManagerPreference = $sync["ManagerPreference"]
|
||||||
|
|
||||||
$handle = Invoke-WPFRunspace -ParameterList @(("PackagesToInstall", $PackagesToInstall),("ManagerPreference", $ManagerPreference)) -ScriptBlock {
|
$handle = Invoke-WPFRunspace -ParameterList @(("PackagesToInstall", $PackagesToInstall),("ManagerPreference", $ManagerPreference)) -ScriptBlock {
|
||||||
param($PackagesToInstall, $ManagerPreference)
|
param($PackagesToInstall, $ManagerPreference)
|
||||||
|
|||||||
@@ -32,17 +32,17 @@ function Invoke-WPFPresets {
|
|||||||
$CheckBoxesToCheck = $sync.configs.preset.$preset
|
$CheckBoxesToCheck = $sync.configs.preset.$preset
|
||||||
}
|
}
|
||||||
|
|
||||||
# clear out the filtered pattern so applying a preset replaces the current
|
# clear out the filtered pattern
|
||||||
# state rather than merging with it
|
if (!$preset) {
|
||||||
switch ($checkboxfilterpattern) {
|
switch ($checkboxfilterpattern) {
|
||||||
"WPFTweak*" { $sync.selectedTweaks = [System.Collections.Generic.List[string]]::new() }
|
"WPFTweak*" { $sync.selectedTweaks = [System.Collections.Generic.List[string]]::new() }
|
||||||
"WPFInstall*" { $sync.selectedApps = [System.Collections.Generic.List[string]]::new() }
|
"WPFInstall*" { $sync.selectedApps = [System.Collections.Generic.List[string]]::new() }
|
||||||
"WPFeatures" { $sync.selectedFeatures = [System.Collections.Generic.List[string]]::new() }
|
"WPFeatures" { $sync.selectedFeatures = [System.Collections.Generic.List[string]]::new() }
|
||||||
"WPFToggle" { $sync.selectedToggles = [System.Collections.Generic.List[string]]::new() }
|
"WPFToggle" { $sync.selectedToggles = [System.Collections.Generic.List[string]]::new() }
|
||||||
default {}
|
default {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if ($preset) {
|
|
||||||
Update-WinUtilSelections -flatJson $CheckBoxesToCheck
|
Update-WinUtilSelections -flatJson $CheckBoxesToCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ function Invoke-WPFSelectedCheckboxesUpdate{
|
|||||||
if (!$sync.selectedApps.Contains($appKey)) {
|
if (!$sync.selectedApps.Contains($appKey)) {
|
||||||
$sync.selectedApps.Add($appKey)
|
$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
|
# 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[string]]$sync.selectedApps = $sync.SelectedApps | Sort-Object
|
[System.Collections.Generic.List[pscustomobject]]$sync.selectedApps = $sync.SelectedApps | Sort-Object
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function Invoke-WPFUnInstall {
|
|||||||
|
|
||||||
if($confirm -eq "No") {return}
|
if($confirm -eq "No") {return}
|
||||||
|
|
||||||
$ManagerPreference = $sync.preferences.packagemanager
|
$ManagerPreference = $sync["ManagerPreference"]
|
||||||
|
|
||||||
Invoke-WPFRunspace -ParameterList @(("PackagesToUninstall", $PackagesToUninstall),("ManagerPreference", $ManagerPreference)) -ScriptBlock {
|
Invoke-WPFRunspace -ParameterList @(("PackagesToUninstall", $PackagesToUninstall),("ManagerPreference", $ManagerPreference)) -ScriptBlock {
|
||||||
param($PackagesToUninstall, $ManagerPreference)
|
param($PackagesToUninstall, $ManagerPreference)
|
||||||
|
|||||||
@@ -15,14 +15,12 @@ $maxthreads = [int]$env:NUMBER_OF_PROCESSORS
|
|||||||
$hashVars = New-object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'sync',$sync,$Null
|
$hashVars = New-object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'sync',$sync,$Null
|
||||||
$debugVar = New-object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'DebugPreference',$DebugPreference,$Null
|
$debugVar = New-object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'DebugPreference',$DebugPreference,$Null
|
||||||
$uiVar = New-object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'PARAM_NOUI',$PARAM_NOUI,$Null
|
$uiVar = New-object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'PARAM_NOUI',$PARAM_NOUI,$Null
|
||||||
$offlineVar = New-object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'PARAM_OFFLINE',$PARAM_OFFLINE,$Null
|
|
||||||
$InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
|
$InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
|
||||||
|
|
||||||
# Add the variable to the session state
|
# Add the variable to the session state
|
||||||
$InitialSessionState.Variables.Add($hashVars)
|
$InitialSessionState.Variables.Add($hashVars)
|
||||||
$InitialSessionState.Variables.Add($debugVar)
|
$InitialSessionState.Variables.Add($debugVar)
|
||||||
$InitialSessionState.Variables.Add($uiVar)
|
$InitialSessionState.Variables.Add($uiVar)
|
||||||
$InitialSessionState.Variables.Add($offlineVar)
|
|
||||||
|
|
||||||
# Get every private function and add them to the session state
|
# Get every private function and add them to the session state
|
||||||
$functions = Get-ChildItem function:\ | Where-Object { $_.Name -imatch 'winutil|WPF' }
|
$functions = Get-ChildItem function:\ | Where-Object { $_.Name -imatch 'winutil|WPF' }
|
||||||
@@ -68,7 +66,7 @@ $sync.configs.applications.PSObject.Properties | ForEach-Object {
|
|||||||
$sync.configs.applicationsHashtable[$_.Name] = $_.Value
|
$sync.configs.applicationsHashtable[$_.Name] = $_.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
Set-Preferences
|
Set-PackageManagerPreference
|
||||||
|
|
||||||
if ($PARAM_NOUI) {
|
if ($PARAM_NOUI) {
|
||||||
Show-CTTLogo
|
Show-CTTLogo
|
||||||
@@ -156,7 +154,7 @@ $sync.Form.Add_Loaded({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Invoke-WinutilThemeChange -theme $sync.preferences.theme
|
Invoke-WinutilThemeChange -init $true
|
||||||
|
|
||||||
|
|
||||||
# Now call the function with the final merged config
|
# Now call the function with the final merged config
|
||||||
@@ -179,16 +177,10 @@ Invoke-WPFUIElements -configVariable $sync.configs.feature -targetGridName "feat
|
|||||||
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {$sync["$("$($psitem.Name)")"] = $sync["Form"].FindName($psitem.Name)}
|
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {$sync["$("$($psitem.Name)")"] = $sync["Form"].FindName($psitem.Name)}
|
||||||
|
|
||||||
#Persist Package Manager preference across winutil restarts
|
#Persist Package Manager preference across winutil restarts
|
||||||
$sync.ChocoRadioButton.Add_Checked({
|
$sync.ChocoRadioButton.Add_Checked({Set-PackageManagerPreference Choco})
|
||||||
$sync.preferences.packagemanager = [PackageManagers]::Choco
|
$sync.WingetRadioButton.Add_Checked({Set-PackageManagerPreference Winget})
|
||||||
Set-Preferences -save
|
|
||||||
})
|
|
||||||
$sync.WingetRadioButton.Add_Checked({
|
|
||||||
$sync.preferences.packagemanager = [PackageManagers]::Winget
|
|
||||||
Set-Preferences -save
|
|
||||||
})
|
|
||||||
|
|
||||||
switch ($sync.preferences.packagemanager) {
|
switch ($sync["ManagerPreference"]) {
|
||||||
"Choco" {$sync.ChocoRadioButton.IsChecked = $true; break}
|
"Choco" {$sync.ChocoRadioButton.IsChecked = $true; break}
|
||||||
"Winget" {$sync.WingetRadioButton.IsChecked = $true; break}
|
"Winget" {$sync.WingetRadioButton.IsChecked = $true; break}
|
||||||
}
|
}
|
||||||
@@ -352,10 +344,11 @@ $sync["Form"].Add_ContentRendered({
|
|||||||
Write-Debug "Unable to retrieve information about the primary monitor."
|
Write-Debug "Unable to retrieve information about the primary monitor."
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($PARAM_OFFLINE) {
|
# Check internet connectivity and disable install tab if offline
|
||||||
# Show offline banner
|
#$isOnline = Test-WinUtilInternetConnection
|
||||||
$sync.WPFOfflineBanner.Visibility = [System.Windows.Visibility]::Visible
|
$isOnline = $true # Temporarily force online mode until we can resolve false negatives
|
||||||
|
|
||||||
|
if (-not $isOnline) {
|
||||||
# Disable the install tab
|
# Disable the install tab
|
||||||
$sync.WPFTab1BT.IsEnabled = $false
|
$sync.WPFTab1BT.IsEnabled = $false
|
||||||
$sync.WPFTab1BT.Opacity = 0.5
|
$sync.WPFTab1BT.Opacity = 0.5
|
||||||
@@ -542,7 +535,10 @@ $sync["FontScalingApplyButton"].Add_Click({
|
|||||||
# ── Win11ISO Tab button handlers ──────────────────────────────────────────────
|
# ── Win11ISO Tab button handlers ──────────────────────────────────────────────
|
||||||
|
|
||||||
$sync["WPFTab5BT"].Add_Click({
|
$sync["WPFTab5BT"].Add_Click({
|
||||||
$sync["Form"].Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{ Invoke-WinUtilISOCheckExistingWork }) | Out-Null
|
$sync["Form"].Dispatcher.BeginInvoke(
|
||||||
|
[System.Windows.Threading.DispatcherPriority]::Background,
|
||||||
|
[action]{ Invoke-WinUtilISOCheckExistingWork }
|
||||||
|
) | Out-Null
|
||||||
})
|
})
|
||||||
|
|
||||||
$sync["WPFWin11ISOBrowseButton"].Add_Click({
|
$sync["WPFWin11ISOBrowseButton"].Add_Click({
|
||||||
|
|||||||
@@ -9,8 +9,7 @@
|
|||||||
param (
|
param (
|
||||||
[string]$Config,
|
[string]$Config,
|
||||||
[switch]$Run,
|
[switch]$Run,
|
||||||
[switch]$Noui,
|
[switch]$Noui
|
||||||
[switch]$Offline
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if ($Config) {
|
if ($Config) {
|
||||||
@@ -28,10 +27,24 @@ if ($Noui) {
|
|||||||
$PARAM_NOUI = $true
|
$PARAM_NOUI = $true
|
||||||
}
|
}
|
||||||
|
|
||||||
$PARAM_OFFLINE = $false
|
# Load DLLs
|
||||||
if ($Offline) {
|
Add-Type -AssemblyName PresentationFramework
|
||||||
$PARAM_OFFLINE = $true
|
Add-Type -AssemblyName System.Windows.Forms
|
||||||
}
|
|
||||||
|
# Variable to sync between runspaces
|
||||||
|
$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.selectedTweaks = [System.Collections.Generic.List[string]]::new()
|
||||||
|
$sync.selectedToggles = [System.Collections.Generic.List[string]]::new()
|
||||||
|
$sync.selectedFeatures = [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)) {
|
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||||
@@ -66,26 +79,6 @@ if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]:
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load DLLs
|
|
||||||
Add-Type -AssemblyName PresentationFramework
|
|
||||||
Add-Type -AssemblyName System.Windows.Forms
|
|
||||||
|
|
||||||
# Variable to sync between runspaces
|
|
||||||
$sync = [Hashtable]::Synchronized(@{})
|
|
||||||
$sync.PSScriptRoot = $PSScriptRoot
|
|
||||||
$sync.version = "#{replaceme}"
|
|
||||||
$sync.configs = @{}
|
|
||||||
$sync.Buttons = [System.Collections.Generic.List[PSObject]]::new()
|
|
||||||
$sync.preferences = @{}
|
|
||||||
$sync.ProcessRunning = $false
|
|
||||||
$sync.selectedApps = [System.Collections.Generic.List[string]]::new()
|
|
||||||
$sync.selectedTweaks = [System.Collections.Generic.List[string]]::new()
|
|
||||||
$sync.selectedToggles = [System.Collections.Generic.List[string]]::new()
|
|
||||||
$sync.selectedFeatures = [System.Collections.Generic.List[string]]::new()
|
|
||||||
$sync.currentTab = "Install"
|
|
||||||
$sync.selectedAppsStackPanel
|
|
||||||
$sync.selectedAppsPopup
|
|
||||||
|
|
||||||
$dateTime = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
|
$dateTime = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
|
||||||
|
|
||||||
# Set the path for the winutil directory
|
# Set the path for the winutil directory
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
<settings pass="windowsPE">
|
<settings pass="windowsPE">
|
||||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
<UserData>
|
<UserData>
|
||||||
|
<ProductKey>
|
||||||
|
<Key>00000-00000-00000-00000-00000</Key>
|
||||||
|
<WillShowUI>Always</WillShowUI>
|
||||||
|
</ProductKey>
|
||||||
<AcceptEula>true</AcceptEula>
|
<AcceptEula>true</AcceptEula>
|
||||||
</UserData>
|
</UserData>
|
||||||
<UseConfigurationSet>false</UseConfigurationSet>
|
<UseConfigurationSet>false</UseConfigurationSet>
|
||||||
|
|||||||
@@ -278,6 +278,7 @@
|
|||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="ComboBox">
|
<ControlTemplate TargetType="ComboBox">
|
||||||
<Grid>
|
<Grid>
|
||||||
|
<!-- Outer border gives the combo a visible box -->
|
||||||
<Border x:Name="OuterBorder"
|
<Border x:Name="OuterBorder"
|
||||||
BorderBrush="{DynamicResource BorderColor}"
|
BorderBrush="{DynamicResource BorderColor}"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
@@ -288,6 +289,7 @@
|
|||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||||
ClickMode="Press">
|
ClickMode="Press">
|
||||||
|
<!-- Text + arrow laid out in a two-column Grid -->
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
@@ -299,6 +301,7 @@
|
|||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
HorizontalAlignment="Left" VerticalAlignment="Center"
|
HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||||
Margin="6,3,2,3"/>
|
Margin="6,3,2,3"/>
|
||||||
|
<!-- Scalable vector chevron -->
|
||||||
<Path Grid.Column="1"
|
<Path Grid.Column="1"
|
||||||
Data="M 0,0 L 8,0 L 4,5 Z"
|
Data="M 0,0 L 8,0 L 4,5 Z"
|
||||||
Fill="{TemplateBinding Foreground}"
|
Fill="{TemplateBinding Foreground}"
|
||||||
@@ -943,19 +946,13 @@
|
|||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
<Grid Background="{DynamicResource MainBackgroundColor}" ShowGridLines="False" Name="WPFMainGrid" Width="Auto" Height="Auto" HorizontalAlignment="Stretch">
|
<Grid Background="{DynamicResource MainBackgroundColor}" ShowGridLines="False" Name="WPFMainGrid" Width="Auto" Height="Auto" HorizontalAlignment="Stretch">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<!-- Offline banner -->
|
<Grid Grid.Row="0" Background="{DynamicResource MainBackgroundColor}">
|
||||||
<Border Name="WPFOfflineBanner" Grid.Row="0" Background="#8B0000" Visibility="Collapsed" Padding="6,4">
|
|
||||||
<TextBlock Text="⚠ Offline Mode - No Internet Connection" Foreground="White" FontWeight="Bold"
|
|
||||||
HorizontalAlignment="Center" FontSize="13" Background="Transparent"/>
|
|
||||||
</Border>
|
|
||||||
<Grid Grid.Row="1" Background="{DynamicResource MainBackgroundColor}">
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/> <!-- Navigation buttons -->
|
<ColumnDefinition Width="Auto"/> <!-- Navigation buttons -->
|
||||||
<ColumnDefinition Width="*"/> <!-- Search bar and buttons -->
|
<ColumnDefinition Width="*"/> <!-- Search bar and buttons -->
|
||||||
@@ -1198,7 +1195,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<TabControl Name="WPFTabNav" Background="Transparent" Width="Auto" Height="Auto" BorderBrush="Transparent" BorderThickness="0" Grid.Row="2" Grid.Column="0" Padding="-1">
|
<TabControl Name="WPFTabNav" Background="Transparent" Width="Auto" Height="Auto" BorderBrush="Transparent" BorderThickness="0" Grid.Row="1" Grid.Column="0" Padding="-1">
|
||||||
<TabItem Header="Install" Visibility="Collapsed" Name="WPFTab1">
|
<TabItem Header="Install" Visibility="Collapsed" Name="WPFTab1">
|
||||||
<Grid Background="Transparent" >
|
<Grid Background="Transparent" >
|
||||||
|
|
||||||
@@ -1367,17 +1364,20 @@
|
|||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Header="Win11ISO" Visibility="Collapsed" Name="WPFTab5">
|
<TabItem Header="Win11ISO" Visibility="Collapsed" Name="WPFTab5">
|
||||||
<Grid Name="Win11ISOPanel" Margin="{DynamicResource TabContentMargin}" Background="Transparent">
|
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="{DynamicResource TabContentMargin}">
|
||||||
<Grid.RowDefinitions>
|
<Grid Background="Transparent" Name="Win11ISOPanel">
|
||||||
<RowDefinition Height="Auto"/> <!-- Steps 1-4 -->
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*"/> <!-- Log / Status -->
|
<RowDefinition Height="Auto"/> <!-- Step 1: Select ISO -->
|
||||||
</Grid.RowDefinitions>
|
<RowDefinition Height="Auto"/> <!-- Step 2: Mount & Verify -->
|
||||||
|
<RowDefinition Height="Auto"/> <!-- Step 3: Modify install.wim -->
|
||||||
|
<RowDefinition Height="Auto"/> <!-- Step 4: Output Options -->
|
||||||
|
<RowDefinition Height="Auto"/> <!-- Log / Status -->
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Steps 1-4 -->
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
<StackPanel Grid.Row="0">
|
<!-- STEP 1 : Select Windows 11 ISO -->
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
<!-- ─── STEP 1 : Select Windows 11 ISO ─────────────── -->
|
<Grid Grid.Row="0" Name="WPFWin11ISOSelectSection" Margin="5" HorizontalAlignment="Left" MinWidth="{DynamicResource ButtonWidth}">
|
||||||
<Grid Name="WPFWin11ISOSelectSection" Margin="5" HorizontalAlignment="Left" MinWidth="{DynamicResource ButtonWidth}">
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
@@ -1463,13 +1463,16 @@
|
|||||||
Height="{DynamicResource ButtonHeight}"/>
|
Height="{DynamicResource ButtonHeight}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- ─── STEP 2 : Mount & Verify ISO ──────────────────── -->
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
<Grid Name="WPFWin11ISOMountSection"
|
<!-- STEP 2 : Mount & Verify ISO -->
|
||||||
Margin="5"
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
Visibility="Collapsed"
|
<Grid Grid.Row="1"
|
||||||
HorizontalAlignment="Left" MinWidth="{DynamicResource ButtonWidth}">
|
Name="WPFWin11ISOMountSection"
|
||||||
|
Margin="5"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
HorizontalAlignment="Left" MinWidth="{DynamicResource ButtonWidth}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
@@ -1491,13 +1494,6 @@
|
|||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Width="Auto" Padding="12,0"
|
Width="Auto" Padding="12,0"
|
||||||
Height="{DynamicResource ButtonHeight}"/>
|
Height="{DynamicResource ButtonHeight}"/>
|
||||||
<CheckBox Name="WPFWin11ISOInjectDrivers"
|
|
||||||
Content="Inject current system drivers"
|
|
||||||
FontSize="{DynamicResource FontSize}"
|
|
||||||
Foreground="{DynamicResource MainForegroundColor}"
|
|
||||||
IsChecked="False"
|
|
||||||
Margin="0,8,0,0"
|
|
||||||
ToolTip="Exports all drivers from this machine and injects them into install.wim and boot.wim. Recommended for systems with unsupported NVMe or network controllers."/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Verification results panel -->
|
<!-- Verification results panel -->
|
||||||
@@ -1530,13 +1526,16 @@
|
|||||||
Margin="0,0,0,0"/>
|
Margin="0,0,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- ─── STEP 3 : Modify install.wim ───────────────────── -->
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
<StackPanel Name="WPFWin11ISOModifySection"
|
<!-- STEP 3 : Modify install.wim -->
|
||||||
Margin="5"
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
Visibility="Collapsed"
|
<StackPanel Grid.Row="2"
|
||||||
HorizontalAlignment="Left" MinWidth="{DynamicResource ButtonWidth}">
|
Name="WPFWin11ISOModifySection"
|
||||||
|
Margin="5"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
HorizontalAlignment="Left" MinWidth="{DynamicResource ButtonWidth}">
|
||||||
<TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold"
|
<TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold"
|
||||||
Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,8">
|
Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,8">
|
||||||
Step 3 - Modify install.wim
|
Step 3 - Modify install.wim
|
||||||
@@ -1554,13 +1553,16 @@
|
|||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Width="Auto" Padding="12,0"
|
Width="Auto" Padding="12,0"
|
||||||
Height="{DynamicResource ButtonHeight}"/>
|
Height="{DynamicResource ButtonHeight}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- ─── STEP 4 : Output Options ───────────────────────── -->
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
<StackPanel Name="WPFWin11ISOOutputSection"
|
<!-- STEP 4 : Output Options -->
|
||||||
Margin="5"
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
Visibility="Collapsed"
|
<StackPanel Grid.Row="3"
|
||||||
HorizontalAlignment="Left" MinWidth="{DynamicResource ButtonWidth}">
|
Name="WPFWin11ISOOutputSection"
|
||||||
|
Margin="5"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
HorizontalAlignment="Left" MinWidth="{DynamicResource ButtonWidth}">
|
||||||
<!-- Header row: title + Clean & Reset button -->
|
<!-- Header row: title + Clean & Reset button -->
|
||||||
<Grid Margin="0,0,0,12">
|
<Grid Margin="0,0,0,12">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -1644,37 +1646,31 @@
|
|||||||
Margin="0,0,0,10"/>
|
Margin="0,0,0,10"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<!-- Status / Log Output -->
|
||||||
|
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||||
|
<StackPanel Grid.Row="4" Margin="5">
|
||||||
|
<TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold"
|
||||||
|
Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,6">
|
||||||
|
Status Log
|
||||||
|
</TextBlock>
|
||||||
|
<TextBox Name="WPFWin11ISOStatusLog"
|
||||||
|
IsReadOnly="True"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
Height="140" Padding="6"
|
||||||
|
Background="{DynamicResource MainBackgroundColor}"
|
||||||
|
Foreground="{DynamicResource MainForegroundColor}"
|
||||||
|
BorderBrush="{DynamicResource BorderColor}"
|
||||||
|
BorderThickness="1"
|
||||||
|
Text="Ready. Please select a Windows 11 ISO to begin."/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<!-- Status Log (fills remaining height) -->
|
|
||||||
<Grid Grid.Row="1" Margin="5">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<TextBlock Grid.Row="0"
|
|
||||||
FontSize="{DynamicResource FontSize}" FontWeight="Bold"
|
|
||||||
Foreground="{DynamicResource MainForegroundColor}"
|
|
||||||
Margin="0,0,0,4">
|
|
||||||
Status Log
|
|
||||||
</TextBlock>
|
|
||||||
<TextBox Grid.Row="1"
|
|
||||||
Name="WPFWin11ISOStatusLog"
|
|
||||||
IsReadOnly="True"
|
|
||||||
TextWrapping="Wrap"
|
|
||||||
VerticalScrollBarVisibility="Visible"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
Padding="6"
|
|
||||||
Background="{DynamicResource MainBackgroundColor}"
|
|
||||||
Foreground="{DynamicResource MainForegroundColor}"
|
|
||||||
BorderBrush="{DynamicResource BorderColor}"
|
|
||||||
BorderThickness="1"
|
|
||||||
Text="Ready. Please select a Windows 11 ISO to begin."/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</ScrollViewer>
|
||||||
</Grid>
|
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
Reference in New Issue
Block a user