Skip to content

Instantly share code, notes, and snippets.

@kmobs
Last active June 6, 2026 16:43
Show Gist options
  • Select an option

  • Save kmobs/b0ccedd0340b34beafa9033f75a0d7c3 to your computer and use it in GitHub Desktop.

Select an option

Save kmobs/b0ccedd0340b34beafa9033f75a0d7c3 to your computer and use it in GitHub Desktop.
USB/IP for passing a Steam Controller 2 between Windows devices

Guide: Passing the Steam Controller 2 to a Sunshine Host via USB/IP (Windows to Windows)

I recently managed to get my Steam Controller seamlessly passed back and forth between my Windows Moonlight client and my Windows Sunshine host. While this is arguably easier with a Linux client, I don't want my Moonlight PC running Linux right now.

Why not VirtualHere? I have no problem paying $50 for good software, but I don't like their licensing practices—specifically, the fact that the license isn't easily transferable between devices.

If you want a free, network-based USB passthrough solution for the SC2, here is my process using usbip-win2, usbipd-win, and OpenSSH.

Prerequisites

  1. OpenSSH: You'll need an OpenSSH server running on the Moonlight client and an OpenSSH client on the Sunshine server, configured with key-based authentication. I won't detail that here, but there are plenty of guides online.
  2. USB/IP Tools:

Step 1: Initial Installation

Note: In this network topology, the Moonlight PC acts as the USB/IP Server (because the controller puck is physically plugged into it), and the Sunshine PC acts as the USB/IP Client.

  1. On the Moonlight PC (Client): Install both usbipd-win and usbip-win2.
  2. On the Sunshine PC (Host): Install just usbip-win2.

Step 2: Binding the Controller on the Moonlight PC

First, you need to bind the SC2 puck to the USB/IP server. Open a terminal as Administrator on the Moonlight PC and run:

usbipd bind --force --busid=<BUSID>

(Replace <BUSID> with the actual Bus ID of your controller puck).

This forces a stubbed attachment, which makes the Steam Controller temporarily inaccessible on the Moonlight client. This is necessary because otherwise, the local Steam instance will aggressively grab the controller and refuse to release it.

To actually use the controller locally on the Moonlight PC, you then connect to it using usbip-win2 locally. You will need to use Task Scheduler to automate this local connection at boot; otherwise, the controller will remain in a stubbed state.

Step 3: Sunshine Command Automation

Now, set up the scripts on the Sunshine Server to handle the handoff automatically when you start and stop a stream. Add these to your Sunshine app configuration as "Do" and "Undo" commands.

(Note: Change ipaddr to your Moonlight PC's IP address, user to your SSH user, and bus-id to your controller's Bus ID).

Do Command (Start Stream): This tells the Moonlight client to release the device, then attaches it to the Sunshine server.

ssh user@ipaddr "cmd /c \"\"C:\Program Files\USBip\usbip.exe\" detach -a\""
timeout /t 2 /nobreak >nul
"C:\Program Files\USBip\usbip.exe" attach -r ipaddr -b bus-id --once
exit /b 0

Undo Command (End Stream): This detaches the controller from the Sunshine server and tells the Moonlight client to grab it back.

@echo off
"C:\Program Files\USBip\usbip.exe" detach -a
timeout /t 2 /nobreak >nul
ssh user@ipaddr "cmd /c \"\"C:\Program Files\USBip\usbip.exe\" attach -r ipaddr -b bus-id\""
exit /b 0

Drawbacks

There are two minor caveats to this method:

  1. Device Desync: You might end up in a state where the controller is connected to the wrong device (though this hasn't happened to me yet).
  2. Wake from Controller: You lose the ability to wake the PC using the Steam Controller. This hasn't worked reliably for me anyway, so it's not a major loss.

Other notes

SISR didn't work reliably for me in the way that I wanted. You may be able to avoid doing a forced connection on the moonlight client if you don't want steam running on the moonlight client

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment