In PowerShell there are 2 main ways to extend the shell this are:

* Modules – A package that contains Windows PowerShell commands int he form of functions, cmdlerts and worksflows, in addition it may contain variables, aliases and providers. Modules can be written in PowerShell and/or compiled as DLLs.

* Snap-Ins – Are compiled cmdlets in to a DLL written in a .Net language are bening deprecated and no longer recomended as the way to create and package new cmdlets.

There is a big miss conception with people starting with PowerShell when they install some server products like Exchange or SharePoint and the programs place a shotcut to what they call a “Management Shell” it is nothing more than PowerShell with a loaded Module or PSSnapin. As you will see extending the shell is quite simple and flexible.

## Working with Modules

Modules have primarily 2 locations on your system:

* %windir%\system32\WindowsPowerShell\v1.0\Modules this is the location for system wide modules available to any user in the system. * %USERPROFILE%\Documents\WindowsPowerShell\Modules

Each module is stored in a folder where there is a psm1 file that is known as a Module Manifest, this manifest has the settings for the module and sets the restrictions for it in terms of .Net Framework version, version of PowerShell, files to load, version, copyright, author and many other settings. This file can load what is called a main module and sub-modules each can either be a psm1 or dll file, in addition they can also be scripts that gets procresses. As it can be seen using modules provide great flexibility in terms of formats and structure.

We can also have modules in other locations that can be accessed by the PowerShell session we run in, the locations are defined in the environemt variable $env:PSModulePath

C:\> $env:PSModulePath
C:\Users\Carlos\Documents\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules\

If we want to add another path for PowerShell to look at we just add that path to the current environment variable:

$env:psmodulepath = $env:psmodulepath + ";"

To list the modules that are available we use the Get-Module cmdlet withe the -listavailable parameter:

Get-Module -ListAvailable

This will list all modules that the session can see in the paths that are specified in the environmet variable. On PowerShell v2 we would have to load each module we wanted by hand and only then would be be able to use the commands available, in the case of PowerShell v3 Microsoft now allows us access to the modules in those paths and the modules are loaded dynamically when a cmdlet, workflow, alias or function that form part of the module is invoked.

If you only want to see the modules that are currently loaded in to the session the -All parameter is used with Get-Module:

