Patch My PC / Blog

Write Better PowerShell – You’re Out of Excuses

by | Dec 13, 2023 | Blog

PowerShell has, for many admins, become an indispensable tool. Its versatility, and, dare I say, “power”, have made it a go-to tool for a wide range of tasks around Windows management. Over the course of the past year, PowerShell’s adoption has continued to increase. With the arrival of advanced tools like GitHub CoPilot, Chat GPT, and more, there are dozens of new ways to optimize the writing of a PowerShell script. Let’s take a look at the common ways we can use these new tools to improve our everyday PowerShell scripts, and, because nothing is perfect, some security concerns we should have as a result of these emerging technologies.

GitHub CoPilot

GitHub CoPilot is one of many tools you can use to help streamline some of the repetitive tasks found in writing and documenting PowerShell scripts. While GitHub does have a monthly cost attached, if you find yourself writing PowerShell scripts regularly, then it really is worth the small fee.

If you want to learn more about how to acquire and configure GitHub CoPilot, you can read more here.

Assuming you’ve moved away from the PowerShell ISE and use a more standard IDE like VSCode, you should be pretty familiar with the process of adding an extension. Once you’ve added the CoPilot extension, you can ask it for help anywhere in your code using the hotkey “ctrl+I”. But don’t worry: if you forget these things easily, CoPilot will be there to remind you of the rules.

Press Ctrl+I to ask copilot to help you out of a jam

So that’s great, but what are some practical uses for it?

Commenting Scripts So You Don’t Have To

One of the more onerous tasks in writing PowerShell scripts is maintaining accurate comments. Fortunately, with the introduction of GitHub CoPilot, your life just got a lot easier.

As an example, watch how I take one of my favorite useless PowerShell functions and have the code commented for easier readability:

So that’s all well and good, but it’s still a pretty useless PowerShell function. Can it do something more complicated? Of course! Here’s an example:

Learning About New Code

That’s not all, though. If you’re new to Windows PowerShell, GitHub CoPilot can also help you understand what the code you’ve downloaded actually does. Let’s take a look at something I found on the Patch My PC community GitHub:

Behold: CoPilot explaining what this code does

Here, you can see that after copying the code into VSCode, I selected a few lines and asked CoPilot to explain; the result was a brief synopsis that tells me exactly what that code does. This can help me gain confidence when parsing out functions or scripts I stumble upon online, especially if it’s in a scripting language I’m unfamiliar with.

Writing Boring Code

If you’ve already mastered the entire PowerShell language, you may be thinking, “where is the value in this for me?”. Well, if you value time-and I’m betting you do since you probably automate administrative tasks for a living-fear not! CoPilot can help by saving your fingers from writing repetitive code (e.g., hash tables).

That’s neat code, right? But does it work?

Hash table value example

Looks good to me!

How About Unit Tests?

The more complicated your custom PowerShell commands get, the more likely you are to introduce a concept called unit tests. However, writing unit tests is, to put it lightly, a time-consuming and confusing process. It’s so difficult that most people only familiar with the PowerShell ISE are not comfortable with it. Don’t worry, though: if you’re one of those people, CoPilot can help with this too.

You can quickly test this by using ctrl+I to start the prompt (as discussed above), then simply ask it to write a unit test for you!

Example of unit test creation

If you already have the Pester PowerShell module installed, you can select the three dots in the top right corner of the code snippet to insert the code into a “new file”. From there, you can save it with the appropriate file name. For my purposes, my “appropriate file name” is “get-dadjoke.tests.ps1”. I can then run the call invoke-pester from the directory with both files, and presto! I now have unit tests.

When I write unit tests, they never pass on the first attempt...

Cool, But What About ChatGPT?

AI and ChatGPT have been revolutionizing how we use and learn programming languages. If you were to ask me, “what do I need to know about PowerShell?”, I would tell you there are only three things you need to memorize.

  • Get-Help

  • Get-Command

  • Get-Member

If you memorize these three PowerShell cmdlets, you can eventually teach yourself to fish. But that’s just me, a mere human. What does ChatGPT think about this?

If I input the prompt “Give me a common set of PowerShell Cmdlets everyone should know” into ChatGPT, I get this:

PowerShell cmdlet cheat sheet from ChatGPT

Turns out, the robots agree with me on the most important PowerShell cmdlets you can learn. Who would have thought?

So… Can ChatGPT Just Do It for Me, Then?

