A while ago I decided to split a number of my modules up as they were becoming messy. Instead of standalone modules I now have modular modules.

The split introduced something of a version management problem for me, so I made up a set of module management functions and scripts to see me through from development to release and maintenance of released modules.

This article explores the module tree and looks at the installation and update functionality.

Modular modules

The module structure I use is hierarchical, the root module contains functions which are shared by other modules, functions involved in management, and functions which have no better home.

A few modules are still standalone, these are only bound to the hierarchical structure by the update mechanisms I incorporated into Indented.

Managing updates

Module management comes in three flavours.

  1. Manual updates
  2. Semi-automatic updates
  3. Automatic updates

All automatic components are part of Indented.Common and may be viewed in full by exploring the Indented.Common.psm1 file.

As automatic update components are part of Indented.Common they cannot be used to perform the very first installation of Indented.Common. Taking a bit of a hint from Lee Holmes I wrote a web-installation script which may be used to install Indented.Common.

Manual updates

Manual updating is, of course, fully supported. Files can be downloaded manually from their respective home pages, installation is entirely in the control of the user.

Dependencies must still be honoured, manifest files (psd1) technically enforce this through use of the RequiredModules option.

Semi-automatic updates

My web server hosts a module version control file which is consumed by Get-IndentedModule. The file is updated every time I update and release a version of one of my modules. This file is merged with the output from "Get-Module -ListAvailable" to give a picture of local vs server versions.

Updates are still manually invoked, a user can elect to update a module using Install-IndentedModule. For example:

An attempt is made to reduce the number of calls to the web server, if running in a pipeline the call executes during begin.

Automatic updates

Automatic updates, if enabled (it’s disabled by default), execute for installed modules only. If a module has not been installed one of the two manual processes above must be used.

To minimise the degree of intrusion the update process is executed when Indented.Common loads rather than through a scheduling mechanism. This means removal of the module remains nothing more than deletion of the module folder. The command is found at the very bottom of Indented.Common.psm1.

To keep modules clean, an update (through Install-IndentedModule) will purge existing content.

This also destroys the file which dictates how updates are performed if Indented.Common is updated. To overcome this the automatic update function, Start-IndentedAutoUpdate, reads and caches the file in memory, writing back much of the same content to a new file.

Finally, to attempt to avoid errors finding a way in, the meaningful content of the auto-update configuration file is hashed. The hash is checked to verify the consistency, if the consistency check fails the file is dumped and regenerated. Perhaps overkill, but it was interesting to write.

Development to test and release

The script to execute this is a bit too environment specific to share. The general process is as follows:

  1. If test release copy the module $env:PsModulePath (first value).
  2. If live release:
    1. Update version numbers (minor unless explicitly stated to be a major update),
    2. Commit pending changes into TFS (tagged with the version number as a comment).
    3. Copy the module to $env:PsModulePath (first value).
    4. Package the module into a zip file and upload the zip file to my web server.
    5. Regenerate the module list consumed by Get-IndentedModule and upload the file to my web server.

A cron job on the web server takes it from there, setting appropriate permissions and putting the file in the right place.

Version number updates are handled via a pair of functions which deal with reading and writing module manifest files.

Get-ModuleManifest is a simple function which attempts to read the manifest as a hash table from a fixed location (the folder I use for development).

Update-ModuleManifest allows arbitrary changes to properties, then uses splatting to pass the changed manifest information back to New-ModuleManifest.

Perhaps the most frustrating thing about this process is the need to continually restart PowerShell to get the updated instance of the module. In the end I simplified that process by setting up a shortcut in exactly the way I wish, then simply creating a new process based on it:

I like it, it’s extremely simple and leaves me with a console which has focus. No need to reach for the mouse and no need to alt-tab through everything else.

Leave a Reply

Your email address will not be published. Required fields are marked *