Deploying PowerShell Modules

on Wednesday, May 14, 2014

On MSDN there is an article on how to install PowerShell modules onto systems. One of the subsections is about Installing Multiple Versions of a Module. The basic idea behind it seems to continue to use PowerShells autoload feature, while using a Version number within the PowerShell descriptor file (.psd1 or manifest file) as a selector.

This seems to create a repeated hierarchy of directories. Each hierarchy starting with a folder name that is also versioned. Their example diagram is:

C:\Program Files
Fabrikam Manager
Fabrikam8
Fabrikam
Fabrikam.psd1 (module manifest: ModuleVersion = "8.0")
Fabrikam.dll (module assembly)
Fabrikam9
Fabrikam
Fabrikam.psd1 (module manifest: ModuleVersion = "9.0")
Fabrikam.dll (module assembly)

Followed by adding each of the versioned directories to the environment variable PSModulePath. Their example is:

$p = [Environment]::GetEnvironmentVariable("PSModulePath")
$p += ";C:\Program Files\Fabrikam\Fabrikam8;C:\Program Files\Fabrikam\Fabrikam9"
[Environment]::SetEnvironmentVariable("PSModulePath",$p)

Environment Variable Length Problems

Unfortunately, when extending the value of an environment variable, you also run the risk of hitting the 8191 character limit. Which can happen pretty quickly. Especially with frequent deployments.

One solution is to tightly control the rules in which a Module will be updated, versioned, and deployed. But, this removes a lot of flexibility and usually isn’t ideal. A great thing about PowerShell  is how quick the language can be used to get tasks done. Limiting it’s ability to be fluid and updateable doesn’t seem to fit with that design.

Potentially, the environment variable character limit problem could be alleviated by using the nested environment variable trick. (Grouping PS environment variables alphabetically before the PSModulePath variable seems to be the best approach). An example might be (written in shorthand):

%PS1_F8% = C:\Program Files Fabrikam\Manager Fabrikam8
%PS1_F9% = C:\Program Files Fabrikam\Manager Fabrikam9
%PS1_F% = %PS1_F8%;%PS1_F9%
%PSModulePath% = %PSModulePath%;%PS1_F%

Deploying Multiple Versions

All of these variables can be difficult to setup by hand. It would probably be best to have guidelines or standards at your company for Module development. Some good ones up front would be:

  • Determine a source control system for module development
  • Agree to the usage of a .psd1 file for each module
    • And, agree that a version number must be included. If the module is updated then the version needs to be updated as well. (In C# development, a build number is often attached to a specific build of a dll; but with PowerShell you probably don’t want the version number to contain the build number. More below.)
  • Determine the default module installation location to deploy to on target machines.
  • Have the deployment system inspect the .psd1 file for version information and construct the deployment path on target machines.
    • (Continuation on version number, from above:) If a machine already has a path with a matching version number, then that machine shouldn’t be updated. This is what requires development on the modules to always go hand-in-hand with updating the version number.
  • Have the deployment system update the machine’s environment variables with the deployments.

Pushing the Problem Down The Road

A solution like this doesn’t seem to fix the real problem: The need to add multiple versions of a module to machines without conflict and making them easily discoverable.

The recommendations from the PowerShell team are a good solution, but it looks like there is always room for improvement.

 

0 comments:

Post a Comment


Creative Commons License
This site uses Alex Gorbatchev's SyntaxHighlighter, and hosted by herdingcode.com's Jon Galloway.