Extending Objects in Windows PowerShell, Part 3

In the last part of this series, I demonstrated how to extend results that you might get back from a cmdlet. As you hopefully know, you can create an object out of thin air in PowerShell by using the New-Object cmdlet.
Extending Objects in PowerShell Article Series:

Revisiting How to Make an Object in PowerShell

To create an object in PowerShell, all you need to do is specify a hashtable of property values.

$obj = New-Object psobject -Property @{
  Name = $env:username
  Computer = $env:computername
  OS = (Get-CimInstance Win32_OperatingSystem).Caption
  PSVersion = $PSVersionTable.PSVersion
}

You can also use the [PSCustomObject] type accelerator.

$obj = [pscustomobject]@{
  Name = $env:username
  Computer = $env:computername
  OS = (Get-CimInstance Win32_OperatingSystem).Caption
  PSVersion = $PSVersionTable.PSVersion
}

In either event, you get an object.

Our new object in Windows PowerShell. (Image Credit: Jeff Hicks)
Our new object in Windows PowerShell. (Image Credit: Jeff Hicks)

This type of object can also be extended by using the same techniques I showed earlier.

$obj | Add-Member -MemberType ScriptProperty -Name Uptime  -value {
 (Get-Date) - (Get-CimInstance win32_operatingsystem).LastBootUpTime }
$m1= {get-service | where {$_.status -eq "stopped"}}
$m2= {Param([string]$log="System") Get-Eventlog -logname $log -newest 10}
$obj | Add-Member -MemberType ScriptMethod -Name GetRunning -Value $m1
$obj | Add-Member -MemberType ScriptMethod -Name GetLastLogs -Value $m2

I went ahead and added a script property and a few methods.

Our new script properties and methods. (Image Credit: Jeff Hicks)
Our new script properties and methods. (Image Credit: Jeff Hicks)

I can use this object to get some useful management information from the local computer.
Using the uptime property to gather meaningful information. (Image Credit: Jeff Hicks)
Using the uptime property to gather meaningful information. (Image Credit: Jeff Hicks)

Creating a Custom Server Management Framework

With this in mind, it seemed to me that I could create a custom server management framework. Here’s how this might work.
First, I need a computer name.

$computername = "chi-test01"

Next, I’ll outline a few standard properties.

$os = Get-Ciminstance -ClassName Win32_operatingsystem -ComputerName $computername
$PSVersion = Invoke-Command {$PSVersionTable.PSVersion} -HideComputerName -computername $Computername

This is probably enough information to create an object.

$managed = [pscustomobject]@{
Computername = $computername.ToUpper()
PSVersion = $PSVersion
OperatingSystem = $os.Caption
ServicePack = $os.CSDVersion
LastBoot = $os.LastBootUpTime
}

071215 1927 AllAboutTha4
 
 
 
 
Now to add some custom methods I can use as management tools.

$managed | Add-Member -MemberType ScriptProperty -Name ProcessCount -Value {(Get-Process -ComputerName $this.computername).count}
$managed | Add-Member -MemberType ScriptProperty -Name Uptime -Value { (Get-Date) - (Get-Ciminstance win32_operatingsystem -computername $this.computername).lastBootUptime  } -force
$managed | Add-Member -MemberType AliasProperty -name OS -Value OperatingSystem
$managed | Add-Member -MemberType ScriptMethod -Name GetFreeSpace -Value {
Param([string]$Drive="c:")
$disk = Get-CimInstance -Classname win32_logicaldisk -filter "deviceid = '$drive'" -ComputerName $this.computername
$disk.Freespace}
$managed | Add-Member -MemberType ScriptMethod -Name Reboot -value { Restart-Computer -ComputerName $this.computername -force}

There’s one item that I haven’t show you, and that’s a property set. With a property set, you can reference a collection of properties by using a single name.

$managed | Add-Member -MemberType PropertySet -Name Boot -Value Computername,LastBoot,Uptime

071215 1927 AllAboutTha5
I hope that you realize that there’s no limit to the type of information and methods you could include here. Although one step I think I should have is an option to refresh the object. Should something change, I need to be able to update any static properties.

$refresh = {
$this.PSVersion = Invoke-Command {$PSVersionTable.PSVersion} -HideComputerName -computername $this.Computername
$os = Get-Ciminstance -ClassName Win32_operatingsystem -ComputerName $this.computername
$this.OperatingSystem = $os.Caption
$this.LastBoot = $os.LastBootUpTime
$this.ServicePack = $os.CSDVersion
}
$managed | Add-Member -MemberType ScriptMethod -Name Refresh -value $refresh

I’ll test by rebooting the server.

$managed.Reboot()

Using our refresh method in Windows PowerShell. (Image Credit: Jeff Hicks)
Using our refresh method in Windows PowerShell. (Image Credit: Jeff Hicks)

What have we ended up with in terms of a management object?
071215 1927 AllAboutTha7
By default I get all of the properties, including my alias. It might be more useful to define a default display. We can do this by defining a custom type for this object.

$myType = "my.ManagedComputer"
$managed.psobject.TypeNames.Insert(0, $myType)

These commands insert a new type name for my object.
071215 1927 AllAboutTha8
Now that I have a unique type name, I can use Update-TypeData and define a default property set.

Update-TypeData -TypeName $myType -DefaultDisplayPropertySet Computername,OS,PSVersion,LastBoot,Uptime

Notice the change?
071215 1927 AllAboutTha9
The other properties and methods are still available should I need them.

In the final article, we’ll take one final step and explore how to use this techniques to manage at scale.