Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Microsoft Exchange Server 2013 PowerShell Cookbook: Second Edition

You're reading from   Microsoft Exchange Server 2013 PowerShell Cookbook: Second Edition Benefit from over 120 recipes that tackle the everyday issues that arise with Microsoft Exchange Server. Using PowerShell you'll learn to add scripts that provide new functions and efficiencies. Only basic knowledge required.

Arrow left icon
Product type Paperback
Published in May 2013
Publisher Packt
ISBN-13 9781849689427
Length 504 pages
Edition 2nd Edition
Concepts
Arrow right icon
Toc

Table of Contents (23) Chapters Close

Microsoft Exchange Server 2013 PowerShell Cookbook
Credits
About the Authors
Acknowledgement
About the Reviewers
www.PacktPub.com
Preface
1. PowerShell Key Concepts FREE CHAPTER 2. Exchange Management Shell Common Tasks 3. Managing Recipients 4. Managing Mailboxes 5. Distribution Groups and Address Lists 6. Mailbox Database Management 7. Managing Client Access 8. Managing Transport Service 9. High Availability 10. Exchange Security 11. Compliance and Audit Logging 12. Server Monitoring and Troubleshooting 13. Scripting with the Exchange Web Services Managed API Common Shell Information Query Syntaxes Index

Creating custom objects


The fact that PowerShell is an object-based shell gives us a great deal of flexibility when it comes to writing one-liners, scripts, and functions. When generating detailed reports, we need to be able to customize the data output from our code so it can be formatted or piped to other commands that can export the data in a clean, structured format. We also need to be able to control and customize the output from our code so that we can merge data from multiple sources into a single object. In this recipe, you'll learn a few techniques used to build custom objects.

How to do it...

The first thing we'll do is create a collection of mailbox objects that will be used as the data source for a new set of custom objects:

$mailboxes = Get-Mailbox

You can add custom properties to any object coming across the pipeline using calculated properties. This can be done using either the Select-Object or Format-Table cmdlets:

$mailboxes | 
  Select-Object Name,
    Database,
    @{name="Title";expression={(Get-User $_.Name).Title}},
    @{name="Dept";expression={(Get-User $_.Name).Department}}

Another easy way to do this is by assigning a hash table to the -Property parameter of the New-Object cmdlet:

$mailboxes | %{
  New-Object PSObject -Property @{
    Name = $_.Name
    Database = $_.Database
    Title = (Get-User $_.Name).Title
    Dept = (Get-User $_.Name).Department
  }
}

You can also use the New-Object cmdlet to create an empty custom object, and then use the Add-Member cmdlet to tack on any custom properties that are required:

$mailboxes | %{
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty Name $_.Name
  $obj | Add-Member NoteProperty Database $_.Database
  $obj | Add-Member NoteProperty Title (Get-User $_.Name).Title
  $obj | Add-Member NoteProperty Dept (Get-User $_.Name).Department
  Write-Output $obj
}

Each of these three code samples will output the same custom objects that combine data retrieved from both the Get-Mailbox and Get-User cmdlets. Assuming that the Title and Department fields have been defined for each user, the output would look similar to the following:

How it works...

The reason we're building a custom object here is because we want to merge data from multiple sources into a single object. The Get-Mailbox cmdlet does not return the Title or Department properties that are tied to a user account: the Get-User cmdlet needs to be used to retrieve that information. Since we may want to generate a report that includes information from both the Get-Mailbox and Get-User cmdlets for each individual user, it makes sense to build a custom object that contains all of the required information. We can then pipe these objects to other cmdlets that can be used to export this information to a file.

We can modify one of our previous code samples and pipe the output to a CSV file used to document this information for the current user population:

$mailboxes | 
  Select-Object Name,
    Database,
    @{n="Title";e={(Get-User $_.Name).Title}},
    @{n="Dept";e={(Get-User $_.Name).Department}} | 
      Export-CSV –Path C:\report.csv -NoType

Keep in mind that even though you can also create calculated properties using the Format-Table cmdlet, you'll want to use Select-Object, as shown previously, when converting these objects to CSV or HTML reports. These conversion cmdlets do not understand the formatting information returned by the Format-Table cmdlet, and you'll end up with a lot of useless data if you try to do this.

