Files
Win11Debloat/.github/CONTRIBUTING.md
T
SashankandGitHub 6feebba878 Add localization for app names and descriptions (#769)
* Translate app names and descriptions in Config/Apps.json

* Document Apps section and first-ID translation key for multi-ID apps

* Fix app list breaking when "Only show installed" runs translation in an isolated runspace
2026-10-01 21:25:34 +02:00

24 KiB

How to Contribute?

We welcome contributions from the community. You can contribute to Win11Debloat by:

  • Reporting issues and bugs here
  • Submitting feature requests here
  • 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.

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:

& ([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:

    git clone https://github.com/YOUR-USERNAME/Win11Debloat.git
    cd Win11Debloat
    
  3. Create a new branch for your contribution:

    git checkout -b feature/your-feature-name
    

Running the Script Locally

  1. Open PowerShell as an administrator

  2. Enable script execution if necessary:

    Set-ExecutionPolicy Bypass -Scope Process -Force
    
  3. Navigate to your Win11Debloat directory

  4. Run the script:

    .\Win11Debloat.ps1
    

Running Automated Tests

The automated tests use Pester 5 and are found in the Tests directory. They cover registry operations, app removal, CLI/GUI logic, and config handling. Some Windows behavior is mocked so the tests can run safely, but they do not replace manual testing on a Windows test environment.

The bootstrap option can be used to automatically install Pester on your machine and run the full suite of tests:

.\Scripts\Run-Tests.ps1 -Bootstrap

After the initial setup, you can simply run the full suite with:

.\Scripts\Run-Tests.ps1

For a focused test run during development, you can also call Pester directly:

Invoke-Pester -Path .\Tests\Invoke-Changes.Tests.ps1 -Output Detailed

GitHub Actions runs the same suite with Windows PowerShell 5.1 for pull requests and pushes to master.

Architecture & Design

Win11Debloat is a PowerShell script with a WPF (Windows Presentation Foundation)-based GUI and command-line interface. The CLI provides an alternative to the GUI, allowing most features to be invoked directly through command-line parameters. The project uses a data-driven architecture, separating feature and application definitions from the logic that applies them.

Entry Points

Win11Debloat.ps1 is the main entry point and can be launched directly or through one of the provided launchers:

  • Run.bat launches a locally downloaded copy of Win11Debloat.ps1.
  • Get.ps1 downloads Win11Debloat and launches Win11Debloat.ps1.

Both Get.ps1 and Win11Debloat.ps1 support command-line parameters, allowing Win11Debloat to be configured and run without using the GUI.

High-Level Architecture

Win11Debloat.ps1 loads the configuration and shared functions, then routes execution through either the WPF GUI or CLI. Both interfaces use the same underlying feature and app-removal engine.

flowchart TB
    Main[Win11Debloat.ps1] --> GUI[WPF GUI]
    Main --> CLI[CLI]

    Config["Config Files (JSON)"] --> GUI
    Config --> CLI

    GUI --> Changes[Apply Selected Changes]
    CLI --> Changes
    Config --> Changes

    Changes --> Regfiles[Regfiles]
    Changes --> Tools[Appx / WinGet]

Project Structure

Win11Debloat/
├── Win11Debloat.ps1             # Main PowerShell script
├── Run.bat                      # Local launcher
├── Scripts/                     # Additional PowerShell scripts and functions
│   ├── Get.ps1                  # Download-and-launch script
│   ├── Run-Tests.ps1            # Pester test runner (optionally bootstraps Pester)
│   ├── AppRemoval/              # App package removal logic
│   ├── CLI/                     # Command-line interface helpers
│   ├── Features/                # Feature apply, undo, backup, and restore logic
│   ├── FileIO/                  # File input/output helpers
│   ├── GUI/                     # GUI window definitions and logic
│   ├── Helpers/                 # Shared helper functions
│   └── Threading/               # Threading utilities
├── 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)
│   └── Languages/               # GUI translation files, one folder per culture code (e.g. en-US/)
├── Regfiles/                    # Registry files for all features
│   ├── Undo/                    # Registry files for reverting features
│   └── Sysprep/                 # Registry files for Sysprep mode
├── Schemas/                     # XAML views and shared GUI resources
├── Assets/                      # Static assets (icons, start menu templates)
├── Tests/                       # Pester tests for script and XAML contracts
├── Backups/                     # Registry backups (generated during use)
└── Logs/                        # Script logs (generated during use)

Implementation Guidelines

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, wiki, and other relevant documentation.
  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 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: For registry-backed features, create an Undo registry file for reversibility and a Sysprep registry file for applying changes to other users and Sysprep mode.

  3. Incorrect Registry Hives for Sysprep: Sysprep registry files are meant to apply changes to a different 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 may cause the script to fail when trying to apply or undo changes.

  5. Not Testing Undo Functionality: Always test that your undo registry file properly reverts all changes.

  6. 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.

  9. Missing Translation Entry: A new Feature, Category, UI Group, or App needs a matching entry in Config/Languages/en-US/ (see Localizing UI Text). Without one, the GUI silently falls back to displaying the raw FeatureId/CategoryId/GroupId/AppId instead of your Label/ToolTip/FriendlyName/Description text.

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: For an Appx app, find the package name with:

    Get-AppxPackage | Select-Object Name, PackageFullName
    

    For a WinGet app, use winget list and use its Id value.

  2. Edit Config/Apps.json: Add a new entry to the "Apps" array:

    {
      "FriendlyName": "Display Name",
      "AppId": "AppPackageIdentifier",
      "Description": "Brief description of the app",
      "SelectedByDefault": false,
      "Recommendation": "optional",
      "RemovalMethod": "Appx"
    }
    

    Field Descriptions:

    • FriendlyName: Display name shown in the GUI.
    • AppId: The package name from Get-AppxPackage or the Id from winget list, depending on removal method. Use an array when one app requires multiple identifiers. The GUI looks up the translation entry by the first ID in the array, key Apps.json by that one.
    • Description: Brief description of the app shown in the GUI.
    • SelectedByDefault: Set to true only for apps that are largely considered bloatware, otherwise set to false.
    • Recommendation: Indicates how strongly the app is recommended for removal. One of:
      • safe — safe to remove for most users
      • optional — can be safely removed if the user doesn't need the app
      • unsafe — should only remove if the user knows what they are doing
    • RemovalMethod: The method used to remove the app. One of:
      • Appx — remove as a standard Appx package via Remove-AppxPackage (most apps)
      • WinGet — remove via WinGet (winget uninstall). Use for non-Appx apps such as Microsoft Copilot.
  3. Add the English Translation Entry: Add a matching entry for your AppId to Config/Languages/en-US/Apps.json (see Localizing UI Text) with FriendlyName and Description matching what you set above, so the GUI shows them instead of the raw AppId.

  4. Follow the Guidelines:

    • Use clear, user-friendly names for FriendlyName
    • 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:

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:

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 Invoke-FeatureApply function (in Scripts/Features/Invoke-Changes.ps1) for your new feature. If your feature also requires custom undo logic (beyond a simple registry file import), add a corresponding entry to the Invoke-FeatureUndo function in the same file.

2. Add Feature to Features.json

Add your feature to the "Features" array in Config/Features.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,
  "RegistryKey": "Disable_YourFeature.reg",
  "ApplyText": "Disabling your feature",
  "UndoLabel": "Short description for the undo",
  "ApplyUndoText": "Enabling your feature",
  "RegistryUndoKey": "Enable_YourFeature.reg",
  "RequiresReboot": false,
  "DisableWhenApplied": false,
  "MinVersion": null,
  "MaxVersion": null
}

Field Descriptions:

  • FeatureId: Unique identifier, this must match parameter name in the Win11Debloat.ps1 and Get.ps1 files.
  • Label: Short description shown in the UI and wiki documentation.
  • 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.
  • 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.
  • UndoLabel: Short description for the undo shown in the UI.
  • ApplyUndoText: Message shown when undoing the feature.
  • 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.
  • DisableWhenApplied: Optional boolean. Set to true if the feature has no supported undo method.
  • 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:

[switch]$YourFeatureId,

4. Add the English Translation Entry

Add a matching entry for your FeatureId to Config/Languages/en-US/Features.json (see Localizing UI Text) so the GUI shows your Label/ToolTip/etc. instead of the raw FeatureId.

5. Add or Update Tests

Add or update Pester coverage for the new behavior, then run the full suite.

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:

{
  "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:

{
  "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:

    {
      "CategoryId": "YourCategoryId",
      "Name": "Your Category Name",
      "Icon": "&#xE####;"
    }
    

    CategoryId is the stable identifier used for tweak presets, app-removal scope, and localization lookups. Name stays as the English display fallback. Skip CategoryId and the category falls back to using its Name as the ID, which breaks translation lookups, so always set one.

Tip

Use Segoe Fluent Icon Assets for icon codes.

Adding UI Groups

UI Groups allow features to be grouped together in the GUI with a combobox (dropdown) selection. Add the group to the top-level "UiGroups" array in Config/Features.json and use a unique GroupId:

{
  "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"]
    }
  ]
}

