PowerShell Basics - Extending the Shell with Modules and Snapins

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 workflows, 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 being deprecated and no longer recommended as the way to create and package new cmdlets.

There is a big miss conception with people starting with PowerShell install server products like Exchange or SharePoint, this programs place a shortcut to what they call a "Management Shell" which is not in reality a dedicated shell for it. 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 psd1 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 processes. 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 environment 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 environment 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 NameExportedCommands
---------- --------------------
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-nessus {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,, 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 module name we want to know about, if it returns the information about the module the module is loaded, if nothing is returned the module is not:

C:\> Get-Module -Name posh-ssh

ModuleType NameExportedCommands
---------- --------------------
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, lets call another module I'm still developing for controlling Metasploit:

C:\> Import-Module C:\Users\Carlos\Desktop\Posh-Metasploit.psm1 -Verbose
VERBOSE: Loading module from path 'C:\Users\Carlos\Desktop\Posh-Metasploit.psm1'.
VERBOSE: Exporting function 'New-MSFSession'.
VERBOSE: Exporting function 'Get-MSFSession'.
VERBOSE: Exporting function 'Invoke-MSFExploit'.
VERBOSE: Exporting function 'Invoke-MSFAuxiliary'.
VERBOSE: Exporting function 'Get-MSFModuleInfo'.
VERBOSE: Exporting function 'Get-MSFJobs'.
VERBOSE: Exporting function 'Get-MSFSessions'.
VERBOSE: Exporting function 'Get-MSFNotes'.
VERBOSE: Exporting function 'Get-MSFServices'.
VERBOSE: Exporting function 'Get-MSFHosts'.
VERBOSE: Exporting function 'Get-MSFLoot'.
VERBOSE: Exporting function 'Get-MSFCredentials'.
VERBOSE: Importing function 'Get-MSFCredentials'.
VERBOSE: Importing function 'Get-MSFHosts'.
VERBOSE: Importing function 'Get-MSFJobs'.
VERBOSE: Importing function 'Get-MSFLoot'.
VERBOSE: Importing function 'Get-MSFModuleInfo'.
VERBOSE: Importing function 'Get-MSFNotes'.
VERBOSE: Importing function 'Get-MSFServices'.
VERBOSE: Importing function 'Get-MSFSession'.
VERBOSE: Importing function 'Get-MSFSessions'.
VERBOSE: Importing function 'Invoke-MSFAuxiliary'.
VERBOSE: Importing function 'Invoke-MSFExploit'.
VERBOSE: Importing function 'New-MSFSession'.

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
----------- ---- ----------
FunctionAdd-BitLockerKeyProtectorBitlocker
FunctionBackup-BitLockerKeyProtector Bitlocker
FunctionClear-BitLockerAutoUnlockBitlocker
FunctionDisable-BitLockerBitlocker
FunctionDisable-BitLockerAutoUnlockBitlocker
FunctionEnable-BitLocker Bitlocker
FunctionEnable-BitLockerAutoUnlock Bitlocker
FunctionGet-BitLockerVolumeBitlocker
FunctionLock-BitLocker Bitlocker
FunctionRemove-BitLockerKeyProtector Bitlocker
FunctionResume-BitLocker Bitlocker
FunctionSuspend-BitLockerBitlocker
FunctionUnlock-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
----------- ---- ----------
CmdletAdd-PSSnapin Microsoft.PowerShell.Core
CmdletGet-PSSnapin Microsoft.PowerShell.Core
CmdletRemove-PSSnapinMicrosoft.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
----------- ---- ----------
CmdletAdd-PassthroughDeviceVMware.VimAutomation.Core
CmdletAdd-VMHost VMware.VimAutomation.Core
CmdletAdd-VmHostNtpServerVMware.VimAutomation.Core
CmdletApply-DrsRecommendationVMware.VimAutomation.Core
CmdletApply-VMHostProfileVMware.VimAutomation.Core
CmdletConnect-VIServer VMware.VimAutomation.Core
CmdletCopy-DatastoreItem VMware.VimAutomation.Core
CmdletCopy-HardDiskVMware.VimAutomation.Core
CmdletCopy-VMGuestFile VMware.VimAutomation.Core
CmdletDisconnect-VIServerVMware.VimAutomation.Core
CmdletDismount-Tools VMware.VimAutomation.Core
CmdletExport-VAppVMware.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, as a side note many of the Modules you see in my machine are projects I have started and not finished so do ask for when I will release those because many I just do not know other than the SSH module that is in my GitHub.