Set-Privacy.ps1

<#PSScriptInfo
 
.VERSION 1.0.1
 
.GUID bd3a1ade-420c-4ac6-8558-b4f8df963aff
 
.AUTHOR Peter Hahndorf
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI https://raw.githubusercontent.com/hahndorf/Set-Privacy/master/LICENSE
 
.PROJECTURI https://github.com/hahndorf/Set-Privacy
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
   1.0.1 - 10-Aug-2016 Fixed a bug on Version 1607 with handling registry paths
 
#>


<#
.SYNOPSIS
    PowerShell script to batch-change privacy settings in Windows 10
.DESCRIPTION
    With so many different privacy settings in Windows 10, it makes sense to have a script to change them.
.PARAMETER Strong
    Makes changes to allow for the highest privacy
.PARAMETER Default
    Reverts to Windows defaults
.PARAMETER Balanced
    Turns off certain things but not everything.
.PARAMETER Admin
    Updates machine settings rather than user settings, still requires Strong,Balanced or Default switches. Needs to run as elevated admin.
    If this switch is selected, no user settings are changed.
.PARAMETER Features
    A comma separated list of features to disable or enable. Use the Tab key to show all allowed values
.PARAMETER Disable
    Use with -Features to disable all those features
.PARAMETER Enable
   Use with -Features to enable all those features
 
.EXAMPLE
    Set-Privacy -Balanced
    Runs the script to set the balanced privacy settings
.EXAMPLE
    Set-Privacy -Strong -Admin
    Runs the script to set the strong settings on the machine level. This covers Windows update and WiFi sense.
.EXAMPLE
    Set-Privacy -disable -Features WifiSense,ShareUpdates,Contacts
    Disabled those three features to improve your privacy
.NOTES
    Requires Windows 10 and higher
    Author: Peter Hahndorf
    Created: August 4th, 2015
     
.LINK
    https://github.com/hahndorf/Set-Privacy
#>


param(
    [parameter(Mandatory=$true,ParameterSetName = "Strong")]
    [switch]$Strong,
    [parameter(Mandatory=$true,ParameterSetName = "Default")]
    [switch]$Default,
    [parameter(Mandatory=$true,ParameterSetName = "Balanced")]
    [switch]$Balanced,
    [parameter(ParameterSetName = "Balanced")]
    [parameter(ParameterSetName = "Default")]
    [parameter(ParameterSetName = "Strong")]
    [switch]$Admin,
    [parameter(Mandatory=$true,ParameterSetName = "Disable")]
    [switch]$Disable,
    [parameter(Mandatory=$true,ParameterSetName = "Enable")]
    [switch]$Enable,
    [parameter(Mandatory=$true,ParameterSetName = "Enable")]
    [parameter(Mandatory=$true,ParameterSetName = "Disable")]
    [ValidateSet("AdvertisingId","ImproveTyping","Location","Camera","Microphone","SpeachInkingTyping","AccountInfo","Contacts","Calendar","Messaging","Radios","OtherDevices","FeedbackFrequency","ShareUpdates","WifiSense","Telemetry","SpyNet","DoNotTrack","SearchSuggestions","PagePrediction","PhishingFilter")]
    [string[]]$Feature
)           

