add restore and backup fix #14
This commit is contained in:
@@ -13,7 +13,8 @@ param(
|
|||||||
'RemoveRecallTasks')]
|
'RemoveRecallTasks')]
|
||||||
[array]$Options,
|
[array]$Options,
|
||||||
[switch]$AllOptions,
|
[switch]$AllOptions,
|
||||||
[switch]$revertMode
|
[switch]$revertMode,
|
||||||
|
[switch]$backupMode
|
||||||
)
|
)
|
||||||
|
|
||||||
if ($nonInteractive) {
|
if ($nonInteractive) {
|
||||||
@@ -39,6 +40,10 @@ If (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]:
|
|||||||
$arglist = $arglist + ' -revertMode'
|
$arglist = $arglist + ' -revertMode'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($backupMode) {
|
||||||
|
$arglist = $arglist + '-backupMode'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($Options -and $Options.count -ne 0) {
|
if ($Options -and $Options.count -ne 0) {
|
||||||
#if options and alloptions is supplied just do all options
|
#if options and alloptions is supplied just do all options
|
||||||
@@ -106,6 +111,215 @@ function Run-Trusted([String]$command, $psversion) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# function from: https://github.com/the-loan-wolf/Appx-Backup/blob/master/Appx-Backup.ps1
|
||||||
|
function Backup-Appx {
|
||||||
|
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory = $True)]
|
||||||
|
[string] $WSAppPath,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $True)]
|
||||||
|
[string] $WSAppOutputPath
|
||||||
|
)
|
||||||
|
|
||||||
|
function Get-FileFromWeb {
|
||||||
|
param (
|
||||||
|
# Parameter help description
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string]$URL,
|
||||||
|
|
||||||
|
# Parameter help description
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string]$File
|
||||||
|
)
|
||||||
|
Begin {
|
||||||
|
|
||||||
|
}
|
||||||
|
Process {
|
||||||
|
try {
|
||||||
|
$storeEAP = $ErrorActionPreference
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# invoke request
|
||||||
|
$request = [System.Net.HttpWebRequest]::Create($URL)
|
||||||
|
$response = $request.GetResponse()
|
||||||
|
|
||||||
|
if ($response.StatusCode -eq 401 -or $response.StatusCode -eq 403 -or $response.StatusCode -eq 404) {
|
||||||
|
throw "Remote file either doesn't exist, is unauthorized, or is forbidden for '$URL'."
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($File -match '^\.\\') {
|
||||||
|
$File = Join-Path (Get-Location -PSProvider 'FileSystem') ($File -Split '^\.')[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($File -and !(Split-Path $File)) {
|
||||||
|
$File = Join-Path (Get-Location -PSProvider 'FileSystem') $File
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($File) {
|
||||||
|
$fileDirectory = $([System.IO.Path]::GetDirectoryName($File))
|
||||||
|
if (!(Test-Path($fileDirectory))) {
|
||||||
|
[System.IO.Directory]::CreateDirectory($fileDirectory) | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[long]$fullSize = $response.ContentLength
|
||||||
|
$fullSizeMB = $fullSize / 1024 / 1024
|
||||||
|
|
||||||
|
# define buffer
|
||||||
|
[byte[]]$buffer = new-object byte[] 1048576
|
||||||
|
[long]$total = [long]$count = 0
|
||||||
|
|
||||||
|
# create reader / writer
|
||||||
|
$reader = $response.GetResponseStream()
|
||||||
|
$writer = new-object System.IO.FileStream $File, 'Create'
|
||||||
|
|
||||||
|
# start download
|
||||||
|
$finalBarCount = 0 #show final bar only one time
|
||||||
|
do {
|
||||||
|
|
||||||
|
$count = $reader.Read($buffer, 0, $buffer.Length)
|
||||||
|
|
||||||
|
$writer.Write($buffer, 0, $count)
|
||||||
|
|
||||||
|
$total += $count
|
||||||
|
$totalMB = $total / 1024 / 1024
|
||||||
|
|
||||||
|
if ($fullSize -gt 0) {
|
||||||
|
#Show-Progress -TotalValue $fullSizeMB -CurrentValue $totalMB -ProgressText "Downloading $($File.Name)" -ValueSuffix 'MB'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($total -eq $fullSize -and $count -eq 0 -and $finalBarCount -eq 0) {
|
||||||
|
#Show-Progress -TotalValue $fullSizeMB -CurrentValue $totalMB -ProgressText "Downloading $($File.Name)" -ValueSuffix 'MB' -Complete
|
||||||
|
$finalBarCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
} while ($count -gt 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
catch {
|
||||||
|
|
||||||
|
$ExeptionMsg = $_.Exception.Message
|
||||||
|
Write-Host "Download breaks with error : $ExeptionMsg"
|
||||||
|
}
|
||||||
|
|
||||||
|
finally {
|
||||||
|
# cleanup
|
||||||
|
if ($reader) { $reader.Close() }
|
||||||
|
if ($writer) { $writer.Flush(); $writer.Close() }
|
||||||
|
|
||||||
|
$ErrorActionPreference = $storeEAP
|
||||||
|
[GC]::Collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Run-Process {
|
||||||
|
Param ($p, $a)
|
||||||
|
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$pinfo.FileName = $p
|
||||||
|
$pinfo.Arguments = $a
|
||||||
|
$pinfo.RedirectStandardError = $true
|
||||||
|
$pinfo.RedirectStandardOutput = $true
|
||||||
|
$pinfo.UseShellExecute = $false
|
||||||
|
$p = New-Object System.Diagnostics.Process
|
||||||
|
$p.StartInfo = $pinfo
|
||||||
|
$p.Start() | Out-Null
|
||||||
|
$output = $p.StandardOutput.ReadToEnd()
|
||||||
|
$output += $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
return $output
|
||||||
|
}
|
||||||
|
|
||||||
|
#tools path
|
||||||
|
$WSTools = "$env:TEMP\AppxBackupTools-master\tool\x64"
|
||||||
|
if (!(Test-Path $WSTools)) {
|
||||||
|
Get-FileFromWeb -URL 'https://github.com/zoicware/AppxBackupTools/archive/refs/heads/master.zip' -File "$env:TEMP\BackupTools.zip"
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
Expand-Archive "$env:TEMP\BackupTools.zip" -DestinationPath $env:TEMP
|
||||||
|
}
|
||||||
|
|
||||||
|
$WSAppXmlFile = 'AppxManifest.xml'
|
||||||
|
|
||||||
|
# read manifest
|
||||||
|
$FileExists = Test-Path "$WSAppPath\$WSAppXmlFile"
|
||||||
|
if ($FileExists -eq $False) {
|
||||||
|
#temp: debug
|
||||||
|
Write-Status -msg 'ERROR: Windows Store manifest not found.'
|
||||||
|
}
|
||||||
|
[xml]$manifest = Get-Content "$WSAppPath\$WSAppXmlFile"
|
||||||
|
$WSAppName = $manifest.Package.Identity.Name
|
||||||
|
$WSAppPublisher = $manifest.Package.Identity.Publisher
|
||||||
|
|
||||||
|
# prepare
|
||||||
|
$WSAppFileName = Get-Item $WSAppPath | Select-Object basename
|
||||||
|
$WSAppFileName = $WSAppFileName.BaseName
|
||||||
|
|
||||||
|
if (Test-Path "$WSAppOutputPath\$WSAppFileName.appx") {
|
||||||
|
Remove-Item "$WSAppOutputPath\$WSAppFileName.appx"
|
||||||
|
}
|
||||||
|
$proc = "$WSTools\MakeAppx.exe"
|
||||||
|
$args = "pack /d ""$WSAppPath"" /p ""$WSAppOutputPath\$WSAppFileName.appx"" /l"
|
||||||
|
$output = Run-Process $proc $args
|
||||||
|
if ($output -inotlike '*succeeded*') {
|
||||||
|
Write-host ' ERROR: Appx creation failed!'
|
||||||
|
Write-host " proc = $proc"
|
||||||
|
Write-host " args = $args"
|
||||||
|
Write-host (' ' + $output)
|
||||||
|
# Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (Test-Path "$WSAppOutputPath\$WSAppFileName.pvk") {
|
||||||
|
Remove-Item "$WSAppOutputPath\$WSAppFileName.pvk"
|
||||||
|
}
|
||||||
|
if (Test-Path "$WSAppOutputPath\$WSAppFileName.cer") {
|
||||||
|
Remove-Item "$WSAppOutputPath\$WSAppFileName.cer"
|
||||||
|
}
|
||||||
|
$proc = "$WSTools\MakeCert.exe"
|
||||||
|
$args = "-n ""$WSAppPublisher"" -r -a sha256 -len 2048 -cy end -h 0 -eku 1.3.6.1.5.5.7.3.3 -b 01/01/2000 -pe -sv ""$WSAppOutputPath\$WSAppFileName.pvk"" ""$WSAppOutputPath\$WSAppFileName.cer"""
|
||||||
|
$output = Run-Process $proc $args
|
||||||
|
if ($output -inotlike '*succeeded*') {
|
||||||
|
Write-host 'ERROR: Certificate creation failed!'
|
||||||
|
Write-host "proc = $proc"
|
||||||
|
Write-host "args = $args"
|
||||||
|
Write-host (' ' + $output)
|
||||||
|
# Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path "$WSAppOutputPath\$WSAppFileName.pfx") {
|
||||||
|
Remove-Item "$WSAppOutputPath\$WSAppFileName.pfx"
|
||||||
|
}
|
||||||
|
$proc = "$WSTools\Pvk2Pfx.exe"
|
||||||
|
$args = "-pvk ""$WSAppOutputPath\$WSAppFileName.pvk"" -spc ""$WSAppOutputPath\$WSAppFileName.cer"" -pfx ""$WSAppOutputPath\$WSAppFileName.pfx"""
|
||||||
|
$output = Run-Process $proc $args
|
||||||
|
if ($output.Length -gt 0) {
|
||||||
|
Write-host ' ERROR: Certificate conversion to pfx failed!'
|
||||||
|
Write-host " proc = $proc"
|
||||||
|
Write-host " args = $args"
|
||||||
|
Write-host (' ' + $output)
|
||||||
|
# Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
$proc = "$WSTools\SignTool.exe"
|
||||||
|
$args = "sign -fd SHA256 -a -f ""$WSAppOutputPath\$WSAppFileName.pfx"" ""$WSAppOutputPath\$WSAppFileName.appx"""
|
||||||
|
$output = Run-Process $proc $args
|
||||||
|
if ($output -inotlike '*successfully signed*') {
|
||||||
|
Write-host 'ERROR: Package signing failed!'
|
||||||
|
Write-host $output.Length
|
||||||
|
Write-host "proc = $proc"
|
||||||
|
Write-host "args = $args"
|
||||||
|
Write-host (' ' + $output)
|
||||||
|
# Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
Remove-Item "$WSAppOutputPath\$WSAppFileName.pvk"
|
||||||
|
Remove-Item "$WSAppOutputPath\$WSAppFileName.pfx"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function Write-Status {
|
function Write-Status {
|
||||||
param(
|
param(
|
||||||
[string]$msg,
|
[string]$msg,
|
||||||
@@ -158,6 +372,13 @@ else {
|
|||||||
$Global:revert = 0
|
$Global:revert = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($backupMode) {
|
||||||
|
$Global:backup = 1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$Global:backup = 0
|
||||||
|
}
|
||||||
|
|
||||||
#=====================================================================================
|
#=====================================================================================
|
||||||
|
|
||||||
function Add-LogInfo {
|
function Add-LogInfo {
|
||||||
@@ -213,6 +434,7 @@ function Disable-Registry-Keys {
|
|||||||
#disable additional keys
|
#disable additional keys
|
||||||
Reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings' /v 'AutoOpenCopilotLargeScreens' /t REG_DWORD /d @('0', '1')[$revert] /f *>$null
|
Reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings' /v 'AutoOpenCopilotLargeScreens' /t REG_DWORD /d @('0', '1')[$revert] /f *>$null
|
||||||
Reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\generativeAI' /v 'Value' /t REG_SZ /d @('Deny', 'Allow')[$revert] /f *>$null
|
Reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\generativeAI' /v 'Value' /t REG_SZ /d @('Deny', 'Allow')[$revert] /f *>$null
|
||||||
|
Reg.exe add 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\systemAIModels' /v 'Value' /t REG_SZ /d @('Deny', 'Allow')[$revert] /f *>$null
|
||||||
Reg.exe add 'HKLM\SOFTWARE\Policies\Microsoft\Windows\AppPrivacy' /v 'LetAppsAccessGenerativeAI' /t REG_DWORD /d @('2', '1')[$revert] /f *>$null
|
Reg.exe add 'HKLM\SOFTWARE\Policies\Microsoft\Windows\AppPrivacy' /v 'LetAppsAccessGenerativeAI' /t REG_DWORD /d @('2', '1')[$revert] /f *>$null
|
||||||
Reg.exe add 'HKLM\SOFTWARE\Policies\Microsoft\Windows\AppPrivacy' /v 'LetAppsAccessSystemAIModels' /t REG_DWORD /d @('2', '1')[$revert] /f *>$null
|
Reg.exe add 'HKLM\SOFTWARE\Policies\Microsoft\Windows\AppPrivacy' /v 'LetAppsAccessSystemAIModels' /t REG_DWORD /d @('2', '1')[$revert] /f *>$null
|
||||||
Reg.exe add 'HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsCopilot' /v 'AllowCopilotRuntime' /t REG_DWORD /d @('0', '1')[$revert] /f *>$null
|
Reg.exe add 'HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsCopilot' /v 'AllowCopilotRuntime' /t REG_DWORD /d @('0', '1')[$revert] /f *>$null
|
||||||
@@ -228,15 +450,25 @@ function Disable-Registry-Keys {
|
|||||||
$backupPath = "$env:USERPROFILE\RemoveWindowsAI\Backup"
|
$backupPath = "$env:USERPROFILE\RemoveWindowsAI\Backup"
|
||||||
$backupFile = 'WSAIFabricSvc.reg'
|
$backupFile = 'WSAIFabricSvc.reg'
|
||||||
if ($revert) {
|
if ($revert) {
|
||||||
Reg.exe import "$backupPath\$backupFile" >$null
|
if (Test-Path "$backupPath\$backupFile") {
|
||||||
sc.exe create WSAIFabricSvc binPath= "$env:windir\System32\svchost.exe -k WSAIFabricSvcGroup -p" >$null
|
Reg.exe import "$backupPath\$backupFile" *>$null
|
||||||
|
sc.exe create WSAIFabricSvc binPath= "$env:windir\System32\svchost.exe -k WSAIFabricSvcGroup -p" *>$null
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
Write-Status -msg "Path Not Found: $backupPath\$backupFile" -errorOutput $true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ($backup) {
|
||||||
|
Write-Status -msg 'Backing up WSAIFabricSvc...'
|
||||||
#export the service to a reg file before removing it
|
#export the service to a reg file before removing it
|
||||||
if (!(Test-Path $backupPath)) {
|
if (!(Test-Path $backupPath)) {
|
||||||
New-Item $backupPath -Force -ItemType Directory | Out-Null
|
New-Item $backupPath -Force -ItemType Directory | Out-Null
|
||||||
}
|
}
|
||||||
Reg.exe export 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WSAIFabricSvc' "$backupPath\$backupFile" >$null
|
Reg.exe export 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WSAIFabricSvc' "$backupPath\$backupFile" >$null
|
||||||
|
}
|
||||||
|
Write-Status -msg 'Removing up WSAIFabricSvc...'
|
||||||
#delete the service
|
#delete the service
|
||||||
sc.exe delete WSAIFabricSvc *>$null
|
sc.exe delete WSAIFabricSvc *>$null
|
||||||
}
|
}
|
||||||
@@ -251,6 +483,7 @@ function Disable-Registry-Keys {
|
|||||||
# prob not worth trying to restore shouldnt break any functionality if the rest is restored
|
# prob not worth trying to restore shouldnt break any functionality if the rest is restored
|
||||||
# =========================
|
# =========================
|
||||||
function Remove-Copilot-Nudges-Keys {
|
function Remove-Copilot-Nudges-Keys {
|
||||||
|
if (!$revert) {
|
||||||
#prefire copilot nudges package by deleting the registry keys
|
#prefire copilot nudges package by deleting the registry keys
|
||||||
Write-Status -msg 'Removing Copilot Nudges Registry Keys...'
|
Write-Status -msg 'Removing Copilot Nudges Registry Keys...'
|
||||||
$keys = @(
|
$keys = @(
|
||||||
@@ -292,6 +525,7 @@ function Remove-Copilot-Nudges-Keys {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -328,6 +562,32 @@ function Disable-Copilot-Policies {
|
|||||||
|
|
||||||
|
|
||||||
function Remove-AI-Appx-Packages {
|
function Remove-AI-Appx-Packages {
|
||||||
|
if ($revert) {
|
||||||
|
#install backedup appx packages
|
||||||
|
$appxBackup = "$env:USERPROFILE\RemoveWindowsAI\Backup\AppxBackup"
|
||||||
|
if (Test-Path $appxBackup) {
|
||||||
|
$files = Get-ChildItem $appxBackup
|
||||||
|
Write-Status -msg 'Installing Appx Packages...'
|
||||||
|
foreach ($file in $files) {
|
||||||
|
if ($file.FullName -like '*.cer') {
|
||||||
|
#install certs
|
||||||
|
Import-Certificate -FilePath $file.FullName -CertStoreLocation Cert:\LocalMachine\Root | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#install the packages
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
foreach ($file in $files) {
|
||||||
|
if ($file.FullName -like '*.appx') {
|
||||||
|
Add-AppPackage -Path $file.FullName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Status -msg 'Unable to Find AppxBackup in User Directory!' -errorOutput $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
#to make this part faster make a txt file in temp with chunck of removal
|
#to make this part faster make a txt file in temp with chunck of removal
|
||||||
#code and then just run that from run
|
#code and then just run that from run
|
||||||
#trusted function due to the design of having it hidden from the user
|
#trusted function due to the design of having it hidden from the user
|
||||||
@@ -374,6 +634,26 @@ function Remove-AI-Appx-Packages {
|
|||||||
'WindowsWorkload.ImageTextSearch.Stx.3'
|
'WindowsWorkload.ImageTextSearch.Stx.3'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if ($backup) {
|
||||||
|
#backup appx packages before removing them
|
||||||
|
$appxBackup = "$env:USERPROFILE\RemoveWindowsAI\Backup\AppxBackup"
|
||||||
|
if (!(Test-Path $appxBackup)) {
|
||||||
|
New-Item $appxBackup -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Status -msg 'Backing Up AI Appx Packages...'
|
||||||
|
#aix and core ai can not be backed up
|
||||||
|
$packagesToBackup = get-appxpackage -AllUsers | Where-Object { $aipackages -contains $_.Name } | Where-Object { $_.Name -ne 'MicrosoftWindows.Client.AIX' -and $_.Name -ne 'MicrosoftWindows.Client.CoreAI' }
|
||||||
|
[System.Windows.MessageBox]::Show('Please Select [NONE] On The Following Windows' , 'INFO', [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information) *>$null
|
||||||
|
foreach ($package in $packagesToBackup) {
|
||||||
|
Backup-Appx -WSAppPath $package.InstallLocation -WSAppOutputPath $appxBackup
|
||||||
|
}
|
||||||
|
|
||||||
|
#cleanup tools
|
||||||
|
Remove-Item "$env:TEMP\AppxBackupTools-master\tool\x64" -Force -Recurse -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item "$env:TEMP\BackupTools.zip" -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
$code = @'
|
$code = @'
|
||||||
$aipackages = @(
|
$aipackages = @(
|
||||||
'MicrosoftWindows.Client.AIX'
|
'MicrosoftWindows.Client.AIX'
|
||||||
@@ -526,7 +806,10 @@ foreach ($choice in $aipackages) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function Remove-Recall-Optional-Feature {
|
function Remove-Recall-Optional-Feature {
|
||||||
|
if (!$revert) {
|
||||||
#doesnt seem to work just gets stuck (does anyone really want this shit lol)
|
#doesnt seem to work just gets stuck (does anyone really want this shit lol)
|
||||||
#Enable-WindowsOptionalFeature -Online -FeatureName 'Recall' -All -NoRestart
|
#Enable-WindowsOptionalFeature -Online -FeatureName 'Recall' -All -NoRestart
|
||||||
#remove recall optional feature
|
#remove recall optional feature
|
||||||
@@ -543,9 +826,11 @@ function Remove-Recall-Optional-Feature {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# not restoring for now shouldnt cause any issues (also may not even be possible to restore)
|
||||||
function Remove-AI-CBS-Packages {
|
function Remove-AI-CBS-Packages {
|
||||||
|
if (!$revert) {
|
||||||
#additional hidden packages
|
#additional hidden packages
|
||||||
Write-Status -msg 'Removing Additional Hidden AI Packages...'
|
Write-Status -msg 'Removing Additional Hidden AI Packages...'
|
||||||
#unhide the packages from dism, remove owners subkey for removal
|
#unhide the packages from dism, remove owners subkey for removal
|
||||||
@@ -567,11 +852,87 @@ function Remove-AI-CBS-Packages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function Remove-AI-Files {
|
function Remove-AI-Files {
|
||||||
#prob add params here for each file removal
|
#prob add params here for each file removal
|
||||||
|
|
||||||
|
|
||||||
|
if ($revert) {
|
||||||
|
if (Test-Path "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles") {
|
||||||
|
Write-Status -msg 'Restoring Appx Package Files...'
|
||||||
|
$paths = Get-Content "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\backupPaths.txt"
|
||||||
|
foreach ($path in $paths) {
|
||||||
|
$fileName = Split-Path $path -Leaf
|
||||||
|
$dest = Split-Path $path -Parent
|
||||||
|
try {
|
||||||
|
Move-Item -Path "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\$fileName" -Destination $dest -Force -ErrorAction Stop
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$command = "Move-Item -Path `"$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\$fileName`" -Destination `"$dest`" -Force"
|
||||||
|
Run-Trusted -command $command -psversion $psversion
|
||||||
|
Start-Sleep 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\OfficeAI") {
|
||||||
|
Write-Status -msg 'Restoring Office AI Files...'
|
||||||
|
Move-Item "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\OfficeAI\x64\AI" -Destination "$env:ProgramFiles\Microsoft Office\root\vfs\ProgramFilesCommonX64\Microsoft Shared\Office16" -Force
|
||||||
|
Move-Item "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\OfficeAI\x86\AI" -Destination "$env:ProgramFiles\Microsoft Office\root\vfs\ProgramFilesCommonX64\Microsoft Shared\Office16" -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Status -msg 'Restoring AI URIs...'
|
||||||
|
$regs = Get-ChildItem "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\URIHandlers"
|
||||||
|
foreach ($reg in $regs) {
|
||||||
|
Reg.exe import $reg.FullName *>$null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Status -msg 'Files Restored... You May Need to Repair the Apps Using the Microsoft Store'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Status -msg 'Unable to Find Backup Files!' -errorOutput $true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
$aipackages = @(
|
||||||
|
# 'MicrosoftWindows.Client.Photon'
|
||||||
|
'MicrosoftWindows.Client.AIX'
|
||||||
|
'MicrosoftWindows.Client.CoPilot'
|
||||||
|
'Microsoft.Windows.Ai.Copilot.Provider'
|
||||||
|
'Microsoft.Copilot'
|
||||||
|
'Microsoft.MicrosoftOfficeHub'
|
||||||
|
'MicrosoftWindows.Client.CoreAI'
|
||||||
|
#ai component packages installed on copilot+ pcs
|
||||||
|
'WindowsWorkload.Data.Analysis.Stx.1'
|
||||||
|
'WindowsWorkload.Manager.1'
|
||||||
|
'WindowsWorkload.PSOnnxRuntime.Stx.2.7'
|
||||||
|
'WindowsWorkload.PSTokenizer.Stx.2.7'
|
||||||
|
'WindowsWorkload.QueryBlockList.1'
|
||||||
|
'WindowsWorkload.QueryProcessor.Data.1'
|
||||||
|
'WindowsWorkload.QueryProcessor.Stx.1'
|
||||||
|
'WindowsWorkload.SemanticText.Data.1'
|
||||||
|
'WindowsWorkload.SemanticText.Stx.1'
|
||||||
|
'WindowsWorkload.Data.ContentExtraction.Stx.1'
|
||||||
|
'WindowsWorkload.ScrRegDetection.Data.1'
|
||||||
|
'WindowsWorkload.ScrRegDetection.Stx.1'
|
||||||
|
'WindowsWorkload.TextRecognition.Stx.1'
|
||||||
|
'WindowsWorkload.Data.ImageSearch.Stx.1'
|
||||||
|
'WindowsWorkload.ImageContentModeration.1'
|
||||||
|
'WindowsWorkload.ImageContentModeration.Data.1'
|
||||||
|
'WindowsWorkload.ImageSearch.Data.3'
|
||||||
|
'WindowsWorkload.ImageSearch.Stx.2'
|
||||||
|
'WindowsWorkload.ImageSearch.Stx.3'
|
||||||
|
'WindowsWorkload.ImageTextSearch.Data.3'
|
||||||
|
'WindowsWorkload.PSOnnxRuntime.Stx.3.2'
|
||||||
|
'WindowsWorkload.PSTokenizerShared.Data.3.2'
|
||||||
|
'WindowsWorkload.PSTokenizerShared.Stx.3.2'
|
||||||
|
'WindowsWorkload.ImageTextSearch.Stx.2'
|
||||||
|
'WindowsWorkload.ImageTextSearch.Stx.3'
|
||||||
|
)
|
||||||
|
|
||||||
Write-Status -msg 'Removing Appx Package Files...'
|
Write-Status -msg 'Removing Appx Package Files...'
|
||||||
#-----------------------------------------------------------------------remove files
|
#-----------------------------------------------------------------------remove files
|
||||||
$appsPath = "$env:SystemRoot\SystemApps"
|
$appsPath = "$env:SystemRoot\SystemApps"
|
||||||
@@ -634,6 +995,13 @@ function Remove-AI-Files {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($backup) {
|
||||||
|
Write-Status -msg 'Backing Up AI Files...'
|
||||||
|
$backupDir = "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles"
|
||||||
|
if (!(Test-Path $backupDir)) {
|
||||||
|
New-Item $backupDir -Force -ItemType Directory | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($Path in $packagesPath) {
|
foreach ($Path in $packagesPath) {
|
||||||
#only remove dlls from photon to prevent startmenu from breaking
|
#only remove dlls from photon to prevent startmenu from breaking
|
||||||
@@ -643,10 +1011,25 @@ function Remove-AI-Files {
|
|||||||
# Start-Sleep 1
|
# Start-Sleep 1
|
||||||
# }
|
# }
|
||||||
# else {
|
# else {
|
||||||
|
|
||||||
|
if ($backup) {
|
||||||
|
$backupFiles = "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\backupPaths.txt"
|
||||||
|
if (!(Test-Path $backupFiles -PathType Leaf)) {
|
||||||
|
New-Item $backupFiles -Force -ItemType File | Out-Null
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Copy-Item -Path $Path -Destination $backupDir -Force -Recurse -ErrorAction Stop
|
||||||
|
Add-Content -Path $backupFiles -Value $Path
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
#ignore any errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$command = "Remove-item ""$Path"" -force -recurse"
|
$command = "Remove-item ""$Path"" -force -recurse"
|
||||||
Run-Trusted -command $command -psversion $psversion
|
Run-Trusted -command $command -psversion $psversion
|
||||||
Start-Sleep 1
|
Start-Sleep 1
|
||||||
# }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -719,6 +1102,22 @@ function Remove-AI-Files {
|
|||||||
|
|
||||||
foreach ($path in $aiPaths) {
|
foreach ($path in $aiPaths) {
|
||||||
if (Test-Path $path -PathType Container -ErrorAction SilentlyContinue) {
|
if (Test-Path $path -PathType Container -ErrorAction SilentlyContinue) {
|
||||||
|
if ($backup) {
|
||||||
|
Write-Status -msg 'Backing Up Office AI Files...'
|
||||||
|
$backupDir = "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\OfficeAI"
|
||||||
|
if (!(Test-Path $backupDir)) {
|
||||||
|
New-Item $backupDir -Force -ItemType Directory | Out-Null
|
||||||
|
}
|
||||||
|
if ($path -like '*ProgramFilesCommonX64*') {
|
||||||
|
$backupDir = "$backupDir\x64"
|
||||||
|
New-Item $backupDir -Force -ItemType Directory | Out-Null
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$backupDir = "$backupDir\x86"
|
||||||
|
New-Item $backupDir -Force -ItemType Directory | Out-Null
|
||||||
|
}
|
||||||
|
Copy-Item -Path $path -Destination $backupDir -Force -Recurse -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
Remove-Item $path -Recurse -Force
|
Remove-Item $path -Recurse -Force
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -736,10 +1135,22 @@ function Remove-AI-Files {
|
|||||||
)
|
)
|
||||||
|
|
||||||
foreach ($uri in $uris) {
|
foreach ($uri in $uris) {
|
||||||
|
if ($backup) {
|
||||||
|
if (Test-Path $uri) {
|
||||||
|
$backupDir = "$env:USERPROFILE\RemoveWindowsAI\Backup\AIFiles\URIHandlers"
|
||||||
|
if (!(Test-Path $backupDir)) {
|
||||||
|
New-Item $backupDir -Force -ItemType Directory | Out-Null
|
||||||
|
}
|
||||||
|
$regExportPath = "$backupDir\$($uri -replace 'registry::HKEY_CLASSES_ROOT\\', '').reg"
|
||||||
|
Reg.exe export ($uri -replace 'registry::', '') $regExportPath /y *>$null
|
||||||
|
}
|
||||||
|
}
|
||||||
Remove-Item $uri -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item $uri -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function Hide-AI-Components {
|
function Hide-AI-Components {
|
||||||
#hide ai components in immersive settings
|
#hide ai components in immersive settings
|
||||||
@@ -873,10 +1284,16 @@ else {
|
|||||||
$contentRow.Height = [System.Windows.GridLength]::new(1, [System.Windows.GridUnitType]::Star)
|
$contentRow.Height = [System.Windows.GridLength]::new(1, [System.Windows.GridUnitType]::Star)
|
||||||
$mainGrid.RowDefinitions.Add($contentRow) | Out-Null
|
$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
|
||||||
|
$mainGrid.RowDefinitions.Add($toggleRow) | Out-Null
|
||||||
|
|
||||||
$bottomRow = New-Object System.Windows.Controls.RowDefinition
|
$bottomRow = New-Object System.Windows.Controls.RowDefinition
|
||||||
$bottomRow.Height = [System.Windows.GridLength]::new(60)
|
$bottomRow.Height = [System.Windows.GridLength]::new(80)
|
||||||
$mainGrid.RowDefinitions.Add($bottomRow) | Out-Null
|
$mainGrid.RowDefinitions.Add($bottomRow) | Out-Null
|
||||||
|
|
||||||
|
|
||||||
$title = New-Object System.Windows.Controls.TextBlock
|
$title = New-Object System.Windows.Controls.TextBlock
|
||||||
$title.Text = 'Remove Windows AI'
|
$title.Text = 'Remove Windows AI'
|
||||||
$title.FontSize = 18
|
$title.FontSize = 18
|
||||||
@@ -980,9 +1397,189 @@ else {
|
|||||||
$stackPanel.Children.Add($optionContainer) | Out-Null
|
$stackPanel.Children.Add($optionContainer) | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#add switches for backup and revert modes
|
||||||
|
function Add-iOSToggleToUI {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[System.Windows.Controls.Panel]$ParentControl,
|
||||||
|
[bool]$IsChecked = $false,
|
||||||
|
[string]$Name = 'iOSToggle'
|
||||||
|
)
|
||||||
|
|
||||||
|
$styleXaml = @'
|
||||||
|
<ResourceDictionary
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<Style x:Key="CleanToggleStyle" TargetType="{x:Type ToggleButton}">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Width" Value="40"/>
|
||||||
|
<Setter Property="Height" Value="24"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
<Setter Property="Focusable" Value="False"/>
|
||||||
|
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type ToggleButton}">
|
||||||
|
<Grid>
|
||||||
|
<!-- Switch Track -->
|
||||||
|
<Border x:Name="SwitchTrack"
|
||||||
|
Width="40" Height="24"
|
||||||
|
Background="#E5E5E7"
|
||||||
|
CornerRadius="12"
|
||||||
|
BorderThickness="0">
|
||||||
|
|
||||||
|
<!-- Switch Thumb -->
|
||||||
|
<Border x:Name="SwitchThumb"
|
||||||
|
Width="20" Height="20"
|
||||||
|
Background="White"
|
||||||
|
CornerRadius="10"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="2,0,0,0">
|
||||||
|
<Border.Effect>
|
||||||
|
<DropShadowEffect Color="#00000040"
|
||||||
|
Direction="270"
|
||||||
|
ShadowDepth="1"
|
||||||
|
BlurRadius="3"
|
||||||
|
Opacity="0.4"/>
|
||||||
|
</Border.Effect>
|
||||||
|
<Border.RenderTransform>
|
||||||
|
<TranslateTransform x:Name="ThumbTransform" X="0"/>
|
||||||
|
</Border.RenderTransform>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<!-- Checked State (ON) -->
|
||||||
|
<Trigger Property="IsChecked" Value="True">
|
||||||
|
<Trigger.EnterActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<!-- Slide thumb to right -->
|
||||||
|
<DoubleAnimation
|
||||||
|
Storyboard.TargetName="ThumbTransform"
|
||||||
|
Storyboard.TargetProperty="X"
|
||||||
|
To="16"
|
||||||
|
Duration="0:0:0.2"/>
|
||||||
|
<!-- Change track color to green -->
|
||||||
|
<ColorAnimation
|
||||||
|
Storyboard.TargetName="SwitchTrack"
|
||||||
|
Storyboard.TargetProperty="Background.Color"
|
||||||
|
To="#34C759"
|
||||||
|
Duration="0:0:0.2"/>
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</Trigger.EnterActions>
|
||||||
|
<Trigger.ExitActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<!-- Slide thumb to left -->
|
||||||
|
<DoubleAnimation
|
||||||
|
Storyboard.TargetName="ThumbTransform"
|
||||||
|
Storyboard.TargetProperty="X"
|
||||||
|
To="0"
|
||||||
|
Duration="0:0:0.2"/>
|
||||||
|
<!-- Change track color to gray -->
|
||||||
|
<ColorAnimation
|
||||||
|
Storyboard.TargetName="SwitchTrack"
|
||||||
|
Storyboard.TargetProperty="Background.Color"
|
||||||
|
To="#E5E5E7"
|
||||||
|
Duration="0:0:0.2"/>
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</Trigger.ExitActions>
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
||||||
|
'@
|
||||||
|
|
||||||
|
$reader = New-Object System.Xml.XmlNodeReader([xml]$styleXaml)
|
||||||
|
$resourceDict = [Windows.Markup.XamlReader]::Load($reader)
|
||||||
|
|
||||||
|
$toggleButton = New-Object System.Windows.Controls.Primitives.ToggleButton
|
||||||
|
$toggleButton.Name = $Name
|
||||||
|
$toggleButton.IsChecked = $IsChecked
|
||||||
|
$toggleButton.Style = $resourceDict['CleanToggleStyle']
|
||||||
|
$ParentControl.Children.Add($toggleButton) | Out-Null
|
||||||
|
|
||||||
|
return $toggleButton
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$toggleGrid = New-Object System.Windows.Controls.Grid
|
||||||
|
[System.Windows.Controls.Grid]::SetRow($toggleGrid, 2)
|
||||||
|
$toggleGrid.Margin = '20,10,55,15'
|
||||||
|
|
||||||
|
$row1 = New-Object System.Windows.Controls.RowDefinition
|
||||||
|
$row1.Height = [System.Windows.GridLength]::Auto
|
||||||
|
$row2 = New-Object System.Windows.Controls.RowDefinition
|
||||||
|
$row2.Height = [System.Windows.GridLength]::Auto
|
||||||
|
$toggleGrid.RowDefinitions.Add($row1) | Out-Null
|
||||||
|
$toggleGrid.RowDefinitions.Add($row2) | Out-Null
|
||||||
|
|
||||||
|
$mainGrid.Children.Add($toggleGrid) | Out-Null
|
||||||
|
|
||||||
|
$togglePanel1 = New-Object System.Windows.Controls.StackPanel
|
||||||
|
$togglePanel1.Orientation = [System.Windows.Controls.Orientation]::Horizontal
|
||||||
|
$togglePanel1.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Left
|
||||||
|
$togglePanel1.VerticalAlignment = [System.Windows.VerticalAlignment]::Center
|
||||||
|
$togglePanel1.Margin = New-Object System.Windows.Thickness(0, 0, 0, 10)
|
||||||
|
[System.Windows.Controls.Grid]::SetRow($togglePanel1, 0)
|
||||||
|
|
||||||
|
$toggleLabel1 = New-Object System.Windows.Controls.TextBlock
|
||||||
|
$toggleLabel1.Text = 'Revert Mode:'
|
||||||
|
$toggleLabel1.Foreground = [System.Windows.Media.Brushes]::White
|
||||||
|
$toggleLabel1.VerticalAlignment = [System.Windows.VerticalAlignment]::Center
|
||||||
|
$toggleLabel1.Margin = New-Object System.Windows.Thickness(0, 0, 10, 0)
|
||||||
|
$togglePanel1.Children.Add($toggleLabel1) | Out-Null
|
||||||
|
|
||||||
|
$revertModeToggle = Add-iOSToggleToUI -ParentControl $togglePanel1 -IsChecked $revert
|
||||||
|
$toggleGrid.Children.Add($togglePanel1) | Out-Null
|
||||||
|
|
||||||
|
$togglePanel2 = New-Object System.Windows.Controls.StackPanel
|
||||||
|
$togglePanel2.Orientation = [System.Windows.Controls.Orientation]::Horizontal
|
||||||
|
$togglePanel2.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Left
|
||||||
|
$togglePanel2.VerticalAlignment = [System.Windows.VerticalAlignment]::Center
|
||||||
|
[System.Windows.Controls.Grid]::SetRow($togglePanel2, 1)
|
||||||
|
|
||||||
|
$toggleLabel2 = New-Object System.Windows.Controls.TextBlock
|
||||||
|
$toggleLabel2.Text = 'Backup Mode:'
|
||||||
|
$toggleLabel2.Foreground = [System.Windows.Media.Brushes]::White
|
||||||
|
$toggleLabel2.VerticalAlignment = [System.Windows.VerticalAlignment]::Center
|
||||||
|
$toggleLabel2.Margin = New-Object System.Windows.Thickness(0, 0, 10, 0)
|
||||||
|
$togglePanel2.Children.Add($toggleLabel2) | Out-Null
|
||||||
|
|
||||||
|
$backupModeToggle = Add-iOSToggleToUI -ParentControl $togglePanel2 -IsChecked $backup
|
||||||
|
$toggleGrid.Children.Add($togglePanel2) | Out-Null
|
||||||
|
|
||||||
|
$backupModeToggle.Add_Checked({
|
||||||
|
$Global:backup = 1
|
||||||
|
}) | Out-Null
|
||||||
|
|
||||||
|
$backupModeToggle.Add_Unchecked({
|
||||||
|
$Global:backup = 0
|
||||||
|
}) | Out-Null
|
||||||
|
|
||||||
|
$revertModeToggle.Add_Checked({
|
||||||
|
$Global:revert = 1
|
||||||
|
}) | Out-Null
|
||||||
|
$revertModeToggle.Add_Unchecked({
|
||||||
|
$Global:revert = 0
|
||||||
|
}) | Out-Null
|
||||||
|
|
||||||
|
|
||||||
$bottomGrid = New-Object System.Windows.Controls.Grid
|
$bottomGrid = New-Object System.Windows.Controls.Grid
|
||||||
[System.Windows.Controls.Grid]::SetRow($bottomGrid, 2)
|
[System.Windows.Controls.Grid]::SetRow($bottomGrid, 3)
|
||||||
$bottomGrid.Margin = '20,10,20,10'
|
$bottomGrid.Margin = '25,15,25,15'
|
||||||
|
|
||||||
$leftColumn = New-Object System.Windows.Controls.ColumnDefinition
|
$leftColumn = New-Object System.Windows.Controls.ColumnDefinition
|
||||||
$leftColumn.Width = [System.Windows.GridLength]::new(1, [System.Windows.GridUnitType]::Star)
|
$leftColumn.Width = [System.Windows.GridLength]::new(1, [System.Windows.GridUnitType]::Star)
|
||||||
@@ -1260,6 +1857,7 @@ else {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
$actionPanel.Children.Add($cancelButton) | Out-Null
|
$actionPanel.Children.Add($cancelButton) | Out-Null
|
||||||
$actionPanel.Children.Add($applyButton) | Out-Null
|
$actionPanel.Children.Add($applyButton) | Out-Null
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user