This post was written as part of a series for Atera, the PSA and RMM product we use at Cage Data. The first post in the series can be found here.


In the first post you learned some basics about the PowerShell language. I hope that it tickled your fancy enough to have opened the PowerShell console on your PC, or launch the recently released PowerShell console built into Atera.

Now that you've gotten an overview of PowerShell, let's take a look at how to take it beyond what's built into the language with PoeerShell modules!

No programming language is complete without a means to modularize pieces of logic into digestible pieces. PowerShell Modules let you package scripts to share between your team.

While writing PowerShell as scripts is a great start, modules offer a great way to break down PowerShell code into reusable pieces. Writing a module is easy. For example, here's a module that adds on to the Write-Host command by prepending a timestamp to whatever you want to output:

<#
  .SYNOPSIS
  Appends a timestamp to text to write out to the console

  .PARAMETER Text
  Text to output to console

  .EXAMPLE
  Write-timestampedHost -Text "Hello World!"
  
  [2020-06-09T22:19:33] Hello World!
#>
function Write-TimestampedHost {
  param (
      [Parameter()]
      [string]
      $Text
  )

  Write-Host "[$(Get-Date -Format s)] $Text"
}

Export-ModuleMember -Function Write-TimestampedHost

That's all there is to writing your first module. Save the code above to a file named C:\Write-TimestampedHost.psm1 and then from the PowerShell window, you can use your knew module like so:

PS C:\> Import-Module C:\Write-TimestampedHost.psm1
PS C:\> Write-TimestampedHost -Text "Hello world!"
[2020-06-09T22:19:33] Hello world!

So what did we actually do? We've written a module that exports a single function. To start, lines 1-12 provide the documentation of our exported function. These lines are used by PowerShell to build the output when you run Get-Help Write-TimestampedHost -Detailed. Then, on lines 13-21, we actually have the logic of our function. Finally on line 23, we tell PowerShell which functions from our module we want to export. Only exported functions are available when you run the Import-Module command. This lets you have other functions which are only available inside of the module.

Rather than going into depth about writing your own modules, I strongly recommend reading Microsoft's documentation on How to Write a PowerShell Script Module, which goes beyond what we've done here into all of what you can do to write, package, and publish PowerShell modules.

So now that you've written your first module, it's time to start seeing what other people have written. The "central repository for sharing and acquiring PowerShell code" is the PowerShell Gallery, a repository hosted by Microsoft for developers, engineers, tinkerers, etc. to publish their PowerShell code to share with others. Once again, you can find a whole section on PowerShell docs for how to get started with the PowerShell Gallery, and the great thing is that Windows 10 includes everything you need to get started.

The PowerShell Gallery has tons of useful modules for scripting tasks you do every day. There are even modules to do things that you might not have thought possible. As an example, the DellBIOSProvider module lets you read and change BIOS settings from PowerShell, which is super handy for doing things like enabling Wake on LAN when the entire world needs to start working from home.

Security risks of using others' PowerShell code

Before we move on, it's important to note some risks to using open source code. Whenever you use someone else's code, it's important to make sure that it doesn't introduce any new security vulnerabilities to your environment. It's always a good idea to read through the code, which is often linked to from the PowerShell Gallery page, before installing it on client PCs and servers.

One of the other topics of conversation in a lot of other programming communities is to remember that, at the end of the day, you have no control over the PowerShell Gallery, which means, if it goes down for a few hours or days, or worse, if it goes away all together, can you still function?

While those two items are important to keep in mind, leveraging open source code is a great way to optimize your workflows and "stand on the shoulders of giants."

Putting it to work in Atera

Atera comes packed with tools to run PowerShell code against agents. Not only can you write and upload your own scripts, but the Shared Script Library is packed with over 100 scripts written by Atera and the community for you. As hinted above, let's look at a script to check if Wake on LAN is enabled on a PC:

# Get-DellWakeOnLAN.ps1
# Exit if the computer is not a Dell
$Manufacturer = (Get-WMIObject -Class win32_ComputerSystem).Manufacturer
if ($Manufacturer -notlike "*Dell*") {
	Write-Host "Computer is not a Dell."
    exit
}

# Check for Dell BIOS Provider module and install if missing
if (!(Get-Module -Name DellBIOSProvider)) {
	Install-Module -Name DellBIOSProvider -Force
}
# Import the Dell BIOS Provider module now that we know it's installed
Import-Module -Name DellBIOSProvider

# Use the DellBIOSProvider to get the BIOS Wake On LAN settings
$WOL = Get-Item -Path "DellSmBios:\PowerManagement\WakeOnLan" -ErrorAction SilentlyContinue

# Check if WoL is enabled or not
if ($WOL.currentValue -in "LanOnly", "WlanOnly", "LanWlan") {
	Write-Host "Wake On LAN enabled as $($WOL.currentValue)"
} else {
	Write-Host "Wake on LAN not enabled"
}

There you have it, a script to remotely access settings that normally you'd have to have the computer in hand and shut off to check.