Working with PSSnapins and modules - PowerShell fundamentals - PowerShell in Depth, Second Edition (2015)

PowerShell in Depth, Second Edition (2015)

Part 1. PowerShell fundamentals

Chapter 5. Working with PSSnapins and modules

This chapter covers

· Extending PowerShell functionality

· Using PSSnapins and modules

· Module discovery and automatic loading

PowerShell’s real value lies not in the hundreds of built-in commands that it ships with but in its ability to have more commands added. PowerShell extensions—our collective term for the PSSnapins and modules that can be loaded—permit PowerShell to manage anything: IIS, Exchange, SQL Server, VMware, Citrix, NetApp, SharePoint, Cisco, you name it. Being able to efficiently work with these extensions is probably one of the most important things you’ll do in the shell.

5.1. There’s only one shell

Before we jump into working with these extensions, let’s get something straight: There’s no such thing as a product-specific version of PowerShell. It’s easy to get the impression that such a thing exists, because Microsoft tends to create Start menu shortcuts with names like “Exchange Management Shell,” “SharePoint Management Shell,” and so forth.

Note

The PowerShell functionality in SQL Server 2008 and 2008 R2 is the only exception to this rule of which we know. It had its own version of PowerShell—sqlps.exe—that was a recompiled version of PowerShell with the SQL Server functionality added and the snap-in functionality removed. SQL Server 2012 delivers its PowerShell functionality as a module (confusingly called sqlps) so we’ll forget (and possibly even forgive) the oddity that was sqlps.exe.

The fact is that these Start menu shortcuts are running plain ol’ powershell.exe and passing a command-line argument that has the shell do one of four things:

· Autoload a PowerShell console (.psc) file, which specifies one or more PSSnapins to load into memory at startup

· Autorun a PowerShell script (.ps1) file, which can define commands, load extensions, show a “tip of the day,” and whatever else the authors desire

· Autoload a module

· Autoload a PSSnapin

You can look at the properties of these Start menu shortcuts to see which of these four tricks they’re using to provide the illusion of a product-specific shell—and you can manually perform the same task in a “plain” PowerShell console to replicate the results. There’s nothing stopping you from loading the Exchange stuff into the same shell where you’ve already loaded the SharePoint stuff, creating a “custom” shell in much the same way that you could always create a custom graphical Microsoft Management Console (MMC) environment. In fact, it’s less confusing if you do this because you don’t have to worry about which “shell” supplies which functionality.

5.2. PSSnapins vs. modules

PowerShell has two types of extensions: PSSnapins and modules. Both are capable of adding cmdlets and PSProviders to the shell (we’ll get into PSProviders in chapter 15); modules are also capable of adding functions to the shell (we refer to functions and cmdlets as “commands” because they do the same thing in the same way).

PSSnapins are the “v1 way” of extending the shell, although they’re still supported in v2, v3, and v4. Microsoft’s advice is for folks to not make PSSnapins anymore, but it isn’t preventing anyone from doing so. PSSnapins are written in a .NET language like C# or Visual Basic, and they’re packaged as DLL files. They have to be installed and registered with the system before PowerShell can see them and load them into memory.

Modules, introduced in v2, are the preferred way of extending the shell. Sometimes they have to be installed, but most of the time they can be copied from system to system—it depends a bit on the underlying dependencies the module may have on other components or code. Modules can benefit from autoloading, too, which we’ll discuss next.

5.3. Loading, autoloading, and profiles

Prior to PowerShell v3, you had to figure out what extensions were on your system and manually load them into memory. Doing so could be tricky, and you had to load them each time you started a new shell session.

As a workaround, you could also create a PowerShell profile. A profile is a PowerShell script file stored in a specific folder and with a specific filename. If the file exists when PowerShell starts, it runs it. The script could therefore be programmed to load whatever extensions you want, every time the shell started, eliminating some manual effort on your part. You can read more about profiles by running help about_profiles in the shell.

