Welcome PowerShell User! This recipe is just one of the hundreds of useful resources contained in the PowerShell Cookbook.
If you own the book already, login here to get free, online, searchable access to the entire book's content.
If not, the Windows PowerShell Cookbook is available at Amazon, or any of your other favourite book retailers. If you want to see what the PowerShell Cookbook has to offer, enjoy this free 90 page e-book sample: "The Windows PowerShell Interactive Shell".
You want to add your own custom properties or methods to all objects of a certain type.
Use the Update-TypeData
cmdlet to add custom members to all objects of a type.
Update-TypeData
-TypeName
AddressRecord
`
-MemberType
AliasProperty
-Membername
Cell
-Value
Phone
Alternatively, use custom type extension files.
Although the Add-Member
cmdlet is extremely useful in helping you add custom members to individual objects, it requires that you add the members to each object that you want to interact with. It does not let you automatically add them to all objects of that type. For that purpose, PowerShell supports another mechanism—custom type extensions.
The simplest and most common way to add members to all instances of a type is through the Update-TypeData
cmdlet. This cmdlet supports aliases, notes, script methods, and more:
$r
=
[PSCustomObject]
@{
Name
=
"Lee"
;
Phone
=
"555-1212"
;
SSN
=
"123-12-1212"
}
$r
.
PSTypeNames
.
Add
(
"AddressRecord"
)
Update-TypeData
-TypeName
AddressRecord
`
-MemberType
AliasProperty
-Membername
Cell
-Value
Phone
Custom type extensions let you easily add your own features to any type exposed by the system. If you write code (for example, a script or function) that primarily interacts with a single type of object, then that code might be better suited as an extension to the type instead.
For example, imagine a script that returns the free disk space on a given drive. That might be helpful as a script, but instead you might find it easier to make PowerShell’s PSDrive
objects themselves tell you how much free space they have left.
In addition to the Update-TypeData
approach, PowerShell supports type extensions through XML-based type extension files. Since type extension files are XML files, make sure that your customizations properly encode the characters that have special meaning in XML files, such as <
, >
, and &
.
For more information about the features supported by these formatting XML files, type Get-Help about_format.ps1xml
.
If you haven’t done so already, the first step in creating a type extension file is to create an empty one. The best location for this is probably in the same directory as your custom profile, with the filename Types.Custom.ps1xml, as shown in Example 3-11.
<?xml version="1.0" encoding="utf-8" ?> <Types> </Types>
Next, add a few lines to your PowerShell profile so that PowerShell loads your type extensions during startup:
$typeFile
=
(
Join-Path
(
Split-Path
$profile
)
"Types.Custom.ps1xml"
)
Update-TypeData
-PrependPath
$typeFile
By default, PowerShell loads several type extensions from its internal configuration stores. The Update-TypeData
cmdlet tells PowerShell to also look in your
Types.Custom.ps1xml file for extensions. The -PrependPath
parameter makes PowerShell favor your extensions over the built-in ones in case of conflict.
Once you have a custom types file to work with, adding functionality becomes relatively straightforward. As a theme, these examples do exactly what we alluded to earlier: add functionality to PowerShell’s PSDrive
type.
PowerShell does this automatically. Type Get-PSDrive
to see the result.
To support this, you need to extend your custom types file so that it defines additions to the System.Management.Automation.PSDriveInfo
type, shown in Example 3-12. System.Management.Automation.PSDriveInfo
is the type that the Get-PSDrive
cmdlet generates.
<?xml version="1.0" encoding="utf-8" ?> <Types> <Type> <Name>System.Management.Automation.PSDriveInfo</Name> <Members> add members such as <ScriptProperty> here <Members> </Type> </Types>
A ScriptProperty
lets you add properties (that get and set information) to types, using PowerShell script as the extension language. It consists of three child elements: the Name
of the property, the getter of the property (via the GetScriptBlock
child), and the setter of the property (via the SetScriptBlock
child).
In both the GetScriptBlock
and SetScriptBlock
sections, the $this
variable refers to the current object being extended. In the SetScriptBlock
section, the $args[0]
variable represents the value that the user supplied as the righthand side of the
assignment.
Example 3-13 adds an AvailableFreeSpace
ScriptProperty
to PSDriveInfo
, and should be placed within the members section of the template given in Example 3-12. When you access the property, it returns the amount of free space remaining on the drive. When you set the property, it outputs what changes you must make to obtain that amount of free space.
<ScriptProperty> <Name>AvailableFreeSpace</Name> <GetScriptBlock> ## Ensure that this is a FileSystem drive if($this.Provider.ImplementingType -eq [Microsoft.PowerShell.Commands.FileSystemProvider]) { ## Also ensure that it is a local drive $driveRoot = $this.Root $fileZone = [System.Security.Policy.Zone]::CreateFromUrl( $driveRoot).SecurityZone if($fileZone -eq "MyComputer") { $drive = New-Object System.IO.DriveInfo $driveRoot $drive.AvailableFreeSpace } } </GetScriptBlock> <SetScriptBlock> ## Get the available free space $availableFreeSpace = $this.AvailableFreeSpace ## Find out the difference between what is available, and what they ## asked for. $spaceDifference = (([long] $args[0]) - $availableFreeSpace) / 1MB ## If they want more free space than they have, give that message if($spaceDifference -gt 0) { $message = "To obtain $args bytes of free space, " + " free $spaceDifference megabytes." Write-Host $message } ## If they want less free space than they have, give that message else { $spaceDifference = $spaceDifference * -1 $message = "To obtain $args bytes of free space, " + " use up $spaceDifference more megabytes." Write-Host $message } </SetScriptBlock> </ScriptProperty>
An AliasProperty
gives an alternative name (alias) for a property. The referenced property doesn’t need to exist when PowerShell processes your type extension file, since you (or another script) might later add the property through mechanisms such as the Add-Member
cmdlet.
Example 3-14 adds a Free
AliasProperty
to PSDriveInfo
, and it should also be placed within the members section of the template given in Example 3-12. When you access the property, it returns the value of the AvailableFreeSpace
property. When you set the property, it sets the value of the AvailableFreeSpace
property.
<AliasProperty> <Name>Free</Name> <ReferencedMemberName>AvailableFreeSpace</ReferencedMemberName> </AliasProperty>
A ScriptMethod
lets you define an action on an object, using PowerShell script as the extension language. It consists of two child elements: the Name
of the property and the Script
.
In the script element, the $this
variable refers to the current object you are extending. Like a standalone script, the $args
variable represents the arguments to the method. Unlike standalone scripts, ScriptMethod
s do not support the param
statement for parameters.
Example 3-15 adds a Remove
ScriptMethod
to PSDriveInfo
. Like the other additions, place these customizations within the members section of the template given in Example 3-12. When you call this method with no arguments, the method simulates removing the drive (through the -WhatIf
option to Remove-PSDrive
). If you call this method with $true
as the first argument, it actually removes the drive from the PowerShell session.
<ScriptMethod> <Name>Remove</Name> <Script> $force = [bool] $args[0] ## Remove the drive if they use $true as the first parameter if($force) { $this | Remove-PSDrive } ## Otherwise, simulate the drive removal else { $this | Remove-PSDrive -WhatIf } </Script> </ScriptMethod>
PowerShell supports several additional features in the types extension file, including CodeProperty
, NoteProperty
, CodeMethod
, and MemberSet
. Although not generally useful to end users, developers of PowerShell providers and cmdlets will find these features helpful. For more information about these additional features, see the PowerShell software developer’s kit (SDK) or the Microsoft documentation.