#Requires -Version 5.1
<#
.SYNOPSIS
Disables AMD's process watcher for the currently installed display driver.
.DESCRIPTION
Resolves each present AMD PCI display device to its current display-class key
and service. No driver version, class instance number or service suffix is
hardcoded. Run again after driver updates, because AMD may create a new service.
Run in an elevated PowerShell. Use -WhatIf for read-only discovery.
Backups and results are saved under mem\amd-process-watcher beside this script.
The script never restarts Windows, Docker or the graphics device.
.EXAMPLE
.\DisableProcessWatcherSupport.ps1
.EXAMPLE
.\DisableProcessWatcherSupport.ps1 -WhatIf
#>
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='Medium')]
param()
$ErrorActionPreference='Stop'
$valueName='Gmx_MgpuProcessWatcherSupport'
$displayClass='{4d36e968-e325-11ce-bfc1-08002be10318}'
$principal=New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())
if(-not $WhatIfPreference -and -not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)){
throw 'Run this script in PowerShell as Administrator. Use -WhatIf for discovery without changes.'
}
# Device -> Enum\PCI binding -> current display-class instance -> active service.
# Enumerating service names alone would include obsolete driver installations.
$devices=@(Get-CimInstance Win32_PnPEntity -Filter "PNPClass = 'Display'" |
Where-Object {$_.PNPDeviceID -match '^PCI\\VEN_1002&' -and $_.Present -ne $false})
if(-not $devices.Count){throw 'No present AMD PCI display device was found.'}
$targets=@{}
foreach($device in $devices){
$enumKey='HKLM:\SYSTEM\CurrentControlSet\Enum\'+$device.PNPDeviceID
$binding=Get-Item -LiteralPath $enumKey
if([string]$binding.GetValue('ClassGUID') -ine $displayClass){throw ('Unexpected device class: '+$device.PNPDeviceID)}
$classReference=[string]$binding.GetValue('Driver')
if($classReference -notmatch ('^'+[regex]::Escape($displayClass)+'\\[0-9]+$')){
throw ('The display device has no valid current class-instance binding: '+$device.PNPDeviceID)
}
$classKey='HKLM:\SYSTEM\CurrentControlSet\Control\Class\'+$classReference
# Read only the needed values; unrelated AMD class values can have malformed
# registry types that make Get-ItemProperty over the entire key fail.
$class=Get-Item -LiteralPath $classKey
$provider=[string]$class.GetValue('ProviderName')
if($provider -notmatch 'AMD|Advanced Micro Devices'){
throw ('The active display driver is not supplied by AMD: '+$classKey)
}
$service=[string]$binding.GetValue('Service')
if($service -notmatch '^[a-zA-Z0-9_.-]+$'){throw 'The active AMD device has no valid service binding.'}
$serviceKey='HKLM:\SYSTEM\CurrentControlSet\Services\'+$service
$serviceInfo=Get-Item -LiteralPath $serviceKey
$imagePath=[string]$serviceInfo.GetValue('ImagePath')
if([string]::IsNullOrWhiteSpace($imagePath)){
throw ('The current AMD service has no driver image: '+$service)
}
if(-not $targets.ContainsKey($service)){
$targets[$service]=[ordered]@{
Service=$service;Key=$serviceKey+'\Parameters';Name=$valueName
ImagePath=$imagePath;Devices=@()
}
}
$targets[$service].Devices+=,[ordered]@{
Name=$device.Name;InstanceId=$device.PNPDeviceID;DisplayClassKey=$classKey
DriverVersion=[string]$class.GetValue('DriverVersion');InfPath=[string]$class.GetValue('InfPath')
ProviderName=$provider
}
}
$runDirectory=$null
$results=New-Object 'System.Collections.Generic.List[object]'
foreach($target in @($targets.Values|Sort-Object Service)){
Write-Host ('AMD service: '+$target.Service)
foreach($device in $target.Devices){Write-Host (' '+$device.Name+' -> '+$device.DisplayClassKey)}
if(-not $PSCmdlet.ShouldProcess(($target.Key+'\'+$valueName),'Set REG_DWORD to 0')){continue}
if(-not $runDirectory){
$runDirectory=Join-Path $PSScriptRoot ('mem\amd-process-watcher\'+[datetime]::UtcNow.ToString('yyyyMMdd-HHmmss-fff')+'-'+[guid]::NewGuid().ToString('N').Substring(0,8))
New-Item -ItemType Directory -Path $runDirectory -Force|Out-Null
}
$keyExists=Test-Path -LiteralPath $target.Key
$item=if($keyExists){Get-Item -LiteralPath $target.Key}else{$null}
$exists=$keyExists -and ($item.GetValueNames() -contains $valueName)
$before=[ordered]@{
Service=$target.Service;Key=$target.Key;Name=$valueName;KeyExisted=$keyExists
ValueExisted=$exists;Kind=$null;Value=$null;Devices=$target.Devices
ImagePath=$target.ImagePath;Utc=[datetime]::UtcNow.ToString('o')
}
if($exists){$before.Kind=$item.GetValueKind($valueName).ToString();$before.Value=$item.GetValue($valueName)}
$backup=Join-Path $runDirectory ($target.Service+'-before.json')
$before|ConvertTo-Json -Depth 7|Set-Content -LiteralPath $backup -Encoding UTF8
$result=[ordered]@{Service=$target.Service;Key=$target.Key;Name=$valueName;Kind='DWord';Value=0;Changed=$false;Verified=$false;Backup=$backup;Error=$null}
try{
if(-not ($exists -and $before.Kind -eq 'DWord' -and $before.Value -eq 0)){
if(-not $keyExists){New-Item -Path $target.Key -Force|Out-Null}
New-ItemProperty -LiteralPath $target.Key -Name $valueName -PropertyType DWord -Value 0 -Force|Out-Null
$result.Changed=$true
}
$after=Get-Item -LiteralPath $target.Key
if(-not ($after.GetValueNames() -contains $valueName) -or $after.GetValueKind($valueName).ToString() -ne 'DWord' -or $after.GetValue($valueName) -ne 0){
throw ('Registry verification failed: '+$target.Key)
}
$result.Verified=$true
Write-Host ('Verified REG_DWORD 0: '+$target.Key+'\'+$valueName)
}catch{$result.Error=$_.Exception.ToString();throw}
finally{
$results.Add([pscustomobject]$result)
$results|ConvertTo-Json -Depth 7|Set-Content -LiteralPath (Join-Path $runDirectory 'result.json') -Encoding UTF8
}
}
if($runDirectory){
Write-Host ('Backup and verification: '+$runDirectory)
Write-Host 'Restart Windows yourself to reload the driver setting. No restart was performed.'
$results
}