PowerShell-Block-Microsoft-Consumer-Copi ...

PowerShell-Block-Microsoft-Consumer-Copilot

Jul 26, 2026

#requires -Version 5.1

<#

.SYNOPSIS

Removes and blocks the consumer Microsoft Copilot experience on a personal Windows PC.

.DESCRIPTION

Run this script from Windows PowerShell as a local administrator.

The script:

1. Removes installed Microsoft.Copilot Appx packages.

2. Removes provisioned Microsoft.Copilot packages for future user profiles.

3. Enables the Windows policy that requests removal of the consumer Copilot app.

4. Adds an AppLocker packaged-app deny rule for MICROSOFT.COPILOT.

5. Blocks consumer Copilot web entry points in Edge, Chrome, Firefox, and the hosts file.

This script targets consumer Microsoft Copilot. It does not intentionally block

Microsoft 365 Copilot used with a work or school account.

.PARAMETER Mode

Enforce applies the controls. Detect checks them without making changes.

.EXAMPLE

powershell.exe -ExecutionPolicy Bypass -File .\Block-Microsoft-Consumer-Copilot.ps1

.EXAMPLE

powershell.exe -ExecutionPolicy Bypass -File .\Block-Microsoft-Consumer-Copilot.ps1 -Mode Detect

#>

[CmdletBinding()]

param(

[ValidateSet('Enforce', 'Detect')]

[string]$Mode = 'Enforce'

)

$ErrorActionPreference = 'Stop'

$copilotPublisher = 'CN=MICROSOFT CORPORATION, O=MICROSOFT CORPORATION, L=REDMOND, S=WASHINGTON, C=US'

$copilotProduct = 'MICROSOFT.COPILOT'

$appLockerAllowRuleId = 'A54A1EF4-0C58-471C-8F31-4C8B5DB5B7A1'

$appLockerDenyRuleId = 'B8E9655C-E6E8-4E84-B5D7-7D89996E54A2'

$logDirectory = Join-Path $env:ProgramData 'CopilotBlock'

$logPath = Join-Path $logDirectory 'Block-Microsoft-Consumer-Copilot.log'

$blockedBrowserPatterns = @(

'*://copilot.microsoft.com/*',

'*://*.copilot.microsoft.com/*',

'*://www.bing.com/chat*',

'*://bing.com/chat*',

'*://www.bing.com/copilot*',

'*://bing.com/copilot*'

)

$blockedHostNames = @(

'copilot.microsoft.com',

'www.copilot.microsoft.com'

)

function Write-Log {

param([string]$Message)

if (-not (Test-Path -LiteralPath $logDirectory)) {

New-Item -ItemType Directory -Path $logDirectory -Force | Out-Null

}

$entry = '{0:u} {1}' -f (Get-Date), $Message

Write-Host $entry

Add-Content -LiteralPath $logPath -Value $entry -Encoding UTF8

}

function Test-IsAdministrator {

$identity = [Security.Principal.WindowsIdentity]::GetCurrent()

$principal = [Security.Principal.WindowsPrincipal]::new($identity)

return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

}

function Remove-CopilotPackages {

Write-Log 'Removing installed Microsoft.Copilot packages.'

$installedPackages = @(Get-AppxPackage -AllUsers -Name 'Microsoft.Copilot' -ErrorAction SilentlyContinue)

foreach ($package in $installedPackages) {

try {

Remove-AppxPackage -Package $package.PackageFullName -AllUsers -ErrorAction Stop

Write-Log "Removed installed package: $($package.PackageFullName)"

}

catch {

Write-Log "All-users removal failed for $($package.PackageFullName); attempting current-user removal."

Remove-AppxPackage -Package $package.PackageFullName -ErrorAction SilentlyContinue

}

}

$provisionedPackages = @(

Get-AppxProvisionedPackage -Online |

Where-Object {

$_.DisplayName -eq 'Microsoft.Copilot' -or

$_.PackageName -like 'Microsoft.Copilot_*'

}

)

foreach ($package in $provisionedPackages) {

Remove-AppxProvisionedPackage -Online -PackageName $package.PackageName -AllUsers |

Out-Null

Write-Log "Removed provisioned package: $($package.PackageName)"

}

}

function Set-CopilotRemovalPolicy {

$policyPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI'

New-Item -Path $policyPath -Force | Out-Null

New-ItemProperty -Path $policyPath `

-Name 'RemoveMicrosoftCopilotApp' `

-PropertyType DWord `

-Value 1 `

-Force | Out-Null

Write-Log 'Enabled the RemoveMicrosoftCopilotApp Windows policy.'

}

function Set-BrowserUrlBlockList {

param([string]$RegistryPath)

New-Item -Path $RegistryPath -Force | Out-Null

# Remove only numeric URLBlocklist entries so this script owns a predictable list.

# A newly created registry key may cause Get-ItemProperty to emit no object in

# Windows PowerShell 5.1, so inspect its properties only when a result exists.

$registryValues = Get-ItemProperty -Path $RegistryPath -ErrorAction SilentlyContinue

if ($null -ne $registryValues) {

$registryValues.PSObject.Properties |

Where-Object Name -match '^\d+$' |

ForEach-Object {

Remove-ItemProperty -Path $RegistryPath -Name $_.Name -ErrorAction SilentlyContinue

}

}

for ($index = 0; $index -lt $blockedBrowserPatterns.Count; $index++) {

New-ItemProperty -Path $RegistryPath `

-Name ($index + 1).ToString() `

-PropertyType String `

-Value $blockedBrowserPatterns[$index] `

-Force | Out-Null

}

}

function Set-ManagedBrowserPolicies {

Set-BrowserUrlBlockList -RegistryPath 'HKLM:\SOFTWARE\Policies\Microsoft\Edge\URLBlocklist'

Set-BrowserUrlBlockList -RegistryPath 'HKLM:\SOFTWARE\Policies\Google\Chrome\URLBlocklist'

Write-Log 'Configured Microsoft Edge and Google Chrome URL block lists.'

}

function Set-FirefoxPolicy {

$firefoxRoots = @(

(Join-Path $env:ProgramFiles 'Mozilla Firefox'),

(Join-Path ${env:ProgramFiles(x86)} 'Mozilla Firefox')

) | Where-Object { $_ -and (Test-Path -LiteralPath $_) }

foreach ($firefoxRoot in $firefoxRoots) {

$distributionDirectory = Join-Path $firefoxRoot 'distribution'

$policyPath = Join-Path $distributionDirectory 'policies.json'

New-Item -ItemType Directory -Path $distributionDirectory -Force | Out-Null

$policyDocument = [ordered]@{ policies = [ordered]@{} }

if (Test-Path -LiteralPath $policyPath) {

try {

$existing = Get-Content -LiteralPath $policyPath -Raw | ConvertFrom-Json

if ($existing.policies) {

$policyDocument = $existing

}

}

catch {

$backupPath = "$policyPath.pre-copilot-block.bak"

Copy-Item -LiteralPath $policyPath -Destination $backupPath -Force

Write-Log "Existing Firefox policy was invalid JSON and was backed up to $backupPath"

}

}

$policyDocument.policies | Add-Member `

-NotePropertyName 'WebsiteFilter' `

-NotePropertyValue ([ordered]@{ Block = $blockedBrowserPatterns }) `

-Force

$policyDocument |

ConvertTo-Json -Depth 20 |

Set-Content -LiteralPath $policyPath -Encoding UTF8

Write-Log "Configured Mozilla Firefox URL blocking: $policyPath"

}

}

function Set-HostsFileBlock {

$hostsPath = Join-Path $env:SystemRoot 'System32\drivers\etc\hosts'

$beginMarker = '# BEGIN Microsoft Consumer Copilot block'

$endMarker = '# END Microsoft Consumer Copilot block'

$content = Get-Content -LiteralPath $hostsPath -Raw

$escapedBegin = [regex]::Escape($beginMarker)

$escapedEnd = [regex]::Escape($endMarker)

$content = [regex]::Replace(

$content,

"(?ms)\r?\n?$escapedBegin.*?$escapedEnd\r?\n?",

[Environment]::NewLine

)

$blockLines = @($beginMarker)

foreach ($hostName in $blockedHostNames) {

$blockLines += "0.0.0.0`t$hostName"

$blockLines += "::1`t$hostName"

}

$blockLines += $endMarker

$newContent = $content.TrimEnd() +

[Environment]::NewLine +

($blockLines -join [Environment]::NewLine) +

[Environment]::NewLine

Set-Content -LiteralPath $hostsPath -Value $newContent -Encoding ASCII

Clear-DnsClientCache

Write-Log 'Added consumer Copilot host names to the Windows hosts file.'

}

function Set-CopilotAppLockerRule {

if (-not (Get-Command Set-AppLockerPolicy -ErrorAction SilentlyContinue)) {

Install-CopilotRemovalWatchdog

Write-Log 'AppLocker is unavailable. Installed the removal watchdog fallback instead.'

return

}

$xml = @"

"@

$xmlPath = Join-Path $logDirectory 'Microsoft-Copilot-AppLocker.xml'

Set-Content -LiteralPath $xmlPath -Value $xml -Encoding UTF8

Set-AppLockerPolicy -XmlPolicy $xmlPath -Merge

& sc.exe config AppIDSvc start= auto | Out-Null

Start-Service -Name AppIDSvc -ErrorAction SilentlyContinue

Write-Log 'Merged the Microsoft Copilot packaged-app deny rule into the local AppLocker policy.'

}

