Turning IPConfig DNSCache into PowerShell

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. Continue reading

Ping IP Range

Last week I came across a post on using PowerShell, or more specifically a .NET Framework class, to ping a range of computers in an IP subnet. The original post by Thomas Maurer is here. I added a comment. And after looking at this again I decided to take the ball and run with it a bit further. I’m a big proponent of PowerShell tools that are object oriented and that can add real value to the pipeline. To that end I wrote Test-Subnet. Continue reading

Convert Text to Object

Today I have another tool in my new battle regarding turning command line tools into PowerShell tools. The bottom line is we want to have objects written to the pipeline. At the PowerShell Deep Dive in Frankfurt there was a suggestion about providing tools to help with the transformation from CLI to PowerShell and this is one of the items I came up with.

Many command line tools write output in a structured format. For example run this command:

There’s an “object” staring at us for each task. As an aside, don’t focus on the command line tool I’m using, pay attention to the technique. To turn output like this into ah object we simply need to split each line at the colon. The first index of the array will be the “property” name and the second index is the value. Here’s the function I pulled together.

The function processes each incoming line of text and splits it on the delimiter. The default is the colon since many CLI tools seem to use it.

Since I prefer property names without spaces I remove them from index 0 of the array. I’ve also found it helpful to trim everything to eliminate extra white space.

Each line is then added to a hash table.

When the hash table is complete it is used to create a new object.

The other “trick” I added is to group lines into an object. This let’s me take say every 5 lines of text and make that a single object. I create a counter and increment it whenever a line is processed. When the counter meets the limit, the object is created, the hash table is cleared and the process repeats.

Now I can run a command like this:

The output looks similar but now I have objects so I can take advantage of PowerShell. Here are some examples:

This is by no means perfect but I’d like to think it is a good start. For example, one downside is that all properties are strings where it would be nicer to have properties of an appropriate type. Still, I hope you’ll try this out and let me know what you think.

Download Convert-TexttoObject

Update
A newer version of the script can be found at http://jdhitsolutions.com/blog/2012/01/convert-text-to-object-updated/

Friday Fun Convert Object to Hash Table

I’ve been working on a few PowerShell projects recently and one requirement I had was to turn an object into a hash table. I thought this was something that was already handled in PowerShell but I couldn’t find a cmdlet or an easy .NET technique. So I wrote my own function, ConvertTo-Hashtable.

The function is designed to accept pipelined input and turns each object into an associative array, i.e., a hash table, and write the hash table to the pipeline.

As an object is processed by the function it uses Get-Member to retrieve all of the object’s properties.

The function then walks the object and adds each property name and value to a hash table.

This hash table object, $hash, eventually is written to the pipeline. This process happens to each piped in object. However, I also added a function parameter, -NoEmpty, to filter out properties with no values. When specified, the function creates a second hash table and then checks each key in $hash. If the corresponding item has a value, the key and value are added to the secondary hash.

The secondary hash is then written to the pipeline. I had to take this approach because PowerShell doesn’t like it when you try to modify and enumerate a hash table at the same time. Here’s how you might use it:

Or to filter out the empty values:

Granted, your use case for something like this is probably pretty limited. But there are some good technique examples here on working with hash tables.

The one nagging problem, at least until PowerShell v3, is that it is very difficult to write a sorted hash table. I’d love to write the hash table to the pipeline with sorted keys, but that may have to wait.

In the meantime, feel free to download and experiment with ConvertTo-Hashtable.

Select Object Properties with Values

Here’s another concept I know I’ve written about in the past but that needed an update. A common technique I use when exploring and discovering objects is to pipe the object to Select-Object specifying all properties, get-service spooler | select *. There’s nothing wrong with this approach but depending on the object I might get a lot of empty values. This is especially true with WMI objects or items from Active Directory like a user account. The other issue I have is that when using this technique with a WMI object, I also get the system properties like __PATH, which I’d often like to ignore. The solution I came up is a function called Select-PropertyValue. Pipe objects to the function and it will write a custom object to the pipeline only with properties that have a value.

[cc lang=”PowerShell”]
Function Select-PropertyValue {
[cmdletbinding()]

Param(
[Parameter(Position=0,ValueFromPipeline=$True)]
[object]$InputObject,
[Switch]$NoSystem,
[Switch]$Inquire = $False
)

Begin {
Write-Verbose “Starting $($myinvocation.mycommand)”

#define a variable we will be using to keep StrictMode happy.
[email protected]()
} #begin

Process {

<# set debug preference to continue when using -Debug unless user has also used -Inquire. Otherwise, PowerShell will prompt for each command. Due to scoping issues I found the best solution was to set the debug preference for each object in the pipeline #>

if (($PSCmdlet.MyInvocation.BoundParameters.ContainsKey(“debug”)) -AND (-NOT $Inquire)) {
$DebugPreference=”Continue”
}

Write-Debug “In process”
Write-Debug “Checking for `$properties”
<# because this only takes pipelined objects, we only need to get the properties from Get-Member once. When the second object is processed, this IF block will get skipped. The assumption that all pipelined objects are of the same type. #>

if (-Not $properties) {
Write-Verbose “Creating property list”
Write-Debug “Creating property list for pipelined object”

#get properties for the pipelined object sorted by property name
$properties=$_ | Get-Member -membertype Properties | sort Name
$typename=($_ |Get-Member)[0].TypeName
Write-Debug “Typename =$typename”

#filter out WMI System properties if -NoSystem
if ($NoSystem) {
Write-Verbose “Filtering out WMI System properties”
Write-Debug “Filtering out WMI System properties.”
$properties=$properties | where {$_.name -notlike “__*”}
}

Write-Verbose “Found $($properties.count) properties”
Write-Debug “Found $($properties.count) properties”
}

#create an empty custom object
Write-Debug “Creating empty object”
$obj=New-Object PSObject

#enumerate the list of properties
Write-Verbose “Checking properties for values”
foreach ($property in $properties) {
Write-Debug “Checking $($property.name)”
#if object has a value for the current property
if ($_.($property.name)) {
Write-Debug “found value for: $($_.($property.name))”

#assign properties to the custom object
Write-Debug “Adding property and value to custom object”
$obj | Add-Member -MemberType Noteproperty -name $property.Name -value ($_.($property.name))

} #end If
} #end ForEach

#Add the typename to the object
Write-Debug “Adding typename to custom object”
$obj | Add-Member -MemberType Noteproperty -Name “Type” -Value $typename

#write the custom object to the pipeline
Write-Debug “Writing custom object to the pipeline”
Write $obj
} #end process

End {
Write-Verbose “Ending $($myinvocation.mycommand)”
}

} #end function
[/cc]

The function is intended to be used in a pipelined expression and assumes that all the objects are of the same type. The essence of the function is to run each object through Get-Member and keep a list of property names.

[cc lang=”PowerShell”]
if (-Not $properties) {
Write-Verbose “Creating property list”
Write-Debug “Creating property list for pipelined object”
$properties=$_ | Get-Member -membertype Properties | sort Name
[/cc]

Because this happens in the process script block, which runs once for every piped in object, this line only runs if $properties doesn’t already exist. If the user includes the -NoSystem parameter, then any property that starts with __ is removed.

[cc lang=”PowerShell”]
if ($NoSystem) {
Write-Verbose “Filtering out WMI System properties”
Write-Debug “Filtering out WMI System properties.”
$properties=$properties | where {$_.name -notlike “__*”}
}
[/cc]

Armed with the array of property names, the pipelined object is checked for each property name.

[cc lang=”PowerShell”]
foreach ($property in $properties) {
Write-Debug “Checking $($property.name)”
#if object has a value for the current property
if ($_.($property.name)) {
Write-Debug “found value for: $($_.($property.name))”
[/cc]

If a value is found

[cc lang=”PowerShell”]
if ($_.($property.name))
[/cc]

Then the property and value are added to the blank custom object which is created for each piped object.

[cc lang=”PowerShell”]
$obj | Add-Member -MemberType Noteproperty -name $property.Name -value ($_.($property.name))
[/cc]

I include the object type name and write the custom object to the pipeline.

[cc lang=”PowerShell”]
#Add the typename to the object
Write-Debug “Adding typename to custom object”
$obj | Add-Member -MemberType Noteproperty -Name “Type” -Value $typename

#write the custom object to the pipeline
Write-Debug “Writing custom object to the pipeline”
Write $obj
[/cc]

Here’s the end result.

[cc lang=”DOS”]
BiosCharacteristics : {4, 7, 8, 9…}
BIOSVersion : {TOSQCI – 6040000, Ver 1.00PARTTBL}
Caption : Ver 1.00PARTTBL
Description : Ver 1.00PARTTBL
Manufacturer : TOSHIBA
Name : Ver 1.00PARTTBL
PrimaryBIOS : True
ReleaseDate : 20101210000000.000000+000
SerialNumber : Z9131790W
SMBIOSBIOSVersion : V2.90
SMBIOSMajorVersion : 2
SMBIOSMinorVersion : 6
SMBIOSPresent : True
SoftwareElementID : Ver 1.00PARTTBL
SoftwareElementState : 3
Status : OK
Version : TOSQCI – 6040000
Type : System.Management.ManagementObject#root\cimv2\Win32_BIOS
[/cc]

You probably also noticed the Write-Verbose and Write-Debug lines in the script. Continuing the discussion I started in my post on Write-Verbose vs Write-Debug, I’m including the suggestion on controlling the debug preference. By default if you the function with -debug you’ll get all the debug messages. But if you also use -Inquire, then you’ll get prompted for each command which is the normal process when using -Debug. I wanted to see how this would work in one of my own scripts.

As always, I hope you’ll let me know how this works out for you. Download Select-PropertyValue. The full script includes comment-based help as well as an optional alias. Uncomment the last line of the script if you want to use it or define your own.