gamedvr-fso-disabler.ps1
|
<#PSScriptInfo .VERSION 1.0.1 .GUID 87a31f64-6a9a-4a19-8b74-4a634e74fb59 .AUTHOR vadyaravadim .COMPANYNAME .COPYRIGHT .TAGS Windows Windows10 Windows11 Gaming GameDVR GameBar FullscreenOptimizations FSO Performance Stutter Tweak Registry .LICENSEURI https://github.com/vadyaravadim/gamedvr-fso-disabler/blob/main/LICENSE .PROJECTURI https://github.com/vadyaravadim/gamedvr-fso-disabler .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .PRIVATEDATA #> <# .SYNOPSIS Disables Game DVR / Xbox Game Bar capture and Fullscreen Optimizations on Windows 10/11. .DESCRIPTION Turns off Game DVR (Game Bar background capture / recording) via the documented AllowGameDVR machine policy plus the per-user GameDVR values, and disables Fullscreen Optimizations globally via the GameConfigStore FSE values. A .reg undo file with the previous state of every value is written next to the script BEFORE any change. Zero external dependencies. .NOTES Sign out and back in (or reboot) for all changes to take effect. Revert: double-click the gamedvr_fso_undo_*.reg file, then sign out/in. Each undo file is a per-run snapshot (a run that changes nothing writes no undo file); after several runs, apply them newest-to-oldest - only the oldest file holds the original state. .EXAMPLE .\gamedvr-fso-disabler.ps1 Double-click Run.bat, or right-click this file > Run with PowerShell. No parameters needed - it elevates itself. .LINK https://github.com/vadyaravadim/gamedvr-fso-disabler #> [CmdletBinding()] param( [switch]$Elevated, # internal: set by the self-elevation relaunch [string]$UserSid # internal: SID of the pre-elevation user (HKCU hive target) ) $ErrorActionPreference = 'Stop' # Keep the self-elevated window open so the user can read the output. function Wait-IfElevatedWindow { if ($Elevated) { Read-Host "Press Enter to close" | Out-Null } } # Without this, an unhandled error closes the self-elevated window before # the user can read the message. trap { Write-Host "ERROR: $_" -ForegroundColor Red Wait-IfElevatedWindow # Under `irm | iex` this runs inside the user's own session, where `exit` # would close their console - rethrow so only the piped script stops. if ($PSCommandPath) { exit 1 } break } # Launched via `irm <url> | iex` - no file on disk. The undo .reg is written # next to the script, so a stable path is required: save the script to the # user profile (not TEMP - the undo file must survive automatic temp cleanup) # and rerun it from there (the rerun handles elevation). if (-not $PSCommandPath) { # The piped text is not recoverable from inside iex ($MyInvocation there # holds the caller's command line, not the script body) - download the # script. try { $body = Invoke-RestMethod 'https://raw.githubusercontent.com/vadyaravadim/gamedvr-fso-disabler/main/gamedvr-fso-disabler.ps1' -TimeoutSec 30 } catch { Write-Host "ERROR: could not download the script ($($_.Exception.Message)). Check your internet connection, or save the script to a file and run it from there." -ForegroundColor Red return } $saved = Join-Path $env:USERPROFILE 'gamedvr-fso-disabler.ps1' if ((Test-Path $saved) -and ([IO.File]::ReadAllText($saved) -cne $body)) { Copy-Item $saved "$saved.bak" -Force Write-Host "Existing $saved differs - previous copy kept as $saved.bak" -ForegroundColor Yellow } [IO.File]::WriteAllText($saved, $body, [Text.Encoding]::UTF8) Write-Host "Script saved to: $saved (the undo file will be written next to it)" -ForegroundColor Cyan powershell -NoProfile -ExecutionPolicy Bypass -File $saved # The rerun's exit code stays in $LASTEXITCODE for scripted callers. return } $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object Security.Principal.WindowsPrincipal($identity) if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Host "Not running as Administrator. Requesting elevation..." -ForegroundColor Yellow try { # Forward the launching user's SID: if UAC elevates to a DIFFERENT admin # account, HKCU in the elevated process is that admin's hive - the # per-user values would silently land in the wrong profile. $argList = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', "`"$PSCommandPath`"", '-Elevated', '-UserSid', $identity.User.Value) Start-Process -FilePath 'powershell.exe' -ArgumentList $argList -Verb RunAs } catch { # Not always a refusal (UAC service disabled, ...) - show the real cause. Write-Host "ERROR: elevation failed ($($_.Exception.Message)). Run this script as Administrator." -ForegroundColor Red Read-Host "Press Enter to close" | Out-Null } return } # Per-user values go to the pre-elevation user's hive when UAC switched accounts. if ($UserSid -and $UserSid -ne $identity.User.Value) { $hkcu = "Registry::HKEY_USERS\$UserSid" Write-Host "Elevated as a different account - per-user values go to the launching user's hive (HKEY_USERS\$UserSid)." -ForegroundColor Yellow Write-Host "NOTE: re-importing the undo file's HKEY_LOCAL_MACHINE section will also require admin rights." -ForegroundColor Yellow } else { $hkcu = 'HKCU:' } function ConvertTo-RawRegPath([string]$Path) { # Provider path -> raw path for the .reg format ($Path -replace '^Registry::', '') -replace '^HKCU:', 'HKEY_CURRENT_USER' -replace '^HKLM:', 'HKEY_LOCAL_MACHINE' } # .reg text for a value, preserving its original type: a foreign tweaker may # have left one of these as REG_SZ / QWORD / binary instead of the expected DWORD. function ConvertTo-RegValueText($Value) { if ($Value -is [int]) { return 'dword:{0:x8}' -f $Value } if ($Value -is [long]) { return 'hex(b):' + (([BitConverter]::GetBytes($Value) | ForEach-Object { '{0:x2}' -f $_ }) -join ',') } if ($Value -is [byte[]]) { return 'hex:' + (($Value | ForEach-Object { '{0:x2}' -f $_ }) -join ',') } if ($Value -is [string]) { return '"{0}"' -f ($Value -replace '\\', '\\' -replace '"', '\"') } throw "cannot snapshot a value of type $($Value.GetType().Name) into the undo file" } $gcs = "$hkcu\System\GameConfigStore" $dvr = "$hkcu\Software\Microsoft\Windows\CurrentVersion\GameDVR" $pol = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\GameDVR' # All values are DWORD. Grouped: Game DVR capture off, then Fullscreen Optimizations off. $tweaks = @( [PSCustomObject]@{ Path = $pol; Name = 'AllowGameDVR'; Value = 0; Label = 'Game Recording policy (machine-wide kill switch)' } [PSCustomObject]@{ Path = $dvr; Name = 'AppCaptureEnabled'; Value = 0; Label = 'Game Bar capture (recording, screenshots)' } [PSCustomObject]@{ Path = $dvr; Name = 'HistoricalCaptureEnabled'; Value = 0; Label = 'Background recording ("Record what happened")' } [PSCustomObject]@{ Path = $gcs; Name = 'GameDVR_Enabled'; Value = 0; Label = 'Game DVR (per-user toggle)' } [PSCustomObject]@{ Path = $gcs; Name = 'GameDVR_FSEBehaviorMode'; Value = 2; Label = 'Fullscreen Optimizations (2 = off)' } [PSCustomObject]@{ Path = $gcs; Name = 'GameDVR_HonorUserFSEBehaviorMode'; Value = 1; Label = 'Honor the FSE behavior set above' } [PSCustomObject]@{ Path = $gcs; Name = 'GameDVR_DXGIHonorFSEWindowsCompatible'; Value = 1; Label = 'Apply FSE behavior to DXGI (compat path)' } [PSCustomObject]@{ Path = $gcs; Name = 'GameDVR_EFSEFeatureFlags'; Value = 0; Label = 'Enhanced FSE features off' } ) Write-Host "" Write-Host "===================================" -ForegroundColor Cyan Write-Host " GAMEDVR + FSO DISABLER" -ForegroundColor Cyan Write-Host "===================================" -ForegroundColor Cyan Write-Host "" Write-Host "Current state -> target:" foreach ($t in $tweaks) { $old = (Get-ItemProperty -Path $t.Path -Name $t.Name -ErrorAction SilentlyContinue).($t.Name) # strict [int] check: a foreign REG_SZ '0' compares loosely equal to 0 # but must still be rewritten as a DWORD $ok = ($old -is [int]) -and ($old -eq $t.Value) $t | Add-Member NoteProperty Old $old $t | Add-Member NoteProperty Ok $ok $oldText = if ($null -eq $old) { '(absent)' } else { $old } $mark = if ($ok) { 'ok' } else { '->' } Write-Host (" [{0}] {1} = {2} -> {3} ({4})" -f $mark, $t.Name, $oldText, $t.Value, $t.Label) -ForegroundColor $(if ($ok) { 'DarkGray' } else { 'Yellow' }) } # Nothing to change -> no undo file: a repeat-run snapshot would record the # already-tweaked state, and double-clicking that newest file would silently # "revert" to it instead of the original. if (-not ($tweaks | Where-Object { -not $_.Ok })) { Write-Host "" Write-Host "All values already at target - nothing to do, no undo file written." -ForegroundColor Green Wait-IfElevatedWindow return } # Undo file: record the CURRENT state of every value BEFORE changing anything. # Double-clicking it reverts everything. Value-level on purpose: a "[-key]" # stanza would also wipe values this tool never wrote (bitrates, hotkeys, ...). # "=-" deletes a value that did not exist before; reg import may leave an # empty key behind, which is harmless. # The suffix loop keeps two runs within the same second from clobbering # each other's undo file. $stamp = Get-Date -Format 'yyyyMMdd_HHmmss' $undoFile = Join-Path $PSScriptRoot "gamedvr_fso_undo_$stamp.reg" $n = 1 while (Test-Path $undoFile) { $undoFile = Join-Path $PSScriptRoot ("gamedvr_fso_undo_{0}_{1}.reg" -f $stamp, $n++) } $undo = New-Object System.Text.StringBuilder [void]$undo.AppendLine('Windows Registry Editor Version 5.00') [void]$undo.AppendLine('') foreach ($group in ($tweaks | Group-Object Path)) { [void]$undo.AppendLine("[$(ConvertTo-RawRegPath $group.Name)]") foreach ($t in $group.Group) { if ($null -eq $t.Old) { [void]$undo.AppendLine(('"{0}"=-' -f $t.Name)) # value was absent -> delete it } else { [void]$undo.AppendLine(('"{0}"={1}' -f $t.Name, (ConvertTo-RegValueText $t.Old))) } } [void]$undo.AppendLine('') } Set-Content -Path $undoFile -Value $undo.ToString() -Encoding Unicode Write-Host "" Write-Host "Undo file saved: $undoFile" -ForegroundColor Cyan Write-Host "" Write-Host "Applying..." foreach ($t in $tweaks) { if (-not (Test-Path $t.Path)) { New-Item -Path $t.Path -Force | Out-Null # policy key does not exist by default } New-ItemProperty -Path $t.Path -Name $t.Name -Value $t.Value -PropertyType DWord -Force | Out-Null Write-Host (" [OK ] {0} = {1}" -f $t.Name, $t.Value) -ForegroundColor Green } Write-Host "" Write-Host "===================================" -ForegroundColor Cyan Write-Host " DONE" -ForegroundColor Cyan Write-Host "===================================" -ForegroundColor Cyan Write-Host "" Write-Host "Applied:" Write-Host " - Game DVR / Game Bar capture: DISABLED (policy + user values)" Write-Host " - Fullscreen Optimizations: DISABLED (globally, for this user)" Write-Host "" Write-Host "SIGN OUT and back in (or reboot) for all changes to take effect." -ForegroundColor Green Write-Host "Revert any time: double-click the undo file above, then sign out/in." -ForegroundColor DarkGray Wait-IfElevatedWindow |