Skip to content

Instantly share code, notes, and snippets.

@Erquint
Created September 16, 2021 19:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Erquint/a1b89aab864c94dc468fd106c4c1ed15 to your computer and use it in GitHub Desktop.
Save Erquint/a1b89aab864c94dc468fd106c4c1ed15 to your computer and use it in GitHub Desktop.
This script will enumerate processes hogging DS4 device stream handle, try to free the handle by temporarily unloading known hogs detected running, start DS4W and load the unloaded hogs back.
# Ruby 2.6.6
# PowerShell 7.1
# SysInternals Handle 4.22
# DS4W 2.1.8
require 'set'
$task_heap = Set.new
if (ARGV & ['--help', '-h']).any?
puts "This script will enumerate processes hogging DS4 device stream handle,
try to free the handle by temporarily unloading known hogs detected running,
start DS4W and load the unloaded hogs back.
Commands (multiple allowed, combining isn't):
\e[33m--help\e[0m or \e[33m-h\e[0m To print this help message and unload.
\e[33m-nv-on\e[0m To start NvContainerLocalSystem service and unload.
\e[33m-nv-off\e[0m To stop NvContainerLocalSystem service before continuing.
\e[33m-s-on\e[0m To start Steam and unload.
\e[33m-s-off\e[0m To terminate Steam before continuing.
\e[33m--manual\e[0m or \e[33m-m\e[0m To only enumerage and unload. Overrides other commands.
\e[33m--quick\e[0m or \e[33m-q\e[0m To skip precautions."
return
end
if (ARGV & ['--manual', '-m']).any?
$task_heap.add ?m
else
if ARGV.include? '-nv-on'
load_nv
$task_heap.add ?l
elsif ARGV.include? '-nv-off'
unload_nv
end
if ARGV.include? '-s-on'
load_steam
$task_heap.add ?l
elsif ARGV.include? '-s-off'
unload_steam
end
if (ARGV & ['--quick', '-q']).any?
$task_heap.add ?W
else
$task_heap.add ?w
end
$task_heap.add ?e
end
def unload_steam
system 'powershell Stop-Process -Name "steam"'
end
def load_steam
system ('powershell Start-Process -FilePath ' + `powershell (Get-ItemProperty -Path "HKLM:\\SOFTWARE\\Wow6432Node\\Valve\\Steam").InstallPath`.chomp + '\steam.exe -ArgumentList "-silent"')
end
def unload_nv
system 'powershell Stop-Service "NvContainerLocalSystem"'
end
def load_nv
system 'powershell Start-Service "NvContainerLocalSystem"'
end
def load_ds4w
system ('powershell Start-Process -FilePath E:\Programs\Emulators\DS4Windows\DS4Windows.exe')
end
PS_script = "Get-PnpDevice -Class 'HIDClass' `
-InstanceId 'HID\\VID_054C&PID_0BA0*' -PresentOnly |
Get-PnpDeviceProperty -KeyName 'DEVPKEY_Device_PDOName' |
Select-Object -ExpandProperty 'Data' |
Format-Table -HideTableHeaders".gsub! /((?: `)?\n)/, ' '
def flush_bush string_bush
if string_bush[:branches].size > 0
puts string_bush[:root], string_bush[:branches]
if string_bush[:root].downcase.include? "steam"
$task_heap.add ?s
elsif string_bush[:root].downcase.include? "system"
$task_heap.add ?n
elsif string_bush[:root].downcase.include? "dwm"
$task_heap.add ?d
else
$task_heap.add ?p
end
end
end
def enumerate_hogging_processes
IO.popen('powershell -nologo', 'r+') do |stream|
stream.puts './handle64 -nobanner -a', 'Exit'
string_bush = {root: '', branches: []}
while in_line = stream.gets do
if !!(matches = /^(.+?) pid\: (\d+)/.match in_line)
# Process node
flush_bush string_bush
string_bush[:root] = in_line
string_bush[:branches] = []
elsif !!(matches = /^ +?(\w+?)\: File .*? (#{Regexp.quote(Device_handle)})/.match in_line)
# Device handle node
string_bush[:branches] << in_line
end
end
flush_bush string_bush
end
end
def process_task_heap
until $task_heap.empty?
if $task_heap.include? ?l
puts 'No enumeration after loading programs.'
$task_heap = $task_heap & [?S, ?N]
end
if $task_heap.include? ?m
puts 'Manual mode engaged. Enumerating only.'
$task_heap = [?e].to_set
end
if $task_heap.include? ?e
enumerate_hogging_processes
$task_heap.delete ?e
end
if $task_heap.include? ?p
puts 'Panic: not an automated case.'
return
end
if $task_heap.include? ?d
puts "Ignoring DWM. It doesn't tend to interfere."
$task_heap.delete ?d
end
if $task_heap.include? ?s
puts 'Temporarily unloading Steam.'
unload_steam
$task_heap.add ?S
$task_heap.delete ?s
end
if $task_heap.include? ?n
puts 'Temporarily unloading NvContainerLocalSystem.'
unload_nv
$task_heap.add ?N
$task_heap.delete ?n
end
if ($task_heap & [?w, ?W]).any?
puts 'Loading DS4W.'
load_ds4w
if $task_heap.include? ?w
puts 'Turn on the controller, switch back here and press [ENTER].',
'This is a precautionary measure.' ,
"If you are certain it isn't required — hit [ENTER] immediately.",
'We still might have temporarily-unloaded programs to load back up.'
system 'PAUSE'
end
$task_heap = $task_heap ^ ($task_heap & [?w, ?W])
end
if $task_heap.include? ?S
puts 'Loading Steam back.'
load_steam
$task_heap.delete ?S
elsif $task_heap.include? ?N
puts 'Loading NvContainerLocalSystem back.'
load_nv
$task_heap.delete ?N
end
end
end
IO.popen('powershell -nologo', 'r+') do |stream|
out_string = String.new
stream.puts PS_script, 'Exit'
while in_line = stream.gets do
out_string << in_line
end
Device_handle = out_string.split("\n")[-2]
end
puts 'Device handle: ' + Device_handle, 'Users:'
process_task_heap
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment