Since the release of PowerShell version 3, the ability to automatically load modules has been an exciting feature for those using the console. Prior to this, getting access to the cmdlets and functions buried inside of a module (or snappin) needed to be explicitly imported. However, not all modules will support this feature. It’s up to the module owner to determine which module commands are exported. To see this, I’ll use the Pester module as an example.

Get-Module -ListAvailable Pester ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Script 3.4.3 Pester {Describe, Context, It, Should...}

You can see a few of the ExportedCommands are shown. To see all of them, you could try a Format-List or just pick apart the hashtable itself.

(Get-Module -ListAvailable Pester).ExportedCommands Key Value --- ----- Describe Describe Context Context It It Should Should Mock Mock Assert-MockCalled Assert-MockCalled Assert-VerifiableMocks Assert-VerifiableMocks New-Fixture New-Fixture Get-TestDriveItem Get-TestDriveItem etc..

This is why I can type Invoke-Pester from anywhere in the console session and it will autocomplete via Intellisense and subsequently load the Pester module when called. The neat thing is that loading a module isn’t just limited to calling a command. You could also use, for example, the Get-Help cmdlet as shown below. Notice how the first use of Get-Module does not show the Pester module loaded, but after requesting the help file, the Pester module is now loaded. Fairly snazzy.

PS> Get-Module ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Script 1.0.0.0 ISE {Get-IseSnippet, Import-IseSnippet, New-IseSnippet} Binary 2.6.2.2 ISESteroids {Add-SteroidsContextMenuCommand, Add-SteroidsEditorTabCommand, Add-SteroidsLicense, Add-SteroidsTextChange...} Manifest 3.1.0.0 Microsoft.PowerShell.Management {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Content...} Manifest 3.0.0.0 Microsoft.PowerShell.Security {ConvertFrom-SecureString, ConvertTo-SecureString, Get-Acl, Get-AuthenticodeSignature...} Manifest 3.1.0.0 Microsoft.PowerShell.Utility {Add-Member, Add-Type, Clear-Variable, Compare-Object...} PS> Get-Help Invoke-Pester NAME Invoke-Pester <snip> PS> Get-Module ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Binary 1.0.0.0 CimCmdlets {Export-BinaryMiLog, Get-CimAssociatedInstance, Get-CimClass, Get-CimInstance...} Script 1.0.0.0 ISE {Get-IseSnippet, Import-IseSnippet, New-IseSnippet} Binary 2.6.2.2 ISESteroids {Add-SteroidsContextMenuCommand, Add-SteroidsEditorTabCommand, Add-SteroidsLicense, Add-SteroidsTextChange...} Manifest 3.1.0.0 Microsoft.PowerShell.Management {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Content...} Manifest 3.0.0.0 Microsoft.PowerShell.Security {ConvertFrom-SecureString, ConvertTo-SecureString, Get-Acl, Get-AuthenticodeSignature...} Manifest 3.1.0.0 Microsoft.PowerShell.Utility {Add-Member, Add-Type, Clear-Variable, Compare-Object...} Script 3.4.3 Pester {AfterAll, AfterEach, Assert-MockCalled, Assert-VerifiableMocks...}

VMware’s PowerCLI Modules

As stated earlier, not all modules support this. One example is the VMware PowerCLI 6.5 module. I bring this up as I’ve had a number of folks report this behavior to me on various forums and comments threads. My guess is that as VMware continues to swap over from a rigid snappin architecture to a more open module architecture this will be remediated. However, for now there are hardly any commands being exported by any of their modules.