Begin
{

#requires -version 3

# check https://fix10.isleaked.com/ for changing things manually.

    # ----------- Helper Functions -----------

    Function Test-Admin()
    {
        if (!($userIsAdmin))
        {
            Write-Warning "When using -admin switch or specifying a machine setting, please run this script as elevated administrator"
            Exit 102
        }
    }

    Function Test-RegistryValue([String]$Path,[String]$Name){

      if (!(Test-Path $Path)) { return $false }
   
      $Key = Get-Item -LiteralPath $Path
      if ($Key.GetValue($Name, $null) -ne $null) {
          return $true
      } else {
          return $false
      }
    }

    Function Get-RegistryValue([String]$Path,[String]$Name){

      if (!(Test-Path $Path)) { return $null }
   
      $Key = Get-Item -LiteralPath $Path
      if ($Key.GetValue($Name, $null) -ne $null) {
          return $Key.GetValue($Name, $null)
      } else {
          return $null
      }
    }

    Function Remove-RegistryValue([String]$Path,[String]$Name){

        $old = Get-RegistryValue -Path $Path -Name $Name
        if ($old -ne $null)
        {
            Remove-ItemProperty -Path "$Path" -Name "$Name"
            Write-Host "$Path\$Name removed" -ForegroundColor Yellow
        }
        else
        {
            Write-Host "$Path\$Name does not exist" -ForegroundColor Green
        }

    }

    Function Create-RegistryKey([string]$path)
    {        
        # creates a parent key and if needed grandparent key as well
        # for this script that is good enough

        If (!(Test-Path $Path))
        {
            $parent = "$path\.."

            $grandParent = "$parent\.."
            If (!(Test-Path $grandParent))
            {
                New-item -Path $grandParent | Out-Null
            }

            If (!(Test-Path $parent))
            {
                New-item -Path $parent | Out-Null
            }

            New-item -Path $Path | Out-Null
        }
    }

    Function Add-RegistryDWord([String]$Path,[String]$Name,[int32]$value){

        $old = Get-RegistryValue -Path $Path -Name $Name
        if ($old -ne $null)
        {
            if ([int32]$old -eq $value)
            {
                Write-Host "$Path\$Name already set to $value" -ForegroundColor Green
                return
            }
        }


        If (Test-RegistryValue $Path $Name)
        {
            Set-ItemProperty -Path $Path -Name $Name -Value $value
        }
        else
        {
            Create-RegistryKey -path $path
            New-ItemProperty -Path $Path -Name $Name -PropertyType DWord -Value $value | Out-Null
        }


        Write-Host "$Path\$Name changed to $value" -ForegroundColor Yellow
    }

    Function Add-RegistryString([String]$Path,[String]$Name,[string]$value){


        $old = Get-RegistryValue -Path $Path -Name $Name
        if ($old -ne $null)
        {
            if ([string]$old -eq $value)
            {
                Write-Host "$Path\$Name already set to $value" -ForegroundColor Green
                return
            }
        }

        If (Test-RegistryValue $Path $Name)
        {
            Set-ItemProperty -Path $Path -Name $Name -Value $value
        }
        else
        {
            Create-RegistryKey -path $path
            New-ItemProperty -Path $Path -Name $Name -PropertyType String -Value $value |Out-Null
        }

        Write-Host "$Path\$Name changed to $value" -ForegroundColor Yellow
    }

    Function Get-AppSID(){

        Get-ChildItem "HKCU:\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Mappings" | foreach {

        $key = $_.Name -replace "HKEY_CURRENT_USER","HKCU:"

        $val = Get-RegistryValue -Path $key -Name "Moniker" 

        if ($val -ne $null)
        {
            if ($val -match "^microsoft\.people_")
            {
                $script:sidPeople = $_.PsChildName
            }
            if ($val -match "^microsoft\.windows\.cortana")
            {
                $script:sidCortana = $_.PsChildName
            }
        }     
    }              
    }

    Function DeviceAccess([string]$guid,[string]$value){
        Add-RegistryString -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeviceAccess\Global\{$guid}" -Name Value -Value $value
    }

    Function DeviceAccessName([string]$name,[string]$value){
        Add-RegistryString -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeviceAccess\Global\$name" -Name Value -Value $value
    }

    Function DeviceAccessApp([string]$app,[string]$guid,[string]$value){

        Add-RegistryString -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeviceAccess\$app\{$guid}" -Name Value -Value $value
    }

    Function Report(){

        Write-Host "Privacy settings changed"
        Exit 0
    }

    # ----------- User Privacy Functions -----------
    
    Function SmartScreen([int]$value){
        
        # Turn on SmartScreen Filter
        Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppHost" -Name EnableWebContentEvaluation -Value $value
    }

    Function ImproveTyping([int]$value){

        # Send Microsoft info about how to write to help us improve typing and writing in the future
        Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\Input\TIPC" -Name Enabled -Value $value
    }

    Function AdvertisingId([int]$value){

       # Let apps use my advertising ID for experience across apps
        Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\AdvertisingInfo" -Name Enabled -Value $value
    }

    Function LanguageList([int]$value){

        # Let websites provice locally relevant content by accessing my language list
        Add-RegistryDWord -Path "HKCU:\Control Panel\International\User Profile" -Name HttpAcceptLanguageOptOut -Value $value
    }

    Function SpeachInkingTyping([bool]$enable){

        if ($enable)
        {
            Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\Personalization\Settings" -Name AcceptedPrivacyPolicy -Value 1
            Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\InputPersonalization" -Name RestrictImplicitTextCollection -Value 0
            Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\InputPersonalization" -Name RestrictImplicitInkCollection -Value 0
            Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\InputPersonalization\TrainedDataStore" -Name HarvestContacts -Value 1
        }
        else
        {
            Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\Personalization\Settings" -Name AcceptedPrivacyPolicy -Value 0
            Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\InputPersonalization" -Name RestrictImplicitTextCollection -Value 1
            Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\InputPersonalization" -Name RestrictImplicitInkCollection -Value 1
            Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\InputPersonalization\TrainedDataStore" -Name HarvestContacts -Value 0    
        }
    }

    Function Location([string]$value){

        DeviceAccess -guid "BFA794E4-F964-4FDB-90F6-51056BFE4B44" -value $value
    }

    Function Camera([string]$value){

        DeviceAccess -guid "E5323777-F976-4f5b-9B55-B94699C46E44" -value $value
    }

    Function Microphone([string]$value){
        DeviceAccess -guid "2EEF81BE-33FA-4800-9670-1CD474972C3F" -value $value
    }

    Function Contacts([string]$value){

        $exclude = $script:sidCortana + "|" + $script:sidPeople

        Get-ChildItem HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeviceAccess | ForEach-Object{

            $app = $_.PSChildName

            if ($app -ne "Global")
            {
                $key = $_.Name -replace "HKEY_CURRENT_USER","HKCU:"

                $contactsGUID = "7D7E8402-7C54-4821-A34E-AEEFD62DED93"
           
                $key += "\{$contactsGUID}"

                if (Test-Path "$key")
                {
                    if ($app -notmatch $exclude)
                    {
                        DeviceAccessApp -app $app -guid $contactsGUID -value $value
                    }
                }
            }
        }
    }

    Function Calendar([string]$value){
        DeviceAccess -guid "D89823BA-7180-4B81-B50C-7E471E6121A3" -value $value
    }

    Function AccountInfo([string]$value){
        DeviceAccess -guid "C1D23ACC-752B-43E5-8448-8D0E519CD6D6" -value $value
    }

    Function Messaging([string]$value){

        DeviceAccess -guid "992AFA70-6F47-4148-B3E9-3003349C1548" -value $value
    }

    Function Radios([string]$value){

        DeviceAccess -guid "A8804298-2D5F-42E3-9531-9C8C39EB29CE" -value $value
    }

    Function OtherDevices([string]$value){

        DeviceAccessName -name "LooselyCoupled" -value $value
    }

    Function FeedbackFrequency([int]$value){

        if ($value -lt 0)
        {
            # remove entry
            Remove-RegistryValue -Path "HKCU:\SOFTWARE\Microsoft\Siuf\Rules" -Name NumberOfSIUFInPeriod
        }
        else
        {
            Add-RegistryDWord -Path "HKCU:\SOFTWARE\Microsoft\Siuf\Rules" -Name NumberOfSIUFInPeriod -Value $value
        }
    }

    # ----------- Edge Browser Privacy Functions -----------

    [string]$EdgeKey = "HKCU:\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Storage\microsoft.microsoftedge_8wekyb3d8bbwe\MicrosoftEdge"

    Function DoNotTrack([int]$value){

       # 1 adds the Do Not Track Header, 0 does not
        Add-RegistryDWord -Path "$EdgeKey\Main" -Name DoNotTrack -Value $value
    }

    Function SearchSuggestions([int]$value){
    
       # 0 disables search suggestions, 1 does not
        Add-RegistryDWord -Path "$EdgeKey\User\Default\SearchScopes" -Name ShowSearchSuggestionsGlobal -Value $value
    }

    Function PagePrediction([int]$value){
    
       # 0 disables PagePrediction, 1 enables them
        Add-RegistryDWord -Path "$EdgeKey\FlipAhead" -Name FPEnabled -Value $value
    }

    Function PhishingFilter([int]$value){
    
       # 0 disables PhishingFilter, 1 enables it
        Add-RegistryDWord -Path "$EdgeKey\PhishingFilter" -Name EnabledV9 -Value $value
    }


    # ----------- Machine Settings Functions -----------

    Function ShareUpdates([int]$value){

        Test-Admin

        # 0 = Off
        # 1 = PCs on my local network
        # 3 = PCs on my local network, and PCs on the Internet

        Add-RegistryDWord -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\DeliveryOptimization\Config" -Name DODownloadMode -Value $value        
    }

    Function WifiSense([int]$value){

        Test-Admin

        Add-RegistryDWord -Path "HKLM:\SOFTWARE\Microsoft\WcmSvc\wifinetworkmanager\features" -Name WiFiSenseCredShared -Value $value        
        Add-RegistryDWord -Path "HKLM:\SOFTWARE\Microsoft\WcmSvc\wifinetworkmanager\features" -Name WiFiSenseOpen -Value $value        
    }

    Function SpyNet([bool]$enable){

        # Access to these registry keys are not allowed for administrators
        # so this does not work until we change those,
        # we give admins full permissions and after updating the values change it back.

        Test-Admin

$definition = @"
using System;
using System.Runtime.InteropServices;
namespace Win32Api
{
    public class NtDll
    {
        [DllImport("ntdll.dll", EntryPoint="RtlAdjustPrivilege")]
        public static extern int RtlAdjustPrivilege(ulong Privilege, bool Enable, bool CurrentThread, ref bool Enabled);
    }
}
"@

                 
        if (-not ("Win32Api.NtDll" -as [type])) 
        {
            Add-Type -TypeDefinition $definition -PassThru | out-null
        }
        else
        {
             ("Win32Api.NtDll" -as [type]) | Out-Null
        }
       
        $bEnabled = $false
        # Enable SeTakeOwnershipPrivilege
        $res = [Win32Api.NtDll]::RtlAdjustPrivilege(9, $true, $false, [ref]$bEnabled)

        $adminGroupSID = "S-1-5-32-544"

        $adminGroupName = (get-wmiobject -class "win32_account" -namespace "root\cimv2" | where-object{$_.sidtype -eq 4 -and $_.Sid -eq "$adminGroupSID"}).Name 

        # we take ownership from SYSTEM and I tried to give it back but that failed. I don't think that's a problem.
        $key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("SOFTWARE\Microsoft\Windows Defender\Spynet", [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::takeownership)
        $acl = $key.GetAccessControl()
        $acl.SetOwner([System.Security.Principal.NTAccount]$adminGroupName)
        $key.SetAccessControl($acl)

        $rule = New-Object System.Security.AccessControl.RegistryAccessRule ("$adminGroupName","FullControl","Allow")
        $acl.SetAccessRule($rule)
        $key.SetAccessControl($acl)

        if ($enable)
        {
            Add-RegistryDWord -Path "HKLM:\SOFTWARE\Microsoft\Windows Defender\Spynet" -Name "SpyNetReporting" -Value 2
            Add-RegistryDWord -Path "HKLM:\SOFTWARE\Microsoft\Windows Defender\Spynet" -Name "SubmitSamplesConsent" -Value 1 
        }
        else
        {
            Add-RegistryDWord -Path "HKLM:\SOFTWARE\Microsoft\Windows Defender\Spynet" -Name "SpyNetReporting" -Value 0    
            Add-RegistryDWord -Path "HKLM:\SOFTWARE\Microsoft\Windows Defender\Spynet" -Name "SubmitSamplesConsent" -Value 0                   
        }      

        # remove FUll Access ACE again
        $acl.RemoveAccessRule($rule) | Out-Null
        $key.SetAccessControl($acl)
     
    }

    Function Telemetry ([bool]$enable){

        Test-Admin

        # http://winaero.com/blog/how-to-disable-telemetry-and-data-collection-in-windows-10/
        # this covers Diagnostic and usage data in 'Feedback and diagnostics'
        if ($enable)
        {
            Set-service -Name DiagTrack -Status Running -StartupType Automatic
            if ((Get-Service | where Name -eq dmwappushservice).count -eq 1)
            {
                & sc.exe config dmwappushservice start= delayed-auto | Out-Null
                Set-service -Name dmwappushservice -Status Running
            }
            # just setting the value to zero did not do the trick.
            Remove-RegistryValue -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" -Name AllowTelemetry
        }
        else
        {            
            Stop-Service -Name DiagTrack -Force
            Set-service -Name DiagTrack -StartupType Disabled
            
            if((Get-Service | where Name -eq dmwappushservice).count -eq 1)
            {
                Stop-Service -Name dmwappushservice -Force
                Set-service -Name dmwappushservice -StartupType Disabled
            }

            Add-RegistryDWord -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" -Name AllowTelemetry -Value 0                      
        }
    }

    # ----------- Grouping Functions -----------

    Function Set-StrictPrivacyFeature([bool]$enable)
    {
        #enabled for -default, disabled for -strong and -balanced

        $AllowDeny = "Deny"
        $OnOff = 0      
        $OffOn = 1  
        
        if ($enable)
        {
            $AllowDeny = "Allow"
            $OnOff = 1
            $OffOn = 0
        }

        # General
        AdvertisingId -value $OnOff
        ImproveTyping -value $OnOff          
        # Location
        Location -value $AllowDeny
        # Camera
        Camera -value $AllowDeny
        # Microphone
        Microphone -value $AllowDeny
        # Speach, Inking, Typing
        SpeachInkingTyping -enable $enable
        # Account Info
        AccountInfo -value $AllowDeny
        # Contacts
        Contacts -value $AllowDeny
        # Calendar
        Calendar -value $AllowDeny
        # Messaging
        Messaging -value $AllowDeny
        # Radios
        Radios -value $AllowDeny
        # Other devices
        OtherDevices -value $AllowDeny
        # Feedback & diagnostics
        if ($enable)
        {
            FeedbackFrequency -value -1
        }
        else
        {
            FeedbackFrequency -value 0
        }

        # Edge

        DoNotTrack -value $OffOn
        SearchSuggestions -value $OnOff 
        PagePrediction -value $OnOff 
        PhishingFilter -value $OnOff 
        
    }

    Function Set-MiscPrivacyFeature([bool]$enable)
    {            
        #enabled for -default and -balanced disabled for -strong

        if ($enable)
        {
            SmartScreen -value 1
            LanguageList -value 0
        }
        else
        {
            SmartScreen -value 0
            LanguageList -value 1
        }
    }
    
}
Process
{
    
    $myOS = Get-CimInstance -ClassName Win32_OperatingSystem -Namespace root/cimv2 -Verbose:$false

    if ([int]$myOS.BuildNumber -lt 10240)
    {   
        Write-Warning "Your OS version is not supported, Windows 10 or higher is required" 
        Exit 101
    }

    $UserCurrent = [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $userIsAdmin = $false
    $UserCurrent.Groups | ForEach-Object { if($_.value -eq "S-1-5-32-544") {$userIsAdmin = $true} }

    if ($Admin)
    {        
        if ($Strong)
        {
            ShareUpdates -value 0
            WifiSense -value 0
            Telemetry -enable $false
            SpyNet -enable $false
        }
        if ($Balanced)
        {
            # allow LAN sharing of updates
            ShareUpdates -value 1
            WifiSense -value 0
            Telemetry -enable $false
            # in balanced mode, we don't disable SpyNet
            SpyNet -enable $true
        }
        if ($Default)
        {
            ShareUpdates -value 3
            WifiSense -value 1
            Telemetry -enable $true
            SpyNet -enable $true
        }

        Report
    }

    # this gets internal IDs for certain Apps like Cortana which we need in some functions
    Get-AppSID

    if ($Strong)
    {
        # turn off as much as we can
        Set-MiscPrivacyFeature -enable $false
        Set-StrictPrivacyFeature -enable $false        
        Report        
    }

    if ($Balanced)
    {
        Set-MiscPrivacyFeature -enable $true
        Set-StrictPrivacyFeature -enable $false
        
        Report        
    }

    if ($Default)
    {
        Set-MiscPrivacyFeature -enable $true
        Set-StrictPrivacyFeature -enable $true  
        Report
    }

    # handle specific features

    $AllowDeny = "Deny"
    $OnOff = 0
    $OffOn = 1   
    $DoEnable = $false  
        
    if ($Enable)
    {
        $AllowDeny = "Deny"
        $OnOff = 1
        $OffOn = 0
        $DoEnable = $true 
    }


    $Feature | ForEach-Object {

        switch ($_) 
            { 
                "AdvertisingId" {AdvertisingId -value $OnOff;break} 
                "ImproveTyping" {ImproveTyping -value $OnOff;break} 
                "Location" {Location -value $AllowDeny;break}
                "Camera" {Camera -value $AllowDeny;break} 
                "Microphone" {Microphone -value $AllowDeny;break} 
                "SpeachInkingTyping" {SpeachInkingTyping -enable $DoEnable;break} 
                "AccountInfo" {AccountInfo -value $AllowDeny;break} 
                "Contacts" {Contacts -value $AllowDeny;break} 
                "Calendar" {Calendar -value $AllowDeny;break} 
                "Messaging" {Messaging -value $AllowDeny;break} 
                "Radios" {Radios -value $AllowDeny;break} 
                "OtherDevices" {OtherDevices -value $AllowDeny;break} 
                "FeedbackFrequency" {
                        if ($Enable) {
                            FeedbackFrequency -value -1;
                        }
                        else
                        {
                            FeedbackFrequency -value 0;
                        }
                        break} 
                "ShareUpdates" {
                        if ($Enable) {
                            ShareUpdates -value 3;
                        }
                        else
                        {
                            ShareUpdates -value 0;
                        }
                        break}
                "WifiSense" {WifiSense -value $OnOff;break}                                                                    
                "Telemetry" {Telemetry -enable $DoEnable;break} 
                "SpyNet" {SpyNet -enable $DoEnable ;break}
                "DoNotTrack" {DoNotTrack -value $OffOn;break}  
                "SearchSuggestions" {SearchSuggestions -value $OnOff;break}  
                "PagePrediction" {PagePrediction -value $OnOff;break}  
                "PhishingFilter" {PhishingFilter -value $OnOff;break}  
                default {"ooops, nothing selected"}
            }
    }

}
End
{


}