Fun With PowerShell Classes – Constructors

Introduction

In our previous two posts, we covered the use of static properties and methods in classes, then saw how to use method overloading.

This is our final post of the series, and will cover the use of constructors. Constructors are functions that execute automatically when a class is instantiated.

For all of the examples we’ll display the code, then (when applicable) under it the result of our code. In this article I’ll be using PowerShell Core, 7.2.1, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

You may notice a backtick ` character at the end of many lines in the code samples. This is PowerShell’s line continuation character. The blog formatting has a limited width, so using the line continuation character makes the examples much easier to read. I have a section dedicated to the line continuation character in my post Fun With PowerShell Pipelined Functions if you want to learn more.

To run a snippet of code highlight the lines (or parts of a line) you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of any variable by highlighting it and using F8/F5.

Starting Point

As a reminder, this is our demo class TwittererRedux as we left it at the end of the last post. We’ll start from it in this post.

class TwittererRedux
{
  # Create a property
  [string]$TwitterHandle

  # Create a property and set a default value
  [string]$Name = 'Robert C. Cain'

  # Static Properties
  static [string] $Version = '2022.01.07.002'

  # Function that returns a string
  [string] TwitterURL()
  {
    $url = "https://twitter.com/$($this.TwitterHandle)"
    return $url
  }

  # Overloaded Function that returns a string
  [string] TwitterURL($twitterHandle)
  {
    $this.TwitterHandle = $twitterHandle
    $url = $this.TwitterURL()
    return $url
  }

  # Function that has no return value
  [void] OpenTwitter()
  {
    Start-Process $this.TwitterURL()
  }

  # Can launch a twitter page without instantiating the class
  static [void] OpenTwitterPage([string] $TwitterHandle)
  {
    # Note here we cannot call the $this.TwitterUrl function
    # because no object exists (hence no $this)
    $url = "http://twitter.com/$($TwitterHandle)"
    Start-Process $url
  }

}

# Create a new instance and update the handle
$twit = [TwittererRedux]::new()
$twit.TwitterHandle = 'ArcaneCode'

Constructors

In the original version of our class, we created a new instance of the class by calling the ::new() static method. Then, we assigned a value to our TwitterHandle property. Wouldn’t it have been nice to do it all in one step?

Well that is possible through the use of a constructor. A constructor is a function that gets run automatically when the object is instantiated, as part of the ::new() static method. Every class gets a constructor automatically, it’s just empty.

Below is an example of our class with a constructor. For brevity I’m omitting most of the class code, and will reproduce the full class sample at the end of this post.

class TwittererRedux
{
  # Default Constructor
  TwittererRedux ()
  {
  }

  # Create a property
  [string]$TwitterHandle

  # ... rest of class goes here

A constructor is a function, with the exact same name as the class. As you can see in the sample above, TwitterRedux is both the name of the class, as well as of the function.

In this case the function is empty, it doesn’t do anything, which is what the behavior of the default constructor should be.

Having constructors allows us to create more compact code. For example, in previous examples we create a new instance of our class, then assign a handle to the TwitterHandle property on the next line. Using a constructor we can provide the ability to compress our code, creating a new instance and assigning the TwitterHandle value all in one step.

To do so, we need to create another function with the same name as our class, TwittererRedux.

class TwittererRedux
{
  # Default Constructor
  TwittererRedux ()
  {
  }

  # Constructor passing in Twitter Handle
  TwittererRedux ([string]$TwitterHandle)
  {
    $this.TwitterHandle = $TwitterHandle
  }

  # Create a property
  [string]$TwitterHandle

  # ... rest of class goes here

This technique uses overloading, as discussed in a previous post. Here we have added a single parameter, $TwitterHandle. Within the function we take the value passed in and assign it to the TwitterHandle property for the current instance, represented by $this.

Before I go on, I need to mention an important rule. When you override a constructor, you must manually add the default constructor! You can see that was done in the above sample.

So how do we use it? Pretty simple actually, when we instantiate our object by using new, we pass in the value.

# Create a new instance using an overloaded constructor
$twit = [TwittererRedux]::new('ArcaneCode')

# Display the result
$twit.TwitterHandle

Result:

ArcaneCode

Here when we called new, instead of leaving the parameter area empty we passed in a single string value. PowerShell then followed the rules of overloading as seen in the previous post. It looked over the set of constructors and found one that had a single parameter of type string and executed the code associated with it.

Let’s further expand by adding another constructor so we can assign both the handle and the name when we instantiate a new object from our class.

class TwittererRedux
{
  # Default Constructor
  TwittererRedux ()
  {
  }

  # Constructor passing in Twitter Handle
  TwittererRedux ([string]$TwitterHandle)
  {
    $this.TwitterHandle = $TwitterHandle
  }

  # Constructor passing in Twitter Handle and Name
  TwittererRedux ([string]$TwitterHandle, [string]$Name)
  {
    $this.TwitterHandle = $TwitterHandle
    $this.Name = $Name
  }

  # Create a property
  [string]$TwitterHandle

  # ... rest of class goes here

In our second constructor we have two string parameters, which will be assigned to the handle and name properties of the current object.

$twit = [TwittererRedux]::new('ArcaneCode', 'Mr. Code')
$twit.TwitterHandle
$twit.Name

Result:

ArcaneCode
Mr. Code

The Final Version

As promised, here is the final version of our TwitterRedux class.

class TwittererRedux
{
  # Default Constructor
  TwittererRedux ()
  {
  }

  # Constructor passing in Twitter Handle
  TwittererRedux ([string]$TwitterHandle)
  {
    $this.TwitterHandle = $TwitterHandle
  }

  # Constructor passing in Twitter Handle and Name
  TwittererRedux ([string]$TwitterHandle, [string]$Name)
  {
    $this.TwitterHandle = $TwitterHandle
    $this.Name = $Name
  }

  # Create a property
  [string]$TwitterHandle

  # Create a property and set a default value
  [string]$Name = 'Robert C. Cain'

  # Static Properties
  static [string] $Version = '2022.01.07.002'

  # Function that returns a string
  [string] TwitterURL()
  {
    $url = "https://twitter.com/$($this.TwitterHandle)"
    return $url
  }

  # Overloaded Function that returns a string
  [string] TwitterURL($twitterHandle)
  {
    $this.TwitterHandle = $twitterHandle
    $url = $this.TwitterURL()
    return $url
  }

  # Function that has no return value
  [void] OpenTwitter()
  {
    Start-Process $this.TwitterURL()
  }

  # Can launch a twitter page without instantiating the class
  static [void] OpenTwitterPage([string] $TwitterHandle)
  {
    # Note here we cannot call the $this.TwitterUrl function
    # because no object exists (hence no $this)
    $url = "http://twitter.com/$($TwitterHandle)"
    Start-Process $url
  }

}

Constructors vs Overloading

Constructors are very similar to overloading a function, but not exactly the same.

Just like overloading, each constructor declaration must be different in terms of the number of parameters and their data types.

Unlike overloads, you have access to the properties and methods of the object. This is what let us assign values to our properties when we created the new instance of the object.

Conclusion

Constructors can aid in making our code more compact, and allowing us to assign values when we instantiate new objects. Be cautious though, it can be tempting to make far more constructors than you need. Ensure that your constructors cover only the most common situations, otherwise you’ll have a confusing mess that you have to document and maintain.

The demos in this series of blog posts were inspired by my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight . At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.

Fun With PowerShell Classes – Overloading

Introduction

This is the next installment in our series of advanced techniques for PowerShell classes. In the previous installment we saw how to implement static properties and methods. In this one, we’ll see how to overload your methods.

We’ll take a deeper look at overloading in a moment, but first let me mention that for all of the examples we’ll display the code, then under it the result of our code when applicable. In this article I’ll be using PowerShell Core, 7.2.1, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

Additionally, many of the code samples have lines which end in a backtick `, PowerShell’s line continuation character. The blog formatting has a limited width, so using the line continuation character makes the examples much easier to read. My post Fun With PowerShell Pipelined Functions dedicates a section to the line continuation character if you want to learn more.