PS> Get-Module -ListAvailable "VMware*" Directory: C:\Program Files (x86)\VMware\Infrastructure\PowerCLI\Modules ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Binary 6.0.0.0 VMware.DeployAutomation Binary 6.0.0.0 VMware.ImageBuilder Binary 6.5.0.4... VMware.VimAutomation.Cis.Core Binary 6.5.0.4... VMware.VimAutomation.Cloud Manifest 6.5.0.4... VMware.VimAutomation.Common Binary 6.5.0.2... VMware.VimAutomation.Core HookGetViewAutoCompleter Binary 6.0.0.0 VMware.VimAutomation.HA Binary 7.0.2.4... VMware.VimAutomation.HorizonView Binary 6.5.0.4... VMware.VimAutomation.License Binary 6.5.0.4... VMware.VimAutomation.PCloud Manifest 6.5.0.4... VMware.VimAutomation.Sdk Get-PSVersion Binary 6.5.0.4... VMware.VimAutomation.Storage Binary 6.5.0.4... VMware.VimAutomation.Vds Binary 6.5.0.4... VMware.VimAutomation.vROps Binary 6.0.0.0 VMware.VumAutomation

If you’ve ever tried entering Connect-VIServer without first implicitly loading the module, you’ll know the pain of seeing the “The term ‘Connect-VIServer’ is not recognized as the name of a cmdlet, function, script file, or operable program” error. I’m assuming there’s just something not quite right with the export code in their module at this time. Of course, you can always implicitly load the module in your code. Kyle Ruddy describes the process on the VMware PowerCLI blog along with a sample script to update your existing scripts. Kudos for sharing!

The other approach is to use a requires statement.

The Requires Statement

A practice that I highly advise making habit is using a requires statement at the top of your scripts and functions. It’s a handy way to define the requirements necessary for code to execute. Here’s some examples of what can be examined:

#Requires -Version <N>[.<n>] #Requires -PSSnapin <PSSnapin-Name> [-Version <N>[.<n>]] #Requires -Modules { <Module-Name> | <Hashtable> } #Requires -ShellId <ShellId> #Requires -RunAsAdministrator

For this blog post, I’ve written a tiny sample script to show how to require the VMware module before code will execute without having to lay in extra logic or potentially stumble upon a module that’s already loaded and throw an error.

#requires -Modules VMware.VimAutomation.Core Write-Host "Loaded!"

What an exciting sample script! Its job in life is to load the VMware.VimAutomation.Core module and then write the word “Loaded!” onto the console. Here’s what happens:

PS> Get-Module ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Manifest 3.1.0.0 Microsoft.PowerShell.Management {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Con Manifest 3.0.0.0 Microsoft.PowerShell.Security {ConvertFrom-SecureString, ConvertTo-SecureString, Get-Acl Manifest 3.1.0.0 Microsoft.PowerShell.Utility {Add-Member, Add-Type, Clear-Variable, Compare-Object...} Script 1.2 PSReadline {Get-PSReadlineKeyHandler, Get-PSReadlineOption, Remove-PS PS> .\SampleRequires.ps1 Loaded! PS> Get-Module ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Script 0.0 Initialize-VMware_VimAutomation_Cis Manifest 3.1.0.0 Microsoft.PowerShell.Management {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Con Manifest 3.0.0.0 Microsoft.PowerShell.Security {ConvertFrom-SecureString, ConvertTo-SecureString, Get-Acl Manifest 3.1.0.0 Microsoft.PowerShell.Utility {Add-Member, Add-Type, Clear-Variable, Compare-Object...} Script 1.2 PSReadline {Get-PSReadlineKeyHandler, Get-PSReadlineOption, Remove-PS Binary 6.5.0.4... VMware.VimAutomation.Cis.Core {Connect-CisServer, Disconnect-CisServer, Get-CisService} Manifest 6.5.0.4... VMware.VimAutomation.Common Binary 6.5.0.2... VMware.VimAutomation.Core {Add-PassthroughDevice, Add-VirtualSwitchPhysicalNetworkAd Manifest 6.5.0.4... VMware.VimAutomation.Sdk Get-PSVersion

If the module doesn’t exist, you’ll instead get an error. To show this, I’ve changed the requirement to find a non-existent module named “SpongeBob.”

.\SampleRequires.ps1 : The script 'SampleRequires.ps1' cannot be run because the following modules that are specified by the "#requires" statements of the script are missing: SpongeBob.

In the case of PowerCLI, this will work for versions 6.0 and later due to the conversion from a pssnapin to a partial module (in 6.0) and full module (in 6.5). Enjoy!