Tag Archives: get-member

Convert PowerShell Object to Hashtable Revised

squarepatternA while back I posted an advanced PowerShell function that would take an object and convert it to a hashtable. The premise was simple enough: look at the incoming object with Get-Member to discover the property names then create a hashtable with each property name as a hashtable key. I’ve a need to use this over the last few weeks and realized the function could use a little updating.

The new version works like the old, with the addition of one new parameter. I decided I wanted a way to exclude properties from the hashtable. Of course this presumes you know in advance about the object you are working with and what properties you wish to exclude. This is the core segment of code, which has also been revised over version 1.

In the first version I was duplicating some code and I generally try to avoid that. In this snippet $names is the collection of property names and $Inputobject is the piped in object. Armed with this tool I can create hashtables from objects with just the properties I want.

This version should work in PowerShell 2.0 or 3.0. Download ConvertTo-Hashtable2.

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.
$properties=@()
} #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.