0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WSL2からのUSBデバイス接続(USB-IPD)を自動化するPythonスクリプト

Last updated at Posted at 2026-01-06

はじめに

Windowsで組み込み開発をするとき、どうしてもLinuxが必要になることがあるとおもいます。

こちらの記事にある通り、USB-IPD Winを使えばいけます。

usbipd list # usb deviceリスト取得
usbipd attach --busid 2-4 # attach, 管理者権限必要
usbipd bind --busid 2-4 # WSLにbind

が、毎回コマンドを打つのが面倒です。

特に何回も抜き差ししたり、Rebootを繰り返すと、とても面倒です。

というわけで自動化するPythonスクリプトを作ってみました。

スクリプトの使い方

Powershellから下記のようにコマンドを叩くと

usbipd list

下記のように、VID:PIDが出てきます。

Connected:
BUSID  VID:PID    DEVICE                          STATE
2-4    2fe3:0100  USB シリアル デバイス (COM5)     Shared 

その中から、WSL2に自動で接続させたいデバイスをスクリプトの中の、

conditions = [
    ["2fe3:0100"],  # USB-CDC
]

の部分に記載します。

デスクトップに*.pyとして保存し、必要な時にダブルクリックして実行すればOKです。

bindが必要なときは管理者権限を要求しますのでOKしてください。

*ちなみに、上記のVID:PIDはZephyr RTOSのデフォルトのものです。
 こちらの記事で使いました。(宣伝)

スクリプト本体

内容としては、無限ループして該当するbus-idのデバイスにbind/attachするだけです。

"""usbipd_attacher.py."""

import subprocess
import time
import ctypes
from ctypes import windll

"""
Run this script on Windows to automatically attach USB serial devices to WSL.
It uses usbipd-win.
"""

# Define the target USB devices (VendorID:ProductID)
conditions = [
    ["2fe3:0100"],  # Example: USB-CDC
]

# Define excluded bus IDs if necessary
exclude_conditions_bus = []

# Input host IP address if you need to specify host address manually
host_ip = ""


def run_command_as_admin(executable, arguments):
    """
    Execute a command with Administrator privileges using ShellExecuteW.
    This triggers the UAC prompt.
    """
    # 1 = SW_SHOWNORMAL (Show window normally)
    # 0 = SW_HIDE (Hide window - useful if you don't want to see the popup console)
    ret = windll.shell32.ShellExecuteW(
        None, "runas", executable, arguments, None, 1
    )
    return ret > 32  # Returns True if execution was successful (started)


print("Starting usbipd auto-attacher...")

i = 0
while True:
    # Get the list of usbipd devices
    try:
        ret = subprocess.run(["usbipd", "list"], capture_output=True)
        strs = ret.stdout.decode("utf-8")
    except FileNotFoundError:
        print("Error: 'usbipd' command not found. Please install usbipd-win.")
        time.sleep(5)
        continue

    # Initialize exclusion list
    bus_is_excluded = [False] * 20
    
    # Print list periodically for monitoring
    if i % 5 == 0:
        print("")
        print("-------------------- usbipd list -----------------")
        print(strs)
    
    lines = strs.split("\n")
    
    # Update exclusion list based on bus IDs
    for s in lines:
        try:
            for c in exclude_conditions_bus:
                if c in s:
                    # Parse bus ID (assumes single digit for simplicity, adjust if needed)
                    bus_idx = int(s.strip().split(" ")[0].split("-")[0])
                    bus_is_excluded[bus_idx] = True
        except Exception:
            pass

    # Check devices and perform Bind/Attach
    for s in lines:
        try:
            if not s or len(s.split(" ")) < 1:
                continue

            # Parse bus ID to check exclusion
            try:
                # Extracts "1" from "1-2"
                bus_id_str = s.strip().split(" ")[0]
                bus_root = int(bus_id_str.split("-")[0])
                if bus_is_excluded[bus_root]:
                    continue
            except:
                pass # Skip if parsing fails (headers, etc.)

        except Exception:
            continue

        # Check against target conditions
        for cond in conditions:
            is_ok = True
            for c in cond:
                if c not in s:
                    is_ok = False
            
            if not is_ok:
                continue

            # --- Bind Logic (Requires Admin) ---
            if "Not shared" in s:
                print(f"[Action Required] Binding device: {s.strip()}")
                device_id = s.split(" ")[0]
                
                # Execute 'usbipd bind' with Admin privileges
                success = run_command_as_admin("usbipd", f"bind --busid {device_id}")
                
                if success:
                    print("  -> Admin prompt triggered. Waiting for bind to complete...")
                    # Wait for the user to click "Yes" and the bind to finish
                    time.sleep(3) 
                else:
                    print("  -> Failed to trigger admin prompt.")

            # --- Attach Logic (Runs as current user) ---
            elif "Shared" in s:
                # Check if already attached (Depends on usbipd version output)
                if "Attached" in s:
                    continue

                print(f"[Action Required] Attaching device: {s.strip()}")
                device_id = s.split(" ")[0]
                
                cmd = ["usbipd", "attach", "--wsl", "--busid", device_id]
                if host_ip != "":
                    cmd.append("--host-ip")
                    cmd.append(host_ip)
                
                # Run attach command (standard subprocess is usually sufficient for attach)
                subprocess.run(cmd)

    time.sleep(1)
    i += 1
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?