ArcaneBooks – ISBN Overview, PowerShell, and the Simple OpenLibrary ISBN API

Introduction

In this post we’ll begin with an overview of what an ISBN is. We’ll then talk about the website that will be the source for our data. It has two different web APIs (Application Programming Interface) that we can use. We’ll discuss one here, then in the next blog post cover the advanced version.

First though, if you haven’t read the introductory post in this series, The ArcaneBooks Project – An Introduction, I’d highly recommend doing so as it lays the foundation for why and how this project to get ISBN data originated.

ISBN Overview

ISBN, or International Standard Book Number, is a 10 or 13 digit number used to uniquely identify a book. You can find more information on ISBNs at https://www.isbn.org.

Every country has a service that creates an ISBN number for works created in that country, and cannot create numbers for books in other countries. ISBN’s began in 1970 as a ten digit number. In 2007, due to a dwindling supply of numbers, it was switched to a thirteen digit number.

Thirteen digit numbers in the US currently begin with 978-0 and 978-1, and 979-8. For purposes of this module, though, we will be able to use either the ten or thirteen number version of the ISBN.

Publishers sometimes vary the format through the inclusion or exclusion of dashes and/or spaces to separate the parts of the ISBN. For our purposes this won’t be relevant.

The data source we use (more on that momentarily) requires us to use only the number with no spaces or dashes. Thus the cmdlet in this module to fetch the ISBN data will remove any spaces or dashes from the number before it is used.

Converting Between Ten and Thirteen Characters

It is possible, although not necessary for this module, to convert the ten digit ISBN to a thirteen digit one. The https://www.isbn.org website has an online converter which you’ll find at https://www.isbn.org/ISBN_converter.

There is also a good blog article at The Postulate. In it the author gives an overview of how to convert from ten to thirteen character ISBNs, and provides code samples in Python.

Again, since our source can use either format of the ISBN, there are no plans at this time to implement the routine as PowerShell code.

Data Source – The Simple OpenLibrary API

In the ArcaneBooks PowerShell module that we are building, we will use the OpenLibrary.org API to get our data. The OpenLibrary website is run by the Internet Archive.

As I mentioned in the introduction, OpenLibrary actually has two different APIs we can call. The first I call the Simple API as it is very easy to use and parse the data.

The second API I’ve called the Advanced version, as it returns much more data, but the returned JSON is more complex to parse.

Note the words Simple and Advanced are my words to describe their APIs, not OpenLibrary’s. I just needed an easy way to distinguish between the two.

For our ArcaneBooks module we’ll be using the Advanced version as it contains extra data we need for our project. That may not be the case for you, so in this post I’ll cover how to use the Simple version. The next post will dive into the more complex Advanced API.

The OpenLibrary Simple API works in one of two ways. Whichever mode you choose, any dashes, spaces, etc must be removed before calling their URLs. Only a string of ten or thirteen numbers can be passed in.

In the first method, you can return an HTML webpage with the book data nicely formatted. The URL (Uniform Resource Locater, a fancy way of saying the web address) to access this is formatted like:

https://openlibrary.org/isbn/[isbn]

Where [isbn] is replaced by the ten or thirteen character ISBN number.

https://openlibrary.org/isbn/0672218747

Will bring up the book data for William Orr’s The Radio Handbook.

We can also return the data in JSON format. To get the data in JSON, all we have to do is append .json to the url. This url will return the same book in JSON format.

https://openlibrary.org/isbn/0672218747.json

The OpenLibrary is flexible, you can use either the ten or thirteen digit number in the call. Both of these examples will bring up the same book, Master Handbook of Ham Radio Circuits by Robert J. Traister.

https://openlibrary.org/isbn/0830678018.json
https://openlibrary.org/isbn/9780830678013.json

The Output JSON

Below is an example of the JSON output (formatted) as returned by the simple API when we call it using the call of https://openlibrary.org/isbn/0672218747.json.

{
  "publishers": [
    "Sams"
  ],
  "languages": [
    {
      "key": "/languages/eng"
    }
  ],
  "identifiers": {
    "goodreads": [
      "3084620"
    ],
    "librarything": [
      "1522789"
    ]
  },
  "title": "Radio Handbook",
  "physical_format": "Hardcover",
  "number_of_pages": 1168,
  "isbn_13": [
    "9780672218743"
  ],
  "isbn_10": [
    "0672218747"
  ],
  "publish_date": "December 1982",
  "key": "/books/OL7667922M",
  "authors": [
    {
      "key": "/authors/OL1196498A"
    }
  ],
  "works": [
    {
      "key": "/works/OL8273120W"
    }
  ],
  "type": {
    "key": "/type/edition"
  },
  "subjects": [
    "Radio",
    "Technology & Industrial Arts"
  ],
  "latest_revision": 6,
  "revision": 6,
  "created": {
    "type": "/type/datetime",
    "value": "2008-04-29T15:03:11.581851"
  },
  "last_modified": {
    "type": "/type/datetime",
    "value": "2022-02-16T09:26:53.493088"
  }
}

Parsing the Returned Data

Below is PowerShell code for accessing the data from OpenLibrary. We call the Simple API using Invoke-RestMethod, then parse its various properties.

For an explanation of what is happening, see the comments in the PowerShell sample code. Note that the sample code doesn’t access every property returned, just enough of them to show you how to deal with the various ways the returned JSON is formatted.


# Set the URL and call the API via Invoke-RestMethod
# The returned JSON data will be held in the variable $BookData
$url = 'https://openlibrary.org/isbn/0672218747.json'
$bookData = Invoke-RestMethod $url

# Here is an extract of part of the JSON code.
# Below we'll show how to access it with PowerShell

<#
   ...more json here
   "title": "Radio Handbook",
   "number_of_pages": 1168,
   ...more json follows
#>

# Here we can just use the variable holding the returned JSON,
# then dot notation to access the property we want
# We're also using string interpolation. Because we are accessing
# properties of an object, we have to wrap it in $()
"Title: $($bookData.title)"
"Number Of Pages: $($bookData.number_of_pages)"

# Identifiers is a JSON object with two values, goodreads and librarything

<#
   ...more json here
   "identifiers": {
     "goodreads": [
       "3084620"
     ],
     "librarything": [
       "1522789"
     ]
   },
   ...more json follows
#>

# We can get the data by just using additional dot notation after the
# identifiers object
"GoodReads Number: $($bookData.identifiers.goodreads)"
"LibraryThing Number: $($bookData.identifiers.librarything)"


# Subjects is returned as a JSON array within the Subjects property

<#
   ...more json here
  "subjects": [
    "Radio",
    "Technology & Industrial Arts"
  ],
   ...more json follows
#>

# You can deal with these in two ways.
# First, you can list individually
foreach ($s in $bookData.subjects)
{
  "Subject: $s"
}

# In the second method you could combine in a single string

# Start by creating a StringBuilder object to append the strings
# as efficiently as possible
$mySubjects = [System.Text.StringBuilder]::new()

# Loop over the BookData Subjects array, copying the current
# subject into the variable $s
foreach ($s in $bookData.subjects)
{
  if ($mySubjects.Length -gt 1)
  {
    # If we already have data in our StringBuilder $mySubjects,
    # then add a comma first, then the name of the subject from $s
    [void]$mySubjects.Append(", $($s)")
  }
  else
  {
    # If the length of our StringBuilder variable is less than 1,
    # it's empty so we'll just append the name of the subject without
    # a comma in front
    [void]$mySubjects.Append($s)
  }
}

# We need to convert the StringBuilder to a normal String to
# use it effectively, for example as a property in a class
$myCombinedSubjects = $mySubjects.ToString()
"Combined Subjects: $myCombinedSubjects"

# The created and last_modified properties are objects,
# simliar to the identifiers

<#
   ...more json here
  "created": {
    "type": "/type/datetime",
    "value": "2008-04-29T15:03:11.581851"
  },
  "last_modified": {
    "type": "/type/datetime",
    "value": "2022-02-16T09:26:53.493088"
  }
   ...more json follows
#>

# For both of these we only need the value property, so we can
# just ignore the type
"Created: $($bookData.created.value)"
"Last Modified: $($bookData.last_modified.value)"

Sample Data

Here are some sample ISBNs you can use for testing the sample code.

ISBN Title
0-87259-481-5 Your HF Digital Companion
0-8306-7801-8 Master Handbook of Ham Radio Circuits (Hardback)
0-8306-6801-2 Master Handbook of Ham Radio Circuits (Paperback)
0-672-21874-7 Radio Handbook Twenty-Second Edition
0-07-830973-5 Electricity Principles and Applications
1418065803 Delmar’s Standard Textbook of Electricity
978-0-9890350-5-7 The Antique Wireless Association Review Volume 31
1-887736-06-9 Crystal Set Projects
0-914126-02-4 Vintage Radio

See Also

For some of the techniques in this blog posts samples, I’ve written other posts in the past which cover their use.

To learn more about String Interpolation, see my post Fun With PowerShell Strings.

My post Fun With PowerShell Arrays will demonstrate how to work with arrays in PowerShell.

Conclusion

In this post we began with an overview of the ISBN, what it is and its history. We then dove into how to access the simple form of the OpenLibrary API to retrieve a books data based on the ISBN.

In my next post I will cover the use of OpenLibrary’s advanced API to get book data.

If you want to learn more about PowerShell, I have many courses on Pluralsight. Two courses in particular I would recommend are:

PowerShell 7 Quick Start for Developers on Linux, macOS, and Windows

Everyday PowerShell for Developers on Linux, macOS, and Windows

Advertisement

The ArcaneBooks Project – An Introduction

Introduction

As some of you may know, I’ve been a ham (amateur) radio operator since 1999, holding the call sign N4IXT. I’m a member of several clubs, including the Birmingham Amateur Radio Club, the Shelby County Amateur Radio Club (where I’m also the webmaster), and the Amateur Radio Relay League (ARRL), in which I am a life member.

More importantly for this post, I am a member of the Alabama Historical Radio Society. We are beginning a project to catalog our exhibits and library into cloud based software named PastPerfect. As part of this effort we’ll be entering data for our extensive library into the software.

