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 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-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 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, 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 ----------- ---- ---------- 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, 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.
Reader Comments (1)
Thanks for your great post