C:\> Get-Module -All
ModuleType Name                                ExportedCommands
---------- ----                                ----------------
Script     Discovery                           {Invoke-ARPScan, Invoke-PingScan, Invoke-PortScan, Invoke-ReverseDNSLookup...
Binary     Microsoft.PowerShell.Activities
Binary     Microsoft.PowerShell.Commands.Ma... {Add-Content, Clear-Content, Clear-ItemProperty, Join-Path...}
Binary     Microsoft.PowerShell.Commands.Ut... {Get-FormatData, Export-FormatData, Format-List, Format-Custom...}
Manifest   Microsoft.PowerShell.Management     {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Content...}
Manifest   Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Object...}
Binary     Microsoft.Powershell.Workflow.Se... {Import-PSWorkflow, New-PSWorkflowExecutionOption}
Script     Parse                               {Import-DNSReconXML, Import-NessusReport}
Script     posh-git                            {Add-SshKey, Enable-GitColors, Get-AliasPattern, Get-GitDirectory...}
Script     posh-nvs                            {Copy-NessusPolicy, Get-NessusPolicyXML, Get-NessusReportHostsDetailed, Ge...
Script     Posh-SecMod                         {Add-Zip, Compress-PostScript, Confirm-IsAdmin, Connect-SQLite3...}
Binary     PoshSSH                             {New-SSHSession, New-SFTPSession}
Script     Posh-SSH                            {New-SFTPSession, New-SSHSession, Get-SFTPCurrentDirectory, Get-SFTPDirect...
Script     PostExploitation                    {Compress-PostScript, ConvertTo-PostBase64Command, New-PostDownloadExecute...
Script     PSWorkflow                          {New-PSWorkflowSession, nwsn}
Manifest   PSWorkflow                          {New-PSWorkflowExecutionOption, New-PSWorkflowSession, nwsn}
Script     Registry                            {Get-RegKeys, Get-RegKeySecurityDescriptor, Get-RegValue, Get-RegValues...}

To import a module in to our session we just use the Import-Module cmdlet and give it the name of the module. I tend to recommend to people starting with PowerShell that when working on a shell session interactively to always add the -Verbose parameter also, this will list the cmdlets, functions and aliases that are being made available to you when you import the module. Lets take for example a module that I have been developing for automating tasks via SSH:

C:\> Import-Module -Name Posh-SSH -Verbose
VERBOSE: Loading module from path 'C:\Users\Carlos\Documents\WindowsPowerShell\Modules\Posh-SSH\Posh-SSH.psd1'.
VERBOSE: Importing cmdlet 'New-SFTPSession'.
VERBOSE: Importing cmdlet 'New-SSHSession'.
VERBOSE: Importing function 'Get-SFTPCurrentDirectory'.
VERBOSE: Importing function 'Get-SFTPDirectoryList'.
VERBOSE: Importing function 'Get-SFTPFile'.
VERBOSE: Importing function 'Get-SFTPSession'.
VERBOSE: Importing function 'Get-SSHPortForward'.
VERBOSE: Importing function 'Get-SSHSession'.
VERBOSE: Importing function 'Invoke-SSHCommand'.
VERBOSE: Importing function 'Move-SFTPFile'.
VERBOSE: Importing function 'New-SFTPDirectory'.
VERBOSE: Importing function 'New-SSHDynamicPortForward'.
VERBOSE: Importing function 'New-SSHPortForward'.
VERBOSE: Importing function 'Remove-SFTPDirectory'.
VERBOSE: Importing function 'Remove-SFTPFile'.
VERBOSE: Importing function 'Remove-SFTPSession'.
VERBOSE: Importing function 'Remove-SSHSession'.
VERBOSE: Importing function 'Set-SFTPDirectoryPath'.
VERBOSE: Importing function 'Set-SFTPFile'.
VERBOSE: Importing function 'Start-SSHPortForward'.
VERBOSE: Importing function 'Stop-SSHPortForward'.

As you can see it tells me the cmdlets and script functions it loaded in to the session. If you are in a session and want to know if a module is loaded the Get-Module cmndlet with the -Name option is use and we give it the moduel name we want to know about, if it returns the information about the module the module is loaded, if nothing is retured the module is not:

C:\> Get-Module -Name posh-ssh
ModuleType Name                                ExportedCommands
---------- ----                                ----------------
Script     Posh-SSH                            {New-SFTPSession, New-SSHSession, Get-SFTPCurrentDirectory, Get-SFTPDirect...

To remove the module from our session we use the Remove-Module cmdlet and give it the name of the module we want to remove:

C:\> Remove-Module -Name posh-ssh -Verbose
VERBOSE: Performing operation "Remove-Module" on Target "PoshSSH (Path:
'C:\Users\Carlos\Documents\WindowsPowerShell\Modules\Posh-SSH\PoshSSH.dll')".
VERBOSE: Performing operation "Remove-Module" on Target "Posh-SSH (Path:
'C:\Users\Carlos\Documents\WindowsPowerShell\Modules\Posh-SSH\Posh-SSH.psm1')".
VERBOSE: Removing the imported "Get-SFTPCurrentDirectory" function.
VERBOSE: Removing the imported "Get-SFTPDirectoryList" function.
VERBOSE: Removing the imported "Get-SFTPFile" function.
VERBOSE: Removing the imported "Get-SFTPSession" function.
VERBOSE: Removing the imported "Get-SSHPortForward" function.
VERBOSE: Removing the imported "Get-SSHSession" function.
VERBOSE: Removing the imported "Invoke-SSHCommand" function.
VERBOSE: Removing the imported "Move-SFTPFile" function.
VERBOSE: Removing the imported "New-SFTPDirectory" function.
VERBOSE: Removing the imported "New-SSHDynamicPortForward" function.
VERBOSE: Removing the imported "New-SSHPortForward" function.
VERBOSE: Removing the imported "Remove-SFTPDirectory" function.
VERBOSE: Removing the imported "Remove-SFTPFile" function.
VERBOSE: Removing the imported "Remove-SFTPSession" function.
VERBOSE: Removing the imported "Remove-SSHSession" function.
VERBOSE: Removing the imported "Set-SFTPDirectoryPath" function.
VERBOSE: Removing the imported "Set-SFTPFile" function.
VERBOSE: Removing the imported "Start-SSHPortForward" function.
VERBOSE: Removing the imported "Stop-SSHPortForward" function.
C:\> Get-Module -Name posh-ssh
C:\>

You can see in the example I used the Get-Module cmdlet to confirm the module is not present. We can also load modules by calling directly the DLL or the PSM1 file. If you are developing a module and whant to reload the module with the changes you just made I recommend just using the Import-Module cmdlet with the -Force parameter instead of removing and importing the module again. If we want tot see the command for a specific module we can use the Get-Command cmdlet:

C:\> Get-Command -Module Bitlocker
CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Function        Add-BitLockerKeyProtector                          Bitlocker
Function        Backup-BitLockerKeyProtector                       Bitlocker
Function        Clear-BitLockerAutoUnlock                          Bitlocker
Function        Disable-BitLocker                                  Bitlocker
Function        Disable-BitLockerAutoUnlock                        Bitlocker
Function        Enable-BitLocker                                   Bitlocker
Function        Enable-BitLockerAutoUnlock                         Bitlocker
Function        Get-BitLockerVolume                                Bitlocker
Function        Lock-BitLocker                                     Bitlocker
Function        Remove-BitLockerKeyProtector                       Bitlocker
Function        Resume-BitLocker                                   Bitlocker
Function        Suspend-BitLocker                                  Bitlocker
Function        Unlock-BitLocker                                   Bitlocker

## Working with PSSnapins PSSnapings is the old method from PowerShell v1 that is used to extend the shell, in PowerShell v2 and PowerShell v3 it can still be used but Microsoft has started to tell developers to move away from the sanpin model and move to the module model of extending the shell. Still many 3rd Party extension, the most popular being VMware PowerCLI, in fact Microsoft PowerShell core cmdlets are still in snapin format so we will still see support for snapins for a while.

We can list the cmdlets available for managing PSSnapin usin the Get-Command cmdlet and giving it PSSnapin as the verb to look for:

C:\> Get-Command -Noun PSSnapin
CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Cmdlet          Add-PSSnapin                                       Microsoft.PowerShell.Core
Cmdlet          Get-PSSnapin                                       Microsoft.PowerShell.Core
Cmdlet          Remove-PSSnapin                                    Microsoft.PowerShell.Core

Since snapins are DLLs that get registered on the system unlike modules that do not need any registration we use the -Registered paramter with the Get-PSSnapin cmdlet to list the snapins available:

C:\> Get-PSSnapin -Registered
Name        : VMware.DeployAutomation
PSVersion   : 2.0
Description : Cmdlets for Rule-Based-Deployment
Name        : VMware.ImageBuilder
PSVersion   : 2.0
Description : This Windows PowerShell snap-in contains VMware ESXi Image Builder cmdlets used to generate custom images.
Name        : VMware.VimAutomation.Core
PSVersion   : 2.0
Description : This Windows PowerShell snap-in contains Windows PowerShell cmdlets for managing vSphere.
Name        : VMware.VimAutomation.License
PSVersion   : 2.0
Description : This Windows Powershell snap-in contains cmdlets for managing License components.

To load a snapin we use the Add-PSSnapin cmdlet and give it the name of the PSSnapin we want to load:

C:\> Add-PSSnapin -Name VMware.VimAutomation.Core
C:\> Remove-PSSnapin -Name VMware.VimAutomation.Core
C:\> Add-PSSnapin -Name VMware.VimAutomation.Core -Verbose
C:\>

The cmndlet does not produce any output, even when -Verbose is used as it can be see in the example. To see what snapins are loaded we use the Get-PSSnapin with no parameters:

C:\> Get-PSSnapin
Name        : Microsoft.PowerShell.Core
PSVersion   : 3.0
Description : This Windows PowerShell snap-in contains cmdlets used to manage components of Windows PowerShell.
Name        : VMware.VimAutomation.Core
PSVersion   : 2.0
Description : This Windows PowerShell snap-in contains Windows PowerShell cmdlets for managing vSphere.

To get a list of the cmdlets and Functions it importer we use the Get-Command cmdlet wit the -Module parameter and give it the PSSnapin name:

C:\> Get-Command -Module VMware.VimAutomation.Core
CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Cmdlet          Add-PassthroughDevice                              VMware.VimAutomation.Core
Cmdlet          Add-VMHost                                         VMware.VimAutomation.Core
Cmdlet          Add-VmHostNtpServer                                VMware.VimAutomation.Core
Cmdlet          Apply-DrsRecommendation                            VMware.VimAutomation.Core
Cmdlet          Apply-VMHostProfile                                VMware.VimAutomation.Core
Cmdlet          Connect-VIServer                                   VMware.VimAutomation.Core
Cmdlet          Copy-DatastoreItem                                 VMware.VimAutomation.Core
Cmdlet          Copy-HardDisk                                      VMware.VimAutomation.Core
Cmdlet          Copy-VMGuestFile                                   VMware.VimAutomation.Core
Cmdlet          Disconnect-VIServer                                VMware.VimAutomation.Core
Cmdlet          Dismount-Tools                                     VMware.VimAutomation.Core
Cmdlet          Export-VApp                                        VMware.VimAutomation.Core
.......

As it can be seen PSSnapins are limited, thus making their management simpler.

As always I hope you found the blogpost useful and informative.

About the author