0

Using PowerShell, how does one assign and append the output of a command that produces a continuous 'stream' of data to a variable in memory as opposed to a file?

I am attempting to write a script that captures DHCP Offer packets returned to the client device. When I issue the following commands one by one natively in PowerShell (while a DHCP discover packet generator is executed on the same client device):

pktmon filter add -t udp -p 68
pktmon start --etw --log-mode real-time | Select-String ".67 > 255.255.255.255.68"

The expected output is shown on the console. I have to press CTRL+C to exit.

PS C:\Test> pktmon start --etw --log-mode real-time | Select-String ".67 > 255.255.255.255.68" | Select-String -notmatch "ssap SNAP"

        E0-CB-BC-2A-C7-20 > FF-FF-FF-FF-FF-FF, ethertype IPv4 (0x0800), length 342: 10.0.0.254.67 > 255.255.255.255.68: UDP, length 300
        E0-CB-BC-2A-C7-20 > FF-FF-FF-FF-FF-FF, ethertype IPv4 (0x0800), length 342: 10.0.0.254.67 > 255.255.255.255.68: UDP, length 300
        E0-CB-BC-2A-C7-20 > FF-FF-FF-FF-FF-FF, ethertype IPv4 (0x0800), length 342: 10.0.0.254.67 > 255.255.255.255.68: UDP, length 300
        E0-CB-BC-2A-C7-20 > FF-FF-FF-FF-FF-FF, ethertype IPv4 (0x0800), length 342: 10.0.0.254.67 > 255.255.255.255.68: UDP, length 300
        E0-CB-BC-2A-C7-20 > FF-FF-FF-FF-FF-FF, ethertype IPv4 (0x0800), length 342: 10.0.0.254.67 > 255.255.255.255.68: UDP, length 300

But when I add the same command to a variable within a script:

pktmon filter add -t udp -p 68 | Out-Null
Write-Host "Detecting DHCP Servers...." -ForegroundColor Green
$result = pktmon start --etw --log-mode real-time | Select-String ".67 > 255.255.255.255.68" | Select-String -notmatch "ssap SNAP"
$result
pktmon stop | Out-Null
pktmon filter remove | Out-Null

The script runs through and completes without any output, or any errors. I have no issue when appending it to a text file. I am assuming that the line:

$result = pktmon start --etw --log-mode real-time | Select-String ".67 > 255.255.255.255.68" | Select-String -notmatch "ssap SNAP" | Out-Null

doesn't wait for data to be received and stored in the $result variable and the script immediately executes the lines of code that follow.

Please forgive me as this is my first PowerShell script. I have tried searching the forums but I am obviously not using the correct terminology.

--UPDATE--

Simply adding | Write-Output to capture the variable did the trick for me.

$result = pktmon start --etw --log-mode real-time | Select-String ".67 > 255.255.255.255.68" | Select-String -notmatch "ssap SNAP" | Write-Output

Thanks

HazyMaze
  • 23
  • 4
  • 3
    Why are you piping to `| Out-Null`? The `Out-Null` cmdlet "Hides the output instead of sending it down the pipeline or displaying it." https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/out-null?view=powershell-7.2 – codaamok Apr 24 '22 at 11:04
  • Ahh sorry - the | Out-Null wasn't supposed to be there on the $result variable line. I used it on the other lines as it output unnecessary junk to the console (particularly the 'pktmon stop' command). I've removed it with no effect. – HazyMaze Apr 24 '22 at 11:15

1 Answers1

2

Trying to catch output from native binaries in PowerShell can sometimes be tricky.

With this line (below), you are discarding the output to NULL, therefore it would never be stored in the $result variable.

$result = pktmon start --etw --log-mode real-time | Select-String ".67 > 255.255.255.255.68" | Select-String -notmatch "ssap SNAP" | Out-Null

I recommend removing the | Out-Null at the end of this line, and it should put the output in the $result variable.

If removing the pipe to Out-Null still does not capture the output from pktmon to the $result variable, you can try using a function like Invoke-NativeCommand. This function is nice because it can redirect native command output streams to the desired PowerShell output stream, too.

$result = (Invoke-NativeCommand pktmon start --etw --log-mode real-time) | Select-String ".67 > 255.255.255.255.68" | Select-String -notmatch "ssap SNAP"

If you prefer not to use a function and want to try and keep things 'vanilla', see this question How do I capture the output into a variable from an external process in PowerShell?.

codaamok
  • 717
  • 3
  • 11
  • 21
  • The `Out-Null` on the `result` variable line was a mistake - I removed it but still faced the same issue. However your "vanilla" options post led me to discover the `Write-Host` command which worked perfectly, so thank you! I just need to figure out how to gracefully close the external `pktmon` executable - when run natively, a CTRL+C is the only way to close it.) – HazyMaze Apr 24 '22 at 12:21
  • 1
    @HazyMaze I recommend looking into PowerShell jobs: jobs let you invoke a PowerShell script / code as an asynchronous process. – codaamok Apr 24 '22 at 12:25
  • thank you for pointing me in the right direction, it's much appreciated. – HazyMaze Apr 24 '22 at 12:31
  • 1
    Write-host will put it in the console. For the user to see. But is not interactable. If you want other commands to interact with it use write-output. – Robert Cotterman Apr 25 '22 at 01:55