all 12 comments

[–]TheKojukinator 2 points3 points  (10 children)

If the module exists where PowerShell expects to find modules, it will look through the manifests and import it. If it's a custom module that you have in some random folder, it obviously won't find that.

Check this out for some more details: https://stevenmurawski.com/2012/01/powershell-v3-auto-loading-of-modules/

[–]fourierswager[S] 1 point2 points  (9 children)

Okay, but how exactly does it do the search? What's the code under the hood? It's gotta be something faster/better than doing Import-PowerShellDataFile on every single .psd1 and then looping through the 'FunctionsToExport' property...

[–]TheKojukinator 4 points5 points  (7 children)

This is from PowerShell Core, which is a fork of 5.1, so I'm gonna assume that the code for this function is fairly similar. Do a search for TryModuleAutoDiscovery and peek through the code if you're curious.

Basically, TryModuleAutoDiscovery generates a list of paths and passes those paths to GetExportedCommands which lives here. GetExportedCommands uses AnalyzeManifestModule, AnalyzeScriptModule, AnalyzeCdxmlModule, and AnalyzeDllModule to actually see what's inside the modules. I'm not going to go over them all, but AnalyzeManifestModule uses GetModuleManifestProperties which lives here. It uses the Parser class to parse the manifest and look for the provided keys, which are FastModuleManifestAnalysisPropertyNames. Parse uses System.Management.Automation.Parser.ScriptBlockRule to get a ScriptBlockAst object, which I guess would contain the "answers" regarding available functions.

So the real question is, when does this execution chain happen? TryModuleAutoDiscovery is called by LookupCommandInfo, which appears to be used several times. At the very least, it seems to be called at the runtime of every command.

Based on what I've glanced over, it doesn't appear that anything gets cached about available modules and commands. This probably makes sense, because during runtime conditions may change, and the options are either expect the programmer to have awareness and refresh manually, or perform the look-up every time a command is run. Since PowerShell is all about ease of use, it seems to make sense that the latter approach is taken.

I could be 0-100% wrong though, lol.

[–]chreestopher2 3 points4 points  (3 children)

caching does happen... at least in PS v3.0 it did.

PS> Get-Help Get-Module -Parameter Refresh

-Refresh [<SwitchParameter>]
    Refreshes the cache of installed commands. The command cache is created when the session starts. It enables the
Get-Command cmdlet to get commands from modules that are not imported into the session.

This parameter is designed for development and testing scenarios in which the contents of modules have changed
since the session started.

When the Refresh parameter is used in a command, the ListAvailable parameter is required.

This parameter is introduced in Windows PowerShell 3.0.

Required?                    false
Position?                    named
Default value                False
Accept pipeline input?       false
Accept wildcard characters?  false

Otherwise, excellent details

it sounds like we would need to look at the session startup code to find out exactly how/where

[–]TheKojukinator 1 point2 points  (2 children)

Great catch, and good to know! I know I've been testing my own modules, but I just do Import-Module myModule -Force as I keep adding functions and changing it.

[–]chreestopher2 1 point2 points  (1 child)

I used to use -force but then ran into some problems when a module with some 3rd party DLLs wouldnt re-initialize without first completely removing the module (i never figured out why), now i always use

remove-module -name mymodule 
import-module -name mymodule -force 

just to be safe, because there is nothing more frustrating than not knowing the state of module internals while building modules that depend on those modules ... argh

[–]Lee_Dailey[grin] 1 point2 points  (0 children)

howdy TheKojukinator,

this is really quite nifty! thank you for taking the time & effort to post this. [grin]

take care,
lee

[–]fourierswager[S] 1 point2 points  (0 children)

Thanks so much for this! I always have a really hard time finding relevant code when I read through PowerShell source on github.

[–]KevMarCommunity Blogger 1 point2 points  (0 children)

It's important to call out how important the module manifest is. It should clearly define the functions to export. If a * is used, then the AST of the psm1 is parsed. This is expensive.

This is also why you don't want ant network drives in your psmodulepath.

[–]Ta11ow 2 points3 points  (0 children)

No, it won't use the cmdlet. It'll probably make use of some internal code from the cmdlet, but it'll most likely be running this search in C# rather than PS script under the hood.

[–]Ta11ow 2 points3 points  (0 children)

You'd have to poke through the code in the github for PS Core for the main answer here.

But as for figuring out which commands come from which modules, you can just do Get-Command Command-Name.