Using PowerShell Forms for Repetitive (Work) Tasks

Ed Rutherford - Sep 12 '23 - - Dev Community

TL;DR

Response Generator



About 🗃

As IT Support Professionals, we are constantly sending correspondance to various clients and end users Very rarely do we help only one or two customer groups each day, and because of that fact, it's normal for us to have to create tailored response messages with contact info specific to that client.


This repository is meant to supplement the Medium article: "Using PowerShell Forms for Repetitive Tasks"


Getting Started 🖥

The utility was designed as straightforward, custom module meant to be easily imported into a powershell session and invoked by the user. In order for this module to be imported, it's important to locate the designated system path to place this project's inner directory in. The easiest way to find that location is by opening a powershell terminal and typing the following:

PS > $env:
Enter fullscreen mode Exit fullscreen mode

PowerShell...Seriously?

Yes, really! I know that many of the excellent articles many of us read each day tend to follow the more flashy, exciting languages that dominate headlines as a result of their growing popularity and expansive use-cases. While that's all well and good, many of us that may work in IT aren't fortunate enough to use many of these new fancy releases in our day to day roles...usually because of this thing called Access Control Lists and Group Policy Objects (that's right, good ol' Active Directory management).
There is a way, however, that many in IT are able to utilize automation and scripting that in most situations is allowed by GPO (depending on your role of course), and that's by utilizing Window's very own powerhouse scripting language, PowerShell!

Quick Recap

For those who may not be all that familiar with what PowerShell is, and just how powerful it can be for developers, here's a brief intro:

PowerShell is a modern command shell that includes the best features of other popular shells. Unlike most shells that only accept and return text, PowerShell accepts and returns .NET objects. The shell includes the following features:

  • Robust command-line history
  • Tab completion and command prediction (See about_PSReadLine)
  • Supports command and parameter aliases
  • Pipeline for chaining commands
  • In-console help system, similar to Unix man pages

At its inception, PowerShell was originally developed on and designed to be a better and more feature-rich shell experience for Windows users and system administrators. As the project continued to grow and blossom, a decision was made by Microsoft to develop a cross-platform version of PowerShell and make it open source for the broader community to contribute to...and thus, PowerShell Core was born!

Sometimes this can be slightly confusing to new programmers that are trying to understand the differences between the PowerShell they see built in to their Windows device, and PS Core installs that they see online. It all comes down to the version of .NET that they run on:

Windows PowerShell 5.1 is built on top of the .NET Framework v4.5. With the release of PowerShell 6.0, PowerShell became an open source project built on .NET Core 2.0. Moving from the .NET Framework to .NET Core allowed PowerShell to become a cross-platform solution.

The project outlined in this article is solely dependent on Windows PowerShell. It will not function if ran on any version of PS Core, regardless of whether you're running it on Windows, macOS, or Linux. If you're wondering why that is exactly, it's due to the fact that the Windows Forms API that we will use is only part of the native .NET Framework included in all recent versions of Windows.

Harness the Strength of PowerShell

The goal of our project is pretty straightforward:

  • Streamline and automate the generation of response emails for customers
  • Build a custom PowerShell module to incorporate this functionality
  • Create a simple graphical interface using the Forms API to interact with the module

Because this project is merely a starting point for future applications, its structure will be pretty mundane. Even so, it demonstrates a great way for organizing any future module projects.

We're going to put together a relatively simple ResponseGenerator UI using .NET Forms via PowerShell. It provides a means of quick email response generation depending on the client ID chosen by the user. The following will be its structure:

.
├── ResponseCore.ps1
├── ResponseForm.ps1
├── ResponseGenerator.psd1
├── ResponseGenerator.psm1
└── assets
└── coding.ico

Building A Module

As I mentioned previously, the best approach for building our utility is to create a dedicated module for it. PowerShell modules are similar in structure to Python package directories and modules in other languages, so they should feel relatively familiar to many of you.

At their simplest, new modules can be made up of a single file, though in most scenarios they will consist of several files located in a central root directory. One very important factor to keep in mind when building a new module:

The root directory should be named exactly the same as the module file itself.