In PowerShell v3 and later, much of that is unnecessary for many extensions, thanks to a feature called module autoloading. This feature makes modules look “available” even when they’re not loaded, and it implicitly loads them into memory when you try to run one of their commands. Let’s look at some specific rules about which extensions can take advantage of this feature:

· Only modules, not PSSnapins, support autoloading.

· Only modules stored in specific locations are eligible. These locations are defined in the PSModulePath environment variable, which you can modify to include additional locations (such as a shared location on a file server).

· Autoloading behavior can be changed, which we’ll discuss later in this chapter.

5.4. Using extensions

Using extensions involves three steps: discovering what you’ve installed, loading them, and discovering what they’ve added to the shell.

5.4.1. Discovering extensions

To see the PSSnapins that are installed on your system, use the following command:

PS C:\> Get-PSSnapin –Registered

This command displays the registered snap-ins, excluding the core PowerShell snap-ins in PowerShell v2, regardless of whether they’re loaded. If you want to see only the loaded snap-ins, use Get-PSSnapin, which shows the core PowerShell snap-ins.

Note

In PowerShell v3 and v4 the core PowerShell functionality is delivered as modules. In PowerShell v3 they’re also listed as PSSnapins by Get-PSSnapin but PowerShell v4 only lists the Microsoft.PowerShell.Core snap-in.

You can do the same trick for modules, using a different command:

PS C:\> Get-Module -ListAvailable

Directory: C:\Windows\system32\WindowsPowerShell\v1.0\Modules

ModuleType Name ExportedCommands

---------- ---- ----------------

Manifest ADDeploymentWF Invoke-ADCommand