When building custom objects with the Select-Object cmdlet, we can select existing properties from objects coming across the pipeline and also add one or more calculated properties. This is done by using a hash table that defines a custom property name in the hash table key and a script block within the hash table value. The script block is an expression where you can run one or more commands to define the custom property value. In our previous example, you can see that we've called the Get-User cmdlet to retrieve both the Title and Department properties for a user that will be assigned to calculated properties on a new object.

The syntax for creating a calculated property looks a little strange at first glance since it uses name and expression keywords to create a hash table that defines the calculated property. You can abbreviate these keywords as shown next:

$mailboxes | 
  Select-Object Name,
    Database,
    @{n="Title";e={(Get-User $_.Name).Title}},
    @{n="Dept";e={(Get-User $_.Name).Department}}

The property name uses the string value assigned to n, and the property value is assigned to e using a script block. Abbreviating these keywords with n and e just makes it easier to type. You can also use label or l to provide the calculated property name.

Using the New-Object cmdlet and assigning a hash table to the -Property parameter is a quick and easy way to create a custom object. The only issue with this technique is that the properties can be returned in a random order. This is due to how the .NET Framework assigns random numeric values to hash table keys behind the scenes, and the properties are sorted based on those values, not in the order that you've defined them. The only way to get the properties back in the order you want is to continue to pipe the command to Select-Object and select the property names in order, or use one of the other techniques shown in this recipe.

Creating an empty custom object and manually adding note properties with the Add-Member cmdlet can require a lot of extra typing, so generally this syntax is not widely used. This technique becomes useful when you want to add script methods or script properties to a custom object, but this is an advanced technique that we won't need to utilize for the recipes in the remainder of this book.

There's more...

There is another useful technique for creating custom objects which utilizes the Select-Object cmdlet. Take a look at the following code:

$mailboxes | %{
  $obj = "" | Select-Object Name,Database,Title,Dept
  $obj.Name = $_.Name
  $obj.Database = $_.Database
  $obj.Title = (Get-User $_.Name).Title
  $obj.Dept = (Get-User $_.Name).Department
  Write-Output $obj
}

You can create a custom object by piping an empty string variable to the Select-Object cmdlet, specifying the property names that should be included. The next step is to simply assign values to the properties of the object using the property names that you've defined. This code loops through the items in our $mailboxes object and returns a custom object for each one. The output from this code returns the same exact objects as all of the previous examples.

Watch out for concurrent pipeline errors

One of the reasons we first stored the collection of mailboxes in the $mailbox variable is due to the way PowerShell deals with multiple cmdlets executing through a remote session. Ideally, we would just do the following:

Get-Mailbox | %{
  New-Object PSObject -Property @{
    Name = $_.Name
    Database = $_.Database
    Title = (Get-User $_.Name).Title
    Dept = (Get-User $_.Name).Department
  }
}

Unfortunately, even though this syntax is completely valid, it will not work consistently in the Exchange Management Shell. This is because, as the Get-Mailbox cmdlet is sending objects down the pipeline to ForEach-Object, we're also trying to run the Get-User cmdlet to build our custom object, and PowerShell remoting does not support more than one pipeline executing at a time. To get around this, use the technique shown previously to save the results of the first command to a variable, and then pipe that variable to ForEach-Object. For more details on this, refer to the recipe entitled Dealing with concurrent pipelines in remote PowerShell in Chapter 2, Exchange Management Shell Common Tasks.

See also

  • The Looping through items recipe

  • The Working with variables and objects recipe

  • The Exporting reports to text and CSV files recipe in Chapter 2, Exchange Management Shell Common Tasks

  • The Dealing with concurrent pipelines in remote PowerShell recipe in Chapter 2, Exchange Management Shell Common Tasks

You have been reading a chapter from
Microsoft Exchange Server 2013 PowerShell Cookbook: Second Edition - Second Edition
Published in: May 2013
Publisher: Packt
ISBN-13: 9781849689427
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image