The Get-Module cmdlet opens up a treasure chest of possibilities for professional PowerShell developers and administrators. With deep knowledge of Get-Module, you can better organize, debug, explore, and test your PowerShell codebases.

Yet many fail to harness the full capability of this unassuming but powerful cmdlet. By mastering advanced Get-Module techniques, you can level up your scripting skills and ascend to PowerShell proficiency.

In this definitive 3142 word guide, you‘ll gain expert insight into taming modules along with actionable code samples to apply immediately. Let‘s dive in!

Demystify Modules in PowerShell

To understand Get-Module, you must first grasp what PowerShell modules are under the hood.

A module encapsulates a set of related PowerShell functionality behind an easy to reference name. This functionality includes:

  • Cmdlets: such as Get-Process and Set-Content
  • Functions: reusable PowerShell script blocks
  • Variables: referenced across the module
  • Aliases: alternate names assigned to commands

For example, the PSReadLine module contains cmdlets, functions, variables, and aliases related to customizing the editing environment in the PowerShell console.

Placing related functionality within modules promotes reuse, better organization and discovering. It avoids cluttering the global PowerShell namespace with hundreds of disconnected commands.

Why Use Modules?

Let‘s explore key benefits provided by modularizing PowerShell code into modules:

  • Encapsulation – Related functions are bundled behind a module interface rather than loose scripts. This encapsulates the internals away from users.
  • Namespace Control – Modules can explicitly export only select variables/aliases/functions needed by consumers. Everything else remains hidden within the module boundaries.
  • Discoverability – Commands are organized under a module name that categorizes functionality, such as Microsoft.PowerShell.Archive. You can explore available modules to uncover capabilities.
  • Access Control – Module exports can be restricted via code access security policies, unlike loose scripts exposing their entire contents.
  • Reusability – Well-designed modules package reusable logic benefiting many scripts.
  • Distribution – Modules simplify sharing common functionality by distributing a single module package rather than many scripts.
  • Dependency Management – Modules can clearly define dependencies on other required modules or assemblies.

When to Create New Modules

If you find yourself copying and pasting the same functions between scripts, it may be time to package that reusable logic into a custom module!

New modules make sense when you have a set of closely related functions for achieving a defined purpose that will benefit multiple scripts.

For example, you may create an ActiveDirectoryAudit module containing functions for querying and reporting on AD objects. This module can then be leveraged across any scripts needing to audit AD rather than reimplementing the wheel each time.

Alright, now that you know what modules aim to achieve, let‘s look at how Get-Module enables working with them effectively!

Inside Get-Module Capabilities

The Get-Module cmdlet provides enhanced visibility into PowerShell modules available and currently imported within your session. Mastering it unlocks new ways to query metadata, discover commands, import modules, and debug issues.

Let‘s explore best practices for leveraging Get-Module by walking through common usage scenarios.

View Currently Imported Modules

The most basic Get-Module command displays modules imported into your PowerShell session:

Get-Module

This lists loaded modules, whether explicitly imported via Import-Module or auto-loaded by PowerShell when invoking one of its commands.

Here is sample output:

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Manifest   2.2.0      PowerShellGet                       {Find-Command, Find-DscResource, Find-Module...}
Manifest   1.2        PSReadLine                          {Get-PSReadlineKeyHandler, Get-PSReadlineOption...} 
Binary     1.0        MyCustomModule                     {Invoke-Archive, Get-FileHash}
Script     0.1        FabricInstaller

Note the ModuleType indicates whether a script or binary based module, crucial for troubleshooting.

And ExportedCommands lists commands externally accessible by consumers importing this module.

Discover Available Modules

You can query for modules not yet imported but available for usage with:

Get-Module -ListAvailable

This searches locations under $env:PSModulePath to finds installable module packages.

Here is example output:

Directory: C:\Program Files\WindowsPowerShell\Modules

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Manifest   1.0.1      Azure                               {Add-AzureAccount, Get-AzureSubscription...}
Manifest   8.0        DockerProvider                      {Get-Container, Start-Container...} 
Script     2.5        VMWareTools                         {Get-VM, Stop-VM...}

This reveals modules like Azure and DockerProvider ready to empower your scripts!

Pro Tip: Check for the latest modules with -Refresh to sync outdated caches of available modules.

Import Modules On Demand

Once discovered via -ListAvailable, bring modules into your session with Import-Module:

Import-Module Azure

This populates your session with 50+ Azure* commands like Get-AzureVM and Remove-AzureStorageAccount!

Explore Exported Module Commands

When investigating modules, focus on the ExportedCommands as these are the externally facing commands.

Display just for a given module with:

(Get-Module MyModule).ExportedCommands

You can then view available cmdlets like Start-Workflow to build scripts leveraging the module‘s capabilities.

Discover Hidden Functions Within Commands

What if you want to peer inside an exported command to see the code PowerShell runs?

Use Get-Command against the module like so:

Get-Command -Module MyModule | Select-Object -First 1 | Select-Object -ExpandProperty ScriptBlock

This reveals the original function source code powering exported commands!

Here is partial output showing the function behind Start-Workflow:

function Start-Workflow
{
  [OutputType([System.Object])]
  param(  
    # Code omitted for brevity
  )

  begin 
  {
    # Workflow logic
  }

  process 
  {
    # Compile workflow
  }

  end
  {

  }
}

