How WSL Lets Linux and Windows Executables Call Each Other
The specific interop layer that lets a WSL shell launch Windows executables and Windows shells launch Linux commands, translating paths and streams both ways.
Running notepad.exe from a WSL Bash prompt and having it actually launch feels unremarkable once you’ve used WSL for a while — underneath, it’s bridging two completely different executable formats and process models, and that bridge is specifically engineered, not incidental.
The two directions of interop
Linux calling Windows (running notepad.exe, explorer.exe, or any other Windows binary from a WSL shell) and Windows calling Linux (running a WSL command directly from PowerShell or cmd.exe via wsl <command>) are both supported, and both go through distinct interop mechanisms rather than one unified layer.
How Linux-to-Windows execution actually works
When you run a .exe from inside WSL, the WSL interop layer recognizes the Windows PE (Portable Executable) binary format and hands the actual execution off to the Windows side — the process genuinely runs as a native Windows process, with WSL bridging the working directory, arguments, and standard input/output streams between the two environments.
How Windows-to-Linux execution actually works
The wsl command, run from PowerShell or cmd.exe, launches the specified command inside the WSL2 Linux environment and pipes its output back to the calling Windows shell — genuinely useful for scripting scenarios that need to combine Windows-native and Linux-native tools within the same script or pipeline.
What actually gets translated in both directions
Beyond just launching the correct binary, the interop layer handles translating file paths (/mnt/c/Users/... on the Linux side corresponding to C:\Users\... on the Windows side, using the filesystem bridge covered elsewhere), environment variables, and exit codes — enough plumbing that piping a Windows command’s output into a Linux tool, or vice versa, generally works the way you’d expect from either side alone.
The wslpath utility for path translation specifically
wslpath -w /mnt/c/Users/name/file.txt
# outputs: C:\Users\name\file.txt
wslpath -u 'C:\Users\name\file.txt'
# outputs: /mnt/c/Users/name/file.txt
Because scripts crossing the interop boundary frequently need to convert a path from one side’s format to the other’s explicitly, wslpath exists specifically for this — a small utility, but one that comes up constantly in any script mixing Windows and Linux tooling.
Why this interop can be selectively disabled
/etc/wsl.conf
[interop]
enabled = false
Some use cases (security-sensitive environments, or setups deliberately wanting strict isolation between the Windows host and the Linux environment) may want to disable this interop entirely — a configuration option Microsoft built in specifically because tight host integration isn’t universally desirable for every WSL use case.
Why this interop layer is the feature that makes WSL feel different from a “real” VM
A traditional virtual machine keeps the guest OS meaningfully isolated from the host by default — WSL’s interop layer is what makes it feel like Linux and Windows tools are part of one unified environment rather than two separate machines you have to deliberately bridge yourself, which is arguably the single biggest usability difference between WSL and running Linux in a conventional VM.
What actually happens to exit codes and standard streams
Beyond just launching the right binary, the interop layer propagates exit codes correctly across the boundary — a failing Windows command invoked from a Bash script reports its actual non-zero exit status back to the calling shell script, letting ordinary error-handling logic (if, &&, set -e) work the same way it would for a purely Linux-native command. Standard input, output, and error streams are piped across the boundary as well, which is what makes something like explorer.exe "$(wslpath -w .)" or piping a Windows command’s output into a Linux text-processing tool actually work as a single, composed pipeline rather than requiring separate, disconnected invocations.
A common point of confusion: which shell actually parses your quoting
Because a command crossing the interop boundary is ultimately parsed twice — once by the shell that invoked it, and potentially again by the target environment’s own command-line parsing rules — quoting and escaping that works perfectly for a purely Linux-side command can behave unexpectedly when the target is a Windows executable expecting Windows-style argument parsing conventions. Testing a cross-boundary command with a simple, unambiguous argument first, before relying on it with paths containing spaces or special characters, catches this class of quoting mismatch early rather than debugging a garbled argument deep inside a larger script.
Interop settings live in wsl.conf, per distribution
Interop behavior is configured per distribution, not globally, meaning two distributions on the same machine can have genuinely different interop policies:
# /etc/wsl.conf
[interop]
enabled = true
appendWindowsPath = true
appendWindowsPath controls whether Windows’s own PATH entries are appended to the distribution’s Linux PATH, which is what lets you type a Windows executable’s name directly without its full path in many default configurations — disabling it requires explicit full or relative paths for any Windows executable you invoke from that specific distribution instead.
Performance: interop calls aren’t free either
Launching a process across the interop boundary — either direction — carries more overhead than launching a native process within the same environment, since it involves the WSL platform layer coordinating process creation across the Windows/Linux boundary rather than a single environment’s ordinary process-spawn path. For a script calling a cross-boundary command occasionally, this is a non-issue; for a tight loop invoking a Windows executable from Linux (or vice versa) many times in rapid succession, this overhead can become a genuine, measurable performance factor worth designing around — batching work into fewer cross-boundary calls rather than one call per item, for instance.
Some environments deliberately disable appendWindowsPath or interop entirely — a security-conscious setup wanting a cleaner separation between Linux and Windows tooling, or simply avoiding accidental collisions between a Linux tool and a Windows tool that happen to share a name. Checking a distribution’s actual /etc/wsl.conf before assuming interop behaves identically to another machine avoids exactly this kind of surprise.
Checking a distribution’s actual interop settings before assuming they match another machine
cat /etc/wsl.conf
Reviewing this file directly, rather than assuming default interop behavior applies, is the fastest way to confirm whether a specific distribution has interop or appendWindowsPath explicitly disabled — a five-second check that avoids a much longer troubleshooting detour into “why doesn’t calling notepad.exe work on this machine when it works everywhere else.”
Related:
- How WSL Bridges Two Completely Different Filesystems
- WSLENV and Path Translation Across the Windows-Linux Process Boundary
Sources: