Using a ModuleSpecification Object
- Details
- Written by June Blender
- Last Updated: 09 October 2019
- Created: 21 June 2016
- Hits: 15106
Applies to: PowerShell 5.1.14352.1002, 6.0.0.9, 6.0.0.10. Updated 9/28/2016 to include Using statement.
With the advent of side-by-side module versions in Windows PowerShell 5.0, the lovely, but obscure ModuleSpecification object has become your new best friend. Use it to make sure that the commands and module that you use are the ones that you intend.
Using ModuleSpecification
Let’s start with an example. I want to get the Expand-Archive command in the Microsoft.PowerShell.Archive module. I can use Get-Command, of course, but when I surround the command name with wildcard characters to force a search, Get-Command returns this:
PS C:\ > Get-Command *Expand-Archive* CommandType Name Version Source ----------- ---- ------- ------ Function Expand-Archive 1.0.0.0 PowerShellLogging Function Expand-Archive 1.0.0.0 PowerShellLogging Function Expand-Archive 1.0.0.0 Microsoft.PowerShell.Archive Function Expand-Archive 0.8.0.0 Microsoft.PowerShell.Archive Cmdlet Expand-Archive 3.2.1.0 Pscx
[Tip: To detect name conflicts in your installed modules, use Group-Object.]
When I run ‘Get-Command Expand-Archive’ (without wildcard characters), PowerShell gets the command that actually runs when I type ‘Expand-Archive.’ That command is determined by command precedence and by the order in which PowerShell finds modules, which is, in turn, determined by the order of paths in the $PSModulePath environment variable. That’s complex enough on my own system, but if I’m running shared code in an arbitrary environment, I better make sure that I’m running the correct command.
To get the Expand-Archive command in the PSCX module, I could use a module-qualified name, such as:
Get-Command PSCX\Expand-Archive |
But, I want to specify both the module name and the version. That’s where the ModuleSpecification object comes in. This command gets the Expand-Archive function in the 1.0.0.0 version of Microsoft.PowerShell.Archive.
Get-Command -Name Expand-Archive ` -FullyQualifiedModule @{ModuleName = 'Microsoft.PowerShell.Archive'; RequiredVersion = '1.0.0.0'} |
To distinguish between two different modules with the same name and version, add a GUID value to get the right module.
Get-Command -Name Expand-Archive ` -FullyQualifiedModule @{ModuleName = 'PowerShellLogging'; RequiredVersion = '1.0.0.0'; GUID='abc0b34-02de-453a-9726-6bb7b716a63f'} |
I can even use the invoke/call operator (&) to run a command in a specific version of a specific module.
$myCommand = Get-Command -Name Expand-Archive ` -FullyQualifiedModule @{ModuleName = 'Microsoft.PowerShell.Archive'; RequiredVersion = '1.0.0.0'} & $myCommand -Path .\Myzip.zip -DestinationPath .\Unzipped |
Where can I use ModuleSpecification?
One of the most important places to use a ModuleSpecification object is the value of the #Requires -Module parameter.
#Requires -Module @{ModuleName='Pester'; ModuleVersion='3.4.0'}
|
The Using module statement, which imports modules and any PowerShell classes defined in the modules, takes a ModuleSpecification object. The Using statement was introduced in PowerShell 5.0.
using module @{ModuleName='TestClasses'; RequiredVersion='2.1.25'}
|
Also, several cmdlets and functions in PowerShell 5.0 have parameters that take a ModuleSpecification object. They're indicated by a parameter name that begins with FullyQualified.
PS C:\ > .\Get-ParameterType.ps1 -ParameterType ModuleSpecification CmdletName Parameter ---------- --------- Export-PSSession FullyQualifiedModule Get-Command FullyQualifiedModule Get-Module FullyQualifiedName Import-Module FullyQualifiedName Import-PSSession FullyQualifiedModule Remove-Module FullyQualifiedName Save-Help FullyQualifiedModule Update-Help FullyQualifiedModule
(See Get-ParameterType.ps1 on GitHub.)
Import-Module has a FullyQualifiedName parameter that takes a ModuleSpecification object. It also has version parameters that have the same effect, except for the GUID.
PS C:\> (Get-Command Import-Module).ParameterSets.Parameters | where Name -like "*Version" | Sort Name | Select -Property Name, ParameterType -Unique Name ParameterType ---- ------------- MaximumVersion System.String MinimumVersion System.Version RequiredVersion System.Version
Also, several commands, including the functions in the PowerShellGet module, have version parameters, even though they don’t have parameter that takes a ModuleSpecification object.
Find-Module -Name Pester -RequiredVersion 3.4.1 |
Be aware that Version and ModuleVersion parameters often behave like MinimumVersion, not RequiredVersion. To verify for any given command, check the help.
PS C:\> C:\ps-test\Get-ParameterName.ps1 -ParameterName "*Version" CmdletName Parameter Type ---------- --------- ---- Find-DscResource MinimumVersion System.Version Find-Module MinimumVersion System.Version Find-Script MinimumVersion System.Version Get-InstalledModule MinimumVersion System.Version ...
Syntax of a ModuleSpecification Object
You can create a ModuleSpecification object from a hash table using the specified keys. PowerShell converts the hash table to a ModuleSpecification object.
Here are the hash table keys:
- ModuleName <string> (required): Specifies one module name. Enter one name string. Wildcard characters are not suppored.
Select one of the following keys (required):
- ModuleVersion <String or System.Version>: Specifies the minimum acceptable version.
@{ModuleName = 'Pester'; ModuleVersion = '3.4.0'}
- MaximumVersion <String or System.Version>: Specifies the maximum acceptable version.
@{ModuleName = 'Pester'; MaximumVersion = '3.3.10'}
- RequiredVersion <String or System.Version>: Specifies the required version.
@{ModuleName = 'Pester'; RequiredVersion = '3.3.9'}
The GUID key is optional:
- GUID <String or System.Guid>: Specifies the module GUID.
@{ModuleName = 'Pester'; ModuleVersion = '3.4.0'; GUID='a699dea5-2c73-4616-a270-1f7abb777e71'}
Unfortunately, examining the Microsoft.PowerShell.Commands.ModuleSpecification class separate from its PowerShell implementation is not very helpful.
For example, you can create a ModuleSpecification object with no arguments or with a Name argument, but if you do, all of the other fields are blank, because they are read-only (get, not set).
PS C:\> $ms = [Microsoft.PowerShell.Commands.ModuleSpecification]::New('PSScriptAnalyzer') PS C:\> $ms | Get-Member TypeName: Microsoft.PowerShell.Commands.ModuleSpecification Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() Guid Property System.Nullable[guid] Guid {get;} MaximumVersion Property string MaximumVersion {get;} Name Property string Name {get;} RequiredVersion Property version RequiredVersion {get;} Version Property version Version {get;} PS C:\ps-test> $ms.Version = '1.0.0.0' 'Version' is a ReadOnly property. At line:1 char:1 + $ms.Version = '1.0.0.0' + ~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : PropertyAssignmentException
And, the property names don’t match the required hash table key names.
PS C:\> $ms Name : PSScriptAnalyzer Guid : Version : MaximumVersion : RequiredVersion :
So, forget the class and use the rules to create a hash table.
How does it work?
One word of caution. When the core commands use the ModuleSpecification object parameters, they don’t always return what you expect.
For example, in PowerShell 5.1.14352.1002, when you specify a minimum version, Import-Module doesn’t look for the earliest qualified version. Instead, it imports the first instance of that module that it encounters with a version greater than or equal to the minimum.
Also, Get-Command cannot get a command in a non-default version of a module unless that version is already imported into the current session.
We’ll look at these behaviors in a separate article.
June Blender is a technology evangelist at SAPIEN Technologies, Inc. and a Windows PowerShell MVP. You can reach her at This email address is being protected from spambots. You need JavaScript enabled to view it. or follow her on Twitter at @juneb_get_help.
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Former and Future Customers - Questions forum.