function Install-CopilotRemovalWatchdog {

$watchdogPath = Join-Path $logDirectory 'Remove-Microsoft-Copilot-Watchdog.ps1'

$watchdogScript = @'

$installed = @(Get-AppxPackage -AllUsers -Name 'Microsoft.Copilot' -ErrorAction SilentlyContinue)

foreach ($package in $installed) {

Remove-AppxPackage -Package $package.PackageFullName -AllUsers -ErrorAction SilentlyContinue

}

$provisioned = @(

Get-AppxProvisionedPackage -Online |

Where-Object {

$_.DisplayName -eq 'Microsoft.Copilot' -or

$_.PackageName -like 'Microsoft.Copilot_*'

}

)

foreach ($package in $provisioned) {

Remove-AppxProvisionedPackage -Online -PackageName $package.PackageName -AllUsers -ErrorAction SilentlyContinue |

Out-Null

}

'@

Set-Content -LiteralPath $watchdogPath -Value $watchdogScript -Encoding UTF8

$action = New-ScheduledTaskAction `

-Execute 'powershell.exe' `

-Argument "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File "$watchdogPath""

$startupTrigger = New-ScheduledTaskTrigger -AtStartup

$logonTrigger = New-ScheduledTaskTrigger -AtLogOn

$repeatingTrigger = New-ScheduledTaskTrigger `

-Once `

-At ((Get-Date).AddMinutes(2)) `

-RepetitionInterval (New-TimeSpan -Minutes 30)

$principal = New-ScheduledTaskPrincipal `

-UserId 'SYSTEM' `

-LogonType ServiceAccount `

-RunLevel Highest

Register-ScheduledTask `

-TaskName 'Block Microsoft Consumer Copilot' `

-Action $action `

-Trigger @($startupTrigger, $logonTrigger, $repeatingTrigger) `

-Principal $principal `

-Description 'Repeatedly removes the consumer Microsoft Copilot package when AppLocker is unavailable.' `

-Force | Out-Null

}

function Get-ComplianceState {

$findings = [System.Collections.Generic.List[string]]::new()

if (Get-AppxPackage -AllUsers -Name 'Microsoft.Copilot' -ErrorAction SilentlyContinue) {

$findings.Add('Microsoft.Copilot is installed.')

}

if (

Get-AppxProvisionedPackage -Online |

Where-Object {

$_.DisplayName -eq 'Microsoft.Copilot' -or

$_.PackageName -like 'Microsoft.Copilot_*'

}

) {

$findings.Add('Microsoft.Copilot is provisioned for new user profiles.')

}

$removePolicy = Get-ItemPropertyValue `

-Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI' `

-Name 'RemoveMicrosoftCopilotApp' `

-ErrorAction SilentlyContinue

if ($removePolicy -ne 1) {

$findings.Add('RemoveMicrosoftCopilotApp policy is not enabled.')

}

foreach ($browserPath in @(

'HKLM:\SOFTWARE\Policies\Microsoft\Edge\URLBlocklist',

'HKLM:\SOFTWARE\Policies\Google\Chrome\URLBlocklist'

)) {

$values = @(

(Get-ItemProperty -Path $browserPath -ErrorAction SilentlyContinue).PSObject.Properties |

Where-Object Name -match '^\d+$' |

Select-Object -ExpandProperty Value

)

if ($values -notcontains '*://copilot.microsoft.com/*') {

$findings.Add("Consumer Copilot URL isn't blocked at $browserPath")

}

}

if (Get-Command Get-AppLockerPolicy -ErrorAction SilentlyContinue) {

$localAppLocker = Get-AppLockerPolicy -Local -Xml -ErrorAction SilentlyContinue

if ($localAppLocker -notmatch [regex]::Escape($copilotProduct)) {

$findings.Add('The local AppLocker policy does not contain the Copilot deny rule.')

}

}

elseif (-not (Get-ScheduledTask -TaskName 'Block Microsoft Consumer Copilot' -ErrorAction SilentlyContinue)) {

$findings.Add('Neither AppLocker nor the Microsoft Copilot removal watchdog is configured.')

}

return $findings

}

if (-not (Test-IsAdministrator)) {

throw 'Run this script from an elevated Windows PowerShell session (Run as administrator).'

}

Write-Log "Starting mode: $Mode"

if ($Mode -eq 'Enforce') {

Remove-CopilotPackages

Set-CopilotRemovalPolicy

Set-ManagedBrowserPolicies

Set-FirefoxPolicy

Set-HostsFileBlock

Set-CopilotAppLockerRule

}

$remainingFindings = @(Get-ComplianceState)

if ($remainingFindings.Count -eq 0) {

Write-Log 'COMPLIANT: consumer Microsoft Copilot is removed and the local controls are present.'

exit 0

}

foreach ($finding in $remainingFindings) {

Write-Log "NONCOMPLIANT: $finding"

}

exit 1

Gefällt dir dieser Beitrag?

Kaufe Gregarious einen Kaffee

Mehr von Gregarious

DatenschutzNutzungsbedingungenMelden