Manifest AppLocker {Get-AppLockerFileInform...

Manifest Appx {Add-AppxPackage, Get-Ap...

Manifest BestPractices {Get-BpaModel, Get-BpaRe...

Manifest BitsTransfer {Add-BitsFile, Complete-...

Manifest BranchCache {Add-BCDataCacheExtensio...

Manifest CimCmdlets {Get-CimAssociatedInstan...

Manifest DirectAccessClientComponents {Disable-DAManualEntryPo...

We want to point out a few more caveats about this command. Because there’s no central registration of modules, as there is for PSSnapins, the command can only include those modules that are installed to specific locations. Those locations are defined in a systemwide environment variable,PSModulePath:

PS C:\> $env:psmodulepath

C:\Users\Administrator\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\windows\system32\WindowsPowerShell\v1.0\Modules\

Note

In PowerShell v4, C:\Program Files\WindowsPowerShell\Modules has been added to the module path (for Desired State Configuration primarily). You won’t see that in earlier versions.

As with any Windows environment variable, you can change this variable to include alternate or additional locations that should be autosearched for modules. In fact, some third-party PowerShell solutions might update this variable.

Note

You’ll still need to use the –ListAvailable parameter of Get-Module, because even though PowerShell v4 “sees” all modules automatically, thanks to its autoloading feature Get-Module sees only modules that are fully loaded—either by using Import-Module or by using a command in a module that triggers a full load in the background.

In chapter 10, we’ll discuss PowerShell Remoting, which is the shell’s ability to maintain a connection with remote computers. The Get-Module cmdlet has a special feature that uses Remoting to list the modules available on a remote machine. For example, create a Remoting session to another computer, and then see what modules it contains:

PS C:\> $session = New-PSSession -ComputerName Win8

PS C:\> Get-Module -PSSession $session -ListAvailable

ModuleType Name ExportedCommands

---------- ---- ----------------

Manifest ActiveDirectory {Set-ADAccountPassword, ...

Manifest ADDeploymentWF Invoke-ADCommand

Manifest ADDSDeployment {Install-ADDSForest, Add...

Manifest AppLocker {Set-AppLockerPolicy, Ne...

Manifest Appx {Remove-AppxPackage, Get...

Manifest BestPractices {Get-BpaResult, Set-BpaR...

Manifest BitsTransfer {Complete-BitsTransfer, ...

Manifest BranchCache {Get-BCNetworkConfigurat...

Manifest CimCmdlets {Get-CimSession, New-Cim...

Manifest DirectAccessClientComponents {New-DAEntryPointTableIt...

Script Dism {Use-WindowsUnattend, Ad...

Manifest DnsClient {Resolve-DnsName, Remove...

Manifest International {Set-Culture, Get-WinHom...

Manifest iSCSI {Disconnect-iSCSITarget,...

Manifest IscsiTarget {Convert-IscsiVirtualDis...

Manifest Kds {Get-KdsConfiguration, G...

This example reveals a great trick for discovering the modules that exist on a remote machine. In chapter 10, we’ll also explore a technique called implicit remoting, which lets you load those remotely stored modules into your own, local PowerShell session—which means once you’ve discovered modules, it’s easy to start using them.

5.4.2. Loading extensions

To load a PSSnapin, you add it to your session:

PS C:\> Add-PSSnapin microsoft.sqlserver.cmdletsnapin.100

Specify the PSSnapin name as revealed by Get-PSSnapin –Registered. Modules are loaded similarly, although in this case you import them:

PS C:\> Import-Module storage

Note that some modules are script modules, meaning they can load only if you’ve enabled execution of scripts. If you try to load one on a default PowerShell configuration where scripting isn’t enabled, you’ll get an error message. You’ll need to enable script execution, which we cover inchapter 17, or you can read the help for the Set-ExecutionPolicy command to learn how to load such a module.

Note

For modules stored in one of the PSModulePath locations, you won’t need to import the module explicitly. PowerShell will import the module automatically through its autoloading feature the first time you try to run one of the commands in the module.

If modules aren’t stored in one of the PSModulePath locations, you can import them by providing the full path to the module’s folder, rather than providing only the module’s name. For example, a module stored in C:\MyModules\Fred would be loaded by running Import-Module C:\MyModules\Fred. Because that module doesn’t live in one of the autosearched locations, it wouldn’t be autoloaded, nor would it be revealed by running Get-Module –ListAvailable.

5.4.3. Discovering extensions’ additions

Once an extension is loaded, you can see what commands it contains:

PS C:\> Get-Command -Module storage

CommandType Name ModuleName

---------- ---- -------

Alias Initialize-Volume storage

Function Add-InitiatorIdToMaskingSet storage

Function Add-PartitionAccessPath storage

Function Add-PhysicalDisk storage

Function Add-TargetPortToMaskingSet storage

Function Add-VirtualDiskToMaskingSet storage

Function Clear-Disk storage

Function Connect-VirtualDisk storage

This technique works with both modules and PSSnapins. From here, you can ask for help on a specific command to learn how to use it.

Note

The –Module parameter has an alias, -PSSnapin, which makes it also legal to run Get-Command –PSSnapin My.Snapin.Name. It’s the same effect.

Keep in mind that extensions can add more than commands; they can also add providers. To see what providers are available on your machine, run the following:

PS C:\> Get-PSProvider

Name Capabilities Drives

---- ------------ ------

Alias ShouldProcess {Alias}

Environment ShouldProcess {Env}

FileSystem Filter, ShouldProcess, ... {C, A, D}

Function ShouldProcess {Function}

Registry ShouldProcess, Transact... {HKLM, HKCU}

Variable ShouldProcess {Variable}

WSMan Credentials {WSMan}

Certificate ShouldProcess {Cert}

This is the list from a standard Windows 8.1 machine. You may see more providers if you have other modules loaded such as those for Active Directory or SQL Server. In a newly opened PowerShell console, you may not see the WSMan or Certificate provider in the list until you have accessed them because they aren’t part of the core PowerShell load.

We didn’t filter for a specific module or PSSnapin, so you’ll see all available providers. Remember that you can ask for help on a provider (help alias, for example) once it’s loaded.

5.4.4. Managing extensions

You can use the following commands to manage extensions:

· Remove-Module unloads a module.

· Get-Module displays a list of all loaded modules in the current PowerShell session.

· Remove-PSSnapin removes a PSSnapin.

· Get-PSSnapin displays a list of all loaded PSSnapins in the current PowerShell session.

Generally, when you remove a module or a snap-in all of its commands are removed from your PowerShell session. But be aware that some items, such as custom type or format extensions, might persist. This may not be a big deal, but you may get an exception if you reimport or readd the module or PSSnapin in the same session. If so, you can ignore the error message. Using a new PowerShell console is one way to avoid these messages.

5.5. Command name conflicts

When you start loading up a bunch of modules or PSSnapins, it’s obviously possible for two of them to contain commands having the same name. So what happens?

By default, when you run a command, PowerShell runs the last version of that command that was loaded into memory—that is, whichever one was loaded most recently. That command has the effect of “hiding” commands having the same name that were loaded earlier. There’s a specific purpose for that proxy functions, which we’ll discuss in chapter 37.

But you can access any specific command you want to by providing a fully qualified name. That name combines the name of the PSSnapin or module that contains the command you want, a backslash, and then the command name. ActiveDirectory\ Get-ADUser, for example, will run the Get-ADUser command contained in the ActiveDirectory module or PSSnapin, even if some other extension has more recently loaded a different “Get-ADUser” command.

An alternative is to use the –Prefix parameter of Import-Module, which enables you to add a prefix to the noun for each of the cmdlets (or functions) in your module. Assume you had a module called MyModule that contains

Get-MyNoun

Set-MyNoun

If you import it as Import-Module MyModule –Prefix DJR, the functions would have a prefix applied and would become

Get-DJRMyNoun

Set-DJRMyNoun

Now you can run these commands without worrying about naming collisions.

In PowerShell v4, you can also get modules by a fully qualified name. If for some reason you have two modules with the same name but they’re different versions (don’t ask us why you would), you can specify the module you want. FullyQualifiedname is a special hash table of the format @{ModuleName="MyModule";ModuleVersion="1.0"}. Both Get-Module and Get-Module –ListAvailable provide the version number and name as part of the default display:

PS C:\> Get-Module -FullyQualifiedName @{ModuleName="Applocker";

ModuleVersion="2.0"} -ListAvailable

Directory: C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules

ModuleType Version Name ExportedCommands

---------- ------- ---- ----------------

Manifest 2.0.0.0 AppLocker {Get-AppLockerFile...

You’ll want to include –ListAvailable. If this is the module you wanted to import, the best thing is to pipe it to Import-Module:

PS C:\> Get-Module -FullyQualifiedName @{ModuleName="Applocker";

ModuleVersion="2.0"} –ListAvailable | Import-Module

Now, there’s an odd quirk here, or perhaps a bug. If you specify a version but the only version you have is newer, you’ll get the newer version. We assume the reasoning is that the newer version is backwards compatible. But if you ask for a version that’s newer than the one that’s installed, you’ll get nothing. In our example, the AppLocker module is at version 2.0. If we ask for version 1.0, we’ll get this version. But if we ask for version 3.0, we’ll get nothing.

5.6. Managing module autoloading

PowerShell has a built-in variable, $PSModuleAutoLoadingPreference, that controls autoloading behavior. You probably won’t see this variable if you run Get-Variable. PowerShell’s default behavior is to autoload all modules. But you can explicitly create the variable and assign it one of the following values:

· All—Automatically imports a module on first use of any command contained in the module.

· ModuleQualified—Modules are loaded automatically only if you use a qualified command name, such as MyModule\Do-Something. Running only Do-Something wouldn’t load the module containing that command.

· None—Modules aren’t loaded automatically.

This variable doesn’t prevent you from explicitly loading a module using Import-Module. But autoloading makes it easier because all you have to do is run the command and let PowerShell handle any necessary module imports. Be aware that this applies only to modules; you still need to manually add a PSSnapin before you can use any of its commands.

5.7. Summary

Managing PowerShell extensions is one key to being successful with the shell. Much of the functionality you’ll rely on to accomplish administrative tasks comes from extensions rather than from the shell’s core functionality. Being able to find, load, and inventory extensions is the primary way you can get needed functionality to the shell and have it available for your use.