Compare commits

..

6 Commits

Author SHA1 Message Date
Jeffrey
9ee0126259 Bump version 2026-06-24 22:13:48 +02:00
Jeffrey
e23ecf36d6 Update minimum window sizing 2026-06-24 22:00:44 +02:00
Jeffrey
32dc3d6bdf Fix maximized window sizing (#673) 2026-06-24 21:45:53 +02:00
Jeffrey
f76adc5054 Add docstrings 2026-06-24 20:55:17 +02:00
Jeffrey
95b583606d Update start menu backup/restore with timestamped filenames (#672) 2026-06-24 17:32:45 +02:00
Jeffrey
693b805114 Simplify Window management (#671) 2026-06-24 14:40:48 +02:00
11 changed files with 298 additions and 261 deletions

View File

@@ -4,10 +4,10 @@ setlocal EnableDelayedExpansion
:: Set Windows Terminal installation paths. (Default and Scoop installation) :: Set Windows Terminal installation paths. (Default and Scoop installation)
set "wtDefaultPath=%LOCALAPPDATA%\Microsoft\WindowsApps\wt.exe" set "wtDefaultPath=%LOCALAPPDATA%\Microsoft\WindowsApps\wt.exe"
set "wtScoopPath=%USERPROFILE%\scoop\apps\windows-terminal\current\wt.exe" set "wtScoopPath=%USERPROFILE%\scoop\apps\windows-terminal\current\wt.exe"
set "logFile=%LOCALAPPDATA%\Win11Debloat\Logs\Win11Debloat-Run.log" set "logFile=%~dp0Logs\Win11Debloat-Run.log"
:: Ensure Logs folder exists :: Ensure Logs folder exists
if not exist "%LOCALAPPDATA%\Win11Debloat\Logs" mkdir "%LOCALAPPDATA%\Win11Debloat\Logs" if not exist "%~dp0Logs" mkdir "%~dp0Logs"
:: Determine which terminal exists :: Determine which terminal exists
if exist "%wtDefaultPath%" ( if exist "%wtDefaultPath%" (

View File

@@ -2,13 +2,13 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework" xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework"
Title="Win11Debloat" Title="Win11Debloat"
MinWidth="860" MinHeight="600" MinWidth="860" MinHeight="640"
ResizeMode="CanResize" ResizeMode="CanResize"
SnapsToDevicePixels="True" SnapsToDevicePixels="True"
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
WindowStyle="None" WindowStyle="None"
AllowsTransparency="True" AllowsTransparency="False"
Background="Transparent" Background="{DynamicResource AppBorderColor}"
Foreground="{DynamicResource AppFgColor}"> Foreground="{DynamicResource AppFgColor}">
<shell:WindowChrome.WindowChrome> <shell:WindowChrome.WindowChrome>
<shell:WindowChrome ResizeBorderThickness="5" <shell:WindowChrome ResizeBorderThickness="5"
@@ -464,7 +464,7 @@
<Grid> <Grid>
<StackPanel x:Name="HomeContentPanel" HorizontalAlignment="Center" VerticalAlignment="Top"> <StackPanel x:Name="HomeContentPanel" HorizontalAlignment="Center" VerticalAlignment="Top">
<!-- Logo --> <!-- Logo -->
<Viewbox Width="250" Height="250" Margin="0,0,0,24" HorizontalAlignment="Center"> <Viewbox Width="250" Height="250" Margin="0,0,0,16" HorizontalAlignment="Center">
<Grid Width="250" Height="250"> <Grid Width="250" Height="250">
<!-- Windows logo style icon --> <!-- Windows logo style icon -->
<Path x:Name="LogoFallback" Data="M0,0 L80,0 L80,80 L0,80 Z M90,0 L170,0 L170,80 L90,80 Z M0,90 L80,90 L80,170 L0,170 Z M90,90 L170,90 L170,170 L90,170 Z" <Path x:Name="LogoFallback" Data="M0,0 L80,0 L80,80 L0,80 Z M90,0 L170,0 L170,80 L90,80 Z M0,90 L80,90 L80,170 L0,170 Z M90,90 L170,90 L170,170 L90,170 Z"
@@ -483,7 +483,7 @@
<!-- Title --> <!-- Title -->
<TextBlock Text="Welcome to Win11Debloat" FontSize="40" FontWeight="SemiBold" Foreground="{DynamicResource AppFgColor}" HorizontalAlignment="Center"/> <TextBlock Text="Welcome to Win11Debloat" FontSize="40" FontWeight="SemiBold" Foreground="{DynamicResource AppFgColor}" HorizontalAlignment="Center"/>
<TextBlock TextWrapping="Wrap" Foreground="{DynamicResource AppFgColor}" FontSize="20" HorizontalAlignment="Center" Margin="0,8,0,64"> <TextBlock TextWrapping="Wrap" Foreground="{DynamicResource AppFgColor}" FontSize="20" HorizontalAlignment="Center" Margin="0,4,0,48">
<Run Text="Your clean Windows experience is just a few clicks away!"/> <Run Text="Your clean Windows experience is just a few clicks away!"/>
</TextBlock> </TextBlock>

View File

@@ -113,16 +113,15 @@ function ReplaceStartMenu {
return return
} }
$startMenuBackupsDir = Join-Path $script:AppDataPath 'Backups' $timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
if (-not (Test-Path $startMenuBackupsDir)) { $backupFileName = "Win11Debloat-StartBackup-$timestamp.bak"
New-Item -ItemType Directory -Path $startMenuBackupsDir -Force | Out-Null $startMenuDir = Split-Path $startMenuBinFile -Parent
} $backupBinFile = Join-Path $startMenuDir $backupFileName
$backupTimestamp = (Get-Date).ToString('yyyyMMdd_HHmmss')
$backupBinFile = Join-Path $startMenuBackupsDir "Win11Debloat-Start2BinBackup-$userName-$backupTimestamp.bak"
if (Test-Path $startMenuBinFile) { if (Test-Path $startMenuBinFile) {
# Backup current start menu file # Backup current start menu file
Move-Item -Path $startMenuBinFile -Destination $backupBinFile -Force Copy-Item -Path $startMenuBinFile -Destination $backupBinFile -Force
Write-Verbose "Start menu backup for user $userName saved to $backupFileName"
} }
else { else {
Write-Host "Unable to find original start2.bin file for user $userName, no backup was created for this user" -ForegroundColor Yellow Write-Host "Unable to find original start2.bin file for user $userName, no backup was created for this user" -ForegroundColor Yellow
@@ -194,6 +193,55 @@ function GetStartMenuUserNameFromPath {
} }
<#
.SYNOPSIS
Returns the path to the latest start menu backup file for the given scope.
.DESCRIPTION
Resolves the LocalState folder for the specified scope and returns the
full path to the most recent Win11Debloat-StartBackup-*.bak file, or
$null if no backup exists.
For CurrentUser, uses $env:LOCALAPPDATA directly. For AllUsers, scans
every user profile.
.PARAMETER Scope
The scope to check: CurrentUser or AllUsers.
.EXAMPLE
$backupPath = Get-StartMenuBackupPath -Scope 'CurrentUser'
.EXAMPLE
$backupPath = Get-StartMenuBackupPath -Scope 'AllUsers'
#>
function Get-StartMenuBackupPath {
param(
[Parameter(Mandatory)]
[ValidateSet('CurrentUser', 'AllUsers')]
[string]$Scope
)
if ($Scope -eq 'CurrentUser') {
$localStateDir = "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState"
$latestBackup = Get-ChildItem -Path (Join-Path $localStateDir 'Win11Debloat-StartBackup-*.bak') -ErrorAction SilentlyContinue |
Sort-Object Name -Descending |
Select-Object -First 1
if ($latestBackup) { return $latestBackup.FullName }
return $null
}
else {
$userPathString = GetUserDirectory -userName "*" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState"
$usersStartMenuPaths = Get-ChildItem -Path $userPathString -ErrorAction SilentlyContinue
foreach ($startMenuPath in $usersStartMenuPaths) {
$latestBackup = Get-ChildItem -Path (Join-Path $startMenuPath.FullName 'Win11Debloat-StartBackup-*.bak') -ErrorAction SilentlyContinue |
Sort-Object Name -Descending |
Select-Object -First 1
if ($latestBackup) { return $latestBackup.FullName }
}
return $null
}
}
<# <#
.SYNOPSIS .SYNOPSIS
@@ -209,14 +257,14 @@ function GetStartMenuUserNameFromPath {
The full path to the user's start2.bin file to restore. The full path to the user's start2.bin file to restore.
.PARAMETER BackupFilePath .PARAMETER BackupFilePath
Path to the backup file to restore from. If omitted, defaults to Path to the backup file to restore from. If omitted, automatically
StartMenuBinFile with a .bak extension. finds the latest Win11Debloat-StartBackup-*.bak file.
.EXAMPLE .EXAMPLE
RestoreStartMenuFromBackup -StartMenuBinFile "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin" RestoreStartMenuFromBackup -StartMenuBinFile "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin"
.EXAMPLE .EXAMPLE
RestoreStartMenuFromBackup -StartMenuBinFile "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin" -BackupFilePath "C:\Backups\start2.bin" RestoreStartMenuFromBackup -StartMenuBinFile "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin" -BackupFilePath "C:\Backups\Win11Debloat-StartBackup-20260101_120000.bak"
#> #>
function RestoreStartMenuFromBackup { function RestoreStartMenuFromBackup {
param( param(
@@ -226,20 +274,32 @@ function RestoreStartMenuFromBackup {
) )
$userName = GetStartMenuUserNameFromPath -StartMenuBinFile $StartMenuBinFile $userName = GetStartMenuUserNameFromPath -StartMenuBinFile $StartMenuBinFile
$backupTimestamp = (Get-Date).ToString('yyyyMMdd_HHmmss') $backupBinFile = if ([string]::IsNullOrWhiteSpace($BackupFilePath)) {
$startMenuBackupsDir = Join-Path $script:AppDataPath 'Backups' # Auto-detect latest backup in the same folder as the start2.bin
if (-not (Test-Path $startMenuBackupsDir)) { New-Item -ItemType Directory -Path $startMenuBackupsDir -Force | Out-Null } $startMenuDir = Split-Path $StartMenuBinFile -Parent
$latestBackup = Get-ChildItem -Path (Join-Path $startMenuDir 'Win11Debloat-StartBackup-*.bak') -ErrorAction SilentlyContinue |
Sort-Object Name -Descending |
Select-Object -First 1
$resolvedBackupPath = if ([string]::IsNullOrWhiteSpace($BackupFilePath)) { if ($latestBackup) { $latestBackup.FullName } else { $null }
Join-Path $startMenuBackupsDir "Win11Debloat-Start2BinBackup-$userName-$backupTimestamp.bak"
} }
else { else {
$BackupFilePath $BackupFilePath
} }
$currentBinBackup = Join-Path $startMenuBackupsDir "Win11Debloat-Start2BinRestore-$userName-$backupTimestamp.bak" $restoreTimestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$restoreBackupFileName = "Win11Debloat-StartRestore-$restoreTimestamp.bak"
$currentBinBackup = Join-Path (Split-Path $StartMenuBinFile -Parent) $restoreBackupFileName
if ([string]::IsNullOrWhiteSpace($backupBinFile)) {
return [PSCustomObject]@{
UserName = $userName
Result = $false
Message = "No start menu backup file found for user $userName."
}
}
if ($script:Params.ContainsKey("WhatIf")) { if ($script:Params.ContainsKey("WhatIf")) {
Write-Host "[WhatIf] Restore start menu for user $userName from backup $resolvedBackupPath" -ForegroundColor Cyan Write-Host "[WhatIf] Restore start menu for user $userName from backup $backupBinFile" -ForegroundColor Cyan
return [PSCustomObject]@{ return [PSCustomObject]@{
UserName = $userName UserName = $userName
Result = $true Result = $true
@@ -247,11 +307,11 @@ function RestoreStartMenuFromBackup {
} }
} }
if (-not (Test-Path -LiteralPath $resolvedBackupPath)) { if (-not (Test-Path -LiteralPath $backupBinFile)) {
return [PSCustomObject]@{ return [PSCustomObject]@{
UserName = $userName UserName = $userName
Result = $false Result = $false
Message = "Start menu backup file not found: $resolvedBackupPath" Message = "No start menu backup file found for user $userName."
} }
} }
@@ -260,7 +320,7 @@ function RestoreStartMenuFromBackup {
Move-Item -Path $StartMenuBinFile -Destination $currentBinBackup -Force Move-Item -Path $StartMenuBinFile -Destination $currentBinBackup -Force
} }
Copy-Item -Path $resolvedBackupPath -Destination $StartMenuBinFile -Force Copy-Item -Path $backupBinFile -Destination $StartMenuBinFile -Force
return [PSCustomObject]@{ return [PSCustomObject]@{
UserName = $userName UserName = $userName
Result = $true Result = $true
@@ -281,34 +341,26 @@ function RestoreStartMenuFromBackup {
Restores the start menu for the current target user from a backup. Restores the start menu for the current target user from a backup.
.DESCRIPTION .DESCRIPTION
Resolves the start2.bin path for the current user (or the user specified Resolves the start2.bin path for the currently logged-in user, then
via the -User parameter), then delegates to RestoreStartMenuFromBackup. delegates to RestoreStartMenuFromBackup.
Returns early with a warning if the user's start menu path cannot
be resolved.
.PARAMETER BackupFilePath .PARAMETER BackupFilePath
Path to the backup file to restore from. Path to the backup file to restore from. If omitted, automatically
finds the latest Win11Debloat-StartBackup-*.bak file.
.EXAMPLE .EXAMPLE
RestoreStartMenu -BackupFilePath "$env:LOCALAPPDATA\Win11Debloat\Backups\Win11Debloat-Start2BinBackup-Jeff-20260623_143000.bak" RestoreStartMenu
.EXAMPLE
RestoreStartMenu -BackupFilePath "C:\Backups\Win11Debloat-StartBackup-20260101_120000.bak"
#> #>
function RestoreStartMenu { function RestoreStartMenu {
param( param(
[Parameter(Mandatory)]
[string]$BackupFilePath [string]$BackupFilePath
) )
$targetUserName = GetUserName $targetUserName = $env:USERNAME
$startMenuBinFile = GetStartMenuBinPathForUser -UserName $targetUserName $startMenuBinFile = "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin"
if ([string]::IsNullOrWhiteSpace($startMenuBinFile)) {
Write-Host "Unable to resolve start menu path for user $targetUserName, nothing to restore" -ForegroundColor Yellow
return [PSCustomObject]@{
UserName = $targetUserName
Result = $false
Message = "Could not resolve start menu path for user $targetUserName."
}
}
Write-Host "Restoring start menu for user $targetUserName from backup..." Write-Host "Restoring start menu for user $targetUserName from backup..."
@@ -321,19 +373,24 @@ function RestoreStartMenu {
.DESCRIPTION .DESCRIPTION
Iterates over every existing user profile and restores each user's Iterates over every existing user profile and restores each user's
start2.bin from the specified backup file. For the Default user profile, start2.bin from the latest backup in their LocalState folder. For the
removes the start2.bin file (which was previously copied from a template) Default user profile, removes the start2.bin file (which was previously
so that new profiles revert to the system default start menu. copied from a template) so that new profiles revert to the system
default start menu.
.PARAMETER BackupFilePath .PARAMETER BackupFilePath
Path to the backup file to restore from. Path to the backup file to restore from. If omitted, automatically
finds the latest Win11Debloat-StartBackup-*.bak in each user's
LocalState folder.
.EXAMPLE .EXAMPLE
RestoreStartMenuForAllUsers -BackupFilePath "$env:LOCALAPPDATA\Win11Debloat\Backups\Win11Debloat-Start2BinBackup-Jeff-20260623_143000.bak" RestoreStartMenuForAllUsers
.EXAMPLE
RestoreStartMenuForAllUsers -BackupFilePath "C:\Backups\Win11Debloat-StartBackup-20260101_120000.bak"
#> #>
function RestoreStartMenuForAllUsers { function RestoreStartMenuForAllUsers {
param( param(
[Parameter(Mandatory)]
[string]$BackupFilePath [string]$BackupFilePath
) )

View File

@@ -1,71 +1,5 @@
# MainWindow-WindowChrome.ps1 # MainWindow-WindowChrome.ps1
# Window sizing, DPI-aware coordinate conversion, maximized-window taskbar-constraint helpers, and UI animations. # Window sizing, DPI-aware coordinate conversion, and UI animations.
function Register-MaximizedWindowHelper {
if (-not ([System.Management.Automation.PSTypeName]'Win11Debloat.MaximizedWindowHelper').Type) {
Add-Type -Namespace Win11Debloat -Name MaximizedWindowHelper `
-ReferencedAssemblies 'PresentationFramework','System.Windows.Forms','System.Drawing' `
-MemberDefinition @'
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct MINMAXINFO {
public POINT ptReserved, ptMaxSize, ptMaxPosition, ptMinTrackSize, ptMaxTrackSize;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct POINT { public int x, y; }
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern System.IntPtr MonitorFromWindow(System.IntPtr hwnd, uint dwFlags);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool GetMonitorInfo(System.IntPtr hMonitor, ref MONITORINFO lpmi);
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct RECT {
public int Left, Top, Right, Bottom;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private struct MONITORINFO {
public int cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
}
public static System.IntPtr WmGetMinMaxInfoHook(
System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) {
if (msg == 0x0024) { // WM_GETMINMAXINFO
var mmi = (MINMAXINFO)System.Runtime.InteropServices.Marshal.PtrToStructure(
lParam, typeof(MINMAXINFO));
const uint MONITOR_DEFAULTTONEAREST = 0x00000002;
var monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
var monitorInfo = new MONITORINFO();
monitorInfo.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(MONITORINFO));
if (monitor != System.IntPtr.Zero && GetMonitorInfo(monitor, ref monitorInfo)) {
mmi.ptMaxPosition.x = monitorInfo.rcWork.Left - monitorInfo.rcMonitor.Left;
mmi.ptMaxPosition.y = monitorInfo.rcWork.Top - monitorInfo.rcMonitor.Top;
mmi.ptMaxSize.x = monitorInfo.rcWork.Right - monitorInfo.rcWork.Left;
mmi.ptMaxSize.y = monitorInfo.rcWork.Bottom - monitorInfo.rcWork.Top;
}
else {
var screen = System.Windows.Forms.Screen.FromHandle(hwnd);
var wa = screen.WorkingArea;
var bounds = screen.Bounds;
mmi.ptMaxPosition.x = wa.Left - bounds.Left;
mmi.ptMaxPosition.y = wa.Top - bounds.Top;
mmi.ptMaxSize.x = wa.Width;
mmi.ptMaxSize.y = wa.Height;
}
System.Runtime.InteropServices.Marshal.StructureToPtr(mmi, lParam, true);
}
return System.IntPtr.Zero;
}
'@
}
}
# Convert screen-pixel coordinates to WPF device-independent pixels (DIP) # Convert screen-pixel coordinates to WPF device-independent pixels (DIP)
function ConvertTo-ScreenPointToDip { function ConvertTo-ScreenPointToDip {
@@ -118,16 +52,35 @@ function Update-MainWindowChrome {
) )
$windowStateMaximized = [System.Windows.WindowState]::Maximized $windowStateMaximized = [System.Windows.WindowState]::Maximized
$chrome = [System.Windows.Shell.WindowChrome]::GetWindowChrome($Window)
if ($Window.WindowState -eq $windowStateMaximized) { if ($Window.WindowState -eq $windowStateMaximized) {
$MainBorder.Margin = [System.Windows.Thickness]::new(0) $chrome = [System.Windows.Shell.WindowChrome]::GetWindowChrome($Window)
$resizeBorder = if ($chrome) { $chrome.ResizeBorderThickness } else { [System.Windows.SystemParameters]::WindowResizeBorderThickness }
# Compute margins using screen bounds vs working area
$marginLeft = $resizeBorder.Left
$marginTop = $resizeBorder.Top
$marginRight = $resizeBorder.Right
$marginBottom = $resizeBorder.Bottom
$screen = Get-WindowScreen -Window $Window
if ($screen) {
$workTL = ConvertTo-ScreenPointToDip -Window $Window -X $screen.WorkingArea.Left -Y $screen.WorkingArea.Top
$workSize = ConvertTo-ScreenPixelsToDip -Window $Window -Width $screen.WorkingArea.Width -Height $screen.WorkingArea.Height
$screenTL = ConvertTo-ScreenPointToDip -Window $Window -X $screen.Bounds.Left -Y $screen.Bounds.Top
$screenSize = ConvertTo-ScreenPixelsToDip -Window $Window -Width $screen.Bounds.Width -Height $screen.Bounds.Height
$marginLeft += ($workTL.X - $screenTL.X)
$marginTop += ($workTL.Y - $screenTL.Y)
$marginRight += ($screenTL.X + $screenSize.Width) - ($workTL.X + $workSize.Width)
$marginBottom += ($screenTL.Y + $screenSize.Height) - ($workTL.Y + $workSize.Height)
}
$MainBorder.Margin = [System.Windows.Thickness]::new($marginLeft, $marginTop, $marginRight, $marginBottom)
$MainBorder.BorderThickness = [System.Windows.Thickness]::new(0) $MainBorder.BorderThickness = [System.Windows.Thickness]::new(0)
$MainBorder.CornerRadius = [System.Windows.CornerRadius]::new(0) $MainBorder.CornerRadius = [System.Windows.CornerRadius]::new(0)
$MainBorder.Effect = $null $MainBorder.Effect = $null
$TitleBarBackground.CornerRadius = [System.Windows.CornerRadius]::new(0) $TitleBarBackground.CornerRadius = [System.Windows.CornerRadius]::new(0)
# Zero out resize borders when maximized so the entire title bar row is draggable
if ($chrome) { $chrome.ResizeBorderThickness = [System.Windows.Thickness]::new(0) }
} }
else { else {
$MainBorder.Margin = [System.Windows.Thickness]::new(0) $MainBorder.Margin = [System.Windows.Thickness]::new(0)
@@ -135,7 +88,6 @@ function Update-MainWindowChrome {
$MainBorder.CornerRadius = [System.Windows.CornerRadius]::new(8) $MainBorder.CornerRadius = [System.Windows.CornerRadius]::new(8)
$MainBorder.Effect = $NormalWindowShadow $MainBorder.Effect = $NormalWindowShadow
$TitleBarBackground.CornerRadius = [System.Windows.CornerRadius]::new(8, 8, 0, 0) $TitleBarBackground.CornerRadius = [System.Windows.CornerRadius]::new(8, 8, 0, 0)
if ($chrome) { $chrome.ResizeBorderThickness = [System.Windows.Thickness]::new(5) }
} }
} }

View File

@@ -1,3 +1,23 @@
<#
.SYNOPSIS
Hides the currently displayed bubble popup.
.DESCRIPTION
Closes the bubble popup with a smooth fade-out animation (220ms). If the
-Immediate switch is used, the popup is closed instantly without animation.
This function is called automatically by Show-Bubble's timer and can also
be invoked manually to dismiss the bubble early.
.PARAMETER Immediate
If specified, the bubble popup is closed instantly without a fade-out
animation. Any pending close timer is also stopped.
.EXAMPLE
Hide-Bubble
.EXAMPLE
Hide-Bubble -Immediate
#>
function Hide-Bubble { function Hide-Bubble {
param ( param (
[Parameter(Mandatory=$false)] [Parameter(Mandatory=$false)]
@@ -37,6 +57,34 @@ function Hide-Bubble {
$bubblePanel.BeginAnimation([System.Windows.UIElement]::OpacityProperty, $fadeOut) $bubblePanel.BeginAnimation([System.Windows.UIElement]::OpacityProperty, $fadeOut)
} }
<#
.SYNOPSIS
Displays a transient bubble popup hint anchored above a target control.
.DESCRIPTION
Shows a WPF popup styled as a speech bubble above the specified target
control. The bubble fades in with a animation, displays for a configurable
duration, then fades out. Any previously shown bubble is dismissed
immediately before showing the new one.
.PARAMETER TargetControl
The WPF Control above which the bubble popup will be placed. This
parameter is mandatory.
.PARAMETER Message
The text message to display inside the bubble. Defaults to
'View the selected changes here'.
.PARAMETER DurationSeconds
The number of seconds the bubble remains visible before auto-hiding.
The minimum value is 1 second. Defaults to 5 seconds.
.EXAMPLE
Show-Bubble -TargetControl $myButton
.EXAMPLE
Show-Bubble -TargetControl $myButton -Message 'Changes saved!' -DurationSeconds 3
#>
function Show-Bubble { function Show-Bubble {
param ( param (
[Parameter(Mandatory=$true)] [Parameter(Mandatory=$true)]

View File

@@ -1,71 +1,6 @@
function Show-MainWindow { function Show-MainWindow {
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase,System.Windows.Forms | Out-Null Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase,System.Windows.Forms | Out-Null
# ---- Constrain maximized window to taskbar work area ----
if (-not ([System.Management.Automation.PSTypeName]'Win11Debloat.MaximizedWindowHelper').Type) {
Add-Type -Namespace Win11Debloat -Name MaximizedWindowHelper `
-ReferencedAssemblies 'PresentationFramework','System.Windows.Forms','System.Drawing' `
-MemberDefinition @'
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct MINMAXINFO {
public POINT ptReserved, ptMaxSize, ptMaxPosition, ptMinTrackSize, ptMaxTrackSize;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct POINT { public int x, y; }
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern System.IntPtr MonitorFromWindow(System.IntPtr hwnd, uint dwFlags);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool GetMonitorInfo(System.IntPtr hMonitor, ref MONITORINFO lpmi);
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
private struct RECT {
public int Left, Top, Right, Bottom;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private struct MONITORINFO {
public int cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
}
public static System.IntPtr WmGetMinMaxInfoHook(
System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) {
if (msg == 0x0024) { // WM_GETMINMAXINFO
var mmi = (MINMAXINFO)System.Runtime.InteropServices.Marshal.PtrToStructure(
lParam, typeof(MINMAXINFO));
const uint MONITOR_DEFAULTTONEAREST = 0x00000002;
var monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
var monitorInfo = new MONITORINFO();
monitorInfo.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(MONITORINFO));
if (monitor != System.IntPtr.Zero && GetMonitorInfo(monitor, ref monitorInfo)) {
mmi.ptMaxPosition.x = monitorInfo.rcWork.Left - monitorInfo.rcMonitor.Left;
mmi.ptMaxPosition.y = monitorInfo.rcWork.Top - monitorInfo.rcMonitor.Top;
mmi.ptMaxSize.x = monitorInfo.rcWork.Right - monitorInfo.rcWork.Left;
mmi.ptMaxSize.y = monitorInfo.rcWork.Bottom - monitorInfo.rcWork.Top;
}
else {
var screen = System.Windows.Forms.Screen.FromHandle(hwnd);
var wa = screen.WorkingArea;
var bounds = screen.Bounds;
mmi.ptMaxPosition.x = wa.Left - bounds.Left;
mmi.ptMaxPosition.y = wa.Top - bounds.Top;
mmi.ptMaxSize.x = wa.Width;
mmi.ptMaxSize.y = wa.Height;
}
System.Runtime.InteropServices.Marshal.StructureToPtr(mmi, lParam, true);
}
return System.IntPtr.Zero;
}
'@
}
$WinVersion = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' CurrentBuild $WinVersion = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' CurrentBuild
$usesDarkMode = GetSystemUsesDarkMode $usesDarkMode = GetSystemUsesDarkMode
@@ -123,12 +58,6 @@
$window.Add_SourceInitialized({ $window.Add_SourceInitialized({
& $applyInitialWindowSize & $applyInitialWindowSize
& $updateWindowChrome & $updateWindowChrome
$hwndHelper = New-Object System.Windows.Interop.WindowInteropHelper($window)
$hwndSource = [System.Windows.Interop.HwndSource]::FromHwnd($hwndHelper.Handle)
$hookMethod = [Win11Debloat.MaximizedWindowHelper].GetMethod('WmGetMinMaxInfoHook')
$hook = [System.Delegate]::CreateDelegate([System.Windows.Interop.HwndSourceHook], $hookMethod)
$hwndSource.AddHook($hook)
}) })
$window.Add_SizeChanged({ $window.Add_SizeChanged({
@@ -159,7 +88,7 @@
$menuReportBug.Add_Click({ Start-Process "https://github.com/Raphire/Win11Debloat/issues" }) $menuReportBug.Add_Click({ Start-Process "https://github.com/Raphire/Win11Debloat/issues" })
$menuLogs.Add_Click({ $menuLogs.Add_Click({
$logsFolder = Split-Path $script:DefaultLogPath -Parent $logsFolder = Join-Path (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) 'Logs'
if (Test-Path $logsFolder) { if (Test-Path $logsFolder) {
Start-Process "explorer.exe" -ArgumentList $logsFolder Start-Process "explorer.exe" -ArgumentList $logsFolder
} }

View File

@@ -61,7 +61,6 @@ function Show-RestoreBackupDialog {
$startMenuIntroPanel = $window.FindName('StartMenuIntroPanel') $startMenuIntroPanel = $window.FindName('StartMenuIntroPanel')
$startMenuScopeCombo = $window.FindName('StartMenuScopeCombo') $startMenuScopeCombo = $window.FindName('StartMenuScopeCombo')
$startMenuAutoBackupCheck = $window.FindName('StartMenuAutoBackupCheck') $startMenuAutoBackupCheck = $window.FindName('StartMenuAutoBackupCheck')
$startMenuAutoBackupCheck.Visibility = 'Collapsed'
$introInfoPanel = $window.FindName('IntroInfoPanel') $introInfoPanel = $window.FindName('IntroInfoPanel')
$overviewPanel = $window.FindName('OverviewPanel') $overviewPanel = $window.FindName('OverviewPanel')
$overviewFeaturesSection = $window.FindName('OverviewFeaturesSection') $overviewFeaturesSection = $window.FindName('OverviewFeaturesSection')
@@ -149,8 +148,9 @@ function Show-RestoreBackupDialog {
return return
} }
$hasSelectedFile = -not [string]::IsNullOrWhiteSpace($state.SelectedStartMenuBackupFilePath) $isAutoBackupEnabled = ($startMenuAutoBackupCheck.IsChecked -eq $true)
if ($hasSelectedFile) { $hasSelectedManualFile = -not [string]::IsNullOrWhiteSpace($state.SelectedStartMenuBackupFilePath)
if ($isAutoBackupEnabled -or $hasSelectedManualFile) {
$primaryActionBtn.Content = 'Restore backup' $primaryActionBtn.Content = 'Restore backup'
} }
else { else {
@@ -196,6 +196,10 @@ function Show-RestoreBackupDialog {
$primaryActionBtn.Visibility = 'Visible' $primaryActionBtn.Visibility = 'Visible'
$primaryActionBtn.IsDefault = $true $primaryActionBtn.IsDefault = $true
$chooseRegistryBtn.IsDefault = $false $chooseRegistryBtn.IsDefault = $false
# Show intro panel so user can configure scope & auto-detect
$startMenuAutoBackupCheck.IsChecked = $true
$state.SelectedStartMenuBackupFilePath = $null
& $refreshStartMenuUi & $refreshStartMenuUi
} }
@@ -302,11 +306,15 @@ function Show-RestoreBackupDialog {
} }
$handleStartMenuPrimaryAction = { $handleStartMenuPrimaryAction = {
if ([string]::IsNullOrWhiteSpace($state.SelectedStartMenuBackupFilePath)) { $scope = (& $getStartMenuScopeInfo).Scope
$useManualBackupFile = -not ($startMenuAutoBackupCheck.IsChecked -eq $true)
if ($useManualBackupFile -and [string]::IsNullOrWhiteSpace($state.SelectedStartMenuBackupFilePath)) {
$openDialog = New-Object Microsoft.Win32.OpenFileDialog $openDialog = New-Object Microsoft.Win32.OpenFileDialog
$openDialog.Title = 'Select Start Menu Backup File' $openDialog.Title = 'Select Start Menu Backup File'
$openDialog.Filter = 'Start Menu backup (*.bak)|*.bak' $openDialog.Filter = 'Start Menu backup (*.bak)|*.bak'
$openDialog.InitialDirectory = (Join-Path $script:AppDataPath 'Backups') $openDialog.InitialDirectory = "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState"
$openDialog.DefaultExt = '.bak'
if ($openDialog.ShowDialog($window) -ne $true) { if ($openDialog.ShowDialog($window) -ne $true) {
return return
@@ -318,10 +326,21 @@ function Show-RestoreBackupDialog {
return return
} }
$scope = (& $getStartMenuScopeInfo).Scope if (-not $useManualBackupFile) {
$scopeInfo = & $getStartMenuScopeInfo
$autoBackupPath = Get-StartMenuBackupPath -Scope $scopeInfo.Scope
if ($null -eq $autoBackupPath) {
$scopeText = $scopeInfo.SummaryText
Show-MessageBox -Owner $window -Title 'No Backup Found' -Message "No Start Menu backup file was found for $scopeText. Uncheck 'Automatically find Start Menu backup' to select a backup file manually." -Button 'OK' -Icon 'Warning' | Out-Null
return
}
$state.SelectedStartMenuBackupFilePath = if ($scopeInfo.Scope -eq 'CurrentUser') { $autoBackupPath } else { $null }
}
$window.Tag = @{ $window.Tag = @{
Result = 'RestoreStartMenu' Result = 'RestoreStartMenu'
StartMenuScope = $scope StartMenuScope = $scope
UseManualBackupFile = $useManualBackupFile
BackupFilePath = $state.SelectedStartMenuBackupFilePath BackupFilePath = $state.SelectedStartMenuBackupFilePath
} }
$window.DialogResult = $true $window.DialogResult = $true
@@ -340,7 +359,16 @@ function Show-RestoreBackupDialog {
} }
} }
$startMenuAutoBackupCheck.Add_Checked({
$state.SelectedStartMenuBackupFilePath = $null
& $refreshStartMenuUi
})
$startMenuAutoBackupCheck.Add_Unchecked({
& $refreshStartMenuUi
})
$startMenuScopeCombo.Add_SelectionChanged({ $startMenuScopeCombo.Add_SelectionChanged({
$state.SelectedStartMenuBackupFilePath = $null
& $refreshStartMenuUi & $refreshStartMenuUi
}) })
@@ -374,6 +402,7 @@ function Show-RestoreBackupDialog {
if ($state.WizardStep -eq 'StartMenu') { if ($state.WizardStep -eq 'StartMenu') {
$state.SelectedStartMenuBackupFilePath = $null $state.SelectedStartMenuBackupFilePath = $null
$startMenuAutoBackupCheck.IsChecked = $true
} }
& $setWizardStep 'SelectType' & $setWizardStep 'SelectType'

View File

@@ -40,6 +40,7 @@ function Show-RestoreBackupWindow {
} }
elseif ($dialogResult.Result -eq 'RestoreStartMenu') { elseif ($dialogResult.Result -eq 'RestoreStartMenu') {
$scope = $dialogResult.StartMenuScope $scope = $dialogResult.StartMenuScope
$useManualBackupFile = ($dialogResult.UseManualBackupFile -eq $true)
$backupFilePath = $null $backupFilePath = $null
if ($dialogResult -is [hashtable] -and $dialogResult.ContainsKey('BackupFilePath')) { if ($dialogResult -is [hashtable] -and $dialogResult.ContainsKey('BackupFilePath')) {
$backupFilePath = $dialogResult['BackupFilePath'] $backupFilePath = $dialogResult['BackupFilePath']
@@ -48,7 +49,7 @@ function Show-RestoreBackupWindow {
$backupFilePath = $dialogResult.BackupFilePath $backupFilePath = $dialogResult.BackupFilePath
} }
if ([string]::IsNullOrWhiteSpace($backupFilePath)) { if ($useManualBackupFile -and [string]::IsNullOrWhiteSpace($backupFilePath)) {
throw 'Start Menu restore canceled: no backup file selected.' throw 'Start Menu restore canceled: no backup file selected.'
} }

View File

@@ -131,33 +131,31 @@ catch {
Exit Exit
} }
# Migrate old user data from previous runs to AppData before cleanup # Remove old script folder if it exists, but keep configs, logs and backups
if (Test-Path $tempWorkPath) { if (Test-Path $tempWorkPath) {
$appDataPath = Join-Path $env:LOCALAPPDATA 'Win11Debloat'
if (-not (Test-Path $appDataPath)) { New-Item -ItemType Directory -Path $appDataPath -Force | Out-Null }
$oldBackupsDir = Join-Path $tempWorkPath 'Backups'
$oldLogsDir = Join-Path $tempWorkPath 'Logs'
$oldSettingsFile = Join-Path $tempWorkPath 'Config\LastUsedSettings.json'
if ((Test-Path $oldBackupsDir) -and (Get-ChildItem -Path $oldBackupsDir -ErrorAction SilentlyContinue)) {
$newBackupsDir = Join-Path $appDataPath 'Backups'
if (-not (Test-Path $newBackupsDir)) { New-Item -ItemType Directory -Path $newBackupsDir -Force | Out-Null }
Get-ChildItem -Path $oldBackupsDir | Move-Item -Destination $newBackupsDir -Force -ErrorAction SilentlyContinue
}
if ((Test-Path $oldLogsDir) -and (Get-ChildItem -Path $oldLogsDir -ErrorAction SilentlyContinue)) {
$newLogsDir = Join-Path $appDataPath 'Logs'
if (-not (Test-Path $newLogsDir)) { New-Item -ItemType Directory -Path $newLogsDir -Force | Out-Null }
Get-ChildItem -Path $oldLogsDir | Move-Item -Destination $newLogsDir -Force -ErrorAction SilentlyContinue
}
if (Test-Path $oldSettingsFile) {
Move-Item -Path $oldSettingsFile -Destination $appDataPath -Force -ErrorAction SilentlyContinue
}
Write-Output "" Write-Output ""
Write-Output "> Cleaning up old Win11Debloat folder..." Write-Output "> Cleaning up old Win11Debloat folder..."
Remove-Item $tempWorkPath -Recurse -Force Get-ChildItem -Path $tempWorkPath -Exclude Config,Logs,Backups | Remove-Item -Recurse -Force
}
$configDir = Join-Path $tempWorkPath 'Config'
$backupDir = Join-Path $tempWorkPath '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") {
Write-Output ""
Write-Output "> Backing up existing config files..."
New-Item -ItemType Directory -Path "$backupDir" -Force | Out-Null
$filesToKeep = @(
'LastUsedSettings.json'
)
Get-ChildItem -Path "$configDir" -Recurse | Where-Object { $_.Name -in $filesToKeep } | Move-Item -Destination "$backupDir"
Remove-Item "$configDir" -Recurse -Force
} }
Write-Output "" Write-Output ""
@@ -172,6 +170,19 @@ Remove-Item $tempArchivePath
# Move files # Move files
Get-ChildItem -Path (Join-Path $tempWorkPath '*Win11Debloat-*') -Recurse | Move-Item -Destination $tempWorkPath Get-ChildItem -Path (Join-Path $tempWorkPath '*Win11Debloat-*') -Recurse | Move-Item -Destination $tempWorkPath
# 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
}
Write-Output ""
Write-Output "> Restoring existing config files..."
Get-ChildItem -Path "$backupDir" -Recurse | Move-Item -Destination "$configDir"
Remove-Item "$backupDir" -Recurse -Force
}
# Make list of arguments to pass on to the script # Make list of arguments to pass on to the script
$arguments = $($PSBoundParameters.GetEnumerator() | ForEach-Object { $arguments = $($PSBoundParameters.GetEnumerator() | ForEach-Object {
if ($_.Value -eq $true) { if ($_.Value -eq $true) {
@@ -208,12 +219,13 @@ if ($null -ne $debloatProcess) {
$debloatProcess.WaitForExit() $debloatProcess.WaitForExit()
} }
# Remove all remaining script files # Remove all remaining script files, except for configs, logs and backups
if (Test-Path $tempWorkPath) { if (Test-Path $tempWorkPath) {
Write-Output "" Write-Output ""
Write-Output "> Cleaning up..." Write-Output "> Cleaning up..."
Remove-Item $tempWorkPath -Recurse -Force # Cleanup, remove Win11Debloat directory
Get-ChildItem -Path $tempWorkPath -Exclude Config,Logs,Backups | Remove-Item -Recurse -Force
} }
Write-Output "" Write-Output ""

View File

@@ -132,33 +132,31 @@ catch {
Exit Exit
} }
# Migrate old user data from previous runs to AppData before cleanup # Remove old script folder if it exists, but keep configs, logs and backups
if (Test-Path $tempWorkPath) { if (Test-Path $tempWorkPath) {
$appDataPath = Join-Path $env:LOCALAPPDATA 'Win11Debloat'
if (-not (Test-Path $appDataPath)) { New-Item -ItemType Directory -Path $appDataPath -Force | Out-Null }
$oldBackupsDir = Join-Path $tempWorkPath 'Backups'
$oldLogsDir = Join-Path $tempWorkPath 'Logs'
$oldSettingsFile = Join-Path $tempWorkPath 'Config\LastUsedSettings.json'
if ((Test-Path $oldBackupsDir) -and (Get-ChildItem -Path $oldBackupsDir -ErrorAction SilentlyContinue)) {
$newBackupsDir = Join-Path $appDataPath 'Backups'
if (-not (Test-Path $newBackupsDir)) { New-Item -ItemType Directory -Path $newBackupsDir -Force | Out-Null }
Get-ChildItem -Path $oldBackupsDir | Move-Item -Destination $newBackupsDir -Force -ErrorAction SilentlyContinue
}
if ((Test-Path $oldLogsDir) -and (Get-ChildItem -Path $oldLogsDir -ErrorAction SilentlyContinue)) {
$newLogsDir = Join-Path $appDataPath 'Logs'
if (-not (Test-Path $newLogsDir)) { New-Item -ItemType Directory -Path $newLogsDir -Force | Out-Null }
Get-ChildItem -Path $oldLogsDir | Move-Item -Destination $newLogsDir -Force -ErrorAction SilentlyContinue
}
if (Test-Path $oldSettingsFile) {
Move-Item -Path $oldSettingsFile -Destination $appDataPath -Force -ErrorAction SilentlyContinue
}
Write-Output "" Write-Output ""
Write-Output "> Cleaning up old Win11Debloat folder..." Write-Output "> Cleaning up old Win11Debloat folder..."
Remove-Item $tempWorkPath -Recurse -Force Get-ChildItem -Path $tempWorkPath -Exclude Config,Logs,Backups | Remove-Item -Recurse -Force
}
$configDir = Join-Path $tempWorkPath 'Config'
$backupDir = Join-Path $tempWorkPath '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") {
Write-Output ""
Write-Output "> Backing up existing config files..."
New-Item -ItemType Directory -Path "$backupDir" -Force | Out-Null
$filesToKeep = @(
'LastUsedSettings.json'
)
Get-ChildItem -Path "$configDir" -Recurse | Where-Object { $_.Name -in $filesToKeep } | Move-Item -Destination "$backupDir"
Remove-Item "$configDir" -Recurse -Force
} }
Write-Output "" Write-Output ""
@@ -173,6 +171,19 @@ Remove-Item $tempArchivePath
# Move files # Move files
Get-ChildItem -Path (Join-Path $tempWorkPath '*Win11Debloat-*') -Recurse | Move-Item -Destination $tempWorkPath Get-ChildItem -Path (Join-Path $tempWorkPath '*Win11Debloat-*') -Recurse | Move-Item -Destination $tempWorkPath
# 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
}
Write-Output ""
Write-Output "> Restoring existing config files..."
Get-ChildItem -Path "$backupDir" -Recurse | Move-Item -Destination "$configDir"
Remove-Item "$backupDir" -Recurse -Force
}
# Make list of arguments to pass on to the script # Make list of arguments to pass on to the script
$arguments = $($PSBoundParameters.GetEnumerator() | ForEach-Object { $arguments = $($PSBoundParameters.GetEnumerator() | ForEach-Object {
if ($_.Value -eq $true) { if ($_.Value -eq $true) {
@@ -209,12 +220,13 @@ if ($null -ne $debloatProcess) {
$debloatProcess.WaitForExit() $debloatProcess.WaitForExit()
} }
# Remove all remaining script files # Remove all remaining script files, except for configs, logs and backups
if (Test-Path $tempWorkPath) { if (Test-Path $tempWorkPath) {
Write-Output "" Write-Output ""
Write-Output "> Cleaning up..." Write-Output "> Cleaning up..."
Remove-Item $tempWorkPath -Recurse -Force # Cleanup, remove Win11Debloat directory
Get-ChildItem -Path $tempWorkPath -Exclude Config,Logs,Backups | Remove-Item -Recurse -Force
} }
Write-Output "" Write-Output ""

View File

@@ -137,19 +137,19 @@ if (-not $isAdmin) {
} }
# Define script-level variables & paths # Define script-level variables & paths
$script:Version = "2026.06.14" $script:Version = "2026.06.24"
$configPath = Join-Path $PSScriptRoot 'Config' $configPath = Join-Path $PSScriptRoot 'Config'
$logsPath = Join-Path $PSScriptRoot 'Logs'
$schemasPath = Join-Path $PSScriptRoot 'Schemas' $schemasPath = Join-Path $PSScriptRoot 'Schemas'
$scriptsPath = Join-Path $PSScriptRoot 'Scripts' $scriptsPath = Join-Path $PSScriptRoot 'Scripts'
$script:AppDataPath = Join-Path $env:LOCALAPPDATA 'Win11Debloat'
$script:AppsListFilePath = Join-Path $configPath 'Apps.json' $script:AppsListFilePath = Join-Path $configPath 'Apps.json'
$script:DefaultSettingsFilePath = Join-Path $configPath 'DefaultSettings.json' $script:DefaultSettingsFilePath = Join-Path $configPath 'DefaultSettings.json'
$script:FeaturesFilePath = Join-Path $configPath 'Features.json' $script:FeaturesFilePath = Join-Path $configPath 'Features.json'
$script:SavedSettingsFilePath = Join-Path $script:AppDataPath 'LastUsedSettings.json' $script:SavedSettingsFilePath = Join-Path $configPath 'LastUsedSettings.json'
$script:DefaultLogPath = Join-Path (Join-Path $script:AppDataPath 'Logs') 'Win11Debloat.log' $script:DefaultLogPath = Join-Path $logsPath 'Win11Debloat.log'
$script:RegfilesPath = Join-Path $PSScriptRoot 'Regfiles' $script:RegfilesPath = Join-Path $PSScriptRoot 'Regfiles'
$script:RegistryBackupsPath = Join-Path $script:AppDataPath 'Backups' $script:RegistryBackupsPath = Join-Path $PSScriptRoot 'Backups'
$script:AssetsPath = Join-Path $PSScriptRoot 'Assets' $script:AssetsPath = Join-Path $PSScriptRoot 'Assets'
$script:AppSelectionSchema = Join-Path $schemasPath 'AppSelectionWindow.xaml' $script:AppSelectionSchema = Join-Path $schemasPath 'AppSelectionWindow.xaml'
$script:MainWindowSchema = Join-Path $schemasPath 'MainWindow.xaml' $script:MainWindowSchema = Join-Path $schemasPath 'MainWindow.xaml'
@@ -212,9 +212,6 @@ Write-Host ""
Write-Host "" Write-Host ""
# Log script output to 'Win11Debloat.log' at the specified path # Log script output to 'Win11Debloat.log' at the specified path
$logDir = if ($LogPath) { $LogPath } else { Split-Path $script:DefaultLogPath -Parent }
if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }
if ($LogPath -and (Test-Path $LogPath)) { if ($LogPath -and (Test-Path $LogPath)) {
Start-Transcript -Path (Join-Path $LogPath 'Win11Debloat.log') -Append -IncludeInvocationHeader -Force | Out-Null Start-Transcript -Path (Join-Path $LogPath 'Win11Debloat.log') -Append -IncludeInvocationHeader -Force | Out-Null
} }