Dev Investigation Notes

When launching Python with PowerShell Start-Process gives unrecognized arguments, but a bat file works fine

This is a translated article. Read the original in Korean ↗

I was building a local voice assistant (voice-assistant) that stays running on Windows, transcribes speech when it hears a wake word, and reads its answers aloud. The assistant wasn't running after boot, so I tried launching pythonw directly from PowerShell to investigate. That produced error: unrecognized arguments: USB Audio. But launching it through the usual bat file worked fine with the same arguments.

Conclusion

When you pass an argument containing spaces, such as --device "KT USB Audio", through Start-Process -ArgumentList, the quotes can disappear. Python then receives the command line --device KT USB Audio. argparse takes only KT as the value of --device, rejects the remaining USB Audio as unrecognized arguments, and exits . This isn't a bug in the program or the bat file: it's a quoting bug in the command entered for testing .

How to identify it and fix it:

# 1) Check whether this is a false lead — run the actual launch path (bat) as-is
cmd /c path\to\start_assistant.bat

# 2) If you must use Start-Process: wrap the value containing spaces in an extra pair of quotes
Start-Process pythonw -ArgumentList 'main.py', '--device', '"KT USB Audio"'
#   Or pass the entire command line as a single string
Start-Process pythonw -ArgumentList 'main.py --device "KT USB Audio"'

# 3) If you don't need a new window: use the call operator (&). It handles quoting for each argument
& .\venv\Scripts\python.exe main.py --device "KT USB Audio"

