top of page

How to worry less about PowerShell compatibility

gs9074

How often have you added Install-Module statements upgrading a module to existing PowerShell scripts? All to ensure it will run with the version you've tested on your local development environment or because it's the only version that works with the piece of code you've, ahem borrowed from the extensive research on the problem you're trying to solve? Only once it's all deployed and do you start worrying about compatibility issues? Well, have no fear because PowerShell versioning is here to make your life easier!

PowerShell versioning is a feature that allows you to install and manage different versions of PowerShell on your system. This means you can use different versions of PowerShell for different tasks, and you won't have to worry about compatibility issues or breaking changes.

Let me show you how it works with a few examples.

First, let's check which version of PowerShell you're currently running by opening up PowerShell and typing:



$PSVersionTable.PSVersion

This will display the version of PowerShell you're currently using. If you're running Windows 10, you'll likely be using PowerShell version 5.1.

Now, let's say you want to install PowerShell version 7.x. To do this, you'll need to go to the PowerShell GitHub releases page and download the appropriate version for your system. Once you've downloaded the installer, simply run it and follow the installation prompts.

Once you've installed PowerShell 7.1, you can check which version you're using by typing the same command as before:


$PSVersionTable.PSVersion

This time, you should see that you're running PowerShell version 7.1.


But what if you want to use a specific version of PowerShell for a specific script? You can do this by adding a shebang line to the top of your script. For example, if you want to use PowerShell version 7.1 for a script, add the following line to the top of your script:


#Requires -Version 7.0

This tells the script to use the default version of PowerShell installed on the system, which in this case is PowerShell version 7.1.


That's PowerShell getting the right version of PowerShell, now onto the modules themselves.


First, let's quickly recap what a PowerShell module is. A module is essentially a collection of cmdlets, functions, and scripts that you can use to extend the functionality of PowerShell. Modules are designed to be easily shared and reused.


So when you write a line such as


Select-AzSubscription -Subscription "MySubscription"

PowerShell will go through Module resolution which is the process to determine which version of a module to use when you import it. PowerShell does this by looking for the module in a specific order of locations, or paths. Here's the order in which PowerShell looks for modules:

  1. The current directory

  2. The directories listed in the PSModulePath environment variable, in the order they're listed

  3. Any additional directories that you specify using the -ModulePath parameter when you import the module

So, if you have multiple versions of a module, installed in different locations, PowerShell will select the version that's found first in the list above. That means that if you have a newer version of a module installed in a directory that appears later in the PSModulePath environment variable, PowerShell will still select the older version that's found in an earlier directory.

So how do you get round it and use the specific version of a module, regardless of where it's located? Well, you can do that by specifying the version number when you import the module. For example, if you want to import version 2.0 of the MyModule module, you would use the following command:



Install-Module MyModule -RequiredVersion 2.0

What if all the versions up to 2.0 could be used, for example a breaking change had been introduced in version 3 and afterwards we could then use the MaxVersion switch.



Install-Module MyModule -MaximumVersion 2.0

We can reverse the selection if we are happy with all versions after version 3.0 and set a minimum version.


Install-Module MyModule -MinimumVersion 3.0

However, the problem with this is that if a breaking change was introduced in a new module it would not guard against it. So I prefer to use the required version.


So now we can select which module version we want.



if ((Get-Module -Name Az -ListAvailable).Version -eq "3.5.0" ){
    Import-Module -Name Az -RequiredVersion 3.5.0
}
else
{
    Install-Module -Name Az -RequiredVersion 3.5.0
}

New-ItemFromMyModule -Some Value

if ((Get-Module -Name AnotherModule --ListAvailable).Version -eq "4.0.0") {
    Install-Module -Name AnotherModule -RequiredVersion 4.0
}

Get-StatusAnotherModule -Some Value

There is another function, Get-InstalledModule which has a similar role and simpler syntax.



if (Get-InstalledModule -Name AnotherModule -RequiredVersion 4.0) {
    Install-Module -Name AnotherModule -RequiredVersion 4.0
}
    

It differs from Get-Module in that it only returns modules installed using PowerShellGet. So calling Get-InstalledModule may not list a module that is returned by Get-Module. To ensure all modules are always listed use Get-Module.


As you may have noticed the code is littered with version tests for each module before its used, which detracts from the code's purpose.


Although it ensures consistent behaviour you'll only discover that a machine doesn't have a required module until part way through the script.


One approach could be to check for all the version of the modules you need using the require statement as we did for the PowerShell version.


#Requires -Modules @{ ModuleName="Az.Accounts"; ModuleVersion="5.4.0" }

The ensures that the module Az.Accounts version 5.4.0 or greater is installed.

As mentioned earlier with Install-Module you specify a maxium version if your script is happy with all versions up to a point.



#Requires -Modules @{ ModuleName="AzureRM.Netcore"; MaximumVersion="0.12.0" }

Or ensure that a only a very specific version is installed.


#Requires -Modules @{ ModuleName="AzureRM.Netcore"; RequiredVersion="0.12.0" }

Or you script will happily work with any version


#Requires -Modules Az.Accounts

Although I wouldn't recommend the above as you don't know what may come in a new version.

And that's it! Now you know how PowerShell selects the version of a module, and how you can specify a specific version if you need to. Thanks for reading, and happy scripting!

5 views0 comments

댓글


Bagh Co Logo

Bagh Co Ltd

  • LinkedIn
  • X
  • Threads

©2024 by Bagh Co Ltd.

bottom of page