From 630377d0bd0960a3ac914f389322db4383ca39c8 Mon Sep 17 00:00:00 2001 From: zoicware <118035521+zoicware@users.noreply.github.com> Date: Mon, 12 Jan 2026 16:10:13 -0500 Subject: [PATCH] add new classic apps options --- RemoveWindowsAi.ps1 | 916 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 735 insertions(+), 181 deletions(-) diff --git a/RemoveWindowsAi.ps1 b/RemoveWindowsAi.ps1 index 7da7e7b..fbfc407 100644 --- a/RemoveWindowsAi.ps1 +++ b/RemoveWindowsAi.ps1 @@ -14,11 +14,13 @@ param( [array]$Options, [switch]$AllOptions, [switch]$revertMode, - [switch]$backupMode + [switch]$backupMode, + [ValidateSet('photoviewer', 'mspaint', 'snippingtool', 'notepad', 'photoslegacy')] + [array]$InstallClassicApps ) if ($nonInteractive) { - if (!($AllOptions) -and (!$Options -or $Options.Count -eq 0)) { + if (!($AllOptions) -and (!$Options -or $Options.Count -eq 0) -and !($InstallClassicApps)) { throw 'Non-Interactive mode was supplied without any options... Please use -Options or -AllOptions when using Non-Interactive Mode' exit } @@ -58,6 +60,10 @@ If (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]: $arglist = $arglist + " -Options $Options" } } + + if ($InstallClassicApps -and $InstallClassicApps.Count -ne 0) { + $arglist = $arglist + " -InstallClassicApps $InstallClassicApps" + } } if ($EnableLogging) { @@ -999,183 +1005,184 @@ function Disable-Copilot-Policies { } +#function from: https://github.com/Andrew-J-Larson/OS-Scripts/blob/main/Windows/Wrapper-Functions/Download-AppxPackage-Function.ps1 +function Download-AppxPackage { + param( + # there has to be an alternative, as sometimes the API fails on PackageFamilyName + [string]$PackageFamilyName, + [string]$ProductId, + [string]$outputDir + ) + if (-Not ($PackageFamilyName -Or $ProductId)) { + # can't do anything without at least one + Write-Error 'Missing either PackageFamilyName or ProductId.' + return $null + } + + try { + $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome # needed as sometimes the API will block things when it knows requests are coming from PowerShell + } + catch { + #ignore error + } + + $DownloadedFiles = @() + $errored = $false + $allFilesDownloaded = $true + + $apiUrl = 'https://store.rg-adguard.net/api/GetFiles' + $versionRing = 'Retail' + + $architecture = switch ($env:PROCESSOR_ARCHITECTURE) { + 'x86' { 'x86' } + { @('x64', 'amd64') -contains $_ } { 'x64' } + 'arm' { 'arm' } + 'arm64' { 'arm64' } + default { 'neutral' } # should never get here + } + + if (Test-Path $outputDir -PathType Container) { + New-Item -Path "$outputDir\$PackageFamilyName" -ItemType Directory -Force | Out-Null + $downloadFolder = "$outputDir\$PackageFamilyName" + } + else { + $downloadFolder = Join-Path $env:TEMP $PackageFamilyName + if (!(Test-Path $downloadFolder -PathType Container)) { + New-Item $downloadFolder -ItemType Directory -Force | Out-Null + } + } + + $body = @{ + type = if ($ProductId) { 'ProductId' } else { 'PackageFamilyName' } + url = if ($ProductId) { $ProductId } else { $PackageFamilyName } + ring = $versionRing + lang = 'en-US' + } + + # required due to the api being protected behind Cloudflare now + if (-Not $apiWebSession) { + $global:apiWebSession = $null + $apiHostname = (($apiUrl.split('/'))[0..2]) -Join '/' + Invoke-WebRequest -Uri $apiHostname -UserAgent $UserAgent -SessionVariable $apiWebSession -UseBasicParsing + } + + $raw = $null + try { + $raw = Invoke-RestMethod -Method Post -Uri $apiUrl -ContentType 'application/x-www-form-urlencoded' -Body $body -UserAgent $UserAgent -WebSession $apiWebSession + } + catch { + $errorMsg = 'An error occurred: ' + $_ + Write-Host $errorMsg + $errored = $true + return $false + } + + # hashtable of packages by $name + # > values = hashtables of packages by $version + # > values = arrays of packages as objects (containing: url, filename, name, version, arch, publisherId, type) + [Collections.Generic.Dictionary[string, Collections.Generic.Dictionary[string, array]]] $packageList = @{} + # populate $packageList + $patternUrlAndText = '.*)"\s.*>(?.*\.(app|msi)x.*)<\/a>' + $raw | Select-String $patternUrlAndText -AllMatches | ForEach-Object { $_.Matches } | ForEach-Object { + $url = ($_.Groups['url']).Value + $text = ($_.Groups['text']).Value + $textSplitUnderscore = $text.split('_') + $name = $textSplitUnderscore.split('_')[0] + $version = $textSplitUnderscore.split('_')[1] + $arch = ($textSplitUnderscore.split('_')[2]).ToLower() + $publisherId = ($textSplitUnderscore.split('_')[4]).split('.')[0] + $textSplitPeriod = $text.split('.') + $type = ($textSplitPeriod[$textSplitPeriod.length - 1]).ToLower() + + # create $name hash key hashtable, if it doesn't already exist + if (!($packageList.keys -match ('^' + [Regex]::escape($name) + '$'))) { + $packageList["$name"] = @{} + } + # create $version hash key array, if it doesn't already exist + if (!(($packageList["$name"]).keys -match ('^' + [Regex]::escape($version) + '$'))) { + ($packageList["$name"])["$version"] = @() + } + + # add package to the array in the hashtable + ($packageList["$name"])["$version"] += @{ + url = $url + filename = $text + name = $name + version = $version + arch = $arch + publisherId = $publisherId + type = $type + } + } + + # an array of packages as objects, meant to only contain one of each $name + $latestPackages = @() + # grabs the most updated package for $name and puts it into $latestPackages + $packageList.GetEnumerator() | ForEach-Object { ($_.value).GetEnumerator() | Select-Object -Last 1 } | ForEach-Object { + $packagesByType = $_.value + $msixbundle = ($packagesByType | Where-Object { $_.type -match '^msixbundle$' }) + $appxbundle = ($packagesByType | Where-Object { $_.type -match '^appxbundle$' }) + $msix = ($packagesByType | Where-Object { ($_.type -match '^msix$') -And ($_.arch -match ('^' + [Regex]::Escape($architecture) + '$')) }) + $appx = ($packagesByType | Where-Object { ($_.type -match '^appx$') -And ($_.arch -match ('^' + [Regex]::Escape($architecture) + '$')) }) + if ($msixbundle) { $latestPackages += $msixbundle } + elseif ($appxbundle) { $latestPackages += $appxbundle } + elseif ($msix) { $latestPackages += $msix } + elseif ($appx) { $latestPackages += $appx } + } + + # download packages + $latestPackages | ForEach-Object { + $url = $_.url + $filename = $_.filename + # TODO: may need to include detection in the future of expired package download URLs..... in the case that downloads take over 10 minutes to complete + + $downloadFile = Join-Path $downloadFolder $filename + + # If file already exists, ask to replace it + if (Test-Path $downloadFile) { + Write-Host "`"${filename}`" already exists at `"${downloadFile}`"." + $confirmation = '' + while (!(($confirmation -eq 'Y') -Or ($confirmation -eq 'N'))) { + $confirmation = Read-Host "`nWould you like to re-download and overwrite the file at `"${downloadFile}`" (Y/N)?" + $confirmation = $confirmation.ToUpper() + } + if ($confirmation -eq 'Y') { + Remove-Item -Path $downloadFile -Force + } + else { + $DownloadedFiles += $downloadFile + } + } + + if (!(Test-Path $downloadFile)) { + # Write-Host "Attempting download of `"${filename}`" to `"${downloadFile}`" . . ." + $fileDownloaded = $null + $PreviousProgressPreference = $ProgressPreference + $ProgressPreference = 'SilentlyContinue' # avoids slow download when using Invoke-WebRequest + try { + Invoke-WebRequest -Uri $url -OutFile $downloadFile + $fileDownloaded = $? + } + catch { + $ProgressPreference = $PreviousProgressPreference # return ProgressPreference back to normal + $errorMsg = 'An error occurred: ' + $_ + Write-Host $errorMsg + $errored = $true + break $false + } + $ProgressPreference = $PreviousProgressPreference # return ProgressPreference back to normal + if ($fileDownloaded) { $DownloadedFiles += $downloadFile } + else { $allFilesDownloaded = $false } + } + } + + if ($errored) { Write-Host 'Completed with some errors.' } + if (-Not $allFilesDownloaded) { Write-Host 'Warning: Not all packages could be downloaded.' } + return $DownloadedFiles +} + function Remove-AI-Appx-Packages { - #function from: https://github.com/Andrew-J-Larson/OS-Scripts/blob/main/Windows/Wrapper-Functions/Download-AppxPackage-Function.ps1 - function Download-AppxPackage { - param( - # there has to be an alternative, as sometimes the API fails on PackageFamilyName - [string]$PackageFamilyName, - [string]$ProductId, - [string]$outputDir - ) - if (-Not ($PackageFamilyName -Or $ProductId)) { - # can't do anything without at least one - Write-Error 'Missing either PackageFamilyName or ProductId.' - return $null - } - - try { - $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome # needed as sometimes the API will block things when it knows requests are coming from PowerShell - } - catch { - #ignore error - } - - $DownloadedFiles = @() - $errored = $false - $allFilesDownloaded = $true - - $apiUrl = 'https://store.rg-adguard.net/api/GetFiles' - $versionRing = 'Retail' - - $architecture = switch ($env:PROCESSOR_ARCHITECTURE) { - 'x86' { 'x86' } - { @('x64', 'amd64') -contains $_ } { 'x64' } - 'arm' { 'arm' } - 'arm64' { 'arm64' } - default { 'neutral' } # should never get here - } - - if (Test-Path $outputDir -PathType Container) { - New-Item -Path "$outputDir\$PackageFamilyName" -ItemType Directory -Force | Out-Null - $downloadFolder = "$outputDir\$PackageFamilyName" - } - else { - $downloadFolder = Join-Path $env:TEMP $PackageFamilyName - if (!(Test-Path $downloadFolder -PathType Container)) { - New-Item $downloadFolder -ItemType Directory -Force | Out-Null - } - } - - $body = @{ - type = if ($ProductId) { 'ProductId' } else { 'PackageFamilyName' } - url = if ($ProductId) { $ProductId } else { $PackageFamilyName } - ring = $versionRing - lang = 'en-US' - } - - # required due to the api being protected behind Cloudflare now - if (-Not $apiWebSession) { - $global:apiWebSession = $null - $apiHostname = (($apiUrl.split('/'))[0..2]) -Join '/' - Invoke-WebRequest -Uri $apiHostname -UserAgent $UserAgent -SessionVariable $apiWebSession -UseBasicParsing - } - - $raw = $null - try { - $raw = Invoke-RestMethod -Method Post -Uri $apiUrl -ContentType 'application/x-www-form-urlencoded' -Body $body -UserAgent $UserAgent -WebSession $apiWebSession - } - catch { - $errorMsg = 'An error occurred: ' + $_ - Write-Host $errorMsg - $errored = $true - return $false - } - - # hashtable of packages by $name - # > values = hashtables of packages by $version - # > values = arrays of packages as objects (containing: url, filename, name, version, arch, publisherId, type) - [Collections.Generic.Dictionary[string, Collections.Generic.Dictionary[string, array]]] $packageList = @{} - # populate $packageList - $patternUrlAndText = '.*)"\s.*>(?.*\.(app|msi)x.*)<\/a>' - $raw | Select-String $patternUrlAndText -AllMatches | ForEach-Object { $_.Matches } | ForEach-Object { - $url = ($_.Groups['url']).Value - $text = ($_.Groups['text']).Value - $textSplitUnderscore = $text.split('_') - $name = $textSplitUnderscore.split('_')[0] - $version = $textSplitUnderscore.split('_')[1] - $arch = ($textSplitUnderscore.split('_')[2]).ToLower() - $publisherId = ($textSplitUnderscore.split('_')[4]).split('.')[0] - $textSplitPeriod = $text.split('.') - $type = ($textSplitPeriod[$textSplitPeriod.length - 1]).ToLower() - - # create $name hash key hashtable, if it doesn't already exist - if (!($packageList.keys -match ('^' + [Regex]::escape($name) + '$'))) { - $packageList["$name"] = @{} - } - # create $version hash key array, if it doesn't already exist - if (!(($packageList["$name"]).keys -match ('^' + [Regex]::escape($version) + '$'))) { - ($packageList["$name"])["$version"] = @() - } - - # add package to the array in the hashtable - ($packageList["$name"])["$version"] += @{ - url = $url - filename = $text - name = $name - version = $version - arch = $arch - publisherId = $publisherId - type = $type - } - } - - # an array of packages as objects, meant to only contain one of each $name - $latestPackages = @() - # grabs the most updated package for $name and puts it into $latestPackages - $packageList.GetEnumerator() | ForEach-Object { ($_.value).GetEnumerator() | Select-Object -Last 1 } | ForEach-Object { - $packagesByType = $_.value - $msixbundle = ($packagesByType | Where-Object { $_.type -match '^msixbundle$' }) - $appxbundle = ($packagesByType | Where-Object { $_.type -match '^appxbundle$' }) - $msix = ($packagesByType | Where-Object { ($_.type -match '^msix$') -And ($_.arch -match ('^' + [Regex]::Escape($architecture) + '$')) }) - $appx = ($packagesByType | Where-Object { ($_.type -match '^appx$') -And ($_.arch -match ('^' + [Regex]::Escape($architecture) + '$')) }) - if ($msixbundle) { $latestPackages += $msixbundle } - elseif ($appxbundle) { $latestPackages += $appxbundle } - elseif ($msix) { $latestPackages += $msix } - elseif ($appx) { $latestPackages += $appx } - } - - # download packages - $latestPackages | ForEach-Object { - $url = $_.url - $filename = $_.filename - # TODO: may need to include detection in the future of expired package download URLs..... in the case that downloads take over 10 minutes to complete - - $downloadFile = Join-Path $downloadFolder $filename - - # If file already exists, ask to replace it - if (Test-Path $downloadFile) { - Write-Host "`"${filename}`" already exists at `"${downloadFile}`"." - $confirmation = '' - while (!(($confirmation -eq 'Y') -Or ($confirmation -eq 'N'))) { - $confirmation = Read-Host "`nWould you like to re-download and overwrite the file at `"${downloadFile}`" (Y/N)?" - $confirmation = $confirmation.ToUpper() - } - if ($confirmation -eq 'Y') { - Remove-Item -Path $downloadFile -Force - } - else { - $DownloadedFiles += $downloadFile - } - } - - if (!(Test-Path $downloadFile)) { - # Write-Host "Attempting download of `"${filename}`" to `"${downloadFile}`" . . ." - $fileDownloaded = $null - $PreviousProgressPreference = $ProgressPreference - $ProgressPreference = 'SilentlyContinue' # avoids slow download when using Invoke-WebRequest - try { - Invoke-WebRequest -Uri $url -OutFile $downloadFile - $fileDownloaded = $? - } - catch { - $ProgressPreference = $PreviousProgressPreference # return ProgressPreference back to normal - $errorMsg = 'An error occurred: ' + $_ - Write-Host $errorMsg - $errored = $true - break $false - } - $ProgressPreference = $PreviousProgressPreference # return ProgressPreference back to normal - if ($fileDownloaded) { $DownloadedFiles += $downloadFile } - else { $allFilesDownloaded = $false } - } - } - - if ($errored) { Write-Host 'Completed with some errors.' } - if (-Not $allFilesDownloaded) { Write-Host 'Warning: Not all packages could be downloaded.' } - return $DownloadedFiles - } if ($revert) { @@ -2250,6 +2257,380 @@ Get-ScheduledTask -TaskName "*Office Actions Server*" -ErrorAction SilentlyConti } +function install-photoviewer { + + #restore classic photoviewer + $extensions = @('.Bmp', '.Cr2', '.Dib', '.Gif', '.JFIF', '.Jpe', '.Jpeg', '.Jpg', '.Jxr', '.Png', '.Tif', '.Tiff', '.Wdp') + + foreach ($ext in $extensions) { + if ($ext -in @('.JFIF', '.Jpeg', '.Gif', '.Png', '.Wdp')) { + reg.exe add "HKLM\SOFTWARE\Classes\PhotoViewer.FileAssoc$ext" /v 'EditFlags' /t REG_DWORD /d 65536 /f >$null + reg.exe add "HKLM\SOFTWARE\Classes\PhotoViewer.FileAssoc$ext" /v 'ImageOptionFlags' /t REG_DWORD /d 1 /f >$null + reg.exe add "HKLM\SOFTWARE\Classes\PhotoViewer.FileAssoc$ext" /v 'FriendlyTypeName' /t REG_EXPAND_SZ /d '@%ProgramFiles%\Windows Photo Viewer\PhotoViewer.dll,-3055' /f >$null + reg.exe add "HKLM\SOFTWARE\Classes\PhotoViewer.FileAssoc$ext\DefaultIcon" /ve /t REG_SZ /d '%SystemRoot%\System32\imageres.dll,-72' /f >$null + reg.exe add "HKLM\SOFTWARE\Classes\PhotoViewer.FileAssoc$ext\shell\open" /v 'MuiVerb' /t REG_EXPAND_SZ /d '@%ProgramFiles%\Windows Photo Viewer\photoviewer.dll,-3043' /f >$null + reg.exe add "HKLM\SOFTWARE\Classes\PhotoViewer.FileAssoc$ext\shell\open\command" /ve /t REG_EXPAND_SZ /d "%SystemRoot%\System32\rundll32.exe \`"%ProgramFiles%\Windows Photo Viewer\PhotoViewer.dll\`", ImageView_Fullscreen %1" /f >$null + reg.exe add "HKLM\SOFTWARE\Classes\PhotoViewer.FileAssoc$ext\shell\open\DropTarget" /v 'Clsid' /t REG_SZ /d '{FFE2A43C-56B9-4bf5-9A79-CC6D4285608A}' /f >$null + } + + if ($ext -in @('.Cr2', '.Tif')) { + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations' /v $ext.ToLower() /t REG_SZ /d 'PhotoViewer.FileAssoc.Tiff' /f >$null + } + elseif ($ext -in @('.Dib', '.Bmp')) { + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations' /v $ext.ToLower() /t REG_SZ /d 'PhotoViewer.FileAssoc.Bitmap' /f >$null + } + elseif ($ext -in @('.Jpg', '.Jpe', '.Jpeg')) { + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations' /v $ext.ToLower() /t REG_SZ /d 'PhotoViewer.FileAssoc.Jpeg' /f >$null + } + else { + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations' /v $ext.ToLower() /t REG_SZ /d "PhotoViewer.FileAssoc$ext" /f >$null + } + } +} + +function install-paint { + param( + [string]$path + ) + + get-appxpackage '*Microsoft.Paint*' | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue + + $command = " + copy-item `"$path\paint\mspaint.exe`" -Destination `"$env:systemroot\system32\mspaint.exe`" -Force + copy-item `"$path\paint\mspaint.exe.mui`" -Destination `"$env:systemroot\System32\en-US\mspaint.exe.mui`" -Force + copy-item `"$path\paint\mspaint.exe.mun`" -Destination `"$env:systemroot\SystemResources`" -Force +" + Run-Trusted -command $command + Start-Sleep 1 + + $command = "regedit.exe /s `"$path\paint\paint.reg`"" + Run-Trusted -command $command + + $langID = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Nls\Language' -Name 'InstallLanguage').InstallLanguage + $languageMap = @{ + '0804' = @{PAD = 'zh-CN'; Name = 'Chinese (Simplified)' } + '0412' = @{PAD = 'ko-KR'; Name = 'Korean' } + '0404' = @{PAD = 'zh-TW'; Name = 'Chinese (Traditional)' } + '0422' = @{PAD = 'uk-UA'; Name = 'Ukrainian' } + '041f' = @{PAD = 'tr-TR'; Name = 'Turkish' } + '041e' = @{PAD = 'th-TH'; Name = 'Thai' } + '241a' = @{PAD = 'sr-Latn-RS'; Name = 'Serbian (Latin)' } + '0424' = @{PAD = 'sl-SI'; Name = 'Slovenian' } + '041b' = @{PAD = 'sk-SK'; Name = 'Slovak' } + '0419' = @{PAD = 'ru-RU'; Name = 'Russian' } + '0418' = @{PAD = 'ro-RO'; Name = 'Romanian' } + '0816' = @{PAD = 'pt-PT'; Name = 'Portuguese (Portugal)' } + '0416' = @{PAD = 'pt-BR'; Name = 'Portuguese (Brazil)' } + '0415' = @{PAD = 'pl-PL'; Name = 'Polish' } + '0413' = @{PAD = 'nl-NL'; Name = 'Dutch' } + '0414' = @{PAD = 'nb-NO'; Name = 'Norwegian' } + '0426' = @{PAD = 'lv-LV'; Name = 'Latvian' } + '0427' = @{PAD = 'lt-LT'; Name = 'Lithuanian' } + '0411' = @{PAD = 'ja-JP'; Name = 'Japanese' } + '0410' = @{PAD = 'it-IT'; Name = 'Italian' } + '040e' = @{PAD = 'hu-HU'; Name = 'Hungarian' } + '041a' = @{PAD = 'hr-HR'; Name = 'Croatian' } + '040d' = @{PAD = 'he-IL'; Name = 'Hebrew' } + '040c' = @{PAD = 'fr-FR'; Name = 'French (France)' } + '0c0c' = @{PAD = 'fr-CA'; Name = 'French (Canada)' } + '040b' = @{PAD = 'fi-FI'; Name = 'Finnish' } + '0425' = @{PAD = 'et-EE'; Name = 'Estonian' } + '080a' = @{PAD = 'es-MX'; Name = 'Spanish (Mexico)' } + '040a' = @{PAD = 'es-ES'; Name = 'Spanish (Spain)' } + '0809' = @{PAD = 'en-GB'; Name = 'English (UK)' } + '0408' = @{PAD = 'el-GR'; Name = 'Greek' } + '0407' = @{PAD = 'de-DE'; Name = 'German' } + '0406' = @{PAD = 'da-DK'; Name = 'Danish' } + '0405' = @{PAD = 'cs-CZ'; Name = 'Czech' } + '0402' = @{PAD = 'bg-BG'; Name = 'Bulgarian' } + '0401' = @{PAD = 'ar-SA'; Name = 'Arabic' } + '041d' = @{PAD = 'sv-SE'; Name = 'Swedish' } + } + + if ($languageMap.ContainsKey($langID)) { + $lang = $languageMap[$langID] + $pad = $lang.PAD + + # Copy language specific MUI file + $command = "Copy-Item -Path `"$path\paint\paint_lang_files\$pad\mspaint.exe.mui`" -Destination `"$env:SYSTEMROOT\System32\$pad\mspaint.exe.mui`" -Force" + Run-Trusted -command $command + + Write-Status -msg "Copied $pad language file" + } + + + #create start shortcut + $WshShell = New-Object -comObject WScript.Shell + $Shortcut = $WshShell.CreateShortcut('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Paint.lnk') + $Shortcut.TargetPath = 'C:\Windows\System32\mspaint.exe' + $Shortcut.Save() + +} + +function install-snipping { + param( + [string]$path + ) + # uninstall uwp + Get-AppxPackage '*ScreenSketch*' -ErrorAction SilentlyContinue | Remove-AppxPackage -ErrorAction SilentlyContinue + + $command = " + copy-item `"$path\snipping\SnippingTool.exe`" -Destination `"$env:systemroot\system32\SnippingTool.exe`" -Force + copy-item `"$path\snipping\SnippingTool.exe.mui`" -Destination `"$env:systemroot\System32\en-US\SnippingTool.exe.mui`" -Force +" + Run-Trusted -command $command + Start-Sleep 1 + + $langID = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Nls\Language' -Name 'InstallLanguage').InstallLanguage + $languageMap = @{ + '0804' = @{PAD = 'zh-CN'; Name = 'Chinese (Simplified)' } + '0412' = @{PAD = 'ko-KR'; Name = 'Korean' } + '0404' = @{PAD = 'zh-TW'; Name = 'Chinese (Traditional)' } + '0422' = @{PAD = 'uk-UA'; Name = 'Ukrainian' } + '041f' = @{PAD = 'tr-TR'; Name = 'Turkish' } + '041e' = @{PAD = 'th-TH'; Name = 'Thai' } + '241a' = @{PAD = 'sr-Latn-RS'; Name = 'Serbian (Latin)' } + '0424' = @{PAD = 'sl-SI'; Name = 'Slovenian' } + '041b' = @{PAD = 'sk-SK'; Name = 'Slovak' } + '0419' = @{PAD = 'ru-RU'; Name = 'Russian' } + '0418' = @{PAD = 'ro-RO'; Name = 'Romanian' } + '0816' = @{PAD = 'pt-PT'; Name = 'Portuguese (Portugal)' } + '0416' = @{PAD = 'pt-BR'; Name = 'Portuguese (Brazil)' } + '0415' = @{PAD = 'pl-PL'; Name = 'Polish' } + '0413' = @{PAD = 'nl-NL'; Name = 'Dutch' } + '0414' = @{PAD = 'nb-NO'; Name = 'Norwegian' } + '0426' = @{PAD = 'lv-LV'; Name = 'Latvian' } + '0427' = @{PAD = 'lt-LT'; Name = 'Lithuanian' } + '0411' = @{PAD = 'ja-JP'; Name = 'Japanese' } + '0410' = @{PAD = 'it-IT'; Name = 'Italian' } + '040e' = @{PAD = 'hu-HU'; Name = 'Hungarian' } + '041a' = @{PAD = 'hr-HR'; Name = 'Croatian' } + '040d' = @{PAD = 'he-IL'; Name = 'Hebrew' } + '040c' = @{PAD = 'fr-FR'; Name = 'French (France)' } + '0c0c' = @{PAD = 'fr-CA'; Name = 'French (Canada)' } + '040b' = @{PAD = 'fi-FI'; Name = 'Finnish' } + '0425' = @{PAD = 'et-EE'; Name = 'Estonian' } + '080a' = @{PAD = 'es-MX'; Name = 'Spanish (Mexico)' } + '040a' = @{PAD = 'es-ES'; Name = 'Spanish (Spain)' } + '0809' = @{PAD = 'en-GB'; Name = 'English (UK)' } + '0408' = @{PAD = 'el-GR'; Name = 'Greek' } + '0407' = @{PAD = 'de-DE'; Name = 'German' } + '0406' = @{PAD = 'da-DK'; Name = 'Danish' } + '0405' = @{PAD = 'cs-CZ'; Name = 'Czech' } + '0402' = @{PAD = 'bg-BG'; Name = 'Bulgarian' } + '0401' = @{PAD = 'ar-SA'; Name = 'Arabic' } + '041d' = @{PAD = 'sv-SE'; Name = 'Swedish' } + } + + if ($languageMap.ContainsKey($langID)) { + $lang = $languageMap[$langID] + $pad = $lang.PAD + + # Copy language specific MUI file + $command = "Copy-Item -Path `"$path\snipping\snipping_lang_files\$pad\SnippingTool.exe.mui`" -Destination `"$env:SYSTEMROOT\System32\$pad\SnippingTool.exe.mui`" -Force" + Run-Trusted -command $command + + Write-Status -msg "Copied $pad language file" + + } + + + $WshShell = New-Object -comObject WScript.Shell + $Shortcut = $WshShell.CreateShortcut('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\SnippingTool.lnk') + $Shortcut.TargetPath = ('C:\Windows\System32\SnippingTool.exe') + $Shortcut.Save() + +} + + +function install-notepad { + + #uninstall new notepad + taskkill.exe /im notepad.exe /f *>$null + taskkill.exe /im dllhost.exe /f *>$null + get-appxpackage '*notepad*' | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue + #enable win10 notepad + Add-WindowsCapability -Online -Name Microsoft.Windows.Notepad.System~~~~0.0.1.0 -LimitAccess | Out-Null + # fix registry + Remove-Item -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\App Paths\notepad.exe' -Force -ErrorAction SilentlyContinue + Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Classes\Applications\notepad.exe' -Name NoOpenWith -Force -ErrorAction SilentlyContinue + reg.exe add 'HKLM\SOFTWARE\Classes\*\OpenWithList\notepad.exe' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.htm\OpenWithList' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.htm\OpenWithList\notepad.exe' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.inf' /ve /t REG_SZ /d 'inffile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.ini' /ve /t REG_SZ /d 'inifile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.log' /ve /t REG_SZ /d 'txtfile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.ps1' /ve /t REG_SZ /d 'Microsoft.PowerShellScript.1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.psd1' /ve /t REG_SZ /d 'Microsoft.PowerShellData.1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.psm1' /ve /t REG_SZ /d 'Microsoft.PowerShellModule.1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.scp' /ve /t REG_SZ /d 'txtfile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.txt' /ve /t REG_SZ /d 'txtfile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.txt\ShellNew' /v 'ItemName' /t REG_EXPAND_SZ /d '@%SystemRoot%\system32\notepad.exe,-470' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.txt\ShellNew' /v 'NullFile' /t REG_SZ /d ' ' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\.wtx' /ve /t REG_SZ /d 'txtfile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Applications\notepad.exe' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Applications\notepad.exe\shell' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Applications\notepad.exe\shell\edit' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Applications\notepad.exe\shell\edit\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Applications\notepad.exe\shell\open' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Applications\notepad.exe\shell\open\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inffile' /ve /t REG_SZ /d 'Setup Information' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inffile' /v 'FriendlyTypeName' /t REG_EXPAND_SZ /d '@%SystemRoot%\System32\setupapi.dll,-2000' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inffile\DefaultIcon' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\System32\imageres.dll,-69' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inffile\shell' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inffile\shell\open' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inffile\shell\open\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inffile\shell\print' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inffile\shell\print\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE /p %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inifile' /ve /t REG_SZ /d 'Configuration Settings' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inifile' /v 'EditFlags' /t REG_DWORD /d 0x00200000 /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inifile' /v 'FriendlyTypeName' /t REG_SZ /d '@shell32.dll,-10151' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inifile\DefaultIcon' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\imageres.dll,-69' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inifile\shell' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inifile\shell\open' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inifile\shell\open\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inifile\shell\print' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\inifile\shell\print\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE /p %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellData.1' /v 'EditFlags' /t REG_DWORD /d 0x00020000 /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellData.1' /v 'FriendlyTypeName' /t REG_EXPAND_SZ /d "@\`"%systemroot%\system32\windowspowershell\v1.0\powershell.exe\`",-104" /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellData.1\Shell' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellData.1\Shell\Open' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellData.1\Shell\Open\Command' /ve /t REG_SZ /d "\`"C:\Windows\System32\notepad.exe\`" \`"%1\`"" /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellModule.1' /v 'EditFlags' /t REG_DWORD /d 0x00020000 /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellModule.1' /v 'FriendlyTypeName' /t REG_EXPAND_SZ /d "@\`"%systemroot%\system32\windowspowershell\v1.0\powershell.exe\`",-106" /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellModule.1\Shell' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellModule.1\Shell\Open' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellModule.1\Shell\Open\Command' /ve /t REG_SZ /d "\`"C:\Windows\System32\notepad.exe\`" \`"%1\`"" /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellScript.1' /v 'EditFlags' /t REG_DWORD /d 0x00020000 /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellScript.1' /v 'FriendlyTypeName' /t REG_EXPAND_SZ /d "@\`"%systemroot%\system32\windowspowershell\v1.0\powershell.exe\`",-103" /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellScript.1\DefaultIcon' /ve /t REG_SZ /d "\`"C:\Windows\System32\WindowsPowerShell\v1.0\powershell_ise.exe\`",1" /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellScript.1\Shell' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellScript.1\Shell\Open' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\Microsoft.PowerShellScript.1\Shell\Open\Command' /ve /t REG_SZ /d "\`"C:\Windows\System32\notepad.exe\`" \`"%1\`"" /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\SystemFileAssociations\text\OpenWithList' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\SystemFileAssociations\text\OpenWithList\Notepad.exe' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\SystemFileAssociations\text\shell' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\SystemFileAssociations\text\shell\edit' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\SystemFileAssociations\text\shell\edit\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\SystemFileAssociations\text\shell\open' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\SystemFileAssociations\text\shell\open\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile' /ve /t REG_SZ /d 'Text Document' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile' /v 'EditFlags' /t REG_DWORD /d 0x00210000 /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile' /v 'FriendlyTypeName' /t REG_EXPAND_SZ /d '@%SystemRoot%\system32\notepad.exe,-469' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile\DefaultIcon' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\imageres.dll,-102' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile\shell' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile\shell\open' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile\shell\open\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile\shell\print' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile\shell\print\command' /ve /t REG_EXPAND_SZ /d '%SystemRoot%\system32\NOTEPAD.EXE /p %1' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile\shell\printto' /f >$null + reg.exe add 'HKLM\SOFTWARE\Classes\txtfile\shell\printto\command' /ve /t REG_EXPAND_SZ /d "%SystemRoot%\system32\notepad.exe /pt \`"%1\`" \`"%2\`" \`"%3\`" \`"%4\`"" /f >$null + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\Notepad' /f >$null + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\Notepad\Capabilities' /v 'ApplicationDescription' /t REG_EXPAND_SZ /d '@%SystemRoot%\system32\NOTEPAD.EXE,-9' /f >$null + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\Notepad\Capabilities' /v 'ApplicationName' /t REG_EXPAND_SZ /d '@%SystemRoot%\system32\NOTEPAD.EXE,-9' /f >$null + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\Notepad\Capabilities\FileAssociations' /v '.ini' /t REG_SZ /d 'inifile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\Notepad\Capabilities\FileAssociations' /v '.log' /t REG_SZ /d 'logfile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\Notepad\Capabilities\FileAssociations' /v '.scp' /t REG_SZ /d 'scpfile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\Notepad\Capabilities\FileAssociations' /v '.txt' /t REG_SZ /d 'txtfile' /f >$null + reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\Notepad\Capabilities\FileAssociations' /v '.wtx' /t REG_SZ /d 'wtxfile' /f >$null + reg.exe add 'HKLM\SOFTWARE\RegisteredApplications' /v 'Notepad' /t REG_SZ /d 'Software\Microsoft\Windows\Notepad\Capabilities' /f >$null + reg.exe add 'HKCU\Software\Microsoft\Notepad' /v 'ShowStoreBanner' /t REG_DWORD /d 0x00000000 /f >$null + + #create start shortcut + $WshShell = New-Object -comObject WScript.Shell + $Shortcut = $WshShell.CreateShortcut('C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Notepad.lnk') + $Shortcut.TargetPath = 'C:\Windows\System32\Notepad.exe' + $Shortcut.Save() + +} + +function install-photoslegacy { + + $appx = Get-AppxPackage -AllUsers | Where-Object { $_.PackageFullName -like '*PhotosLegacy*' } + + if (!$appx) { + Remove-Item "$env:TEMP\Microsoft.PhotosLegacy_8wekyb3d8bbwe*" -Force -Recurse -ErrorAction SilentlyContinue + $downloadedfiles = Download-AppxPackage -PackageFamilyName 'Microsoft.PhotosLegacy_8wekyb3d8bbwe' -outputDir "$env:TEMP" + $package = $downloadedfiles | Where-Object { $_ -match '\.appxbundle$' } | Select-Object -First 1 + $dependencies = $downloadedfiles | Where-Object { $_ -match '\.appx$' } + if ($package) { + try { + Add-AppPackage $package -DependencyPath $dependencies -ForceApplicationShutdown + } + catch { + Write-status -msg "Can't install PhotosLegacy via appxbundle... make sure you have the appx service enabled" -errorOutput + } + + } + else { + Write-status -msg "Can't find PhotosLegacy Installer" -errorOutput + } + } +} + +function install-classicapps { + param( + [ValidateSet('photoviewer', 'mspaint', 'snippingtool', 'notepad', 'photoslegacy')] + [array]$app + ) + + #check if files are downloaded locally + if (Test-Path "$PSScriptroot\ClassicApps") { + Write-Status -msg 'Classic Apps Files Found Locally' + $classicApps = "$PSScriptroot\ClassicApps" + } + else { + #check if they are already downloaded if not download them + if (!(Test-Path "$env:TEMP\ClassicApps")) { + $ProgressPreference = 'SilentlyContinue' + Write-Status -msg 'Downloading Classic Apps Files from Github...' + $url = 'https://github.com/zoicware/RemoveWindowsAI/archive/refs/heads/main.zip' + try { + Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\main.zip" -ErrorAction Stop + } + catch { + Write-Status -msg 'Unable to Download Github Repo' -errorOutput + return + } + Expand-Archive -Path "$env:TEMP\main.zip" -DestinationPath $env:TEMP -Force + $sourceDir = "$env:TEMP\RemoveWindowsAI-main\ClassicApps" + $destDir = "$env:TEMP\ClassicApps" + Copy-Item -Path $sourceDir -Destination $destDir -Recurse -Force + Remove-Item "$env:TEMP\RemoveWindowsAI-main" -Recurse -Force -ErrorAction SilentlyContinue + Remove-Item "$env:TEMP\main.zip" -Recurse -Force -ErrorAction SilentlyContinue + } + + $classicApps = "$env:TEMP\ClassicApps" + } + + + switch ($app) { + 'photoviewer' { + Write-Status -msg 'Installing Classic Photo Viewer...' + install-photoviewer + } + 'mspaint' { + Write-Status -msg 'Installing Classic Paint...' + install-paint -path $classicApps + } + 'snippingtool' { + Write-Status -msg 'Installing Classic Snipping Tool...' + install-snipping -path $classicApps + } + 'notepad' { + Write-Status -msg 'Installing Classic Notepad...' + install-notepad + } + 'photoslegacy' { + Write-Status -msg 'Installing Photos Legacy...' + install-photoslegacy + } + Default { + Write-Status -msg 'Unknown Classic App Option' -errorOutput + } + } +} + if ($nonInteractive) { if ($AllOptions) { @@ -2279,6 +2660,12 @@ if ($nonInteractive) { 'RemoveRecallTasks' { Remove-Recall-Tasks } } } + + if ($InstallClassicApps) { + foreach ($app in $InstallClassicApps) { + install-classicapps -app $app + } + } } else { @@ -2320,9 +2707,8 @@ else { $contentRow.Height = [System.Windows.GridLength]::new(1, [System.Windows.GridUnitType]::Star) $mainGrid.RowDefinitions.Add($contentRow) | Out-Null - # Add this BEFORE your bottom row definition: $toggleRow = New-Object System.Windows.Controls.RowDefinition - $toggleRow.Height = [System.Windows.GridLength]::new(130) # Fixed height for toggle + $toggleRow.Height = [System.Windows.GridLength]::new(130) $mainGrid.RowDefinitions.Add($toggleRow) | Out-Null $bottomRow = New-Object System.Windows.Controls.RowDefinition @@ -2347,6 +2733,78 @@ else { [System.Windows.Controls.Grid]::SetRow($scrollViewer, 1) $mainGrid.Children.Add($scrollViewer) | Out-Null + $scrollViewerStyle = @' + + + + + + + + + + + + + + + + + +'@ + + $reader = New-Object System.Xml.XmlNodeReader([xml]$scrollViewerStyle) + $scrollViewer.Style = [Windows.Markup.XamlReader]::Load($reader) + + $stackPanel = New-Object System.Windows.Controls.StackPanel $stackPanel.Orientation = 'Vertical' $scrollViewer.Content = $stackPanel @@ -2549,7 +3007,98 @@ else { return $toggleButton } - + $divider = New-Object System.Windows.Controls.Separator + $divider.Margin = '0,10,0,10' + $divider.Background = [System.Windows.Media.Brushes]::DarkGray + $stackPanel.Children.Add($divider) | Out-Null + + $classicAppsHeader = New-Object System.Windows.Controls.TextBlock + $classicAppsHeader.Text = 'Install Classic Windows Apps' + $classicAppsHeader.FontSize = 16 + $classicAppsHeader.FontWeight = 'Bold' + $classicAppsHeader.Foreground = [System.Windows.Media.Brushes]::Cyan + $classicAppsHeader.Margin = '0,10,0,10' + $stackPanel.Children.Add($classicAppsHeader) | Out-Null + + $classicAppsFunctions = @( + 'Install-Classic-Photoviewer' + 'Install-Classic-Mspaint' + 'Install-Classic-SnippingTool' + 'Install-Classic-Notepad' + 'Install-Photos-Legacy' + ) + + $classicAppsDescriptions = @{ + 'Install-Classic-Photoviewer' = 'Installs the classic Windows Photo Viewer from Windows 7/8, allowing you to view images with the traditional viewer instead of the modern Photos app.' + 'Install-Classic-Mspaint' = 'Installs the classic Microsoft Paint application from older Windows versions.' + 'Install-Classic-SnippingTool' = 'Installs the classic Snipping Tool, replacing the modern Snip & Sketch app.' + 'Install-Classic-Notepad' = 'Installs the classic Notepad from Windows 10, replacing the modern uwp version.' + 'Install-Photos-Legacy' = 'Installs the legacy Windows Photos app from the Microsoft Store.' + } + + $functionDescriptions += $classicAppsDescriptions + foreach ($func in $classicAppsFunctions) { + $optionContainer = New-Object System.Windows.Controls.DockPanel + $optionContainer.Margin = '0,5,0,5' + $optionContainer.LastChildFill = $false + + $checkbox = New-Object System.Windows.Controls.CheckBox + $checkbox.Content = $func.Replace('-', ' ') + $checkbox.FontSize = 14 + $checkbox.Foreground = [System.Windows.Media.Brushes]::White + $checkbox.Margin = '0,0,10,0' + $checkbox.VerticalAlignment = 'Center' + $checkbox.IsChecked = $false + [System.Windows.Controls.DockPanel]::SetDock($checkbox, 'Left') + $checkboxes[$func] = $checkbox + + $infoButton = New-Object System.Windows.Controls.Button + $infoButton.Content = '?' + $infoButton.Width = 25 + $infoButton.Height = 25 + $infoButton.FontSize = 12 + $infoButton.FontWeight = 'Bold' + $infoButton.Background = [System.Windows.Media.Brushes]::DarkBlue + $infoButton.Foreground = [System.Windows.Media.Brushes]::White + $infoButton.BorderBrush = [System.Windows.Media.Brushes]::Transparent + $infoButton.BorderThickness = 0 + $infoButton.VerticalAlignment = 'Center' + $infoButton.Cursor = 'Hand' + [System.Windows.Controls.DockPanel]::SetDock($infoButton, 'Right') + + $infoTemplate = @' + + + + + +'@ + $infoButton.Template = [System.Windows.Markup.XamlReader]::Parse($infoTemplate) + + $infoButton.Add_Click({ + param($sender, $e) + + # Find the correct function name + foreach ($f in $classicAppsFunctions) { + if ($checkboxes[$f].Parent -eq $sender.Parent) { + $funcName = $f + break + } + } + + $description = $functionDescriptions[$funcName] + [System.Windows.MessageBox]::Show($description, $funcName, [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information) + }) + + $optionContainer.Children.Add($checkbox) | Out-Null + $optionContainer.Children.Add($infoButton) | Out-Null + $stackPanel.Children.Add($optionContainer) | Out-Null + } + + $allFunctions = $functions + $classicAppsFunctions $toggleGrid = New-Object System.Windows.Controls.Grid [System.Windows.Controls.Grid]::SetRow($toggleGrid, 2) @@ -2902,7 +3451,7 @@ else { $progressWindow.Show() $selectedFunctions = @() - foreach ($func in $functions) { + foreach ($func in $allFunctions) { if ($checkboxes[$func].IsChecked) { $selectedFunctions += $func } @@ -2931,6 +3480,11 @@ else { 'Hide-AI-Components' { Hide-AI-Components } 'Disable-Notepad-Rewrite' { Disable-Notepad-Rewrite } 'Remove-Recall-Tasks' { Remove-Recall-Tasks } + 'Install-Classic-Photoviewer' { install-classicapps -app 'photoviewer' } + 'Install-Classic-Mspaint' { install-classicapps -app 'mspaint' } + 'Install-Classic-SnippingTool' { install-classicapps -app 'snippingtool' } + 'Install-Classic-Notepad' { install-classicapps -app 'notepad' } + 'Install-Photos-Legacy' { install-classicapps -app 'photoslegacy' } } Start-Sleep -Milliseconds 500