In VSCode you can highlight snippet of code then press F8 to execute it. In the IDE, use F5. You can display the contents of any variable by highlighting it and using F8/F5.

Starting Point

For easy reference, here is our demo class as we left it at the end of the previous post.

class TwittererRedux
{
  # Create a property
  [string]$TwitterHandle

  # Create a property and set a default value
  [string]$Name = 'Robert C. Cain'

  # Static Properties
  static [string] $Version = '2022.01.07.002'

  # Function that returns a string
  [string] TwitterURL()
  {
    $url = "https://twitter.com/$($this.TwitterHandle)"
    return $url
  }

  # Function that has no return value
  [void] OpenTwitter()
  {
    Start-Process $this.TwitterURL()
  }

  # Can launch a twitter page without instantiating the class
  static [void] OpenTwitterPage([string] $TwitterHandle)
  {
    # Note here we cannot call the $this.TwitterUrl function
    # because no object exists (hence no $this)
    $url = "http://twitter.com/$($TwitterHandle)"
    Start-Process $url
  }

}

The Need to Overload a Method

About half way into our class definition we have a method named TwitterURL. This function is pretty simple, it takes the value in the TwitterHandle property, composes the URL to the Twitter site for it, then returns it.

Here is what it would look like in action.

$twit = [TwittererRedux]::new()
$twit.TwitterHandle = 'ArcaneCode'
$twit.TwitterURL()

