Creating a Custom Class Library

PowerShell 5 brings some nice capability to PowerShell, including support for the creation of custom classes. Very simply, a class can be used to define a custom type, and allow you to create an object of that custom type. This can be useful for example, if you want to create an object that has specific properties that you define, as well as some methods, or portions of code that do something specific to your need and relevant to that object.

Class libraries are used in programming so that instead of having to create code to do low-level, fundamental or often-repeated tasks, a collection of classes are provided for you so you can simply call a class and its properties and methods when you need it.

You can call .Net classes in Powershell using a type accelerator. For example, this code gives me the value of PI using the System.Math class. It is defined in the class as a static property.


[math]::PI

Since the value of PI is returned with 14 decimal places, I might want to reduce that say to 4 decimal places. So I can call a static method on the System.Math class to round the number of decimal places to 4:


[math]::Round([math]::PI,4)

Create a Custom Class

I won’t go into detail here about how to create a custom class (Stephane van Gulick gives a nice introduction), but below is a simple example of a class I created in PowerShell, which allows me to create an object representing a user account in Active Directory. I have defined exactly what properties I want to have returned so I don’t have to pass a list of properties to the Get-ADUser cmdlet every time I run it.


class ADUser
{
    [string]$Username
    [string]$Enabled
    [string]$Displayname
    [string]$Title
    [string]$Department
    [string]$EmailAddress
    [string]$CanonicalName
    [string]$City
    [string]$co
    [string]$OfficePhone
    [string]$MobilePhone
    [string]$ipPhone
    [array]$MemberOf
    [array]$DirectReports
    [string]$homeMDB
    [string]$Created
    [string]$Modified
    [string]$LastBadPasswordAttempt
    [string]$PasswordLastSet

   # Constructor
   ADUser ([string] $Username)
   {
        $this.Username = $Username
        $Properties = @(
            'CanonicalName',
            'City',
            'co',
            'Created',
            'Department',
            'DirectReports',
            'Displayname',
            'EmailAddress',
            'Enabled',
            'homeMDB',
            'ipPhone',
            'LastBadPasswordAttempt',
            'MemberOf',
            'MobilePhone',
            'Modified',
            'OfficePhone',
            'PasswordLastSet',
            'Title'
        )
       try
        {
            $P = Get-ADUser $Username -Properties $Properties | Select $Properties
            $Properties | foreach {
                $this.$_ = $P.$_
                }
        }
       Catch
        {
            $_; continue
        }
   }
}

I can create a custom object from this class in a couple of ways:


# create a new object
$me = New-Object -TypeName ADUser -ArgumentList tjones

# Instantiate using the 'new' static method
$me = [ADUser]::new('tjones')

# Simply set the variable type
[ADUSer]$me = 'tjones'

In each case, I need to pass a username, or actually any of the properties in this list, as this is required by the class constructor and the Get-ADUser cmdlet:
— A distinguished name
— A GUID (objectGUID)
— A security identifier (objectSid)
— A SAM account name (sAMAccountName)

When I create the object, the code runs and gets the info from AD. When I call the variable I can see that the properties I have defined are populated:

captures

I can view the list of properties on the object using the dot operator…

capture

…or view an individual property…

capture

…or even find the value of a property without first storing it to a variable:

capture

Scope

This custom class is quite handy to quickly find out information about a user, and I want to be able to call this class any time I need it. Trouble is, in the current implementation of this, a custom class is limited in scope and I can only use this class in the same context I’ve created it in. Or to say it another way, I can’t change the class scope in the same way you could a variable for example. You can of course change the scope of the object you create from the class, for example:


New-Variable -Name me -Value ([ADuser]::new('tjones')) -Scope Script

But once my current session or script is closed, this custom class is no longer available to me. To use it again, I must add the class code and run it in each session or script so it is available in the current context. This can make your scripts fatter than they need to be.

So here’s an idea:

Create a Class Library (of sorts)

In C# for example, you can create a library of classes as a dll file, but for PowerShell I can’t do that.

So why not simply create a folder of class code saved into text files, then read and run the code in your session?

Here’s one way to do that. In my PowerShell $Profile directory, I have two folders “Modules” and “Scripts”. I add a folder called “Classes”.

capture

I create the code for my custom class using PowerShell ISE, then save it as a text file to the Classes folder. Any time I create a new custom class that I want to reuse later, I save it as a text file in this location.

capture

Now I can simply read the contents of a class file and run it in my current session with a one-liner to give me instant access to this custom class.


Invoke-Expression $([System.IO.File]::ReadAllText('C:\Users\tjones\Documents\WindowsPowerShell\Classes\ADUser.txt'))

I can also load in all the custom classes in the Classes directory into my session like this:

 

# Import Custom Classes
Get-ChildItem '$env:USERPROFILE\Documents\WindowsPowerShell\Classes\' |
    Select -ExpandProperty FullName |
        foreach {
            $class = [System.IO.File]::ReadAllText($_)
            Invoke-Expression $Class
        }

Even better, I can add this code into my PowerShell profile scripts (the Microsoft.Powershell_profile.ps1 and Microsoft.PowershellISE_profile.ps1) and all these classes will be available for me to use every time I start a new PowerShell session 🙂

Get Creative

This capability for custom classes in PowerShell opens a door of creativity for IT administrators and developers alike. You can create simple classes to use in a script for example, or create reusable classes in a kind of class library as we have discussed, and you can add custom code that is relevant to the custom object so you can simply call a method instead of writing out the code each time.

How would custom classes be useful to you? What kinds of objects and methods would be useful in your day to day work?

I do a lot of troubleshooting on remote computers, so I wrote a custom class that gets lots of useful information from a remote computer, or performs certain tasks on the remote computer.

In the example below, I’ve created a custom computer object representing “PC001”. Creating the object runs a quick “Test-Connection” against the machine, so I call the “Online” property to see if it is. Then I get the current user using the “GetCurrentUser()” method, then I output a list of methods in the object. These methods allow me to get information from Active Directory for the computer, get hardware information, get installed hotfixes or software, get local administrators and other useful things.

I can also start / stop services, or kill running processes.

capture

The custom type also contains a couple of static methods that I can use without creating an object and assigning it to a variable. “GetComputerFromUser()” checks my Configuration Manager database to find the computer/s that a user was last logged into, and “GetSerialTag()” gets the serial number (or asset tag) for the remote computer.

capture

Cool stuff 🙂

Advertisements