112 lines
5.6 KiB
PowerShell
112 lines
5.6 KiB
PowerShell
[Console]::OutputEncoding = [Text.Encoding]::UTF8
|
|
$ErrorActionPreference = 'SilentlyContinue'
|
|
|
|
$pass = 0; $fail = 0
|
|
function Check($label, [bool]$ok, $detail='') {
|
|
if ($ok) { $script:pass++; $mark = '[OK] ' } else { $script:fail++; $mark = '[FAIL]' }
|
|
Write-Host ("{0} {1}" -f $mark, $label)
|
|
if ($detail) { Write-Host (" {0}" -f $detail) }
|
|
}
|
|
|
|
Write-Host "===== Services (expect removed) ====="
|
|
# Only actual AI services that RemoveWindowsAI targets.
|
|
foreach ($s in @('WSAIFabricSvc','AarSvc')) {
|
|
$svc = Get-Service -Name $s -ErrorAction SilentlyContinue
|
|
$detail = if ($svc) { "still present (Status=$($svc.Status))" } else { "gone" }
|
|
Check "service '$s' removed" (-not $svc) $detail
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "===== Appx packages (expect removed) ====="
|
|
foreach ($pat in @('Microsoft.Copilot','Microsoft.MicrosoftCopilot','Microsoft.Windows.Copilot','MicrosoftWindows.Client.AIX','MicrosoftWindows.Client.CoreAI')) {
|
|
$pkg = Get-AppxPackage -AllUsers -Name "$pat*" -ErrorAction SilentlyContinue
|
|
$detail = if ($pkg) { "still present: $(($pkg | Select -Expand Name) -join ',')" } else { "not installed" }
|
|
Check "Appx '$pat*' removed" (-not $pkg) $detail
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "===== Recall ====="
|
|
$recall = Get-WindowsOptionalFeature -Online -FeatureName 'Recall' -ErrorAction SilentlyContinue
|
|
if ($recall) {
|
|
Check "Recall optional feature disabled" ($recall.State -eq 'Disabled') "state=$($recall.State)"
|
|
} else {
|
|
Check "Recall optional feature absent" $true "feature not found"
|
|
}
|
|
$rct = @(Get-ScheduledTask -TaskPath '\Microsoft\Windows\WindowsAI\*' -ErrorAction SilentlyContinue)
|
|
$detail = if ($rct.Count -gt 0) { "remaining: $(($rct | Select -Expand TaskName) -join ',')" } else { "none" }
|
|
Check "WindowsAI scheduled tasks removed" ($rct.Count -eq 0) $detail
|
|
|
|
Write-Host ""
|
|
Write-Host "===== Policy registry ====="
|
|
# Copilot's turn-off flag is under HKCU (tool writes to current user hive).
|
|
# WindowsAI policy keys are machine-wide (HKLM).
|
|
$policies = @(
|
|
@{ Path = 'HKCU:\SOFTWARE\Policies\Microsoft\Windows\WindowsCopilot'; Name = 'TurnOffWindowsCopilot'; Expect = 1 },
|
|
@{ Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI'; Name = 'DisableAIDataAnalysis'; Expect = 1 },
|
|
@{ Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI'; Name = 'DisableClickToDo'; Expect = 1 },
|
|
@{ Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI'; Name = 'AllowRecallEnablement'; Expect = 0 }
|
|
)
|
|
foreach ($p in $policies) {
|
|
$val = (Get-ItemProperty -Path $p.Path -Name $p.Name -ErrorAction SilentlyContinue).($p.Name)
|
|
$shortPath = $p.Path -replace '^HK..:\\SOFTWARE\\',''
|
|
Check "$shortPath : $($p.Name) == $($p.Expect)" ($val -eq $p.Expect) "actual=$val"
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "===== Notepad Rewrite (per-user, populated on first Notepad launch) ====="
|
|
# Key only appears after a user opens Notepad. Fail only if any user hive has RewriteEnabled=1.
|
|
$bad = @()
|
|
Get-ChildItem 'Registry::HKEY_USERS' -ErrorAction SilentlyContinue | ForEach-Object {
|
|
$np = "Registry::$($_.Name)\Software\Microsoft\Notepad"
|
|
$v = (Get-ItemProperty $np -Name RewriteEnabled -ErrorAction SilentlyContinue).RewriteEnabled
|
|
if ($v -eq 1) { $bad += "$($_.Name)=1" }
|
|
}
|
|
$d = if ($bad) { "enabled in: $($bad -join ',')" } else { "not enabled in any user hive" }
|
|
Check "Notepad Rewrite not enabled anywhere" (-not $bad) $d
|
|
|
|
Write-Host ""
|
|
Write-Host "===== IntegratedServicesRegionPolicySet (Copilot entries) ====="
|
|
$jsonPath = 'C:\Windows\System32\IntegratedServicesRegionPolicySet.json'
|
|
if (Test-Path $jsonPath) {
|
|
$j = Get-Content $jsonPath -Raw | ConvertFrom-Json
|
|
$copilot = @($j.policies | Where-Object { ($_ | ConvertTo-Json -Depth 3) -match '[Cc]opilot' })
|
|
$disabled = @($copilot | Where-Object { $_.defaultState -eq 'disabled' })
|
|
$ok = ($copilot.Count -gt 0) -and ($disabled.Count -eq $copilot.Count)
|
|
Check "all Copilot policies disabled" $ok "disabled $($disabled.Count) of $($copilot.Count) Copilot entries"
|
|
} else {
|
|
Check "IntegratedServicesRegionPolicySet.json present" $false "file missing"
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "===== Update cleanup safety net ====="
|
|
$uct = Get-ScheduledTask -TaskName '*RemoveAI*' -ErrorAction SilentlyContinue
|
|
$uctDetail = if ($uct) { "found: $($uct.TaskName), state=$($uct.State)" } else { "missing" }
|
|
Check "RemoveAI update-cleanup scheduled task exists" ([bool]$uct) $uctDetail
|
|
|
|
Write-Host ""
|
|
Write-Host "===== Leftover AI SystemApps (expect gone) ====="
|
|
# Only check SystemApps dirs and WindowsApps — DLLs in System32 are protected and not
|
|
# expected to be deleted; the services/executables are what matter.
|
|
$paths = @(
|
|
'C:\Windows\SystemApps\MicrosoftWindows.Client.CoPilot_cw5n1h2txyewy',
|
|
'C:\Windows\SystemApps\MicrosoftWindows.Client.AIX_cw5n1h2txyewy'
|
|
)
|
|
foreach ($p in $paths) {
|
|
$hit = Get-Item -Path $p -ErrorAction SilentlyContinue
|
|
$d = if ($hit) { "still exists" } else { "gone" }
|
|
Check "path gone: $p" (-not $hit) $d
|
|
}
|
|
$wap = @(Get-ChildItem 'C:\Program Files\WindowsApps' -Filter 'Microsoft.Copilot_*' -ErrorAction SilentlyContinue)
|
|
$d = if ($wap.Count -gt 0) { "$($wap.Count) dir(s)" } else { "none" }
|
|
Check "WindowsApps Microsoft.Copilot_* gone" ($wap.Count -eq 0) $d
|
|
|
|
Write-Host ""
|
|
Write-Host "===== Restore point ====="
|
|
$rps = Get-ComputerRestorePoint -ErrorAction SilentlyContinue | Where-Object { $_.Description -match 'RemoveWindowsAI' }
|
|
$rpDetail = if ($rps) { "found: $(($rps | Select -Expand Description) -join ',')" } else { "none" }
|
|
Check "RemoveWindowsAI restore point exists" ([bool]$rps) $rpDetail
|
|
|
|
Write-Host ""
|
|
Write-Host "===== Summary ====="
|
|
Write-Host ("PASS: {0} FAIL: {1}" -f $pass, $fail)
|