Result:

http://twitter.com/ArcaneCode

What if we had a lot of handles we wanted to get URLs for. It would be a two step process for each one, first assigning the handle to the TwitterHandle property, then calling the TwitterURL method.

$twit.TwitterHandle = 'ArcaneCode'
$twit.TwitterURL()
$twit.TwitterHandle = 'N4IXT'
$twit.TwitterURL()
$twit.TwitterHandle = 'ArcaneTC'
$twit.TwitterURL()
$twit.TwitterHandle = 'BuckWoodyMSFT'
$twit.TwitterURL()
$twit.TwitterHandle = 'tradney'
$twit.TwitterURL()
$twit.TwitterHandle = 'VKCsh'
$twit.TwitterURL()
$twit.TwitterHandle = 'TechTrainerTime'
$twit.TwitterURL()

Of course these could all be put into an array, or read in from a file and run through a foreach loop, even so it still takes two calls to our $twit object. Wouldn’t it be nice to set the TwitterHandle property and return the URL all in one method call?

But what to call the method? We could go with SetHandleAndGetURL, or perhaps UpdateAndGetTwitter, or even HeyHeresAMethodToSetTheTwitterHandleAndGetTheURL.

But in fact we already have a great name in TwitterURL. Its short and explains just what it does. It’s too bad we can’t use it more than once.

Oh wait, we can!

Implementing an Overloaded Method

To create an overload, create a new function within your class and use the same name. To differentiate, you need to have it accept a different number of parameters. Let’s make this clearer by the example below.

  [string] TwitterURL()
  {
    $url = "https://twitter.com/$($this.TwitterHandle)"
    return $url
  }

  [string] TwitterURL($twitterHandle)
  {
    $this.TwitterHandle = $twitterHandle
    $url = $this.TwitterURL()
    return $url
  }

At the top is our original function. Below it is the overloaded version. In it I pass in a single parameter, the $TwitterHandle. PowerShell can use this to determine which version of the function to call.

If you execute the TwitterURL method with no parameters, the version of the function at the top is executed.