Naturally we want to automate as much of this as possible, since the collection is rather extensive. Some of our books are so old they have neither an ISBN (International Standard Book Number) or a Library of Congress Catalog Number (LCCN for short). Others have only the LCCN, the newer books have an ISBN, and a very few have both.

In the process of meeting with other museums I learned this is a need for many other organizations. So I decided to do something about it.

I plan to create a PowerShell module with cmdlets that can retrieve book metadata, such as title, author, and the like. This module will then be made available as on open source project on my website so other groups can use it as well.

As a source a user can pass in either an ISBN or LCCN number, or better yet pipe in an entire list of numbers from a text file, and generate book data.

The sources we’ll use are the Library of Congress and the Open Library site, which is part of the Internet Archive. Both provide web APIs we can use to retrieve data, and we’ll document that information in upcoming posts.

Why PowerShell?

You may be wondering why I chose PowerShell for this project. There were several good reasons.

First, and people often forget this, PowerShell is multi-platform. It can run on Windows, MacOS, and Linux. If you want to learn more on this you should watch my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows.

Next, the PowerShell code is viewable by anyone. Any user can download the code and easily examine it before running. This should address security concerns by many organizations.

The third reason is readability. As many will point out, there are other languages such as Python that will meet the above needs. In general though, code from other languages can be hard to read and execute for people who aren’t developers. I’m imagining my module will be used by many people with only a basic understanding of tech. As such a simple command like Get-BookByISBN -ISBN 1234567890 will be much easier to use.

Finally, well hey I just love PowerShell! As I need to turn this project around quickly I wanted to use something I already know and love.

The Plan

In the next two posts I will cover what ISBNs and LCCNs are, and the web APIs (Application Programming Interface) that we’ll use to get the data.

I’ll then begin a series of posts documenting the PowerShell code needed to retrieve the book data, and how you can use the book data for your organization.

The series will wrap up with the creation of the ArcaneBooks PowerShell Module, and its publication to my Github site.

Kusto Will Return!

For those of you who have been following Kusto Query Language series over the last few years, don’t worry it will return! I’m just taking a short diversion for the next month or so to document this project. Then we’ll return to the world of Kusto.

Conclusion

In this post I established the groundwork for my new ArcaneBooks PowerShell project. In the next few posts we’ll cover terms and data sources, then look at the PowerShell code needed to achieve our results.

I have a long series of blog posts on PowerShell, you’ll find them listed at my Fun With PowerShell Roundup

If you want to take a deeper dive into PowerShell, I have many PowerShell courses at Pluralsight, you’ll find them listed on my About Me page.

One course that may be especially helpful is my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, as it dives into the creation of functions, modules, and more.

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.

The Fun With PowerShell Roundup

PSCustomObject Sample

Introduction

Since September 2020 I’ve been posting extensively about PowerShell in a series I’ve titled Fun With PowerShell. In my next post I will begin a series on a new topic, but before I do I wanted to leave with a Fun With PowerShell Roundup" post.

Below you will find a listing of all posts in my Fun With PowerShell series. Note there are other posts I’ve done in this time frame, but since they did not focus on PowerShell I’ve omitted them from this listing.

The Posts

Date Title
20-09-29 VSCode User Snippets for PowerShell and MarkDown
20-12-05 Two New PowerShell Courses for Developers on Pluralsight
20-12-14 Iterate Over A Hashtable in PowerShell
20-12-21 Fixing the Failed To Acquire Token Error When Logging Into Azure from PowerShell
21-01-04 Suppress Write-Verbose When Calling A function in PowerShell
21-07-05 Fun with PowerShell Get-Random
21-07-12 Fun With PowerShell Strings
21-07-26 Fun With PowerShell Arrays
21-08-02 Fun With PowerShell Hash Tables
21-08-09 Fun With PowerShell Logic Branching
21-08-16 Fun With PowerShell Code Formatting
21-08-23 Fun with PowerShell Loops
21-07-19 Fun With PowerShell String Formatting
21-08-30 Fun With PowerShell Basic Functions
21-09-06 Fun With PowerShell Advanced Functions
21-09-13 Fun With PowerShell Pipelined Functions
21-09-20 Fun With The PowerShell Switch Parameter
21-09-20 Fun With the PowerShell Switch Parameter
21-09-27 Fun With PowerShell Write-Verbose
21-10-04 Fun With PowerShell Write-Debug
21-10-11 Fun With VSCode Snippets for Markdown and PowerShell
21-10-18 Fun With PowerShell Providers
21-11-15 Fun with PowerShell Enums
21-11-29 More Fun with PowerShell Enums
21-12-06 Fun with PowerShell Enum Flags
21-12-14 Fun With PowerShell Classes – The Basics
22-01-10 Fun With PowerShell Objects – PSCustomObject
22-01-17 Fun With PowerShell Objects – Adding Methods to PSCustomObject
22-01-24 Fun With PowerShell Objects – Creating Objects from C#
22-01-31 Fun With PowerShell Objects – Modifying Existing Objects
22-02-07 Fun With PowerShell Classes – Static Properties and Methods
22-02-14 Fun With PowerShell Classes – Overloading
22-02-21 Fun With PowerShell Classes – Constructors
22-03-24 Fun With PowerShell – Extracting Blog Titles and Links from a WordPress Blog with PowerShell
22-03-28           Fun With PowerShell – Extracting Blog Titles and Links from a WordPress Blog with PowerShell – Generating Markdown

Conclusion

This is the wrap up post for my Fun With PowerShell series. Use it as an index to quickly refer back to posts of interest to you. These will make a good quick reference to the many aspects of PowerShell programming.

In my next blog post I’ll begin a new "Fun With…" series, so stay tuned for more fun.

All of the posts in my Fun With PowerShell series 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 – Extracting Blog Titles and Links from a WordPress Blog with PowerShell – Generating Markdown

Introduction

In my previous blogpost, Fun With PowerShell – Extracting Blog Titles and Links from a WordPress Blog with PowerShell, I described how I extracted the title, link, and publication date for posts in my WordPress blog using PowerShell. I then went on to use PowerShell to generate HTML code that I could insert into a post, or create a basic webpage.

It would also be useful to generate Markdown, instead of HTML, in case I want to use it somewhere such as my GitHub page. In this post we’ll see how to do just that, and create Markdown from the output array of PSCustomObjects.

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.2, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

Additionally, be on the lookout for the backtick ` , PowerShell’s line continuation character, at the end of many lines in the code samples. 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.

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.

Where to Start

Much of the work has already been done in the previous post. Review it, stopping at the Creating HTML section. The array we created will now be used in generating Markdown.

This is the reason I created an array of custom objects holding the title, link, and publication date. Just as I used it to create HTML, I can now use it to generate Markdown.

Generating Markdown

Like I did with the HTML, I created a function to create Markdown. This is and advanced function that I’ll pipeline the array of PSCustomObjects into.

function Get-WPMarkdown()
{
  [CmdletBinding()]
  param (
          [Parameter (ValuefromPipeline)] $wpObjects
        , [switch] $FormatAsTable
        )

  process
  {
    # Create a formatted output line
    if (!$FormatAsTable.IsPresent)
    {
      # Create each line as a paragraph
      $outLine = @"
$($wpObjects.PubDate) - [$($wpObjects.Title)]($($wpObjects.Link))
"@
    }
    else
    {
      # Create each line as a row in a table
      $outLine = @"
|$($wpObjects.PubDate)|[$($wpObjects.Title)]($($wpObjects.Link))|
"@
    }

    # Return the formatted line
    $outLine
  }

}

The first parameter accepts the custom objects we generated from the pipeline. The second is a switch that will format the output as a row in a Markdown table, as opposed to just a line of Markdown text.

I then check to see if the switch was passed in, and format the line to return accordingly. Finally I send the generated line out of the function.

Using the Get-WPMarkdown Function

Now all we have to do is call the function. As a reminder, the data in the $outData variable is the array of custom objects we generated in the previous posts.

$outMd = $outData | Get-WPMarkdown

$wpOutputMd = 'D:\OneDrive\BlogPosts\Markdown\arcanecode.wordpress2.md'
Out-File -FilePath $wpOutputMd -InputObject $outMd -Force

This will generate our data as rows in a Markdown file. Below is a small example.

2020-09-29 - [VSCode User Snippets for PowerShell and MarkDown](https://arcanecode.com/2020/09/29/vscode-user-snippets-for-powershell-and-markdown/)
2020-12-05 - [Two New PowerShell Courses for Developers on Pluralsight](https://arcanecode.com/2020/12/05/two-new-powershell-courses-for-developers-on-pluralsight/)
2020-12-14 - [Iterate Over A Hashtable in PowerShell](https://arcanecode.com/2020/12/14/iterate-over-a-hashtable-in-powershell/)

Outputting a Markdown Table

In the code there was a switch to format the output Markdown as a table.

$outMd = $outData | Get-WPMarkdown -FormatAsTable

As I did with the HTML example, I wanted to wrap the generated data in the appropriate Markdown code to make this a complete Markdown table. I created another function to handle this.

function Add-WPMarkdownHeader()
{
  [CmdletBinding()]
  param (
          [Parameter (Mandatory = $true)]
          $markdownData
        )

  # Create a new array
  $outTable = @()

  # Add the html to create a left aligned table header
  $outTable += '|Date|Post|'
  $outTable += '|:-----|:-----|'

  # Add the existing table row data
  foreach ($row in $markdownData) { $outTable += $row }

  # Return the output
  return $outTable
}

As you can see, it creates a new array, adding the Markdown code for a table header, one specific for our data. It then cycles through the array that was passed in and adds it to the new array. Once done this new array is returned by the function.

To call it we simply use the following sample to write it to a file.

$outTable = Add-WPMarkdownHeader $outMd
Out-File -FilePath $wpOutputMd -InputObject $outTable -Force

Here is a sample of the output.

|Date|Post|
|:-----|:-----|
2020-09-29 - [VSCode User Snippets for PowerShell and MarkDown](https://arcanecode.com/2020/09/29/vscode-user-snippets-for-powershell-and-markdown/)
2020-12-05 - [Two New PowerShell Courses for Developers on Pluralsight](https://arcanecode.com/2020/12/05/two-new-powershell-courses-for-developers-on-pluralsight/)
2020-12-14 - [Iterate Over A Hashtable in PowerShell](https://arcanecode.com/2020/12/14/iterate-over-a-hashtable-in-powershell/)

Conclusion

In this post we saw how to generate Markdown code from a WordPress blog extract. Combined with the code in my previous post I now have a handy script I can use to generate HTML and Markdown code from my blog posts. This will be handy for both now, and when I want to create wrap up posts for future series.

These techniques can be easily adapted for any XML file that you wish to create a summary listing for, in HTML or Markdown or both.

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 – Extracting Blog Titles and Links from a WordPress Blog with PowerShell

Introduction

Since September of 2020 I have been blogging heavily on PowerShell. In a few posts I’m going to start a new series on a different subject, but first I wanted to provide a wrap up post with links to all my recent PowerShell posts.

Extracting all of those titles and links by hand seemed like a labor intensive task, so of course I wanted to automate it. In addition, I’ll be able to reuse the code when I’m ready to wrap up my next, or a future, series.

My blog is hosted on WordPress.com, which provides an export function. In this post I’ll cover the code I created to extract all my links, and how I generated HTML from it. In my next post I’ll show the same methodology for generating Markdown, and in the next post will do the PowerShell roundup.

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.2, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

Additionally, be on the lookout for the backtick ` , PowerShell’s line continuation character, at the end of many lines in the code samples. 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.

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.

Extracting Data from WordPress

One of the administrator tools in the WordPress.com site is the ability to extract your blog. You can generate an XML file with the entire contents of your blog. This includes all of the data including the post itself, comments, and associated metadata. They do provide the ability to limit the extract by by date range and subjects.

As you can guess this extract file is large, far too much to sift through by hand. That’s where PowerShell came to my rescue!

For each post, the exported XML file has three lines we are interested in, the tags with <title>, <pubDate> and <link>. I tackled this in stages.

As the first stage, I simply loop over the data in the file, looking for the XML tags I need. When I’ve found all three, I have a small function that creates a PowerShell custom object. After each object is created, it is added into an array. I needed to do a little filtering, as over the last year I’ve added a few more blog posts on other topics. I did not want these to be included in my future "Fun With PowerShell Roundup" post.

Once I have an array of custom objects, I can easily use them in multiple scenarios. For generating HTML I created a function that takes each object and generates a line of HTML code. It also has a way to generate the line as an HTML row instead of a series of paragraphs.

For my purposes, this was all I needed. However there may be times when you wish to generate a complete, but basic, web page. There is one more function I created that will take the output of the HTML rows and add the lines needed to make it a valid HTML page.

Generating a Custom WordPress Object

I mentioned a function to create a custom object, so let’s start with that.

function Get-WPObject()
{
  [CmdletBinding()]
  param (
          [Parameter( Mandatory = $true ) ]
          [string] $Title
        , [Parameter( Mandatory = $true ) ]
          [string] $Link
        , [Parameter( Mandatory = $true ) ]
          [string] $PubDate
        )

  # Build a hash table with the properties
  $properties = [ordered]@{ Title = $Title
                            Link = $Link
                            PubDate = $PubDate
                          }

  # Start by creating an object of type PSObject
  $object = New-Object –TypeName PSObject `
                       -Property $properties

  # Return the newly created object
  return $object
}

The function is straightforward, it takes the three passed in parameters and creates a custom object from it. This is a common technique, it allows you to easily generate a custom object. It also leverages code reuse.

If you want to get a more detailed explanation on creating and using custom PowerShell objects, see my post Fun With PowerShell Objects – PSCustomObject.

Creating The Array

Before we create the array, we need to read in the data from the WordPress XML extract file. I create a variable to hold the location, then read it in.

$wpInput = 'D:\OneDrive\BlogPosts\Markdown\arcanecode.wordpress.2022-03-08.000.xml'

# Read the data from input file
$inData = Get-Content $wpInput

Now it’s time to read in the data from the XML file, one line at a time.

# Setup an empty array to hold the output
$outData = @()

foreach ($line in $inData)
{

  # Extract the title. Replace the XML tags with the Markdown for a link title
  if ($line.Trim().StartsWith('<title>'))
  {
    $title = $line.Trim().Replace('<title>', '').Replace('</title>', '')
  }

  # Extract the link, replacing the XML tags with the Markdown link characters
  if ($line.Trim().StartsWith('<link>'))
  {
    $link = $line.Trim().Replace('<link>', '').Replace('</link>', '')

    # For some reason the WordPress export uses http instead of https. Since the
    # blog supports https, lets fix that.
    $link = $link.Replace('http:', 'https:')
  }

  if ($line.Trim().StartsWith('<pubDate>'))
  {
    # Extract just the date, then covert it to a DateTime datatype
    $pubDateTemp = [DateTime]($line.Trim().Replace('<pubDate>', '').Replace('</pubDate>', ''))

    # Now use the ToString feature of a DataTime datatype to format the date
    $pubDate = $pubDateTemp.ToString('yyyy-MM-dd')

    # In addition to links to the blog posts themselves, the exported XML file also
    # has links to images. To weed these out, we will search for posts that have PowerShell
    # in the title. The Contains method is case sensitive so it will omit the links
    # to the images.
    #
    # When a match is found, it passes the Title/Link/PubDate to our function, which will
    # generate a custom object. This object will be added to our output array.
    if ($title.Contains('PowerShell'))
    {
      $outData += Get-WPObject -Title $title -Link $link -PubDate $pubDate
    }

  }

} # End the foreach ($line in $inData) loop

First I create an empty array that will hold the output. To learn more about arrays, see my post Fun With PowerShell Arrays.

Now I enter a foreach loop, to go over each line in the array. If you don’t know, when you use Get-Content it returns each line in the file as a row in an array. That’s what I want here, but be aware if you add the -Raw switch to the Get-Content it returns the entire file as one big text string.

The data in the XML occurs in the order of Title, Link, then PubDate. PubDate is the Publication Date for the blog post.

As I find the title and link, I remove the XML tags then copy the data into a local variable. For some reason the extract uses http for the links, so I wanted to correct it to use https.

When I find the PubDate, I wanted to reformat it as a string in YYYY-MM-DD format. I extract just the date portion of the line by removing the XML tags. I then cast it to a [DateTime] and store it in a temporary variable.

I can then call the ToString method of the DataTime datatype to format it in a format I want, namely YYYY-MM-DD (Year, Month, Day).

Next I check to see if the title contains the word PowerShell. If so, I now have the three pieces of info I need, and call my function to generate the PSCustomObject and add it to the output array.

Creating HTML

To create the HTML I wrote a function, Get-WPHtml. Like the other functions I created this as an Advanced function. To read up on Advanced Functions, see my article Fun With PowerShell Advanced Functions.

I needed this so I could pipe the data from the array containing my WordPress PSCustomObjects into it. By doing it this way, I could reuse the Get-WPHtml with any array that has objects with three properties of Title, Link, and PubDate.

Let’s look at the function.

function Get-WPHtml()
{
  [CmdletBinding()]
  param (
          [Parameter (ValuefromPipeline)] $wpObjects
        , [Parameter (Mandatory = $false)] $Indent = 0
        , [switch] $FormatAsTable
        )

  process
  {
    # Create a string with spaces to indent the code. If not used no indent is created.
    $space = ' ' * $Indent

    # Create a formatted output line
    if (!$FormatAsTable.IsPresent)
    {
      # Create each line as a paragraph
      $outLine = @"
$space<p>$($wpObjects.PubDate) - <a href="$($wpObjects.Link)" target=blank>$($wpObjects.Title)</a></p>
"@
    }
    else
    {
      # Create each line as a row in a table
      $outLine = @"
$space<tr> <td>$($wpObjects.PubDate)</td> <td><a href="$($wpObjects.Link)" target=blank>$($wpObjects.Title)</a></td> </tr>
"@
    }

    # Return the formatted line
    $outLine
  }

}

The first parameter will accept the data from our pipeline, as I explain in my article Fun With PowerShell Pipelined Functions. Next is an optional parameter that allows the user to indent each row a certain number of spaces. The final parameter toggles between formatting each row as a standard paragraph or as a table row.

The process block will run once for each piece of data passed in from the pipeline. It creates a variable with the number of spaces the user indicated. If the user didn’t pass a value in, this will wind up being an empty string.

Next we check to see if the switch FormatAsTable was passed in, then create an output string based on the users choice. For more on switches, refer to my article Fun With the PowerShell Switch Parameter.

As a final step we return the newly formatted line, which puts it out to the pipeline.

Using the New Function

Using these functions is easy. We take the array of custom objects, then pipe it into the new Get-WPHtml function using an indent of 2. The result is copied into the $outHtml variable which will be an array.

Finally we set the path for our output file, then use the Out-File cmdlet to write to disk.

$outHtml = $outData | Get-WPHtml -Indent 2

# Save the new array to a file. Use Force to overwrite the file if it exists
$wpOutputHtml = 'D:\OneDrive\BlogPosts\Markdown\arcanecode.wordpress2.html'
Out-File -FilePath $wpOutputHtml -InputObject $outHtml -Force

Creating a Full HTML Page

For my purposes, I am going to take the data in the file and copy and paste it into the WordPress post editor when I create my roundup blog post. For testing purposes, however, it was convenient to have a full webpage. With a full webpage I can open it in a web browser, see the result, and test it out. Further, in other projects I may actually need a full webpage and not the part of one that I’ll be using for my blog.

The version of the webpage with just paragraph tags will open OK in a browser, but the version of the table will not. So let’s fix that.

Here is the function I created to wrap the output of the previous function, when called using the -FormatAsTable flag, in the necessary HTML to make it a functioning webpage.

function Add-WPHtmlHeader()
{
  [CmdletBinding()]
  param (
          [Parameter (Mandatory = $true)]
          $htmlData
        )

  # Create a new array
  $outTable = @()

  # Add the html to create a left aligned table header
  $outTable += '<style>th { text-align: left; } </style>'
  $outTable += '<table>'
  $outTable += '<tr>'
  $outTable += '<th>Date</th> <th>Post</th>'
  $outTable += '</th>'

  # Add the existing table row data
  foreach ($row in $htmlData) { $outTable += $row }

  # Add the closing table tag
  $outTable += '</table>'

  # Return the output
  return $outTable
}

The one parameter is the array that was output from our Get-WPHtml function. While you can add rows to an array, or change values at a specific position, you can’t insert new rows at specific positions. As such we have to create a new empty array, which was done with $outTable.

We then add the lines needed to create the table header. For this article I’m assuming you are familiar with basic HTML tags.

Once the header rows have been added we cycle through the input array, adding each row to the new output array.

Finally we add the closing tag to finish off the table element, then return the output.

Generating the Complete Webpage

Now that the hard part is done, all we have to do is call the function, passing in the output of the previous function, stored in $outHtml. This will then be written to a file using the Out-File cmdlet.

$outTable = Add-WPHtmlHeader $outHtml

# Save the new array to a file. Use Force to overwrite the file if it exists
Out-File -FilePath $wpOutputHtml -InputObject $outTable -Force

The Output

Here is a sample of the output of our hard work. Note I’ve only included a few rows of blog posts to keep it brief.

<style>th { text-align: left; } </style>
<table>
<tr>
<th>Date</th> <th>Post</th>
</th>
  <tr> <td>2020-09-29</td> <td><a href="https://arcanecode.com/2020/09/29/vscode-user-snippets-for-powershell-and-markdown/" target=blank>VSCode User Snippets for PowerShell and MarkDown</a></td> </tr>
  <tr> <td>2020-12-05</td> <td><a href="https://arcanecode.com/2020/12/05/two-new-powershell-courses-for-developers-on-pluralsight/" target=blank>Two New PowerShell Courses for Developers on Pluralsight</a></td> </tr>
  <tr> <td>2020-12-14</td> <td><a href="https://arcanecode.com/2020/12/14/iterate-over-a-hashtable-in-powershell/" target=blank>Iterate Over A Hashtable in PowerShell</a></td> </tr>
</table>

Conclusion

In this post we tackled a project to create an HTML page based on the export of a WordPress blog. In the process we used many of the techniques I’ve blogged about over the last year and a half.

For the next post we’ll use these same techniques to create an output file in Markdown format.

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 – 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 – Static Properties and Methods

Introduction

Over the last few articles we’ve been covering PowerShell objects. The first article in the series, Fun With PowerShell Classes – The Basics, covered the basics of using of the PowerShell class construct introduced in PowerShell version 5.

If you’ve not read it I’d suggest you do so now as we’ll be building on it in this article, as well as in the next two, as we explore the advanced capabilities of PowerShell classes. In this post we’ll cover the concept of static properties and methods.

Let me mention that for all of the examples we’ll display the code, then under it the result of our code if applicable. 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.

At the end of the line in many code samples you may notice a backtick ` character. 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. My post Fun With PowerShell Pipelined Functions dedicates a section to the line continuation character if you want to learn more.

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.

Starting Point

Just as a refresher, here is the class we originally developed.

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()
  }

}

We can create a new instance of the class by calling the static new method built into all PowerShell defined classes. Once created we can start assigning values to its properties.

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

With that reminder, let’s start diving in to some advanced features offered by classes.

Static Properties

In a previous post on creating PowerShell objects from C# code, I introduced the concept of static properties and methods. A static property or method is one that can be called without having to create a new instance of an object from the class.

To call a static method or property, use the name of the class in brackets, then two colons, then the name of the property or method you want to call. In fact, you’ve already done this in creating a new instance of a class when you used [Twitterer]::new().

It’s easy to create your own static properties and methods. Let’s create a new version of our class, and name it TwittererRedux. (Redux is a fancy word meaning ‘bring back’.) Then, we’ll add a new static property to it.

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()
  }

}

In the properties area we add one new property, Version. At the front we added the keyword static. This, of course, is the indicator this property is available even without creating a new instance of the class.

Having a version number is a fairly common and useful thing to include in a class. Let’s see it in use. First though, make sure you’ve executed the above class definition for TwitterRedux to make sure it is memory.

[TwittererRedux]::Version

Result:

2022.01.07.002

Other examples of things you might wish to manifest as static properties include the author name, contact information, copyright, or perhaps a link to documentation or github where your class is stored.

Let’s turn now to the creation of a static method.

Static Methods

In our original version of the class we have a method called OpenTwitter. This accessed the objects function TwitterURL, which returned the formatted Twitter URL for the users handle, stored in the objects TwitterHandle property. Finally it opened up the Twitter page in the default browser.

It could be useful to have a function that would do something similar, only without having to go to the effort of creating a class, then populating the TwitterHandle property just so we could call this function.

We’ll do so by adding a new, static function to the class.

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 = '2021.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
  }

}

We call the new method similar to the way we accessed our property, when we called the new method to create the class.

[TwittererRedux]::OpenTwitterPage('ArcaneCode')

If your coding went well, your default browser should open to my Twitter page (or whosever you passed in).

Restrictions on Static Properties and Methods

There is one restriction when working with static properties and methods, but it is one you need to know about.

> Static properties and methods must be self contained, and cannot reference other properties and methods of the class.

This makes sense if you think about it a moment. You are only accessing the class definition, i.e. the blue print. Normal properties and methods only exist once an object has been created from a class. While it makes sense, it isn’t intuitively obvious so I wanted to point it out.

A Note on Defining Classes

I just wanted to point out a little "gotcha" when working with classes. Within a single PowerShell script (i.e. PS1 file) you can only define a class once. Normally this is not a big issue.

However, if you are developing a class it’s possible you might want multiple versions of it. For example, at the top of the script you might want your original version.

Under it you might want basically the same code, but you’ve added a new method, or perhaps changed the code to an existing method. You want to do this for testing, so you can compare one version versus the other.

PowerShell, or more precisely VSCode or the PowerShell IDE, will generate an error for the second, third, or more versions in your code warning you it has already been defined.

The fix is pretty simple, you could just comment out all but one of the class definitions, leaving the one you are working with uncommented. Alternatively, you could just create multiple PS1 files and work with different versions in each. VSCode is especially nice for this as it lets you have your PS1 files side by side.

Conclusion

Static properties and methods are not difficult to implement, and can be quite useful. As you create your classes, think about situations where they may benefit from a static property or method.

In the next installment of this series we’ll continue our examination of the PowerShell class type by diving into overloads.

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 Objects – Modifying Existing Objects

Introduction

So far we’ve covered a lot in this series on PowerShell Objects. We began by creating a class using the class keyword introduced in PowerShell 5. We then looked at using PSCustomObject to create new objects, then add methods to those objects. In the previous post, we used C# code to create our PowerShell objects.

In this installment, we’ll see how to add properties and methods to existing objects created by someone else. For this example we’ll use objects returned by the Get-ChildItem cmdlet, but we could use any objects.

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.

In the code samples be on the lookout for the backtick ` , PowerShell’s line continuation character, at the end of many lines. 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.

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.

Getting The Objects to Work With

As stated in the Introduction, we will use the objects returned by the Get-ChildItem cmdlet to add a new property and method to. We’ll set our location (in my case to the folder where these samples are stored), call the Get-ChildItem cmdlet and store the result in a variable, $items.

Set-Location C:\Users\arcan\OneDrive\BlogPosts\Markdown
$items = Get-ChildItem

Let’s look a the first item in the $items collection to see what its datatype is.

$items[0].GetType()

Result:

IsPublic IsSerial Name     BaseType
-------- -------- ----     --------
True     False    FileInfo System.IO.FileSystemInfo

As you can see, each item is of type FileInfo. Each object contains information about the corresponding file it represents. You can find a full list of properties and methods for the FileInfo class in the online Microsoft Documentation for FileInfo.

Coding Our New Method

For this example, we are going to iterate over our collection of FileInfo objects. To each one, we’ll be adding one property and one method. The property will just be a number that can be used to uniquely identify each object. We’ll look more at that momentarily.

The method we’ll add will analyze the existing Extension property of the FileInfo object. As I’m sure you know, the extension is the data that occurs after the period in the file name, and is used to identify the type of file it is.

Here is the script block for this method.

# Define the custom script property
$script = {

  switch ($this.Extension)
  {
    '.cs'   {$retValue = 'C#'}
    '.md'   {$retValue = 'Markdown'}
    '.ps1'  {$retValue = 'Script'}
    '.psd1' {$retValue = 'Module Definition'}
    '.psm1' {$retValue = 'Module'}
    '.xml'  {$retValue = 'XML File'}
    '.pptx' {$retValue = 'PowerPoint'}
    '.csv'  {$retValue = 'Comma Separated Values file'}
    '.json' {$retValue = 'JavaScript Object Notation data'}
    default {$retValue = 'Sorry dude, no clue.'}
  }

  return $retValue
}

Within the switch statement, I use $this to access the current object. It then access the Extension property of the current object.

It then goes down the list, comparing the extension value to the text to the left of the squiggly brace. If it finds a match, it will run the code inside the script block. This simply sets a return value variable to a more human friendly text representation of the file type.

If no match is found, it runs the code by the default value. For more in the switch statement, see my post Fun With PowerShell Logic Branching.

Adding The Property and Method to the FileInfo Object

Now that our script is defined, it’s time to add it as well as a property to our FileInfo objects. Let’s see the code, then we’ll break it down.

# Create an item count variable
$itemCount = 0

# Iterate over each DirectoryInfo object in the $items collection
foreach($item in $items)
{
  # Add a note property, setting it to the current item counter
  $itemCount++
  $item | Add-Member –MemberType NoteProperty `
                     –Name ItemNumber `
                     –Value $itemCount

  # Add script property to the individual file object
  Add-Member -InputObject $item `
             -MemberType ScriptMethod `
             -Name 'ScriptType' `
             -Value $script

  # Now display the already existing Name property along with the
  # property and method we just added.
  "$($item.ItemNumber): $($item.Name) = $($item.ScriptType())"
}

We begin by creating a variable, $itemCount. Within the foreach loop we’ll increment it, then use it as our index for the ItemNumber property.

The foreach loop is entered, where we iterate over the collection of FileInfo objects stored in $items. Each time through the loop, the current item is copied into the $item variable. For more info on foreach, see my post Fun With PowerShell Loops.

The next line is straightforward, we simply increment the $itemCount by one.

You’ve seen the Add-Member cmdlet used in recent posts on adding properties and methods to a PSCustomObject, so I won’t delve deep into it here.

