powershell - 如何跟踪由于 PowerShell 脚本中较早的命令而写入的日志文件?

标签 powershell windows-installer

我正在为我公司的桌面应用程序编写安装和配置过程的脚本。我们发出 kiosk不能把所有东西都放在安装程序中……继续前进!我正在使用 Start-Process等待msiexeccomplete .

function Run-Installer
{
    param
    (
        [string] $msi = $(throw "Required parameter: 'msi'"),
    )

    if(-not(Test-Path $msi -Type Leaf))
    {
        throw "The installer could not be found: '$msi'"
    }

    $name = (Get-Item $msi).BaseName

    Write-Host "Installing $name"

    $p = 
    @(
        "/I `"$msi`"",                    # Install this MSI
        "/QN",                            # Quietly, without a UI
        "/L*V `"$ENV:TEMP\$name.log`""    # Verbose output to this log
    )

    Start-Process -FilePath "msiexec" -ArgumentList $p -Wait
}

我想看中的是 msiexec 的日志输出。我想在安装程序运行时将日志内容流式传输到控制台。我猜解决方案有多个部分

  1. 在后台以可等待的方式运行安装程序
  2. 跟踪日志文件直到满足某些条件(安装程序作业完成)
  3. 可选:过滤输出或写入 debug/verbose 以获得乐趣

最佳答案

function Start-FileTail {
    param($path)
    # Get unique source ID
    $sourceID = "FileTailLine-" + [guid]::NewGuid()

    $job = Start-Job -ArgumentList $path, $sourceID {
        param($path,$sid)

        Register-EngineEvent -SourceIdentifier $sid -Forward

        do{}until(Test-Path $path)

        $fs = New-Object IO.FileStream ($path, [IO.FileMode]::Open, 
                [IO.FileAccess]::Read, [IO.FileShare]::ReadWrite)
        $sr = New-Object IO.StreamReader ($fs)
        $lines = @()

        while(1) {
            $line = $sr.ReadLine()
            $lines += $line
            # Send after every 100 reads
            if($lines.Count -gt 100) {
                # Join lines into 1 string
                $text = @($lines| where {$_} ) -join "`n"
                # Only send if text was found
                if($text){New-Event -SourceIdentifier $sid -MessageData $text}
                $lines = @()
            }
        }
    }

    $event = Register-EngineEvent -SourceIdentifier $sourceID -Action {
        Write-Host $event.MessageData
    }
    New-Object Object|
        Add-Member -Name Job -Type NoteProperty -Value $job -PassThru|
        Add-Member -Name SourceIdentifier -Type NoteProperty -Value $sourceID -PassThru
}

function Stop-FileTail {
    param($TailInfo)
    Remove-Job $TailInfo.Job -Force
    Unregister-Event -SourceIdentifier $tail.SourceIdentifier
}

您可以删除作业,并在安装完成后注销事件。

Write-Host 更改为 Write-Verbose 以获得 -Verbose 支持

编辑: 我在安装应用程序时测试了我的答案,发现它在读取日志文件时非常慢。我更新了 Get-Content 调用以使用 -ReadCount 100 将数据作为行数组发送。 Write-Host 行已更新以处理数组。

我还发现,在 Start-Process 上使用 -Wait 开关会导致在安装完成后写入所有日志输出。这可以通过使用来解决:

$msi = Start-Process -FilePath "msiexec" -ArgumentList $p -PassThru
do{}until($msi.HasExited)

编辑 2: 嗯,当我同时使用 -Wait-ReadCount 时,我没有得到所有的日志文件。我把日志文件的读取恢复到原来的样子。我还不确定如何处理速度。

编辑 3: 我更新了代码以使用 StreamReader 而不是 Get-Content,并将代码放入函数中。然后你会这样调用它:

$path = "$ENV:TEMP\$name.log"
if(Test-Path $path){Remove-Item $path}

$msi = Start-Process -FilePath "msiexec" -ArgumentList $p -PassThru
$tail = Start-FileTail $p
do{}until($msi.HasExited)
sleep 1 # Allow time to finish reading log.
Stop-FileTail $tail

关于powershell - 如何跟踪由于 PowerShell 脚本中较早的命令而写入的日志文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7109366/

相关文章:

windows - 如何使 vcredist 成为我的 MSI 安装程序的启动条件?

powershell - 无人值守安装 ilmerge

regex - 正则表达式分组

csv - 从CSV读取会在变量中产生重复的条目

c# - 部署:this.Context.Parameters 在整个安装过程中不可用

mysql - 通过 visual studio 安装程序运行另一个 MSI

windows - 从 MSI 文件中查找 GUID

powershell - 有没有更好的方法使用 Powershell 将标题添加到 CSV 文件?

html - Excel 导出到重叠的 HTML 单元格

powershell - 是否可以在 PowerShell 中的 bool[] 中包含 [Nullable[bool]]