- Reading Azure VM name, IP address, and hostname with PowerShell - Fri, Jul 28 2017
- Automating WSUS with PowerShell - Thu, Jul 13 2017
- Disable SSL and TLS 1.0/1.1 on IIS with PowerShell - Tue, Jun 27 2017
It is important to note that that this script does not remove all Windows 10 telemetry. However, you can use the script to add more registry keys and disable services or scheduled tasks related to telemetry.
Function ChangeReg { param ([string] $RegKey, [string] $Value, [string] $SvcName, [Int] $CheckValue, [Int] $SetData) Write-Host "Checking if $SvcName is enabled" -ForegroundColor Green if (!(Test-Path $RegKey)){ Write-Host "Registry Key for service $SvcName does not exist, creating it now" -ForegroundColor Yellow New-Item -Path (Split-Path $RegKey) -Name (Split-Path $RegKey -Leaf) } $ErrorActionPreference = 'Stop' try{ Get-ItemProperty -Path $RegKey -Name $Value if((Get-ItemProperty -Path $RegKey -Name $Value).$Value -eq $CheckValue) { Write-Host "$SvcName is enabled, disabling it now" -ForegroundColor Green Set-ItemProperty -Path $RegKey -Name $Value -Value $SetData -Force } if((Get-ItemProperty -Path $RegKey -Name $Value).$Value -eq $SetData){ Write-Host "$SvcName is disabled" -ForegroundColor Green } } catch [System.Management.Automation.PSArgumentException] { Write-Host "Registry entry for service $SvcName doesn't exist, creating and setting to disable now" -ForegroundColor Yellow New-ItemProperty -Path $RegKey -Name $Value -Value $SetData -Force } } # Disabling Advertising ID $RegKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AdvertisingInfo" $Value = "Enabled" $SvcName = "Advertising ID" $CheckValue = 1 $SetData = 0 ChangeReg -RegKey $RegKey -Value $Value -SvcName $SvcName -CheckValue $CheckValue -SetData $SetData #Telemetry Disable $RegKey = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" $Value = "AllowTelemetry" $SvcName = "Telemetry" $CheckValue = 1 $SetData = 0 ChangeReg -RegKey $RegKey -Value $Value -SvcName $SvcName -CheckValue $CheckValue -SetData $SetData #SmartScreen Disable $RegKey = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppHost\EnableWebContentEvaluation" $Value = "Enabled" $SvcName = "Smart Screen" $CheckValue = 1 $SetData = 0 ChangeReg -RegKey $RegKey -Value $Value -SvcName $SvcName -CheckValue $CheckValue -SetData $SetData Write-Host "Disabling DiagTrack Services" -ForegroundColor Green Get-Service -Name DiagTrack | Set-Service -StartupType Disabled | Stop-Service Get-Service -Name dmwappushservice | Set-Service -StartupType Disabled | Stop-Service Write-Host "DiagTrack Services are disabled" -ForegroundColor Green Write-Host "Disabling telemetry scheduled tasks" -ForegroundColor Green $tasks ="SmartScreenSpecific","ProgramDataUpdater","Microsoft Compatibility Appraiser","AitAgent","Proxy","Consolidator", "KernelCeipTask","BthSQM","CreateObjectTask","Microsoft-Windows-DiskDiagnosticDataCollector","WinSAT", "GatherNetworkInfo","FamilySafetyMonitor","FamilySafetyRefresh","SQM data sender","OfficeTelemetryAgentFallBack", "OfficeTelemetryAgentLogOn" $ErrorActionPreference = 'Stop' $tasks | %{ try{ Get-ScheduledTask -TaskName $_ | Disable-ScheduledTask } catch [Microsoft.PowerShell.Cmdletization.Cim.CimJobException] { "task $($_.TargetObject) is not found" } }
Now I’ll go line by line through this script.
Function ChangeReg {
param ([string] $RegKey, [string] $Value, [string] $SvcName, [Int] $CheckValue, [Int] $SetData)
Because more than one registry key needs modification, I decided to write this part as a function. The function accepts the following parameters:
$RegKey – represents the registry
$Value –name of the registry entry
$SvcName – name of the service
$CheckValue – initial value of the registry entry
$SetData – desired value of the registry entry
Write-Host "Checking if $SvcName is enabled" -ForegroundColor Green if (!(Test-Path $RegKey)){ Write-Host "Registry Key for service $SvcName does not exist, creating it now" -ForegroundColor Yellow New-Item -Path (Split-Path $RegKey) -Name (Split-Path $RegKey -Leaf) }
This section informs the user what the script is currently doing using the Write-Host cmdlet. Then it checks if the registry key that we have to change exists using Test-Path. If not, I create this key, spitting the original $RegKey value into the parent and leaf with the help of the Split-Path cmdlet. I’m doing this while bearing in mind that a lot of Windows services are enabled by default but don't have registry keys or values for disabling them. This seems to be true for some telemetry services as well.
$ErrorActionPreference = 'Stop' try{ Get-ItemProperty -Path $RegKey -Name $Value if((Get-ItemProperty -Path $RegKey -Name $Value).$Value -eq $CheckValue) { Write-Host "$SvcName is enabled, disabling it now" -ForegroundColor Green Set-ItemProperty -Path $RegKey -Name $Value -Value $SetData -Force } if((Get-ItemProperty -Path $RegKey -Name $Value).$Value -eq $SetData){ Write-Host "$SvcName is disabled" -ForegroundColor Green } } catch [System.Management.Automation.PSArgumentException] { Write-Host "Registry entry for service $SvcName doesn't exist, creating and setting to disable now" -ForegroundColor Yellow New-ItemProperty -Path $RegKey -Name $Value -Value $SetData -Force } } }
Now I need to check whether the registry entry that is responsible for disabling a particular telemetry option already exists. I did this using a try-catch block to avoid errors that the Get-ItemProperty cmdlet would generate if the item I’m trying to read does not exist. To accomplish this, I have to set $ErrorActionPreference to 'Stop' before the try clause because try-catch only reacts to fatal errors. [System.Management.Automation.PSArgumentException] is not one of them. Thus, I ensure that any error is considered fatal using the $ErrorActionPreference variable.
If the registry entry exists, I use an if-statement to check whether the value of this entry equals one, which means that the corresponding telemetry service is enabled. In this case, I let the user know that this particular telemetry option is enabled and that it is going to be disabled. Then I set the registry entry value to $SetData, which disables the telemetry option.
The second if-statement verifies whether the value was changed successfully and then informs the user that it was. The catch statement comes into play if there was an exception, which means that the registry entry does not exist. If this happens, I create a new entry using the New-ItemProperty cmdlet and assign the value that disables the telemetry option.
# Disabling Advertising ID $RegKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AdvertisingInfo" $Value = "Enabled" $SvcName = "Advertising ID" $CheckValue = 1 $SetData = 0 ChangeReg -RegKey $RegKey -Value $Value -SvcName $SvcName -CheckValue $CheckValue -SetData $SetData #Telemetry Disable $RegKey = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" $Value = "AllowTelemetry" $SvcName = "Telemetry" $CheckValue = 1 $SetData = 0 ChangeReg -RegKey $RegKey -Value $Value -SvcName $SvcName -CheckValue $CheckValue -SetData $SetData #SmartScreen Disable $RegKey = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppHost\EnableWebContentEvaluation" $Value = "Enabled" $SvcName = "Smart Screen" $CheckValue = 1 $SetData = 0 ChangeReg -RegKey $RegKey -Value $Value -SvcName $SvcName -CheckValue $CheckValue -SetData $SetData
As you can see, all this bunch of code does is set the variables to the values that correspond to the most obvious telemetry components and then uses the ChangeReg function to disable them.
Write-Host "Disabling DiagTrack Services" -ForegroundColor Green Get-Service -Name DiagTrack | Set-Service -StartupType Disabled | Stop-Service Get-Service -Name dmwappushservice | Set-Service -StartupType Disabled | Stop-Service Write-Host "DiagTrack Services are disabled" -ForegroundColor Green Now I disabling two system services which send telemetry data to Microsoft.. $tasks ="SmartScreenSpecific","ProgramDataUpdater","Microsoft Compatibility Appraiser","AitAgent","Proxy","Consolidator", "KernelCeipTask","BthSQM","CreateObjectTask","Microsoft-Windows-DiskDiagnosticDataCollector","WinSAT", "GatherNetworkInfo","FamilySafetyMonitor","FamilySafetyRefresh","SQM data sender","OfficeTelemetryAgentFallBack", "OfficeTelemetryAgentLogOn"
Finally, I’m coming to the scheduled tasks that are used for telemetry processes. I store them into a string array. Below is a short description of each task:
SmartScreenSpecific – collects data for Microsoft SmartScreen
ProgramDataUpdater – collects program telemetry information if opted-in to the Microsoft Customer Experience Improvement Program (CEIP)
Microsoft Compatibility Appraiser – ollects program telemetry information if opted-in to the CEIP
AitAgent – aggregates and uploads application telemetry information if opted-in to the CEIP
Proxy – collects and uploads Software Quality Management (SQM) data if opted-in to the CEIP
Consolidator – collects and sends usage data to Microsoft (if the user has consented to participate in the CEIP)
KernelCeipTask (Kernel Customer Experience Improvement Program) – collects additional information related to customer experience and sends it to Microsoft (if the user consented to participate in the Windows CEIP)
BthSQM (Bluetooth Customer Experience Improvement Program) – collects Bluetooth-related statistics and information about your machine and sends it to Microsoft (if you have consented to participate in the Windows CEIP). The information received is used to help improve the reliability, stability, and overall functionality of Bluetooth in Windows.
DiskDiagnosticDataCollector (Windows Disk Diagnostic reports) – collects general disk and system information and sends it to Microsoft (if the user users participates in the CEIP)
WinSAT – measures system performance and capabilities
GatherNetworkInfo – collects network information
FamilySafetyMonitor – initializes family safety monitoring and enforcement
FamilySafetyRefresh – synchronizes the latest settings with the family safety website
SQM data sender - sends SQM data to Microsoft
OfficeTelemetryAgentFallBack – initiates the background task for the Office Telemetry Agent that scans and uploads usage and error information for Office solutions
OfficeTelemetryAgentLogOn – initiates the Office Telemetry Agent that scans and uploads usage and error information for Office solutions when a user logs on to the computer
$ErrorActionPreference = 'Stop' $tasks | %{ try{ Get-ScheduledTask -TaskName $_ | Disable-ScheduledTask } catch [Microsoft.PowerShell.Cmdletization.Cim.CimJobException] { "task $($_.TargetObject) is not found" } }
Some tasks might be absent on different Windows 10 installations, so I added a try-catch block to avoid error messages’ being displayed on the console. "$ErrorActionPreference = 'Stop'" serves the same purpose as it did in the previous case; that is, it ensures that any error calls the Stop instruction.
Subscribe to 4sysops newsletter!
At the end of the script, I’m trying to disable the task from the $tasks array using the Get-ScheduledTask cmdlet. First, I get the task object, and then, if this operation is successful, I pipe this object to Disable-ScheduledTask. If there is no task with such a name, the catch section generates and catches a Microsoft.PowerShell.Cmdletization.Cim.CimJobException exception . In this case, the message that the task was not found will be produced.
nice!
Just what I was looking for.
Hmm, seems like there may be a problem with the try/catch on the scheduled tasks. The ones that are present appear to be getting disabled, but the ones that aren’t present are generating errors.
I just ran it on couple test VMs with windows 1o. This is the output from one of them:
However, I’ve seen such behavior for some scripts before. And usually when you run the try-catch block for the first time it throws an error, but second time it works as it supposed to do. I have no logical explanation to it.
Hi,
Just to alert you to the typo at :
$ErrorActionPreference = ‘’Stop
good catch.
Corrected.
I tried running a few times, no change. Even after killing the PS session and starting a new one, just in case things were cached. I’m getting the error below. Taskname changes but otherwise same stuff. There are about 5 or so in my case.
Well, I just have to admit it does throw and error when ran from PowerShell console. It works perfectly when ran from PowerShell ISE, though. I can’t understand why there is such a difference.
The Set-StrictMode command doesn’t change console behavior as well.
Will continue to investigate.
Since this was just a single machine for now I decided to run it from the ISE. It failed there as well. In case it makes any difference this is running on 10586. Powershell version reports as 5/0/10586/494
So, the only way I could get it to work in console is adding the -ErrorAction to each command in the trycatch block. Which is weird, to be honest. Please find the peace of code below:
1 – when i copied this script, i got a lot of unicode spaces. don't know how that happened.
2 – when i run it, i get lots of what looks like dumped registry entries in white text and access errors in red text.
does this need to be updated?
undo ?????
If you’re creating complex PowerShell scripts like this, you should already be aware that setting the AllowTelemetry key in the registry, will have the same effect as using the Local Group Policy Editor to set one on of the 4 allowed levels of Data Reporting. You should also be aware that setting it to Zero is only possible on Windows Enterprise and if you choose to do it anyway…. for example, if you set this key to 0 on a Windows Pro copy…. the system will revert to the level of Diagnostic Data that Microsoft sees fit, and this effect will be invisible. You can verify what I’m telling you by simply visiting the relevant Group Policy, setting it to 4 then refresh Regedit (press F5) and watch as the AllowTelemetry key changes to 4. If you’re not on Enterprise then then 1 is the lowest setting you can use.
Basically, if you don’t know what you’re doing by poking around in the registry, you may very well be enabling more Telemetry while you think you’re turning it off.
Key: HKLM\SOFTWARE\Policies\Microsoft\Windows\DataCollection\”AllowTelemetry”
Local Group Policy: Computer Configuration\Administrative Templates\Windows Components\Data Collection and Preview Builds\Allow Telemetry (it tells you that you can only set 0 if you’re running Enterprise.)
*I’d never recommend that anybody run a script that automatically makes a bunch of changes to their Windows in the hopes of tuning it for privacy reasons. The best thing to do is do the research yourself and understand what it is that you’ll be changing.