The first call to Add-Member takes the current FileInfo object, stored in $item, and adds a new property we’ll name ItemNumber. When we add it, we’ll go ahead and assign the value in $itemCount. Note that this property could be updated at a future time, although we won’t need to for this example.

We then call Add-Member a second time, adding in the script you saw earlier and naming it ScriptType.

Finally, we use string interpolation to build a nicely formatted string with the item number, the name of the file (a native property of the FileInfo object), and finally we call the method we just added ScriptType.

Here is the final output of our effort.

Result:

1: blog-template.md = Markdown
2: fun-with-powershell-classes-the-basics.md = Markdown
3: fun-with-powershell-classes-the-basics.ps1 = Script
4: fun-with-powershell-enum-flags-header.png = Sorry dude, no clue.
5: Fun-With-PowerShell-Enum-Flags.md = Markdown
6: Fun-With-PowerShell-Enums.md = Markdown
7: Fun-With-PowerShell-Objects-Part 1.md = Markdown
8: Fun-With-PowerShell-Objects-Part 1.ps1 = Script
9: Fun-With-PowerShell-Objects-Part 2.md = Markdown
10: Fun-With-PowerShell-Objects-Part 2.ps1 = Script
11: Fun-With-PowerShell-Objects-Part 3.cs = C#
12: Fun-With-PowerShell-Objects-Part 3.md = Markdown
13: Fun-With-PowerShell-Objects-Part 3.ps1 = Script
14: Fun-With-PowerShell-Objects-Part 4.md = Markdown
15: Fun-With-PowerShell-Objects-Part 4.ps1 = Script
16: fun-with-powershell-objects-part-1.png = Sorry dude, no clue.
17: Fun-With-PowerShell-Providers.md = Markdown
18: Fun-With-PowerShell-Write-Debug.md = Markdown
19: Fun-With-PowerShell-Write-Verbose-and-Write-Debug.md = Markdown
20: Fun-With-VSCode-Code-Snippets.md = Markdown
21: IMG_0965.JPG = Sorry dude, no clue.
22: more-fun-with-powershell-enums-header.png = Sorry dude, no clue.
23: More-Fun-With-PowerShell-Enums.md = Markdown
24: More-Fun-With-PowerShell-Enums.ps1 = Script
25: security-for-apartment-dwellers-01.png = Sorry dude, no clue.
26: Security-for-Apartment-Dwellers-header.png = Sorry dude, no clue.
27: Security-for-Apartment-Dwellers.md = Markdown

I author these blog posts in markdown within VSCode first, prior to copying them into my WordPress based blog. This folder contains a markdown file for each post, most of which have one or more accompanying code files associated with it.

I deliberately omitted the image type extensions (.jpg, .png) from the switch statement so you could see the default option being taken.

Persistance

There is an important fact you need to recall when using this technique. The new property and method only exist for the set of FileInfo objects contained in our $items collection. If I were to get another collection, perhaps using $moreItems = Get-ChildItem, the FileInfo objects stored in $moreItems will NOT have our ItemNumber and ScriptType in them.

You will have to explicitly add custom properties and methods to objects each time you need them.

Conclusion

As you can see, this technique offers many possibilities. You could define a script block at the top of your script that does a complex calculation, or perhaps formats data for easier reading by the end user. Then you simply add this script block to the objects you generate.

This makes your code much more readable. The complex part is at the top where we define the script block, out of the way of your loops.

It can also promote code reuse. You can create a separate script with many script blocks that you commonly use. You call that script from the one you are currently developing, and you instantly have a set of new properties and methods that can be added to the set of objects you are working with.

This method provides for extensibility with objects you did not author, or have the source code for. Perhaps you have a compiled PowerShell module that came from a vendor, but it lacks that one method that would, for your unique situation, make it much easier to work with. You can now code that method for yourself and use it.

As time goes on I’m sure you’ll find many situations you can use these techniques to solve problems.

In the next three installments of this series we’ll return to the PowerShell class type. We’ll look at some of the advanced abilities that it offers.

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 Objects – Creating Objects from C#

Introduction

This is the next installment in my series on creating objects in PowerShell. In the first installment we showed how to create an object using the class type introduced in PowerShell 5. That covered the basics, and in the last installment of this series we’ll cover some advanced techniques.

In the last two installment of this series, I covered the various ways to create objects using the PSCustomObject. We saw how to create it using the New-Object cmdlet, then how to add your custom properties to it using the Add-Member cmdlet. In the subsequent post we saw how to add new methods to it.

In this post, we’ll cover something new, creating an object based on C# code!

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.

Additionally, be on the lookout for the backtick ` , PowerShell’s line continuation character, at the end of many lines in the code samples. 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.

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.

Why C#

You may be asking yourself, why integrate C# code into PowerShell? Why not just define our objects using PowerShell? There are several reasons, especially if you are working with a team of C# developers, or are a C# developer yourself.

First, it can make testing your C# classes easy. You can code the class and save it in a .CS file. Then run some simple PowerShell to create a new object from your class and test its various properties and methods. This lets you make changes easily and test again. All without having to create a full blown C# project just to test.

It also allows for code reuse. Let’s say your C# developers have created a library to do some calculations, and you need to use one of the methods from that library, but that library expects you to pass in an object based on a class.

Let’s further the example, perhaps you have the task of reading in a CSV file, doing a calculation for each row, then outputting another CSV file, or maybe even a JSON file. This is a one time use, so you don’t want to go to the effort of creating a full blown C# project.

Using the techniques in this demo, you could simply access the C# file in which the class was defined, and generate an object from it in PowerShell. Then all you’d have to do is populate the object and pass it into the library to do the calculation, and output the result.

These are just a few simple examples, I’m sure you’ll come up with many more as the need arises. I’ll be honest, this isn’t something you will need to do a great deal, but when you do you’ll appreciate knowing how.

Embedding a C# Class in your PowerShell

In this first method, we’ll define a standard C# class within a here string then add it as a new data type in PowerShell. Once it exists as a type, we can then generate new objects from it. Let’s take a look at a very simple class definition.

$code = @"
using System;

public class SchemaTable
{
  public string DatabaseName;

  public string SchemaTableName(string pSchema, string pTable)
  {
    string retVal = "";  // Setup a return variable

    retVal = pSchema + "." + pTable;

    return retVal;

  } // public SchemaTableName

  public string FullName(string pSchema, string pTable)
  {
    string retVal = "";  // Setup a return variable

    retVal = this.DatabaseName + "." + pSchema + "." + pTable;

    return retVal;

  } // public FullName

} // class SchemaTable

"@

If you’ve read this far I’m going to assume you are familiar with C#, at least the basics of it, so I’ll keep this explanation at a high level.

We start by declaring a class named SchemaTable. The next line declares a variable (which will become a property) called DatabaseName.

I then create the first of two functions (which will become our methods). The SchemaTableName simply takes the two passed in values of pSchema and pTable and concatenates them together with a period between them.

The second, FullName, takes the value in DatabaseName and concatenates them with the schema and table name parameters, again using a period as a separator in the return string.

Next, we need to add this class as a new data type in PowerShell. You are already familiar with many data types, such as int, string, and more. We simply want to add a new data type to our PowerShell environment.

To do so, we will use the Add-Type cmdlet.

Add-Type -TypeDefinition $code `
         -Language CSharp

The first parameter, TypeDefinition, takes the C# code we defined in the here string. The second, Language, is pretty obvious. We simply need to let PowerShell know what language this code was written in.

As of right now, the only supported language is C#. Because of this, if you leave off the -Language CSharp parameter, it will default to C# as the language. I included it here for completeness, but will omit it for future examples in this post.

So now we’ve defined a class in C#, and have added it as a new data type in PowerShell. How then do we create an object from it?

We’ll turn to our old friend, New-Object.

$result = New-Object -TypeName SchemaTable

That’s it, that simple one line will create our new object based on the C# code we defined in the $code variable. You can even use Get-Member to display its properties and methods like you would with any other object.

$result | Get-Member

Result:

Name            MemberType Definition
----            ---------- ----------
Equals          Method     bool Equals(System.Object obj)
FullName        Method     string FullName(string pSchema, string pTable)
GetHashCode     Method     int GetHashCode()
GetType         Method     type GetType()
SchemaTableName Method     string SchemaTableName(string pSchema, string pTable)
ToString        Method     string ToString()
DatabaseName    Property   string DatabaseName {get;set;}

It contains the standard methods and properties built into all objects, but it also has the three we defined: FullName, SchemaTableName, and DatabaseName.

We can use these properties and methods just like ones in any other object. Let’s set the DatabaseName property, then display it.

$result.DatabaseName = 'MyDB'
$result.DatabaseName

Result:

MyDB

Likewise, we can access the methods we created. Here’s the SchemaTableName method.

$result.SchemaTableName('ASchema', 'ATable')

Result:

ASchema.ATable

And for completeness, the FullName method.

$result.FullName('ASchema', 'ATable')

Result:

MyDB.ASchema.ATable

C# Classes with Static Methods

In the original post in this series on basic PowerShell classes, I mentioned the concept of static methods and properties. As static method or property is simply one that can be called without having to generate a new object.

While we’ll circle back around to discuss implementing static methods and properties in PowerShell classes in the final post in this series, it is likely you’ll encounter C# classes with static methods and properties. As such we’ll go ahead and cover them here, while we are talking C#.

In the code below, I’ve defined a class with one method, and labeled it as static. In reality you will encounter many classes that have a mix of static and non-static members, but for this post we’ll keep the example simple.

$code = @"
using System;

public class StaticSchemaTable
{
  public static string FullName(string pSchema, string pTable)
  {
    string retVal = "";

    retVal = pSchema + "." + pTable;

    return retVal;

  } // public static FullName
} // class StaticSchemaTable
"@

As you can see, I’ve simply used the static keyword as part of the FullName function declaration. I also changed the name of the class, otherwise the code is the same as the previous demo.

Now we need to add this as a new type in our current PowerShell session.

Add-Type -TypeDefinition $code

Calling our static method requires different syntax. First, it won’t be necessary to create an object from it. Second, we’ll need to use the full name of our class in brackets, followed by two colons. We then indicate the name of the static function to call, and pass in any parameters.

