Write PowerShell Modules, not Scripts

When you think of PowerShell, is writing a PowerShell “script” one of the first things you think of? If so, I implore you to read on and think about the next time you write any PowerShell code. During the rest of this article, I’ll attempt to describe a gap I’ve identified in the PowerShell ecosystem, specifically a lack of PowerShell modules, and what we can do to rectify it.

tl;dr: Every language and framework has gaps. You can help fill those gaps. Write robust code, and share it with the world.

Examining Alternatives

Look at other mainstream application programming languages, such as Java, C# / .NET, Node.js, Ruby, and Python. All of these have relatively comprehensive sets of modules (synonyms: Ruby gems / packages / libraries) that exist in a centralized, publicly accessible repository, much like the PowerShell Gallery. While PowerShell provides an extensive set of commands built-in / “out of box,” there are quite a few common tasks that require some Googling or doing a bit of your own investigative work.

Personally, I find this type of investigative work fun and enjoyable, as it significantly increases my understanding of the language and framework I’m writing. Not everyone is in that same boat, however. Some people just want to “get the job done,” and move on to their next task. We need people like that in the world, who produce end-to-end solutions. There’s also a place for people who support those end-to-end developers.

Break Apart Your Scripts

Before moving too far ahead, let’s discuss the concept of writing scripts vs. writing modules.

While it might “feel” very satisfying to write a PowerShell script that’s a couple thousand lines long, feelings aren’t always the best guidance. Sure, you wrote a lot of code, and perhaps it accomplishes a very specific purpose that you set out to perform. However, what are the chances that someone else would be able to read your code and make any sense of what it’s doing? What are the chances that you’ll be able to take some of that code and reuse it in a different project?

The longer that your single script file is, the probability of answering the above questions positively diminishes rapidly.

Instead of writing long scripts, think about your scripts as individual components. Any time that you perform a task in PowerShell code, think about how that could be packaged up as a generic function that anyone in the world, at any company, on any project, could reuse. Keep company-specific and environment-specific data out of your code, and instead use environment variables or configuration files to “drive” your code.

Challenge yourself to limit a function to less than 20 lines of actual code. Think about the function inputs and outputs, and how you’d interact with it if someone else had written it.

  • When you call the function, what input does it need in order to execute properly?
  • After the function executes, what do you expect to receive as output from it?
  • Is the function doing “too much?” Can it be broken into smaller components?

Once you’ve broken apart your code into functions, package them up as PowerShell modules. Again, imagine that someone else had created the modules.

  • What would you expect the module names to be?
  • How would you expect that the functions in the module would be named?
  • What inputs and outputs would you expect of the functions?

Trust me, if you start thinking about writing your code as modules, rather than writing one-off scripts, you will unlock serious potential for your software development future. Objectively speaking, the following will be true:

  • Your PowerShell code will be reusable, by yourself and others.
  • Your PowerShell code will be easier to debug.
  • Your PowerShell knowledge will transition more easily to other software languages, and vice versa.
  • It will be easier to search for and locate modules that are relevant to your project.
  • You’ll be able to logically assemble solutions, rather than hack them together.

What’s Boilerplate Code?

Earlier, we talked about “end-to-end solution developers.”

These developers tend to rely on a wide variety of existing libraries in order to accomplish their goals. Without access to these libraries, solution developers end up writing their own “boilerplate” code. The idea of writing “boilerplate” code is, generally speaking, bad; it’s the idea that  someone else could ideally write the code once, and scale out across millions of other software developers. Of course, this presumes that the code was written robustly, accounts for all types of use cases, and is thoroughly tested. While a lot of code is subject to “code rot,” a piece of well-written code can actually not be maintained for a long time, and still hold its own.

The time that a developer spends writing boilerplate code, means that they’re not spending their time focusing on their business objectives. While it’s not realistic to expect a module to exist for every task, it’s reasonable to work, as a community, towards providing modules for many of the “low hanging fruit” scenarios.

An example of PowerShell boilerplate code would be encoding and decoding Base64. If you’ve used Base64 before, I highly doubt that you only found a single use case for it; you’ve probably used it for a few different projects. Unfortunately, PowerShell doesn’t provide Base64 encoding and decoding out of the box, but it’s incredibly easy to do with some calls into the .NET Framework.

Still, it would be nice if this functionality was wrapped up in a small, but very useful, PowerShell module. That way, you could simply import that module as a dependency for your project, use the functions / APIs inside it, and keep moving forward with your application objectives. Thankfully, someone just did that recently!

Plan Your Project

One of the things you can start doing immediately, to help you design and build robust PowerShell modules, is to “think like a user.” Instead of thinking about all the things that you could theoretically create, instead think about all of the things that you need to accomplish some goal. Don’t worry about whether or not those things actually exist, just put on your “project manager hat,” and plan out the journey from start to finish.

After identifying the requirements to get from your current state to your end state, go through and identify which areas need development, and which areas might already have a solution.

Write User Stories

One of the helpful exercises you can go through, to help identify gaps in your project plans, is to write user stories. User stories are essentially a collection of individual user statements that identify how an end user, or perhaps even a developer, interacts with a product. You really have to challenge yourself to think differently than you normally are accustomed to. You have to put yourself into an entirely different mindset, one that disconnects yourself from the implementation, and instead focuses on the user interaction.

Better yet, depending on what you’re creating, find someone else who may not have any technical background, to help you think through these things from a true user standpoint.

Given that, from a relative perspective, a software developer is a “user” of a library, you can come up with user stories similar to the following:

  • As a developer, I need to call a PowerShell function to encode and decode Base64.”
  • As a developer, I need a REST interface that runs PowerShell code on the back end.”
  • As a systems engineer, I need a simple PowerShell interface to manage AWS cloud resources.”

Start with more generic user stories, and get more specific when appropriate. Go through the exercise with other individuals, who can help refine the process. Alternatively, after writing your user stories, go to a friend and ask them for feedback.

Once you’ve identified how a user will interact with your product, you can start building solutions that match up to the user stories.

What Can I Do?

In the PowerShell world, there are quite a few existing gaps in boilerplate modules, code that people are probably rewriting on a regular basis. The lack of these modules means that developers writing PowerShell can’t firmly depend on the existence of the modules, and may not even bother searching for them. The more common, boilerplate modules that exist in the PowerShell Gallery, the more productive developers can be, by focusing on their business logic.

I’ve previously put out a call to action for developers to contribute more modules to the PowerShell Gallery, and we’ve seen improvement since then, but there’s still a lot more to do!

One way to approach this would be to immediately start looking at modules and frameworks that other, more mature languages offer, and identify those as gaps in the PowerShell Gallery. Another approach is to think about an interesting project, like home automation with PowerShell, or something crazy, like writing an Android app in PowerShell, and then follow the steps that we outlined above, to identify gaps.

Once you’ve identified gaps, you can fill them! Your unique contributions to the PowerShell Gallery, and any other open source projects, are a direct part of your industry experience, and a strongly relevant item on your resume.

Looking Forward

While we’ve touched on the topic of module gaps in the PowerShell Gallery, there’s still more to consider.

Another topic for discussion is the determination of how broad or miniscule a module should be. In the Node.js world, there are tons of small modules, but the Node Package Manager (NPM) has the mechanism to handle these complex dependency chains. Conversely, in the PowerShell world, we’re more used to having larger, comprehensive PowerShell modules.

What’s the best balance? Time and experience will tell.