(The bat path and main.py are examples. The session output doesn't preserve the exact test command .)

Situation

This voice assistant runs in the background without a console window, using the venv's pythonw.exe . Its automatic startup path is VoiceAssistant.lnk in the Startup folder → start_assistant_hidden.vbs → bat → pythonw . The microphone device name is passed as the command-line argument --device "KT USB Audio" . The two spaces in that device name are the key to this incident.

The investigation proceeded by running commands one at a time in a PowerShell shell .

Symptom

That last error seemed to explain perfectly why it died only through the pythonw path. Initially, it was treated as a "decisive clue" .

Cause

Start-Process joins the array elements passed to -ArgumentList with spaces to form a single command-line string. It doesn't automatically quote elements that contain spaces. This behavior has long been noted in an issue in the official PowerShell documentation repository (MicrosoftDocs/PowerShell-Docs#7701) and a PowerShell issue (PowerShell/PowerShell#5576). Windows processes receive the command line as a single string, and Python splits that string back up based on spaces and quotes to build sys.argv. Without the quotes, KT, USB, and Audio become separate arguments.

In the bat file, on the other hand, --device "KT USB Audio" is written with the quotes intact, so cmd passes it along as-is. Running the actual bat file with cmd /c left the command running for over 40 seconds. Because cmd waits for the pythonw launched by the bat file to exit, blocking like this meant pythonw was still alive . Checking from a separate shell confirmed that it had started normally through the bat path and reached "준비 완료. Hey Jarvis" (Ready. Hey Jarvis) .

In other words, the argparse error was a new bug introduced because the launch path created to reproduce the problem differed from the original path .

Fix

There was nothing to fix in the program or the bat file. The testing method changed.

Before (quotes disappear):

Start-Process pythonw -ArgumentList 'main.py', '--device', 'KT USB Audio'
# Command line Python receives: main.py --device KT USB Audio
# → error: unrecognized arguments: USB Audio

After:

Start-Process pythonw -ArgumentList 'main.py', '--device', '"KT USB Audio"'
# Command line Python receives: main.py --device "KT USB Audio"

(Both examples were reconstructed from the documented behavior. They are not the exact commands entered during this session.)

Bonus — removing this quoting bug still left the boot problem

Once the quoting bug was removed, the code, bat file, and device recognition were all confirmed to work normally . But the reason it hadn't started at boot was never established in this session. The last log entry was from August 23, with no entries after that day's boot, so the investigation got only as far as observing that automatic startup hadn't run at all on this boot . The shell used for the investigation also cleaned up its child processes when the invocation ended, producing another false failure that looked like "it starts, then dies" . The lesson is the same. When the reproduction path used for debugging differs from the actual launch path, that difference creates new symptoms.

Reporter's Notes — the error message was too convincing

Park Doeun
You know that voice assistant on Windows that answers when it hears the wake word? After a reboot, it isn't running in the background. The shortcut is still in the Startup folder, but there isn't a single pythonw process
Jung Bada
Isn't the code dying as soon as it starts? If the shortcut is fine but there's no process, the most natural explanation is that it started and immediately died.
Jung Haneul
Then let's run it directly with the console python.exe, where we can see errors on-screen, instead of the windowless pythonw. If it dies there too, it's a code problem.
Park Doeun
Running it in the console picks up the microphone device and gets all the way to "준비 완료" (Ready) just fine. But launching it through the usual bat and vbs path still gives us nothing after 25 seconds
Jung Haneul
So it isn't the code. The remaining difference is launching with pythonw. We'll need to isolate that path.

They try launching pythonw directly with Start-Process in PowerShell, passing the device argument.

Park Doeun
Something came up! Actually, it's an error. error: unrecognized arguments: USB Audio
Jung Bada
That's it. The device name is KT USB Audio, so it contains spaces. The argument splits at those spaces, and argparse, which reads the command-line arguments, takes only KT as the device name and dies because it doesn't recognize USB Audio
Park Dohyun
The explanation is right. But what split it? The bat file should have the quotes in place. It could be the command we just reconstructed in PowerShell that split it.
Jung Haneul
That's easy to distinguish. Let's run the actual bat file as-is with cmd /c instead of reconstructing it in PowerShell. If we get the same error there, it's the bat file. If we don't, it's our test command.
Park Doeun
I ran it with cmd /c, but the command still hasn't finished after more than 40 seconds. No error either. It's just sitting there
Jung Bada
If it's stuck, doesn't that mean something else is blocking it there?
Jung Haneul
The opposite. cmd waits for the pythonw launched by the bat file to exit. If it hasn't finished, that means pythonw is alive and running. Check from another window
Park Doeun
Confirmed. Through the bat path, it reached "준비 완료. Hey Jarvis" (Ready. Hey Jarvis) and is waiting for the wake word
Jung Haneul
That settles it. The bat file was passing the arguments correctly, quotes and all. unrecognized arguments was a quoting bug in our Start-Process command, so we can rule it out as a candidate for the real cause
Park Dohyun
Start-Process -ArgumentList just joins the argument array with spaces. It doesn't automatically quote values that contain spaces. So you need to wrap the value in another pair of quotes, like '"KT USB Audio"', or run it with the & call operator.
Jung Bada
The error message fit the symptoms so well that I took it at face value. It seemed like the perfect explanation for why it failed only through the pythonw path.
Park Dohyun
The more convincing a clue looks, the more you need to check which path produced it first. This error came from the new path we built to reproduce the problem, rather than the original launch path.
Park Doeun
Then what happened when it didn't show up for 25 seconds through bat and vbs at the start? We used the bat file then too.
Jung Haneul
That was likely on our side too. The shell we were investigating from cleaned up the child processes it launched when the invocation ended. When we launched it outside that shell, it stayed alive for the full 30 seconds
Park Dohyun
So we had two layers of false failures. Did we solve the real question, then: why it didn't start at boot?
Park Doeun
No. Even after removing the quoting problem, we never pinned down why it didn't start at boot. There wasn't a single log line after this boot, so all we established was that automatic startup hadn't run at all
Jung Haneul
We did confirm that the code, bat file, and device recognition all work normally. At least we stopped ourselves from chasing a false lead and tearing apart a perfectly good bat file
Park Dohyun
If a reproduction command built for debugging differs from the original launch path by even one character, that difference creates a new bug. When a strange error appears, the first thing to do is run the original path exactly as-is.