Native Execution Wrappers
Relevant source files
The following files were used as context for generating this wiki page:
- src/System.Management.Automation/engine/NativeCommandProcessor.cs
- src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs
- test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1
- src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
- test/powershell/Language/Scripting/NativeExecution/NativeStreams.Tests.ps1
- tools/buildCommon/startNativeExecution.ps1
Native Execution Wrappers in PowerShell provide the architectural bridge between the PowerShell engine and external binary executables. These wrappers manage the lifecycle of native processes, including argument passing, standard input/output (I/O) redirection, character encoding, and process tree termination. By encapsulating these operations, PowerShell ensures that external applications behave consistently with internal cmdlets within a pipeline.
The primary component responsible for this integration is the NativeCommandProcessor, which handles the complexities of starting processes across different platforms (Windows, Linux, macOS) while maintaining PowerShell's high-level abstractions for data streams and error handling.
Core Architecture and Process Lifecycle
The lifecycle of a native command execution involves several stages: preparation, process initialization, asynchronous I/O handling, and completion.
Process Initialization
Initialization is handled via InitNativeProcess, which determines whether a process should run "standalone" or with redirected streams. Standalone mode is typically used when a native command is the sole element in a pipeline and doesn't require PowerShell to capture its output.
The system uses System.Diagnostics.ProcessStartInfo to configure the environment, including the working directory and environment variables. If a command is part of a pipeline, PowerShell redirects StandardOutput, StandardError, and StandardInput to communicate with the process.
Sources: src/System.Management.Automation/engine/NativeCommandProcessor.cs:511-540, src/System.Management.Automation/engine/NativeCommandProcessor.cs:646-680
Stream Redirection and Object Marshaling
PowerShell translates native text streams into PowerShell objects. ProcessOutputHandler manages this by reading data from the process and adding it to a BlockingCollection<ProcessOutputObject>.
| Stream Type | PowerShell Handling | Logic Source |
|---|---|---|
| StdOut | Converted to strings and written to the success stream. | src/System.Management.Automation/engine/NativeCommandProcessor.cs:1520-1530 |
| StdErr | Wrapped in ErrorRecord objects; first line becomes a NativeCommandError. | src/System.Management.Automation/engine/NativeCommandProcessor.cs:1544-1560 |
| CliXml | Deserialized into complex objects if the #< CLIXML tag is detected. | src/System.Management.Automation/engine/NativeCommandProcessor.cs:1568-1580 |
Argument Passing and Legacy Support
PowerShell supports multiple styles of passing arguments to native applications, primarily controlled by the $PSNativeCommandArgumentPassing preference variable.
Argument Passing Styles
- Standard/Standardized: Uses a list-based approach (
ArgumentList) to avoid shell injection and quoting issues on Unix-like systems. - Windows/Legacy: Reverts to a single string-based approach (
Arguments) for specific Windows executables that handle quoting non-standardly (e.g.,cmd.exe,find.exe,.batfiles).
Process Management Cmdlets
The Microsoft.PowerShell.Commands.Management namespace provides cmdlets that wrap lower-level process management functions. These cmdlets interact with the NativeCommandProcessor to manipulate processes by name, ID, or object reference.
Key Management Classes
ProcessBaseCommand: An abstract base class providing process selection modes (ByName,ById,ByInput) and idempotent selection logic.GetProcessCommand: Retrieves process information, optionally including modules and file version info.StopProcessCommand: Terminates processes. On Windows, it handles elevated process termination and dependent service management (e.g., forsvchost.exe).StartProcessCommand: Direct wrapper for creating new processes with support for credentials, environment variables, and window styles.
Sources: src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs:23-55, src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs:725-750
Error Handling and Exit Codes
Native execution wrappers track process termination to set automatic variables and handle errors based on user preference.
Exit Code Mapping
Upon process completion, the exit code is assigned to the $LASTEXITCODE variable. If $PSNativeCommandUseErrorActionPreference is set to $true, a non-zero exit code triggers a NativeCommandExitException.
Pipeline Interaction and Blocking
Native wrappers are designed to prevent blocking in multi-stage pipelines. The NativeCommandProcessor uses asynchronous reading to ensure that native | ps_cmdlet | native pipelines function without deadlocking, even when the intermediate PowerShell cmdlet processes data slower than the native source produces it.
Tests confirm that native processes are killed when the pipeline is disposed, preventing "zombie" processes from persisting after a PowerShell command is stopped or timed out.
Sources: test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1:35-50, src/System.Management.Automation/engine/NativeCommandProcessor.cs:835-860
Summary
Native Execution Wrappers enable PowerShell to act as a powerful coordinator for external tools. By managing cross-platform process creation, implementing sophisticated argument passing logic, and marshaling unstructured text into structured objects, these wrappers allow native binaries to integrate seamlessly into the PowerShell object-based pipeline while providing robust error and lifecycle management.