You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell处理Nessus Essentials标准输出错误问题

解决PowerShell捕获Nessus Essentials未连接管理器状态的问题

问题描述

尝试通过PowerShell捕获Nessus Essentials的运行状态,目标是当软件输出[warn] [scanner] Not linked to a manager时,控制台仅输出一行Not linked to a manager。但无论将-like改为-match,还是调整匹配字符串(加/不加通配符、缩短字符串),均无法匹配成功,反而会输出多行冗余错误信息。

问题分析

  1. 运算符使用错误:
    • 使用-like时未添加通配符*,-like依赖通配符实现模糊匹配,直接写完整字符串仅会匹配完全一致的内容。
    • 使用-match时,字符串中的[和]是正则元字符,未转义会导致匹配逻辑失效。
  2. 输出流判断偏差:Nessus可能将警告信息输出到StdErr而非StdOut,原代码仅检查StdOut会遗漏该情况。
  3. 多行内容匹配问题:$agentStatus.stdOut可能包含多行文本,直接用整串匹配会因换行符或额外内容导致失败。
  4. 错误抛出方式不当:使用Throw会触发PowerShell错误处理机制,输出错误堆栈信息,造成冗余内容。

修复方案

  1. 同时检查StdOut和StdErr:确保不会遗漏输出到错误流的警告信息。
  2. 正确使用匹配运算符:
    • 用-like时添加通配符:*[warn] [scanner] Not linked to a manager*
    • 用-match时转义元字符:\[warn\] \[scanner\] Not linked to a manager,或用[regex]::Escape()自动转义特殊字符
  3. 采用包含匹配逻辑:无需匹配整串内容,只需判断目标字符串是否存在于输出中。
  4. 替换Throw为Write-Host:若仅需输出提示信息而非终止脚本,用Write-Host替代Throw避免错误堆栈输出。

完整修正代码

Function Start-ProcessGetStreams {

    [CmdLetBinding()]
    Param(
        [System.IO.FileInfo]$FilePath,
        [string[]]$ArgumentList
    )

    $pInfo = New-Object System.Diagnostics.ProcessStartInfo
    $pInfo.FileName = $FilePath
    $pInfo.Arguments = $ArgumentList
    $pInfo.RedirectStandardError = $true
    $pInfo.RedirectStandardOutput = $true
    $pinfo.UseShellExecute = $false
    $pInfo.CreateNoWindow = $true
    $pInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden

    $proc = New-Object System.Diagnostics.Process
    $proc.StartInfo = $pInfo

    Write-Verbose "Starting $FilePath"
    $proc.Start() | Out-Null
    
    Write-Verbose "Waiting for $($FilePath.BaseName) to complete"
    $proc.WaitForExit()

    $stdOut = $proc.StandardOutput.ReadToEnd()
    $stdErr = $proc.StandardError.ReadToEnd()
    $exitCode = $proc.ExitCode

    Write-Verbose "Standard Output: $stdOut"
    Write-Verbose "Standard Error: $stdErr"
    Write-Verbose "Exit Code: $exitCode"

    [PSCustomObject]@{
        "StdOut" = $stdOut
        "Stderr" = $stdErr
        "ExitCode" = $exitCode
    }

}

Function Get-NessusStatsFromStdOut {
    
    Param(
        [string]$stdOut
    )
    
    $stats = New-Object System.Collections.Hashtable

    $StdOut -split "`r`n" | % {
        if($_ -like "*:*") {
            $result = $_ -split ":"
            $stats.add(($result[0].Trim() -replace "[^A-Za-z0-9]","_").ToLower(),$result[1].Trim())
        }
    }

    Return $stats
}

Function Get-DateFromEpochSeconds {
    Param(
        [int]$seconds
    )
    
    $utcTime = (Get-Date 01.01.1970)+([System.TimeSpan]::fromseconds($seconds))
    Return Get-Date $utcTime.ToLocalTime() -Format "yyyy-MM-dd HH:mm:ss"
}    

Try {
    $nessusExe = Join-Path $env:ProgramFiles -ChildPath "Tenable\Nessus\nessuscli.exe" -ErrorAction Stop
}  Catch {
    Write-Host "Cannot find NessusCli.exe"
    exit 1
}
    
Write-Host "Getting Agent Status..."
$agentStatus = Start-ProcessGetStreams -FilePath $nessusExe -ArgumentList "managed status"

$notLinkedMsg = "Not linked to a manager"
$warnPattern = "\[warn\] \[scanner\] $notLinkedMsg"

If($agentStatus.stdOut -eq "" -and $agentStatus.StdErr -eq "") {
    Write-Host "No Data Returned from NessusCli"
    exit 1
} elseif($agentStatus.StdErr -match $warnPattern -or $agentStatus.stdOut -match $warnPattern) {
    Write-Host $notLinkedMsg
    exit 0
} elseif($agentStatus.StdOut -eq "" -and $agentStatus.StdErr -ne "") {
    Write-Host "StdErr: $($agentStatus.StdErr)"
    exit 1
} elseif(-not($agentStatus.stdOut -like "*Running: *")) {
    Write-Host "StdOut: $($agentStatus.StdOut)"
    exit 1
} else {
    $stats = Get-NessusStatsFromStdOut -stdOut $agentStatus.StdOut
    If($stats.last_connection_attempt -as [int]) { $stats.last_connection_attempt = Get-DateFromEpochSeconds $stats.last_connection_attempt }
    If($stats.last_connect -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_connect }
    If($stats.last_scanned -as [int]) { $stats.last_scanned = Get-DateFromEpochSeconds $stats.last_scanned }

    $stats | Out-Host
}

关键修改点

  • 新增$warnPattern变量,用转义后的正则表达式匹配警告信息
  • 同时检查StdOut和StdErr两个流的内容,避免遗漏警告
  • 用Write-Host替换Throw,消除错误堆栈的冗余输出
  • 添加exit命令控制脚本流程,匹配到目标状态后直接退出

内容的提问来源于stack exchange,提问作者T-Heron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 06:30:39