启动进程、调用命令还是?

dca*_*caz 2 powershell

使用该程序可以得到您的支持或 GYB。我运行以下命令

Start-Process -FilePath 'C:\Gyb\gyb.exe' -ArgumentList @("--email <Email Address>", "--action backup", "--local-folder $GYBfolder", "--service-account", "--batch-size 4") -Wait
Run Code Online (Sandbox Code Playgroud)

问题是,当该过程完成时,我的脚本未完成。

$GYBfolder = $GYBfolder.Replace('"', "")
$output = [PSCustomObject]@{
    Name   = $SourceGYB
    Folder = $GYBfolder
}

$filename = "C:\reports\" + $SourceGYB.Split("@")[0] + "_Backup.csv"

$output | Export-Csv $filename -NoTypeInformation | Format-Table text-align=left -AutoSize
Return $filename
Run Code Online (Sandbox Code Playgroud)

由于某种原因,脚本在返回之前停止。我很想知道我是否应该使用不同的命令来运行 GYB?关于为什么脚本不处理返回的任何想法?

mkl*_*nt0 8

评论中有很多信息,但让我尝试系统概述一下

  • 同步执行外部控制台应用程序并捕获其输出,请直接调用它们C:\Gyb\gyb.exe ...& 'C:\Gyb\gyb.exe' ...),不要使用-Start-Process请参阅此答案

    • 仅当gyb.exeGUI应用程序时,您才需要同步Start-Process -Wait执行它

      • 一个简单但不明显的快捷方式是将调用传递给另一个命令,例如Out-Null,这也会强制 PowerShell 等待(例如gyb.exe | Out-Null) - 见下文。
    • Start-Process适当的情况下,传递所有参数的最可靠方法是作为对所有参数进行编码的单个字符串,并根据需要使用适当的嵌入引用; "..."这是不幸的,但需要作为长期存在的错误的解决方法:请参阅此答案

  • Invoke-Command的主要目的是远程调用命令;虽然它可以在本地使用,但很少有充分的理由这样做,因为&调用运算符既更简洁又更高效 - 请参阅此答案

  • 当您使用数组将参数传递给外部应用程序时,每个元素必须仅包含一个参数,其中参数名称及其被视为不同的参数;例如,您必须使用@(--'action', 'backup', ...)而不是
    @('--action backup', ...)

因此,请使用以下命令同步运行命令

  • 如果gyb.exe控制台应用程序
# Note: Enclosing @(...) is optional
$argList = '--email',  $emailAddress, '--action', 'backup', '--local-folder', $GYBfolder, '--service-account', '--batch-size',  4

# Note: Stdout and stderr output will print to the current console, unless captured.
& 'C:\Gyb\gyb.exe' $argList
Run Code Online (Sandbox Code Playgroud)
  • 如果gyb.exe是一个GUI应用程序,则需要使用Start-Process -Wait(使用此处字符串,因为它使嵌入引用更容易):
# Note: A GUI application typically has no stdout or stderr output, and
#       Start-Process never returns the application's *output*, though
#       you can ask to have a *process object* returned with -PassThru.
Start-Process -Wait 'C:\Gyb\gyb.exe' @"
--email $emailAddress --action backup --local-folder "$GYBfolder" --service-account --batch-size 4
@"
Run Code Online (Sandbox Code Playgroud)

上面提到的快捷方式-管道到另一个命令以强制等待 GUI 应用程序退出 - 尽管晦涩难懂,但有两个优点:

  • 可以使用普通的参数传递语法。
  • 自动$LASTEXITCODE变量被设置为外部程序的进程退出代码Start-Process. 虽然 GUI 应用程序很少报告有意义的退出代码,但有些应用程序会报告有意义的退出代码,尤其是msiexec.
# Pipe to | Out-Null to force waiting (argument list shortened).
# $LASTEXITCODE will reflect gyb.exe's exit code.
# Note: In the rare event that the target GUI application explicitly
#       attaches to the caller's console and produces output there,
#       pipe to `Write-Output` instead, and possibly apply 2>&1 to 
#       the application call so as to also capture std*err* output.
& 'C:\Gyb\gyb.exe' --email $emailAddress --action backup | Out-Null
Run Code Online (Sandbox Code Playgroud)

注意:如果上面的操作意外地没有同步运行,则意味着gyb.exe它本身启动了另一个异步操作。对此没有通用的解决方案,并且特定于应用程序的解决方案需要您了解应用程序的内部结构,并且这将是非常重要的。


使用直接 /&基于调用传递参数的注释:

  • 将数组按原样传递给外部程序本质上是隐式执行展开 ,而不需要使用[1]。也就是说,它将每个数组元素作为其自己的参数传递。@argList

  • 相比之下,如果要传递$argListPowerShell命令,它将作为单个数组值参数传递,因此@argList确实有必要将元素作为单独位置参数传递。然而,与 PowerShell 命令一起使用的更典型的展开形式是使用 hashtable 它允许传递命名参数(参数名称-值对;例如,将值传递给 PowerShell 命令的
    -LiteralPath参数:
    $argHash = @{ LiteralPath = $somePath; ... }; Set-Content @argHash


[1]$args@args在这种情况下基本相同,但奇怪的是,@argList,尊重使用停止解析符号运算符--%,即使它只在字面指定的参数列表中有意义。