This post is about how I wrote a few PowerShell functions to parse the output of the ‘Net.exe’ commands (net user, net localgroup, etc.). (UPDATE: I have since found a better way to do this, so this post documents a less than efficient way to pass and receive objects across a pipeline and is only here for reference. The new script is located here.) This took a lot more time than I thought it would, for reasons I’ll explain, but the TLDR is the script is available on my GitHub and here is how you use it:
If you want to send it to a text file just pipe it to Out-File:
PS > net users /domain | Parse-NetUser | Out-File .\domain_users.txt
Okay, so now some background. The net commands have been around forever and are great for enumerating users and groups and shares, but the output of the net commands don’t work well if you are trying to get a list of items and feed it into other scripts. For net user, the main issue is that the output is displayed in multiple columns, however it also includes unnecessary lines at beginning and the end:
While there are other commands and scripts that can be used to get a properly formatted output, the net commands are typically quick and reliable and I figured it would be fun to write some code to parse the output. Initially, I was just going to write a script that would read in a text file containing the output and then parse it, but I figured it would be much more useful if I could just pipe the command into the script.
Parsing the output didn’t take me a long time to figure out…my real problem was sending an array through the pipeline. It turns out that the output of the net commands is an array.
This turned out to be trouble for me because my parsing code expected to work on the entire array, while the pipeline only processed one item of the array at a time. I wrote the below test function to illustrate my problem.
When I passed the string ‘abc’ through the pipeline the string was processed and ‘abc’ was written to the console. However, when I passed the array @(1,2,3,4,5) through the pipeline only 5 was written to the console.
So after some Internet searches I came across two viable solutions on Stack Overflow (https://stackoverflow.com/questions/29973212/pipe-complete-array-objects-instead-of-array-items-one-at-a-time). The first solution was basically to unarray the array. This would have meant that I would have to the parser like this:
PS C:\Users\Jake> ,(net user) | Parse-NetUser
I didn’t like this solution, because it seemed like less of a solution and more of a hack. The second solution was to use a separate function to process the array and then call another to do the parsing. This function used begin, process, and end blocks to rebuild the array. Here is an example of what how the array gets processed when sent through the pipeline to this function:
As you can see in this example, the array is rebuilt and written to the console, where in the previous example only the last value of the array was written to the console.
My code basically does this, and then passes the array to a function to parse the output. The parsing isn’t too complicated, but I’ll go over a few code snippets from one of the parsing functions to show the basic process.
Recall that this is what we are trying to parse:
The first thing I wanted to do was to remove the lines of the array that I did not need, in this case all lines before and including ‘——–’, and all lines after and including ‘The command completed successfully’.
Here is how I accomplished this:
It turns out that in PowerShell it is difficult to remove slices from an array, and is much easier to create a new array, copying over the required items, which is what I ended up doing.
The next step was to remove the spaces between the user names. Here is how I removed the spaces:
After that I had to do minor parsing based on the function (for example, for the net group I removed the asterisks from the output). Once again, the code is on GitHub if you’re curious how all the code looks together.