Important

Define the referenced features before adding a group. Each FeatureId in a group's Values list must already be defined in the "Features" array in Features.json. Features referenced by a group are shown through that group rather than as standalone controls.

Add a matching entry for your GroupId to Config/Languages/en-US/Features.json (see Localizing UI Text) so the GUI shows your Label/ToolTip/option text instead of the raw GroupId.

Localizing UI Text

GUI text lives in Config/Languages/en-US/, not hardcoded in Schemas/*.xaml or Scripts/GUI/*.ps1. Adding or changing a Feature, Category, UI Group, or App means updating the matching English entry, or the GUI falls back to showing the raw ID.

  • Config/Languages/en-US/Features.json, under "Features", keyed by FeatureId. Add Label, ToolTip, ApplyText, UndoLabel, and ApplyUndoText to match whatever fields you set in Config/Features.json.
  • Config/Languages/en-US/Features.json, under "UiGroups", keyed by GroupId. Add Label, ToolTip, and a Values map of FeatureId: "Option label" matching the group's Values array.
  • Config/Languages/en-US/Categories.json, keyed by CategoryId. Add a Label for every new category.
  • Config/Languages/en-US/Apps.json, keyed by AppId. Add FriendlyName and Description for every new app.
  • Config/Languages/en-US/Chrome.json, a flat key/value map for static GUI chrome: buttons, dialog titles, tooltips not tied to a specific Feature/Category/UiGroup. Add a key here only for new static text, and reference it from XAML with a %LANG:YourKey% marker or from PowerShell with Get-Translation -Key 'YourKey'.

Check for an existing Chrome.json key with the same English text before adding a new one. Two keys holding identical strings is duplication waiting to drift.

Not everything needs a translation key. A throw guarding against a caller passing the wrong argument type, or any other error that signals a bug in the code rather than something the user did, stays as a plain English string. No user will ever see it.

A new language is its own pull request, not something bundled with unrelated changes.

Adding a New Language

  1. Create the language folder: copy Config/Languages/en-US/ to Config/Languages/<culture-code>/, using the .NET culture code the GUI should match (nl-NL, es-ES). This is also the folder matched against the user's Windows display language: exact match first, then a language-only prefix match (nl-BE falls back to nl-NL if that's the only Dutch folder present), then en-US if nothing matches.

  2. Translate the four files (Chrome.json, Features.json, Categories.json, Apps.json), keeping every key name exactly as it is in en-US. Only the values change. Leave a key untranslated and the GUI shows the en-US text for it instead of a blank or a crash, so a translation can land incrementally.

  3. Add the language's plural rule. Strings using the _one/_other suffix convention (see AppsSelectedCount_one in en-US/Chrome.json) need a matching case in Get-PluralCategory (Scripts/FileIO/Import-LanguageFile.ps1), keyed by language prefix ('nl'). Several languages share English's rule, singular at exactly 1, plural otherwise, and can reuse it as-is. Others need more categories: CLDR defines zero/one/two/few/many/other. Match your key suffixes to whatever categories your language's rule actually uses.

  4. Check your coverage. Dot-source Scripts/FileIO/Import-LanguageFile.ps1 and run Test-LanguageKeyCoverage -LanguageCode '<culture-code>' to diff your key set against en-US. Check ResolvedLanguageCode matches the folder you meant to test, MissingKeys is the same fallback-eligible gap from step 2, fine to leave for later, and ExtraKeys usually means a typo'd key name that nothing will ever look up.

  5. Test it. Run .\Win11Debloat.ps1 -Language '<culture-code>' to launch the GUI in that language regardless of your Windows display language, and click through every tab, dialog, and tooltip.

Submitting a Pull Request

  1. Commit your changes with clear, descriptive commit messages:

    git add .
    git commit -m "Add feature: Description of your changes"
    
  2. Push to your fork:

    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. For registry changes, include 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
  • Comment on an existing issue
  • Ask in your pull request