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 return structured results from a command so that users can easily sort, group, and filter them.
Use the [PSCustomObject]
type cast to a new PSCustomObject
, supplying a hashtable with the custom information as its value, as shown in Example 3-8.
$output
=
[PSCustomObject]
@{
'User'
=
'DOMAIN\User'
;
'Quota'
=
100MB
;
'ReportDate'
=
Get-Date
;
}
If you want to create a custom object with associated functionality, write a PowerShell class in a module, and create an instance of that class:
using
module
c
:
\
modules
\
PlottingObject
.
psm1
$obj
=
[PlottingObject]
::
new
()
$obj
.
Move
(
10
,
10
)
$obj
.
Points
=
SineWave
while
(
$true
)
{
$obj
.
Rotate
(
10
);
$obj
.
Draw
();
Sleep
-m
20
}
When your script outputs information to the user, always prefer richly structured data over hand-formatted reports. By emitting custom objects, you give the end user as much control over your script’s output as PowerShell gives you over the output of its own commands.
Despite the power afforded by the output of custom objects, user-written scripts have frequently continued to generate plain-text output. This can be partly blamed on PowerShell’s previously cumbersome support for the creation and initialization of custom objects, as shown in Example 3-9.
$output
=
New-Object
PsObject
Add-Member
-InputObject
$output
NoteProperty
User
'DOMAIN\user'
Add-Member
-InputObject
$output
NoteProperty
Quota
100MB
Add-Member
-InputObject
$output
NoteProperty
ReportDate
(
Get-Date
)
$output
In PowerShell version 1, creating a custom object required creating a new object (of the type PsObject
), and then calling the Add-Member
cmdlet multiple times to add the desired properties. PowerShell version 2 made this immensely easier by adding the
-Property
parameter to the New-Object
cmdlet, which applied to the PSObject
type as well. PowerShell version 3 made this as simple as possible by directly supporting the [PSCustomObject]
type cast.
While creating a PSCustomObject
makes it easy to create data-centric objects (often called property bags), it doesn’t let you add functionality to those objects. When you need functionality as well, the next step is to create a PowerShell class (see Example 3-10). Like many other languages, PowerShell classes support constructors, public properties, and public methods, as well as internal helper variables and
methods.
##############################################################################
##
## PlottingObject.psm1
##
## From PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Demonstrates a module that implements a custom class
.EXAMPLE
function SineWave { -15..15 | % { ,($_,(10 * [Math]::Sin($_ / 3))) } }
function Box { -5..5 | % { ($_,-5),($_,5),(-5,$_),(5,$_) } }
using module PlottingObject
$obj = [PlottingObject]::New(@())
$obj.Points = Box
$obj.Move(10,10)
while($true) { $obj.Rotate(10); $obj.Draw(); Start-Sleep -m 20 }
$obj = [PlottingObject]::New((SineWave))
while($true) { $obj.Rotate(10); $obj.Draw(); Start-Sleep -m 20 }
#>
class
PlottingObject
{
## Constructors: one with no arguments and another that takes a
## set of initial points.
PlottingObject
()
{
$this
.
Points
=
@()
}
PlottingObject
(
$initialPoints
)
{
$this
.
Points
=
$initialPoints
}
## An external property holding the points to plot
$Points
=
@()
## Internal variables
hidden
$x
=
0
hidden
$y
=
0
hidden
$angle
=
0
hidden
$xScale
=
-
50
,
50
hidden
$yScale
=
-
50
,
50
hidden
$windowWidth
=
[Console]
::
WindowWidth
hidden
$windowHeight
=
[Console]
::
WindowHeight
## A public method to rotate the points by a certain amount
[void]
Rotate
(
[int]
$angle
)
{
$this
.
angle
+=
$angle
}
## A public method to move the points by a certain amount
[void]
Move
(
[int]
$xDelta
,
[int]
$yDelta
)
{
$this
.
x
+=
$xDelta
$this
.
y
+=
$yDelta
}
## A public method to draw the given points
[void]
Draw
()
{
$degToRad
=
180
*
[Math]
::
Pi
## Go through each of the supplied points,
## move them the amount specified, and then rotate them
## by the angle specified
$frame
=
foreach
(
$point
in
$this
.
Points
)
{
$pointX
,
$pointY
=
$point
$pointX
=
$pointX
+
$this
.
x
$pointY
=
$pointY
+
$this
.
y
$newX
=
$pointX
*
[Math]
::
Cos
(
$this
.
angle
/
$degToRad
)
-
$pointY
*
[Math]
::
Sin
(
$this
.
angle
/
$degToRad
)
$newY
=
$pointY
*
[Math]
::
Cos
(
$this
.
angle
/
$degToRad
)
+
$pointX
*
[Math]
::
Sin
(
$this
.
angle
/
$degToRad
)
$this
.
PutPixel
(
$newX
,
$newY
,
'O'
)
}
## Draw the origin
$frame
+=
$this
.
PutPixel
(
0
,
0
,
'+'
)
Clear-Host
Write-Host
"`e[?25l"
-NoNewline
Write-Host
$frame
-NoNewline
}
## A helper function to draw a pixel on the screen
hidden
[string]
PutPixel
(
[int]
$x
,
[int]
$y
,
[char]
$character
)
{
$scaledX
=
(
$x
-
$this
.
xScale
[
0
])
/
(
$this
.
xScale
[
1
]
-
$this
.
xScale
[
0
])
$scaledX
=
[int]
(
$scaledX
*
$this
.
windowHeight
*
2
.
38
)
$scaledY
=
((
$y
*
4
/
3
)
-
$this
.
yScale
[
0
])
/
(
$this
.
yScale
[
1
]
-
$this
.
yScale
[
0
])
$scaledY
=
[int]
(
$scaledY
*
$this
.
windowHeight
)
return
"`e[$scaledY;${scaledX}H$character"
}
}
For more information about creating modules, see Recipe 11.6. For more information about the syntax of PowerShell classes, see “Classes”.
Recipe 7.13, “Create a Hashtable or Associative Array”
Recipe 11.6, “Package Common Commands in a Module”
“Classes”