Skip to content

Instantly share code, notes, and snippets.

@magnetikonline
Last active February 21, 2023 15:03
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save magnetikonline/2cdbfe45258c0cc3cf1530548baf30a7 to your computer and use it in GitHub Desktop.
PowerShell Import-Module with .ps1 quirk.

PowerShell Import-Module with .ps1 quirk

Well, not so much a quirk - but an interesting anti-pattern I found in some (poor quality) PowerShell. Documenting the "how and why" so I can refer to it again if needed!

Example

We have two files callme.ps1 and functions.ps1:

functions.ps1:

function Magnetik-Function() {
	Write-Output "This is Magnetik-Function"
}

callme.ps1:

Import-Module -Name ($PSScriptRoot + "\functions.ps1")
Magnetik-Function

Note that callme.ps1 incorrectly uses Import-Module against a .ps1 file (not a module) - that's what exposes the quirk.

Running

PS Z:\> .\callme.ps1
This is Magnetik-Function
PS Z:\> .\callme.ps1
Magnetik-Function : The term 'Magnetik-Function' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included,
verify that the path is correct and try again.
At Z:\callme.ps1:5 char:1
+ Magnetik-Function
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Magnetik-Function:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

PS Z:\>

Weird? Why does Magnetik-Function() work once only?

  • When Import-Module is called in the first instance, functions.ps1 as a module doesn't exist - so the code is executed.
  • Executing functions.ps1 defines the function Magnetik-Function() in the scope of callme.ps1 and is able to be called successfully.
  • On the second and subsequent runs, the module functions is already known to PowerShell in this session - so is not re-run, thus Magnetik-Function() is never re-declared and we get failure.

We can also see this by a call to Get-Module:

PS Z:\> Get-Module

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.0        functions
Manifest   3.1.0.0    Microsoft.PowerShell.Management     {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Content...}
Manifest   3.1.0.0    Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Object...}

PS Z:\>

Note that functions as a module exists (it takes it's name from functions.ps1) - but because the file is not a true module (with a file extension of .psm1) it doesn't export any methods (functions).

In conclusion

  • If needing to bring in a .ps1 of functions/code - source them like so:

     . ($PSScriptRoot + "\functions.ps1")
  • When creating actual PowerShell modules, be sure to name such files correctly, with the right file extension - e.g. functions.psm1.

@stkb
Copy link

stkb commented Mar 20, 2018

Hope you won't mind me commenting here but I came here from google after experiencing this confusing behaviour myself.
This saved me a lot of time and headache so thanks!

@jakubin
Copy link

jakubin commented Jun 6, 2018

Great tip - thanks!

@timothies
Copy link

Thank you for the illustration, it was well written and very useful

@ishepherd
Copy link

Oh yay 😖 thanks for the writeup!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment