Lately I've been writing about techniques to turn command line tools into PowerShell tools. Although I suppose the more accurate description is turning command line output into PowerShell pipelined output. The goal is to run a command line tool and write objects to the PowerShell pipeline so I can do other operations with them. Today I have another example that takes the DNS cache from IPConfig and turns it into a collection of PowerShell objects.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
To understand what I'm talking about open a prompt (Powershell or CMD) and run ipconfig /displaydns.
In text format there is essentially an "object" for each entry separated by the dashed line. What I needed to do was turn that into an PowerShell-based object. If you look at your output you'll see the challenging part is that there isn't necessarily a consistent output for each host. Some entries might not have any record types. When you have output like this I think you need to determine what is really important and is there anything in common you can work with? I decided all I really needed was the record name, its type and value (ie A or CNAME record value).
So my first pass at the output is to pipe it to Select-String.
[cc lang="PowerShell"]
$data=ipconfig /displaydns | select-string "Record "
[/cc]
I'm filtering on the string record followed by a space. Barring some odd result, this should leave me with 3 lines of data for each DNS entry in the cache. Now the fun part. I need to create a new object for every 3 lines of data. I accomplished this with a For construct.
[cc lang="PowerShell"]
for ($i=0;$i -lt $data.count;$i+=3) {
Write-Verbose $data[$i]
...
[/cc]
The "trick" here is that instead of incrementing by 1 each time through the For loop which we typically do, I'm stepping by 3. Within the For loop I can parse each entry.
When you use Select-String, the output is not a simple string but a Match object. I could have messed with the Matches property but I decided it was just as easy to turn each one into a string. Once I have a string, then I can split it on the colon and grab the "value".
[cc lang="PowerShell"]
New-Object -TypeName PSobject -Property @{
Name=$data[$i].toString().Split(":")[1].Trim()
Type=($data[$i+1].toString().Split(":")[1].Trim()) -as [int]
Value=$data[$i+2].toString().Split(":")[1].Trim()
}
[/cc]
Each "value" is added as a property value for a custom object. I like trimming values because you'll often end up with leading and trailing spaces which can cause issues later. Notice also that I'm casing the Type as an [Int}. I did this so any sort on that property will be accurate.
Here's my full sample script.
[cc lang="PowerShell"]
#requires -version 2.0
[cmdletbinding()]
Param()
Write-Verbose "Getting DNS cache information"
#parse dns data looking only for "Record" followed by a space
$data=ipconfig /displaydns | select-string "Record "
Write-Verbose ("Retrieved {0} entries" -f $data.count)
Write-Verbose ("There should be {0} dns records" -f ($data.count/3))
#should be grouped into 3s.
for ($i=0;$i -lt $data.count;$i+=3) {
Write-Verbose $data[$i]
#each item is a Match object so convert to string, split at colon,
#grab the last item and trim it up. Cast the Type as an integer
#so it sorts properly
New-Object -TypeName PSobject -Property @{
Name=$data[$i].toString().Split(":")[1].Trim()
Type=($data[$i+1].toString().Split(":")[1].Trim()) -as [int]
Value=$data[$i+2].toString().Split(":")[1].Trim()
}
} #for
Write-Verbose "Finished parsing DNS cache data"
[/cc]
When I run the script I'll get an object like this for each entry in my DNS cache.
[cc lang="DOS"]
Value Name Type
----- ---- ----
64.191.203.30 digg.com 1
[/cc]
Or I can enjoy all the benefits of the PowerShell pipeline:
[cc lang="DOS"]
PS S:\> .\get-ipconfigdns.ps1 | where {$_.type -eq 1} | sort Name | Select Name,Value
Name Value
---- -----
api.bitly.com 69.58.188.41
api.bitly.com 69.58.188.42
api-ssl.bitly.com 69.58.188.38
api-ssl.bitly.com 69.58.188.37
av3.lyncweb.microsoft.com 65.55.30.131
blog.sapien.com 98.129.229.162
blogpulse.com 208.64.96.141
client1.jdhlab.local 172.16.10.192
...
[/cc]
I don't expect you to use this script in a production environment, but maybe you'll find a technique or two that might help.
Download Get-IpconfigDNS and let me know what you think.