HashTables and New-Object -Property in Powershell

There are many uses for the New-Object cmdlet. One of the more obvious uses is to transform a HashTable to a PSObject, perhaps to be pipelined into Format-Table.

New-Object PSObject -Property @{
    Name = "Justin Dearing";
    Occupation = ".NET Developer"
}

That is a convenient output formatting trick because you can then pass it to an Out-* or Format-* cmdlet. However, this trick has uses beyond formatting. For example, lets say you encapsulated web service calls into a PowerShell module via the New-WebServiceProxy cmdlet. If the parameters of the service methods of the object in question aren’t .NET primitives like strings and ints, you will need to figure out how your wrapper functions will take those parameters. Once again New-Object -Property and a HashTable. Consider this contrived example:

$service = New-WebServiceProxy http://somedomain/webservices/something.svc?wsdl  -Namespace SomeService

function Get-Something ([HashTable]$SomethingRequest) {
    $request = New-Object SomeService.GetSomethingRequest -Property $SomethingRequest;
    return $service.GetSomethingRequest($SomethingRequest);
}

Note that you might want to use Parameter Sets to allow the user of your module to pass either a HashTable or the native request object in production.

One final note, you need to be aware that New-Object’s -Property parameter doesn’t handle nested HashTable’s. To Illustrate, consider the following PowerShell snippet:

Add-Type -TypeDefinition @"

public class Child {
	string name;
	public string Name {
		get { return name; }
		set { name = value; }
	}

	string email;
	public string Email {
		get { return email; }
		set { email = value; }
	}
}

public class Container {
	string name;
	public string Name {
		get { return name; }
		set { name = value; }
	}

	private Child myChild;
	public Child MyChild {
	 	get { return myChild; }
		set { myChild = value; }
	}
}
"@

$container = New-Object Container -Property @{
	Name = 'My Container'
	MyChild = @{
		Name = 'Justin Dearing'
		Email = 'justin@dearing.com'
	}
}

This will return the following error:

New-Object : The value supplied is not valid, or the property is read-only. Change the value, and then try again.
At C:UsersjdearingAppDataLocalTempe072a665-0543-4b85-9489-e843b9b932e5.ps1:32 char:24
+ $container = New-Object <<<< Container -Property @{
 + CategoryInfo : InvalidData: (:) [New-Object], Exception
 + FullyQualifiedErrorId : InvalidValue,Microsoft.PowerShell.Commands.NewObjectCommand

The workaround for this is you have to call New-Object on $container.MyChild first as follows:

Add-Type -TypeDefinition @"

public class Child {
	string name;
	public string Name {
		get { return name; }
		set { name = value; }
	}

	string email;
	public string Email {
		get { return email; }
		set { email = value; }
	}
}

public class Container {
	string name;
	public string Name {
		get { return name; }
		set { name = value; }
	}

	private Child myChild;
	public Child MyChild {
	 	get { return myChild; }
		set { myChild = value; }
	}
}
"@

$container = @{
	Name = 'My Container'
	MyChild = @{
		Name = 'Justin Dearing'
		Email = 'justin@dearing.com'
	}
}

$container.MyChild = New-Object Child -Property $container.MyChild;
$container = New-Object Container -Property $container;

Naturally, your code can get very verbose if your class is very complicated. You could probably write a script that reflects on the object type and handles nested HashTables. I’ll leave that as an exercise to the reader.

These three examples should help you gain a better understanding of the New-Object cmdlet and HashTable’s in PowerShell.