【问题标题】:How do I tail a log file that's being written because of an earlier command in a PowerShell script?如何跟踪由于 PowerShell 脚本中的较早命令而写入的日志文件?
【发布时间】:2011-10-29 21:02:54
【问题描述】:

我正在为我公司的桌面应用程序编写安装和配置过程的脚本。我们发送了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 以获得乐趣

【问题讨论】:

    标签: powershell windows-installer


    【解决方案1】:
    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
    

    【讨论】:

    • 哇,感谢所有的工作!我今晚可能有时间来实现它。我会定期回来查看:)
    • 还没有尝试过解决方案,它是用于工作中的一个副项目,你不知道吗,我的主要职责一直在阻碍:) 但是,你已经等了足够长的时间了代表!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    相关资源
    最近更新 更多