PowerShell: Working with the error from Standard Out (using Nessus Essentials)

143 Views Asked by At
Trying to use PowerShell to capture the running status of the "Nessus Essentials" software product.  Simply trying to capture product status: running, not running, or other.  Getting the below error each time. I've tried changing `-like` to `-match` and changing string **[warn] [scanner] Not linked to a manager** to various other shorter versions, with wildcards and without,  to no avail. I still get several lines of an ugly error message when all I want is one line with the string **Not linked to a manager** returned to console with nothing beneath that.  

Pertinent snippet working incorrectly:

    } elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
        Throw "Not linked to a manager"


The Error:
   
[![enter image description here][1]][1]

The Code:
        
    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 {
        Throw "Cannot find NessusCli.exe"
    }
        
    Write-Host "Getting Agent Status..."
    $agentStatus = Start-ProcessGetStreams -FilePath $nessusExe -ArgumentList "managed status"
    
    If($agentStatus.stdOut -eq "" -and $agentStatus.StdErr -eq "") {
        Throw "No Data Returned from NessusCli"
    } elseif($agentStatus.StdOut -eq "" -and $agentStatus.StdErr -ne "") {
        Throw "StdErr: $($agentStatus.StdErr)"
    } elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
        Throw "Not linked to a manager"
    } elseif(-not($agentStatus.stdOut -like "*Running: *")) {
        Throw "StdOut: $($agentStatus.StdOut)"
    } 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_connect = Get-DateFromEpochSeconds $stats.last_scanned }
    }
    
    $stats | Out-Host

Note: Code above is courtesy of [here][2], I've only made a change to the path of Nessus, and I am adding the attempt to capture that it's not connected to a manager.
1

There are 1 best solutions below

0
On

Modify your code so that it separates standard output from error and so that it handles each line separately.

The following is how to capture standard output (excluding else statements and error handling) of a program (according to your $Proc variable)

if ($proc.Start())
{
    while (!$proc.StandardOutput.EndOfStream)
    {
        $StreamLine = $proc.StandardOutput.ReadLine()

        if (![string]::IsNullOrEmpty($StreamLine))
        {
            # TODO: Duplicate code in this scope as needed or rewrite to use multiline regex

            $WantedLine = [regex]::Match($StreamLine, "(?<wanted>.*Not linked to a manager.*)")
            $Capture = $WantedLine.Groups["wanted"]

            if ($Capture.Success)
            {
                Write-Output $Capture.Value
            }
        }
    }
}

After that deal with error output separately:

$StandardError = $Proc.StandardError.ReadToEnd()
if (![string]::IsNullOrEmpty($StandardError))
{
    # Or use Write-Error
    Write-Output $StandardError
}