来自powershell函数内部的外部命令的流输出

Ami*_*rge 1 powershell powershell-3.0

考虑以下命令:

7z.exe a -t7z folder.7z folder
Run Code Online (Sandbox Code Playgroud)

我有以下两个精简的 powershell 脚本

文件 1:common.ps1

function Archive-Folder ($src, $dest_path, $archive_name) {

    $script_dir = split-path $script:MyInvocation.MyCommand.Path

    if ((test-path $src) -eq $false) {
        write-error "$src is not a valid source directory"
        #return
        return $false
    }

    if ((test-path $dest_path) -eq $false) {
        write-error "$dest_path is not a valid destination directory"
        #return
        return $false
    }

    if ([string]::IsNullOrWhiteSpace($archive_name) -eq $true) {
        write-error "$archive_name is not a valid archive name"
        #return
        return $false
    }

    write-verbose "archiving the folder"

    $archive_command = "$script_dir\7z.exe a -t7z $dest_path\$archive_name $src"

    $exe = "$script_dir\7z.exe"
    $arguments = @('a', '-t7z', "$dest_path\$archive_name", "$src")

    iex $archive_command

    # this doesn't stream the output. it prints it all at once.
    # & $exe $arguments | write-verbose

    return $true
}
Run Code Online (Sandbox Code Playgroud)

文件 2:script.ps1

$script_dir = split-path $script:MyInvocation.MyCommand.Path
. "$script_dir\common.ps1"

$VerbosePreference = "Continue"

$src = 'C:\some\source'
$backup_path = 'C:\some\destination'
$date_format = 'yyyy_MM_dd_HHmm'
$date = get-date
$date_str = $date.tostring($date_format)
$date_ticks = $date.ticks
$archive_name = "backup-$date_str-$date_ticks.7z"

# this prints the output streamed. The output ends with `True`
archive-folder $src $backup_path $archive_name 

# the following however doesn't output anything. in order to separate the command output from my function output, 
# i was printing the command output using write-verbose
$isSuccess = archive-folder $src $backup_path $archive_name
if ($isSuccess -eq $true) {
    #proceed with the rest of the code
}
Run Code Online (Sandbox Code Playgroud)

通过@Christian & @zdan 的输入,我能够将问题与返回值的捕获隔离开来。与 类似archive-folder,我还有其他函数可以执行一些命令行工具。我在想,这些函数中的每一个都可以返回 true 或 false,这取决于是否使用正确的操作调用了该函数以及是否正确执行了命令行工具。

但是,如果我捕获archive-folder函数的返回值,则命令的输出不会打印到控制台。此外,我的返回值不包含真值或假值。它由命令的整个输出组成。

我解决这个问题的第一次尝试是将命令执行语句写为iex $archive_command | write-verbose,但这并没有流输出。

我想我可以检查命令行工具在成功的情况下的副作用(例如存档文件的存在)以确定我的函数是否成功执行,但不确定我是否能够对所有可能的函数执行此操作最终创造。

有没有办法返回一个值并流式传输命令行工具的输出?

编辑 2

至于我为什么要把代码分成两个独立的文件/函数,我的实际使用场景如下

script.ps1将协调这一流程。备份数据库(mongodb 为数据库的每个集合生成文件)。归档数据库备份。将存档上传到 S3。这些步骤中的每一个都将由common.ps1. 在script.ps1将只包含胶水代码。发布所有这些可能会使问题复杂化,我觉得不需要了解我面临的问题

编辑 1

如果被压缩的文件夹有5个文件,7zip会先输出版权。然后它将输出文本Scanning。然后它会输出一行Creating archive at some location。然后它将处理每个文件,将每个文件的进度一一输出。通过这种方式,我们可以获得有关操作进度的持续反馈。

如果我执行 powershell 函数,那么在操作期间我看不到任何输出,然后一次看到所有输出。我没有得到 7zip 的反馈。我想模拟 7zip 在作为独立 exe 运行时显示的行为。

W1M*_*M0R 6

这对我有用:

& 7z.exe a -t7z -bsp1 $archive_name $src 2>&1 | Out-Host

-bsp1开关的重定向progress information流的stdout流。这是7z的一个特点。还要看-bb开关。

2>&1错误流重定向到stdout。这是 PowerShell 的一个功能。

-bs(设置输出/错误/进度行的输出流)开关语法

句法

-bs{o|e|p}{0|1|2}

{id} | 流类型
………………………………………………………………………………………………………………………………………………………………………………………………………………
 ○ | 标准输出消息
 电子 | 错误信息
 p | 进度信息
{N} | 流目的地
………………………………………………………………………………………………………………………………………………………………………………………………………………
 0 | 禁用流
 1 | 重定向到标准输出流
 2 | 重定向到 stderr 流