$result = [StaticSchemaTable]::FullName('MySchema', 'myTable')
$result

Result:

MySchema.myTable

Static methods and parameters aren’t something that’s used a great deal, but they are used so you should know how to handle them.

Creating an Object from A C# File

While it is certainly possible to embed C# code right in your PowerShell, this could lead to some issues. The moment a developer makes a change to their .cs file, you are now out of sync. You don’t want to have to keep cutting and pasting all the time.

It makes far more sense, then, to simply access the C# file with the class definition, and load it at run time.

First, you need to create a C# file with the sample code. Here is what I put in my .cs file:

using System;

public class StaticSchemaTableInFile
{
  public static string FullName(string pSchema, string pTable)
  {
    string retVal = "";

    retVal = pSchema + "." + pTable;

    return retVal;

  } // public static FullName
} // class StaticSchemaTableInFile

This is the same static class you just saw, with the minor change to the class name.

In the next sample, I simply build the path to the file name, then use the Get-Content to read it.

$csPath = 'C:\Users\arcan\OneDrive\BlogPosts\Markdown\'
$file = "$($csPath)Fun-With-PowerShell-Objects-Part 3.cs"
$code = Get-Content $file | Out-String

Get-Content will read the contents of the file. By default Get-Content reads it as an array with each line in the file being an element, so we’ll have to pipe it through the Out-String cmdlet to convert it to a single string. This string is then stored in the $code variable. Of course you’ll need to update the path and file variables you used on your computer.

Now we do just like the previous demo, call Add-Type then run it.

Add-Type -TypeDefinition $code
$result = [StaticSchemaTableInFile]::FullName('mySchema', 'myTable')
$result

Result:

mySchema.myTable

Again, I reused the example from the static demo but we could also have used the first example, or any standard C# file containing class definitions.

Other Ways To Add Types

While outside the scope of this post, I did want to mention there are two other ways you can add new data types to your PowerShell scripts. First, Add-Type will let you load types stored in an assmebly, in other words a .dll file.

Second, if you are running on a Windows computer you can add types stored in native Windows APIs. If you want to learn more about these, I’ll refer you to the Add-Type Documentation at Microsoft.

Persistance

One last thing you need to be aware of. When you add a type it does not persist between sessions. The moment you close your command window or VSCode, that type goes away. You’ll need to recreate it the next time you run your script.

This is probably a good thing, as it’s doubtful you will need to use these types on a daily basis. Should you need to, though, you’ll have to edit your PowerShell profile and have them added within it.

Conclusion

In this post we saw how to create custom objects from C# classes. They could be embedded in our PowerShell code, or stored in external files. The subject of static methods and properties were mentioned, along with a demo on how to use them.

In the next post we’ll see a very useful technique, and cover the ability to add our own custom methods and properties to existing objects that others created, including ones built right into PowerShell.

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 Objects – Adding Methods to PSCustomObject

Introduction

In the previous installment of this series, I covered the various ways to create objects using the PSCustomObject. We saw how to create it using the New-Object cmdlet, then how to add your custom properties to it using the Add-Member cmdlet.

In this post we’ll learn how to add our own methods to our objects using script blocks. Before we go on, just a quick reminder on vocabulary.

In object oriented terminology, objects have properties and methods. From the perspective of the script writer who uses our object, they only know of the properties and methods we expose. They don’t know, or care, how we implemented them.

From the perspective of us, the authors of the code to create the object, it’s a little different. What the end user calls properties we store in variables. We implement our objects methods using functions.

When we are talking about our code in terms of writing our object, you will frequently see the terms properties and variables used interchangeably. Likewise you’ll see the terms method and function used interchangeably.

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.

Additionally, be on the lookout for the backtick ` , PowerShell’s line continuation character, at the end of many lines in the code samples. 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.

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.

Script Blocks

Before we get started, it’s important to understand the concept of a script block. A script block is a piece of code encapsulated within squiggly braces {}. This code is meant to execute as a unit. Here’s an example you’ve probably seen before.

$x = 1
if ($x -eq 1)
{ Write-Host 'Yep its one' }

The code on the last line is the script block. This unit of code, within the squiggly braces, will execute should the if statement evaluates to true.

It’s possible to define your own script blocks, and store them in a variable.

$hw = {
        Clear-Host
        "Hello World"
      }

Here I’ve generated a simple block with two lines. The first clears the display, the second prints Hello World.

Now you have a variable, $hw, holding a script block. How can we use this?

First, we could execute the script block stored in the variable. To do so, we need to precede the name of the variable with an ampersand &. The ampersand is the PowerShell shortcut for execute the code block contained in this variable.

& $hw

Result:

Hello World

Although it’s difficult to show, the display did indeed clear before displaying our text.

Note the space between the & and the variable name is optional, this works too.

&$hw

Personally I think the space makes it a bit easier to read, not to mention it’s easier for the eye to notice the &. Whichever way you go, I suggest picking a format and sticking to it.

There are some interesting ways we can use this concept. Of course we’ll look at using script blocks to add new methods to an object in a moment, but another fun thing you can do is pass a script block into a function.

A quick note, it is generally considered poor practice to have Write-Host statements within a function. Since this is just a simple demo though, we’ll use them just to illustrate our concepts.

function Run-AScriptBlock($block)
{
  Write-Host 'About to run a script block'

  & $block

  Write-Host "Block was run"
}

Run-AScriptBlock $hw

Result:

Hello World
Block was run

The first line to display "About to run…." did execute, but it was wiped out due to the Clear-Host in the script block.

The script block then displayed Hello World, and returned control to the function. The function then displayed "Block was run" then exited.

The PowerShell testing tool, Pester, makes extensive use of this functionality to pass the code blocks being tested into Pester’s unit testing functions.

Your imagination is probably running wild at the various ways you can use this. For example, you could build a string of PowerShell code based on certain conditions, then once the string of code is complete execute it.

At this point you have a nice foundation on the concept of script blocks, so let’s move on to the main topic of this post.

Starting Point

This post picks up where the previous one left off. If you recall, our previous post built a function to generate a custom object of type PSCustomObject. If you need an explanation please go back and read part 1 of this series, but to make it easy for you I’ll reproduce the function needed to create the object we’ll be working with.

function Create-Object ($Schema, $Table, $Comment)
{
  # Build a hash table with the properties
  $properties = [ordered]@{ Schema = $Schema
                            Table = $Table
                            Comment = $Comment
                          }

  # Start by creating an object of type PSObject
  $object = New-Object –TypeName PSObject -Property $properties

  Add-Member -InputObject $object `
             -MemberType AliasProperty `
             -Name 'Description' `
             -Value 'Comment'

  # Return the newly created object
  return $object
}

$myObject = Create-Object -Schema 'MySchema' `
                          -Table 'MyTable' `
                          -Comment 'MyComment'
$myObject

Adding a Method (aka Function) to an Object

With the knowledge above, combined with what we learned in the previous post, it turns out adding a simple function to an object is easy. First, we need to define our function in a script block. This function will combine the schema name and the table name with a period to separate the two.

$block = {
           $st = "$($this.Schema).$($this.Table)"
           return $st
         }

In this example I used string interpolation to build my return string. (For more on string interpolation, see my post Fun With PowerShell Strings.)

Note my use of the $this keyword. Just like with objects generated by the more modern classes in PowerShell 5 and beyond, $this is used to represent the current instance of our custom object. Thus we’ll be getting the schema and table names for the current object, stored in $myObject, and not one in another variable that was instantiated using the same code.

If you aren’t a fan of string interpolation, you could have opted for concatenation with $st = $this.Schema + '.' + $this.Table to generate the return value, but interpolation is the generally accepted best practice for building strings.

Concatenation is generally slower and takes more processing power than interpolation. Granted in this case it is barely measurable, but done over a dataset of millions of rows you might see an impact.

With the schema-table string ($st) built it is then returned.

Now we will use the Add-Member cmdlet to add this function to our custom object. Assuming you have already run the function to create the $myObject variable, shown in the Starting Point section, you can use the following code to achieve our goal.

Add-Member -InputObject $myObject `
           -MemberType ScriptMethod `
           -Name 'SchemaTable' `
           -Value $block

I start by passing in the object I wish to add a member to, our $myObject variable.

Next I indicate what type of member we are adding. ScriptMethod is the value to pass in to MemberType to indicate the data in the variable is a script block and should be manifested as a method.

The Name is next, in other words what we want to name this method. Finally into the Value parameter we pass in the variable holding the script block.

Once you add this new member, you can simply call it using the dot notation, with one important caveat. Because this is a method, you need to add parenthesis to the name of the method.

$myObject.SchemaTable()

Result:

MySchema.MyTable

Using the parenthesis lets PowerShell make the distinction between a property and a method.

Parameters

What’s that? You in the back row raising your hand, what did you say? Parameters? You want to add parameters to your new method?

Well, OK because you asked so nice.

This turns out to be pretty easy. We just need to add a param section within our script block.

$block = {
           param ($DatabaseName)
           $dst = "$DatabaseName.$($this.Schema).$($this.Table)"
           return $dst
         }

On the first line of our script block we use the param keyword, then have a list of our parameters within parenthesis. Here we only have one, $DatabaseName, but we could have more separated by commas.

I then build a string that uses the passed in database name, with the schema and table names already in the object, and finally return it.

Next, I use Add-Member to add this function to our object just like I did with the previous example, the only difference being the name and the variable with our script block. Now we can call it.

$myObject.DatabaseSchemaTable('MyDBName')

Result:

MyDBName.MySchema.MyTable

Conclusion

This post began with an explanation of script blocks. Using this knowledge we added new methods to our existing object. One even allowed us to pass in a parameter.

In in the next post we’ll see how to create custom objects from bits of C# code. Later on we’ll see how to add our own properties and methods to an existing object created by PowerShell.

Well conclude this series by returning to our discussion of PowerShell classes by looking at some advanced features of the built in class construct.

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 Objects – PSCustomObject

PSCustomObject Sample

Introduction

Before the holidays I had started a series on classes and objects in PowerShell. If you haven’t read my post Fun With PowerShell Classes – The Basics you should give it a quick read. There are terms that were defined in it that we’ll be using here.

For this post I’ll begin a series 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. It still has a lot of validity today though, as you can use these techniques to extend the objects other people defined, including those already built into PowerShell.

In addition, understanding the use of PSCustomObject will give you a better understanding of the way classes work.

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.

Second, be on the lookout for the backtick ` , PowerShell’s line continuation character, at the end of many lines in the code samples. 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.

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.

