mirror of
https://github.com/Raphire/Win11Debloat.git
synced 2026-04-03 14:06:27 +00:00
Compare commits
73 Commits
2026.02.04
...
2026.03.15
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6535803ec | ||
|
|
c37bdcf5f2 | ||
|
|
d187679cd0 | ||
|
|
06f8f9eb6a | ||
|
|
8d5295d831 | ||
|
|
260a143509 | ||
|
|
94e5c95d57 | ||
|
|
8401474a79 | ||
|
|
992c80bc1e | ||
|
|
18823c4a80 | ||
|
|
3d6259f117 | ||
|
|
1ea82b9728 | ||
|
|
df20b007ca | ||
|
|
0887eaadfd | ||
|
|
eb3e041ed6 | ||
|
|
63a219d3e7 | ||
|
|
9467d6cb7b | ||
|
|
ea9b3ce02b | ||
|
|
1eeacf3351 | ||
|
|
e8adac1852 | ||
|
|
ec99a1c619 | ||
|
|
238a48d39b | ||
|
|
9afd4ee02e | ||
|
|
70f8170e81 | ||
|
|
ad0b49060a | ||
|
|
bbfbd7193e | ||
|
|
495762e378 | ||
|
|
7c3af36e06 | ||
|
|
c72e4fcb54 | ||
|
|
8956c41b4d | ||
|
|
33ce8d6f70 | ||
|
|
a1907c2a78 | ||
|
|
b5b67290de | ||
|
|
d25960de64 | ||
|
|
ea67435f64 | ||
|
|
a611e6b128 | ||
|
|
033fa1b8af | ||
|
|
1b6aa00bdd | ||
|
|
7d00b84a07 | ||
|
|
15775d9dc8 | ||
|
|
2cb9f41db1 | ||
|
|
e496aa3af0 | ||
|
|
b355706cee | ||
|
|
810fb3be43 | ||
|
|
9500c2099e | ||
|
|
d172a0ef0c | ||
|
|
c76c3ce7ac | ||
|
|
2c940ff489 | ||
|
|
e0e69c0ef5 | ||
|
|
c9ce72f79a | ||
|
|
397eba7ca8 | ||
|
|
bffa6dfc3e | ||
|
|
754c3cee4c | ||
|
|
f47b0531a4 | ||
|
|
6427b35bc8 | ||
|
|
60e8985db0 | ||
|
|
6589dab528 | ||
|
|
2a9a3960b8 | ||
|
|
65aabbc050 | ||
|
|
95dc490b6e | ||
|
|
687c089f2e | ||
|
|
5dcc8bffdd | ||
|
|
f9b4cec417 | ||
|
|
0e7b289d03 | ||
|
|
feef8f76b9 | ||
|
|
50db66bb5f | ||
|
|
b48fa24627 | ||
|
|
f8c2c6ddd7 | ||
|
|
1ea2c63522 | ||
|
|
675882cb3b | ||
|
|
ae4d19f59c | ||
|
|
327f4ee7ab | ||
|
|
3af62159a5 |
347
.github/CONTRIBUTING.md
vendored
Normal file
347
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
# How to Contribute?
|
||||
|
||||
We welcome contributions from the community. You can contribute to Win11Debloat by:
|
||||
- Reporting issues and bugs [here](https://github.com/Raphire/Win11Debloat/issues/new?template=bug_report.yml)
|
||||
- Submitting feature requests [here](https://github.com/Raphire/Win11Debloat/issues/new?template=feature_request.yml)
|
||||
- Testing Win11Debloat
|
||||
- Creating a pull request
|
||||
- Improving the documentation
|
||||
|
||||
# Testing Win11Debloat
|
||||
|
||||
You can help us test the latest changes and additions to the script. If you encounter any issues, please report them [here](https://github.com/Raphire/Win11Debloat/issues/new?template=bug_report.yml).
|
||||
|
||||
> [!WARNING]
|
||||
> The prerelease version of Win11Debloat is meant for developers to test the script. Don't use this in production environments!
|
||||
|
||||
You can launch the prerelease version of Win11Debloat by running this command:
|
||||
```ps1
|
||||
& ([scriptblock]::Create((irm "https://debloat.raphi.re/dev")))
|
||||
```
|
||||
|
||||
# Contributing Code
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Fork and Clone the Repository
|
||||
|
||||
1. **Fork the project** on GitHub by clicking the "Fork" button at the top right of the repository page.
|
||||
|
||||
2. **Clone the repository** to your local machine:
|
||||
```powershell
|
||||
git clone https://github.com/YOUR-USERNAME/Win11Debloat.git
|
||||
cd Win11Debloat
|
||||
```
|
||||
|
||||
3. **Create a new branch** for your contribution:
|
||||
```powershell
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
|
||||
### Running the Script Locally
|
||||
|
||||
1. Open PowerShell as an administrator
|
||||
2. Enable script execution if necessary:
|
||||
```powershell
|
||||
Set-ExecutionPolicy Unrestricted -Scope Process -Force
|
||||
```
|
||||
3. Navigate to your Win11Debloat directory
|
||||
4. Run the script:
|
||||
```powershell
|
||||
.\Win11Debloat.ps1
|
||||
```
|
||||
|
||||
## Implementation Guidelines
|
||||
|
||||
### Project Structure
|
||||
|
||||
Understanding the project structure is essential for contributing effectively:
|
||||
|
||||
```
|
||||
Win11Debloat/
|
||||
├── Win11Debloat.ps1 # Main PowerShell script
|
||||
├── Scripts/ # Additional PowerShell scripts and functions
|
||||
│ └── Get.ps1 # Script used for the quick launch method to automatically download and run Win11debloat
|
||||
├── Config/
|
||||
│ ├── Apps.json # List of supported apps for removal
|
||||
│ ├── DefaultSettings.json # Default configuration preset
|
||||
│ ├── Features.json # All features with metadata
|
||||
│ └── LastUsedSettings.json # Last used configuration (generated during use)
|
||||
├── Regfiles/ # Registry files for each feature
|
||||
└── Schemas/ # XAML Schemas for GUI elements
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Test Thoroughly**: Always test your changes on a Windows test environment before submitting. This includes undoing tweaks and running script as another user and in Sysprep mode.
|
||||
2. **Document Changes**: Update the `README.md` and other relevant documentation. Wiki documentation will be generated/updated based on the `Features.json` and `Apps.json` files.
|
||||
3. **Follow Existing Patterns**: Look at existing implementations for guidance.
|
||||
4. **Use Clear Naming**: Choose descriptive names for features, IDs, and registry files.
|
||||
5. **Minimal Changes**: Registry files should only modify what's necessary. Avoid using policies where possible.
|
||||
6. **Comment Your Code**: Add comments explaining your reasoning for complex logic in PowerShell scripts.
|
||||
7. **Version Constraints**: Use `MinVersion` and `MaxVersion` if a feature only applies to specific Windows versions.
|
||||
8. **Limit pull requests to 1 feature**: Keep pull requests limited to just one feature, this makes it easier to review your changes.
|
||||
|
||||
### Code Style
|
||||
|
||||
- Use **4 spaces** for indentation in PowerShell scripts
|
||||
- Use **2 spaces** for indentation in JSON files
|
||||
- Follow existing naming conventions
|
||||
- Keep lines reasonable in length
|
||||
- Use descriptive variable names
|
||||
- Try to limit your indentation to a max of 4-5 levels, if possible.
|
||||
- Use [Segoe Fluent Icon Assets](https://learn.microsoft.com/en-us/windows/apps/design/iconography/segoe-fluent-icons-font) for icons.
|
||||
|
||||
### Common Pitfalls
|
||||
|
||||
Avoid these common mistakes when contributing:
|
||||
|
||||
1. **Forgetting Get.ps1**: When adding a new command-line parameter, contributors often remember to add it to `Win11Debloat.ps1` but forget to add the same parameter to `Scripts/Get.ps1`. Both files **must** have matching parameters.
|
||||
|
||||
2. **Missing Registry Files**: Always create an `Undo` registry file for reversibility, aswell as a `Sysprep` registry file for Sysprep mode.
|
||||
|
||||
3. **Incorrect Registry Hives for Sysprep**: Sysprep registry files apply changes to Windows' default user, registry keys in the `HKEY_CURRENT_USER` hive must use `hkey_users\default` instead. Ensure you update **all** registry keys in the file.
|
||||
|
||||
4. **Wrong Registry File Location**:
|
||||
- Main action files go in `Regfiles/`
|
||||
- Undo files go in `Regfiles/Undo/`
|
||||
- Sysprep files go in `Regfiles/Sysprep/`
|
||||
|
||||
Placing files in the wrong directory will cause the script to fail when trying to apply or undo changes.
|
||||
|
||||
6. **Not Testing Undo Functionality**: Always test that your undo registry file properly reverts all changes. A feature that can't be undone will frustrate users.
|
||||
|
||||
7. **Not Testing User/Sysprep Functionality**: Always test that your feature works when applied to another user or to the Windows default user with Sysprep. Sysprep changes can be tested by creating new users after running the script.
|
||||
|
||||
7. **Missing Category**: Features without a `Category` field (set to `null`) won't appear in the GUI. This is intentional for command-line-only features, make sure this is what you want before submitting.
|
||||
|
||||
8. **Hardcoded Paths**: When writing PowerShell logic, use `$PSScriptRoot` and script variables instead of hardcoded paths. This ensures the script works regardless of where it's installed.
|
||||
|
||||
## Implementing New Features
|
||||
|
||||
### Adding Support for a New App
|
||||
|
||||
> [!NOTE]
|
||||
> The script automatically generates the app options for the GUI from the app information in the Apps.json file.
|
||||
|
||||
To add a new app that can be removed via Win11Debloat:
|
||||
|
||||
1. **Find the AppId**: To find the correct AppId for an app:
|
||||
```powershell
|
||||
Get-AppxPackage | Select-Object Name, PackageFullName
|
||||
```
|
||||
|
||||
2. **Edit `Config/Apps.json`**: Add a new entry to the `"Apps"` array:
|
||||
```json
|
||||
{
|
||||
"FriendlyName": "Display Name",
|
||||
"AppId": "AppPackageIdentifier",
|
||||
"Description": "Brief description of the app",
|
||||
"SelectedByDefault": true|false
|
||||
}
|
||||
```
|
||||
|
||||
3. **Follow the Guidelines**:
|
||||
- Use clear, user-friendly names for `FriendlyName`
|
||||
- Set `SelectedByDefault` to `true` only for apps that are largely considered bloatware, otherwise set to `false`
|
||||
- Provide a concise description explaining what the app does
|
||||
|
||||
### Adding a New Feature
|
||||
|
||||
Features are defined in `Config/Features.json` and can modify Windows settings via registry files or PowerShell commands.
|
||||
|
||||
> [!NOTE]
|
||||
> For simple features that just include a registry change, no actual coding is required in the main script except for adding the corresponding command-line parameters. The GUI is automatically built using the information in the Features.json file.
|
||||
|
||||
#### 1a. Create the Registry File(s)
|
||||
|
||||
Create new registry files in the `Regfiles/` directory:
|
||||
|
||||
- **Disable file**: `Disable_YourFeature.reg`
|
||||
- **Enable file**: `Undo/Enable_YourFeature.reg` (for reverting)
|
||||
- **Sysprep file**: `Sysprep/Disable_YourFeature.reg` (for Sysprep mode)
|
||||
|
||||
Example registry file structure:
|
||||
```reg
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\YourPath]
|
||||
"SettingName"=dword:00000000
|
||||
```
|
||||
|
||||
A Sysprep registry file should apply the same changes as the normal action. Replace the hive of registry keys that start with `HKEY_CURRENT_USER` with `hkey_users\default`. For example:
|
||||
```reg
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\YourPath]
|
||||
"SettingName"=dword:00000000
|
||||
```
|
||||
|
||||
#### 1b. Implement the Feature Logic
|
||||
|
||||
If your feature requires more than just applying a registry file, add custom logic to the main script in the appropriate section. In most cases this will involve creating a new entry in the `ExecuteParameter` function for your new feature.
|
||||
|
||||
#### 2. Add Feature to Features.json
|
||||
|
||||
Add your feature to the `"Features"` array in `Config/Features.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"FeatureId": "YourFeatureId",
|
||||
"Label": "Short label describing the feature",
|
||||
"ToolTip": "Detailed explanation of what this feature does and its impact.",
|
||||
"Category": "Privacy & Suggested Content",
|
||||
"Priority": 1,
|
||||
"Action": "Disable",
|
||||
"RegistryKey": "Disable_YourFeature.reg",
|
||||
"ApplyText": "Disabling your feature...",
|
||||
"UndoAction": "Enable",
|
||||
"RegistryUndoKey": "Enable_YourFeature.reg",
|
||||
"RequiresReboot": false,
|
||||
"MinVersion": null,
|
||||
"MaxVersion": null
|
||||
}
|
||||
```
|
||||
|
||||
**Field Descriptions**:
|
||||
- `FeatureId`: Unique identifier (must match parameter name in Win11Debloat.ps1 and Get.ps1)
|
||||
- `Label`: Short description shown in the UI, written in a way to fit with the Action or UndoAction prefixed
|
||||
- `ToolTip`: Detailed explanation of what the feature does, used for tooltips in the GUI
|
||||
- `Category`: One of the predefined categories (see Categories array in Features.json), features without a category won't be loaded into the GUI.
|
||||
- `Priority`: Optional. The priority value (int) is used to sort features within a category. If this field is omitted the feature will be sorted based on the order in the Features.json file.
|
||||
- `Action`: Action word for the feature (e.g., "Disable", "Enable", "Hide", "Show")
|
||||
- `RegistryKey`: Filename of the registry file to apply (in Regfiles/ directory) or null if feature does not require registry changes
|
||||
- `ApplyText`: Message shown when applying the feature
|
||||
- `UndoAction`: Action word for reverting (e.g., "Enable", "Show")
|
||||
- `RegistryUndoKey`: Filename of the registry file to revert changes or null if feature does not require registry changes
|
||||
- `RequiresReboot`: Optional boolean. Set to `true` if the feature requires a system reboot to take effect
|
||||
- `MinVersion`: Minimum Windows build version (e.g., "22000") or null
|
||||
- `MaxVersion`: Maximum Windows version or null
|
||||
|
||||
#### 3. Add Command-Line Parameter
|
||||
|
||||
Add a corresponding parameter to both `Win11Debloat.ps1` AND `Scripts/Get.ps1`, the parameter name should match the FeatureId you have defined in `Features.json`. In most cases this will be a switch parameter, example:
|
||||
```powershell
|
||||
[switch]$YourFeatureId,
|
||||
```
|
||||
|
||||
### Adding a Feature to the Default Preset
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The default preset is intentionally conservative. Features added to it should be thoroughly tested and widely beneficial. When in doubt, leave the feature out of the default preset.
|
||||
|
||||
The default preset (`Config/DefaultSettings.json`) defines which features are automatically applied when users run Win11Debloat in "Default Mode" or with the `-RunDefaults` parameter. This preset should include features that are widely considered to improve the Windows experience without breaking functionality.
|
||||
|
||||
**When to add a feature to the default preset:**
|
||||
- The feature removes obvious bloatware or distractions
|
||||
- The feature enhances privacy without breaking core functionality
|
||||
- The feature is generally non-controversial and beneficial to most users
|
||||
- The change can be easily reverted if needed
|
||||
|
||||
**When NOT to add a feature to the default preset:**
|
||||
- The feature significantly changes core Windows behavior
|
||||
- The feature might break applications or workflows for some users
|
||||
- The feature is highly opinionated or preference-based
|
||||
- The feature is experimental or not thoroughly tested
|
||||
|
||||
To add your feature to the default preset, edit `Config/DefaultSettings.json` and add a new entry to the `"Settings"` array:
|
||||
|
||||
```json
|
||||
{
|
||||
"Name": "YourFeatureId",
|
||||
"Value": true
|
||||
}
|
||||
```
|
||||
|
||||
**Field Descriptions**:
|
||||
- `Name`: Must exactly match the `FeatureId` from Features.json
|
||||
- `Value`: Set to `true` to enable the feature in default mode
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"Version": "1.0",
|
||||
"Settings": [
|
||||
{
|
||||
"Name": "CreateRestorePoint",
|
||||
"Value": true
|
||||
},
|
||||
{
|
||||
"Name": "DisableTelemetry",
|
||||
"Value": true
|
||||
},
|
||||
{
|
||||
"Name": "YourFeatureId",
|
||||
"Value": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Adding a Category
|
||||
|
||||
To add a new category for organizing features:
|
||||
|
||||
- Add a new category entry to the `"Categories"` array in `Config/Features.json`:
|
||||
```json
|
||||
{
|
||||
"Name": "Your Category Name",
|
||||
"Icon": "#### ;"
|
||||
}
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> Use [Segoe Fluent Icon Assets](https://learn.microsoft.com/en-us/windows/apps/design/iconography/segoe-fluent-icons-font) for icon codes.
|
||||
|
||||
### Adding UI Groups
|
||||
|
||||
UI Groups allow features to be grouped together in the GUI with a combobox (dropdown) selection:
|
||||
|
||||
```json
|
||||
{
|
||||
"GroupId": "UniqueGroupId",
|
||||
"Label": "Display label for the group",
|
||||
"ToolTip": "Explanation of what this group controls",
|
||||
"Category": "Category Name",
|
||||
"Priority": 1,
|
||||
"Values": [
|
||||
{
|
||||
"Label": "Option 1",
|
||||
"FeatureIds": ["FeatureId1"]
|
||||
},
|
||||
{
|
||||
"Label": "Option 2",
|
||||
"FeatureIds": ["FeatureId2"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Submitting a Pull Request
|
||||
|
||||
1. **Commit your changes** with clear, descriptive commit messages:
|
||||
```powershell
|
||||
git add .
|
||||
git commit -m "Add feature: Description of your changes"
|
||||
```
|
||||
|
||||
2. **Push to your fork**:
|
||||
```powershell
|
||||
git push origin feature/your-feature-name
|
||||
```
|
||||
|
||||
3. **Create a Pull Request** on GitHub:
|
||||
- Go to the original Win11Debloat repository
|
||||
- Click "New Pull Request"
|
||||
- Select your fork and branch
|
||||
- Provide a clear description of your changes, include references to the registry keys used
|
||||
- Reference any related issues
|
||||
|
||||
4. **Respond to feedback**: Be prepared to make adjustments based on code review feedback.
|
||||
|
||||
# Questions?
|
||||
|
||||
If you have questions about contributing, feel free to:
|
||||
- Open a [discussion](https://github.com/Raphire/Win11Debloat/discussions)
|
||||
- Comment on an existing issue
|
||||
- Ask in your pull request
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,4 +2,5 @@ LastSettings
|
||||
SavedSettings
|
||||
LastUsedSettings.json
|
||||
CustomAppsList
|
||||
Logs/*
|
||||
Win11Debloat.log
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 62 KiB |
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,14 @@
|
||||
"Name": "DisableBing",
|
||||
"Value": true
|
||||
},
|
||||
{
|
||||
"Name": "DisableStoreSearchSuggestions",
|
||||
"Value": true
|
||||
},
|
||||
{
|
||||
"Name": "DisableSearchHighlights",
|
||||
"Value": true
|
||||
},
|
||||
{
|
||||
"Name": "DisableCopilot",
|
||||
"Value": true
|
||||
@@ -37,6 +45,10 @@
|
||||
"Name": "DisableClickToDo",
|
||||
"Value": true
|
||||
},
|
||||
{
|
||||
"Name": "DisableAISvcAutoStart",
|
||||
"Value": true
|
||||
},
|
||||
{
|
||||
"Name": "DisableWidgets",
|
||||
"Value": true
|
||||
File diff suppressed because it is too large
Load Diff
80
README.md
80
README.md
@@ -4,9 +4,9 @@
|
||||
[](https://github.com/Raphire/Win11Debloat/discussions)
|
||||
[](https://github.com/Raphire/Win11Debloat/wiki/)
|
||||
|
||||
Win11Debloat is a lightweight, easy to use PowerShell script that allows you to quickly declutter and improve your Windows experience. It can remove pre-installed bloatware apps, disable telemetry, remove intrusive interface elements and much more. No need to painstakingly go through all the settings yourself or remove apps one by one. Win11Debloat makes the process quick and easy!
|
||||
Win11Debloat is a lightweight, easy to use PowerShell script that allows you to quickly declutter and customize your Windows experience. It can remove pre-installed bloatware apps, disable telemetry, remove intrusive interface elements and much more. No need to painstakingly go through all the settings yourself or remove apps one by one. Win11Debloat makes the process quick and easy!
|
||||
|
||||
The script also includes many features that system administrators and power users will enjoy. Such as support for Windows Audit mode, the option to make changes to other Windows users and the ability to access all of Win11Debloat's features right from the command-line. Please refer to our [wiki](https://github.com/Raphire/Win11Debloat/wiki/) for more details.
|
||||
The script also includes many features that system administrators and power users will enjoy. Such as a powerful command-line interface, support for Windows Audit mode and the option to make changes to other Windows users. Please refer to our [wiki](https://github.com/Raphire/Win11Debloat/wiki/) for more details.
|
||||
|
||||

|
||||
|
||||
@@ -33,7 +33,7 @@ Download & run the script automatically via PowerShell.
|
||||
3. Wait for the script to automatically download Win11Debloat.
|
||||
4. Carefully read through and follow the on-screen instructions.
|
||||
|
||||
This method supports command-line parameters to customize the behaviour of the script. Please click [here](https://github.com/Raphire/Win11Debloat/wiki/How-To-Use#parameters) for more information.
|
||||
This method supports command-line parameters to customize the behaviour of the script. Please click [here](https://github.com/Raphire/Win11Debloat/wiki/Command%E2%80%90line-Interface#parameters) for more information.
|
||||
|
||||
### Traditional method
|
||||
|
||||
@@ -69,7 +69,7 @@ This method supports command-line parameters to customize the behaviour of the s
|
||||
|
||||
6. Carefully read through and follow the on-screen instructions.
|
||||
|
||||
This method supports command-line parameters to customize the behaviour of the script. Please click [here](https://github.com/Raphire/Win11Debloat/wiki/How-To-Use#parameters) for more information.
|
||||
This method supports command-line parameters to customize the behaviour of the script. Please click [here](https://github.com/Raphire/Win11Debloat/wiki/Command%E2%80%90line-Interface#parameters) for more information.
|
||||
</details>
|
||||
|
||||
## Features
|
||||
@@ -87,6 +87,8 @@ Below is an overview of the key features and functionality offered by Win11Deblo
|
||||
|
||||
- Disable telemetry, diagnostic data, activity history, app-launch tracking & targeted ads.
|
||||
- Disable tips, tricks, suggestions & ads across Windows.
|
||||
- Disable Windows location services & app location access.
|
||||
- Disable Find My Device location tracking.
|
||||
- Disable 'Windows Spotlight' and tips & tricks on the lock screen.
|
||||
- Disable 'Windows Spotlight' desktop background option.
|
||||
- Disable ads, suggestions and the MSN news feed in Microsoft Edge.
|
||||
@@ -95,21 +97,23 @@ Below is an overview of the key features and functionality offered by Win11Deblo
|
||||
#### AI Features
|
||||
|
||||
- Disable & remove Microsoft Copilot.
|
||||
- Disable Windows Recall. (W11 only)
|
||||
- Disable Click to Do, AI text & image analysis tool. (W11 only)
|
||||
- Disable AI Features in Edge. (W11 only)
|
||||
- Disable AI Features in Paint. (W11 only)
|
||||
- Disable AI Features in Notepad. (W11 only)
|
||||
- Disable Windows Recall.
|
||||
- Disable Click to Do, AI text & image analysis tool.
|
||||
- Prevent AI service (WSAIFabricSvc) from starting automatically.
|
||||
- Disable AI Features in Edge.
|
||||
- Disable AI Features in Paint.
|
||||
- Disable AI Features in Notepad.
|
||||
|
||||
#### System
|
||||
|
||||
- Disable the Drag Tray for sharing & moving files. (W11 only)
|
||||
- Restore the old Windows 10 style context menu. (W11 only)
|
||||
- Disable the Drag Tray for sharing & moving files.
|
||||
- Restore the old Windows 10 style context menu.
|
||||
- Turn off Enhance Pointer Precision, also known as mouse acceleration.
|
||||
- Disable the Sticky Keys keyboard shortcut. (W11 only)
|
||||
- Disable the Sticky Keys keyboard shortcut.
|
||||
- Disable Storage Sense automatic disk cleanup.
|
||||
- Disable fast start-up to ensure a full shutdown.
|
||||
- Disable BitLocker automatic device encryption.
|
||||
- Disable network connectivity during Modern Standby to reduce battery drain. (W11 only)
|
||||
- Disable network connectivity during Modern Standby to reduce battery drain.
|
||||
|
||||
#### Windows Update
|
||||
|
||||
@@ -123,35 +127,51 @@ Below is an overview of the key features and functionality offered by Win11Deblo
|
||||
- Disable transparency effects
|
||||
- Disable animations and visual effects.
|
||||
|
||||
#### Start Menu
|
||||
#### Start Menu & Search
|
||||
|
||||
- Remove or replace all pinned apps from start for the current user, or for all existing & new users. (W11 only)
|
||||
- Disable the recommended section in the start menu. (W11 only)
|
||||
- Remove or replace all pinned apps from the start menu.
|
||||
- Hide the recommended section in the start menu.
|
||||
- Hide the 'All Apps' section in the start menu.
|
||||
- Disable the Phone Link mobile devices integration in the start menu.
|
||||
- Disable Bing web search & Copilot integration in Windows search.
|
||||
- Disable the Phone Link mobile devices integration in the start menu. (W11 only)
|
||||
- Disable Microsoft Store app suggestions in Windows search.
|
||||
- Disable Search Highlights (dynamic/branded content) in the taskbar search box.
|
||||
- Disable local Windows search history.
|
||||
|
||||
#### Taskbar
|
||||
|
||||
- Align taskbar icons to the left. (W11 only)
|
||||
- Hide or change the search icon/box on the taskbar. (W11 only)
|
||||
- Hide the taskview button from the taskbar. (W11 only)
|
||||
- Align taskbar icons to the left.
|
||||
- Hide or change the search icon/box on the taskbar.
|
||||
- Hide the taskview button from the taskbar.
|
||||
- Disable widgets on the taskbar & lock screen.
|
||||
- Hide the chat (meet now) icon from the taskbar. (W10 only)
|
||||
- Enable the 'End Task' option in the taskbar right click menu. (W11 only)
|
||||
- Hide the chat (meet now) icon from the taskbar.
|
||||
- Enable the 'End Task' option in the taskbar right click menu.
|
||||
- Enable the 'Last Active Click' behavior in the taskbar app area. This allows you to repeatedly click on an application's icon in the taskbar to switch focus between the open windows of that application.
|
||||
- Choose how app icons are shown on the taskbar when using multiple monitors. (W11 only)
|
||||
- Choose combine mode for taskbar buttons and labels. (W11 only)
|
||||
- Choose how app icons are shown on the taskbar when using multiple monitors.
|
||||
- Choose combine mode for taskbar buttons and labels.
|
||||
|
||||
#### File Explorer
|
||||
|
||||
- Change the default location that File Explorer opens to.
|
||||
- Show file extensions for known file types.
|
||||
- Show hidden files, folders and drives.
|
||||
- Hide the Home or Gallery section from the File Explorer navigation pane. (W11 only)
|
||||
- Hide the Home or Gallery section from the File Explorer navigation pane.
|
||||
- Hide duplicate removable drive entries from the File Explorer navigation pane, so only the entry under 'This PC' remains.
|
||||
- Add all common folders (Desktop, Downloads, etc.) back to 'This PC' in File Explorer. (W11 only)
|
||||
- Hide the 3D objects, music or OneDrive folder from the File Explorer navigation pane. (W10 only)
|
||||
- Hide the 'Include in library', 'Give access to' and 'Share' options from the context menu. (W10 only)
|
||||
- Add all common folders (Desktop, Downloads, etc.) back to 'This PC' in File Explorer.
|
||||
- Hide the 3D objects, music or OneDrive folder from the File Explorer navigation pane.
|
||||
- Hide the 'Include in library', 'Give access to' and 'Share' options from the context menu.
|
||||
|
||||
#### Multi-tasking
|
||||
|
||||
- Disable window snapping.
|
||||
- Disable Snap Assist suggestions when snapping a window.
|
||||
- Disable Snap Layout suggestions when dragging windows to the top of screen and when hovering on the maximize button.
|
||||
- Change if tabs are shown when snapping or pressing Alt+Tab.
|
||||
|
||||
#### Optional Windows Features
|
||||
|
||||
- Enable Windows Sandbox, a lightweight desktop environment for safely running applications in isolation.
|
||||
- Enable Windows Subsystem for Linux which allows you to run a Linux environment directly on Windows.
|
||||
|
||||
#### Other
|
||||
|
||||
@@ -163,6 +183,10 @@ Below is an overview of the key features and functionality offered by Win11Deblo
|
||||
- Option to [apply changes to a different user](https://github.com/Raphire/Win11Debloat/wiki/Advanced-Features#running-as-another-user), instead of the currently logged in user.
|
||||
- [Sysprep mode](https://github.com/Raphire/Win11Debloat/wiki/Advanced-Features#sysprep-mode) to apply changes to the Windows Default user profile. Which ensures, all new users will have the changes automatically applied to them.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions of all kinds! Please see our [Contributing Guidelines](/.github/CONTRIBUTING.md) for detailed instructions on how to get started and best practices for contributing.
|
||||
|
||||
## License
|
||||
|
||||
Win11Debloat is licensed under the MIT license. See the LICENSE file for more information.
|
||||
|
||||
4
Regfiles/Disable_AI_Service_Auto_Start.reg
Normal file
4
Regfiles/Disable_AI_Service_Auto_Start.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WSAIFabricSvc]
|
||||
"Start"=dword:00000003
|
||||
Binary file not shown.
5
Regfiles/Disable_Find_My_Device.reg
Normal file
5
Regfiles/Disable_Find_My_Device.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Disable Find My Device location tracking
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\FindMyDevice]
|
||||
"AllowFindMyDevice"=dword:00000000
|
||||
4
Regfiles/Disable_Location_Services.reg
Normal file
4
Regfiles/Disable_Location_Services.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\LocationAndSensors]
|
||||
"DisableLocation"=dword:00000001
|
||||
5
Regfiles/Disable_Search_Highlights.reg
Normal file
5
Regfiles/Disable_Search_Highlights.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Disable Search Highlights (dynamic/branded content in Windows search box)
|
||||
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\SearchSettings]
|
||||
"IsDynamicSearchBoxEnabled"=dword:00000000
|
||||
5
Regfiles/Disable_Search_History.reg
Normal file
5
Regfiles/Disable_Search_History.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Disable Windows search history
|
||||
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\SearchSettings]
|
||||
"IsDeviceSearchHistoryEnabled"=dword:00000000
|
||||
BIN
Regfiles/Disable_Snap_Assist.reg
Normal file
BIN
Regfiles/Disable_Snap_Assist.reg
Normal file
Binary file not shown.
BIN
Regfiles/Disable_Snap_Layouts.reg
Normal file
BIN
Regfiles/Disable_Snap_Layouts.reg
Normal file
Binary file not shown.
4
Regfiles/Disable_Start_All_Apps.reg
Normal file
4
Regfiles/Disable_Start_All_Apps.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
|
||||
"NoStartMenuMorePrograms"=dword:00000001
|
||||
5
Regfiles/Disable_Storage_Sense.reg
Normal file
5
Regfiles/Disable_Storage_Sense.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Disable Storage Sense
|
||||
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\StorageSense\Parameters\StoragePolicy]
|
||||
"01"=dword:00000000
|
||||
4
Regfiles/Disable_Window_Snapping.reg
Normal file
4
Regfiles/Disable_Window_Snapping.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_CURRENT_USER\Control Panel\Desktop]
|
||||
"WindowArrangementActive"="0"
|
||||
4
Regfiles/Hide_Tabs_In_Alt_Tab.reg
Normal file
4
Regfiles/Hide_Tabs_In_Alt_Tab.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
|
||||
"MultiTaskingAltTabFilter"=dword:00000003
|
||||
4
Regfiles/Show_20_Tabs_In_Alt_Tab.reg
Normal file
4
Regfiles/Show_20_Tabs_In_Alt_Tab.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
|
||||
"MultiTaskingAltTabFilter"=dword:00000000
|
||||
4
Regfiles/Show_3_Tabs_In_Alt_Tab.reg
Normal file
4
Regfiles/Show_3_Tabs_In_Alt_Tab.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
|
||||
"MultiTaskingAltTabFilter"=dword:00000002
|
||||
4
Regfiles/Show_5_Tabs_In_Alt_Tab.reg
Normal file
4
Regfiles/Show_5_Tabs_In_Alt_Tab.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
|
||||
"MultiTaskingAltTabFilter"=dword:00000001
|
||||
4
Regfiles/Sysprep/Disable_AI_Service_Auto_Start.reg
Normal file
4
Regfiles/Sysprep/Disable_AI_Service_Auto_Start.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WSAIFabricSvc]
|
||||
"Start"=dword:00000003
|
||||
Binary file not shown.
5
Regfiles/Sysprep/Disable_Find_My_Device.reg
Normal file
5
Regfiles/Sysprep/Disable_Find_My_Device.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Disable Find My Device location tracking
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\FindMyDevice]
|
||||
"AllowFindMyDevice"=dword:00000000
|
||||
4
Regfiles/Sysprep/Disable_Location_Services.reg
Normal file
4
Regfiles/Sysprep/Disable_Location_Services.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\LocationAndSensors]
|
||||
"DisableLocation"=dword:00000001
|
||||
5
Regfiles/Sysprep/Disable_Search_Highlights.reg
Normal file
5
Regfiles/Sysprep/Disable_Search_Highlights.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Disable Search Highlights (dynamic/branded content in Windows search box)
|
||||
[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\SearchSettings]
|
||||
"IsDynamicSearchBoxEnabled"=dword:00000000
|
||||
5
Regfiles/Sysprep/Disable_Search_History.reg
Normal file
5
Regfiles/Sysprep/Disable_Search_History.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Disable Windows search history
|
||||
[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\SearchSettings]
|
||||
"IsDeviceSearchHistoryEnabled"=dword:00000000
|
||||
BIN
Regfiles/Sysprep/Disable_Snap_Assist.reg
Normal file
BIN
Regfiles/Sysprep/Disable_Snap_Assist.reg
Normal file
Binary file not shown.
BIN
Regfiles/Sysprep/Disable_Snap_Layouts.reg
Normal file
BIN
Regfiles/Sysprep/Disable_Snap_Layouts.reg
Normal file
Binary file not shown.
4
Regfiles/Sysprep/Disable_Start_All_Apps.reg
Normal file
4
Regfiles/Sysprep/Disable_Start_All_Apps.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
|
||||
"NoStartMenuMorePrograms"=dword:00000001
|
||||
6
Regfiles/Sysprep/Disable_Storage_Sense.reg
Normal file
6
Regfiles/Sysprep/Disable_Storage_Sense.reg
Normal file
@@ -0,0 +1,6 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Disable Storage Sense
|
||||
[HKEY_USERS\Default\SOFTWARE\Microsoft\Windows\CurrentVersion\StorageSense\Parameters\StoragePolicy]
|
||||
"01"=dword:00000000
|
||||
|
||||
4
Regfiles/Sysprep/Disable_Window_Snapping.reg
Normal file
4
Regfiles/Sysprep/Disable_Window_Snapping.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[hkey_users\default\Control Panel\Desktop]
|
||||
"WindowArrangementActive"="0"
|
||||
4
Regfiles/Sysprep/Hide_Tabs_In_Alt_Tab.reg
Normal file
4
Regfiles/Sysprep/Hide_Tabs_In_Alt_Tab.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[hkey_users\default\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
|
||||
"MultiTaskingAltTabFilter"=dword:00000003
|
||||
4
Regfiles/Sysprep/Show_20_Tabs_In_Alt_Tab.reg
Normal file
4
Regfiles/Sysprep/Show_20_Tabs_In_Alt_Tab.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[hkey_users\default\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
|
||||
"MultiTaskingAltTabFilter"=dword:00000000
|
||||
4
Regfiles/Sysprep/Show_3_Tabs_In_Alt_Tab.reg
Normal file
4
Regfiles/Sysprep/Show_3_Tabs_In_Alt_Tab.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[hkey_users\default\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
|
||||
"MultiTaskingAltTabFilter"=dword:00000002
|
||||
4
Regfiles/Sysprep/Show_5_Tabs_In_Alt_Tab.reg
Normal file
4
Regfiles/Sysprep/Show_5_Tabs_In_Alt_Tab.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[hkey_users\default\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
|
||||
"MultiTaskingAltTabFilter"=dword:00000001
|
||||
4
Regfiles/Undo/Enable_AI_Service_Auto_Start.reg
Normal file
4
Regfiles/Undo/Enable_AI_Service_Auto_Start.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WSAIFabricSvc]
|
||||
"Start"=dword:00000002
|
||||
Binary file not shown.
5
Regfiles/Undo/Enable_Find_My_Device.reg
Normal file
5
Regfiles/Undo/Enable_Find_My_Device.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Restore Find My Device to Windows default
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\FindMyDevice]
|
||||
"AllowFindMyDevice"=-
|
||||
@@ -17,4 +17,4 @@ Windows Registry Editor Version 5.00
|
||||
"URL Protocol"=""
|
||||
"NoOpenWith"=-
|
||||
|
||||
[-HKEY_CLASSES_ROOT\ms-gamebar\shell\open\command]
|
||||
[-HKEY_CLASSES_ROOT\ms-gamebarservices\shell\open\command]
|
||||
4
Regfiles/Undo/Enable_Location_Services.reg
Normal file
4
Regfiles/Undo/Enable_Location_Services.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\LocationAndSensors]
|
||||
"DisableLocation"=-
|
||||
5
Regfiles/Undo/Enable_Search_Highlights.reg
Normal file
5
Regfiles/Undo/Enable_Search_Highlights.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Re-enable Search Highlights (dynamic/branded content in Windows search box)
|
||||
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\SearchSettings]
|
||||
"IsDynamicSearchBoxEnabled"=dword:00000001
|
||||
5
Regfiles/Undo/Enable_Search_History.reg
Normal file
5
Regfiles/Undo/Enable_Search_History.reg
Normal file
@@ -0,0 +1,5 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Disable Windows search history
|
||||
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\SearchSettings]
|
||||
"IsDeviceSearchHistoryEnabled"=dword:00000001
|
||||
BIN
Regfiles/Undo/Enable_Snap_Assist.reg
Normal file
BIN
Regfiles/Undo/Enable_Snap_Assist.reg
Normal file
Binary file not shown.
BIN
Regfiles/Undo/Enable_Snap_Layouts.reg
Normal file
BIN
Regfiles/Undo/Enable_Snap_Layouts.reg
Normal file
Binary file not shown.
7
Regfiles/Undo/Enable_Start_All_Apps.reg
Normal file
7
Regfiles/Undo/Enable_Start_All_Apps.reg
Normal file
@@ -0,0 +1,7 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
|
||||
"NoStartMenuMorePrograms"=-
|
||||
|
||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer]
|
||||
"NoStartMenuMorePrograms"=-
|
||||
6
Regfiles/Undo/Enable_Storage_Sense.reg
Normal file
6
Regfiles/Undo/Enable_Storage_Sense.reg
Normal file
@@ -0,0 +1,6 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
; Enable Storage Sense
|
||||
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\StorageSense\Parameters\StoragePolicy]
|
||||
"01"=dword:00000001
|
||||
|
||||
4
Regfiles/Undo/Enable_Window_Snapping.reg
Normal file
4
Regfiles/Undo/Enable_Window_Snapping.reg
Normal file
@@ -0,0 +1,4 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_CURRENT_USER\Control Panel\Desktop]
|
||||
"WindowArrangementActive"="1"
|
||||
5
Run.bat
5
Run.bat
@@ -4,7 +4,10 @@ setlocal EnableDelayedExpansion
|
||||
:: Set Windows Terminal installation paths. (Default and Scoop installation)
|
||||
set "wtDefaultPath=%LOCALAPPDATA%\Microsoft\WindowsApps\wt.exe"
|
||||
set "wtScoopPath=%USERPROFILE%\scoop\apps\windows-terminal\current\wt.exe"
|
||||
set "logFile=%~dp0Win11Debloat.log"
|
||||
set "logFile=%~dp0Logs\Win11Debloat-Run.log"
|
||||
|
||||
:: Ensure Logs folder exists
|
||||
if not exist "%~dp0Logs" mkdir "%~dp0Logs"
|
||||
|
||||
:: Determine which terminal exists
|
||||
if exist "%wtDefaultPath%" (
|
||||
|
||||
170
Schemas/AboutWindow.xaml
Normal file
170
Schemas/AboutWindow.xaml
Normal file
@@ -0,0 +1,170 @@
|
||||
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="About Win11Debloat"
|
||||
Width="500"
|
||||
SizeToContent="Height"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None"
|
||||
AllowsTransparency="True"
|
||||
Background="Transparent"
|
||||
Topmost="True"
|
||||
ShowInTaskbar="False">
|
||||
|
||||
<Border BorderBrush="{DynamicResource BorderColor}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Background="{DynamicResource CardBgColor}"
|
||||
Margin="25">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="Black"
|
||||
Opacity="0.15"
|
||||
BlurRadius="20"
|
||||
ShadowDepth="0"
|
||||
Direction="0"/>
|
||||
</Border.Effect>
|
||||
|
||||
<Grid Margin="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Title Bar -->
|
||||
<Grid Grid.Row="0" x:Name="TitleBar" Height="48" Background="Transparent">
|
||||
<TextBlock Text="About Win11Debloat"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
FontSize="18"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"
|
||||
Margin="20,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Message Content -->
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Message Text -->
|
||||
<Grid Grid.Row="0" Margin="24,12,24,20">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Version -->
|
||||
<TextBlock Grid.Row="0" Grid.Column="0"
|
||||
Text="Version:"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
FontWeight="SemiBold"
|
||||
Margin="0,0,16,8"/>
|
||||
<TextBlock x:Name="VersionText"
|
||||
Grid.Row="0" Grid.Column="1"
|
||||
Text="0.0.0"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
Margin="0,0,0,8"/>
|
||||
|
||||
<!-- Author -->
|
||||
<TextBlock Grid.Row="1" Grid.Column="0"
|
||||
Text="Author:"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
FontWeight="SemiBold"
|
||||
Margin="0,0,16,8"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1"
|
||||
Text="Raphire"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
Margin="0,0,0,8"/>
|
||||
|
||||
<!-- Project Link -->
|
||||
<TextBlock Grid.Row="2" Grid.Column="0"
|
||||
Text="Project:"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
FontWeight="SemiBold"
|
||||
Margin="0,0,16,0"/>
|
||||
<TextBlock x:Name="ProjectLink"
|
||||
Grid.Row="2" Grid.Column="1"
|
||||
Text="https://github.com/Raphire/Win11Debloat"
|
||||
FontSize="14"
|
||||
Style="{DynamicResource HyperlinkStyle}"
|
||||
Margin="0,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Separator -->
|
||||
<Border Grid.Row="1"
|
||||
Height="1"
|
||||
Background="{DynamicResource BorderColor}"
|
||||
Margin="10,0"/>
|
||||
|
||||
<!-- Content -->
|
||||
<StackPanel Grid.Row="2" Margin="24,20">
|
||||
<!-- Donation Message -->
|
||||
<TextBlock Text="Win11Debloat is a passion project that I maintain in my free time. If you've found this tool useful, please consider making a small donation to support its development. I really appreciate it!"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="0,0,0,15"/>
|
||||
|
||||
<!-- Ko-fi Link -->
|
||||
<Grid HorizontalAlignment="Left">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock x:Name="KofiLinkIcon"
|
||||
Grid.Column="0"
|
||||
FontSize="16"
|
||||
Style="{DynamicResource HyperlinkStyle}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="SemiBold"
|
||||
FontFamily="Segoe Fluent Icons"
|
||||
Text=""
|
||||
Foreground="{DynamicResource CloseHover}"
|
||||
Margin="0,0,8,0"/>
|
||||
|
||||
<TextBlock x:Name="KofiLink"
|
||||
Grid.Column="1"
|
||||
FontSize="16"
|
||||
Style="{DynamicResource HyperlinkStyle}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="SemiBold"
|
||||
Text="Support me on Ko-fi"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- Button Panel -->
|
||||
<Border Grid.Row="2"
|
||||
Background="{DynamicResource BgColor}"
|
||||
BorderBrush="{DynamicResource BorderColor}"
|
||||
BorderThickness="0,1,0,0"
|
||||
Padding="16,12"
|
||||
CornerRadius="0,0,8,8">
|
||||
<StackPanel x:Name="ButtonPanel"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button x:Name="CloseButton"
|
||||
Content="Close"
|
||||
Height="32" MinWidth="80" Margin="4,0"
|
||||
Style="{DynamicResource SecondaryButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
@@ -9,43 +9,6 @@
|
||||
Background="Transparent"
|
||||
Foreground="{DynamicResource FgColor}">
|
||||
<Window.Resources>
|
||||
<!-- ScrollBar Style -->
|
||||
<Style TargetType="{x:Type ScrollBar}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Width" Value="8"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ScrollBar}">
|
||||
<Grid>
|
||||
<Track Name="PART_Track" IsDirectionReversed="true">
|
||||
<Track.Thumb>
|
||||
<Thumb>
|
||||
<Thumb.Style>
|
||||
<Style TargetType="Thumb">
|
||||
<Setter Property="Background" Value="{DynamicResource ScrollBarThumbColor}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Border Background="{TemplateBinding Background}" CornerRadius="4"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ScrollBarThumbHoverColor}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Thumb.Style>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
</Track>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- CheckBox Style -->
|
||||
<Style TargetType="CheckBox">
|
||||
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
|
||||
@@ -94,84 +57,6 @@
|
||||
<Style x:Key="AppsPanelCheckBoxStyle" TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
|
||||
<Setter Property="Margin" Value="2,3,2,3"/>
|
||||
</Style>
|
||||
|
||||
<!-- Button Style -->
|
||||
<Style x:Key="Win11Button" TargetType="Button">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBg}"/>
|
||||
<Setter Property="Foreground" Value="white"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBg}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonDisabled}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDisabled}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonTextDisabled}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonHover}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonHover}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonPressed}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonPressed}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- Secondary Button Style -->
|
||||
<Style x:Key="Win11ButtonSecondary" TargetType="Button">
|
||||
<Setter Property="Background" Value="{DynamicResource SecondaryButtonBg}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderColor}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,1"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{DynamicResource SecondaryButtonDisabled}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BorderColor}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource SecondaryButtonTextDisabled}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource SecondaryButtonHover}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderColor}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource SecondaryButtonPressed}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderColor}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- Title Bar Button Style -->
|
||||
<Style x:Key="TitleBarButton" TargetType="Button">
|
||||
@@ -205,7 +90,15 @@
|
||||
<Border BorderBrush="{DynamicResource BorderColor}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Background="{DynamicResource BgColor}">
|
||||
Background="{DynamicResource BgColor}"
|
||||
Margin="25">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="Black"
|
||||
Opacity="0.15"
|
||||
BlurRadius="20"
|
||||
ShadowDepth="0"
|
||||
Direction="0"/>
|
||||
</Border.Effect>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
@@ -268,11 +161,21 @@
|
||||
<Grid Margin="0,8,10,10">
|
||||
<CheckBox x:Name="OnlyInstalledBox" Content="Only show installed apps" Foreground="{DynamicResource FgColor}" AutomationProperties.Name="Only show installed apps"/>
|
||||
</Grid>
|
||||
<Button x:Name="ConfirmBtn" Width="80" Height="32" Margin="0,0,10,0" Content="Confirm" Style="{StaticResource Win11Button}" AutomationProperties.Name="Confirm"/>
|
||||
<Button x:Name="CancelBtn" Width="80" Height="32" Content="Cancel" Style="{StaticResource Win11ButtonSecondary}" IsCancel="True" AutomationProperties.Name="Cancel"/>
|
||||
<Button x:Name="ConfirmBtn" Width="80" Height="32" Margin="0,0,10,0" Content="Confirm" Style="{DynamicResource PrimaryButtonStyle}" AutomationProperties.Name="Confirm"/>
|
||||
<Button x:Name="CancelBtn" Width="80" Height="32" Content="Cancel" Style="{DynamicResource SecondaryButtonStyle}" IsCancel="True" AutomationProperties.Name="Cancel"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- Modal Overlay for MessageBoxes -->
|
||||
<Rectangle x:Name="ModalOverlay"
|
||||
Grid.RowSpan="2"
|
||||
Fill="#80000000"
|
||||
Visibility="Collapsed"
|
||||
Panel.ZIndex="1000"
|
||||
RadiusX="8"
|
||||
RadiusY="8"
|
||||
Margin="-1"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
203
Schemas/ApplyChangesWindow.xaml
Normal file
203
Schemas/ApplyChangesWindow.xaml
Normal file
@@ -0,0 +1,203 @@
|
||||
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Apply Changes"
|
||||
Width="500"
|
||||
SizeToContent="Height"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None"
|
||||
AllowsTransparency="True"
|
||||
Background="Transparent"
|
||||
Topmost="True"
|
||||
ShowInTaskbar="False">
|
||||
|
||||
<Border BorderBrush="{DynamicResource BorderColor}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Background="{DynamicResource CardBgColor}"
|
||||
Margin="25">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="Black"
|
||||
Opacity="0.15"
|
||||
BlurRadius="20"
|
||||
ShadowDepth="0"
|
||||
Direction="0"/>
|
||||
</Border.Effect>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Close/Cancel button (top right) -->
|
||||
<Button x:Name="ApplyCancelBtn" Grid.Row="0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Top"
|
||||
Width="36" Height="32"
|
||||
BorderThickness="0"
|
||||
Cursor="Hand"
|
||||
ToolTip="Cancel"
|
||||
AutomationProperties.Name="Cancel">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}" BorderThickness="0" CornerRadius="0,8,0,0">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Button.Template>
|
||||
<Button.Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource CloseHover}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<TextBlock Text="" FontFamily="Segoe Fluent Icons" FontSize="10"/>
|
||||
</Button>
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.RowSpan="2">
|
||||
<!-- In-progress content -->
|
||||
<StackPanel x:Name="ApplyInProgressPanel">
|
||||
<StackPanel Margin="32,24">
|
||||
<!-- Loading icon (spinning) -->
|
||||
<TextBlock x:Name="ApplySpinnerIcon"
|
||||
Text=""
|
||||
FontFamily="Segoe Fluent Icons"
|
||||
FontSize="36"
|
||||
Foreground="{DynamicResource ButtonBg}"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,0,0,16"
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<TextBlock.RenderTransform>
|
||||
<RotateTransform x:Name="SpinnerRotation" Angle="0"/>
|
||||
</TextBlock.RenderTransform>
|
||||
<TextBlock.Triggers>
|
||||
<EventTrigger RoutedEvent="Loaded">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="SpinnerRotation"
|
||||
Storyboard.TargetProperty="Angle"
|
||||
From="0" To="360"
|
||||
Duration="0:0:1.5"
|
||||
RepeatBehavior="Forever"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</TextBlock.Triggers>
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Text="Applying Changes"
|
||||
Style="{DynamicResource ModalTitleStyle}"/>
|
||||
|
||||
<!-- Current step name -->
|
||||
<TextBlock x:Name="ApplyStepName"
|
||||
Text="Preparing..."
|
||||
Style="{DynamicResource ModalSubtextStyle}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
MaxWidth="430"/>
|
||||
</StackPanel>
|
||||
|
||||
<Border Background="{DynamicResource BgColor}"
|
||||
BorderBrush="{DynamicResource BorderColor}"
|
||||
BorderThickness="0,1,0,0"
|
||||
Padding="16,12"
|
||||
CornerRadius="0,0,8,8">
|
||||
<StackPanel>
|
||||
|
||||
<!-- Progress bar -->
|
||||
<ProgressBar x:Name="ApplyProgressBar"
|
||||
Style="{DynamicResource ApplyProgressBarStyle}"
|
||||
Minimum="0" Maximum="100" Value="0"
|
||||
Margin="0,2,0,8"/>
|
||||
|
||||
<!-- Step counter -->
|
||||
<TextBlock x:Name="ApplyStepCounter"
|
||||
Text="Step 0 of 0"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
HorizontalAlignment="Right"
|
||||
Opacity="0.8"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Completion content -->
|
||||
<StackPanel x:Name="ApplyCompletionPanel" Visibility="Collapsed">
|
||||
<StackPanel Margin="32,24">
|
||||
<!-- Success icon -->
|
||||
<TextBlock x:Name="ApplyCompletionIcon"
|
||||
Text=""
|
||||
FontFamily="Segoe Fluent Icons"
|
||||
FontSize="40"
|
||||
Foreground="{DynamicResource ButtonBg}"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,0,0,12"/>
|
||||
|
||||
<TextBlock x:Name="ApplyCompletionTitle"
|
||||
Text="Changes Applied"
|
||||
Style="{DynamicResource ModalTitleStyle}"/>
|
||||
|
||||
<TextBlock x:Name="ApplyCompletionMessage"
|
||||
Text="Please note that some changes will only take effect after a reboot. Thanks for using Win11Debloat!"
|
||||
TextWrapping="Wrap"
|
||||
Style="{DynamicResource ModalSubtextStyle}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Reboot required section -->
|
||||
<Border x:Name="ApplyRebootPanel"
|
||||
Visibility="Collapsed"
|
||||
BorderBrush="{DynamicResource BorderColor}"
|
||||
HorizontalAlignment="Center"
|
||||
BorderThickness="0,1,0,1"
|
||||
Padding="24,12,24,14">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,6">
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe Fluent Icons"
|
||||
FontSize="14"
|
||||
Foreground="#e8912d"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,8,0"/>
|
||||
<TextBlock Text="A reboot is required for these changes to take effect:"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<StackPanel x:Name="ApplyRebootList" Margin="22,0,0,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Button Panel -->
|
||||
<Border Background="{DynamicResource BgColor}"
|
||||
BorderBrush="{DynamicResource BorderColor}"
|
||||
BorderThickness="0,1,0,0"
|
||||
Padding="16,12"
|
||||
CornerRadius="0,0,8,8">
|
||||
<StackPanel x:Name="ButtonPanel"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Center">
|
||||
<Button x:Name="ApplyKofiBtn" Width="210" Height="32"
|
||||
Style="{DynamicResource SecondaryButtonStyle}"
|
||||
Margin="0,0,12,0"
|
||||
AutomationProperties.Name="Support the creator">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="" FontFamily="Segoe Fluent Icons" FontSize="14" VerticalAlignment="Center" Margin="0,0,8,-1"/>
|
||||
<TextBlock Text="Support the creator" VerticalAlignment="Center" FontSize="14" Margin="0,0,0,1"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button x:Name="ApplyCloseBtn" Width="100" Height="32"
|
||||
Style="{DynamicResource PrimaryButtonStyle}"
|
||||
AutomationProperties.Name="Close">
|
||||
<TextBlock Text="Close" VerticalAlignment="Center" FontSize="14" Margin="0,0,0,1"/>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
41
Schemas/BubbleHint.xaml
Normal file
41
Schemas/BubbleHint.xaml
Normal file
@@ -0,0 +1,41 @@
|
||||
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Name="BubblePanel"
|
||||
SnapsToDevicePixels="True">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Name="BubbleBorder"
|
||||
Grid.Row="0"
|
||||
Background="{DynamicResource CardBgColor}"
|
||||
BorderBrush="{DynamicResource ButtonBorderColor}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Padding="10,7,10,7">
|
||||
<TextBlock Name="BubbleText"
|
||||
Text="View the selected changes here"
|
||||
TextWrapping="Wrap"
|
||||
MaxWidth="260"
|
||||
Foreground="{DynamicResource FgColor}"/>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,-1,0,0"
|
||||
Width="12"
|
||||
Height="8">
|
||||
<Polygon Name="BubblePointer"
|
||||
Points="0,0 12,0 6,7"
|
||||
Fill="{DynamicResource CardBgColor}"
|
||||
Stroke="{DynamicResource ButtonBorderColor}"
|
||||
StrokeThickness="1"
|
||||
Stretch="Fill"/>
|
||||
|
||||
<Rectangle VerticalAlignment="Top"
|
||||
Height="2"
|
||||
Margin="1,-1,1,0"
|
||||
Fill="{DynamicResource CardBgColor}"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
File diff suppressed because it is too large
Load Diff
99
Schemas/MessageBoxWindow.xaml
Normal file
99
Schemas/MessageBoxWindow.xaml
Normal file
@@ -0,0 +1,99 @@
|
||||
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="MessageBox"
|
||||
Width="440"
|
||||
SizeToContent="Height"
|
||||
MaxHeight="501"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None"
|
||||
AllowsTransparency="True"
|
||||
Background="Transparent"
|
||||
Topmost="True"
|
||||
ShowInTaskbar="False">
|
||||
|
||||
<Border BorderBrush="{DynamicResource BorderColor}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
Background="{DynamicResource CardBgColor}"
|
||||
Margin="25">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="Black"
|
||||
Opacity="0.15"
|
||||
BlurRadius="20"
|
||||
ShadowDepth="0"
|
||||
Direction="0"/>
|
||||
</Border.Effect>
|
||||
|
||||
<Grid Margin="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Title Bar -->
|
||||
<Grid Grid.Row="0" x:Name="TitleBar" Height="40" Background="Transparent">
|
||||
<TextBlock x:Name="TitleText"
|
||||
Text="Message"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"
|
||||
Margin="16,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Message Content -->
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" MaxHeight="500" Padding="0" Margin="20,12,1,20">
|
||||
<Grid Margin="0,0,20,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Icon -->
|
||||
<TextBlock x:Name="IconText"
|
||||
Grid.Column="0"
|
||||
FontFamily="Segoe Fluent Icons"
|
||||
FontSize="24"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="4,2,14,0"
|
||||
Visibility="Collapsed"/>
|
||||
|
||||
<!-- Message Text -->
|
||||
<TextBlock x:Name="MessageText"
|
||||
Grid.Column="1"
|
||||
Text="Message content goes here"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="14"
|
||||
LineHeight="20"
|
||||
Foreground="{DynamicResource FgColor}"
|
||||
VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Button Panel -->
|
||||
<Border Grid.Row="2"
|
||||
Background="{DynamicResource BgColor}"
|
||||
BorderBrush="{DynamicResource BorderColor}"
|
||||
BorderThickness="0,1,0,0"
|
||||
Padding="16,12"
|
||||
CornerRadius="0,0,8,8">
|
||||
<StackPanel x:Name="ButtonPanel"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button x:Name="Button1"
|
||||
Content="OK"
|
||||
Height="32" MinWidth="80" Margin="4,0"
|
||||
Style="{DynamicResource PrimaryButtonStyle}"/>
|
||||
<Button x:Name="Button2"
|
||||
Content="Cancel"
|
||||
Height="32" MinWidth="80" Margin="4,0"
|
||||
Style="{DynamicResource SecondaryButtonStyle}"
|
||||
Visibility="Collapsed"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
165
Schemas/SharedStyles.xaml
Normal file
165
Schemas/SharedStyles.xaml
Normal file
@@ -0,0 +1,165 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<!-- Primary Button Style -->
|
||||
<Style x:Key="PrimaryButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBg}"/>
|
||||
<Setter Property="Foreground" Value="white"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBg}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonDisabled}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDisabled}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonTextDisabled}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonHover}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonHover}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonPressed}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonPressed}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- Secondary Button Style -->
|
||||
<Style x:Key="SecondaryButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="{DynamicResource SecondaryButtonBg}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderColor}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,1"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{DynamicResource SecondaryButtonDisabled}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource BorderColor}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource SecondaryButtonTextDisabled}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource SecondaryButtonHover}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderColor}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource SecondaryButtonPressed}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderColor}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- Hyperlink Style -->
|
||||
<Style x:Key="HyperlinkStyle" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonBg}"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonHover}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- ProgressBar Style -->
|
||||
<Style x:Key="ApplyProgressBarStyle" TargetType="ProgressBar">
|
||||
<Setter Property="Background" Value="{DynamicResource ButtonBorderColor}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource ButtonBg}"/>
|
||||
<Setter Property="Height" Value="6"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ProgressBar">
|
||||
<Grid>
|
||||
<Border x:Name="PART_Track" Background="{TemplateBinding Background}" CornerRadius="3" Height="{TemplateBinding Height}"/>
|
||||
<Border x:Name="PART_Indicator" Background="{TemplateBinding Foreground}" CornerRadius="3" HorizontalAlignment="Left" Height="{TemplateBinding Height}"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Modal Title Style -->
|
||||
<Style x:Key="ModalTitleStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="20"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="0,0,0,8"/>
|
||||
</Style>
|
||||
|
||||
<!-- Modal Subtext Style -->
|
||||
<Style x:Key="ModalSubtextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
|
||||
<Setter Property="Opacity" Value="0.8"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="TextAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<!-- ScrollBar Style -->
|
||||
<Style TargetType="{x:Type ScrollBar}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Width" Value="8"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ScrollBar}">
|
||||
<Grid>
|
||||
<Track Name="PART_Track" IsDirectionReversed="true">
|
||||
<Track.Thumb>
|
||||
<Thumb>
|
||||
<Thumb.Style>
|
||||
<Style TargetType="Thumb">
|
||||
<Setter Property="Background" Value="{DynamicResource ScrollBarThumbColor}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Border Background="{TemplateBinding Background}" CornerRadius="4"/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource ScrollBarThumbHoverColor}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Thumb.Style>
|
||||
</Thumb>
|
||||
</Track.Thumb>
|
||||
</Track>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
57
Scripts/AppRemoval/ForceRemoveEdge.ps1
Normal file
57
Scripts/AppRemoval/ForceRemoveEdge.ps1
Normal file
@@ -0,0 +1,57 @@
|
||||
# Forcefully removes Microsoft Edge using its uninstaller
|
||||
# Credit: Based on work from loadstring1 & ave9858
|
||||
function ForceRemoveEdge {
|
||||
Write-Host "> Forcefully uninstalling Microsoft Edge..."
|
||||
|
||||
$regView = [Microsoft.Win32.RegistryView]::Registry32
|
||||
$hklm = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $regView)
|
||||
$hklm.CreateSubKey('SOFTWARE\Microsoft\EdgeUpdateDev').SetValue('AllowUninstall', '')
|
||||
|
||||
# Create stub (This somehow allows uninstalling Edge)
|
||||
$edgeStub = "$env:SystemRoot\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe"
|
||||
New-Item $edgeStub -ItemType Directory | Out-Null
|
||||
New-Item "$edgeStub\MicrosoftEdge.exe" | Out-Null
|
||||
|
||||
# Remove edge
|
||||
$uninstallRegKey = $hklm.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft Edge')
|
||||
if ($null -ne $uninstallRegKey) {
|
||||
Write-Host "Running uninstaller..."
|
||||
$uninstallString = $uninstallRegKey.GetValue('UninstallString') + ' --force-uninstall'
|
||||
Invoke-NonBlocking -ScriptBlock {
|
||||
param($cmd)
|
||||
Start-Process cmd.exe "/c $cmd" -WindowStyle Hidden -Wait
|
||||
} -ArgumentList $uninstallString
|
||||
|
||||
Write-Host "Removing leftover files..."
|
||||
|
||||
$edgePaths = @(
|
||||
"$env:ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk",
|
||||
"$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\Microsoft Edge.lnk",
|
||||
"$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Microsoft Edge.lnk",
|
||||
"$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Tombstones\Microsoft Edge.lnk",
|
||||
"$env:PUBLIC\Desktop\Microsoft Edge.lnk",
|
||||
"$env:USERPROFILE\Desktop\Microsoft Edge.lnk",
|
||||
"$edgeStub"
|
||||
)
|
||||
|
||||
foreach ($path in $edgePaths) {
|
||||
if (Test-Path -Path $path) {
|
||||
Remove-Item -Path $path -Force -Recurse -ErrorAction SilentlyContinue
|
||||
Write-Host " Removed $path" -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Cleaning up registry..."
|
||||
|
||||
# Remove MS Edge from autostart
|
||||
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "MicrosoftEdgeAutoLaunch_A9F6DCE4ABADF4F51CF45CD7129E3C6C" /f *>$null
|
||||
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "Microsoft Edge Update" /f *>$null
|
||||
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run" /v "MicrosoftEdgeAutoLaunch_A9F6DCE4ABADF4F51CF45CD7129E3C6C" /f *>$null
|
||||
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run" /v "Microsoft Edge Update" /f *>$null
|
||||
|
||||
Write-Host "Microsoft Edge was uninstalled"
|
||||
}
|
||||
else {
|
||||
Write-Host "Unable to forcefully uninstall Microsoft Edge, uninstaller could not be found" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
31
Scripts/AppRemoval/GetInstalledAppsViaWinget.ps1
Normal file
31
Scripts/AppRemoval/GetInstalledAppsViaWinget.ps1
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
# Run winget list and return installed apps.
|
||||
# Use -NonBlocking to keep the UI responsive (GUI mode) via Invoke-NonBlocking.
|
||||
function GetInstalledAppsViaWinget {
|
||||
param (
|
||||
[int]$TimeOut = 10,
|
||||
[switch]$NonBlocking
|
||||
)
|
||||
|
||||
if (-not $script:WingetInstalled) { return $null }
|
||||
|
||||
$fetchBlock = {
|
||||
param($timeOut)
|
||||
$job = Start-Job { return winget list --accept-source-agreements --disable-interactivity }
|
||||
$done = $job | Wait-Job -Timeout $timeOut
|
||||
if ($done) {
|
||||
$result = Receive-Job -Job $job
|
||||
Remove-Job -Job $job -ErrorAction SilentlyContinue
|
||||
return $result
|
||||
}
|
||||
Remove-Job -Job $job -Force -ErrorAction SilentlyContinue
|
||||
return $null
|
||||
}
|
||||
|
||||
if ($NonBlocking) {
|
||||
return Invoke-NonBlocking -ScriptBlock $fetchBlock -ArgumentList $TimeOut
|
||||
}
|
||||
else {
|
||||
return & $fetchBlock $TimeOut
|
||||
}
|
||||
}
|
||||
111
Scripts/AppRemoval/RemoveApps.ps1
Normal file
111
Scripts/AppRemoval/RemoveApps.ps1
Normal file
@@ -0,0 +1,111 @@
|
||||
# Removes apps specified during function call based on the target scope.
|
||||
function RemoveApps {
|
||||
param (
|
||||
$appslist
|
||||
)
|
||||
|
||||
# Determine target from script-level params, defaulting to AllUsers
|
||||
$targetUser = GetTargetUserForAppRemoval
|
||||
|
||||
$appIndex = 0
|
||||
$appCount = @($appsList).Count
|
||||
|
||||
Foreach ($app in $appsList) {
|
||||
if ($script:CancelRequested) {
|
||||
return
|
||||
}
|
||||
|
||||
$appIndex++
|
||||
|
||||
# Update step name and sub-progress to show which app is being removed (only for bulk removal)
|
||||
if ($script:ApplySubStepCallback -and $appCount -gt 1) {
|
||||
& $script:ApplySubStepCallback "Removing apps ($appIndex/$appCount)" $appIndex $appCount
|
||||
}
|
||||
|
||||
Write-Host "Attempting to remove $app..."
|
||||
|
||||
# Use WinGet only to remove OneDrive and Edge
|
||||
if (($app -eq "Microsoft.OneDrive") -or ($app -eq "Microsoft.Edge")) {
|
||||
if ($script:WingetInstalled -eq $false) {
|
||||
Write-Host "WinGet is either not installed or is outdated, $app could not be removed" -ForegroundColor Red
|
||||
continue
|
||||
}
|
||||
|
||||
$appName = $app -replace '\.', '_'
|
||||
|
||||
# Uninstall app via WinGet, or create a scheduled task to uninstall it later
|
||||
if ($script:Params.ContainsKey("User")) {
|
||||
ImportRegistryFile "Adding scheduled task to uninstall $app for user $(GetUserName)..." "Uninstall_$($appName).reg"
|
||||
}
|
||||
elseif ($script:Params.ContainsKey("Sysprep")) {
|
||||
ImportRegistryFile "Adding scheduled task to uninstall $app after for new users..." "Uninstall_$($appName).reg"
|
||||
}
|
||||
else {
|
||||
# Uninstall app via WinGet
|
||||
$wingetOutput = Invoke-NonBlocking -ScriptBlock {
|
||||
param($appId)
|
||||
winget uninstall --accept-source-agreements --disable-interactivity --id $appId
|
||||
} -ArgumentList $app
|
||||
|
||||
If (($app -eq "Microsoft.Edge") -and (Select-String -InputObject $wingetOutput -Pattern "Uninstall failed with exit code")) {
|
||||
Write-Host "Unable to uninstall Microsoft Edge via WinGet" -ForegroundColor Red
|
||||
|
||||
if ($script:GuiWindow) {
|
||||
$result = Show-MessageBox -Message 'Unable to uninstall Microsoft Edge via WinGet. Would you like to forcefully uninstall it? NOT RECOMMENDED!' -Title 'Force Uninstall Microsoft Edge?' -Button 'YesNo' -Icon 'Warning'
|
||||
|
||||
if ($result -eq 'Yes') {
|
||||
Write-Host ""
|
||||
ForceRemoveEdge
|
||||
}
|
||||
}
|
||||
elseif ($( Read-Host -Prompt "Would you like to forcefully uninstall Microsoft Edge? NOT RECOMMENDED! (y/n)" ) -eq 'y') {
|
||||
Write-Host ""
|
||||
ForceRemoveEdge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
# Use Remove-AppxPackage to remove all other apps
|
||||
$appPattern = '*' + $app + '*'
|
||||
|
||||
try {
|
||||
switch ($targetUser) {
|
||||
"AllUsers" {
|
||||
# Remove installed app for all existing users, and from OS image
|
||||
Invoke-NonBlocking -ScriptBlock {
|
||||
param($pattern)
|
||||
Get-AppxPackage -Name $pattern -AllUsers | Remove-AppxPackage -AllUsers -ErrorAction Continue
|
||||
Get-AppxProvisionedPackage -Online | Where-Object { $_.PackageName -like $pattern } | ForEach-Object { Remove-ProvisionedAppxPackage -Online -AllUsers -PackageName $_.PackageName }
|
||||
} -ArgumentList $appPattern
|
||||
}
|
||||
"CurrentUser" {
|
||||
# Remove installed app for current user only
|
||||
Invoke-NonBlocking -ScriptBlock {
|
||||
param($pattern)
|
||||
Get-AppxPackage -Name $pattern | Remove-AppxPackage -ErrorAction Continue
|
||||
} -ArgumentList $appPattern
|
||||
}
|
||||
default {
|
||||
# Target is a specific username - remove app for that user only
|
||||
Invoke-NonBlocking -ScriptBlock {
|
||||
param($pattern, $user)
|
||||
$userAccount = New-Object System.Security.Principal.NTAccount($user)
|
||||
$userSid = $userAccount.Translate([System.Security.Principal.SecurityIdentifier]).Value
|
||||
Get-AppxPackage -Name $pattern -User $userSid | Remove-AppxPackage -User $userSid -ErrorAction Continue
|
||||
} -ArgumentList @($appPattern, $targetUser)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
if ($DebugPreference -ne "SilentlyContinue") {
|
||||
Write-Host "Something went wrong while trying to remove $app" -ForegroundColor Yellow
|
||||
Write-Host $psitem.Exception.StackTrace -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
11
Scripts/CLI/AwaitKeyToExit.ps1
Normal file
11
Scripts/CLI/AwaitKeyToExit.ps1
Normal file
@@ -0,0 +1,11 @@
|
||||
function AwaitKeyToExit {
|
||||
# Suppress prompt if Silent parameter was passed
|
||||
if (-not $Silent) {
|
||||
Write-Output ""
|
||||
Write-Output "Press any key to exit..."
|
||||
$null = [System.Console]::ReadKey()
|
||||
}
|
||||
|
||||
Stop-Transcript
|
||||
Exit
|
||||
}
|
||||
20
Scripts/CLI/PrintHeader.ps1
Normal file
20
Scripts/CLI/PrintHeader.ps1
Normal file
@@ -0,0 +1,20 @@
|
||||
# Prints the header for the script
|
||||
function PrintHeader {
|
||||
param (
|
||||
$title
|
||||
)
|
||||
|
||||
$fullTitle = " Win11Debloat Script - $title"
|
||||
|
||||
if ($script:Params.ContainsKey("Sysprep")) {
|
||||
$fullTitle = "$fullTitle (Sysprep mode)"
|
||||
}
|
||||
else {
|
||||
$fullTitle = "$fullTitle (User: $(GetUserName))"
|
||||
}
|
||||
|
||||
Clear-Host
|
||||
Write-Host "-------------------------------------------------------------------------------------------"
|
||||
Write-Host $fullTitle
|
||||
Write-Host "-------------------------------------------------------------------------------------------"
|
||||
}
|
||||
66
Scripts/CLI/PrintPendingChanges.ps1
Normal file
66
Scripts/CLI/PrintPendingChanges.ps1
Normal file
@@ -0,0 +1,66 @@
|
||||
# Prints all pending changes that will be made by the script
|
||||
function PrintPendingChanges {
|
||||
Write-Output "Win11Debloat will make the following changes:"
|
||||
|
||||
if ($script:Params['CreateRestorePoint']) {
|
||||
Write-Output "- $($script:Features['CreateRestorePoint'].Label)"
|
||||
}
|
||||
foreach ($parameterName in $script:Params.Keys) {
|
||||
if ($script:ControlParams -contains $parameterName) {
|
||||
continue
|
||||
}
|
||||
|
||||
# Print parameter description
|
||||
switch ($parameterName) {
|
||||
'Apps' {
|
||||
continue
|
||||
}
|
||||
'CreateRestorePoint' {
|
||||
continue
|
||||
}
|
||||
'RemoveApps' {
|
||||
$appsList = GenerateAppsList
|
||||
|
||||
if ($appsList.Count -eq 0) {
|
||||
Write-Host "No valid apps were selected for removal" -ForegroundColor Yellow
|
||||
Write-Output ""
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Output "- Remove $($appsList.Count) apps:"
|
||||
Write-Host $appsList -ForegroundColor DarkGray
|
||||
continue
|
||||
}
|
||||
'RemoveAppsCustom' {
|
||||
$appsList = LoadAppsFromFile $script:CustomAppsListFilePath
|
||||
|
||||
if ($appsList.Count -eq 0) {
|
||||
Write-Host "No valid apps were selected for removal" -ForegroundColor Yellow
|
||||
Write-Output ""
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Output "- Remove $($appsList.Count) apps:"
|
||||
Write-Host $appsList -ForegroundColor DarkGray
|
||||
continue
|
||||
}
|
||||
default {
|
||||
if ($script:Features -and $script:Features.ContainsKey($parameterName)) {
|
||||
$action = $script:Features[$parameterName].Action
|
||||
$message = $script:Features[$parameterName].Label
|
||||
Write-Output "- $action $message"
|
||||
}
|
||||
else {
|
||||
# Fallback: show the parameter name if no feature description is available
|
||||
Write-Output "- $parameterName"
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
Write-Output ""
|
||||
Write-Output "Press enter to execute the script or press CTRL+C to quit..."
|
||||
Read-Host | Out-Null
|
||||
}
|
||||
28
Scripts/CLI/ShowCLIAppRemoval.ps1
Normal file
28
Scripts/CLI/ShowCLIAppRemoval.ps1
Normal file
@@ -0,0 +1,28 @@
|
||||
# Shows the CLI app removal menu and prompts the user to select which apps to remove.
|
||||
function ShowCLIAppRemoval {
|
||||
PrintHeader "App Removal"
|
||||
|
||||
Write-Output "> Opening app selection form..."
|
||||
|
||||
$result = Show-AppSelectionWindow
|
||||
|
||||
if ($result -eq $true) {
|
||||
Write-Output "You have selected $($script:SelectedApps.Count) apps for removal"
|
||||
AddParameter 'RemoveAppsCustom'
|
||||
|
||||
SaveSettings
|
||||
|
||||
# Suppress prompt if Silent parameter was passed
|
||||
if (-not $Silent) {
|
||||
Write-Output ""
|
||||
Write-Output ""
|
||||
Write-Output "Press enter to remove the selected apps or press CTRL+C to quit..."
|
||||
Read-Host | Out-Null
|
||||
PrintHeader "App Removal"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host "Selection was cancelled, no apps have been removed" -ForegroundColor Red
|
||||
Write-Output ""
|
||||
}
|
||||
}
|
||||
33
Scripts/CLI/ShowCLIDefaultModeAppRemovalOptions.ps1
Normal file
33
Scripts/CLI/ShowCLIDefaultModeAppRemovalOptions.ps1
Normal file
@@ -0,0 +1,33 @@
|
||||
# Shows the CLI default mode app removal options. Loops until a valid option is selected.
|
||||
function ShowCLIDefaultModeAppRemovalOptions {
|
||||
PrintHeader 'Default Mode'
|
||||
|
||||
Write-Host "Please note: The default selection of apps includes Microsoft Teams, Spotify, Sticky Notes and more. Select option 2 to verify and change what apps are removed by the script" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
|
||||
Do {
|
||||
Write-Host "Options:" -ForegroundColor Yellow
|
||||
Write-Host " (n) Don't remove any apps" -ForegroundColor Yellow
|
||||
Write-Host " (1) Only remove the default selection of apps" -ForegroundColor Yellow
|
||||
Write-Host " (2) Manually select which apps to remove" -ForegroundColor Yellow
|
||||
$RemoveAppsInput = Read-Host "Do you want to remove any apps? Apps will be removed for all users (n/1/2)"
|
||||
|
||||
# Show app selection form if user entered option 3
|
||||
if ($RemoveAppsInput -eq '2') {
|
||||
$result = Show-AppSelectionWindow
|
||||
|
||||
if ($result -ne $true) {
|
||||
# User cancelled or closed app selection, change RemoveAppsInput so the menu will be shown again
|
||||
Write-Host ""
|
||||
Write-Host "Cancelled application selection, please try again" -ForegroundColor Red
|
||||
|
||||
$RemoveAppsInput = 'c'
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
}
|
||||
while ($RemoveAppsInput -ne 'n' -and $RemoveAppsInput -ne '0' -and $RemoveAppsInput -ne '1' -and $RemoveAppsInput -ne '2')
|
||||
|
||||
return $RemoveAppsInput
|
||||
}
|
||||
55
Scripts/CLI/ShowCLIDefaultModeOptions.ps1
Normal file
55
Scripts/CLI/ShowCLIDefaultModeOptions.ps1
Normal file
@@ -0,0 +1,55 @@
|
||||
# Show CLI default mode options for removing apps, or set selection if RunDefaults or RunDefaultsLite parameter was passed
|
||||
function ShowCLIDefaultModeOptions {
|
||||
if ($RunDefaults) {
|
||||
$RemoveAppsInput = '1'
|
||||
}
|
||||
elseif ($RunDefaultsLite) {
|
||||
$RemoveAppsInput = '0'
|
||||
}
|
||||
else {
|
||||
$RemoveAppsInput = ShowCLIDefaultModeAppRemovalOptions
|
||||
|
||||
if ($RemoveAppsInput -eq '2' -and ($script:SelectedApps.contains('Microsoft.XboxGameOverlay') -or $script:SelectedApps.contains('Microsoft.XboxGamingOverlay')) -and
|
||||
$( Read-Host -Prompt "Disable Game Bar integration and game/screen recording? This also stops ms-gamingoverlay and ms-gamebar popups (y/n)" ) -eq 'y') {
|
||||
$DisableGameBarIntegrationInput = $true;
|
||||
}
|
||||
}
|
||||
|
||||
PrintHeader 'Default Mode'
|
||||
|
||||
# Add default settings based on user input
|
||||
try {
|
||||
# Select app removal options based on user input
|
||||
switch ($RemoveAppsInput) {
|
||||
'1' {
|
||||
AddParameter 'RemoveApps'
|
||||
AddParameter 'Apps' 'Default'
|
||||
}
|
||||
'2' {
|
||||
AddParameter 'RemoveAppsCustom'
|
||||
|
||||
if ($DisableGameBarIntegrationInput) {
|
||||
AddParameter 'DisableDVR'
|
||||
AddParameter 'DisableGameBarIntegration'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Load settings from DefaultSettings.json and add to params
|
||||
LoadSettings -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to load settings from DefaultSettings.json file: $_"
|
||||
AwaitKeyToExit
|
||||
}
|
||||
|
||||
SaveSettings
|
||||
|
||||
# Skip change summary if Silent parameter was passed
|
||||
if ($Silent) {
|
||||
return
|
||||
}
|
||||
|
||||
PrintPendingChanges
|
||||
PrintHeader 'Default Mode'
|
||||
}
|
||||
16
Scripts/CLI/ShowCLILastUsedSettings.ps1
Normal file
16
Scripts/CLI/ShowCLILastUsedSettings.ps1
Normal file
@@ -0,0 +1,16 @@
|
||||
# Shows the CLI last used settings from LastUsedSettings.json file, displays pending changes and prompts the user to apply them.
|
||||
function ShowCLILastUsedSettings {
|
||||
PrintHeader 'Custom Mode'
|
||||
|
||||
try {
|
||||
# Load settings from LastUsedSettings.json and add to params
|
||||
LoadSettings -filePath $script:SavedSettingsFilePath -expectedVersion "1.0"
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to load settings from LastUsedSettings.json file: $_"
|
||||
AwaitKeyToExit
|
||||
}
|
||||
|
||||
PrintPendingChanges
|
||||
PrintHeader 'Custom Mode'
|
||||
}
|
||||
30
Scripts/CLI/ShowCLIMenuOptions.ps1
Normal file
30
Scripts/CLI/ShowCLIMenuOptions.ps1
Normal file
@@ -0,0 +1,30 @@
|
||||
# Shows the CLI menu options and prompts the user to select one. Loops until a valid option is selected.
|
||||
function ShowCLIMenuOptions {
|
||||
Do {
|
||||
$ModeSelectionMessage = "Please select an option (1/2)"
|
||||
|
||||
PrintHeader 'Menu'
|
||||
|
||||
Write-Host "(1) Default mode: Quickly apply the recommended changes"
|
||||
Write-Host "(2) App removal mode: Select & remove apps, without making other changes"
|
||||
|
||||
# Only show this option if SavedSettings file exists
|
||||
if (Test-Path $script:SavedSettingsFilePath) {
|
||||
Write-Host "(3) Quickly apply your last used settings"
|
||||
|
||||
$ModeSelectionMessage = "Please select an option (1/2/3)"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host ""
|
||||
|
||||
$Mode = Read-Host $ModeSelectionMessage
|
||||
|
||||
if (($Mode -eq '3') -and -not (Test-Path $script:SavedSettingsFilePath)) {
|
||||
$Mode = $null
|
||||
}
|
||||
}
|
||||
while ($Mode -ne '1' -and $Mode -ne '2' -and $Mode -ne '3')
|
||||
|
||||
return $Mode
|
||||
}
|
||||
95
Scripts/Features/CreateSystemRestorePoint.ps1
Normal file
95
Scripts/Features/CreateSystemRestorePoint.ps1
Normal file
@@ -0,0 +1,95 @@
|
||||
function CreateSystemRestorePoint {
|
||||
$SysRestore = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRestore" -Name "RPSessionInterval"
|
||||
$failed = $false
|
||||
|
||||
if ($SysRestore.RPSessionInterval -eq 0) {
|
||||
# In GUI mode, skip the prompt and just try to enable it
|
||||
if ($script:GuiWindow -or $Silent -or $( Read-Host -Prompt "System restore is disabled, would you like to enable it and create a restore point? (y/n)") -eq 'y') {
|
||||
try {
|
||||
$enableResult = Invoke-NonBlocking -TimeoutSeconds 20 -ScriptBlock {
|
||||
try {
|
||||
Enable-ComputerRestore -Drive "$env:SystemDrive"
|
||||
return $null
|
||||
}
|
||||
catch {
|
||||
return "Error: Failed to enable System Restore: $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$enableResult = "Error: Failed to enable System Restore: $_"
|
||||
}
|
||||
|
||||
if ($enableResult) {
|
||||
Write-Host $enableResult -ForegroundColor Red
|
||||
$failed = $true
|
||||
}
|
||||
}
|
||||
else {
|
||||
Write-Host ""
|
||||
$failed = $true
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $failed) {
|
||||
try {
|
||||
$result = Invoke-NonBlocking -TimeoutSeconds 20 -ScriptBlock {
|
||||
try {
|
||||
$recentRestorePoints = Get-ComputerRestorePoint | Where-Object { (Get-Date) - [System.Management.ManagementDateTimeConverter]::ToDateTime($_.CreationTime) -le (New-TimeSpan -Hours 24) }
|
||||
}
|
||||
catch {
|
||||
return [PSCustomObject]@{ Success = $false; Message = "Error: Unable to retrieve existing restore points: $_" }
|
||||
}
|
||||
|
||||
if ($recentRestorePoints.Count -eq 0) {
|
||||
try {
|
||||
Checkpoint-Computer -Description "Restore point created by Win11Debloat" -RestorePointType "MODIFY_SETTINGS"
|
||||
return [PSCustomObject]@{ Success = $true; Message = "System restore point created successfully" }
|
||||
}
|
||||
catch {
|
||||
return [PSCustomObject]@{ Success = $false; Message = "Error: Unable to create restore point: $_" }
|
||||
}
|
||||
}
|
||||
else {
|
||||
return [PSCustomObject]@{ Success = $true; Message = "A recent restore point already exists, no new restore point was created" }
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$result = [PSCustomObject]@{ Success = $false; Message = "Error: Failed to create system restore point: $_" }
|
||||
}
|
||||
|
||||
if ($result -and $result.Success) {
|
||||
Write-Host $result.Message
|
||||
}
|
||||
elseif ($result) {
|
||||
Write-Host $result.Message -ForegroundColor Red
|
||||
$failed = $true
|
||||
}
|
||||
else {
|
||||
Write-Host "Error: Failed to create system restore point" -ForegroundColor Red
|
||||
$failed = $true
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure that the user is aware if creating a restore point failed, and give them the option to continue without a restore point or cancel the script
|
||||
if ($failed) {
|
||||
if ($script:GuiWindow) {
|
||||
$result = Show-MessageBox "Failed to create a system restore point. Do you want to continue without a restore point?" "Restore Point Creation Failed" "YesNo" "Warning"
|
||||
|
||||
if ($result -ne "Yes") {
|
||||
$script:CancelRequested = $true
|
||||
return
|
||||
}
|
||||
}
|
||||
elseif (-not $Silent) {
|
||||
Write-Host "Failed to create a system restore point. Do you want to continue without a restore point? (y/n)" -ForegroundColor Yellow
|
||||
if ($( Read-Host ) -ne 'y') {
|
||||
$script:CancelRequested = $true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Warning: Continuing without restore point" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
52
Scripts/Features/DisableStoreSearchSuggestions.ps1
Normal file
52
Scripts/Features/DisableStoreSearchSuggestions.ps1
Normal file
@@ -0,0 +1,52 @@
|
||||
# Disables Microsoft Store search suggestions in the start menu for all users by denying access to the Store app database file for each user
|
||||
function DisableStoreSearchSuggestionsForAllUsers {
|
||||
# Get path to Store app database for all users
|
||||
$userPathString = GetUserDirectory -userName "*" -fileName "AppData\Local\Packages"
|
||||
$usersStoreDbPaths = get-childitem -path $userPathString
|
||||
|
||||
# Go through all users and disable start search suggestions
|
||||
ForEach ($storeDbPath in $usersStoreDbPaths) {
|
||||
DisableStoreSearchSuggestions ($storeDbPath.FullName + "\Microsoft.WindowsStore_8wekyb3d8bbwe\LocalState\store.db")
|
||||
}
|
||||
|
||||
# Also disable start search suggestions for the default user profile
|
||||
$defaultStoreDbPath = GetUserDirectory -userName "Default" -fileName "AppData\Local\Packages\Microsoft.WindowsStore_8wekyb3d8bbwe\LocalState\store.db" -exitIfPathNotFound $false
|
||||
DisableStoreSearchSuggestions $defaultStoreDbPath
|
||||
}
|
||||
|
||||
|
||||
# Disables Microsoft Store search suggestions in the start menu by denying access to the Store app database file
|
||||
function DisableStoreSearchSuggestions {
|
||||
param (
|
||||
$StoreAppsDatabase = "$env:LocalAppData\Packages\Microsoft.WindowsStore_8wekyb3d8bbwe\LocalState\store.db"
|
||||
)
|
||||
|
||||
# Change path to correct user if a user was specified
|
||||
if ($script:Params.ContainsKey("User")) {
|
||||
$StoreAppsDatabase = GetUserDirectory -userName "$(GetUserName)" -fileName "AppData\Local\Packages\Microsoft.WindowsStore_8wekyb3d8bbwe\LocalState\store.db" -exitIfPathNotFound $false
|
||||
}
|
||||
|
||||
$userName = [regex]::Match($StoreAppsDatabase, '(?:Users\\)([^\\]+)(?:\\AppData)').Groups[1].Value
|
||||
|
||||
# This file doesn't exist in EEA (No Store app suggestions).
|
||||
if (-not (Test-Path -Path $StoreAppsDatabase))
|
||||
{
|
||||
Write-Host "Unable to find Store app database for user $userName, creating it now to prevent Windows from creating it later..." -ForegroundColor Yellow
|
||||
|
||||
$storeDbDir = Split-Path -Path $StoreAppsDatabase -Parent
|
||||
|
||||
if (-not (Test-Path -Path $storeDbDir)) {
|
||||
New-Item -Path $storeDbDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
New-Item -Path $StoreAppsDatabase -ItemType File -Force | Out-Null
|
||||
}
|
||||
|
||||
$AccountSid = [System.Security.Principal.SecurityIdentifier]::new('S-1-1-0') # 'EVERYONE' group
|
||||
$Acl = Get-Acl -Path $StoreAppsDatabase
|
||||
$Ace = [System.Security.AccessControl.FileSystemAccessRule]::new($AccountSid, 'FullControl', 'Deny')
|
||||
$Acl.SetAccessRule($Ace) | Out-Null
|
||||
Set-Acl -Path $StoreAppsDatabase -AclObject $Acl | Out-Null
|
||||
|
||||
Write-Host "Disabled Microsoft Store search suggestions for user $userName"
|
||||
}
|
||||
16
Scripts/Features/EnableWindowsFeature.ps1
Normal file
16
Scripts/Features/EnableWindowsFeature.ps1
Normal file
@@ -0,0 +1,16 @@
|
||||
# Enables a Windows optional feature and pipes its output to the console
|
||||
function EnableWindowsFeature {
|
||||
param (
|
||||
[string]$FeatureName
|
||||
)
|
||||
|
||||
$result = Invoke-NonBlocking -ScriptBlock {
|
||||
param($name)
|
||||
Enable-WindowsOptionalFeature -Online -FeatureName $name -All -NoRestart
|
||||
} -ArgumentList $FeatureName
|
||||
|
||||
$dismResult = @($result) | Where-Object { $_ -is [Microsoft.Dism.Commands.ImageObject] }
|
||||
if ($dismResult) {
|
||||
Write-Host ($dismResult | Out-String).Trim()
|
||||
}
|
||||
}
|
||||
196
Scripts/Features/ExecuteChanges.ps1
Normal file
196
Scripts/Features/ExecuteChanges.ps1
Normal file
@@ -0,0 +1,196 @@
|
||||
# Executes a single parameter/feature based on its key
|
||||
# Parameters:
|
||||
# $paramKey - The parameter name to execute
|
||||
function ExecuteParameter {
|
||||
param (
|
||||
[string]$paramKey
|
||||
)
|
||||
|
||||
# Check if this feature has metadata in Features.json
|
||||
$feature = $null
|
||||
if ($script:Features.ContainsKey($paramKey)) {
|
||||
$feature = $script:Features[$paramKey]
|
||||
}
|
||||
|
||||
# If feature has RegistryKey and ApplyText, use dynamic ImportRegistryFile
|
||||
if ($feature -and $feature.RegistryKey -and $feature.ApplyText) {
|
||||
ImportRegistryFile "> $($feature.ApplyText)" $feature.RegistryKey
|
||||
|
||||
# Handle special cases that have additional logic after ImportRegistryFile
|
||||
switch ($paramKey) {
|
||||
'DisableBing' {
|
||||
# Also remove the app package for Bing search
|
||||
RemoveApps 'Microsoft.BingSearch'
|
||||
}
|
||||
'DisableCopilot' {
|
||||
# Also remove the app package for Copilot
|
||||
RemoveApps 'Microsoft.Copilot'
|
||||
}
|
||||
'DisableWidgets' {
|
||||
# Also remove the app package for Widgets
|
||||
RemoveApps 'Microsoft.StartExperiencesApp'
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# Handle features without RegistryKey or with special logic
|
||||
switch ($paramKey) {
|
||||
'RemoveApps' {
|
||||
Write-Host "> Removing selected apps for $(GetFriendlyTargetUserName)..."
|
||||
$appsList = GenerateAppsList
|
||||
|
||||
if ($appsList.Count -eq 0) {
|
||||
Write-Host "No valid apps were selected for removal" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "$($appsList.Count) apps selected for removal"
|
||||
RemoveApps $appsList
|
||||
}
|
||||
'RemoveAppsCustom' {
|
||||
Write-Host "> Removing selected apps..."
|
||||
$appsList = LoadAppsFromFile $script:CustomAppsListFilePath
|
||||
|
||||
if ($appsList.Count -eq 0) {
|
||||
Write-Host "No valid apps were selected for removal" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "$($appsList.Count) apps selected for removal"
|
||||
RemoveApps $appsList
|
||||
}
|
||||
'RemoveCommApps' {
|
||||
$appsList = 'Microsoft.windowscommunicationsapps', 'Microsoft.People'
|
||||
Write-Host "> Removing Mail, Calendar and People apps..."
|
||||
RemoveApps $appsList
|
||||
return
|
||||
}
|
||||
'RemoveW11Outlook' {
|
||||
$appsList = 'Microsoft.OutlookForWindows'
|
||||
Write-Host "> Removing new Outlook for Windows app..."
|
||||
RemoveApps $appsList
|
||||
return
|
||||
}
|
||||
'RemoveGamingApps' {
|
||||
$appsList = 'Microsoft.GamingApp', 'Microsoft.XboxGameOverlay', 'Microsoft.XboxGamingOverlay'
|
||||
Write-Host "> Removing gaming related apps..."
|
||||
RemoveApps $appsList
|
||||
return
|
||||
}
|
||||
'RemoveHPApps' {
|
||||
$appsList = 'AD2F1837.HPAIExperienceCenter', 'AD2F1837.HPJumpStarts', 'AD2F1837.HPPCHardwareDiagnosticsWindows', 'AD2F1837.HPPowerManager', 'AD2F1837.HPPrivacySettings', 'AD2F1837.HPSupportAssistant', 'AD2F1837.HPSureShieldAI', 'AD2F1837.HPSystemInformation', 'AD2F1837.HPQuickDrop', 'AD2F1837.HPWorkWell', 'AD2F1837.myHP', 'AD2F1837.HPDesktopSupportUtilities', 'AD2F1837.HPQuickTouch', 'AD2F1837.HPEasyClean', 'AD2F1837.HPConnectedMusic', 'AD2F1837.HPFileViewer', 'AD2F1837.HPRegistration', 'AD2F1837.HPWelcome', 'AD2F1837.HPConnectedPhotopoweredbySnapfish', 'AD2F1837.HPPrinterControl'
|
||||
Write-Host "> Removing HP apps..."
|
||||
RemoveApps $appsList
|
||||
return
|
||||
}
|
||||
"EnableWindowsSandbox" {
|
||||
Write-Host "> Enabling Windows Sandbox..."
|
||||
EnableWindowsFeature "Containers-DisposableClientVM"
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
"EnableWindowsSubsystemForLinux" {
|
||||
Write-Host "> Enabling Windows Subsystem for Linux..."
|
||||
EnableWindowsFeature "VirtualMachinePlatform"
|
||||
EnableWindowsFeature "Microsoft-Windows-Subsystem-Linux"
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
'ClearStart' {
|
||||
Write-Host "> Removing all pinned apps from the start menu for user $(GetUserName)..."
|
||||
ReplaceStartMenu
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
'ReplaceStart' {
|
||||
Write-Host "> Replacing the start menu for user $(GetUserName)..."
|
||||
ReplaceStartMenu $script:Params.Item("ReplaceStart")
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
'ClearStartAllUsers' {
|
||||
ReplaceStartMenuForAllUsers
|
||||
return
|
||||
}
|
||||
'ReplaceStartAllUsers' {
|
||||
ReplaceStartMenuForAllUsers $script:Params.Item("ReplaceStartAllUsers")
|
||||
return
|
||||
}
|
||||
'DisableStoreSearchSuggestions' {
|
||||
if ($script:Params.ContainsKey("Sysprep")) {
|
||||
Write-Host "> Disabling Microsoft Store search suggestions in the start menu for all users..."
|
||||
DisableStoreSearchSuggestionsForAllUsers
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "> Disabling Microsoft Store search suggestions for user $(GetUserName)..."
|
||||
DisableStoreSearchSuggestions
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Executes all selected parameters/features
|
||||
function ExecuteAllChanges {
|
||||
# Build list of actionable parameters (skip control params and data-only params)
|
||||
$actionableKeys = @()
|
||||
foreach ($paramKey in $script:Params.Keys) {
|
||||
if ($script:ControlParams -contains $paramKey) { continue }
|
||||
if ($paramKey -eq 'Apps') { continue }
|
||||
if ($paramKey -eq 'CreateRestorePoint') { continue }
|
||||
$actionableKeys += $paramKey
|
||||
}
|
||||
|
||||
$totalSteps = $actionableKeys.Count
|
||||
if ($script:Params.ContainsKey("CreateRestorePoint")) { $totalSteps++ }
|
||||
$currentStep = 0
|
||||
|
||||
# Create restore point if requested (CLI only - GUI handles this separately)
|
||||
if ($script:Params.ContainsKey("CreateRestorePoint")) {
|
||||
$currentStep++
|
||||
if ($script:ApplyProgressCallback) {
|
||||
& $script:ApplyProgressCallback $currentStep $totalSteps "Creating system restore point"
|
||||
}
|
||||
Write-Host "> Attempting to create a system restore point..."
|
||||
CreateSystemRestorePoint
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Execute all parameters
|
||||
foreach ($paramKey in $actionableKeys) {
|
||||
if ($script:CancelRequested) {
|
||||
return
|
||||
}
|
||||
|
||||
$currentStep++
|
||||
|
||||
# Get friendly name for the step
|
||||
$stepName = $paramKey
|
||||
if ($script:Features.ContainsKey($paramKey)) {
|
||||
$feature = $script:Features[$paramKey]
|
||||
if ($feature.ApplyText) {
|
||||
# Prefer explicit ApplyText when provided
|
||||
$stepName = $feature.ApplyText
|
||||
} elseif ($feature.Label) {
|
||||
# Fallback: construct a name from Action and Label, or just Label
|
||||
if ($feature.Action) {
|
||||
$stepName = "$($feature.Action) $($feature.Label)"
|
||||
} else {
|
||||
$stepName = $feature.Label
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($script:ApplyProgressCallback) {
|
||||
& $script:ApplyProgressCallback $currentStep $totalSteps $stepName
|
||||
}
|
||||
|
||||
ExecuteParameter -paramKey $paramKey
|
||||
}
|
||||
}
|
||||
69
Scripts/Features/ImportRegistryFile.ps1
Normal file
69
Scripts/Features/ImportRegistryFile.ps1
Normal file
@@ -0,0 +1,69 @@
|
||||
# Import & execute regfile
|
||||
function ImportRegistryFile {
|
||||
param (
|
||||
$message,
|
||||
$path
|
||||
)
|
||||
|
||||
Write-Host $message
|
||||
|
||||
# Validate that the regfile exists in both locations
|
||||
if (-not (Test-Path "$script:RegfilesPath\$path") -or -not (Test-Path "$script:RegfilesPath\Sysprep\$path")) {
|
||||
Write-Host "Error: Unable to find registry file: $path" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
|
||||
# Reset exit code before running reg.exe for reliable success detection
|
||||
$global:LASTEXITCODE = 0
|
||||
|
||||
if ($script:Params.ContainsKey("Sysprep") -or $script:Params.ContainsKey("User")) {
|
||||
# Sysprep targets Default user, User targets the specified user
|
||||
$hiveDatPath = if ($script:Params.ContainsKey("Sysprep")) {
|
||||
GetUserDirectory -userName "Default" -fileName "NTUSER.DAT"
|
||||
} else {
|
||||
GetUserDirectory -userName $script:Params.Item("User") -fileName "NTUSER.DAT"
|
||||
}
|
||||
|
||||
$regResult = Invoke-NonBlocking -ScriptBlock {
|
||||
param($datPath, $regFilePath)
|
||||
$global:LASTEXITCODE = 0
|
||||
reg load "HKU\Default" $datPath | Out-Null
|
||||
$output = reg import $regFilePath 2>&1
|
||||
$code = $LASTEXITCODE
|
||||
reg unload "HKU\Default" | Out-Null
|
||||
return @{ Output = $output; ExitCode = $code }
|
||||
} -ArgumentList @($hiveDatPath, "$script:RegfilesPath\Sysprep\$path")
|
||||
}
|
||||
else {
|
||||
$regResult = Invoke-NonBlocking -ScriptBlock {
|
||||
param($regFilePath)
|
||||
$global:LASTEXITCODE = 0
|
||||
$output = reg import $regFilePath 2>&1
|
||||
return @{ Output = $output; ExitCode = $LASTEXITCODE }
|
||||
} -ArgumentList "$script:RegfilesPath\$path"
|
||||
}
|
||||
|
||||
$regOutput = $regResult.Output
|
||||
$hasSuccess = $regResult.ExitCode -eq 0
|
||||
|
||||
if ($regOutput) {
|
||||
foreach ($line in $regOutput) {
|
||||
$lineText = if ($line -is [System.Management.Automation.ErrorRecord]) { $line.Exception.Message } else { $line.ToString() }
|
||||
if ($lineText -and $lineText.Length -gt 0) {
|
||||
if ($hasSuccess) {
|
||||
Write-Host $lineText
|
||||
}
|
||||
else {
|
||||
Write-Host $lineText -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $hasSuccess) {
|
||||
Write-Host "Failed importing registry file: $path" -ForegroundColor Red
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
83
Scripts/Features/ReplaceStartMenu.ps1
Normal file
83
Scripts/Features/ReplaceStartMenu.ps1
Normal file
@@ -0,0 +1,83 @@
|
||||
# Replace the startmenu for all users, when using the default startmenuTemplate this clears all pinned apps
|
||||
# Credit: https://lazyadmin.nl/win-11/customize-windows-11-start-menu-layout/
|
||||
function ReplaceStartMenuForAllUsers {
|
||||
param (
|
||||
$startMenuTemplate = "$script:AssetsPath/Start/start2.bin"
|
||||
)
|
||||
|
||||
Write-Host "> Removing all pinned apps from the start menu for all users..."
|
||||
|
||||
# Check if template bin file exists
|
||||
if (-not (Test-Path $startMenuTemplate)) {
|
||||
Write-Host "Error: Unable to clear start menu, start2.bin file missing from script folder" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
return
|
||||
}
|
||||
|
||||
# Get path to start menu file for all users
|
||||
$userPathString = GetUserDirectory -userName "*" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState"
|
||||
$usersStartMenuPaths = get-childitem -path $userPathString
|
||||
|
||||
# Go through all users and replace the start menu file
|
||||
ForEach ($startMenuPath in $usersStartMenuPaths) {
|
||||
ReplaceStartMenu $startMenuTemplate "$($startMenuPath.Fullname)\start2.bin"
|
||||
}
|
||||
|
||||
# Also replace the start menu file for the default user profile
|
||||
$defaultStartMenuPath = GetUserDirectory -userName "Default" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState" -exitIfPathNotFound $false
|
||||
|
||||
# Create folder if it doesn't exist
|
||||
if (-not (Test-Path $defaultStartMenuPath)) {
|
||||
new-item $defaultStartMenuPath -ItemType Directory -Force | Out-Null
|
||||
Write-Host "Created LocalState folder for default user profile"
|
||||
}
|
||||
|
||||
# Copy template to default profile
|
||||
Copy-Item -Path $startMenuTemplate -Destination $defaultStartMenuPath -Force
|
||||
Write-Host "Replaced start menu for the default user profile"
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
|
||||
# Replace the startmenu for all users, when using the default startmenuTemplate this clears all pinned apps
|
||||
# Credit: https://lazyadmin.nl/win-11/customize-windows-11-start-menu-layout/
|
||||
function ReplaceStartMenu {
|
||||
param (
|
||||
$startMenuTemplate = "$script:AssetsPath/Start/start2.bin",
|
||||
$startMenuBinFile = "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin"
|
||||
)
|
||||
|
||||
# Change path to correct user if a user was specified
|
||||
if ($script:Params.ContainsKey("User")) {
|
||||
$startMenuBinFile = GetUserDirectory -userName "$(GetUserName)" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin" -exitIfPathNotFound $false
|
||||
}
|
||||
|
||||
# Check if template bin file exists
|
||||
if (-not (Test-Path $startMenuTemplate)) {
|
||||
Write-Host "Error: Unable to replace start menu, template file not found" -ForegroundColor Red
|
||||
return
|
||||
}
|
||||
|
||||
if ([IO.Path]::GetExtension($startMenuTemplate) -ne ".bin" ) {
|
||||
Write-Host "Error: Unable to replace start menu, template file is not a valid .bin file" -ForegroundColor Red
|
||||
return
|
||||
}
|
||||
|
||||
$userName = [regex]::Match($startMenuBinFile, '(?:Users\\)([^\\]+)(?:\\AppData)').Groups[1].Value
|
||||
|
||||
$backupBinFile = $startMenuBinFile + ".bak"
|
||||
|
||||
if (Test-Path $startMenuBinFile) {
|
||||
# Backup current start menu file
|
||||
Move-Item -Path $startMenuBinFile -Destination $backupBinFile -Force
|
||||
}
|
||||
else {
|
||||
Write-Host "Unable to find original start2.bin file for user $userName, no backup was created for this user" -ForegroundColor Yellow
|
||||
New-Item -ItemType File -Path $startMenuBinFile -Force
|
||||
}
|
||||
|
||||
# Copy template file
|
||||
Copy-Item -Path $startMenuTemplate -Destination $startMenuBinFile -Force
|
||||
|
||||
Write-Host "Replaced start menu for user $userName"
|
||||
}
|
||||
26
Scripts/Features/RestartExplorer.ps1
Normal file
26
Scripts/Features/RestartExplorer.ps1
Normal file
@@ -0,0 +1,26 @@
|
||||
# Restart the Windows Explorer process
|
||||
function RestartExplorer {
|
||||
Write-Host "> Attempting to restart the Windows Explorer process to apply all changes..."
|
||||
|
||||
if ($script:Params.ContainsKey("Sysprep") -or $script:Params.ContainsKey("User") -or $script:Params.ContainsKey("NoRestartExplorer")) {
|
||||
Write-Host "Explorer process restart was skipped, please manually reboot your PC to apply all changes" -ForegroundColor Yellow
|
||||
return
|
||||
}
|
||||
|
||||
foreach ($paramKey in $script:Params.Keys) {
|
||||
if ($script:Features.ContainsKey($paramKey) -and $script:Features[$paramKey].RequiresReboot -eq $true) {
|
||||
$feature = $script:Features[$paramKey]
|
||||
Write-Host "Warning: '$($feature.Action) $($feature.Label)' requires a reboot to take full effect" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
# Only restart if the powershell process matches the OS architecture.
|
||||
# Restarting explorer from a 32bit PowerShell window will fail on a 64bit OS
|
||||
if ([Environment]::Is64BitProcess -eq [Environment]::Is64BitOperatingSystem) {
|
||||
Write-Host "Restarting the Windows Explorer process... (This may cause your screen to flicker)"
|
||||
Stop-Process -processName: Explorer -Force
|
||||
}
|
||||
else {
|
||||
Write-Host "Unable to restart Windows Explorer process, please manually reboot your PC to apply all changes" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
22
Scripts/FileIO/LoadAppPresetsFromJson.ps1
Normal file
22
Scripts/FileIO/LoadAppPresetsFromJson.ps1
Normal file
@@ -0,0 +1,22 @@
|
||||
# Read Apps.json and return the list of preset objects (Name + AppIds).
|
||||
# Returns an empty array if the file cannot be read or contains no presets.
|
||||
function LoadAppPresetsFromJson {
|
||||
try {
|
||||
$jsonContent = Get-Content -Path $script:AppsListFilePath -Raw | ConvertFrom-Json
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to read Apps.json: $_"
|
||||
return @()
|
||||
}
|
||||
|
||||
if (-not $jsonContent.Presets) {
|
||||
return @()
|
||||
}
|
||||
|
||||
return @($jsonContent.Presets | ForEach-Object {
|
||||
[PSCustomObject]@{
|
||||
Name = $_.Name
|
||||
AppIds = @($_.AppIds)
|
||||
}
|
||||
})
|
||||
}
|
||||
47
Scripts/FileIO/LoadAppsDetailsFromJson.ps1
Normal file
47
Scripts/FileIO/LoadAppsDetailsFromJson.ps1
Normal file
@@ -0,0 +1,47 @@
|
||||
# Read Apps.json and return list of app objects with optional filtering
|
||||
function LoadAppsDetailsFromJson {
|
||||
param (
|
||||
[switch]$OnlyInstalled,
|
||||
[string]$InstalledList = "",
|
||||
[switch]$InitialCheckedFromJson
|
||||
)
|
||||
|
||||
$apps = @()
|
||||
try {
|
||||
$jsonContent = Get-Content -Path $script:AppsListFilePath -Raw | ConvertFrom-Json
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to read Apps.json: $_"
|
||||
return $apps
|
||||
}
|
||||
|
||||
foreach ($appData in $jsonContent.Apps) {
|
||||
$appId = $appData.AppId.Trim()
|
||||
if ($appId.length -eq 0) { continue }
|
||||
|
||||
if ($OnlyInstalled) {
|
||||
if (-not ($InstalledList -like ("*$appId*")) -and -not (Get-AppxPackage -Name $appId)) {
|
||||
continue
|
||||
}
|
||||
if (($appId -eq "Microsoft.Edge") -and -not ($InstalledList -like "* Microsoft.Edge *")) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
$friendlyName = if ($appData.FriendlyName) { $appData.FriendlyName } else { $appId }
|
||||
$displayName = if ($appData.FriendlyName) { "$($appData.FriendlyName) ($appId)" } else { $appId }
|
||||
$isChecked = if ($InitialCheckedFromJson) { $appData.SelectedByDefault } else { $false }
|
||||
|
||||
$apps += [PSCustomObject]@{
|
||||
AppId = $appId
|
||||
FriendlyName = $friendlyName
|
||||
DisplayName = $displayName
|
||||
IsChecked = $isChecked
|
||||
Description = $appData.Description
|
||||
SelectedByDefault = $appData.SelectedByDefault
|
||||
Recommendation = $appData.Recommendation
|
||||
}
|
||||
}
|
||||
|
||||
return $apps
|
||||
}
|
||||
45
Scripts/FileIO/LoadAppsFromFile.ps1
Normal file
45
Scripts/FileIO/LoadAppsFromFile.ps1
Normal file
@@ -0,0 +1,45 @@
|
||||
# Returns list of apps from the specified file, it trims the app names and removes any comments
|
||||
function LoadAppsFromFile {
|
||||
param (
|
||||
$appsFilePath
|
||||
)
|
||||
|
||||
$appsList = @()
|
||||
|
||||
if (-not (Test-Path $appsFilePath)) {
|
||||
return $appsList
|
||||
}
|
||||
|
||||
try {
|
||||
# Check if file is JSON or text format
|
||||
if ($appsFilePath -like "*.json") {
|
||||
# JSON file format
|
||||
$jsonContent = Get-Content -Path $appsFilePath -Raw | ConvertFrom-Json
|
||||
Foreach ($appData in $jsonContent.Apps) {
|
||||
$appId = $appData.AppId.Trim()
|
||||
$selectedByDefault = $appData.SelectedByDefault
|
||||
if ($selectedByDefault -and $appId.length -gt 0) {
|
||||
$appsList += $appId
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Legacy text file format
|
||||
Foreach ($app in (Get-Content -Path $appsFilePath | Where-Object { $_ -notmatch '^#.*' -and $_ -notmatch '^\s*$' } )) {
|
||||
if (-not ($app.IndexOf('#') -eq -1)) {
|
||||
$app = $app.Substring(0, $app.IndexOf('#'))
|
||||
}
|
||||
|
||||
$app = $app.Trim()
|
||||
$appString = $app.Trim('*')
|
||||
$appsList += $appString
|
||||
}
|
||||
}
|
||||
|
||||
return $appsList
|
||||
}
|
||||
catch {
|
||||
Write-Error "Unable to read apps list from file: $appsFilePath"
|
||||
AwaitKeyToExit
|
||||
}
|
||||
}
|
||||
32
Scripts/FileIO/LoadJsonFile.ps1
Normal file
32
Scripts/FileIO/LoadJsonFile.ps1
Normal file
@@ -0,0 +1,32 @@
|
||||
# Loads a JSON file from the specified path and returns the parsed object
|
||||
# Returns $null if the file doesn't exist or if parsing fails
|
||||
function LoadJsonFile {
|
||||
param (
|
||||
[string]$filePath,
|
||||
[string]$expectedVersion = $null,
|
||||
[switch]$optionalFile
|
||||
)
|
||||
|
||||
if (-not (Test-Path $filePath)) {
|
||||
if (-not $optionalFile) {
|
||||
Write-Error "File not found: $filePath"
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
try {
|
||||
$jsonContent = Get-Content -Path $filePath -Raw | ConvertFrom-Json
|
||||
|
||||
# Validate version if specified
|
||||
if ($expectedVersion -and $jsonContent.Version -and $jsonContent.Version -ne $expectedVersion) {
|
||||
Write-Error "$(Split-Path $filePath -Leaf) version mismatch (expected $expectedVersion, found $($jsonContent.Version))"
|
||||
return $null
|
||||
}
|
||||
|
||||
return $jsonContent
|
||||
}
|
||||
catch {
|
||||
Write-Error "Failed to parse JSON file: $filePath"
|
||||
return $null
|
||||
}
|
||||
}
|
||||
31
Scripts/FileIO/LoadSettings.ps1
Normal file
31
Scripts/FileIO/LoadSettings.ps1
Normal file
@@ -0,0 +1,31 @@
|
||||
# Loads settings from a JSON file and adds them to script params
|
||||
function LoadSettings {
|
||||
param (
|
||||
[string]$filePath,
|
||||
[string]$expectedVersion = "1.0"
|
||||
)
|
||||
|
||||
$settingsJson = LoadJsonFile -filePath $filePath -expectedVersion $expectedVersion
|
||||
|
||||
if (-not $settingsJson -or -not $settingsJson.Settings) {
|
||||
throw "Failed to load settings from $(Split-Path $filePath -Leaf)"
|
||||
}
|
||||
|
||||
# Get current Windows build version
|
||||
$WinVersion = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' CurrentBuild
|
||||
|
||||
foreach ($setting in $settingsJson.Settings) {
|
||||
if ($setting.Value -eq $false) {
|
||||
continue
|
||||
}
|
||||
|
||||
$feature = $script:Features[$setting.Name]
|
||||
|
||||
# Check version and feature compatibility using Features.json
|
||||
if (($feature.MinVersion -and $WinVersion -lt $feature.MinVersion) -or ($feature.MaxVersion -and $WinVersion -gt $feature.MaxVersion) -or ($feature.FeatureId -eq 'DisableModernStandbyNetworking' -and (-not $script:ModernStandbySupported))) {
|
||||
continue
|
||||
}
|
||||
|
||||
AddParameter $setting.Name $setting.Value
|
||||
}
|
||||
}
|
||||
15
Scripts/FileIO/SaveCustomAppsListToFile.ps1
Normal file
15
Scripts/FileIO/SaveCustomAppsListToFile.ps1
Normal file
@@ -0,0 +1,15 @@
|
||||
# Saves the provided appsList to the CustomAppsList file
|
||||
function SaveCustomAppsListToFile {
|
||||
param (
|
||||
$appsList
|
||||
)
|
||||
|
||||
$script:SelectedApps = $appsList
|
||||
|
||||
# Create file that stores selected apps if it doesn't exist
|
||||
if (-not (Test-Path $script:CustomAppsListFilePath)) {
|
||||
$null = New-Item $script:CustomAppsListFilePath -ItemType File
|
||||
}
|
||||
|
||||
Set-Content -Path $script:CustomAppsListFilePath -Value $script:SelectedApps
|
||||
}
|
||||
26
Scripts/FileIO/SaveSettings.ps1
Normal file
26
Scripts/FileIO/SaveSettings.ps1
Normal file
@@ -0,0 +1,26 @@
|
||||
# Saves the current settings, excluding control parameters, to 'LastUsedSettings.json' file
|
||||
function SaveSettings {
|
||||
$settings = @{
|
||||
"Version" = "1.0"
|
||||
"Settings" = @()
|
||||
}
|
||||
|
||||
foreach ($param in $script:Params.Keys) {
|
||||
if ($script:ControlParams -notcontains $param) {
|
||||
$value = $script:Params[$param]
|
||||
|
||||
$settings.Settings += @{
|
||||
"Name" = $param
|
||||
"Value" = $value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$settings | ConvertTo-Json -Depth 10 | Set-Content $script:SavedSettingsFilePath
|
||||
}
|
||||
catch {
|
||||
Write-Output ""
|
||||
Write-Host "Error: Failed to save settings to LastUsedSettings.json file" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
24
Scripts/FileIO/ValidateAppslist.ps1
Normal file
24
Scripts/FileIO/ValidateAppslist.ps1
Normal file
@@ -0,0 +1,24 @@
|
||||
# Returns a validated list of apps based on the provided appsList and the supported apps from Apps.json
|
||||
function ValidateAppslist {
|
||||
param (
|
||||
$appsList
|
||||
)
|
||||
|
||||
$supportedAppsList = (LoadAppsDetailsFromJson | ForEach-Object { $_.AppId })
|
||||
$validatedAppsList = @()
|
||||
|
||||
# Validate provided appsList against supportedAppsList
|
||||
Foreach ($app in $appsList) {
|
||||
$app = $app.Trim()
|
||||
$appString = $app.Trim('*')
|
||||
|
||||
if ($supportedAppsList -notcontains $appString) {
|
||||
Write-Host "Removal of app '$appString' is not supported and will be skipped" -ForegroundColor Yellow
|
||||
continue
|
||||
}
|
||||
|
||||
$validatedAppsList += $appString
|
||||
}
|
||||
|
||||
return $validatedAppsList
|
||||
}
|
||||
77
Scripts/GUI/ApplySettingsToUiControls.ps1
Normal file
77
Scripts/GUI/ApplySettingsToUiControls.ps1
Normal file
@@ -0,0 +1,77 @@
|
||||
# Applies settings from a JSON object to UI controls (checkboxes and comboboxes)
|
||||
# Used by LoadDefaultsBtn and LoadLastUsedBtn in the UI
|
||||
function ApplySettingsToUiControls {
|
||||
param (
|
||||
$window,
|
||||
$settingsJson,
|
||||
$uiControlMappings
|
||||
)
|
||||
|
||||
if (-not $settingsJson -or -not $settingsJson.Settings) {
|
||||
return $false
|
||||
}
|
||||
|
||||
if (-not $uiControlMappings) {
|
||||
return $true
|
||||
}
|
||||
|
||||
# Build control cache and reverse index (featureId -> control info) in a single pass
|
||||
$controlCache = @{}
|
||||
$featureIdIndex = @{}
|
||||
|
||||
foreach ($comboName in $uiControlMappings.Keys) {
|
||||
$control = $window.FindName($comboName)
|
||||
if (-not $control) { continue }
|
||||
$controlCache[$comboName] = $control
|
||||
|
||||
$mapping = $uiControlMappings[$comboName]
|
||||
if ($mapping.Type -eq 'group') {
|
||||
$i = 1
|
||||
foreach ($val in $mapping.Values) {
|
||||
foreach ($fid in $val.FeatureIds) {
|
||||
$featureIdIndex[$fid] = @{ ComboName = $comboName; Control = $control; Index = $i; MappingType = 'group' }
|
||||
}
|
||||
$i++
|
||||
}
|
||||
}
|
||||
elseif ($mapping.Type -eq 'feature') {
|
||||
$featureIdIndex[$mapping.FeatureId] = @{ ComboName = $comboName; Control = $control; MappingType = 'feature' }
|
||||
}
|
||||
|
||||
# Reset control to default state
|
||||
if ($control -is [System.Windows.Controls.CheckBox]) {
|
||||
$control.IsChecked = $false
|
||||
}
|
||||
elseif ($control -is [System.Windows.Controls.ComboBox]) {
|
||||
$control.SelectedIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
# Apply settings using O(1) lookups
|
||||
foreach ($setting in $settingsJson.Settings) {
|
||||
if ($setting.Value -ne $true) { continue }
|
||||
if ($setting.Name -eq 'CreateRestorePoint') { continue }
|
||||
|
||||
$entry = $featureIdIndex[$setting.Name]
|
||||
if (-not $entry) { continue }
|
||||
|
||||
$control = $entry.Control
|
||||
if (-not $control -or $control.Visibility -ne 'Visible') { continue }
|
||||
|
||||
if ($entry.MappingType -eq 'group') {
|
||||
if ($control -is [System.Windows.Controls.ComboBox]) {
|
||||
$control.SelectedIndex = $entry.Index
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($control -is [System.Windows.Controls.CheckBox]) {
|
||||
$control.IsChecked = $true
|
||||
}
|
||||
elseif ($control -is [System.Windows.Controls.ComboBox]) {
|
||||
$control.SelectedIndex = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
71
Scripts/GUI/AttachShiftClickBehavior.ps1
Normal file
71
Scripts/GUI/AttachShiftClickBehavior.ps1
Normal file
@@ -0,0 +1,71 @@
|
||||
# Attaches shift-click selection behavior to a checkbox in an apps panel
|
||||
# Parameters:
|
||||
# - $checkbox: The checkbox to attach the behavior to
|
||||
# - $appsPanel: The StackPanel containing checkbox items
|
||||
# - $lastSelectedCheckboxRef: A reference to a variable storing the last clicked checkbox
|
||||
# - $updateStatusCallback: Optional callback to update selection status
|
||||
function AttachShiftClickBehavior {
|
||||
param (
|
||||
[System.Windows.Controls.CheckBox]$checkbox,
|
||||
[System.Windows.Controls.StackPanel]$appsPanel,
|
||||
[ref]$lastSelectedCheckboxRef,
|
||||
[scriptblock]$updateStatusCallback = $null
|
||||
)
|
||||
|
||||
# Use a closure to capture the parameters
|
||||
$checkbox.Add_PreviewMouseLeftButtonDown({
|
||||
param(
|
||||
$sender,
|
||||
$e
|
||||
)
|
||||
|
||||
$isShiftPressed = [System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::LeftShift) -or
|
||||
[System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::RightShift)
|
||||
|
||||
if ($isShiftPressed -and $null -ne $lastSelectedCheckboxRef.Value) {
|
||||
# Get all visible checkboxes in the panel
|
||||
$visibleCheckboxes = @()
|
||||
foreach ($child in $appsPanel.Children) {
|
||||
if ($child -is [System.Windows.Controls.CheckBox] -and $child.Visibility -eq 'Visible') {
|
||||
$visibleCheckboxes += $child
|
||||
}
|
||||
}
|
||||
|
||||
# Find indices of the last selected and current checkbox
|
||||
$lastIndex = -1
|
||||
$currentIndex = -1
|
||||
|
||||
for ($i = 0; $i -lt $visibleCheckboxes.Count; $i++) {
|
||||
if ($visibleCheckboxes[$i] -eq $lastSelectedCheckboxRef.Value) {
|
||||
$lastIndex = $i
|
||||
}
|
||||
if ($visibleCheckboxes[$i] -eq $sender) {
|
||||
$currentIndex = $i
|
||||
}
|
||||
}
|
||||
|
||||
if ($lastIndex -ge 0 -and $currentIndex -ge 0 -and $lastIndex -ne $currentIndex) {
|
||||
$startIndex = [Math]::Min($lastIndex, $currentIndex)
|
||||
$endIndex = [Math]::Max($lastIndex, $currentIndex)
|
||||
|
||||
$shouldDeselect = $sender.IsChecked
|
||||
|
||||
# Set all checkboxes in the range to the appropriate state
|
||||
for ($i = $startIndex; $i -le $endIndex; $i++) {
|
||||
$visibleCheckboxes[$i].IsChecked = -not $shouldDeselect
|
||||
}
|
||||
|
||||
if ($updateStatusCallback) {
|
||||
& $updateStatusCallback
|
||||
}
|
||||
|
||||
# Mark the event as handled to prevent the default toggle behavior
|
||||
$e.Handled = $true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
# Update the last selected checkbox reference for next time
|
||||
$lastSelectedCheckboxRef.Value = $sender
|
||||
}.GetNewClosure())
|
||||
}
|
||||
9
Scripts/GUI/GetSystemUsesDarkMode.ps1
Normal file
9
Scripts/GUI/GetSystemUsesDarkMode.ps1
Normal file
@@ -0,0 +1,9 @@
|
||||
# Checks if the system is set to use dark mode for apps
|
||||
function GetSystemUsesDarkMode {
|
||||
try {
|
||||
return (Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' -Name 'AppsUseLightTheme').AppsUseLightTheme -eq 0
|
||||
}
|
||||
catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
94
Scripts/GUI/SetWindowThemeResources.ps1
Normal file
94
Scripts/GUI/SetWindowThemeResources.ps1
Normal file
@@ -0,0 +1,94 @@
|
||||
# Sets resource colors for a WPF window based on dark mode preference
|
||||
function SetWindowThemeResources {
|
||||
param (
|
||||
$window,
|
||||
[bool]$usesDarkMode
|
||||
)
|
||||
|
||||
if ($usesDarkMode) {
|
||||
$window.Resources.Add("BgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#202020")))
|
||||
$window.Resources.Add("FgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFFFFF")))
|
||||
$window.Resources.Add("CardBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#2b2b2b")))
|
||||
$window.Resources.Add("BorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#404040")))
|
||||
$window.Resources.Add("ButtonBorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#404040")))
|
||||
$window.Resources.Add("CheckBoxBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#272727")))
|
||||
$window.Resources.Add("CheckBoxBorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#808080")))
|
||||
$window.Resources.Add("CheckBoxHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#343434")))
|
||||
$window.Resources.Add("ComboBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#373737")))
|
||||
$window.Resources.Add("ComboHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#434343")))
|
||||
$window.Resources.Add("ComboItemBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#2c2c2c")))
|
||||
$window.Resources.Add("ComboItemHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#383838")))
|
||||
$window.Resources.Add("ComboItemSelectedColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#343434")))
|
||||
$window.Resources.Add("AccentColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFD700")))
|
||||
$window.Resources.Add("ButtonDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#434343")))
|
||||
$window.Resources.Add("ButtonTextDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#989898")))
|
||||
$window.Resources.Add("SecondaryButtonBg", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#393939")))
|
||||
$window.Resources.Add("SecondaryButtonHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#2a2a2a")))
|
||||
$window.Resources.Add("SecondaryButtonPressed", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#1e1e1e")))
|
||||
$window.Resources.Add("SecondaryButtonDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#3b3b3b")))
|
||||
$window.Resources.Add("SecondaryButtonTextDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#787878")))
|
||||
$window.Resources.Add("InputFocusColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#1f1f1f")))
|
||||
$window.Resources.Add("ScrollBarThumbColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#3d3d3d")))
|
||||
$window.Resources.Add("ScrollBarThumbHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#4b4b4b")))
|
||||
$window.Resources.Add("TitlebarButtonHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#2d2d2d")))
|
||||
$window.Resources.Add("TitlebarButtonPressed", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#292929")))
|
||||
$window.Resources.Add("AppIdColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#afafaf")))
|
||||
$window.Resources.Add("SearchHighlightColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#4A4A2A")))
|
||||
$window.Resources.Add("SearchHighlightActiveColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#8A7000")))
|
||||
$window.Resources.Add("TableHeaderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#333333")))
|
||||
}
|
||||
else {
|
||||
$window.Resources.Add("BgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f3f3f3")))
|
||||
$window.Resources.Add("FgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#000000")))
|
||||
$window.Resources.Add("CardBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#fbfbfb")))
|
||||
$window.Resources.Add("BorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#ededed")))
|
||||
$window.Resources.Add("ButtonBorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#d3d3d3")))
|
||||
$window.Resources.Add("CheckBoxBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f5f5f5")))
|
||||
$window.Resources.Add("CheckBoxBorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#898989")))
|
||||
$window.Resources.Add("CheckBoxHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#ececec")))
|
||||
$window.Resources.Add("ComboBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFFFFF")))
|
||||
$window.Resources.Add("ComboHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f8f8f8")))
|
||||
$window.Resources.Add("ComboItemBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f9f9f9")))
|
||||
$window.Resources.Add("ComboItemHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f0f0f0")))
|
||||
$window.Resources.Add("ComboItemSelectedColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f3f3f3")))
|
||||
$window.Resources.Add("AccentColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#ffae00")))
|
||||
$window.Resources.Add("ButtonDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#bfbfbf")))
|
||||
$window.Resources.Add("ButtonTextDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#ffffff")))
|
||||
$window.Resources.Add("SecondaryButtonBg", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#fbfbfb")))
|
||||
$window.Resources.Add("SecondaryButtonHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f6f6f6")))
|
||||
$window.Resources.Add("SecondaryButtonPressed", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f0f0f0")))
|
||||
$window.Resources.Add("SecondaryButtonDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f7f7f7")))
|
||||
$window.Resources.Add("SecondaryButtonTextDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#b7b7b7")))
|
||||
$window.Resources.Add("InputFocusColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#fbfbfb")))
|
||||
$window.Resources.Add("ScrollBarThumbColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#b9b9b9")))
|
||||
$window.Resources.Add("ScrollBarThumbHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#8b8b8b")))
|
||||
$window.Resources.Add("TitlebarButtonHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#e1e1e1")))
|
||||
$window.Resources.Add("TitlebarButtonPressed", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#e6e6e6")))
|
||||
$window.Resources.Add("AppIdColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#666666")))
|
||||
$window.Resources.Add("SearchHighlightColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFF4CE")))
|
||||
$window.Resources.Add("SearchHighlightActiveColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFD966")))
|
||||
$window.Resources.Add("TableHeaderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#ffffff")))
|
||||
}
|
||||
|
||||
$window.Resources.Add("ButtonBg", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#0067c0")))
|
||||
$window.Resources.Add("ButtonHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#1E88E5")))
|
||||
$window.Resources.Add("ButtonPressed", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#3284cc")))
|
||||
$window.Resources.Add("CloseHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#c42b1c")))
|
||||
$window.Resources.Add("InformationIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#0078D4")))
|
||||
$window.Resources.Add("WarningIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFB900")))
|
||||
$window.Resources.Add("ErrorIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#E81123")))
|
||||
$window.Resources.Add("QuestionIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#0078D4")))
|
||||
|
||||
# Load and merge shared styles
|
||||
if ($script:SharedStylesSchema -and (Test-Path $script:SharedStylesSchema)) {
|
||||
$sharedXaml = Get-Content -Path $script:SharedStylesSchema -Raw
|
||||
$sharedReader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($sharedXaml))
|
||||
try {
|
||||
$sharedDict = [System.Windows.Markup.XamlReader]::Load($sharedReader)
|
||||
$window.Resources.MergedDictionaries.Add($sharedDict)
|
||||
}
|
||||
finally {
|
||||
$sharedReader.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
95
Scripts/GUI/Show-AboutDialog.ps1
Normal file
95
Scripts/GUI/Show-AboutDialog.ps1
Normal file
@@ -0,0 +1,95 @@
|
||||
function Show-AboutDialog {
|
||||
param (
|
||||
[Parameter(Mandatory=$false)]
|
||||
[System.Windows.Window]$Owner = $null
|
||||
)
|
||||
|
||||
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
|
||||
|
||||
$usesDarkMode = GetSystemUsesDarkMode
|
||||
|
||||
# Determine owner window
|
||||
$ownerWindow = if ($Owner) { $Owner } else { $script:GuiWindow }
|
||||
|
||||
# Show overlay if owner window exists
|
||||
$overlay = $null
|
||||
if ($ownerWindow) {
|
||||
try {
|
||||
$overlay = $ownerWindow.FindName('ModalOverlay')
|
||||
if ($overlay) {
|
||||
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
# Load XAML from file
|
||||
$xaml = Get-Content -Path $script:AboutWindowSchema -Raw
|
||||
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
|
||||
try {
|
||||
$aboutWindow = [System.Windows.Markup.XamlReader]::Load($reader)
|
||||
}
|
||||
finally {
|
||||
$reader.Close()
|
||||
}
|
||||
|
||||
# Set owner to owner window if it exists
|
||||
if ($ownerWindow) {
|
||||
try {
|
||||
$aboutWindow.Owner = $ownerWindow
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
# Apply theme resources
|
||||
SetWindowThemeResources -window $aboutWindow -usesDarkMode $usesDarkMode
|
||||
|
||||
# Get UI elements
|
||||
$titleBar = $aboutWindow.FindName('TitleBar')
|
||||
$versionText = $aboutWindow.FindName('VersionText')
|
||||
$projectLink = $aboutWindow.FindName('ProjectLink')
|
||||
$kofiLink = $aboutWindow.FindName('KofiLink')
|
||||
$closeButton = $aboutWindow.FindName('CloseButton')
|
||||
|
||||
# Set version
|
||||
$versionText.Text = $script:Version
|
||||
|
||||
# Title bar drag to move window
|
||||
$titleBar.Add_MouseLeftButtonDown({
|
||||
$aboutWindow.DragMove()
|
||||
})
|
||||
|
||||
# Project link click handler
|
||||
$projectLink.Add_MouseLeftButtonDown({
|
||||
Start-Process "https://github.com/Raphire/Win11Debloat"
|
||||
})
|
||||
|
||||
# Ko-fi link click handler
|
||||
$kofiLink.Add_MouseLeftButtonDown({
|
||||
Start-Process "https://ko-fi.com/raphire"
|
||||
})
|
||||
|
||||
# Close button handler
|
||||
$closeButton.Add_Click({
|
||||
$aboutWindow.Close()
|
||||
})
|
||||
|
||||
# Handle Escape key to close
|
||||
$aboutWindow.Add_KeyDown({
|
||||
param($sender, $e)
|
||||
if ($e.Key -eq 'Escape') {
|
||||
$aboutWindow.Close()
|
||||
}
|
||||
})
|
||||
|
||||
# Show dialog
|
||||
$aboutWindow.ShowDialog() | Out-Null
|
||||
|
||||
# Hide overlay after dialog closes
|
||||
if ($overlay) {
|
||||
try {
|
||||
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
161
Scripts/GUI/Show-AppSelectionWindow.ps1
Normal file
161
Scripts/GUI/Show-AppSelectionWindow.ps1
Normal file
@@ -0,0 +1,161 @@
|
||||
# Shows application selection window that allows the user to select what apps they want to remove or keep
|
||||
function Show-AppSelectionWindow {
|
||||
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
|
||||
|
||||
$usesDarkMode = GetSystemUsesDarkMode
|
||||
|
||||
# Show overlay if main window exists
|
||||
$overlay = $null
|
||||
if ($script:GuiWindow) {
|
||||
try {
|
||||
$overlay = $script:GuiWindow.FindName('ModalOverlay')
|
||||
if ($overlay) {
|
||||
$script:GuiWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
# Load XAML from file
|
||||
$xaml = Get-Content -Path $script:AppSelectionSchema -Raw
|
||||
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
|
||||
try {
|
||||
$window = [System.Windows.Markup.XamlReader]::Load($reader)
|
||||
}
|
||||
finally {
|
||||
$reader.Close()
|
||||
}
|
||||
|
||||
# Set owner to main window if it exists
|
||||
if ($script:GuiWindow) {
|
||||
try {
|
||||
$window.Owner = $script:GuiWindow
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
SetWindowThemeResources -window $window -usesDarkMode $usesDarkMode
|
||||
|
||||
$appsPanel = $window.FindName('AppsPanel')
|
||||
$checkAllBox = $window.FindName('CheckAllBox')
|
||||
$onlyInstalledBox = $window.FindName('OnlyInstalledBox')
|
||||
$confirmBtn = $window.FindName('ConfirmBtn')
|
||||
$loadingIndicator = $window.FindName('LoadingAppsIndicator')
|
||||
$titleBar = $window.FindName('TitleBar')
|
||||
|
||||
# Track the last selected checkbox for shift-click range selection
|
||||
$script:AppSelectionWindowLastSelectedCheckbox = $null
|
||||
|
||||
# Loads apps into the apps UI
|
||||
function LoadApps {
|
||||
# Show loading indicator
|
||||
$loadingIndicator.Visibility = 'Visible'
|
||||
$window.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{})
|
||||
|
||||
$appsPanel.Children.Clear()
|
||||
$listOfApps = ""
|
||||
|
||||
if ($onlyInstalledBox.IsChecked -and ($script:WingetInstalled -eq $true)) {
|
||||
# Attempt to get a list of installed apps via WinGet, times out after 10 seconds
|
||||
$listOfApps = GetInstalledAppsViaWinget -TimeOut 10
|
||||
if (-not $listOfApps) {
|
||||
# Show error that the script was unable to get list of apps from WinGet
|
||||
Show-MessageBox -Message 'Unable to load list of installed apps via WinGet.' -Title 'Error' -Button 'OK' -Icon 'Error' -Owner $window | Out-Null
|
||||
$onlyInstalledBox.IsChecked = $false
|
||||
}
|
||||
}
|
||||
|
||||
$appsToAdd = LoadAppsDetailsFromJson -OnlyInstalled:$onlyInstalledBox.IsChecked -InstalledList $listOfApps -InitialCheckedFromJson:$true
|
||||
|
||||
# Reset the last selected checkbox when loading a new list
|
||||
$script:AppSelectionWindowLastSelectedCheckbox = $null
|
||||
|
||||
# Sort apps alphabetically and add to panel
|
||||
$appsToAdd | Sort-Object -Property DisplayName | ForEach-Object {
|
||||
$checkbox = New-Object System.Windows.Controls.CheckBox
|
||||
$checkbox.Content = $_.DisplayName
|
||||
$checkbox.SetValue([System.Windows.Automation.AutomationProperties]::NameProperty, $_.DisplayName)
|
||||
$checkbox.Tag = $_.AppId
|
||||
$checkbox.IsChecked = $_.IsChecked
|
||||
$checkbox.ToolTip = $_.Description
|
||||
$checkbox.Style = $window.Resources["AppsPanelCheckBoxStyle"]
|
||||
|
||||
# Attach shift-click behavior for range selection
|
||||
AttachShiftClickBehavior -checkbox $checkbox -appsPanel $appsPanel -lastSelectedCheckboxRef ([ref]$script:AppSelectionWindowLastSelectedCheckbox)
|
||||
|
||||
$appsPanel.Children.Add($checkbox) | Out-Null
|
||||
}
|
||||
|
||||
# Hide loading indicator
|
||||
$loadingIndicator.Visibility = 'Collapsed'
|
||||
}
|
||||
|
||||
# Event handlers
|
||||
$titleBar.Add_MouseLeftButtonDown({
|
||||
$window.DragMove()
|
||||
})
|
||||
|
||||
$checkAllBox.Add_Checked({
|
||||
foreach ($child in $appsPanel.Children) {
|
||||
if ($child -is [System.Windows.Controls.CheckBox]) {
|
||||
$child.IsChecked = $true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$checkAllBox.Add_Unchecked({
|
||||
foreach ($child in $appsPanel.Children) {
|
||||
if ($child -is [System.Windows.Controls.CheckBox]) {
|
||||
$child.IsChecked = $false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$onlyInstalledBox.Add_Checked({ LoadApps })
|
||||
$onlyInstalledBox.Add_Unchecked({ LoadApps })
|
||||
|
||||
$confirmBtn.Add_Click({
|
||||
$selectedApps = @()
|
||||
foreach ($child in $appsPanel.Children) {
|
||||
if ($child -is [System.Windows.Controls.CheckBox] -and $child.IsChecked) {
|
||||
$selectedApps += $child.Tag
|
||||
}
|
||||
}
|
||||
|
||||
# Close form without saving if no apps were selected
|
||||
if ($selectedApps.Count -eq 0) {
|
||||
$window.Close()
|
||||
return
|
||||
}
|
||||
|
||||
if ($selectedApps -contains "Microsoft.WindowsStore" -and -not $Silent) {
|
||||
$result = Show-MessageBox -Message 'Are you sure you wish to uninstall the Microsoft Store? This app cannot easily be reinstalled.' -Title 'Are you sure?' -Button 'YesNo' -Icon 'Warning' -Owner $window
|
||||
|
||||
if ($result -eq 'No') {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
SaveCustomAppsListToFile -appsList $selectedApps
|
||||
|
||||
$window.DialogResult = $true
|
||||
})
|
||||
|
||||
# Load apps after window is shown (allows UI to render first)
|
||||
$window.Add_ContentRendered({
|
||||
$window.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{ LoadApps }) | Out-Null
|
||||
})
|
||||
|
||||
# Show the window and return dialog result
|
||||
$result = $window.ShowDialog()
|
||||
|
||||
# Hide overlay after dialog closes
|
||||
if ($overlay) {
|
||||
try {
|
||||
$script:GuiWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
return $result
|
||||
}
|
||||
254
Scripts/GUI/Show-ApplyModal.ps1
Normal file
254
Scripts/GUI/Show-ApplyModal.ps1
Normal file
@@ -0,0 +1,254 @@
|
||||
function Show-ApplyModal {
|
||||
param (
|
||||
[Parameter(Mandatory=$false)]
|
||||
[System.Windows.Window]$Owner = $null,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[bool]$RestartExplorer = $false
|
||||
)
|
||||
|
||||
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
|
||||
|
||||
# P/Invoke helpers for forcing focus back after Explorer restart
|
||||
if (-not ([System.Management.Automation.PSTypeName]'Win11Debloat.FocusHelper').Type) {
|
||||
Add-Type -Namespace Win11Debloat -Name FocusHelper -MemberDefinition @'
|
||||
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
|
||||
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);
|
||||
[DllImport("user32.dll")] public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
|
||||
[DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId();
|
||||
|
||||
public static void ForceActivate(IntPtr hwnd) {
|
||||
IntPtr fg = GetForegroundWindow();
|
||||
uint fgThread = GetWindowThreadProcessId(fg, IntPtr.Zero);
|
||||
uint myThread = GetCurrentThreadId();
|
||||
if (fgThread != myThread) AttachThreadInput(myThread, fgThread, true);
|
||||
SetForegroundWindow(hwnd);
|
||||
if (fgThread != myThread) AttachThreadInput(myThread, fgThread, false);
|
||||
}
|
||||
'@
|
||||
}
|
||||
|
||||
$usesDarkMode = GetSystemUsesDarkMode
|
||||
|
||||
# Determine owner window
|
||||
$ownerWindow = if ($Owner) { $Owner } else { $script:GuiWindow }
|
||||
|
||||
# Show overlay if owner window exists
|
||||
$overlay = $null
|
||||
if ($ownerWindow) {
|
||||
try {
|
||||
$overlay = $ownerWindow.FindName('ModalOverlay')
|
||||
if ($overlay) {
|
||||
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
# Load XAML from file
|
||||
$xaml = Get-Content -Path $script:ApplyChangesWindowSchema -Raw
|
||||
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
|
||||
try {
|
||||
$applyWindow = [System.Windows.Markup.XamlReader]::Load($reader)
|
||||
}
|
||||
finally {
|
||||
$reader.Close()
|
||||
}
|
||||
|
||||
# Set owner to owner window if it exists
|
||||
if ($ownerWindow) {
|
||||
try {
|
||||
$applyWindow.Owner = $ownerWindow
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
# Apply theme resources
|
||||
SetWindowThemeResources -window $applyWindow -usesDarkMode $usesDarkMode
|
||||
|
||||
# Get UI elements
|
||||
$script:ApplyInProgressPanel = $applyWindow.FindName('ApplyInProgressPanel')
|
||||
$script:ApplyCompletionPanel = $applyWindow.FindName('ApplyCompletionPanel')
|
||||
$script:ApplyStepNameEl = $applyWindow.FindName('ApplyStepName')
|
||||
$script:ApplyStepCounterEl = $applyWindow.FindName('ApplyStepCounter')
|
||||
$script:ApplyProgressBarEl = $applyWindow.FindName('ApplyProgressBar')
|
||||
$script:ApplyCompletionTitleEl = $applyWindow.FindName('ApplyCompletionTitle')
|
||||
$script:ApplyCompletionMessageEl = $applyWindow.FindName('ApplyCompletionMessage')
|
||||
$script:ApplyCompletionIconEl = $applyWindow.FindName('ApplyCompletionIcon')
|
||||
$applyRebootPanel = $applyWindow.FindName('ApplyRebootPanel')
|
||||
$applyRebootList = $applyWindow.FindName('ApplyRebootList')
|
||||
$applyCloseBtn = $applyWindow.FindName('ApplyCloseBtn')
|
||||
$applyKofiBtn = $applyWindow.FindName('ApplyKofiBtn')
|
||||
$applyCancelBtn = $applyWindow.FindName('ApplyCancelBtn')
|
||||
|
||||
# Initialize in-progress state
|
||||
$script:ApplyInProgressPanel.Visibility = 'Visible'
|
||||
$script:ApplyCompletionPanel.Visibility = 'Collapsed'
|
||||
$script:ApplyStepNameEl.Text = "Preparing..."
|
||||
$script:ApplyStepCounterEl.Text = "Preparing..."
|
||||
$script:ApplyProgressBarEl.Value = 0
|
||||
$script:ApplyModalInErrorState = $false
|
||||
|
||||
# Set up progress callback for ExecuteAllChanges
|
||||
$script:ApplyProgressCallback = {
|
||||
param($currentStep, $totalSteps, $stepName)
|
||||
$script:ApplyStepNameEl.Text = $stepName
|
||||
$script:ApplyStepCounterEl.Text = "Step $currentStep of $totalSteps"
|
||||
# Store current step/total in Tag properties for sub-step interpolation
|
||||
$script:ApplyStepCounterEl.Tag = $currentStep
|
||||
$script:ApplyProgressBarEl.Tag = $totalSteps
|
||||
# Show progress at the start of each step (empty at step 1, full after last step completes)
|
||||
$pct = if ($totalSteps -gt 0) { [math]::Round((($currentStep - 1) / $totalSteps) * 100) } else { 0 }
|
||||
$script:ApplyProgressBarEl.Value = $pct
|
||||
# Process pending window messages to keep UI responsive
|
||||
DoEvents
|
||||
}
|
||||
|
||||
# Sub-step callback updates step name and interpolates progress bar within the current step
|
||||
$script:ApplySubStepCallback = {
|
||||
param($subStepName, $subIndex, $subCount)
|
||||
$script:ApplyStepNameEl.Text = $subStepName
|
||||
# Interpolate progress bar between previous step and current step
|
||||
$currentStep = [int]($script:ApplyStepCounterEl.Tag)
|
||||
$totalSteps = [int]($script:ApplyProgressBarEl.Tag)
|
||||
if ($totalSteps -gt 0 -and $subCount -gt 0) {
|
||||
$baseProgress = ($currentStep - 1) / $totalSteps
|
||||
$stepFraction = ($subIndex / $subCount) / $totalSteps
|
||||
$script:ApplyProgressBarEl.Value = [math]::Round(($baseProgress + $stepFraction) * 100)
|
||||
}
|
||||
DoEvents
|
||||
}
|
||||
|
||||
# Run changes in background to keep UI responsive
|
||||
$applyWindow.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{
|
||||
try {
|
||||
ExecuteAllChanges
|
||||
|
||||
# Restart explorer if requested
|
||||
if ($RestartExplorer -and -not $script:CancelRequested) {
|
||||
RestartExplorer
|
||||
|
||||
# Wait for Explorer to finish relaunching, then reclaim focus.
|
||||
Start-Sleep -Milliseconds 800
|
||||
$applyWindow.Dispatcher.Invoke([action]{
|
||||
$hwnd = (New-Object System.Windows.Interop.WindowInteropHelper($applyWindow)).Handle
|
||||
[Win11Debloat.FocusHelper]::ForceActivate($hwnd)
|
||||
})
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
if ($script:CancelRequested) {
|
||||
Write-Host "Script execution was cancelled by the user. Some changes may not have been applied."
|
||||
} else {
|
||||
Write-Host "All changes have been applied successfully!"
|
||||
}
|
||||
|
||||
# Show completion state
|
||||
$script:ApplyProgressBarEl.Value = 100
|
||||
$script:ApplyInProgressPanel.Visibility = 'Collapsed'
|
||||
$script:ApplyCompletionPanel.Visibility = 'Visible'
|
||||
|
||||
if ($script:CancelRequested) {
|
||||
$script:ApplyCompletionIconEl.Text = [char]0xE7BA
|
||||
$script:ApplyCompletionIconEl.Foreground = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#e8912d"))
|
||||
$script:ApplyCompletionTitleEl.Text = "Cancelled"
|
||||
$script:ApplyCompletionMessageEl.Text = "Script execution was cancelled by the user."
|
||||
} else {
|
||||
$script:ApplyCompletionTitleEl.Text = "Changes Applied"
|
||||
|
||||
# Show completion message with reboot instructions if any applied features require reboot
|
||||
if ($RestartExplorer) {
|
||||
$rebootFeatures = @()
|
||||
foreach ($paramKey in $script:Params.Keys) {
|
||||
if ($script:Features.ContainsKey($paramKey) -and $script:Features[$paramKey].RequiresReboot -eq $true) {
|
||||
$feature = $script:Features[$paramKey]
|
||||
$rebootFeatures += "$($feature.Action) $($feature.Label)"
|
||||
}
|
||||
}
|
||||
|
||||
if ($rebootFeatures.Count -gt 0) {
|
||||
foreach ($featureName in $rebootFeatures) {
|
||||
$tb = [System.Windows.Controls.TextBlock]::new()
|
||||
$tb.Text = "$([char]0x2022) $featureName"
|
||||
$tb.FontSize = 12
|
||||
$tb.SetResourceReference([System.Windows.Controls.TextBlock]::ForegroundProperty, 'FgColor')
|
||||
$tb.Opacity = 0.85
|
||||
$tb.Margin = [System.Windows.Thickness]::new(0, 2, 0, 0)
|
||||
$applyRebootList.Children.Add($tb) | Out-Null
|
||||
}
|
||||
$applyRebootPanel.Visibility = 'Visible'
|
||||
}
|
||||
else {
|
||||
$script:ApplyCompletionMessageEl.Text = "Your clean system is ready. Thanks for using Win11Debloat!"
|
||||
}
|
||||
}
|
||||
}
|
||||
$applyWindow.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Render, [action]{})
|
||||
}
|
||||
catch {
|
||||
Write-Host "Error: $($_.Exception.Message)"
|
||||
$script:ApplyInProgressPanel.Visibility = 'Collapsed'
|
||||
$script:ApplyCompletionPanel.Visibility = 'Visible'
|
||||
$script:ApplyCompletionIconEl.Text = [char]0xEA39
|
||||
$script:ApplyCompletionIconEl.Foreground = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#c42b1c"))
|
||||
$script:ApplyCompletionTitleEl.Text = "Error"
|
||||
$script:ApplyCompletionMessageEl.Text = "An error occurred while applying changes: $($_.Exception.Message)"
|
||||
|
||||
# Set error state to change Kofi button to report link
|
||||
$script:ApplyModalInErrorState = $true
|
||||
|
||||
# Update Kofi button to be a report issue button
|
||||
$applyKofiBtn.Content = $null
|
||||
|
||||
$reportText = [System.Windows.Controls.TextBlock]::new()
|
||||
$reportText.Text = 'Report a bug'
|
||||
$reportText.VerticalAlignment = 'Center'
|
||||
$reportText.FontSize = 14
|
||||
$reportText.Margin = [System.Windows.Thickness]::new(0, 0, 0, 1)
|
||||
|
||||
$applyKofiBtn.Content = $reportText
|
||||
|
||||
[System.Windows.Automation.AutomationProperties]::SetName($applyKofiBtn, 'Report a bug')
|
||||
|
||||
$applyWindow.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Render, [action]{})
|
||||
}
|
||||
finally {
|
||||
$script:ApplyProgressCallback = $null
|
||||
$script:ApplySubStepCallback = $null
|
||||
}
|
||||
}) | Out-Null
|
||||
|
||||
# Button handlers
|
||||
$applyCloseBtn.Add_Click({
|
||||
$applyWindow.Close()
|
||||
})
|
||||
|
||||
$applyKofiBtn.Add_Click({
|
||||
if ($script:ApplyModalInErrorState) {
|
||||
Start-Process "https://github.com/Raphire/Win11Debloat/issues/new"
|
||||
} else {
|
||||
Start-Process "https://ko-fi.com/raphire"
|
||||
}
|
||||
})
|
||||
|
||||
$applyCancelBtn.Add_Click({
|
||||
if ($script:ApplyCompletionPanel.Visibility -eq 'Visible') {
|
||||
# Completion state - just close
|
||||
$applyWindow.Close()
|
||||
} else {
|
||||
# In-progress state - request cancellation
|
||||
$script:CancelRequested = $true
|
||||
}
|
||||
})
|
||||
|
||||
# Show dialog
|
||||
$applyWindow.ShowDialog() | Out-Null
|
||||
|
||||
# Hide overlay after dialog closes
|
||||
if ($overlay) {
|
||||
try {
|
||||
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
115
Scripts/GUI/Show-Bubble.ps1
Normal file
115
Scripts/GUI/Show-Bubble.ps1
Normal file
@@ -0,0 +1,115 @@
|
||||
function Hide-Bubble {
|
||||
param (
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$Immediate
|
||||
)
|
||||
|
||||
if ($script:BubbleTimer) {
|
||||
$script:BubbleTimer.Stop()
|
||||
$script:BubbleTimer = $null
|
||||
}
|
||||
|
||||
if (-not $script:BubblePopup) { return }
|
||||
|
||||
if ($Immediate -or -not $script:BubblePopup.Child) {
|
||||
$script:BubblePopup.IsOpen = $false
|
||||
$script:BubblePopup = $null
|
||||
$script:BubbleIsClosing = $false
|
||||
return
|
||||
}
|
||||
|
||||
if ($script:BubbleIsClosing) { return }
|
||||
$script:BubbleIsClosing = $true
|
||||
|
||||
$bubblePanel = $script:BubblePopup.Child
|
||||
$fadeOut = New-Object System.Windows.Media.Animation.DoubleAnimation
|
||||
$fadeOut.From = [double]$bubblePanel.Opacity
|
||||
$fadeOut.To = 0
|
||||
$fadeOut.Duration = [System.Windows.Duration]::new([TimeSpan]::FromMilliseconds(220))
|
||||
$fadeOut.Add_Completed({
|
||||
if ($script:BubblePopup) {
|
||||
$script:BubblePopup.IsOpen = $false
|
||||
$script:BubblePopup = $null
|
||||
}
|
||||
$script:BubbleIsClosing = $false
|
||||
})
|
||||
|
||||
$bubblePanel.BeginAnimation([System.Windows.UIElement]::OpacityProperty, $fadeOut)
|
||||
}
|
||||
|
||||
function Show-Bubble {
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[System.Windows.Controls.Control]$TargetControl,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Message = 'View the selected changes here',
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[int]$DurationSeconds = 5
|
||||
)
|
||||
|
||||
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
|
||||
|
||||
if (-not $TargetControl) { return }
|
||||
|
||||
Hide-Bubble -Immediate
|
||||
|
||||
$xaml = Get-Content -Path $script:BubbleHintSchema -Raw
|
||||
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
|
||||
try {
|
||||
$bubblePanel = [System.Windows.Markup.XamlReader]::Load($reader)
|
||||
}
|
||||
finally {
|
||||
$reader.Close()
|
||||
}
|
||||
|
||||
$bubbleText = $bubblePanel.FindName('BubbleText')
|
||||
if ($bubbleText) {
|
||||
$bubbleText.Text = $Message
|
||||
}
|
||||
|
||||
$bubblePanel.BeginAnimation([System.Windows.UIElement]::OpacityProperty, $null)
|
||||
$bubblePanel.Opacity = 0
|
||||
|
||||
$popup = New-Object System.Windows.Controls.Primitives.Popup
|
||||
$popup.AllowsTransparency = $true
|
||||
$popup.PopupAnimation = 'None'
|
||||
$popup.StaysOpen = $true
|
||||
$popup.PlacementTarget = $TargetControl
|
||||
$popup.Placement = [System.Windows.Controls.Primitives.PlacementMode]::Top
|
||||
$popup.VerticalOffset = -1
|
||||
$popup.Child = $bubblePanel
|
||||
|
||||
$popup.Add_Opened({
|
||||
param($sender, $e)
|
||||
|
||||
if (-not $sender) { return }
|
||||
$panel = $sender.Child
|
||||
$target = $sender.PlacementTarget
|
||||
if (-not $panel -or -not $target) { return }
|
||||
|
||||
$panel.Measure([System.Windows.Size]::new([double]::PositiveInfinity, [double]::PositiveInfinity))
|
||||
$bubbleWidth = $panel.DesiredSize.Width
|
||||
$targetWidth = $target.ActualWidth
|
||||
$sender.HorizontalOffset = ($targetWidth - $bubbleWidth) / 2
|
||||
|
||||
$fadeIn = New-Object System.Windows.Media.Animation.DoubleAnimation
|
||||
$fadeIn.From = 0
|
||||
$fadeIn.To = 1
|
||||
$fadeIn.BeginTime = [TimeSpan]::FromMilliseconds(30)
|
||||
$fadeIn.Duration = [System.Windows.Duration]::new([TimeSpan]::FromMilliseconds(320))
|
||||
$panel.BeginAnimation([System.Windows.UIElement]::OpacityProperty, $fadeIn)
|
||||
})
|
||||
|
||||
$script:BubbleIsClosing = $false
|
||||
$script:BubblePopup = $popup
|
||||
$script:BubblePopup.IsOpen = $true
|
||||
|
||||
$script:BubbleTimer = New-Object System.Windows.Threading.DispatcherTimer
|
||||
$script:BubbleTimer.Interval = [TimeSpan]::FromSeconds([Math]::Max(1, $DurationSeconds))
|
||||
$script:BubbleTimer.Add_Tick({
|
||||
Hide-Bubble
|
||||
})
|
||||
$script:BubbleTimer.Start()
|
||||
}
|
||||
1753
Scripts/GUI/Show-MainWindow.ps1
Normal file
1753
Scripts/GUI/Show-MainWindow.ps1
Normal file
File diff suppressed because it is too large
Load Diff
166
Scripts/GUI/Show-MessageBox.ps1
Normal file
166
Scripts/GUI/Show-MessageBox.ps1
Normal file
@@ -0,0 +1,166 @@
|
||||
# Shows a Windows 11 styled custom message box
|
||||
function Show-MessageBox {
|
||||
param (
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Message,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Title = "Win11Debloat",
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[ValidateSet('OK', 'OKCancel', 'YesNo')]
|
||||
[string]$Button = 'OK',
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[ValidateSet('None', 'Information', 'Warning', 'Error', 'Question')]
|
||||
[string]$Icon = 'None',
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[System.Windows.Window]$Owner = $null,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[int]$Width = 0
|
||||
)
|
||||
|
||||
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
|
||||
|
||||
$usesDarkMode = GetSystemUsesDarkMode
|
||||
|
||||
# Determine owner window - use provided Owner, or fall back to main GUI window
|
||||
$ownerWindow = if ($Owner) { $Owner } else { $script:GuiWindow }
|
||||
|
||||
# Show overlay if owner window exists
|
||||
$overlay = $null
|
||||
$overlayWasAlreadyVisible = $false
|
||||
if ($ownerWindow) {
|
||||
try {
|
||||
$overlay = $ownerWindow.FindName('ModalOverlay')
|
||||
if ($overlay) {
|
||||
$overlayWasAlreadyVisible = ($overlay.Visibility -eq 'Visible')
|
||||
if (-not $overlayWasAlreadyVisible) {
|
||||
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
# Load XAML from file
|
||||
$xaml = Get-Content -Path $script:MessageBoxSchema -Raw
|
||||
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
|
||||
try {
|
||||
$msgWindow = [System.Windows.Markup.XamlReader]::Load($reader)
|
||||
}
|
||||
finally {
|
||||
$reader.Close()
|
||||
}
|
||||
|
||||
# Set owner to owner window if it exists
|
||||
if ($ownerWindow) {
|
||||
try {
|
||||
$msgWindow.Owner = $ownerWindow
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
# Apply custom width if specified
|
||||
if ($Width -gt 0) {
|
||||
$msgWindow.Width = $Width
|
||||
}
|
||||
|
||||
# Apply theme resources
|
||||
SetWindowThemeResources -window $msgWindow -usesDarkMode $usesDarkMode
|
||||
|
||||
# Get UI elements
|
||||
$titleText = $msgWindow.FindName('TitleText')
|
||||
$messageText = $msgWindow.FindName('MessageText')
|
||||
$iconText = $msgWindow.FindName('IconText')
|
||||
$button1 = $msgWindow.FindName('Button1')
|
||||
$button2 = $msgWindow.FindName('Button2')
|
||||
$titleBar = $msgWindow.FindName('TitleBar')
|
||||
|
||||
# Set title and message
|
||||
$titleText.Text = $Title
|
||||
$messageText.Text = $Message
|
||||
|
||||
# Configure icon
|
||||
switch ($Icon) {
|
||||
'Information' {
|
||||
$iconText.Text = [char]0xE946
|
||||
$iconText.Foreground = $msgWindow.FindResource('InformationIconColor')
|
||||
$iconText.Visibility = 'Visible'
|
||||
}
|
||||
'Warning' {
|
||||
$iconText.Text = [char]0xE7BA
|
||||
$iconText.Foreground = $msgWindow.FindResource('WarningIconColor')
|
||||
$iconText.Visibility = 'Visible'
|
||||
}
|
||||
'Error' {
|
||||
$iconText.Text = [char]0xEA39
|
||||
$iconText.Foreground = $msgWindow.FindResource('ErrorIconColor')
|
||||
$iconText.Visibility = 'Visible'
|
||||
}
|
||||
'Question' {
|
||||
$iconText.Text = [char]0xE897
|
||||
$iconText.Foreground = $msgWindow.FindResource('QuestionIconColor')
|
||||
$iconText.Visibility = 'Visible'
|
||||
}
|
||||
default {
|
||||
$iconText.Visibility = 'Collapsed'
|
||||
}
|
||||
}
|
||||
|
||||
# Configure buttons - store result in window's Tag property
|
||||
switch ($Button) {
|
||||
'OK' {
|
||||
$button1.Content = 'OK'
|
||||
$button1.Add_Click({ $msgWindow.Tag = 'OK'; $msgWindow.Close() })
|
||||
$button2.Visibility = 'Collapsed'
|
||||
}
|
||||
'OKCancel' {
|
||||
$button1.Content = 'OK'
|
||||
$button2.Content = 'Cancel'
|
||||
$button1.Add_Click({ $msgWindow.Tag = 'OK'; $msgWindow.Close() })
|
||||
$button2.Add_Click({ $msgWindow.Tag = 'Cancel'; $msgWindow.Close() })
|
||||
$button2.Visibility = 'Visible'
|
||||
}
|
||||
'YesNo' {
|
||||
$button1.Content = 'Yes'
|
||||
$button2.Content = 'No'
|
||||
$button1.Add_Click({ $msgWindow.Tag = 'Yes'; $msgWindow.Close() })
|
||||
$button2.Add_Click({ $msgWindow.Tag = 'No'; $msgWindow.Close() })
|
||||
$button2.Visibility = 'Visible'
|
||||
}
|
||||
}
|
||||
|
||||
# Title bar drag to move window
|
||||
$titleBar.Add_MouseLeftButtonDown({
|
||||
$msgWindow.DragMove()
|
||||
})
|
||||
|
||||
# Handle Escape key to close
|
||||
$msgWindow.Add_KeyDown({
|
||||
param($sender, $e)
|
||||
if ($e.Key -eq 'Escape') {
|
||||
if ($Button -eq 'OK') {
|
||||
$msgWindow.Tag = 'OK'
|
||||
} else {
|
||||
$msgWindow.Tag = 'Cancel'
|
||||
}
|
||||
$msgWindow.Close()
|
||||
}
|
||||
})
|
||||
|
||||
# Show dialog and return result from Tag
|
||||
$msgWindow.ShowDialog() | Out-Null
|
||||
|
||||
# Hide overlay after dialog closes (only if this dialog was the one that showed it)
|
||||
if ($overlay -and -not $overlayWasAlreadyVisible) {
|
||||
try {
|
||||
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
return $msgWindow.Tag
|
||||
}
|
||||
@@ -12,6 +12,7 @@ param (
|
||||
[switch]$RunDefaultsLite,
|
||||
[switch]$RunSavedSettings,
|
||||
[string]$Apps,
|
||||
[string]$AppRemovalTarget,
|
||||
[switch]$RemoveApps,
|
||||
[switch]$RemoveAppsCustom,
|
||||
[switch]$RemoveGamingApps,
|
||||
@@ -21,17 +22,24 @@ param (
|
||||
[switch]$ForceRemoveEdge,
|
||||
[switch]$DisableDVR,
|
||||
[switch]$DisableGameBarIntegration,
|
||||
[switch]$EnableWindowsSandbox,
|
||||
[switch]$EnableWindowsSubsystemForLinux,
|
||||
[switch]$DisableTelemetry,
|
||||
[switch]$DisableSearchHistory,
|
||||
[switch]$DisableFastStartup,
|
||||
[switch]$DisableBitlockerAutoEncryption,
|
||||
[switch]$DisableModernStandbyNetworking,
|
||||
[switch]$DisableStorageSense,
|
||||
[switch]$DisableUpdateASAP,
|
||||
[switch]$PreventUpdateAutoReboot,
|
||||
[switch]$DisableDeliveryOptimization,
|
||||
[switch]$DisableBing,
|
||||
[switch]$DisableStoreSearchSuggestions,
|
||||
[switch]$DisableDesktopSpotlight,
|
||||
[switch]$DisableLockscreenTips,
|
||||
[switch]$DisableSuggestions,
|
||||
[switch]$DisableLocationServices,
|
||||
[switch]$DisableFindMyDevice,
|
||||
[switch]$DisableEdgeAds,
|
||||
[switch]$DisableBraveBloat,
|
||||
[switch]$DisableSettings365Ads,
|
||||
@@ -49,13 +57,16 @@ param (
|
||||
[switch]$HideSearchTb, [switch]$ShowSearchIconTb, [switch]$ShowSearchLabelTb, [switch]$ShowSearchBoxTb,
|
||||
[switch]$HideTaskview,
|
||||
[switch]$DisableStartRecommended,
|
||||
[switch]$DisableStartAllApps,
|
||||
[switch]$DisableStartPhoneLink,
|
||||
[switch]$DisableCopilot,
|
||||
[switch]$DisableRecall,
|
||||
[switch]$DisableClickToDo,
|
||||
[switch]$DisableAISvcAutoStart,
|
||||
[switch]$DisablePaintAI,
|
||||
[switch]$DisableNotepadAI,
|
||||
[switch]$DisableEdgeAI,
|
||||
[switch]$DisableSearchHighlights,
|
||||
[switch]$DisableWidgets,
|
||||
[switch]$HideChat,
|
||||
[switch]$EnableEndTask,
|
||||
@@ -68,6 +79,10 @@ param (
|
||||
[switch]$DisableDragTray,
|
||||
[switch]$DisableMouseAcceleration,
|
||||
[switch]$DisableStickyKeys,
|
||||
[switch]$DisableWindowSnapping,
|
||||
[switch]$DisableSnapAssist,
|
||||
[switch]$DisableSnapLayouts,
|
||||
[switch]$HideTabsInAltTab, [switch]$Show3TabsInAltTab, [switch]$Show5TabsInAltTab, [switch]$Show20TabsInAltTab,
|
||||
[switch]$HideHome,
|
||||
[switch]$HideGallery,
|
||||
[switch]$ExplorerToHome,
|
||||
@@ -112,11 +127,29 @@ catch {
|
||||
Exit
|
||||
}
|
||||
|
||||
# Remove old script folder if it exists, except for CustomAppsList and LastUsedSettings.json files
|
||||
Write-Output ""
|
||||
Write-Output "> Cleaning up old Win11Debloat folder..."
|
||||
|
||||
# Remove old script folder if it exists, but keep config and log files
|
||||
if (Test-Path "$env:TEMP/Win11Debloat") {
|
||||
Write-Output ""
|
||||
Write-Output "> Cleaning up old Win11Debloat folder..."
|
||||
Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log | Remove-Item -Recurse -Force
|
||||
Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log,Config,Logs | Remove-Item -Recurse -Force
|
||||
}
|
||||
|
||||
$configDir = "$env:TEMP/Win11Debloat/Config"
|
||||
$backupDir = "$env:TEMP/Win11Debloat/ConfigOld"
|
||||
|
||||
# Temporarily move existing config files if they exist to prevent them from being overwritten by the new script files, will be moved back after the new script is unpacked
|
||||
if (Test-Path "$configDir") {
|
||||
New-Item -ItemType Directory -Path "$backupDir" -Force | Out-Null
|
||||
|
||||
$filesToKeep = @(
|
||||
'CustomAppsList',
|
||||
'LastUsedSettings.json'
|
||||
)
|
||||
|
||||
Get-ChildItem -Path "$configDir" -Recurse | Where-Object { $_.Name -in $filesToKeep } | Move-Item -Destination "$backupDir"
|
||||
|
||||
Remove-Item "$configDir" -Recurse -Force
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -131,6 +164,16 @@ Remove-Item "$env:TEMP/win11debloat.zip"
|
||||
# Move files
|
||||
Get-ChildItem -Path "$env:TEMP/Win11Debloat/Raphire-Win11Debloat-*" -Recurse | Move-Item -Destination "$env:TEMP/Win11Debloat"
|
||||
|
||||
# Add existing config files back to Config folder
|
||||
if (Test-Path "$backupDir") {
|
||||
if (-not (Test-Path "$configDir")) {
|
||||
New-Item -ItemType Directory -Path "$configDir" -Force | Out-Null
|
||||
}
|
||||
|
||||
Get-ChildItem -Path "$backupDir" -Recurse | Move-Item -Destination "$configDir"
|
||||
Remove-Item "$backupDir" -Recurse -Force
|
||||
}
|
||||
|
||||
# Make list of arguments to pass on to the script
|
||||
$arguments = $($PSBoundParameters.GetEnumerator() | ForEach-Object {
|
||||
if ($_.Value -eq $true) {
|
||||
@@ -152,6 +195,12 @@ else {
|
||||
$windowStyle = "Normal"
|
||||
}
|
||||
|
||||
# Remove Powershell 7 modules from path to prevent module loading issues in the script
|
||||
if ($PSVersionTable.PSVersion.Major -ge 7) {
|
||||
$NewPSModulePath = $env:PSModulePath -split ';' | Where-Object -FilterScript { $_ -like '*WindowsPowerShell*' }
|
||||
$env:PSModulePath = $NewPSModulePath -join ';'
|
||||
}
|
||||
|
||||
# Run Win11Debloat script with the provided arguments
|
||||
$debloatProcess = Start-Process powershell.exe -WindowStyle $windowStyle -PassThru -ArgumentList "-executionpolicy bypass -File $env:TEMP\Win11Debloat\Win11Debloat.ps1 $arguments" -Verb RunAs
|
||||
|
||||
@@ -166,7 +215,7 @@ if (Test-Path "$env:TEMP/Win11Debloat") {
|
||||
Write-Output "> Cleaning up..."
|
||||
|
||||
# Cleanup, remove Win11Debloat directory
|
||||
Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log | Remove-Item -Recurse -Force
|
||||
Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log,Win11Debloat-Run.log,Config,Logs | Remove-Item -Recurse -Force
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
15
Scripts/Helpers/AddParameter.ps1
Normal file
15
Scripts/Helpers/AddParameter.ps1
Normal file
@@ -0,0 +1,15 @@
|
||||
# Add parameter to script and write to file
|
||||
function AddParameter {
|
||||
param (
|
||||
$parameterName,
|
||||
$value = $true
|
||||
)
|
||||
|
||||
# Add parameter or update its value if key already exists
|
||||
if (-not $script:Params.ContainsKey($parameterName)) {
|
||||
$script:Params.Add($parameterName, $value)
|
||||
}
|
||||
else {
|
||||
$script:Params[$parameterName] = $value
|
||||
}
|
||||
}
|
||||
32
Scripts/Helpers/CheckIfUserExists.ps1
Normal file
32
Scripts/Helpers/CheckIfUserExists.ps1
Normal file
@@ -0,0 +1,32 @@
|
||||
function CheckIfUserExists {
|
||||
param (
|
||||
$userName
|
||||
)
|
||||
|
||||
if ($userName -match '[<>:"|?*]') {
|
||||
return $false
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($userName)) {
|
||||
return $false
|
||||
}
|
||||
|
||||
try {
|
||||
$userExists = Test-Path "$env:SystemDrive\Users\$userName"
|
||||
|
||||
if ($userExists) {
|
||||
return $true
|
||||
}
|
||||
|
||||
$userExists = Test-Path ($env:USERPROFILE -Replace ('\\' + $env:USERNAME + '$'), "\$userName")
|
||||
|
||||
if ($userExists) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "Something went wrong when trying to find the user directory path for user $userName. Please ensure the user exists on this system"
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
27
Scripts/Helpers/CheckModernStandbySupport.ps1
Normal file
27
Scripts/Helpers/CheckModernStandbySupport.ps1
Normal file
@@ -0,0 +1,27 @@
|
||||
# Check if this machine supports S0 Modern Standby power state. Returns true if S0 Modern Standby is supported, false otherwise.
|
||||
function CheckModernStandbySupport {
|
||||
$count = 0
|
||||
|
||||
try {
|
||||
switch -Regex (powercfg /a) {
|
||||
':' {
|
||||
$count += 1
|
||||
}
|
||||
|
||||
'(.*S0.{1,}\))' {
|
||||
if ($count -eq 1) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host "Error: Unable to check for S0 Modern Standby support, powercfg command failed" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Press any key to continue..."
|
||||
$null = [System.Console]::ReadKey()
|
||||
return $true
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
20
Scripts/Helpers/GenerateAppsList.ps1
Normal file
20
Scripts/Helpers/GenerateAppsList.ps1
Normal file
@@ -0,0 +1,20 @@
|
||||
# Generates a list of apps to remove based on the Apps parameter
|
||||
function GenerateAppsList {
|
||||
if (-not ($script:Params["Apps"] -and $script:Params["Apps"] -is [string])) {
|
||||
return @()
|
||||
}
|
||||
|
||||
$appMode = $script:Params["Apps"].toLower()
|
||||
|
||||
switch ($appMode) {
|
||||
'default' {
|
||||
$appsList = LoadAppsFromFile $script:AppsListFilePath
|
||||
return $appsList
|
||||
}
|
||||
default {
|
||||
$appsList = $script:Params["Apps"].Split(',') | ForEach-Object { $_.Trim() }
|
||||
$validatedAppsList = ValidateAppslist $appsList
|
||||
return $validatedAppsList
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Scripts/Helpers/GetFriendlyTargetUserName.ps1
Normal file
9
Scripts/Helpers/GetFriendlyTargetUserName.ps1
Normal file
@@ -0,0 +1,9 @@
|
||||
function GetFriendlyTargetUserName {
|
||||
$target = GetTargetUserForAppRemoval
|
||||
|
||||
switch ($target) {
|
||||
"AllUsers" { return "all users" }
|
||||
"CurrentUser" { return "the current user" }
|
||||
default { return "user $target" }
|
||||
}
|
||||
}
|
||||
9
Scripts/Helpers/GetTargetUserForAppRemoval.ps1
Normal file
9
Scripts/Helpers/GetTargetUserForAppRemoval.ps1
Normal file
@@ -0,0 +1,9 @@
|
||||
# Target is determined from $script:Params["AppRemovalTarget"] or defaults to "AllUsers"
|
||||
# Target values: "AllUsers" (removes for all users + from image), "CurrentUser", or a specific username
|
||||
function GetTargetUserForAppRemoval {
|
||||
if ($script:Params.ContainsKey("AppRemovalTarget")) {
|
||||
return $script:Params["AppRemovalTarget"]
|
||||
}
|
||||
|
||||
return "AllUsers"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user