When you call TwitterURL and pass in a parameter, the version of the function at the bottom gets run. In here I first access the TwitterHandle property of the current object (represented by $this) and update it from the parameter $twitterHandle.

Next, I called the original function to get the properly formatted URL from the (newly updated) TwitterHandle property.

I chose to do it this way to demonstrate it is possible to call the original version of a function from its overloaded version. It’s certainly not required though, as the code to format the URL could have been copied from the original function. The downside to this however is if I make a change to one area, I have to make it to both.

Also be aware that setting the TwitterHandle property may be considered a side effect by some. It’s not intuitively obvious this will happen, and some users may think this to be a bug. It’s important then to make sure you document this thoroughly in your documentation.

Let’s see it in action. First, here is the complete class with the new overloaded function added.

class TwittererRedux
{
  # Create a property
  [string]$TwitterHandle

  # Create a property and set a default value
  [string]$Name = 'Robert C. Cain'

  # Static Properties
  static [string] $Version = '2022.01.07.002'

  # Function that returns a string
  [string] TwitterURL()
  {
    $url = "https://twitter.com/$($this.TwitterHandle)"
    return $url
  }

  # Overloaded Function that returns a string
  [string] TwitterURL($twitterHandle)
  {
    $this.TwitterHandle = $twitterHandle
    $url = $this.TwitterURL()
    return $url
  }

  # Function that has no return value
  [void] OpenTwitter()
  {
    Start-Process $this.TwitterURL()
  }

  # Can launch a twitter page without instantiating the class
  static [void] OpenTwitterPage([string] $TwitterHandle)
  {
    # Note here we cannot call the $this.TwitterUrl function
    # because no object exists (hence no $this)
    $url = "http://twitter.com/$($TwitterHandle)"
    Start-Process $url
  }

}

After running this to get the updated class definition in memory let’s call it both ways.

# Create a new instance
$twit = [TwittererRedux]::new()

# Assign the handle, then call TwitterURL
$twit.TwitterHandle = 'ArcaneCode'
$twit.TwitterURL()

Result:

https://twitter.com/ArcaneCode

Now let’s call the overloaded version.

# Now call the overloaded version
$twit.TwitterURL('N4IXT')

Result:

https://twitter.com/N4IXT

We can also check the TwitterHandle property to ensure it has been updated.

$twit.TwitterHandle

Result:

N4IXT

We could have added additional overloads with more parameters. We could have defined [string] TwitterURL($twitterHandle, $anotherParameter), for example.

Other Ways to Differentiate an Overload

In the previous section I stated PowerShell differentiates overloads by the number of parameters passed into our function. There is one other way PowerShell can differentiate, and that is by the data type of each parameter. Let’s look at this simple example.

class over
{
  [string] hello()
    { return 'hello world' }

  [string] hello([string] $name)
    { return "hello string of $name"}

  [string] hello([int] $number)
    { return "hello integer of $number"}
}

As you can see, my class has three overloads. In the second two, we pass in a single parameter. What makes them different though is the data type for the parameter. In the first we use a string, the second an integer. To be accurate then, we need to say PowerShell can tell which overload to call by the number of parameters and the data type of each.

As should be obvious, you will need to strongly type all of your parameters for this to work, but when it comes to classes that’s not a bad idea anyway.

Just as proof, let’s see these working.

$o = [over]::new()
$o.hello()
$o.hello('mom')
$o.hello(33)

Result:

hello world
hello string of mom
hello integer of 33

You can also mix and match, with multiple data types and parameters. For example…

hello([string] $name, [int] $number)
hello([int] $number,  [string] $name)

Both of these are both valid. Just to reiterate, what you could not do is:

hello([string] $nameA, [int] $number)
hello([string] $nameB, [int] $anotherNumber)

PowerShell can’t make the distinction between the two, as they have the same number of parameters and data types in the same order.

Conclusion

Overloads can be very useful when working with classes. They allow you to continue to use method names you are familiar with yet alter them to meet your changing needs.