Code to Generate Our PSCustomObject

For these demos, I’m going to wrap the creation of our objects within a function. This is a common technique which allows us to create multiple objects based on a single set of code. Note this isn’t required, you could use these techniques anywhere in your code. I just find placing it in functions makes for greater reuse.

If you need a refresher on PowerShell functions, I’ll refer you back to my posts on functions: Fun With PowerShell Basic Functions; Fun With PowerShell Advanced Functions; and Fun With PowerShell Pipelined Functions.

Let’s take a look at our first example, then break down each line.

function Create-Object ($Schema, $Table, $Comment)
{
  # Build a hash table with the properties
  $properties = [ordered]@{ Schema = $Schema
                            Table = $Table
                            Comment = $Comment
                          }

  # Start by creating an object of type PSObject
  $object = New-Object –TypeName PSObject `
                       -Property $properties

  # Return the newly created object
  return $object
}

Our first line, obviously, defines our basic function. For this example I will be creating an object that holds the schema and table names for a database. It also will allow for a comment, so these are the three parameters that are passed in.

To add a list of properties to our object, we need to use a hash table. I define the hash table with three properties, Schema, Table, and Comment, and assign the parameter variables we passed in for their respective values. And yes, I do have a post on hash tables if you wish to know more about them, Fun With PowerShell Hash Tables.

Next is where the magic occurs. I call the cmdlet New-Object. For its TypeName parameter I use the value of PSObject. This will create a variable of type PSCustomObject. I then pass in my hash table name for the Property parameter.

This is assigned to the variable $object. In the final line I return that value to the calling code.

Before someone points it out, yes I could have made the last line of the function simply New-Object –TypeName PSObject -Property $properties and not assigned it to a variable. As I explain in my previously mentioned posts on functions, not consuming the output within the function returns the value to the code that called it.

Assigning to a value within my function, then returning that value, gives me some additional flexibility. Primarily I could use the Write-Verbose and Write-Debug statements to echo additional debugging information back to the developer (or user). It also allows for easier integration with testing tools, such as Pester.

For more info on Write-Verbose and Write-Debug, see my posts Fun With PowerShell Write-Verbose and Fun With PowerShell Write-Debug.

Creating Our Custom Object

Now that we have the function created, we can call it to create our custom object. We’ll then display its properties.

$myObject = Create-Object -Schema 'MySchema' `
                          -Table 'MyTable' `
                          -Comment 'MyComment'

# Display all properties
$myObject

Result:

Schema   Table   Comment
------   -----   -------
MySchema MyTable MyComment

As you can see, simply running the name of our variable produces a table. Across the top are the names of our properties, below it are the values we passed into the function to use as values.

If we want to prove to ourselves this is indeed a PSCustomObject, we can use the GetType method.

$myObject.GetType()

Result:

IsPublic IsSerial Name            BaseType
-------- -------- ----            --------
True     False    PSCustomObject  System.Object

As you can see in the Name column, it is indeed of type PSCustomObject!

Like any object, we can assign new values by referencing the individual properties.

$myObject.Schema = 'New Schema'
$myObject.Comment = 'New Comment'
$myObject

Result:

Schema     Table   Comment
------     -----   -------
New Schema MyTable New Comment

In the output, you can see the values for Schema and Comment were updated. The original value for the Table property remained unchanged.

Adding Properties One At A Time

There is an alternate method we can use to create a custom object. We can create an empty object, then use the Add-Member cmdlet to add each property individually.

Let’s rewrite our function to use this methodology.

function Create-Object ($Schema, $Table, $Comment)
{
  # Start by creating an object of type PSObject
  $object = New-Object –TypeName PSObject

  # Add-Member by passing in input object
  Add-Member -InputObject $object `
             –MemberType NoteProperty `
             –Name Schema `
             –Value $Schema

  # Alternate syntax, pipe the object as an input to Add-Member
  $object | Add-Member –MemberType NoteProperty `
                       –Name Table `
                       –Value $Table

  $object | Add-Member -MemberType NoteProperty `
                       -Name Comment `
                       -Value $Comment

  return $object
}

The function declaration is the same as in our first example. We then create an empty object through the line $object = New-Object –TypeName PSObject. This object now exists, but has none of our custom properties. Yet!

Now we are going to call the Add-Member cmdlet. Add-Member allows us to add new properties and methods to an existing object.

The first parameter, InputObject, is used to indicate what object we want to work with.

The next parameter is MemberType. There are a variety of types we can add to a custom object. In this case we want to add a text property, so the correct value to use is NoteProperty. We’ll see examples of other member types as we progress through this series.

The next two parameters are pretty self explanatory. The Name is what we want to call this property, and Value is the value we want it to have.

We then move on to add the Table property. In this example I wanted to show the alternative format for using Add-Member. You can take the object you want to add a member to, and pipe it into the Add-Member cmdlet. I’ve done this here for the Table property, as well as for the final property Comment.

Using this function has identical results as the previous example.

$myObject = Create-Object -Schema 'MySchema' `
                          -Table 'MyTable' `
                          -Comment 'MyComment'
$myObject

Result:

Schema   Table   Comment
------   -----   -------
MySchema MyTable MyComment

So why use Add-Member? Clearly the first example where we used a hash table to declare our property list was more compact.

Think about what we did here. We added new properties to an existing object! In this case it was a custom object we created. but this could be any PowerShell object. For example, we could have a list of file system objects returned to us by the Get-ChildItem cmdlet. Using Add-Member we have the ability to add new properties (and methods) to those objects.

We’ll see an example of this very thing in a future blog post, but for now let’s move on to the final section in today’s post.

Creating Property Aliases

If you’ve been in IT for any length of time, you’ve probably encountered the situation where two different groups refer to the same property by two different names. In our example, let’s say the DBA’s refer to the comment property as Comment. They would like to use that property name when they use your script.

Your software developers though don’t think of this as the comment property, instead they call it Description. They complain that having to use the property name "Comment" is causing a lot of coding errors.

This is one of those rare times we can make everyone happy, and we do so through the use of a property alias.

We’ll start with the same $object variable we left off with in the previous example. We’ll then use Add-Member to add a new alias.

Add-Member -InputObject $myObject `
           -MemberType AliasProperty `
           -Name 'Description' `
           -Value 'Comment' `
           -PassThru

Result:

Schema     Table   Comment     Description
------     -----   -------     -----------
New Schema MyTable New Comment New Comment

The first thing to note is the MemberType. Instead of a NoteProperty, we are using the type AliasProperty. This will let the Add-Member cmdlet know we are simply adding an alternate name for an existing property.

The Name parameter is the name for the alias. The Value is the name of the already existing property.

You’ll also note I added a switch to Add-Member, PassThru. In our previous examples, leaving this off ran the code but displayed no output. If want to see the results though, you can add the PassThru switch and the new values will be displayed in the terminal, as you saw in the Result section above.

Our alias added, you can see a new column Description. The value under it is identical to the one for comment.

Let’s change the Description property and see what happens.

$myObject.Description = 'The Description'
$myObject

Result:

Schema   Table   Comment         Description
------   -----   -------         -----------
MySchema MyTable The Description The Description

As you can see, both Comment and Description hold the newly updated value. Your users can now use these property names interchangeably.

We can of course update our original function to add the alias at the time the object is created.

function Create-Object ($Schema, $Table, $Comment)
{
  # Build a hash table with the properties
  $properties = [ordered]@{ Schema = $Schema
                            Table = $Table
                            Comment = $Comment
                          }

  # Start by creating an object of type PSObject
  $object = New-Object –TypeName PSObject `
                       -Property $properties

  Add-Member -InputObject $object `
             -MemberType AliasProperty `
             -Name 'Description' `
             -Value 'Comment'

  # Return the newly created object
  return $object
}

$myObject = Create-Object -Schema 'MySchema' `
                          -Table 'MyTable' `
                          -Comment 'MyComment'
$myObject

Result:

Schema   Table   Comment   Description
------   -----   -------   -----------
MySchema MyTable MyComment MyComment

As you can see, the function generated an object that included our alias. In this example I also combined methods. I used a hash table to define our initial set of properties, then used Add-Member to add the alias. I could have also put the addition of the alias in the second version of the function, where each property was added one at a time.

Conclusion

In this post we learned how to create a basic object using PSCustomObject. We added some properties, and even created an alias for one.

Now you may be asking "what about methods? Object can have methods too!" And you would be correct. In the next post in the series we’ll see how to add custom methods to our object.

In future posts we’ll see how to create custom objects from bits of C# code. Then we’ll see how to add our own properties and methods to an existing object created by PowerShell.

We’ll then return to our discussion of PowerShell classes by looking at some advanced features of the built in PowerShell class type.

The demos in this series of blog posts was 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.

Fun with PowerShell Enum Flags

Fun with PowerShell Enum Flags

Introduction

In my last two posts, I introduced the concept of Enums in PowerShell, then got into some of the more advanced uses. In this post we’ll examine a special way to use an enum, known as a Flag.

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.

A Brief Refresher on Binary Math

In order to understand how flags work you need at least a basic understanding of binary math. In this section I’ll see if I can’t provide a short, simple refresher on the subject.

In my previous article, I mentioned that I am a ham radio operator, and am a member of multiple clubs. In a small club it’s not unusual to hold multiple offices, for example I’m both the secretary and the webmaster for one of the clubs, as well as a paid member. We can denote this by using a single variable to hold this information through the use of an enum flag.

A flag is a single variable that can be broken into its individual bits to indicate multiple values. In our example, we’ll use a flag to indicate a member’s paid status, their office, and if they hold more than one position in the club, all with a single variable.

Let’s say we have six people standing in a row. Each person has a sign, the first reads "paid", the rest have the names of club offices.

When a member walks into a room, people hold up signs that indicate the person’s status in the club, while the others leave their signs face down. When the Vice President walks in, the paid sign is raised up, as is the Vice President sign. We then take a photograph to capture this information in a single place.

