mirror of
https://github.com/mr-r3b00t/go_darker
synced 2026-08-07 12:43:01 +00:00
Add files via upload
This commit is contained in:
@@ -0,0 +1,531 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<#
|
||||||
|
Manage-BrowserPrivacy.ps1
|
||||||
|
|
||||||
|
Purpose : View and control privacy / telemetry-related policy settings for
|
||||||
|
browsers installed on this Windows 11 machine:
|
||||||
|
Microsoft Edge, Google Chrome, Mozilla Firefox, Brave.
|
||||||
|
|
||||||
|
How : Uses each browser's supported policy registry keys under
|
||||||
|
HKLM\SOFTWARE\Policies\... . Browsers apply these on next start.
|
||||||
|
Only detected (installed) browsers are shown, unless -IncludeAll.
|
||||||
|
|
||||||
|
Notes : - Windows PowerShell 5.1 compatible. ASCII-only source.
|
||||||
|
- HKLM policy changes require Administrator.
|
||||||
|
- "Enabled" = the data-collection / suggestion feature is ON.
|
||||||
|
"Disabled" = hardened / OFF.
|
||||||
|
- "Enable" REMOVES the policy value (true browser default =
|
||||||
|
value absent), so browsers are not left permanently showing
|
||||||
|
"Managed by your organization" after a round trip.
|
||||||
|
- While policies are applied (hardened), browsers WILL show a
|
||||||
|
"managed" notice on their settings pages. That is how
|
||||||
|
Chromium/Firefox indicate active policies and is expected.
|
||||||
|
|
||||||
|
Usage :
|
||||||
|
.\Manage-BrowserPrivacy.ps1 # interactive menu
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -Report # print status and exit
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -DisableAll # harden all browsers
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -EnableAll # restore browser defaults
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -Csv .\out.csv # export status and exit
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -Report -IncludeAll # show non-installed too
|
||||||
|
|
||||||
|
DISCLAIMER: Review before use. Test on a non-production machine first.
|
||||||
|
No warranty.
|
||||||
|
#>
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[switch]$Report,
|
||||||
|
[switch]$DisableAll,
|
||||||
|
[switch]$EnableAll,
|
||||||
|
[switch]$IncludeAll,
|
||||||
|
[string]$Csv
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-StrictMode -Version 2.0
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Elevation helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Test-IsAdmin {
|
||||||
|
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
|
$pr = New-Object Security.Principal.WindowsPrincipal($id)
|
||||||
|
return $pr.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
|
}
|
||||||
|
|
||||||
|
$Script:IsAdmin = Test-IsAdmin
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Browser detection
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Get-BrowserInfo {
|
||||||
|
param([string]$Exe)
|
||||||
|
foreach ($hive in 'HKLM', 'HKCU') {
|
||||||
|
$key = ('{0}:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\{1}' -f $hive, $Exe)
|
||||||
|
if (Test-Path -LiteralPath $key) {
|
||||||
|
$ver = ''
|
||||||
|
try {
|
||||||
|
$path = (Get-ItemProperty -LiteralPath $key -ErrorAction Stop).'(default)'
|
||||||
|
if ($path -and (Test-Path -LiteralPath $path)) {
|
||||||
|
$ver = (Get-Item -LiteralPath $path).VersionInfo.ProductVersion
|
||||||
|
}
|
||||||
|
} catch { $ver = '' }
|
||||||
|
return [pscustomobject]@{ Installed = $true; Version = $ver }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [pscustomobject]@{ Installed = $false; Version = '' }
|
||||||
|
}
|
||||||
|
|
||||||
|
$Script:Browsers = @{
|
||||||
|
'Edge' = Get-BrowserInfo -Exe 'msedge.exe'
|
||||||
|
'Chrome' = Get-BrowserInfo -Exe 'chrome.exe'
|
||||||
|
'Firefox' = Get-BrowserInfo -Exe 'firefox.exe'
|
||||||
|
'Brave' = Get-BrowserInfo -Exe 'brave.exe'
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Registry helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Get-RegValue {
|
||||||
|
param([string]$FullPath, [string]$Name)
|
||||||
|
try {
|
||||||
|
if (-not (Test-Path -LiteralPath $FullPath)) { return $null }
|
||||||
|
$item = Get-ItemProperty -LiteralPath $FullPath -Name $Name -ErrorAction Stop
|
||||||
|
return $item.$Name
|
||||||
|
} catch {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-RegValue {
|
||||||
|
param([string]$FullPath, [string]$Name, $Value, [string]$Type = 'DWord')
|
||||||
|
if (-not (Test-Path -LiteralPath $FullPath)) {
|
||||||
|
New-Item -Path $FullPath -Force | Out-Null
|
||||||
|
}
|
||||||
|
New-ItemProperty -LiteralPath $FullPath -Name $Name -Value $Value -PropertyType $Type -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Remove-RegValue {
|
||||||
|
param([string]$FullPath, [string]$Name)
|
||||||
|
if (Test-Path -LiteralPath $FullPath) {
|
||||||
|
Remove-ItemProperty -LiteralPath $FullPath -Name $Name -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Control model (policy DWORD values under HKLM\SOFTWARE\Policies\...)
|
||||||
|
# All browser policies default to ABSENT, so every control is
|
||||||
|
# remove-on-enable: Enable deletes the value, Disable writes OffValue.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function New-PolicyControl {
|
||||||
|
param(
|
||||||
|
[string]$Name, [string]$Browser, [string]$PolicyPath,
|
||||||
|
[string]$ValueName, [int]$OnValue, [int]$OffValue,
|
||||||
|
[string]$Note = ''
|
||||||
|
)
|
||||||
|
[pscustomobject]@{
|
||||||
|
Type = 'Reg'
|
||||||
|
Name = $Name
|
||||||
|
Category = $Browser
|
||||||
|
Note = $Note
|
||||||
|
FullPath = ('HKLM:\{0}' -f $PolicyPath)
|
||||||
|
ValueName = $ValueName
|
||||||
|
OnValue = $OnValue
|
||||||
|
OffValue = $OffValue
|
||||||
|
AdminReq = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-ControlState {
|
||||||
|
param($Ctrl)
|
||||||
|
$cur = Get-RegValue -FullPath $Ctrl.FullPath -Name $Ctrl.ValueName
|
||||||
|
if ($null -eq $cur) { return 'Enabled (default)' }
|
||||||
|
$curInt = $null
|
||||||
|
try { $curInt = [int]$cur } catch {
|
||||||
|
return ('Enabled (value={0})' -f $cur)
|
||||||
|
}
|
||||||
|
if ($curInt -eq $Ctrl.OffValue) { return 'Disabled' }
|
||||||
|
if ($curInt -eq $Ctrl.OnValue) { return 'Enabled' }
|
||||||
|
return ('Enabled (value={0})' -f $curInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-ControlEnabled {
|
||||||
|
param($Ctrl) # restore browser default: remove the policy value
|
||||||
|
Remove-RegValue -FullPath $Ctrl.FullPath -Name $Ctrl.ValueName
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-ControlDisabled {
|
||||||
|
param($Ctrl) # harden: write the policy value
|
||||||
|
Set-RegValue -FullPath $Ctrl.FullPath -Name $Ctrl.ValueName -Value $Ctrl.OffValue -Type 'DWord'
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Control catalog
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Get-Controls {
|
||||||
|
$c = New-Object System.Collections.ArrayList
|
||||||
|
$edge = 'SOFTWARE\Policies\Microsoft\Edge'
|
||||||
|
$chr = 'SOFTWARE\Policies\Google\Chrome'
|
||||||
|
$ffx = 'SOFTWARE\Policies\Mozilla\Firefox'
|
||||||
|
$brv = 'SOFTWARE\Policies\BraveSoftware\Brave'
|
||||||
|
|
||||||
|
# =========================== Microsoft Edge ===========================
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Diagnostic Data' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'DiagnosticData' -OnValue 2 -OffValue 0 `
|
||||||
|
-Note '0=off 1=required 2=optional') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Personalization Reporting' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'PersonalizationReportingEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Browsing history used for ads/news personalization') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'User Feedback' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'UserFeedbackAllowed' -OnValue 1 -OffValue 0) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Search Suggestions' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'SearchSuggestEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Sends keystrokes to search provider') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Bing Provider in Address Bar' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'AddressBarMicrosoftSearchInBingProviderEnabled' -OnValue 1 -OffValue 0) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Shopping Assistant' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'EdgeShoppingAssistantEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Coupons/price comparison; shares browsing data') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Microsoft Rewards' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'ShowMicrosoftRewards' -OnValue 1 -OffValue 0) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Web Widget (search bar)' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'WebWidgetAllowed' -OnValue 1 -OffValue 0) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Spotlight Recommendations' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'SpotlightExperiencesAndRecommendationsEnabled' -OnValue 1 -OffValue 0) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Do Not Track OFF' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'ConfigureDoNotTrack' -OnValue 0 -OffValue 1 `
|
||||||
|
-Note 'Disabled = DNT header IS sent (hardened)') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Nav Error Web Service' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'ResolveNavigationErrorsUseWebService' -OnValue 1 -OffValue 0) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Alternate Error Pages' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'AlternateErrorPagesEnabled' -OnValue 1 -OffValue 0) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Network Prediction (prefetch)' -Browser Edge -PolicyPath $edge `
|
||||||
|
-ValueName 'NetworkPredictionOptions' -OnValue 0 -OffValue 2 `
|
||||||
|
-Note '0=predict always 2=never') )
|
||||||
|
|
||||||
|
# =========================== Google Chrome ============================
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Metrics Reporting (UMA)' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'MetricsReportingEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Usage statistics and crash reports to Google') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Search Suggestions' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'SearchSuggestEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Sends keystrokes to search provider') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Safe Browsing Ext. Reporting' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'SafeBrowsingExtendedReportingEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Extra page/system data to Google; SB itself stays on') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'URL-keyed Data Collection' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'UrlKeyedAnonymizedDataCollectionEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'URLs of visited pages sent to Google') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Cloud Spell Check' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'SpellCheckServiceEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Typed text sent to Google web service') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Alternate Error Pages' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'AlternateErrorPagesEnabled' -OnValue 1 -OffValue 0) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Network Prediction (prefetch)' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'NetworkPredictionOptions' -OnValue 0 -OffValue 2 `
|
||||||
|
-Note '0=predict always 2=never') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Feedback Surveys' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'FeedbackSurveysEnabled' -OnValue 1 -OffValue 0) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Privacy Sandbox Prompt' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'PrivacySandboxPromptEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Must be Disabled for the three policies below') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Privacy Sandbox: Ad Topics' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'PrivacySandboxAdTopicsEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Interest-based advertising (Topics API)') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Privacy Sandbox: Site Ads' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'PrivacySandboxSiteEnabledAdsEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Site-suggested ads (Protected Audience)') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Privacy Sandbox: Ad Measure' -Browser Chrome -PolicyPath $chr `
|
||||||
|
-ValueName 'PrivacySandboxAdMeasurementEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Attribution / ad measurement API') )
|
||||||
|
|
||||||
|
# =========================== Mozilla Firefox ==========================
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Telemetry' -Browser Firefox -PolicyPath $ffx `
|
||||||
|
-ValueName 'DisableTelemetry' -OnValue 0 -OffValue 1 `
|
||||||
|
-Note 'Usage and technical data to Mozilla') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Firefox Studies (Shield)' -Browser Firefox -PolicyPath $ffx `
|
||||||
|
-ValueName 'DisableFirefoxStudies' -OnValue 0 -OffValue 1 `
|
||||||
|
-Note 'Remote experiments / preference rollouts') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Default Browser Agent' -Browser Firefox -PolicyPath $ffx `
|
||||||
|
-ValueName 'DisableDefaultBrowserAgent' -OnValue 0 -OffValue 1 `
|
||||||
|
-Note 'Scheduled task that pings Mozilla daily') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Pocket Integration' -Browser Firefox -PolicyPath $ffx `
|
||||||
|
-ValueName 'DisablePocket' -OnValue 0 -OffValue 1 `
|
||||||
|
-Note 'Sponsored stories / recommendations') )
|
||||||
|
|
||||||
|
# =============================== Brave ================================
|
||||||
|
# Brave sends little telemetry by default; these harden its bundled
|
||||||
|
# feature surface area (each phones home to Brave services).
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Brave Rewards' -Browser Brave -PolicyPath $brv `
|
||||||
|
-ValueName 'BraveRewardsDisabled' -OnValue 0 -OffValue 1) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Brave Wallet' -Browser Brave -PolicyPath $brv `
|
||||||
|
-ValueName 'BraveWalletDisabled' -OnValue 0 -OffValue 1) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Brave VPN' -Browser Brave -PolicyPath $brv `
|
||||||
|
-ValueName 'BraveVPNDisabled' -OnValue 0 -OffValue 1) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Tor Windows' -Browser Brave -PolicyPath $brv `
|
||||||
|
-ValueName 'TorDisabled' -OnValue 0 -OffValue 1 `
|
||||||
|
-Note 'Private windows with Tor') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-PolicyControl -Name 'Search Suggestions' -Browser Brave -PolicyPath $brv `
|
||||||
|
-ValueName 'SearchSuggestEnabled' -OnValue 1 -OffValue 0 `
|
||||||
|
-Note 'Chromium policy honoured by Brave') )
|
||||||
|
|
||||||
|
# Filter to installed browsers unless -IncludeAll
|
||||||
|
if ($IncludeAll) { return $c }
|
||||||
|
$filtered = New-Object System.Collections.ArrayList
|
||||||
|
foreach ($ctrl in $c) {
|
||||||
|
if ($Script:Browsers[$ctrl.Category].Installed) { [void]$filtered.Add($ctrl) }
|
||||||
|
}
|
||||||
|
return $filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Display
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Get-StateColor {
|
||||||
|
param([string]$State)
|
||||||
|
if ($State -like 'Disabled*') { return 'Green' }
|
||||||
|
if ($State -like 'Enabled*') { return 'Yellow' }
|
||||||
|
return 'Gray'
|
||||||
|
}
|
||||||
|
|
||||||
|
function Show-Status {
|
||||||
|
param($Controls)
|
||||||
|
|
||||||
|
Write-Host ''
|
||||||
|
Write-Host '==================================================================' -ForegroundColor Cyan
|
||||||
|
Write-Host ' Browser Privacy / Telemetry Status' -ForegroundColor Cyan
|
||||||
|
Write-Host (' Host: {0} Admin: {1} {2}' -f $env:COMPUTERNAME, $Script:IsAdmin, (Get-Date)) -ForegroundColor DarkCyan
|
||||||
|
$det = @()
|
||||||
|
foreach ($b in @('Edge','Chrome','Firefox','Brave')) {
|
||||||
|
$info = $Script:Browsers[$b]
|
||||||
|
if ($info.Installed) {
|
||||||
|
if ($info.Version) { $det += ('{0} {1}' -f $b, $info.Version) }
|
||||||
|
else { $det += $b }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($det.Count -eq 0) { $det = @('none detected') }
|
||||||
|
Write-Host (' Browsers: {0}' -f ($det -join ', ')) -ForegroundColor DarkCyan
|
||||||
|
Write-Host ' Enabled = collecting/on Disabled = hardened/off' -ForegroundColor DarkCyan
|
||||||
|
Write-Host '==================================================================' -ForegroundColor Cyan
|
||||||
|
Write-Host ('{0,-4}{1,-32}{2,-10}{3}' -f '#', 'Setting', 'Browser', 'State') -ForegroundColor White
|
||||||
|
Write-Host ('{0,-4}{1,-32}{2,-10}{3}' -f '---', '-------', '-------', '-----') -ForegroundColor DarkGray
|
||||||
|
|
||||||
|
$i = 0
|
||||||
|
$nEnabled = 0; $nDisabled = 0
|
||||||
|
foreach ($ctrl in $Controls) {
|
||||||
|
$i++
|
||||||
|
$state = Get-ControlState -Ctrl $ctrl
|
||||||
|
if ($state -like 'Enabled*') { $nEnabled++ }
|
||||||
|
elseif ($state -like 'Disabled*') { $nDisabled++ }
|
||||||
|
$lock = ''
|
||||||
|
if ($ctrl.AdminReq -and -not $Script:IsAdmin) { $lock = ' *' }
|
||||||
|
$flag = ''
|
||||||
|
if (-not $Script:Browsers[$ctrl.Category].Installed) { $flag = ' (not installed)' }
|
||||||
|
$line = ('{0,-4}{1,-32}{2,-10}' -f $i, $ctrl.Name, $ctrl.Category)
|
||||||
|
Write-Host $line -NoNewline
|
||||||
|
Write-Host ($state + $lock + $flag) -ForegroundColor (Get-StateColor $state)
|
||||||
|
}
|
||||||
|
Write-Host ('{0,-4}{1,-32}{2,-10}{3}' -f '---', '-------', '-------', '-----') -ForegroundColor DarkGray
|
||||||
|
Write-Host (' Summary: {0} enabled, {1} disabled' -f $nEnabled, $nDisabled) -ForegroundColor White
|
||||||
|
Write-Host ' Policies apply on next browser start. While hardened, browsers' -ForegroundColor DarkCyan
|
||||||
|
Write-Host ' show a "managed" notice on settings pages - that is expected.' -ForegroundColor DarkCyan
|
||||||
|
if (-not $Script:IsAdmin) {
|
||||||
|
Write-Host ' * requires Administrator to change (run elevated)' -ForegroundColor DarkYellow
|
||||||
|
}
|
||||||
|
Write-Host ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function Export-StatusCsv {
|
||||||
|
param($Controls, [string]$Path)
|
||||||
|
$rows = foreach ($ctrl in $Controls) {
|
||||||
|
[pscustomobject]@{
|
||||||
|
Name = $ctrl.Name
|
||||||
|
Browser = $ctrl.Category
|
||||||
|
Installed = $Script:Browsers[$ctrl.Category].Installed
|
||||||
|
Policy = $ctrl.ValueName
|
||||||
|
State = (Get-ControlState -Ctrl $ctrl)
|
||||||
|
Note = $ctrl.Note
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rows | Export-Csv -Path $Path -NoTypeInformation -Encoding ASCII
|
||||||
|
Write-Host ("Status written to {0}" -f $Path) -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Apply helpers with guard rails
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Invoke-ControlAction {
|
||||||
|
param($Ctrl, [ValidateSet('Enable','Disable')][string]$Action)
|
||||||
|
|
||||||
|
if ($Ctrl.AdminReq -and -not $Script:IsAdmin) {
|
||||||
|
Write-Host (" SKIP {0}/{1} (needs Administrator)" -f $Ctrl.Category, $Ctrl.Name) -ForegroundColor DarkYellow
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if ($Action -eq 'Enable') { Set-ControlEnabled -Ctrl $Ctrl }
|
||||||
|
else { Set-ControlDisabled -Ctrl $Ctrl }
|
||||||
|
$new = Get-ControlState -Ctrl $Ctrl
|
||||||
|
Write-Host (" OK {0}/{1} -> {2}" -f $Ctrl.Category, $Ctrl.Name, $new) -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Host (" FAIL {0}/{1}: {2}" -f $Ctrl.Category, $Ctrl.Name, $_.Exception.Message) -ForegroundColor Red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-AllAction {
|
||||||
|
param($Controls, [ValidateSet('Enable','Disable')][string]$Action)
|
||||||
|
$verb = if ($Action -eq 'Enable') { 'ENABLE (restore browser defaults)' } else { 'DISABLE (harden)' }
|
||||||
|
Write-Host ''
|
||||||
|
Write-Host ("Applying {0} to ALL items..." -f $verb) -ForegroundColor Cyan
|
||||||
|
foreach ($ctrl in $Controls) { Invoke-ControlAction -Ctrl $ctrl -Action $Action }
|
||||||
|
Write-Host ''
|
||||||
|
Write-Host 'Restart the affected browsers for policies to take effect.' -ForegroundColor Cyan
|
||||||
|
Write-Host ''
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Interactive menu
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Start-Menu {
|
||||||
|
param($Controls)
|
||||||
|
while ($true) {
|
||||||
|
Show-Status -Controls $Controls
|
||||||
|
Write-Host 'Commands:' -ForegroundColor White
|
||||||
|
Write-Host ' <n> toggle item n (Enable<->Disable)'
|
||||||
|
Write-Host ' e <n> enable item n'
|
||||||
|
Write-Host ' d <n> disable item n'
|
||||||
|
Write-Host ' D disable ALL (harden)'
|
||||||
|
Write-Host ' E enable ALL (restore browser defaults)'
|
||||||
|
Write-Host ' b <name> apply D to one browser (e.g. b Edge)'
|
||||||
|
Write-Host ' r refresh view'
|
||||||
|
Write-Host ' c <path> export status to CSV'
|
||||||
|
Write-Host ' q quit'
|
||||||
|
Write-Host ''
|
||||||
|
$inp = Read-Host 'Select'
|
||||||
|
if ([string]::IsNullOrWhiteSpace($inp)) { continue }
|
||||||
|
$inp = $inp.Trim()
|
||||||
|
|
||||||
|
# -CaseSensitive so bare "d"/"e" do NOT match the ALL branches below
|
||||||
|
switch -Regex -CaseSensitive ($inp) {
|
||||||
|
'^[Qq]$' { return }
|
||||||
|
'^[Rr]$' { continue }
|
||||||
|
'^D$' {
|
||||||
|
if ((Read-Host 'Harden ALL browser settings? type YES') -ceq 'YES') {
|
||||||
|
Invoke-AllAction -Controls $Controls -Action Disable
|
||||||
|
}
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^E$' {
|
||||||
|
if ((Read-Host 'Restore ALL browser defaults? type YES') -ceq 'YES') {
|
||||||
|
Invoke-AllAction -Controls $Controls -Action Enable
|
||||||
|
}
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^[Bb]\s+(\w+)$' {
|
||||||
|
$target = $Matches[1]
|
||||||
|
$subset = @($Controls | Where-Object { $_.Category -eq $target })
|
||||||
|
if ($subset.Count -eq 0) {
|
||||||
|
Write-Host ('No controls for browser "{0}" (use Edge/Chrome/Firefox/Brave)' -f $target) -ForegroundColor Red
|
||||||
|
} elseif ((Read-Host ('Harden all {0} settings? type YES' -f $target)) -ceq 'YES') {
|
||||||
|
Invoke-AllAction -Controls $subset -Action Disable
|
||||||
|
}
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^[Cc]\s+(.+)$' {
|
||||||
|
Export-StatusCsv -Controls $Controls -Path $Matches[1].Trim('"')
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^[Ee]\s+(\d+)$' {
|
||||||
|
$n = [int]$Matches[1]
|
||||||
|
if ($n -ge 1 -and $n -le $Controls.Count) { Invoke-ControlAction -Ctrl $Controls[$n-1] -Action Enable }
|
||||||
|
else { Write-Host 'Out of range' -ForegroundColor Red }
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^[Dd]\s+(\d+)$' {
|
||||||
|
$n = [int]$Matches[1]
|
||||||
|
if ($n -ge 1 -and $n -le $Controls.Count) { Invoke-ControlAction -Ctrl $Controls[$n-1] -Action Disable }
|
||||||
|
else { Write-Host 'Out of range' -ForegroundColor Red }
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^\d+$' {
|
||||||
|
$n = [int]$inp
|
||||||
|
if ($n -ge 1 -and $n -le $Controls.Count) {
|
||||||
|
$ctrl = $Controls[$n-1]
|
||||||
|
$state = Get-ControlState -Ctrl $ctrl
|
||||||
|
if ($state -like 'Enabled*') { Invoke-ControlAction -Ctrl $ctrl -Action Disable }
|
||||||
|
else { Invoke-ControlAction -Ctrl $ctrl -Action Enable }
|
||||||
|
} else { Write-Host 'Out of range' -ForegroundColor Red }
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
default { Write-Host 'Unknown command (d/e need an item number; D/E alone mean ALL)' -ForegroundColor Red; Start-Sleep -Milliseconds 600 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Main
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
$controls = Get-Controls
|
||||||
|
|
||||||
|
if (@($controls).Count -eq 0) {
|
||||||
|
Write-Host 'No supported browsers detected (Edge/Chrome/Firefox/Brave).' -ForegroundColor Red
|
||||||
|
Write-Host 'Use -IncludeAll to manage policies for browsers not yet installed.' -ForegroundColor DarkYellow
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($DisableAll) {
|
||||||
|
Invoke-AllAction -Controls $controls -Action Disable
|
||||||
|
Show-Status -Controls $controls
|
||||||
|
if ($Csv) { Export-StatusCsv -Controls $controls -Path $Csv }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($EnableAll) {
|
||||||
|
Invoke-AllAction -Controls $controls -Action Enable
|
||||||
|
Show-Status -Controls $controls
|
||||||
|
if ($Csv) { Export-StatusCsv -Controls $controls -Path $Csv }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($Report -or $Csv) {
|
||||||
|
if ($Report) { Show-Status -Controls $controls }
|
||||||
|
if ($Csv) { Export-StatusCsv -Controls $controls -Path $Csv }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $Script:IsAdmin) {
|
||||||
|
Write-Host ''
|
||||||
|
Write-Host 'NOTE: Not running as Administrator. Policy values live in HKLM,' -ForegroundColor DarkYellow
|
||||||
|
Write-Host ' so nothing can be changed until you relaunch this script' -ForegroundColor DarkYellow
|
||||||
|
Write-Host ' in an elevated PowerShell window. Viewing works fine.' -ForegroundColor DarkYellow
|
||||||
|
}
|
||||||
|
|
||||||
|
Start-Menu -Controls $controls
|
||||||
@@ -0,0 +1,611 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<#
|
||||||
|
Manage-WindowsTelemetry.ps1
|
||||||
|
|
||||||
|
Purpose : View and control common Windows 11 telemetry / diagnostic-data
|
||||||
|
settings, services and scheduled tasks.
|
||||||
|
|
||||||
|
Scope : Shows what is currently ENABLED (data collecting) vs DISABLED,
|
||||||
|
and lets the user turn individual items - or everything - on/off.
|
||||||
|
|
||||||
|
Areas : Core diagnostic data (AllowTelemetry), diagnostic log limits,
|
||||||
|
Windows Error Reporting (full stack: flags, consent, service,
|
||||||
|
task - the modern successor to Dr. Watson), CEIP/SQM, AppCompat
|
||||||
|
appraiser, Cloud Content / Tailored Experiences, Activity
|
||||||
|
History, Advertising ID, Feedback (SIUF), inking/typing and
|
||||||
|
speech data, search suggestions, DiagTrack + related services,
|
||||||
|
and telemetry scheduled tasks.
|
||||||
|
|
||||||
|
Notes : - Windows PowerShell 5.1 compatible. ASCII-only source.
|
||||||
|
- Registry (HKLM) and service changes require Administrator.
|
||||||
|
- "Enabled" = the telemetry / data-collection behaviour is ON.
|
||||||
|
"Disabled" = the telemetry / data-collection behaviour is OFF.
|
||||||
|
- For policy-type values, "Enable" REMOVES the policy value to
|
||||||
|
restore the true Windows default (absent), so the Settings UI
|
||||||
|
is not left in a "managed by your organization" state.
|
||||||
|
|
||||||
|
Usage :
|
||||||
|
.\Manage-WindowsTelemetry.ps1 # interactive menu
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -Report # print status and exit
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -DisableAll # turn telemetry OFF
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -EnableAll # restore Windows default ON
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -Csv .\out.csv # export status and exit
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -Report -Csv .\status.csv
|
||||||
|
|
||||||
|
DISCLAIMER: Review before use. Changing telemetry / service settings alters
|
||||||
|
system behaviour. Run in a test environment first. No warranty.
|
||||||
|
#>
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[switch]$Report,
|
||||||
|
[switch]$DisableAll,
|
||||||
|
[switch]$EnableAll,
|
||||||
|
[string]$Csv
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-StrictMode -Version 2.0
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Elevation helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Test-IsAdmin {
|
||||||
|
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
|
$pr = New-Object Security.Principal.WindowsPrincipal($id)
|
||||||
|
return $pr.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
|
}
|
||||||
|
|
||||||
|
$Script:IsAdmin = Test-IsAdmin
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Registry helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Resolve-RegPath {
|
||||||
|
param([string]$Hive, [string]$Path)
|
||||||
|
return ('{0}:\{1}' -f $Hive, $Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RegValue {
|
||||||
|
param([string]$FullPath, [string]$Name)
|
||||||
|
try {
|
||||||
|
if (-not (Test-Path -LiteralPath $FullPath)) { return $null }
|
||||||
|
$item = Get-ItemProperty -LiteralPath $FullPath -Name $Name -ErrorAction Stop
|
||||||
|
return $item.$Name
|
||||||
|
} catch {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-RegValue {
|
||||||
|
param([string]$FullPath, [string]$Name, $Value, [string]$Type = 'DWord')
|
||||||
|
if (-not (Test-Path -LiteralPath $FullPath)) {
|
||||||
|
New-Item -Path $FullPath -Force | Out-Null
|
||||||
|
}
|
||||||
|
New-ItemProperty -LiteralPath $FullPath -Name $Name -Value $Value -PropertyType $Type -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Remove-RegValue {
|
||||||
|
param([string]$FullPath, [string]$Name)
|
||||||
|
if (Test-Path -LiteralPath $FullPath) {
|
||||||
|
Remove-ItemProperty -LiteralPath $FullPath -Name $Name -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Control model
|
||||||
|
# Each control is a PSCustomObject with a Type that drives Get/Enable/Disable.
|
||||||
|
# Types: Reg, Service, Task
|
||||||
|
#
|
||||||
|
# RemoveOnEnable: for policy-style values whose Windows default is ABSENT.
|
||||||
|
# Enabling such a control deletes the value instead of writing OnValue, so
|
||||||
|
# the machine is not left policy-managed after an "enable".
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function New-RegControl {
|
||||||
|
param(
|
||||||
|
[string]$Name, [string]$Category, [string]$Hive, [string]$Path,
|
||||||
|
[string]$ValueName, [int]$OnValue, [int]$OffValue,
|
||||||
|
[ValidateSet('On','Off')][string]$Default = 'On',
|
||||||
|
[string]$RegType = 'DWord', [string]$Note = '',
|
||||||
|
[switch]$RemoveOnEnable
|
||||||
|
)
|
||||||
|
[pscustomobject]@{
|
||||||
|
Type = 'Reg'
|
||||||
|
Name = $Name
|
||||||
|
Category = $Category
|
||||||
|
Note = $Note
|
||||||
|
FullPath = (Resolve-RegPath -Hive $Hive -Path $Path)
|
||||||
|
ValueName = $ValueName
|
||||||
|
OnValue = $OnValue
|
||||||
|
OffValue = $OffValue
|
||||||
|
Default = $Default
|
||||||
|
RegType = $RegType
|
||||||
|
RemoveOnEnable = [bool]$RemoveOnEnable
|
||||||
|
AdminReq = ($Hive -eq 'HKLM')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function New-ServiceControl {
|
||||||
|
param(
|
||||||
|
[string]$Name, [string]$ServiceName,
|
||||||
|
[ValidateSet('Automatic','Manual')][string]$DefaultStartupType = 'Automatic',
|
||||||
|
[string]$Note = ''
|
||||||
|
)
|
||||||
|
[pscustomobject]@{
|
||||||
|
Type = 'Service'
|
||||||
|
Name = $Name
|
||||||
|
Category = 'Service'
|
||||||
|
Note = $Note
|
||||||
|
ServiceName = $ServiceName
|
||||||
|
DefaultStartupType = $DefaultStartupType
|
||||||
|
AdminReq = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function New-TaskControl {
|
||||||
|
param([string]$Name, [string[]]$Tasks, [string]$Note = '')
|
||||||
|
# $Tasks entries are full task paths, e.g. \Microsoft\Windows\Application Experience\ProgramDataUpdater
|
||||||
|
[pscustomobject]@{
|
||||||
|
Type = 'Task'
|
||||||
|
Name = $Name
|
||||||
|
Category = 'Scheduled Task'
|
||||||
|
Note = $Note
|
||||||
|
Tasks = $Tasks
|
||||||
|
AdminReq = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# State + actions
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Get-ControlState {
|
||||||
|
param($Ctrl)
|
||||||
|
switch ($Ctrl.Type) {
|
||||||
|
'Reg' {
|
||||||
|
$cur = Get-RegValue -FullPath $Ctrl.FullPath -Name $Ctrl.ValueName
|
||||||
|
if ($null -eq $cur) {
|
||||||
|
if ($Ctrl.Default -eq 'On') { return 'Enabled (default)' }
|
||||||
|
else { return 'Disabled (default)' }
|
||||||
|
}
|
||||||
|
$curInt = $null
|
||||||
|
try { $curInt = [int]$cur } catch {
|
||||||
|
return ('Enabled (value={0})' -f $cur) # non-numeric data: report, do not throw
|
||||||
|
}
|
||||||
|
if ($curInt -eq $Ctrl.OffValue) { return 'Disabled' }
|
||||||
|
if ($curInt -eq $Ctrl.OnValue) { return 'Enabled' }
|
||||||
|
return ('Enabled (value={0})' -f $curInt)
|
||||||
|
}
|
||||||
|
'Service' {
|
||||||
|
$svc = Get-Service -Name $Ctrl.ServiceName -ErrorAction SilentlyContinue
|
||||||
|
if ($null -eq $svc) { return 'Not present' }
|
||||||
|
if ($svc.StartType -eq 'Disabled') { return 'Disabled' }
|
||||||
|
return ('Enabled ({0}, {1})' -f $svc.StartType, $svc.Status)
|
||||||
|
}
|
||||||
|
'Task' {
|
||||||
|
$states = @()
|
||||||
|
foreach ($t in $Ctrl.Tasks) {
|
||||||
|
$leaf = Split-Path $t -Leaf
|
||||||
|
$path = (Split-Path $t -Parent) + '\'
|
||||||
|
$task = Get-ScheduledTask -TaskName $leaf -TaskPath $path -ErrorAction SilentlyContinue
|
||||||
|
if ($task) { $states += $task.State }
|
||||||
|
}
|
||||||
|
if ($states.Count -eq 0) { return 'Not present' }
|
||||||
|
if ($states -contains 'Ready' -or $states -contains 'Running') { return 'Enabled' }
|
||||||
|
return 'Disabled'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'Unknown'
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-ControlEnabled {
|
||||||
|
param($Ctrl) # Enable telemetry (restore Windows default behaviour)
|
||||||
|
switch ($Ctrl.Type) {
|
||||||
|
'Reg' {
|
||||||
|
if ($Ctrl.RemoveOnEnable) {
|
||||||
|
Remove-RegValue -FullPath $Ctrl.FullPath -Name $Ctrl.ValueName
|
||||||
|
} else {
|
||||||
|
Set-RegValue -FullPath $Ctrl.FullPath -Name $Ctrl.ValueName -Value $Ctrl.OnValue -Type $Ctrl.RegType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'Service' {
|
||||||
|
Set-Service -Name $Ctrl.ServiceName -StartupType $Ctrl.DefaultStartupType -ErrorAction Stop
|
||||||
|
if ($Ctrl.DefaultStartupType -eq 'Automatic') {
|
||||||
|
Start-Service -Name $Ctrl.ServiceName -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'Task' {
|
||||||
|
foreach ($t in $Ctrl.Tasks) {
|
||||||
|
$leaf = Split-Path $t -Leaf
|
||||||
|
$path = (Split-Path $t -Parent) + '\'
|
||||||
|
Enable-ScheduledTask -TaskName $leaf -TaskPath $path -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-ControlDisabled {
|
||||||
|
param($Ctrl) # Disable telemetry (privacy hardened)
|
||||||
|
switch ($Ctrl.Type) {
|
||||||
|
'Reg' {
|
||||||
|
Set-RegValue -FullPath $Ctrl.FullPath -Name $Ctrl.ValueName -Value $Ctrl.OffValue -Type $Ctrl.RegType
|
||||||
|
}
|
||||||
|
'Service' {
|
||||||
|
Stop-Service -Name $Ctrl.ServiceName -Force -ErrorAction SilentlyContinue
|
||||||
|
Set-Service -Name $Ctrl.ServiceName -StartupType Disabled -ErrorAction Stop
|
||||||
|
}
|
||||||
|
'Task' {
|
||||||
|
foreach ($t in $Ctrl.Tasks) {
|
||||||
|
$leaf = Split-Path $t -Leaf
|
||||||
|
$path = (Split-Path $t -Parent) + '\'
|
||||||
|
Disable-ScheduledTask -TaskName $leaf -TaskPath $path -ErrorAction SilentlyContinue | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Control catalog
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Get-Controls {
|
||||||
|
$c = New-Object System.Collections.ArrayList
|
||||||
|
|
||||||
|
# --- Core telemetry policy ---
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Diagnostic data (AllowTelemetry)' -Category 'Telemetry' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\DataCollection' `
|
||||||
|
-ValueName 'AllowTelemetry' -OnValue 3 -OffValue 0 -Default On -RemoveOnEnable `
|
||||||
|
-Note '0=Off/Security 1=Required 3=Optional. Home/Pro treat 0 as 1.') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Diagnostic data (non-policy)' -Category 'Telemetry' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection' `
|
||||||
|
-ValueName 'AllowTelemetry' -OnValue 3 -OffValue 0 -Default On -RemoveOnEnable) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Feedback Notifications' -Category 'Telemetry' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\DataCollection' `
|
||||||
|
-ValueName 'DoNotShowFeedbackNotifications' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable `
|
||||||
|
-Note 'Disabled hides feedback prompts') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Diagnostic Log Collection' -Category 'Telemetry' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\DataCollection' `
|
||||||
|
-ValueName 'LimitDiagnosticLogCollection' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable `
|
||||||
|
-Note 'Disabled blocks extra diagnostic log upload') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'OneSettings Downloads' -Category 'Telemetry' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\DataCollection' `
|
||||||
|
-ValueName 'DisableOneSettingsDownloads' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable `
|
||||||
|
-Note 'Remote telemetry configuration channel') )
|
||||||
|
|
||||||
|
# --- Application compatibility / appraiser telemetry ---
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'App Impact Telemetry (AITEnable)' -Category 'AppCompat' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\AppCompat' `
|
||||||
|
-ValueName 'AITEnable' -OnValue 1 -OffValue 0 -Default On -RemoveOnEnable) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Inventory Collector' -Category 'AppCompat' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\AppCompat' `
|
||||||
|
-ValueName 'DisableInventory' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable) )
|
||||||
|
|
||||||
|
# --- Windows Error Reporting (successor to Dr. Watson) ---
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Windows Error Reporting' -Category 'Error Reporting' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Microsoft\Windows\Windows Error Reporting' `
|
||||||
|
-ValueName 'Disabled' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Error Reporting (policy)' -Category 'Error Reporting' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\Windows Error Reporting' `
|
||||||
|
-ValueName 'Disabled' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable `
|
||||||
|
-Note 'Group Policy variant; overrides the non-policy flag') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'WER Additional Data' -Category 'Error Reporting' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\Windows Error Reporting' `
|
||||||
|
-ValueName 'DontSendAdditionalData' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable `
|
||||||
|
-Note 'Disabled stops second-stage crash data upload') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'WER Consent Level' -Category 'Error Reporting' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Microsoft\Windows\Windows Error Reporting\Consent' `
|
||||||
|
-ValueName 'DefaultConsent' -OnValue 4 -OffValue 1 -Default On -RemoveOnEnable `
|
||||||
|
-Note '1=always ask 2=params 3=params+safe 4=send all') )
|
||||||
|
|
||||||
|
# --- Customer Experience Improvement Program ---
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'CEIP (SQM Client)' -Category 'CEIP' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Microsoft\SQMClient\Windows' `
|
||||||
|
-ValueName 'CEIPEnable' -OnValue 1 -OffValue 0 -Default On) )
|
||||||
|
|
||||||
|
# --- Cloud content / consumer features / ads ---
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Windows Consumer Features' -Category 'Cloud Content' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\CloudContent' `
|
||||||
|
-ValueName 'DisableWindowsConsumerFeatures' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Tailored Experiences (policy)' -Category 'Cloud Content' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\CloudContent' `
|
||||||
|
-ValueName 'DisableTailoredExperiencesWithDiagnosticData' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable) )
|
||||||
|
|
||||||
|
# --- Activity history / timeline ---
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Publish User Activities' -Category 'Activity History' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\System' `
|
||||||
|
-ValueName 'PublishUserActivities' -OnValue 1 -OffValue 0 -Default On -RemoveOnEnable) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Upload User Activities' -Category 'Activity History' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\System' `
|
||||||
|
-ValueName 'UploadUserActivities' -OnValue 1 -OffValue 0 -Default On -RemoveOnEnable) )
|
||||||
|
|
||||||
|
# --- Per-user privacy (HKCU, no admin needed) ---
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Advertising ID' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKCU -Path 'SOFTWARE\Microsoft\Windows\CurrentVersion\AdvertisingInfo' `
|
||||||
|
-ValueName 'Enabled' -OnValue 1 -OffValue 0 -Default On) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Tailored Experiences (user)' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKCU -Path 'SOFTWARE\Microsoft\Windows\CurrentVersion\Privacy' `
|
||||||
|
-ValueName 'TailoredExperiencesWithDiagnosticDataEnabled' -OnValue 1 -OffValue 0 -Default On) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Feedback Frequency (SIUF)' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKCU -Path 'SOFTWARE\Microsoft\Siuf\Rules' `
|
||||||
|
-ValueName 'NumberOfSIUFInPeriod' -OnValue 1 -OffValue 0 -Default On -RemoveOnEnable `
|
||||||
|
-Note 'Disabled = never asked for feedback') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Implicit Ink Collection' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKCU -Path 'SOFTWARE\Microsoft\InputPersonalization' `
|
||||||
|
-ValueName 'RestrictImplicitInkCollection' -OnValue 0 -OffValue 1 -Default On `
|
||||||
|
-Note 'Inking personalization data') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Implicit Text Collection' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKCU -Path 'SOFTWARE\Microsoft\InputPersonalization' `
|
||||||
|
-ValueName 'RestrictImplicitTextCollection' -OnValue 0 -OffValue 1 -Default On `
|
||||||
|
-Note 'Typing personalization data') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Typing Insights (TIPC)' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKCU -Path 'SOFTWARE\Microsoft\Input\TIPC' `
|
||||||
|
-ValueName 'Enabled' -OnValue 1 -OffValue 0 -Default On `
|
||||||
|
-Note 'Typing/ink telemetry channel') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Online Speech Recognition' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKCU -Path 'SOFTWARE\Microsoft\Speech_OneCore\Settings\OnlineSpeechPrivacy' `
|
||||||
|
-ValueName 'HasAccepted' -OnValue 1 -OffValue 0 -Default Off `
|
||||||
|
-Note 'Cloud speech; default off until user consents') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Linguistic Data Collection' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKLM -Path 'SOFTWARE\Policies\Microsoft\Windows\TextInput' `
|
||||||
|
-ValueName 'AllowLinguisticDataCollection' -OnValue 1 -OffValue 0 -Default On -RemoveOnEnable) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Search Box Web Suggestions' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKCU -Path 'SOFTWARE\Policies\Microsoft\Windows\Explorer' `
|
||||||
|
-ValueName 'DisableSearchBoxSuggestions' -OnValue 0 -OffValue 1 -Default On -RemoveOnEnable `
|
||||||
|
-Note 'Win11 control for web results in Search') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-RegControl -Name 'Bing Search (legacy)' -Category 'Privacy (User)' `
|
||||||
|
-Hive HKCU -Path 'SOFTWARE\Microsoft\Windows\CurrentVersion\Search' `
|
||||||
|
-ValueName 'BingSearchEnabled' -OnValue 1 -OffValue 0 -Default On -RemoveOnEnable `
|
||||||
|
-Note 'Win10-era value; largely ignored on Win11') )
|
||||||
|
|
||||||
|
# --- Services ---
|
||||||
|
[void]$c.Add( (New-ServiceControl -Name 'Connected User Experiences' `
|
||||||
|
-ServiceName 'DiagTrack' -DefaultStartupType Automatic `
|
||||||
|
-Note 'DiagTrack - primary telemetry service') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-ServiceControl -Name 'WAP Push Routing (dmwappush)' `
|
||||||
|
-ServiceName 'dmwappushservice' -DefaultStartupType Manual `
|
||||||
|
-Note 'Disabling can break provisioning package / MDM enrolment') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-ServiceControl -Name 'Error Reporting Svc (WerSvc)' `
|
||||||
|
-ServiceName 'WerSvc' -DefaultStartupType Manual `
|
||||||
|
-Note 'Runs WER report submission') )
|
||||||
|
|
||||||
|
# --- Scheduled tasks ---
|
||||||
|
[void]$c.Add( (New-TaskControl -Name 'Compatibility Appraiser tasks' -Tasks @(
|
||||||
|
'\Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser',
|
||||||
|
'\Microsoft\Windows\Application Experience\ProgramDataUpdater',
|
||||||
|
'\Microsoft\Windows\Application Experience\StartupAppTask'
|
||||||
|
)) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-TaskControl -Name 'CEIP tasks' -Tasks @(
|
||||||
|
'\Microsoft\Windows\Customer Experience Improvement Program\Consolidator',
|
||||||
|
'\Microsoft\Windows\Customer Experience Improvement Program\UsbCeip',
|
||||||
|
'\Microsoft\Windows\Autochk\Proxy'
|
||||||
|
) -Note 'Includes Autochk\Proxy (kernel CEIP)') )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-TaskControl -Name 'Feedback (SIUF) tasks' -Tasks @(
|
||||||
|
'\Microsoft\Windows\Feedback\Siuf\DmClient',
|
||||||
|
'\Microsoft\Windows\Feedback\Siuf\DmClientOnScenarioDownload'
|
||||||
|
)) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-TaskControl -Name 'Error Reporting task' -Tasks @(
|
||||||
|
'\Microsoft\Windows\Windows Error Reporting\QueueReporting'
|
||||||
|
)) )
|
||||||
|
|
||||||
|
[void]$c.Add( (New-TaskControl -Name 'Disk Diagnostic collector' -Tasks @(
|
||||||
|
'\Microsoft\Windows\DiskDiagnostic\Microsoft-Windows-DiskDiagnosticDataCollector'
|
||||||
|
)) )
|
||||||
|
|
||||||
|
return $c
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Display
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Get-StateColor {
|
||||||
|
param([string]$State)
|
||||||
|
if ($State -like 'Disabled*') { return 'Green' }
|
||||||
|
if ($State -like 'Enabled*') { return 'Yellow' }
|
||||||
|
if ($State -like 'Not present*'){ return 'DarkGray' }
|
||||||
|
return 'Gray'
|
||||||
|
}
|
||||||
|
|
||||||
|
function Show-Status {
|
||||||
|
param($Controls)
|
||||||
|
|
||||||
|
Write-Host ''
|
||||||
|
Write-Host '==================================================================' -ForegroundColor Cyan
|
||||||
|
Write-Host ' Windows 11 Telemetry / Diagnostic Data Status' -ForegroundColor Cyan
|
||||||
|
Write-Host (' Host: {0} Admin: {1} {2}' -f $env:COMPUTERNAME, $Script:IsAdmin, (Get-Date)) -ForegroundColor DarkCyan
|
||||||
|
Write-Host ' Enabled = collecting/on Disabled = hardened/off' -ForegroundColor DarkCyan
|
||||||
|
Write-Host '==================================================================' -ForegroundColor Cyan
|
||||||
|
Write-Host ('{0,-4}{1,-34}{2,-18}{3}' -f '#', 'Setting', 'Category', 'State') -ForegroundColor White
|
||||||
|
Write-Host ('{0,-4}{1,-34}{2,-18}{3}' -f '---', '-------', '--------', '-----') -ForegroundColor DarkGray
|
||||||
|
|
||||||
|
$i = 0
|
||||||
|
$nEnabled = 0; $nDisabled = 0; $nAbsent = 0
|
||||||
|
foreach ($ctrl in $Controls) {
|
||||||
|
$i++
|
||||||
|
$state = Get-ControlState -Ctrl $ctrl
|
||||||
|
if ($state -like 'Enabled*') { $nEnabled++ }
|
||||||
|
elseif ($state -like 'Disabled*') { $nDisabled++ }
|
||||||
|
elseif ($state -like 'Not present*') { $nAbsent++ }
|
||||||
|
$lock = ''
|
||||||
|
if ($ctrl.AdminReq -and -not $Script:IsAdmin) { $lock = ' *' }
|
||||||
|
$line = ('{0,-4}{1,-34}{2,-18}' -f $i, $ctrl.Name, $ctrl.Category)
|
||||||
|
Write-Host $line -NoNewline
|
||||||
|
Write-Host ($state + $lock) -ForegroundColor (Get-StateColor $state)
|
||||||
|
}
|
||||||
|
Write-Host ('{0,-4}{1,-34}{2,-18}{3}' -f '---', '-------', '--------', '-----') -ForegroundColor DarkGray
|
||||||
|
Write-Host (' Summary: {0} enabled, {1} disabled, {2} not present' -f $nEnabled, $nDisabled, $nAbsent) -ForegroundColor White
|
||||||
|
if (-not $Script:IsAdmin) {
|
||||||
|
Write-Host ' * requires Administrator to change (run elevated)' -ForegroundColor DarkYellow
|
||||||
|
}
|
||||||
|
Write-Host ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function Export-StatusCsv {
|
||||||
|
param($Controls, [string]$Path)
|
||||||
|
$rows = foreach ($ctrl in $Controls) {
|
||||||
|
[pscustomobject]@{
|
||||||
|
Name = $ctrl.Name
|
||||||
|
Category = $ctrl.Category
|
||||||
|
Type = $ctrl.Type
|
||||||
|
State = (Get-ControlState -Ctrl $ctrl)
|
||||||
|
AdminReq = $ctrl.AdminReq
|
||||||
|
Note = $ctrl.Note
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rows | Export-Csv -Path $Path -NoTypeInformation -Encoding ASCII
|
||||||
|
Write-Host ("Status written to {0}" -f $Path) -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Apply helpers with guard rails
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Invoke-ControlAction {
|
||||||
|
param($Ctrl, [ValidateSet('Enable','Disable')][string]$Action)
|
||||||
|
|
||||||
|
if ($Ctrl.AdminReq -and -not $Script:IsAdmin) {
|
||||||
|
Write-Host (" SKIP {0} (needs Administrator)" -f $Ctrl.Name) -ForegroundColor DarkYellow
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ((Get-ControlState -Ctrl $Ctrl) -eq 'Not present') {
|
||||||
|
Write-Host (" SKIP {0} (not present on this system)" -f $Ctrl.Name) -ForegroundColor DarkGray
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if ($Action -eq 'Enable') { Set-ControlEnabled -Ctrl $Ctrl }
|
||||||
|
else { Set-ControlDisabled -Ctrl $Ctrl }
|
||||||
|
$new = Get-ControlState -Ctrl $Ctrl
|
||||||
|
Write-Host (" OK {0} -> {1}" -f $Ctrl.Name, $new) -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Host (" FAIL {0}: {1}" -f $Ctrl.Name, $_.Exception.Message) -ForegroundColor Red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-AllAction {
|
||||||
|
param($Controls, [ValidateSet('Enable','Disable')][string]$Action)
|
||||||
|
$verb = if ($Action -eq 'Enable') { 'ENABLE (restore Windows default)' } else { 'DISABLE (harden)' }
|
||||||
|
Write-Host ''
|
||||||
|
Write-Host ("Applying {0} to ALL items..." -f $verb) -ForegroundColor Cyan
|
||||||
|
foreach ($ctrl in $Controls) { Invoke-ControlAction -Ctrl $ctrl -Action $Action }
|
||||||
|
Write-Host ''
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Interactive menu
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
function Start-Menu {
|
||||||
|
param($Controls)
|
||||||
|
while ($true) {
|
||||||
|
Show-Status -Controls $Controls
|
||||||
|
Write-Host 'Commands:' -ForegroundColor White
|
||||||
|
Write-Host ' <n> toggle item n (Enable<->Disable)'
|
||||||
|
Write-Host ' e <n> enable item n'
|
||||||
|
Write-Host ' d <n> disable item n'
|
||||||
|
Write-Host ' D disable ALL (harden)'
|
||||||
|
Write-Host ' E enable ALL (restore Windows default)'
|
||||||
|
Write-Host ' r refresh view'
|
||||||
|
Write-Host ' c <path> export status to CSV'
|
||||||
|
Write-Host ' q quit'
|
||||||
|
Write-Host ''
|
||||||
|
$inp = Read-Host 'Select'
|
||||||
|
if ([string]::IsNullOrWhiteSpace($inp)) { continue }
|
||||||
|
$inp = $inp.Trim()
|
||||||
|
|
||||||
|
# -CaseSensitive so bare "d"/"e" do NOT match the ALL branches below
|
||||||
|
switch -Regex -CaseSensitive ($inp) {
|
||||||
|
'^[Qq]$' { return }
|
||||||
|
'^[Rr]$' { continue }
|
||||||
|
'^D$' {
|
||||||
|
if ((Read-Host 'Disable ALL telemetry? type YES') -ceq 'YES') {
|
||||||
|
Invoke-AllAction -Controls $Controls -Action Disable
|
||||||
|
}
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^E$' {
|
||||||
|
if ((Read-Host 'Enable ALL (Windows default)? type YES') -ceq 'YES') {
|
||||||
|
Invoke-AllAction -Controls $Controls -Action Enable
|
||||||
|
}
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^[Cc]\s+(.+)$' {
|
||||||
|
Export-StatusCsv -Controls $Controls -Path $Matches[1].Trim('"')
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^[Ee]\s+(\d+)$' {
|
||||||
|
$n = [int]$Matches[1]
|
||||||
|
if ($n -ge 1 -and $n -le $Controls.Count) { Invoke-ControlAction -Ctrl $Controls[$n-1] -Action Enable }
|
||||||
|
else { Write-Host 'Out of range' -ForegroundColor Red }
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^[Dd]\s+(\d+)$' {
|
||||||
|
$n = [int]$Matches[1]
|
||||||
|
if ($n -ge 1 -and $n -le $Controls.Count) { Invoke-ControlAction -Ctrl $Controls[$n-1] -Action Disable }
|
||||||
|
else { Write-Host 'Out of range' -ForegroundColor Red }
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
'^\d+$' {
|
||||||
|
$n = [int]$inp
|
||||||
|
if ($n -ge 1 -and $n -le $Controls.Count) {
|
||||||
|
$ctrl = $Controls[$n-1]
|
||||||
|
$state = Get-ControlState -Ctrl $ctrl
|
||||||
|
if ($state -like 'Enabled*') { Invoke-ControlAction -Ctrl $ctrl -Action Disable }
|
||||||
|
else { Invoke-ControlAction -Ctrl $ctrl -Action Enable }
|
||||||
|
} else { Write-Host 'Out of range' -ForegroundColor Red }
|
||||||
|
Read-Host 'Press Enter'; continue
|
||||||
|
}
|
||||||
|
default { Write-Host 'Unknown command (d/e need an item number; D/E alone mean ALL)' -ForegroundColor Red; Start-Sleep -Milliseconds 600 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Main
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
$controls = Get-Controls
|
||||||
|
|
||||||
|
if ($DisableAll) {
|
||||||
|
Invoke-AllAction -Controls $controls -Action Disable
|
||||||
|
Show-Status -Controls $controls
|
||||||
|
if ($Csv) { Export-StatusCsv -Controls $controls -Path $Csv }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($EnableAll) {
|
||||||
|
Invoke-AllAction -Controls $controls -Action Enable
|
||||||
|
Show-Status -Controls $controls
|
||||||
|
if ($Csv) { Export-StatusCsv -Controls $controls -Path $Csv }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($Report -or $Csv) {
|
||||||
|
if ($Report) { Show-Status -Controls $controls }
|
||||||
|
if ($Csv) { Export-StatusCsv -Controls $controls -Path $Csv }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $Script:IsAdmin) {
|
||||||
|
Write-Host ''
|
||||||
|
Write-Host 'NOTE: Not running as Administrator. HKLM / service / task items' -ForegroundColor DarkYellow
|
||||||
|
Write-Host ' will show as read-only (*) and cannot be changed until you' -ForegroundColor DarkYellow
|
||||||
|
Write-Host ' relaunch this script in an elevated PowerShell window.' -ForegroundColor DarkYellow
|
||||||
|
}
|
||||||
|
|
||||||
|
Start-Menu -Controls $controls
|
||||||
@@ -1,2 +1,222 @@
|
|||||||
# go_darker
|
# Windows Telemetry & Browser Privacy Tools
|
||||||
A windows telemetry hardening script, use at own risk
|
|
||||||
|
Two single-file, dependency-free PowerShell 5.1 scripts:
|
||||||
|
|
||||||
|
| Script | Scope |
|
||||||
|
|---|---|
|
||||||
|
| `Manage-WindowsTelemetry.ps1` | Windows 11 telemetry / diagnostic-data settings, services and scheduled tasks |
|
||||||
|
| `Manage-BrowserPrivacy.ps1` | Privacy / telemetry policies for Edge, Chrome, Firefox and Brave |
|
||||||
|
|
||||||
|
Both share the same UX: a color-coded status view (**Enabled** = collecting,
|
||||||
|
**Disabled** = hardened), interactive per-item toggling, one-shot
|
||||||
|
`-DisableAll` / `-EnableAll`, `-Report`, and CSV export. Both are ASCII-only,
|
||||||
|
BOM-free, module-free, and run in stock `powershell.exe` on Windows 11.
|
||||||
|
|
||||||
|
> **Disclaimer:** Changing telemetry, service, task and browser-policy
|
||||||
|
> settings alters system behaviour. Review the scripts before running them,
|
||||||
|
> test on a non-production machine first, and consider a restore point.
|
||||||
|
> No warranty.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 1. Manage-WindowsTelemetry.ps1
|
||||||
|
|
||||||
|
Views and controls **Windows 11 telemetry / diagnostic-data settings,
|
||||||
|
services and scheduled tasks** from one place.
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# View status only (read-only, safe anywhere)
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -Report
|
||||||
|
|
||||||
|
# Interactive menu (run from an ELEVATED PowerShell to change HKLM/services/tasks)
|
||||||
|
.\Manage-WindowsTelemetry.ps1
|
||||||
|
|
||||||
|
# One-shot hardening: turn all telemetry OFF
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -DisableAll
|
||||||
|
|
||||||
|
# Restore Windows default behaviour: turn everything back ON
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -EnableAll
|
||||||
|
|
||||||
|
# Export current status to CSV (exits after export)
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -Csv .\telemetry-status.csv
|
||||||
|
|
||||||
|
# Report to screen AND CSV
|
||||||
|
.\Manage-WindowsTelemetry.ps1 -Report -Csv .\telemetry-status.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
If script execution is blocked on your machine:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\Manage-WindowsTelemetry.ps1 -Report
|
||||||
|
```
|
||||||
|
|
||||||
|
## Semantics
|
||||||
|
|
||||||
|
| Term | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| **Enabled** (yellow) | The telemetry / data-collection behaviour is ON |
|
||||||
|
| **Enabled (default)** | No override present; Windows out-of-box behaviour (ON) |
|
||||||
|
| **Disabled** (green) | The behaviour is OFF / hardened |
|
||||||
|
| **Not present** (gray) | Service or task does not exist on this system |
|
||||||
|
| `*` suffix | Requires Administrator to change (run elevated) |
|
||||||
|
|
||||||
|
Two design rules worth knowing:
|
||||||
|
|
||||||
|
1. **"Enable" restores the true Windows default.** For policy-style registry
|
||||||
|
values (where the Windows default is *no value at all*), enabling
|
||||||
|
**removes** the policy value instead of writing one. This avoids leaving
|
||||||
|
the machine in a "Some settings are managed by your organization" state
|
||||||
|
after an enable/disable round trip.
|
||||||
|
2. **Services are restored to their real default start types** (`DiagTrack`
|
||||||
|
= Automatic, `dmwappushservice` / `WerSvc` = Manual), not blanket
|
||||||
|
Automatic.
|
||||||
|
|
||||||
|
## Interactive menu commands
|
||||||
|
|
||||||
|
| Command | Action |
|
||||||
|
|---|---|
|
||||||
|
| `<n>` | Toggle item *n* (Enabled <-> Disabled) |
|
||||||
|
| `e <n>` / `d <n>` | Enable / disable item *n* |
|
||||||
|
| `E` / `D` (uppercase) | Enable / disable **ALL** items (asks for `YES` confirmation) |
|
||||||
|
| `r` | Refresh the view |
|
||||||
|
| `c <path>` | Export status to CSV |
|
||||||
|
| `q` | Quit |
|
||||||
|
|
||||||
|
The menu is case-sensitive where it matters: a bare lowercase `d`/`e` will
|
||||||
|
**not** trigger the ALL branches.
|
||||||
|
|
||||||
|
## What is covered
|
||||||
|
|
||||||
|
### Registry (policy and per-user)
|
||||||
|
|
||||||
|
| Area | Items |
|
||||||
|
|---|---|
|
||||||
|
| Core telemetry | `AllowTelemetry` (policy + non-policy), feedback notifications, `LimitDiagnosticLogCollection`, `DisableOneSettingsDownloads` |
|
||||||
|
| App compatibility | Appraiser telemetry (`AITEnable`), Inventory Collector |
|
||||||
|
| Error Reporting (the modern successor to Dr. Watson) | WER on/off (non-policy + policy), `DontSendAdditionalData`, consent level (`DefaultConsent`) |
|
||||||
|
| CEIP | `CEIPEnable` (SQM Client) |
|
||||||
|
| Cloud content | Consumer Features, Tailored Experiences (policy) |
|
||||||
|
| Activity history | Publish / Upload User Activities |
|
||||||
|
| Per-user privacy (no admin needed) | Advertising ID, Tailored Experiences, Feedback frequency (SIUF), implicit ink/text collection, Typing Insights (TIPC), online speech recognition, linguistic data collection, Search box web suggestions (Win11) + legacy `BingSearchEnabled` |
|
||||||
|
|
||||||
|
### Services
|
||||||
|
|
||||||
|
| Service | Default start | Note |
|
||||||
|
|---|---|---|
|
||||||
|
| `DiagTrack` (Connected User Experiences and Telemetry) | Automatic | Primary telemetry service |
|
||||||
|
| `dmwappushservice` | Manual | Disabling can break provisioning-package / MDM enrolment |
|
||||||
|
| `WerSvc` (Windows Error Reporting) | Manual | Runs WER report submission |
|
||||||
|
|
||||||
|
### Scheduled tasks
|
||||||
|
|
||||||
|
- Application Experience: Compatibility Appraiser, ProgramDataUpdater, StartupAppTask
|
||||||
|
- CEIP: Consolidator, UsbCeip, Autochk\Proxy (kernel CEIP)
|
||||||
|
- Feedback (SIUF): DmClient, DmClientOnScenarioDownload
|
||||||
|
- Windows Error Reporting: QueueReporting
|
||||||
|
- DiskDiagnostic: DiskDiagnosticDataCollector
|
||||||
|
|
||||||
|
## Known limitations
|
||||||
|
|
||||||
|
- **Home/Pro diagnostic-data floor:** `AllowTelemetry = 0` (Security) is only
|
||||||
|
fully honoured on Enterprise/Education/IoT SKUs. On Home/Pro, Windows
|
||||||
|
treats 0 as 1 (Required), so a small baseline of required diagnostic data
|
||||||
|
may still flow even when everything here shows Disabled.
|
||||||
|
- Some items are refreshed by Windows Update or feature updates; re-run
|
||||||
|
`-Report` after major updates to verify state.
|
||||||
|
- `BingSearchEnabled` is a Windows 10-era value kept for completeness; the
|
||||||
|
effective Windows 11 control is `DisableSearchBoxSuggestions` (also
|
||||||
|
included).
|
||||||
|
- Changing WER/crash-reporting settings affects local crash-dump collection
|
||||||
|
behaviour, which you may want during debugging.
|
||||||
|
|
||||||
|
## CSV output columns
|
||||||
|
|
||||||
|
`Name, Category, Type (Reg/Service/Task), State, AdminReq, Note`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 2. Manage-BrowserPrivacy.ps1
|
||||||
|
|
||||||
|
Views and hardens **privacy / telemetry-related policy settings** for the
|
||||||
|
browsers installed on the machine. Browsers are auto-detected (via App Paths
|
||||||
|
registration); only installed ones are shown unless you pass `-IncludeAll`.
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# View status only (read-only)
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -Report
|
||||||
|
|
||||||
|
# Interactive menu (ELEVATED PowerShell required to change anything)
|
||||||
|
.\Manage-BrowserPrivacy.ps1
|
||||||
|
|
||||||
|
# One-shot: harden every detected browser
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -DisableAll
|
||||||
|
|
||||||
|
# Restore all browser defaults (removes the policy values)
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -EnableAll
|
||||||
|
|
||||||
|
# Export status to CSV / include browsers that are not installed
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -Csv .\browser-status.csv
|
||||||
|
.\Manage-BrowserPrivacy.ps1 -Report -IncludeAll
|
||||||
|
```
|
||||||
|
|
||||||
|
The menu supports the same commands as the Windows tool, plus
|
||||||
|
`b <browser>` to harden a single browser at once (e.g. `b Edge`).
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
All controls are **policy DWORD values** under `HKLM\SOFTWARE\Policies\...`
|
||||||
|
(the official enterprise policy locations each vendor documents). Because a
|
||||||
|
browser's true default is *no policy value at all*, **Enable always removes
|
||||||
|
the value** rather than writing one - so an enable/disable round trip leaves
|
||||||
|
no permanent "managed" residue.
|
||||||
|
|
||||||
|
Two things to expect:
|
||||||
|
|
||||||
|
- Policies apply on the **next browser start** - restart the browser after
|
||||||
|
changes.
|
||||||
|
- While hardened, browsers display a **"Managed by your organization"**
|
||||||
|
notice on their settings pages. That is Chromium/Firefox correctly
|
||||||
|
reporting that policies are active, not a malfunction; `-EnableAll`
|
||||||
|
removes it again.
|
||||||
|
|
||||||
|
## What is covered
|
||||||
|
|
||||||
|
| Browser | Policies |
|
||||||
|
|---|---|
|
||||||
|
| **Edge** | Diagnostic data, personalization reporting, user feedback, search suggestions, Bing address-bar provider, Shopping Assistant, Rewards, Web Widget, Spotlight recommendations, Do Not Track, navigation-error web service, alternate error pages, network prediction (prefetch) |
|
||||||
|
| **Chrome** | Metrics reporting (UMA), search suggestions, Safe Browsing extended reporting, URL-keyed data collection, cloud spell check, alternate error pages, network prediction, feedback surveys, Privacy Sandbox (prompt, Ad Topics, site-suggested ads, ad measurement) |
|
||||||
|
| **Firefox** | Telemetry, Firefox Studies (Shield), Default Browser Agent (daily Mozilla ping), Pocket |
|
||||||
|
| **Brave** | Rewards, Wallet, VPN, Tor windows, search suggestions (Chromium policy) |
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- Chrome's Safe Browsing itself is left ON; only the *extended reporting*
|
||||||
|
(extra data to Google) is hardened.
|
||||||
|
- The three Chrome Privacy Sandbox ad policies require the Privacy Sandbox
|
||||||
|
prompt policy to be Disabled as well - the tool includes it.
|
||||||
|
- Brave sends comparatively little telemetry by default; its entries harden
|
||||||
|
the bundled feature surface (Rewards/Wallet/VPN/Tor), each of which
|
||||||
|
contacts Brave services.
|
||||||
|
- DNS-over-HTTPS policies are intentionally not touched - DoH is a privacy
|
||||||
|
*gain* in most settings and is better configured deliberately per network.
|
||||||
|
|
||||||
|
## CSV output columns
|
||||||
|
|
||||||
|
`Name, Browser, Installed, Policy, State, Note`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `Manage-WindowsTelemetry.ps1` | Windows telemetry view + control |
|
||||||
|
| `Manage-BrowserPrivacy.ps1` | Browser privacy view + hardening |
|
||||||
|
| `README.md` | This file |
|
||||||
|
|
||||||
|
Both CSV exports are useful for fleet auditing: run with `-Csv` on multiple
|
||||||
|
machines and diff or aggregate the results.
|
||||||
|
|||||||
Reference in New Issue
Block a user