In our next installment we’ll cover the topic of class constructors, a way to populate properties when you instantiate your new object from the class definition.

The demos in this series of blog posts were inspired by my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight . At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.

Fun With PowerShell Classes – The Basics

Introduction

In the last few posts we looked at the use of Enums, a technique closely associated with classes. In this post we’ll start looking at classes themselves. We’ll open with some terminology, then look at our first class.

For the next post in this series I plan to do a history lesson on the use of PSCustomObject. Prior to the addition of classes in PowerShell 5.0, this was the technique needed to create your own customized objects. From there we’ll return to the modern area and get into some advanced class techniques.

First let me mention that for all of the examples we’ll display the code, then under it the result of our code. In this article I’ll be using PowerShell Core, 7.2, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

To run a snippet of code highlight the lines you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of any variable by highlighting it and using F8/F5.

Terminology

If you are familiar with object oriented terminology, then this short overview will be familiar to you. However, many who come into PowerShell scripting do not come from a coding background. It’s worth taking a few paragraphs, then, to explain some common terms that will be used in this and future articles.

A class is code that is used as a blueprint to create an object variable in memory. In fact, all variables in PowerShell are objects, even built in ones like strings or integers. Their classes are already defined and ready to be used in the core PowerShell libraries.

The act of creating a new object from a class is called instantiation. You can instantiate multiple variables from the same class.

In most object oriented discussions, the classic example compares a class to a blueprint for a house. From that single blueprint a home builder can create an entire neighborhood of houses.

Each house has properties that can be set to make the houses different from each other, even though they are built from the same blueprint. House color, trim color, number of cars the garage will hold, are all properties that can be set on a per house basis.

Likewise, a PowerShell class has properties. These are made available through variables, and may be things like first name, last name, address, birth date, number of pets, or any number of other items that would apply to this instance of an object built from your class.

A house blueprint may also have tasks assigned to it. "Get building permit from city", for example, or "paint the trim". In the PowerShell world, a class can also have tasks assigned to it. These are created by using functions.

If you aren’t familiar with functions yet, you need to brush up. You can start with my series Fun With PowerShell Functions, then continue through the next few posts which move into advanced functions and pipelined functions.

When it comes to classes, we call these built in functions methods. A method is designed to act on the data within the function itself.

A simple example, you may have three properties, first name, middle name, and last name. You could create a method (in the form of a function) called full name, which concatenates the three parts of the name together, correctly formatting for times when a middle name is absent.

Methods in a class can return a value, but do not have to. We’ll see examples of both in this article.

Also be aware there are special types of properties and methods that are called static properties and static methods. These are pieces of code that PowerShell can execute from the class itself, without creating an object from that class.

We’ll see examples of how to create and use these in our future post on advanced classes, but I wanted to mention them as PowerShell classes have a static function we’ll need to use in order to instantiate new objects.

This short intro just hits the tip of the iceberg when it comes to object oriented methodology, entire books have been written on the subject. Hopefully it provides enough information to get you started.

So now that we’re all on the same page when it comes to terminology, let’s go create a class.

A Very Simple Class

This first example will be very simple. Take a look, then we will go over its parts.

class Twitterer
{
  # Create a property
  [string]$TwitterHandle

}

We begin the definition with the keyword class, followed by what we wish to name our class. In my previous articles on enums we used Twitter data as an example, so let’s stick to that.

After the name of the class we need an opening squiggly brace, and a closing one at the end. In PowerShell squiggly braces are used to define a scrpt block. You’ve seen these before, functions, foreach, if statements and more all use script blocks. Classes are no different, everything in the script block is the class definition.