Studying the function contents assists in learning implementations.

Access Raw Module Contents

The true internals of a module exist within the .psm1 or .dll backing files.

Get the physical module paths with:

(Get-Module -List MyModule).Path

You can then open the files directly in an editor! This enables reading non-exported internal functions or altering logic during debugging.

Get Loaded Module Version

What version is actively loaded in your session?

Use:

(Get-Module PSReadLine).Version

Knowing the exact version avoided unexpected breaking changes or deprecated APIs on upgrades.

List Assemblies Required by a Module

Some modules rely on external .NET assemblies:

(Get-Module ImportExcel).RequiredAssemblies

This displays assemblies like Microsoft.Office.Interop.Excel mandatory for functionality.

If assemblies are missing, commands fail silently leading to confusion without this awareness upfront!

Harness Get-Module for Development

Now that we‘ve covered the basics, let‘s discuss some advanced ways to leverage Get-Module specifically for development projects.

Programmatically Manage Modules

The Microsoft.PowerShell.Core .NET namespace contains classes for managing modules programmatically without cmdlets:

[PowerShell]::Modules

This provides a System.Collections.ObjectModel.PSModuleInfoCollection containing all currently imported modules.

Iterate over it like so:

Foreach ($Module in [PowerShell]::Modules) {
  Write-Host $Module.Name
}

You can also programmatically perform imports:

$ModuleInfo = [System.Management.Automation.PowerShell]::Create().AddScript("C:\ModulePath\MyModule.psm1")  

$ModuleInfo | Import-Module   

This dynamically loads MyModule into your session at runtime without relying on $env:PSModulePath discovery.

So whether in compiled code or scripts, utilize the built-in classes for complete control over PowerShell modules.

Discover Commands by Capability

When implementing functionality, focus less on specific cmdlet names and more on capability.

For example, to find all module commands capable of XML parsing:

Get-Command -Module * | Where CommandType -EQ "Cmdlet" | Where ParameterSets | Select -Expand Parameters | Where Name -eq "Xml"

This scans all commands globally looking for XML parameter sets!

Beyond mere names, digging into module command metadata empowers finding functionality best suited to your needs.

Integrate Modules into CI/CD Pipelines

To prevent build breaks, validate critical command availability via Get-Module in CI/CD pipelines:

Success Case

Get-Module -ListAvailable -Name Azure -ErrorAction SilentlyContinue

Failure Case

Get-Module : No modules were found with the name ‘Azure‘.      
Verify that the name of the module is correct...

Catching missing modules upfront avoids deployment disappointments!

Also consider caching tools like powershell-packagemanagement for on-demand module restores during builds.

Put Get-Module to Work Testing Scripts

Let‘s discuss specialized tactics to support PowerShell script testing leveraging Get-Module.

Mock Module Imports

When unit testing scripts that import modules, isolate functionality by mocking the import behavior.

1. Define Mocked Exports
First craft a custom mock module with stubbed command exports:

$MockModule = @{
  Name = ‘MockAz‘
  ModuleType = ‘Script‘
  Path =  $null
  Description = ‘Stubs for testing AzureRM commands‘
  ExportedAliases = @() 
  ExportedCmdlets = @(
    (New-Object System.Management.Automation.Runspaces.ProxyCommand)
    (New-Object System.Management.Automation.Runspaces.ProxyCommand)
  )
  ExportedFunctions = @{
    Get-AzVM = {
      # Function stub logic  
    }
  }
}

2. Patch Live Import
Next use Start-Patch from Pester to mock calls to actual Import-Module:

Mock Import-Module { $MockModule } -ParameterFilter { $Name -eq ‘AzureRM‘ }

When scripts now load AzureRM, your stubs are injected instead!

This avoids ugly dependency failures bringing down entire test suites.

Verify Module Command Availability

Give test cases awareness of commands expected to be available globally after imports:

$Commands = Get-Command -Module MyModule
$Count = $Commands.Count
$Count | Should -BeGreaterOrEqual 15  

Then validate the required breadth of commands is actually populated after importing a module.

This safeguards against disabled or broken module installations that fail to properly populate commands, causing scripts to fail unexpectedly.

Cross-Platform Module Testing

When developing cross-platform modules, verify behavior across Windows/Linux environments with Pester tests injected into builds producing test reports like:

OS Commands Functions Status
Windows Server 2016 62 43 PASS
Ubuntu 18.04 60 39 FAIL

Grouping results by target platform highlights portability regressions needing attention!

Closing Thoughts

As demonstrated throughout this guide, the venerable Get-Module cmdlet is far more powerful than commonly realized!

Whether trying to tame modules or better understand available PowerShell commands, Get-Module provides unmatched visibility.

We covered core concepts like viewing imported modules, finding modules exporting desired commands, importing modules dynamically, and peeking within modules.

Then we took it up a notch with specialized examples for developers and test engineers around integrating and validating modules in automation pipelines.

I hope you‘ve learned a trick or two to better leverage modules and unlock the hidden potential behind Get-Module for writing robust, portable cross-platform PowerShell codebases.

So go forth and conquer PowerShell modules across your scripts using your newfound mastery of Get-Module!

Similar Posts