To start out, we’ll go ahead and create the module directory and primary declaration file for our utility by running the following:

PS > New-Item -Type Directory -Path "ResponseGenerator"
PS > Set-Location -Path ./ResponseGenerator && New-Item -Type File -Path "ResponseGenerator.psm1"
Enter fullscreen mode Exit fullscreen mode

You may have noticed already that the extension of our newly created file is .psm1. These particular files are the “core” of a PowerShell module, in our case, ResponseGenerator.

It will be the primary entry point of our utility, but will only contain a handful of code. The primary body of our module code will be spread out between two other files, which we will create right now:

PS > New-Item -Type File -Path "ResponseForm.ps1" && New-Item -Type File -Path "ResponseCore.ps1"
Enter fullscreen mode Exit fullscreen mode

NOTE: Don’t worry about creating the psd1 file just yet, we'll get to it soon enough!

Creating the Form

Now that we’ve got our core files in place, we can start adding the code needed to generate a nice looking graphical utility!

The following Gist shows how we declare our callback functions for specific button presses, as well as creating a ComboBox for storing the entire list of contacts to choose from, and a few quick response button shortcuts:

Adding the Rest

The only thing left to do for our module at this point is to finish adding the remaining core functions and contact info arrays to the other file in our project, ResponseCore.ps1:

Wrapping Things Up

Now that all of our utility code is written, the last thing to do to finish our PowerShell module is creating a .psd1 Module Manifest. This file allows developers to add fine-grained details about their module, as well as limit which functions are exported for use in the command line.

PowerShell provides a handy cmdlet (pronounced command-let) to generate this for us, which we can pass various arguments to in order to overwrite the default values for important fields:

New-ModuleManifest `
-Path "$PWD\ResponseGenerator.psd1" `
-Author "dedSyn4ps3" `
-RootModule ResponseGenerator.psm1 `
-Description "This module helps generate response messages"
Enter fullscreen mode Exit fullscreen mode

This will create the last piece of our utility! There is a line of code in this manifest that I recommend making a slight adjustment to, however. It’s good practice to not export every single function declared in your module, and by default the manifest generator does just that.

Simply scroll down a ways until you see the field declaring FunctionsToExport and update it with the primary entry point to our utility, which we declared previously in the module file:

FunctionsToExport = 'Invoke-ResponseGenerator'
Enter fullscreen mode Exit fullscreen mode

Run It!

And with that, you’ve successfully put together a PowerShell module that can be imported and run from the command line! When it comes to custom modules, it’s extremely convenient to be able to call it from our shell without having to specify the actual location path of the module directory.

In order to import and run our utility by name, it’s imperative that the module directory be placed in the designated location for all PowerShell modules for your user! This may very from system to system, so to be sure, simply type the following in your shell to find out the exact location to place the new module:

PS > $env:PSModulePath
Enter fullscreen mode Exit fullscreen mode

With the module directory placed where it needs to go, importing and calling the main entry point is as simple as invoking any other command from our shell:

# import the custom module
PS > Import-Module ResponseGenerator

# start the utility by calling it's invoke method
PS > Invoke-ResponseGenerator
Enter fullscreen mode Exit fullscreen mode

Tip

The End Result

Project Code

The entire project repository can be found on Github, and I highly encourage those looking for a great way to kickstart their PowerShell automation to check it out!

Also be sure to give me a like if you found this article interesting, and be sure to subscribe for upcoming articles! And if you're on Medium as well, check me out there for early viewing! ✨

Response Generator


About 🗃

As IT Support Professionals, we are constantly sending correspondance to various clients and end users Very rarely do we help only one or two customer groups each day, and because of that fact, it's normal for us to have to create tailored response messages with contact info specific to that client.


This repository is meant to supplement the Medium article: "Using PowerShell Forms for Repetitive Tasks"


Getting Started 🖥

The utility was designed as straightforward, custom module meant to be easily imported into a powershell session and invoked by the user. In order for this module to be imported, it's important to locate the designated system path to place this project's inner directory in. The easiest way to find that location is by opening a powershell terminal and typing the following:

PS > $env:
Enter fullscreen mode Exit fullscreen mode
. . . . . . . .