With classes, as with most script blocks, it’s not necessary to put the opening squiggly brace on the next line, many use class Twitter { on a single line. I just feel having the squiggly braces vertically aligned makes things easier to read.

Within the class I have defined a single property, $TwitterHandle. Before the name of the variable I have indicated the variable type in brackets, [string]. Unlike regular PowerShell, all properties must be strongly typed.

Let’s create, or instantiate, a new variable from our class (after highlighting the class definition and using F8 or F5 to get it into memory).

$twit = [Twitterer]::new()

This syntax may look a bit odd, so let me explain. When we created our class we defined a single property. Anytime we define a class, though, PowerShell adds extra properties and methods behind the scenes.

One of those methods is new. New is a static method that can be called without the need to instantiate a new object, which is fortunate as it is the way we get new objects from our class.

To call a static method, we use the name of the class in brackets, followed by two colons, then the name of the static method. In PowerShell, to call a method you always have to use parenthesis after the name of the method even if it takes no parameters. This is unlike a regular function in PowerShell.

Finally, we assign our newly instantiated object to the variable $twit.

We can now access the properties (and methods) in our object by using what is formally known as dot notation. If you’ve done any PowerShell coding then you’ve likely used it a million times by now without realizing it had a formal name.

You simply use the name of our object, a period, then the name of the property, as in $twit.TwitterHandle. Of course if we run this right now, we won’t get anything back. This is because our variable is empty when the class is created. So let’s assign it a value.

$twit.TwitterHandle = 'ArcaneCode'
$twit.TwitterHandle

Result:

ArcaneCode

It’s that easy, we can use it like any other variable. Note one thing, when we created the property we used the $ in front of the variable. But outside the class when we reference it as a property the $ is omitted.

Default Values for Properties

There will be many times when you write a class in which you want to have some, or perhaps all, of its properties already populated with values. This will make it easier for your end user, especially for properties where the majority of the time the user can get by with the default value.

Creating a default value is simple, when you create the property you simply assign it a value.

class Twitterer
{
  # Create a property
  [string]$TwitterHandle

  # Create a property and set a default value
  [string]$Name = 'Robert C. Cain'
}

Here a second property, Name, has been added. After its declaration I simply assigned it a name (mine in this case) just like I would assign any value to a variable.

Now let’s create a new instance and examine the value in our Name property.

$twit = [Twitterer]::new()
$twit.Name

Result:

Robert C. Cain

Of course just because we’ve provided a default value doesn’t mean we can’t change it.

$twit.Name = 'Mr. Code'
$twit.Name

Result:

Mr. Code

Our First Method

Now that we’ve added properties, it’s time to add a little functionality with our first method. A class method in PowerShell works just like a function, only without the need for the function keyword. For this example, we’ll add a new method that takes the value in the $TwitterHandle property and return the URL to that handles Twitter page.

class Twitterer
{
  # Create a property
  [string]$TwitterHandle

  # Create a property and set a default value
  [string]$Name = 'Robert C. Cain'

  # Function that returns a string
  [string] TwitterURL()
  {
    $url = "https://twitter.com/$($this.TwitterHandle)"
    return $url
  }

}

The URL to a users Twitter account is simple, it is just twitter.com followed by the users twitter handle. Now, you might think you could just use $TwitterHandle to create this, but not so.

We need to let PowerShell know to use the TwitterHandle for this particular object. That’s where the $this variable comes into play.

$this is a built in variable which simply means "the current object I am running this code in". Using $this, I can reference any property or other method within this instance of my class.

I also want to point out that after the name of our method we added parenthesis. This is an indicator to PowerShell we are defining a method and not a property. In this case we are not passing in any values to our method, so they are empty. It is possible though to pass values in, which we’ll see in a future post.

Finally, note that my function, just like properties, is strongly typed. Since my URL is in the form of a string, I used [string] to indicate the data type being returned by this function.

$twit = [Twitterer]::new()
$twit.TwitterHandle = 'ArcaneCode'
$myTwitter = $twit.TwitterURL()
$myTwitter

Result:

https://twitter.com/ArcaneCode

No Return

In my previous example, our method returned a value. There will be cases though when you simply want your method to do something, and not return any values. For those times, we can use the return type of void.

class Twitterer
{
  # Create a property
  [string]$TwitterHandle

  # Create a property and set a default value
  [string]$Name = 'Robert C. Cain'

  # Function that returns a string
  [string] TwitterURL()
  {
    $url = "https://twitter.com/$($this.TwitterHandle)"
    return $url
  }

  # Function that has no return value
  [void] OpenTwitter()
  {
    Start-Process $this.TwitterURL()
  }

}

I’ve added a new method, OpenTwitter. Before it I used [void] to let Twitter know this particular method won’t be returning any data.

Within the function I call the PowerShell cmdlet Start-Process. This cmdlet will take the value passed into it and attempt to run the application that corresponds to it. For example, if I had passed in the file name to an Excel spreadsheet, PowerShell would have attempted to launch Microsoft Excel and open that file.

In this case we’re passing in a URL, so PowerShell will launch your default browser and open the Twitter webpage for that user.

Also note we used the $this built in variable to call the TwitterURL method for this current instance of our object, here $twit.

To run it we only need to call our method.

$twit = [Twitterer]::new()
$twit.TwitterHandle = 'ArcaneCode'
$twit.OpenTwitter()

If all went well your web browser should open to the Twitter page for the associated user held in the $TwitterHandle variable.

Conclusion

In this opening article we covered some of the basics of using classes in PowerShell. Even with this limited information you should be able to start creating useful classes. In future articles we’ll dive deeper into using classes in PowerShell.

I want to mention, as I write this in December 2021, that my posts for the rest of the year will diverge as I want to give a little gift and share some of my favorite things I’ve found on the internet this year. I’ll pick this series back up in January of 2022.

The demos in this series of blog posts came from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight . At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.

Resolving Ambiguous Class Names Across PowerShell Modules

Right after my last post, I got to wondering what would happen if I had two modules with the same class named defined?

The dictionary defines ambiguous as “unclear or inexact because a choice between alternatives has not been made”. In context of this discussion, it means we have two different PowerShell modules that both have definitions for a class that is named the same (but may not necessarily look the same).

To quote one of the most often used phrases in technical blogging, “Let’s look at an example!”.

Here is our first module, which defines a class MyAmbiguousClass. As you can see it has one property and one method.

# MyAmbiguousModule1.psm1
class MyAmbiguousClass
{
  [string] $MyString = 'Ambigouous String 1'

  [string] GetSomeValue()
  {
    return 'Ambigouous Value 1'
  } 
}

Pretty simple. Now let’s look at a second module. This also has a class defined of MyAmbiguousClass, but it has two properties and one method, all with different names from the previous modules definition.

# MyAmbiguousModule2.psm1
class MyAmbiguousClass
{
  [int] $MyInteger = 2

  [string] $MyName = 'ArcaneCode'

  [string] DidILeaveTheStoveOn()
  {
    return 'Probably not'
  } 
}

You would then declare these at the top of your script thusly:

using module 'C:\PS\Classes and Modules\MyAmbiguousModule1.psm1'
using module 'C:\PS\Classes and Modules\MyAmbiguousModule2.psm1'

As described in my previous post, you would instantiate a new instace with this command:

$myClass = [MyAmbiguousClass]::new()

Now of course you can see the issue, it is not clear which version of the MyAmbiguousClass is being instantiated. What’s even scarier is PowerShell will execute this command without producing an error!

When PowerShell creates the new variable it looks through its memory to find the first time this class is defined, then it uses that definition. In this example, since the MyAmbiguousModule1.psm1 was loaded first, it is that definition that gets used.

If, however, the ‘using module’ statements had been reversed, and MyAmbiguousModule2.psm1 was first, then it is the definition for MyAmbiguousClass found in MyAmbiguousModule2.psm1 that would have been used.

Yikes!

So how to resolve? Well it turns out to be quite simple. All you have to do is prefix the class name with the module name, like so:

$myClass1 = [MyAmbiguousModule1.MyAmbiguousClass]::new()

Now intellisense will list the correct methods and properties, and we can access them in code.

$myClass1.MyString
$myClass1.GetSomeValue()

Will produce

Ambigouous String 1
Ambigouous Value 1

Likewise, we’ll prefix the second version with its module name, MyAmbiguousModule2:

$myClass2 = [MyAmbiguousModule2.MyAmbiguousClass]::new()
$myClass2.MyInteger
$myClass2.MyName
$myClass2.DidILeaveTheStoveOn()

Produces this output

2
ArcaneCode
Probably not

And there you go, resolving ambiguous class names across PowerShell modules is just that easy.

Accessing a PowerShell Class Defined In A Module From Outside A Module

PowerShell 5 introduced the concept of classes. This is an exciting new feature that will really help promote code reusability. It seems natural then, that you would want to organize your classes into PowerShell Modules.

It’s not obvious though, how to use a class defined inside a module from outside that module. There are, in fact, three methods available to you.

Let’s say you have a module, MyModule.psm1. In it you’ve defined a class:

class MyClass
{
  [string] $MyString = 'My String Value'

  [string] GetSomeValue()
  {
    return 'Some Value'
  } 

}

Simple enough. So how do we get to this masterpiece of class coding? The first technique has us creating a function inside the module. Within that function we return a new instance of the class.

function Get-NewMyClass()
{
  return [MyClass]::new()
}

# Export the function, which can generate a new instance of the class
Export-ModuleMember -Function Get-NewMyClass

Using it simply requires we import the module, then call the function. From there we can access the properties and methods of our function.

# Import our test module
Import-Module -Force 'C:\PS\Classes and Modules\mymodule.psm1'

# Use the function to generate a new instance of the 'MyClass' class
$myClassFunction = Get-NewMyClass

# Call a method from it
$myClassFunction.GetSomeValue()

# Get a property of the class
"MyString=$($myClassFunction.MyString)"

Pretty simple and straightforward. This can be a useful method if there are extra checks you wish to do inside the module prior to returning the new instance of the class.

The next method simply has us create a variable within the module, and export that as a module member.

$newClass = [MyClass]::new()
Export-ModuleMember -Variable newClass

You’d then use it in your script, just like any other variable:

# The module also has a variable exported from the function
# of type MyClass. 
"NewClass=$($newClass.MyString)"
$newClass.GetSomeValue()

With that shown I have to say I really don’t like this method. Primarily it is due to the issue of name collisions. If you have a variable also named $newClass in your script, it will block out the one from the class causing the collison.

The final option is the new using clause. I want to give a shout out to PowerShell MVP Dave Wyatt (blog | twitter) for pointing this one out to me.

As the first line of your script (except for comments, which are allowed before it) you use the syntax “using module” followed the module name, or path to the module.

using module 'C:\PS\Classes and Modules\mymodule.psm1'

Here I hard coded the path to the module since this is a simple demo. If the module had been installed in one of the default locations for modules, such as the WindowsPowerShell\Modules folder in the current users Documents area, you could have omitted the path and just put the name of the module.

After this, you would simply create a new variable from the class and use it normally.

$myClassUsing = [MyClass]::new()

# Setting / Getting property
$myClassUsing.MyString                  # Show default property
$myClassUsing.MyString = 'ArcaneCode'   # Change the value
$myClassUsing.MyString                  # Show the change

# Calling a method
$myClassUsing.GetSomeValue()

Note that if you had multiple modules you wanted to access the class definitions in, you would simply have multiple lines of “using module”, each line referencing the module you wanted.

using module 'C:\PS\Classes and Modules\mymodule.psm1'
using module 'C:\PS\Classes and Modules\anothermodule.psm1'

 

There you go. Three ways you can access a class definition stored inside a module, externally. Now not only can you create useful, reusable classes, you can also organize them into modules and use them outside the modules.