【问题标题】:PowerShell save stdout and display stdoutPowerShell 保存标准输出并显示标准输出
【发布时间】:2013-04-24 04:44:17
【问题描述】:

我正在使用 PowerShell 启动一个名为 GoodSync 的应用程序来为我执行备份。在该过程结束时,我将结果通过电子邮件发送给我。我还喜欢(有时)观察 PowerShell 窗口以密切关注它,并在处理过程中观察备份的状态。由于我的代码现在就在,stdout 将用于控制台,仅此而已。

我的问题: 是否可以让标准输出进入控制台,并将其保存到变量中以供以后处理?

您可以看到我正在尝试使用 $output 变量,但无济于事。这是 $output 返回的错误:

You cannot call a method on a null-valued expression.
At GoodSync.ps1:119 char:42
+     $output = $proc.StandardOutput.ReadToEnd <<<< ()
    + CategoryInfo          : InvalidOperation: (ReadToEnd:String) [], Runtime
   Exception
    + FullyQualifiedErrorId : InvokeMethodOnNull

You cannot call a method on a null-valued expression.
At GoodSync.ps1:120 char:42
+     $output += $proc.StandardError.ReadToEnd <<<< ()
    + CategoryInfo          : InvalidOperation: (ReadToEnd:String) [], Runtime
   Exception
    + FullyQualifiedErrorId : InvokeMethodOnNull

这是我的代码:

(并且从你们那里的所有专家那里稍微主动一点,是的,我使用此代码做了很多工作以输出到文件和标准输出,因此我可以关注所有内容。本节只是一个 sn -p 整个文件。)

###############################
## Call the GoodSync process ##
###############################

# This is the section taken from http://stackoverflow.com/questions/8925323
# This is a known working section. However, right now I don't know how to save the stdout to variable and insert into email log file.
$procInfo = New-Object System.Diagnostics.ProcessStartInfo
$procInfo.FileName = "C:\Program Files\Siber Systems\GoodSync\gsync.exe"
$procInfo.UseShellExecute = $false
$procInfo.Arguments = '/progress=yes /exit sync MyBackupJobName'
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo = $procInfo
$proc.Start() | Out-Host
(Get-Date -format T) + " - Loaded gsync.exe. Backup process running. Please stand by..." | Tee-Object -Variable RoboLog
$RoboLog >> $myLogFile
"" | Tee-Object -Variable RoboLog
$RoboLog >> $myLogFile
$proc.WaitForExit()
(Get-Date -format T) + " - Backup complete and gsync.exe has exited." | Tee-Object -Variable RoboLog
$RoboLog >> $myLogFile
"" | Tee-Object -Variable RoboLog
$RoboLog >> $myLogFile

# Now we take the exit code, write it to console and log file, and begin to build our email report. 
if ($proc.ExitCode -eq 0) { 
    "Success: GoodSync Reported: Analyze or Sync Successfully Completed." | Tee-Object -Variable RoboLog
    $RoboLog >> $myLogFile
    $subject = $RoboLog
    "" | Tee-Object -Variable RoboLog
    $RoboLog >> $myLogFile
} elseif ($proc.ExitCode -eq 1) {
    "Failure: GoodSync Error: Analyze had Terminal Errors. Did gsync.exe close abruptly?" | Tee-Object -Variable RoboLog
    $RoboLog >> $myLogFile
    $subject = $RoboLog
    "" | Tee-Object -Variable RoboLog
    $RoboLog >> $myLogFile
} elseif ($proc.ExitCode -eq 2) {
    "Failure: GoodSync Error: Sync had Terminal Errors. Did gsync.exe close abruptly?" | Tee-Object -Variable RoboLog
    $RoboLog >> $myLogFile
    $subject = $RoboLog
    "" | Tee-Object -Variable RoboLog
    $RoboLog >> $myLogFile
} else { 
    "Failure: GoodSync Error: General Error. Check log file." | Tee-Object -Variable RoboLog
    $RoboLog >> $myLogFile
    $subject = $RoboLog
    "" | Tee-Object -Variable RoboLog
    $RoboLog >> $myLogFile
}

# Grab the stdout and stderr to a variable
$output = $proc.StandardOutput.ReadToEnd()
$output += $proc.StandardError.ReadToEnd()
# The ReadToEnd() makes everything 1 long string, so we break it up by carriage return, and filter
$output -split "`n"
# Write to log file for email capture
$output >> $myLogFile

"" | Tee-Object -Variable RoboLog
$RoboLog >> $myLogFile

#---------------------------------------------------------------------------------------------------
# GoodSync backup jobs are now complete.
#---------------------------------------------------------------------------------------------------

【问题讨论】:

    标签: powershell


    【解决方案1】:

    来自$proc.StandardOutput.ReadToEnd (You cannot call a method on a null-valued expression.) 的错误是因为您需要在ProcessStartInfo 对象上设置这些属性:

    $procInfo.RedirectStandardError = $true
    $procInfo.RedirectStandardOutput = $true
    

    注意 - 设置这些时,输出将显示在控制台上。

    这是一种将输出存储在变量中并使用Tee-Object在控制台上显示的方法:

    & ping.exe localhost -n 1 | Tee-Object -Variable output
    $output
    

    顺便说一句 - 您可以打开 $LASTEXITCODE - 例如

    switch ($LASTEXITCODE) {
        0 {'good'}
        1 {'bad'}
        2 {'ugly'}
    }
    

    【讨论】:

    • 谢谢安迪。我已经添加了这些重定向,但现在我没有在控制台中显示任何内容,并且根据您的示例(我没有使用 ping.exe,但假设我会用 gsync.exe 替换它),我不是确定我会把它放在代码中的哪个位置?也是实时显示吗?
    • @Pat,您不能使用System.Diagnostics.Process 类重定向显示。因此,不要使用它,只需使用调用运算符 &amp; 调用您的程序(使用 ping.exe 给出的示例)。使用$LASTEXITCODE后可以查看退出码。
    • 好的,我试试看。
    • 有趣。如果我将 Tee-Object -Variable output $output 添加到脚本中,我在日志中什么也没有,在控制台中什么也没有。如果我删除Tee-Object,那么控制台会显示标准输出。想法?
    • 它适用于我提供的示例。您正在测试的完整线路是什么?
    【解决方案2】:

    为什么不把它作为后台作业运行呢?然后,您可以使用 Receive-Job 来获取输出(如果您使用 -Keep,则可以任意多次,并使用它做任何您想做的事情。

    【讨论】:

    • 听起来不错,但我不得不承认:我不知道该怎么做。 (至少我不认为我知道)。这个 sn-p 主要取自代码注释区的 stackoverflow 链接。我猜它是启动过程?我在这里边做一点阅读。
    • 从 Get-Help About_Jobs 开始
    猜你喜欢
    • 1970-01-01
    • 2015-12-20
    • 2013-09-18
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-21
    相关资源
    最近更新 更多