Creating Custom PowerShell Objects

Summary: Use Windows PowerShell to create custom objects prior to data export.

Microsoft Scripting Guy, Ed Wilson, is here. It is nice and cool this morning so I decided to walk over to the neighborhood coffee and tea shop to have a cup of tea. I can sit outside and enjoy the day. There is free wireless Internet, so I brought my Surface Pro 3 to check my email sent to scripter@microsoft.com, hang out on Facebook and Twitter, and generally do all the things I do in my day-to-day life as the Scripting Guy.

Today, I want to look at creating custom objects from Windows PowerShell as a way of outputting the data that I groomed nicely throughout the week. Because I planned on getting to this point in my script from the very outset, it will be pretty easy to put the pieces together to groom my data. I transformed the date, addresses, and names (see Use PowerShell to Normalize Names Before Data Import), so I expect there to be three sections for these. However, in the end, transforming the date was so easy (see Use PowerShell to Fix Date from CSV File) that I decided to code it directly in the portion of the script that creates the custom object.

Also, because I knew I would be putting everything together, I used the same sorts of variables. So the first portion of the script, which reads the CSV file and walks through the collection is the same:

$datain = import-csv C:\DataIn\DataDump.csv

Foreach ($d in $datain)

    {

Now, I define a region for the name. To do this, I use the #region and #endregion tags. Now, I copy the script that I created earlier to normalize names, and I assign it to a region. This is shown here:

#region Name

 If($d.name -match  ',')

        {

          $name = (Get-Culture).textinfo.ToTitleCase($d.name).Split(',').trim()

          $ln = $name[0]

          $fn = $name[1]

          }

        ELSE {

         $name = $d.Name.Split().trim()

         $fn = $name[0]

         $ln = $name[1]

           }

#endregion

Now I add the region for the address. Once again, I copy the essential transforming code from the script I wrote earlier (see Use PowerShell to Fix Address Issues Prior to Export).

I also create an address region so it makes the script easier to read and troubleshoot. The command is shown here:

#region Address

     $a = $d.address.split(',')

     $str = $a[0] -replace '(Street|street)','ST'

     $city = If($a[1] -match 'dwpt') {"Dewpoint"} ELSE {$a[1]}

     $state = if($a[2] -match 'South Carolina') {"SC"} ELSE {$a[2]}

     $zip = If($a[3].trim().Length -gt 5) {"Error for $a"} ELSE {$a[3]}

#endregion

To create and output the custom object, I use the [PSCustomObject] type accelerator, and I assign a hash table to the [PSCustomObject]. Each element in the hash table is in the form of "property name equals value." Almost every value I need is assigned via a variable. The exception is the date. I decided to do this as a single line of code, as shown here:

Date = [datetime]("{0}/{1}/{2}" -f $d.month, $d.day, $d.year)

I also call the ToUpper method on the strings that are stored in the Street and City properties of the object:

Street = $str.ToUpper()

City = $city.ToUpper()

The last thing I do is clean up the state property. I trim it to remove any leading or trailing spaces. I choose only two letters (beginning at the first position), and I make them capital letters. Here is that command:

State = $state.Trim().Substring(0,2).ToUpper()

And that is it. Here is the complete CreateCustomObjectsFromData.ps1 script:

$datain = import-csv C:\DataIn\DataDump.csv

Foreach ($d in $datain)

    {

#region Name

 If($d.name -match  ',')

        {

          $name = (Get-Culture).textinfo.ToTitleCase($d.name).Split(',').trim()

          $ln = $name[0]

          $fn = $name[1]

          }

        ELSE {

         $name = $d.Name.Split().trim()

         $fn = $name[0]

         $ln = $name[1]

           }

#endregion

 

 #region Address

     $a = $d.address.split(',')

     $str = $a[0] -replace '(Street|street)','ST'

     $city = If($a[1] -match 'dwpt') {"Dewpoint"} ELSE {$a[1]}

     $state = if($a[2] -match 'South Carolina') {"SC"} ELSE {$a[2]}

     $zip = If($a[3].trim().Length -gt 5) {"Error for $a"} ELSE {$a[3]}

#endregion

 

#region Create Custom Object

     [PSCustomObject]@{

       Lname = $ln

       Fname = $fn

       Date = [datetime]("{0}/{1}/{2}" -f $d.month, $d.day, $d.year)

       Street = $str.ToUpper()

       City = $city.ToUpper()

       State = $state.Trim().Substring(0,2).ToUpper()

       Zip = $zip }

#endregion

    } 

And here is the output from the script:

Image of command output

That's it for Data Manipulation Week. I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy