我想从在 Powershell 脚本中启动的进程中捕获 stdout 和 stderr 并将其异步显示到控制台。我通过 MSDN 和其他博客找到了一些有关执行此操作的文档。
创建并运行下面的示例后,我似乎无法异步显示任何输出。所有输出仅在进程终止时显示。
$ps = new-object System.Diagnostics.Process
$ps.StartInfo.Filename = "cmd.exe"
$ps.StartInfo.UseShellExecute = $false
$ps.StartInfo.RedirectStandardOutput = $true
$ps.StartInfo.Arguments = "/c echo `"hi`" `& timeout 5"
$action = { Write-Host $EventArgs.Data }
Register-ObjectEvent -InputObject $ps -EventName OutputDataReceived -Action $action | Out-Null
$ps.start() | Out-Null
$ps.BeginOutputReadLine()
$ps.WaitForExit()
在这个例子中,我期望在程序执行结束之前在命令行上看到“hi”的输出,因为 OutputDataReceived 事件应该已经被触发。
我已经尝试过使用其他可执行文件 - java.exe、git.exe 等。它们都具有相同的效果,所以我认为有一些简单的东西我不理解或错过了。异步读取 stdout 还需要做什么?
不幸的是,如果你想正确地进行异步读取,那么异步读取并不那么容易。如果您在没有超时的情况下调用 WaitForExit(),您可以使用我编写的类似函数(基于 C# 代码):
function Invoke-Executable {
# Runs the specified executable and captures its exit code, stdout
# and stderr.
# Returns: custom object.
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]$sExeFile,
[Parameter(Mandatory=$false)]
[String[]]$cArgs,
[Parameter(Mandatory=$false)]
[String]$sVerb
)
# Setting process invocation parameters.
$oPsi = New-Object -TypeName System.Diagnostics.ProcessStartInfo
$oPsi.CreateNoWindow = $true
$oPsi.UseShellExecute = $false
$oPsi.RedirectStandardOutput = $true
$oPsi.RedirectStandardError = $true
$oPsi.FileName = $sExeFile
if (! [String]::IsNullOrEmpty($cArgs)) {
$oPsi.Arguments = $cArgs
}
if (! [String]::IsNullOrEmpty($sVerb)) {
$oPsi.Verb = $sVerb
}
# Creating process object.
$oProcess = New-Object -TypeName System.Diagnostics.Process
$oProcess.StartInfo = $oPsi
# Creating string builders to store stdout and stderr.
$oStdOutBuilder = New-Object -TypeName System.Text.StringBuilder
$oStdErrBuilder = New-Object -TypeName System.Text.StringBuilder
# Adding event handers for stdout and stderr.
$sScripBlock = {
if (! [String]::IsNullOrEmpty($EventArgs.Data)) {
$Event.MessageData.AppendLine($EventArgs.Data)
}
}
$oStdOutEvent = Register-ObjectEvent -InputObject $oProcess `
-Action $sScripBlock -EventName 'OutputDataReceived' `
-MessageData $oStdOutBuilder
$oStdErrEvent = Register-ObjectEvent -InputObject $oProcess `
-Action $sScripBlock -EventName 'ErrorDataReceived' `
-MessageData $oStdErrBuilder
# Starting process.
[Void]$oProcess.Start()
$oProcess.BeginOutputReadLine()
$oProcess.BeginErrorReadLine()
[Void]$oProcess.WaitForExit()
# Unregistering events to retrieve process output.
Unregister-Event -SourceIdentifier $oStdOutEvent.Name
Unregister-Event -SourceIdentifier $oStdErrEvent.Name
$oResult = New-Object -TypeName PSObject -Property ([Ordered]@{
"ExeFile" = $sExeFile;
"Args" = $cArgs -join " ";
"ExitCode" = $oProcess.ExitCode;
"StdOut" = $oStdOutBuilder.ToString().Trim();
"StdErr" = $oStdErrBuilder.ToString().Trim()
})
return $oResult
}
它捕获标准输出、标准错误和退出代码。用法示例:
$oResult = Invoke-Executable -sExeFile 'ping.exe' -cArgs @('8.8.8.8', '-a')
$oResult | Format-List -Force
有关更多信息和替代实现(C# 语言),请通过 archive.org 或 archive.is 阅读此博客文章。
基于 Alexander Obersht 的回答 我创建了一个使用超时和异步任务类而不是事件处理程序的函数。 根据迈克阿德尔森
不幸的是,这个方法(事件处理程序)无法提供知道 当最后一位数据被接收时。因为一切都是 异步,事件有可能(并且我已经观察到这一点) WaitForExit() 返回后触发。
function Invoke-Executable {
# from https://stackoverflow.com/a/24371479/52277
# Runs the specified executable and captures its exit code, stdout
# and stderr.
# Returns: custom object.
# from http://www.codeducky.org/process-handling-net/ added timeout, using tasks
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String]$sExeFile,
[Parameter(Mandatory=$false)]
[String[]]$cArgs,
[Parameter(Mandatory=$false)]
[String]$sVerb,
[Parameter(Mandatory=$false)]
[Int]$TimeoutMilliseconds=1800000 #30min
)
Write-Host $sExeFile $cArgs
# Setting process invocation parameters.
$oPsi = New-Object -TypeName System.Diagnostics.ProcessStartInfo
$oPsi.CreateNoWindow = $true
$oPsi.UseShellExecute = $false
$oPsi.RedirectStandardOutput = $true
$oPsi.RedirectStandardError = $true
$oPsi.FileName = $sExeFile
if (! [String]::IsNullOrEmpty($cArgs)) {
$oPsi.Arguments = $cArgs
}
if (! [String]::IsNullOrEmpty($sVerb)) {
$oPsi.Verb = $sVerb
}
# Creating process object.
$oProcess = New-Object -TypeName System.Diagnostics.Process
$oProcess.StartInfo = $oPsi
# Starting process.
[Void]$oProcess.Start()
# Tasks used based on http://www.codeducky.org/process-handling-net/
$outTask = $oProcess.StandardOutput.ReadToEndAsync();
$errTask = $oProcess.StandardError.ReadToEndAsync();
$bRet=$oProcess.WaitForExit($TimeoutMilliseconds)
if (-Not $bRet)
{
$oProcess.Kill();
# throw [System.TimeoutException] ($sExeFile + " was killed due to timeout after " + ($TimeoutMilliseconds/1000) + " sec ")
}
$outText = $outTask.Result;
$errText = $errTask.Result;
if (-Not $bRet)
{
$errText =$errText + ($sExeFile + " was killed due to timeout after " + ($TimeoutMilliseconds/1000) + " sec ")
}
$oResult = New-Object -TypeName PSObject -Property ([Ordered]@{
"ExeFile" = $sExeFile;
"Args" = $cArgs -join " ";
"ExitCode" = $oProcess.ExitCode;
"StdOut" = $outText;
"StdErr" = $errText
})
return $oResult
}
我无法让这些示例与 PS 4.0 一起使用。
我想从 Octopus Deploy 包运行
puppet apply
(通过 Deploy.ps1
)并“实时”查看输出,而不是等待该过程完成(一个小时后),所以我想出了以下方法:
# Deploy.ps1
$procTools = @"
using System;
using System.Diagnostics;
namespace Proc.Tools
{
public static class exec
{
public static int runCommand(string executable, string args = "", string cwd = "", string verb = "runas") {
//* Create your Process
Process process = new Process();
process.StartInfo.FileName = executable;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
//* Optional process configuration
if (!String.IsNullOrEmpty(args)) { process.StartInfo.Arguments = args; }
if (!String.IsNullOrEmpty(cwd)) { process.StartInfo.WorkingDirectory = cwd; }
if (!String.IsNullOrEmpty(verb)) { process.StartInfo.Verb = verb; }
//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
//* Start process and handlers
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
//* Return the commands exit code
return process.ExitCode;
}
public static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) {
//* Do your stuff with the output (write to console/log/StringBuilder)
Console.WriteLine(outLine.Data);
}
}
}
"@
Add-Type -TypeDefinition $procTools -Language CSharp
$puppetApplyRc = [Proc.Tools.exec]::runCommand("ruby", "-S -- puppet apply --test --color false ./manifests/site.pp", "C:\ProgramData\PuppetLabs\code\environments\production");
if ( $puppetApplyRc -eq 0 ) {
Write-Host "The run succeeded with no changes or failures; the system was already in the desired state."
} elseif ( $puppetApplyRc -eq 1 ) {
throw "The run failed; halt"
} elseif ( $puppetApplyRc -eq 2) {
Write-Host "The run succeeded, and some resources were changed."
} elseif ( $puppetApplyRc -eq 4 ) {
Write-Warning "WARNING: The run succeeded, and some resources failed."
} elseif ( $puppetApplyRc -eq 6 ) {
Write-Warning "WARNING: The run succeeded, and included both changes and failures."
} else {
throw "Un-recognised return code RC: $puppetApplyRc"
}
归功于 T30 和 Stefan Goßner
这里的示例都很有用,但并不完全适合我的用例。我不想调用命令并退出。我想打开命令提示符,发送输入,读取输出,然后重复。这是我的解决方案。
创建Utils.CmdManager.cs
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
namespace Utils
{
public class CmdManager : IDisposable
{
const int DEFAULT_WAIT_CHECK_TIME = 100;
const int DEFAULT_COMMAND_TIMEOUT = 3000;
public int WaitTime { get; set; }
public int CommandTimeout { get; set; }
Process _process;
StringBuilder output;
public CmdManager() : this("cmd.exe", null, null) { }
public CmdManager(string filename) : this(filename, null, null) { }
public CmdManager(string filename, string arguments) : this(filename, arguments, null) { }
public CmdManager(string filename, string arguments, string verb)
{
WaitTime = DEFAULT_WAIT_CHECK_TIME;
CommandTimeout = DEFAULT_COMMAND_TIMEOUT;
output = new StringBuilder();
_process = new Process();
_process.StartInfo.FileName = filename;
_process.StartInfo.RedirectStandardInput = true;
_process.StartInfo.RedirectStandardOutput = true;
_process.StartInfo.RedirectStandardError = true;
_process.StartInfo.CreateNoWindow = true;
_process.StartInfo.UseShellExecute = false;
_process.StartInfo.ErrorDialog = false;
_process.StartInfo.Arguments = arguments != null ? arguments : null;
_process.StartInfo.Verb = verb != null ? verb : null;
_process.EnableRaisingEvents = true;
_process.OutputDataReceived += (s, e) =>
{
lock (output)
{
output.AppendLine(e.Data);
};
};
_process.ErrorDataReceived += (s, e) =>
{
lock (output)
{
output.AppendLine(e.Data);
};
};
_process.Start();
_process.BeginOutputReadLine();
_process.BeginErrorReadLine();
_process.StandardInput.AutoFlush = true;
}
public void RunCommand(string command)
{
_process.StandardInput.WriteLine(command);
}
public string GetOutput()
{
return GetOutput(null, CommandTimeout, WaitTime);
}
public string GetOutput(string endingOutput)
{
return GetOutput(endingOutput, CommandTimeout, WaitTime);
}
public string GetOutput(string endingOutput, int commandTimeout)
{
return GetOutput(endingOutput, commandTimeout, WaitTime);
}
public string GetOutput(string endingOutput, int commandTimeout, int waitTime)
{
string tempOutput = "";
int tempOutputLength = 0;
int amountOfTimeSlept = 0;
// Loop until
// a) command timeout is reached
// b) some output is seen
while (output.ToString() == "")
{
if (amountOfTimeSlept >= commandTimeout)
{
break;
}
Thread.Sleep(waitTime);
amountOfTimeSlept += waitTime;
}
// Loop until:
// a) command timeout is reached
// b) endingOutput is found
// c) OR endingOutput is null and there is no new output for at least waitTime
while (amountOfTimeSlept < commandTimeout)
{
if (endingOutput != null && output.ToString().Contains(endingOutput))
{
break;
}
else if(endingOutput == null && tempOutputLength == output.ToString().Length)
{
break;
}
tempOutputLength = output.ToString().Length;
Thread.Sleep(waitTime);
amountOfTimeSlept += waitTime;
}
// Return the output and clear the buffer
lock (output)
{
tempOutput = output.ToString();
output.Clear();
return tempOutput.TrimEnd();
}
}
public void Dispose()
{
_process.Kill();
}
}
}
然后从 PowerShell 添加该类并使用它。
Add-Type -Path ".\Utils.CmdManager.cs"
$cmd = new-object Utils.CmdManager
$cmd.GetOutput() | Out-Null
$cmd.RunCommand("whoami")
$cmd.GetOutput()
$cmd.RunCommand("cd")
$cmd.GetOutput()
$cmd.RunCommand("dir")
$cmd.GetOutput()
$cmd.RunCommand("cd Desktop")
$cmd.GetOutput()
$cmd.RunCommand("cd")
$cmd.GetOutput()
$cmd.RunCommand("dir")
$cmd.GetOutput()
$cmd.Dispose()
不要忘记最后调用
Dispose()
函数来清理后台运行的进程。或者,您可以通过运行类似 $cmd.RunCommand("exit")
的命令来关闭该进程
我来到这里寻找一种解决方案来创建一个记录进程并将其输出到屏幕的包装器。这些都不适合我。我编写了这段代码,看起来效果很好。
PSDataCollection 允许您继续执行脚本,而无需等待进程完成。
Using namespace System.Diagnostics;
Using namespace System.Management.Automation;
$Global:Dir = Convert-Path "."
$Global:LogPath = "$global:Dir\logs\mylog.log"
[Process]$Process = [Process]::New();
[ProcessStartInfo]$info = [ProcessStartInfo]::New();
$info.UseShellExecute = $false
$info.Verb = "runas"
$info.WorkingDirectory = "$Global:Dir\process.exe"
$info.FileName = "$Global:Dir\folder\process.exe"
$info.Arguments = "-myarg yes -another_arg no"
$info.RedirectStandardOutput = $true
$info.RedirectStandardError = $true
$Process.StartInfo = $info;
$Process.EnableRaisingEvents = $true
$Global:DataStream = [PSDataCollection[string]]::New()
$Global:DataStream.add_DataAdded(
{
$line = $this[0];
[IO.File]::AppendAllLines($LogPath, [string[]]$line);
[Console]::WriteLine($line)
$this.Remove($line);
}
)
$script = {
param([Object]$sender, [DataReceivedEventArgs]$e)
$global:Datastream.Add($e.Data)
}
Register-ObjectEvent -InputObject $Process -Action $script -EventName 'OutputDataReceived' | Out-Null
Register-ObjectEvent -InputObject $Process -Action $script -EventName 'ErrorDataReceived' | Out-Null
$Process.Start()
$Process.BeginOutputReadLine()
$Process.BeginErrorReadLine()
如果您只想将其动态转储到 PowerShell 控制台,请执行以下操作:
my.exe | Out-Default
我不能声称已经弄清楚了。
这也指的是 this stackoverflow post。
$LASTEXITCODE 还填充了我的 exe 的退出代码,这也是我所需要的。
我遇到了这个帖子,并想为将来可能需要这个的人分享我的解决方案。这适用于 PowerShell Core 7.3.4。
<#
.Synopsis
This function will run a provided command and arguments.
.DESCRIPTION
This function was created due to the inconsistencies of running Start-Process in Linux. This function provides a
consistent way of running non-PowerShell commands that require many parameters/arguments to run (e.g., docker).
PowerShell commands or aliases will NOT work with this function. For example commands such as: echo, history, or cp
will NOT work. Use the build-in PowerShell commands for those.
.PARAMETER Name
The path or name of the command to be ran.
.PARAMETER Arguments
The optional parameters/arguments to be added with your command.
.PARAMETER WorkingDirectory
The current WorkingDirectory to run said Command. If you are not using the full path to files, you should probably
use this parameter.
.PARAMETER LoadUserProfile
Gets or sets a value that indicates whether the Windows user profile is to be loaded from the registry.
This will NOT work on Unix/Linux.
.PARAMETER Timer
Provide a timer (in ms) for how long you want to wait for the process to exit/end.
.PARAMETER Verb
Specifies a verb to use when this cmdlet starts the process. The verbs that are available are determined by the filename extension of the file that runs in the process.
The following table shows the verbs for some common process file types.
File type Verbs
.cmd Edit, Open, Print, RunAs, RunAsUser
.exe Open, RunAs, RunAsUser
.txt Open, Print, PrintTo
.wav Open, Play
To find the verbs that can be used with the file that runs in a process, use the New-Object cmdlet to create a System.Diagnostics.ProcessStartInfo object for the file. The available verbs are in the Verbs property of the ProcessStartInfo object. For details, see the examples.
This will NOT work on Unix/Linux.
.PARAMETER Passthru
Pass the object into the pipeline. Using -Passthru will ignore error-handling.
.NOTES
Author - Zack Flowers
.LINK
GitHub: https://github.com/zackshomelab
.EXAMPLE
Start-Command -Name 'docker' -CommandArguments "container ls --all"
Example #1:
This example executes command 'docker' and passes arguments 'container ls --all' to display the offline/online containers.
.EXAMPLE
Start-Command -Name 'docker' -CommandArguments "container", "ls", "--all"
Example #2:
This example is simular to Example #1, except it accepts comma-separated arguments.
.EXAMPLE
$whoami = Start-Command -Name 'whoami' -Passthru
$whoami
Title : whoami
OutputStream : System.Management.Automation.PSEventJob
OutputData : zac
ErrorStream :
ErrorData :
ExitCode : 0
Example #3:
This example utilizes the -Passthru feature of this script.
.INPUTS
None
.OUTPUTS
System.String
System.Management.Automation.PSCustomObject
#>
function Start-Command {
[cmdletbinding(DefaultParameterSetName="default")]
param (
[parameter(Mandatory,
Position=0,
ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[string]$Name,
[parameter(Mandatory=$false,
Position=1,
ValueFromPipelineByPropertyName)]
[ValidateNotNullOrEmpty()]
[object]$Arguments,
[parameter(Mandatory=$false,
ValueFromPipelineByPropertyName)]
[ValidateScript({Test-Path $_})]
[string]$WorkingDirectory,
[parameter(Mandatory=$false)]
[ValidateScript({
if ($PSVersionTable.Platform -eq "Unix") {
Throw "-LoadUserProfile cannot be used on Unix/Linux."
}
})]
[switch]$LoadUserProfile,
[parameter(Mandatory,
ValueFromPipelineByPropertyName,
ParameterSetName="timer")]
[ValidateRange(1, 600000)]
[int]$Timer,
[parameter(Mandatory=$false,
ValueFromPipelineByPropertyName)]
[ValidateScript({
if ($PSVersionTable.Platform -eq "Unix") {
Throw "-Verb cannot be used on Unix/Linux."
}
})]
[string]$Verb,
[parameter(Mandatory=$false)]
[switch]$Passthru
)
begin {
$FileName = (Get-Command -Name $Name -ErrorAction SilentlyContinue).Source
# If we cannot find the provided FileName, this could be due to the user providing..
# ..a command that is a PowerShell Alias (e.g., echo, history, cp)
if ($null -eq $FileName -or $FileName -eq "") {
# Source doesn't exist. Let's see if the provided command is a PowerShell command
$getPSCommand = (Get-Command -Name $Name -ErrorAction SilentlyContinue)
if ($null -eq $getPSCommand -or $getPSCommand -eq "") {
Throw "Start-Command: Could not find command $Name nor could we find its PowerShell equivalent."
}
# Stop the script if the command was found but it returned an alias.
# Sometimes, a command may not return a source but WILL return an alias. This will cause issues with incompatibility with..
# ..parameters for said commands.
#
# Example commands that will not work: echo, history, and cd
if ($getPSCommand.CommandType -eq 'Alias') {
Throw "Start-Command: This function does not support Aliases. Command $Name matches $($getPSCommand.ResolvedCommand.Name)."
}
# This function does not support Microsoft PowerShell commands.
if ($getPSCommand.Source -like "Microsoft.PowerShell*") {
Throw "Start-Command: This function should only be used for Non-PowerShell commands (e.g., wget, touch, mkdir, etc.)"
}
# Retrieve the version of PowerShell and its location and replace $FileName with it
$FileName = $PSVersionTable.PSEdition -eq 'Core' ? (Get-Command -Name 'pwsh').Source : (Get-Command -Name 'powershell').Source
# Reconfigure Arguments to execute PowerShell
$Arguments = "-noprofile -Command `"& {$($getPSCommand.ReferencedCommand.Name) $Arguments}`""
}
# Data Object will store all streams of data from our command
$dataObject = [pscustomobject]@{
Title = $Name
OutputStream = ''
OutputData = ''
ErrorData = ''
ExitCode = 0
}
}
process {
$processStartInfoProps = @{
Arguments = $null -ne $Arguments ? $Arguments : $null
CreateNoWindow = $true
ErrorDialog = $false
FileName = $FileName
RedirectStandardError = $true
RedirectStandardInput = $true
RedirectStandardOutput = $true
UseShellExecute = $false
WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
WorkingDirectory = $PSBoundParameters.ContainsKey('WorkingDirectory') ? $WorkingDirectory : $PSScriptRoot
Verb = $PSBoundParameters.ContainsKey('Verb') ? $Verb : $null
}
# This will Error on Unix/Linux Systems if property LoadUserProfile is added regardless if it's null or false.
if ($PSBoundParameters.ContainsKey('LoadUserProfile')) {
$processStartInfoProps.Add('LoadUserProfile', $LoadUserProfile)
}
try {
$process = New-Object System.Diagnostics.Process
$process.EnableRaisingEvents = $true
$processStartInfo = New-Object System.Diagnostics.ProcessStartInfo -Property $processStartInfoProps
$process.StartInfo = $processStartInfo
# Register Process OutputDataReceived:
# This will create a background job to capture output data
# Reference: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.standardoutput?redirectedfrom=MSDN&view=net-7.0#System_Diagnostics_Process_StandardOutput
$outputEventParams = @{
InputObject = $process
SourceIdentifier = 'OnOutputDataReceived '
EventName = 'OutputDataReceived'
Action = {
param (
[System.Object]$sender,
[System.Diagnostics.DataReceivedEventArgs]$e
)
foreach ($data in $e.Data) {
if ($null -ne $data -and $data -ne "") {
$($data).Trim()
}
}
}
}
$dataObject.OutputStream = Register-ObjectEvent @outputEventParams
# Start the process/command
if ($process.Start()) {
$process.BeginOutputReadLine()
$dataObject.ErrorData = $process.StandardError.ReadToEnd()
if ($PSCmdlet.ParameterSetName -eq 'timer') {
$process.WaitForExit($Timer) | Out-Null
} else {
$process.WaitForExit()
}
}
# Retrieve the exit code and the OutputStream Job
$dataObject.ExitCode = $process.ExitCode
$dataObject.OutputData = Receive-Job -id $($dataObject.OutputStream.id)
[bool]$hasError = ($null -ne $($dataObject.ErrorData) -and $($dataObject.ErrorData) -ne "" -and $($dataObject.ExitCode) -ne 0) ? $true : $false
[bool]$hasOutput = ($null -ne $($dataObject.OutputData) -and $($dataObject.OutputData) -ne "") ? $true : $false
# Output the PSCustomObject if -Passthru is provided.
if ($Passthru) {
if ($hasError) {
$dataObject.ErrorData = $($dataObject.ErrorData.Trim())
}
$dataObject
} else {
if ($hasError) {
if ($($ErrorActionPreference) -ne 'Stop') {
Write-Error "Exit Code $($dataObject.ExitCode): $($dataObject.ErrorData.Trim())"
} else {
Throw "Exit Code $($dataObject.ExitCode): $($dataObject.ErrorData.Trim())"
}
}
if ($hasOutput) {
$($dataObject.OutputData)
}
}
}
finally {
# Cleanup
$process.Close()
Unregister-Event -SourceIdentifier $($dataObject.OutputStream.Name) -Force | Out-Null
Remove-Job -Id $($dataObject.OutputStream.Id) -Force
}
}
}
示例1:常规用法
Start-Command -Name 'docker' -Arguments 'container ls --all'
示例 2:逗号分隔的参数
Start-Command -Name 'docker' -Arguments 'container', 'ls', '--all'
示例 3:Passthru 用法
$whoami = Start-Command -Name 'whoami' -Passthru
$whoami
Title : whoami
OutputStream : System.Management.Automation.PSEventJob
OutputData : zac
ErrorStream :
ErrorData :
ExitCode : 0
示例 4:错误示例
Start-Command -Name 'docker' -Arguments 'force' -ErrorAction Stop
Output:
Line |
245 | … Throw "Exit Code $($dataObject.ExitCode): $($dataObject.E …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exit Code 1: docker: 'force' is not a docker command. See 'docker --help'