I happen to be both Secretary and Webmaster of my club, as well as a paid member, so in my case three signs would go up and be captured in a photo. If we happen to have a visitor to the club, none of the signs will be raised, and a photo will record that.

Bit flags work the same way. Each sign is a bit, and the photo corresponds to the variable that holds all the bits.

Let’s say we have a 32 bit integer. If all 32 of the bits are set to a 0, then the value of that integer will be 0.

If the bit in position one is set to 1, and all of the other bits are 0, it indicates the value of the variable is 1.

In the second bit position, if the value is set to 1 and all other bits set to 0, the integer value is 2. If both bits one and two are set to 1, the integer value will be 3, and so on.

This chart of binary numbers and their decimal counterparts may help clarify.

Binary Decimal
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 10

These are just the first few as an example, you could continue this chart into the trillions of values if not higher.

Should you need a further refresher on binary numbers, I’d suggest the Binary Number article on Wikipedia as a good guide. It’s important to understand binary values in order to fully understand how flags work.

Enum Flags

Let’s create our own enum flag to hold the status of club members. You declare an enum as a flag by placing the [Flags()] modifier in front of the enum declaration, as you’ll see below. Note that the values must correspond to the integer value if a bit is set. The Wikipedia article includes a nice chart that shows a decimal number and what that number looks like in binary.

[Flags()] enum MemberStatus
{
  Paid = 1
  President = 2
  VicePresident = 4
  Secretary = 8
  Treasurer = 16
  Webmaster = 32
}

I could add more to this list if needed, using the value of 64 for the next member status, then 128, then 256, and so on.

Now lets represent a member status in a variable to show a member is the Vice President, and is also a paid member. To do so, we simply add the various statuses together.

$memStatus = [MemberStatus]::Paid + [MemberStatus]::VicePresident

$memStatus

Result:

Paid, VicePresident

What’s nice about using an enum flag is that when we display the variable PowerShell converts the flags back into the members from the enum.

We could also simply assign the total number. In this case, Paid (value of 1), plus Vice President (value 4), adds up to 5.

$memStatus = [MemberStatus] 5
$memStatus

Result:

Paid, VicePresident

Finally, if we want to display the numeric value behind our flag, we can cast it as an int.

[int]$memStatus

Result:

5

Is the Flag Set? HasFlag to the Rescue!

Often you will want to see if a specific flag is set, for example we want to see if a member is paid. Now, if the paid status is the only flag set, it’s easy, just use $someVariable -eq [MemberStatus]::Paid.

It gets much more complex if a variable has multiple flags set. Fortunately, enums have a method built in called HasFlag you can use to test with.

First, let’s load a variable with several flags from our MemberStatus enum.

$memStatus = [MemberStatus]::Webmaster + [MemberStatus]::Secretary + [MemberStatus]::Paid

$memStatus

Result:

Paid, Secretary, Webmaster

So now we’ve got our $memStatus variable loaded with multiple statuses. Also note that even though we added the status in reverse order, they are always returned in ascending order from the enum declaration.

Now we want to know if our secretary / webmaster has paid their dues for the year. To do so, we’ll call the HasFlag method of our variable, and pass in the status we wish to check.

$memStatus.HasFlag([MemberStatus]::Paid)

Result:

True

The GetHashCode Method

So far, when we’ve wanted to see the value of our enum derived variable, we’ve used [int] to cast the variable in integer form.

$memStatus = [MemberStatus]::Webmaster + [MemberStatus]::Secretary + [MemberStatus]::Paid

[int]$memStatus

Result:

41

This shortcut works, and is something I’ve seen in many blog posts and examples. However, there is a method that is more clear in terms of code self-documentation. Like using [int], it will return an unsigned, 32 bit integer: GetHashCode.

$memStatus = [MemberStatus]::Webmaster + [MemberStatus]::Secretary + [MemberStatus]::Paid

$memStatus.GetHashCode()

Result:

41

Both methods work, but in my opinion GetHashCode is clearer in terms of intention, especially to someone unfamiliar with enum flags. Whichever route you go I suggest being consistent throughout your code.

Conclusion

This article focused on the use of enums as flags. While it is not something I use frequently, enum flags can be extremely useful when an item can have multiple states simultaneously. Our club member status is one such example, another is file attributes. A file could have both the hidden and compressed attributes.

Enum flags can reduce the size of your data for an item. Rather than having six individual variables for the six member statuses, a single variable can hold them all. This reduction in the size of your data can be even more valuable when that data is being stored in a database or file.

The demos in this series of blog posts were derived 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.

More Fun with PowerShell Enums

Introduction

In a previous post, Fun with PowerShell Enums I introduced the concept of Enums.

In this post we’ll dive deeper into enums, taking a look at more of its properties a well as other ways to use enums.

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.

Enums for Code Clarity

One major way enums can be used is to clarify your code. In my previous post on enums I mentioned I was a ham radio operator. The clubs I belong to meet on alternate Thursday nights. Let’s say I wrote a small PowerShell function to let me know if tonight is a ham club meeting.

Into that function I need to pass one parameter, a number that indicates the day of the week. If 0 is Sunday, and 6 Saturday, the number 4 represents a Thursday.

function IsItHamClubNight($Day)
{
  if ($Day -eq 4)
  { Write-Host "Yay! It's ham club night" }
  else 
  { Write-Host "Sorry, just a boring night" }
}

When I call this function, I have to know what number to use.

$day = 4
IsItHamClubNight $day

Result:

Yay! It's ham club night

Obviously it would be easier to pass in the name of the day of the week rather than a number. But this function is now heavily embedded in your organization, changing it would require a large effort.

By using an enum, we can provide the ability to use a human readable name, without the need to rewrite our function.

Enum DaysOfWeek
{
  Sunday = 0
  Monday = 1
  Tuesday = 2
  Wednesday = 3
  Thursday = 4
  Friday = 5
  Saturday = 6
}

Enums allow us to assign a value to each label. Here we made Sunday 0, and so on, but we can use any integer value. Now we can assign one of the enums to a variable and pass that into our function.

$day = [DaysOfWeek]::Thursday
IsItHamClubNight $day

Result:

Yay! It's ham club night

Even better, we can skip the use of a variable.

IsItHamClubNight ([DayOfWeek]::Thursday)

Which gives the same result. Now users of your function don’t have to remember which number represents Thursday, they can simply use the name of our enum followed by the day of the week. All of this without the need to modify our IsItHamClubNight function!

Getting the Enum Values

Let’s say you know the enum you want to use is DaysOfWeek, but you can’t quite recall the various day names. Was it Monday, or the short abbreviation Mon? Or maybe you just want the full list so you can iterate over them.

The Enum type has a method, GetEnumNames. It can be used to retrieve the members of the enum.

[DaysOfWeek].GetEnumNames()

Result:

Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday

It actually returns a collection so you can use it to iterate over the members, as in a foreach loop.

foreach( $enumValue in [DaysOfWeek].GetEnumNames() )
{
  Write-Host "Enum Value is $enumValue"
}

Result:

Enum Value is Sunday
Enum Value is Monday
Enum Value is Tuesday
Enum Value is Wednesday
Enum Value is Thursday
Enum Value is Friday
Enum Value is Saturday

Alternatively you can pipe it, for example into a ForEach-Object.

[DaysOfWeek].GetEnumNames() |
  ForEach-Object { "{0} {1}" -f $_, [int]([DaysOfWeek]::$_) }

Result:

Sunday 0
Monday 1
Tuesday 2
Wednesday 3
Thursday 4
Friday 5
Saturday 6

This looks a bit cryptic so let me break it down. The "{0} {1}" -f indicates we want to create a formatted string. The {0} and {1} are placeholders. After the -f is a list of values. The first value will go into the {0}, the second into the {1}.

The next thing you see is $_. This is simply a PowerShell shortcut for "the current object coming through the pipeline". From the enum, Sunday will be first, then Monday, and so on.

Next you see [int]([DaysOfWeek]::$_). The [int] is used to convert what comes after it into an integer value. Next, we access the DayOfWeek enum, and give it the current object.

As a result, the output displays both the name from the enum, as well as the value associated with it.

If you want to learn more about string formatting, I’ll refer you to my post Fun With PowerShell String Formatting.

Enums with Duplicate Values

It is possible to assign the same numeric value to multiple items in an enum. For each position in our radio club, we want to indicate their level. President and Vice President are at the top, with Secretary and Treasurer in the second tier. Finally there are some appointed positions that are important, but not the top of the chain.

Here’s how this might be expressed in an enum.

Enum ClubPositions
{
  President = 1
  VicePresident = 1
  Secretary = 2
  Treasurer = 2
  Webmaster = 3
  Greeter = 3
  SnackBringer = 3
}

We can do comparisons between our various offices and their associated numeric value.

[ClubPositions]::President -eq 1
[ClubPositions]::VicePresident -eq 1

Result:

True
True

You can even compare two enums to each other.

[ClubPositions]::President -eq [ClubPositions]::VicePresident

Result:

True

Remember the GetEnumNames method we looked at a moment ago? This works as well.

[ClubPositions].GetEnumNames()

Result:

President
VicePresident
Secretary
Treasurer
Webmaster
Greeter
SnackBringer

There is one other method very similar to GetEnumNames, GetEnumValues. It doesn’t work quite like you’d think though.

First, let’s use it with our DaysOfWeek enum.

[DaysOfWeek].GetEnumValues()

Result:

Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday

As you can see, there’s no real difference compared to GetEnumNames. But now let’s run it for the ClubPositions enum.

[ClubPositions].GetEnumValues()

Result:

VicePresident
VicePresident
Treasurer
Treasurer
Greeter
Greeter
Greeter

In the second example it went through the enum, and only returned one text value for each integer. This is why we only see one entry for each numeric value.

It actually does the same thing with the DaysOfWeek enum, but because we only used each integer value once, only one label for each value was returned.

Conclusion

Using enums to aid with code clarity was the first item in this blog post. We then saw how to assign values to the individual members of an enum, as well as how to iterate over the members of an enum.

In the next article in this series, we’ll look at the concept of using enums as bit flags for when you need to save multiple states for a single item.

The demos in this series of blog posts were derived 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.