Over the last few years I've written and presented a bit on the idea of turning command line tools into PowerShell tools. We have a lot of great CLI based tools that are still worth using. What I've done is come up with tools and techniques for turning their output into an object that can be used in the PowerShell pipeline. Often all I need to do is parse and clean up command line output. But one thing that has always nagged me is what to use for property names.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
For example, I can pretty easily turn output from the ARP.EXE command into objects. Here's what I start with.

What I want to do is take the column headings and turn them into properties. The problem is I don't like spaces in property names. Plus, I would need to know in advance the command line heading so I could use something like a custom hashtable to rename. I was after something a bit more convenient and something that would work with almost any command line output, although I think tabular output works best. Thus I came up with a short function I call Convert-StringProperty.
Function Convert-StringProperty {
<#
.Synopsis
Convert strings to proper case property names.
.Description
This function will take strings like principal_id and convert it into a form
more suitable for a property name, ie PrincipalID. If the text doesn't contain
the delimiter, which by default is a single space, then the first character will
be set to upper case. Otherwise, the string is is split on the delimiter, each
first character is set to upper case and then everything joined back together.
.Example
PS C:\> Convert-StringProperty principal_id
PrincipalId
.Example
PS C:\> $raw = arp -g | select -Skip 2
This command will get ARP data. It can then be processed using this function:
PS C:\> [regex]$rx="\s{2,}"
PS C:\> $properties = $rx.Split($raw[0].trim()) | Convert-StringProperty
PS C:\> for ($i=1;$i -lt $raw.count; $i++) {
$splitData = $rx.split($raw[$i].Trim())
#create an object for each entry
$hash = [ordered]@{}
for ($j=0;$j -lt $properties.count;$j++) {
$hash.Add($properties[$j],$splitData[$j])
}
[pscustomobject]$hash
}
InternetAddress PhysicalAddress Type
--------------- --------------- ----
172.16.10.1 00-13-d3-66-50-4b dynamic
172.16.10.100 00-0d-a2-01-07-5d dynamic
172.16.10.101 2c-76-8a-3d-11-30 dynamic
172.16.10.199 00-0a-cd-25-28-99 dynamic
172.16.10.254 20-4e-7f-b5-0f-1a dynamic
172.16.100.1 c4-3d-c7-48-16-ee dynamic
172.16.255.255 ff-ff-ff-ff-ff-ff static
224.0.0.22 01-00-5e-00-00-16 static
224.0.0.251 01-00-5e-00-00-fb static
224.0.0.252 01-00-5e-00-00-fc static
239.255.255.250 01-00-5e-7f-ff-fa static
255.255.255.255 ff-ff-ff-ff-ff-ff static
.Notes
Last Updated: 3/27/2014
Version : 0.9.6
Learn more:
PowerShell in Depth: An Administrator's Guide
PowerShell Deep Dives
Learn PowerShell 3 in a Month of Lunches
Learn PowerShell Toolmaking in a Month of Lunches
****************************************************************
* DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
* THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF *
* YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
* DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. *
****************************************************************
.Link
https://jdhitsolutions.com/blog/2014/03/convert-a-string-to-a-powershell-property-name
#>
[cmdletbinding()]
Param(
[Parameter(Position=0,Mandatory=$True,
HelpMessage="Enter a string to convert",
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True)]
[ValidateNotNullorEmpty()]
[Alias("name")]
[string]$Text,
[ValidateNotNullorEmpty()]
[string]$Delimiter = " "
)
Begin {
Write-Verbose -Message "Starting $($MyInvocation.Mycommand)"
Write-Verbose "Using delimiter: $Delimiter"
#define a regular expression pattern
[regex]$rx = "[^$Delimiter]+"
} #begin
Process {
Write-Verbose "Converting $Text"
#initialize the output string for the new property name
[string]$Output=""
#find each word
$rx.Matches($text) | foreach {
#capitalize the first letter of each word
$value = "{0}{1}" -f $_.value[0].tostring().ToUpper(),$_.value.tostring().substring(1).ToLower()
#and add to output stipping off any extra non word characters
$output+= $Value -replace "\W+",""
} #foreach
#send the new string to the pipeline
$Output
$counter++
} # process
End {
Write-Verbose -Message "Ending $($MyInvocation.Mycommand)"
} #end
} #end function
Here's how it works. I'll take the raw ARP output and skip the first couple of lines.
$raw = arp -g | select -Skip 2
The $raw variable has the data I want to turn into objects.
Internet Address Physical Address Type 172.16.10.1 00-13-d3-66-50-4b dynamic 172.16.10.100 00-0d-a2-01-07-5d dynamic 172.16.10.101 2c-76-8a-3d-11-30 dynamic 172.16.10.199 00-0a-cd-25-28-99 dynamic 172.16.10.254 20-4e-7f-b5-0f-1a dynamic 172.16.30.212 94-de-80-84-8d-4d dynamic 172.16.100.1 c4-3d-c7-48-16-ee dynamic 172.16.255.255 ff-ff-ff-ff-ff-ff static 224.0.0.22 01-00-5e-00-00-16 static 224.0.0.251 01-00-5e-00-00-fb static 224.0.0.252 01-00-5e-00-00-fc static 239.255.255.246 01-00-5e-7f-ff-f6 static 239.255.255.250 01-00-5e-7f-ff-fa static 255.255.255.255 ff-ff-ff-ff-ff-ff static
The first line contains the property names but I want them without the spaces. As a separate step, outside of the function, I need to split the first line. I'm going to do that with a regular expression pattern that matches 2 or more white spaces.
[regex]$rx="\s{2,}"
$properties = $rx.Split($raw[0].trim()) | Convert-StringProperty
I can take the first line, item [0], remove leading and trailing spaces and split it. This will give me three strings: Internet Address, Physical Address, and Type. Each of these is then piped to my Convert-StringProperty.
The function will look at each string and split it again based on a delimiter, which by default is a space. But you can specify something different if you run into CLI names like INTERNET_ADDRESS. Each word is then processed with a capital first letter. The end result is camel case so "Internet Address" becomes "InternetAddress".
Once I know what my property names will be, I can continue parsing the command line output and create a custom object.
for ($i=1;$i -lt $raw.count; $i++) {
$splitData = $rx.split($raw[$i].Trim())
#create an object for each entry
$hash = [ordered]@{}
for ($j=0;$j -lt $properties.count;$j++) {
$hash.Add($properties[$j],$splitData[$j])
}
[pscustomobject]$hash
}
You still need to come up with code to process your command line tool, but you can use this function to define proper PowerShell properties. Here's one more example.
$raw = qprocess
$properties = $raw[0] -split "\s{2,}" | Convert-StringProperty
$raw | select -Skip 1 | foreach {
#split each line
$data = $_ -split "\s{2,}"
$hash=[ordered]@{}
for ($i=0;$i -lt $properties.count;$i++) {
#strip off any non word characters
$hash.Add($properties[$i],($data[$i] -replace '\W+',''))
}
[pscustomobject]$hash
}
This takes command output like this:
USERNAME SESSIONNAME ID PID IMAGE jeff services 0 1920 sqlservr.exe >jeff console 1 3312 taskhostex.exe >jeff console 1 3320 ipoint.exe >jeff console 1 3328 itype.exe
And turns it into PowerShell output like this:
Username : jeff Sessionname : services Id : 0 Pid : 1920 Image : sqlservrexe Username : jeff Sessionname : console Id : 1 Pid : 3312 Image : taskhostexexe Username : jeff Sessionname : console Id : 1 Pid : 3320 Image : ipointexe
In another article I'll share with you another tool that takes advantage of this function. Enjoy.

In case you have more than one NIC, you’ll have to filter out NIC specific lines :
arp -g | select-string -Pattern “Interface”,”Internet Address”,^$ -NotMatch | ForEach-Object {$_.tostring()} | foreach {$_.Trim()} | convertfrom-text $arp
Sure. My focus was on taking the CLI output and turning into something to use in the PowerShell pipeline. It is up to you to figure out what text you need to process.