Typing Lesson: Taking PowerShell Farther with Object Types
If there's such thing as a secret sauce to PowerShell, the PowerShell team has added it to the types.ps1xml file.
- By Jeffery Hicks
An often overlooked feature of Windows PowerShell is its extensibility. With a little effort on your part, you can add features to PowerShell that will make your job easier to do. The Microsoft PowerShell team couldn't think of everything you might need, but they at least gave us the tools to extend PowerShell.
Remember that everything in PowerShell is an object. When you pipe an object to Get-Member, you can discover its properties:
PS C:\Scripts> get-item $profile | get-member
You can pick any file. I simply grabbed my profile script. Many of the properties are part of the underlying .NET object, System.IO.FileInfo. What's interesting is, if you compare the object documentation in MSDN with these properties you'll find some new ones. Where did they come from? They were added by the PowerShell team.
Every object type is defined in the types.ps1xml file, which you'll find in the $PSHOME directory. The reason you should care is because you can add your own type extensions and new properties. Let me show you how.
First off: Never modify the ps1xml files in $PSHome. They are digitally signed by Microsoft and could be replaced with new versions during upgrades or patches. Instead, we're going to create a new ps1xml file. I always suggest opening types.ps1xml and finding the object type you want to extend. Then copy a section that is close to what you want to accomplish. Paste it into your new file.
The tags in these XML files are case sensitive, so be careful. You also need to make sure you have closing tags for everything. Finally, don't forget you'll need to keep the same tag hierarchy, like this:
<Name>Object Type Name</Name>
Insert your new definitions here
I also like to include the XML version tag at the beginning. You can see that in my finished example below. You can define as many members (i.e., properties) as you want in a single file.
I'm going to create a new property for a File object called Owner, that will return the Owner value from the access control list. I'll accomplish this with a ScriptProperty called Owner. The value will be returned by the underlying scritpblock, where $this represents the current object. Here's my completed file:
<?xml version="1.0" encoding="utf-8" ?>
I save this as FileOwner.ps1xml. To load it into PowerShell, I use the Update-TypeData cmdlet. I need to specify the path to the ps1xml file, but I also need to tell PowerShell whether to load my type extension ahead of PowerShell's, using -PrependPath or after with-AppendPath:
PS C:\> Update-TypeDate -AppendPath c:\scripts\fileowner.ps1xml
In this particular case, it doesn't make much difference since I'm defining something completely new. But if you were redefining an existing property, then you might want to make a different decision. By the way, if you make a mistake with your XML file, you have to restart PowerShell and then reload the corrected file.
But now when I get a file and pipe it to Get-Member, I'll see a new property called Owner. PowerShell doesn't have a default way to view that property, but since I know it's there I can simply call it.
PS C:\Scripts> get-item $profile | select name,owner
Your first typing lesson might be a little rough, but once you get the XML formatted properly, it's not too difficult to get PowerShell objects in...uh...type-top shape.
Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.