Fajela Tajkiya
Fajela Tajkiya

Reputation: 694

Making a PowerShell script portable with its dependencies

I am working on a PowerShell script that requires a specific PowerShell module to be installed on the machine where the script is run. This module provides additional functionality that is crucial for the script to work correctly.

I would like to make my script portable, so that I can put my script and the module in a folder and copy it to another machine and run it directly without the need for manual installations. Is this possible? I have tried searching for a solution online, but I couldn't find anything that specifically addresses my problem.

Upvotes: 5

Views: 2556

Answers (1)

zett42
zett42

Reputation: 27766

Preparations

Copy the module directory (using the same directory structure as the installed module) into a sub directory where your script is located.

For example, the directory structure could look like this for the Pester module:

  • Script Directory
    • YourScript.ps1
    • Modules
      • Pester
        • 5.4.0
          • pester.psm1
          • pester.psd1

When the module is available in PSGallery you can alternatively save the module without installing it first. For example to save the Pester module from PSGallery in a directory structure like above:

md Modules
Save-Module -Name Pester -Path Modules

Loading the portable module

You basically have two ways to load the module.

  1. Explicitly using Import-Module, specifying the full path of the module directory, without the version sub directory.
  2. Implicitly by inserting the "Modules" path into the $env:PSModulePath variable. This enables simple import using just the module name and module auto-loading (as if the module were actually installed). This might be preferred if your script is split into multiple files. In this case you only have to modify the root script and any scripts loaded by the root script will automatically use the portable module(s).

Example for using Import-Module:

# Import module from a sub directory relative to the current script
Import-Module $PSScriptRoot\Modules\Pester

# Now using functions from portable Pester module
Describe 'Portable Module Test' {
    It 'Should have loaded portable module' {
        $portableModuleFilePath = (Get-Item $PSScriptRoot\Modules\Pester\*\Pester.psm1).FullName
        (Get-Module Pester).Path | Should -Be $portableModuleFilePath 
    }
}

Example for using $env:PSModulePath:

# Insert portable module directory at the front of PSModulePath so our portable 
# version of the module will be preferred over any installed version.
# This is only in script scope, the system environment variable won't be modified!
$env:PSModulePath = "$PSScriptRoot\modules;$env:PSModulePath"

# Now using functions from portable Pester module, which PowerShell loads automatically.
Describe 'Portable Module Test' {
    It 'Should have loaded portable module' {
        $portableModuleFilePath = (Get-Item $PSScriptRoot\Modules\Pester\*\Pester.psm1).FullName
        (Get-Module Pester).Path | Should -Be $portableModuleFilePath 
    }
}

Upvotes: 8

Related Questions