How to make sure PowerShell module manifest (.psd1) is used

1.7k views Asked by At

I created a PowerShell module MyUtil.psm1 and a manifest file MyUtil.psd1 for it. In the psd1 file it has the prefix defined to prevent name conflicts for exported functions:

DefaultCommandPrefix = 'MyToolbox'

This way, after running Import-Module .\MyUtil.psd1, a function like Get-Command in the psm1 file will be Get-MyToolboxCommand, everything is fine. But if someone runs Import-Module .\MyUtil.psm1 to import the psm1 file directly, the psd1 file is simply not used and the prefix I want won't be applied.

If I want to prevent this (importing MyUtil.psm1 directly), is there a way to ONLY allow importing the corresponding psd1 manifest file instead of the psm1 file? Or a programmatic way to detect that this module was not imported through psd1 so I can warn the user to use psd1?

2

There are 2 answers

0
Rajiv Iyer On

You can use: #Requires

For example:

Require that Hyper-V (version 1.1 or greater) is installed.

#Requires -Modules @{ ModuleName="Hyper-V"; ModuleVersion="1.1" }

Requires that Hyper-V (only version 1.1) is installed.

#Requires -Modules @{ ModuleName="Hyper-V"; RequiredVersion="1.1" }

Requires that any version of PSScheduledJob and PSWorkflow, is installed.

#Requires -Modules PSWorkflow, PSScheduledJob

About Requires

0
SamuelWarren On

Ok, this is a bit annoying, but it works. You can use the Export-ModuleMember cmdlet with no args to stop the psm1 from exporting anything, but you need to send a value from the psd1 to the psm1 during the import. That way we know when we're being called with the psd1. So first off, add a value to the PrivateData hashtable in your PSD:

    PrivateData = @{
    FromPSD = $true       
    PSData = @{

Then you need to access it in the psm1 file. You can in a function, but not inline, so we have to stick it into a function.

function Get-PD
{
    [CmdletBinding()]
    $MyInvocation.MyCommand.Module.PrivateData
}

(I totally stole this from this SO answer Accessing PrivateData during Import-Module).

Then you wrap it all up by calling this code in the module which will get run as the module is loaded.

$MyPD = Get-PD
if($MyPD.Count -eq 0)
{
    Export-ModuleMember
}

Now, if you don't want this pesky extra function to be referenced when the module is loaded, you'll need to populate the FunctionsToExport in the psd1 file with the list of functions you want the users to have access to.