Well, if we give it the same prompt as we did in GitHub CoPilot, it might give us a good answer along with some more context. However, because ChatGPT’s nature is language and context focused first, it may take some liberties you aren’t expecting.

Example of asking for a hash table.

However, these new innovations don’t come without a cost. While the internet enabled us to all connect to each other, it turns out not all of us have the best intentions in mind. Just as you might use this tool to simplify your coding life, tools like this will be used by threat actors to develop better PowerShell scripts faster as well. So, what should you be aware of, that way you don’t accidentally run malicious code in your environment?

Before Running PowerShell Scripts

When you’re getting ready to run a PowerShell script you didn’t create, there are several things to keep in mind. Here’s a list of things I commonly look for below:

  • Community Reputation

    • Was the code written by someone I know?

    • Are lots of people already using the code?

  • Code Signing

    • Was the code signed using a public code-signing tool?

  • Commented Code

    • Is the code commented so I can clearly understand what it’s doing?

  • Code Storage – website or repo-based

    • Is the code stored in a repo so I can view a change log, or is the code on a website that could be influenced by others?

  • Does the code make changes, or is it read-only?

  • Does the code access anything sensitive?

  • Does the code utilize remote commands or encoded commands?

PowerShell Trust

Trust is a powerful word in the world of scripting. It takes time and continuous work to build in our industry. However, anyone can upload code to GitHub or the PowerShell Gallery. So, what are indicators of a trustworthy piece of code?

One of the first “at a glance” indicators of how good or trusted a PowerShell script might be is often based on metrics. Take, for example, the commonly used PowerShell Application Deployment Toolkit or PSADT. If you look at the code repository on GitHub, you’ll quickly see the tool is incredibly popular.

Example of a popular PowerShell tool in the industry.

PowerShell Code Signing

PowerShell is shipped as a part of the Windows operating system, and, if configured as such, it allows administrators to execute remote commands. It’s also frequently seen as a part of an attacker’s toolkit. What’s less common, though, is for attackers to sign their code using publicly trusted certificates, as these certificates are difficult to acquire and maintain. By default, Microsoft sets the default execution policy to be restricted on Windows computers. This commonly leads system administrators, when they first launch PowerShell, to run:

Set-ExecutionPoliy -ExecutionPolicy Bypass

This allows a system to bypass its execution policy for all PowerShell scripts run on the machine. While this might be a great way to test code, it may not be the best default to run with.

Due to the nature of how challenging and expensive it is to acquire a code signing certificate, most public authors do not sign their code. Unfortunately, this process will only get more difficult with recent standard changes for public certificate authorities around hardware security modules (HSM). However, some authors do use these certificates, as it ensures their provided PowerShell script has not been modified by others.

If you’re unsure what a signed PowerShell script looks like, look at the bottom of a script file for something that looks like this:

# SIG # Begin signature block

If you see this with a large string of text below it, that is a good indicator the code was signed. That being said, a signature does not mean you should trust the code by default. To truly trust the PowerShell script, you should investigate the certificate it was signed with, who issued the certificate, and validate you trust the author and signer of the code. Otherwise, you could end up in a situation like this:

I Made This | Know Your Meme

Okay, So What About AI?

You may be wondering if you can use AI to determine if written code is secure. As an example, I tried it with a PowerShell module I wrote several years ago called CMOperations. This is something that uses PowerShell remoting to call Windows Management Instrumentation (WMI) actions on a remote Configuration Manager client. Unfortunately, the results weren’t terribly helpful.

However, it does line up with some of the previosly mentioned tips!

Out of curiosity, I tried this again with different programming languages (specifically, Java and GO). I found that when I used some Java from a repository that is purposefully used as a showcase insecure code, I got a very different result.

In some cases, CoPilot can see when a piece of code is dangerous.

When I tested against a GO package, I wrote code for downloading a CSV file in a simple tool I use regularly. I was promptly yelled at for not validating my outputs.

Looks like I need to go make a pull request or two on this

End result? The security validation is still hit or miss and very contextual.

Now I’m Scared… Will The Robots Really Replace Me?

If you’ve already learned how to use PowerShell, I think you’re safe. If anything, I hope this post has inspired you to dust off some of those old PowerShell scripts and run them through the various AI tools out there so you can share them with the community.

All of this being said, if you’re still using the command prompt, don’t worry; you’ll be fine. But with all of these tools at your disposal, you should have an easier time making the migration from the command line to the PowerShell console, especially when you can just ask for a simple reference sheet when you’re lost.

command line to PowerShell reference sheet