r/PowerShell 19d ago

Information third-party PS modules and the gotchas nobody warns you about

been burnt a few times now pulling in modules from the Gallery for managing third-party software and figured it's worth talking about. the big one for me was version conflicts. had a module pinned at one version in prod and a totally different one on dev because someone did an Install-Module without specifying -RequiredVersion. took way too long to figure out why the same script was behaving differently across environments. now I just always pin versions and keep a private repo rather than pulling straight from Gallery. worth calling out if you're still on MSOnline or the old AzureAD module - those are fully gone now, so if you haven't migrated to Microsoft.Graph yet that's going to be your most urgent version conflict to deal with. learned that one the hard way when automation started failing in prod. the other thing I didn't expect was how modules auto-load from PSModulePath without much fanfare. if you've got a sketchy or outdated module sitting somewhere in that path it can get pulled in without you realising. I've started being a lot more deliberate about Import-Module with explicit paths and setting $PSModuleAutoLoadingPreference to None in scripts that need to be predictable. also worth auditing what's actually in your module paths occasionally, especially on shared systems. working with stuff like PowerCLI or any vendor-specific module adds another layer too. they sometimes ship with their own dependencies that conflict with things you already have loaded. had a fun afternoon where PowerCLI's version of a shared assembly was fighting with something else in the session. ended up having to run it in a separate PS process just to isolate it. anyone else run into that kind of thing with vendor modules and found a cleaner way to handle it?

11 Upvotes

17 comments sorted by

7

u/KevMar Community Blogger 19d ago

I always try not to pin versions but it always bites me eventually and everything gets pinned in the end. I like to mirror modules into an internal psrepository to gate when new version are introduced into the environment.

The trick that you are looking for next is to use save-module to a local folder and set your $PSModuleRoot to that to isolate it from any other modules already on the system. All my scheduled stuff and pipeline stuff does that (if I don't need any system modules). This way it doesn't matter if different stuff uses different versions from your scripts.

2

u/tingnossu 18d ago

mirroring into an internal repo is honestly the move, we started doing that after a surprise breaking change in one of the Microsoft.Graph modules wrecked a pipeline, on a Monday morning and I never want to relive that, especially now with MSOnline fully gone and everyone scrambling to migrate auth methods at the same time.

1

u/dodexahedron 19d ago

I like to mirror modules into an internal psrepository to gate when new version are introduced into the environment.

This is the way, for things you have important dependencies on.

Internal repo, GP that deploys the repo config and sets a higher priority on it than psgallery, and internally signing/re-signing everything that goes in there.

1

u/KevMar Community Blogger 19d ago

I fully remove the external psgallery as a source across the environment when I do that.

6

u/pantherghast 19d ago

Looks like you could use a module that will paragraph your wall of text.

1

u/tingnossu 18d ago

touché, spent so long untangling MSOnline and AzureAD migration chaos that basic formatting went out the window lol. dependency hell will do that to you.

3

u/420GB 19d ago

I'm pretty sure you can just use the #Requires statement to specify a required version of a module. If you just did that you should have had no issues.

1

u/tingnossu 18d ago

Yeah #Requires helps and will actually throw a terminating error if the module isn't there, but it doesn't guarantee runtime API compatibility, had scripts pass, the version check just fine and then blow up anyway because the module's internals changed between versions, especially after the MSOnline and AzureAD forced migrations.

1

u/cottonycloud 19d ago

I don't really face the problem that you have because my modules don't have much overlap and I don't use as many. Usually, my development environment isn't version-pinned but production is.

1

u/tingnossu 18d ago

Keeping dev loose and prod pinned is exactly how we run it too, and even with minimal, overlap we, still hit an assembly conflict once from two modules shipping different versions of the same. NET dependency into the same session.

1

u/cottonycloud 18d ago

It really sucks when that happens. Wish there was something similar to pyproject.toml like Python…

0

u/BlackV 19d ago edited 19d ago

Sir, Please Formatting in your posts (for the old and blind people like me)

the big one for me was version conflicts. had a module pinned at one version in prod and a totally different one on dev because someone did an Install-Module without specifying -RequiredVersion

that is on you, your script should specify a module and version if a version is required

Install a new version of the module (and seeing what breaks) is EXACTLY why you have DEV, test the new version then move to prod

this also has 0 to do with 3rd party module, this covers ALL modules 1st, 2nd, 3rd

worth calling out if you're still on MSOnline or the old AzureAD module - those are fully gone now

again as per your previous post those are super super deprecated and should have been used in like the last 3? years, not worth calling out as they shouldn't function regardless

the other thing I didn't expect was how modules auto-load from PSModulePath without much fanfare

this has been the default behaviors since PS3 ? maybe 4, a further complication to this is powershell version and where you store your modules

ps 7 looks in

  • C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
  • C:\Program Files\WindowsPowerShell\Modules
  • C:\program files\powershell\7\Modules - FFFFFFFFFUUUUUUUUU why did you add this MS/powershell team
  • C:\Program Files\PowerShell\Modules
  • C:\Users\<username>\Documents\PowerShell\Modules
  • C:\Users\<username>\OneDrive\Documents\PowerShell\Modules - Or onedrive/google drive/home drive/etc *C:\Users\<username>\Documents\WindowsPowerShell\Modules
  • C:\Users\<username>\OneDrive\WindowsDocuments\PowerShell\Modules - Or onedrive/google drive/home drive/etc

ps 5 looks in

  • C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
  • C:\Program Files\WindowsPowerShell\Modules
  • C:\Users\<username>\Documents\WindowsPowerShell\Modules
  • C:\Users\<username>\OneDrive\WindowsDocuments\PowerShell\Modules - Or onedrive/google drive/home drive/etc

that's just x64, x86 adds the additional 32bit folders too, also include and custom module paths you've added

but you should be aware of your required modules and versions

had a fun afternoon where PowerCLI's version of a shared assembly was fighting with something else in the session

I have not used vmware powercli in ages, it was always one of the best behaved and designed modules, but you can confirm a modules dependencies (assembly wise) in its properties (again not limited to 3rd party modules, ms graph modules have been a chronic pain point for this)

There was a good post/reply in here the other day about module assembly version issues and how to work around them
I think there is even a module that will find this for you

the other thing you have not mentioned with additional modules is name overlap, import your powercli modules and run get-vm do the same with the hyperv module and then do the same again with the virtual machine manager modules (and possibly proxmox), you can address this by being specific and using the fully qualified name hyperv\get-vm, vmware.powercli\get-vm and so on

1

u/dodexahedron 19d ago

C:\program files\powershell\7\Modules - FFFFFFFFFUUUUUUUUU why did you add this MS/powershell team

For side-by-side installation of modules with system scope, on different powershell versions.

If you ever have powershell and powershell-preview installed at the same time, you'll see that in action. And you will both appreciate it for the separation and curse it every time you forget which one you installed what on.

1

u/BlackV 18d ago

Yeah, it just leads to mess

I now have psreadline installed in 50 places

And I ever do install module it has 0 idea that \7\ exists

It's not the end of the world, and I don't think it's always existed in 7 (could be wrong there but I seem to remember it appearing)

1

u/tingnossu 18d ago

fair point, threw this together between IR calls and it shows, cleaning it up now.

-1

u/Apprehensive-Tea1632 19d ago

Nope. Ps only has the one AppDomain so side by side (sxs) doesn’t work.

See if it’ll work using jobs- these are put into dedicated runspaces and a runspace is basically another powershell instance (much like multithreaded Perl).

This means overhead, and as runspaces are isolated, you need to serialize input and output. Type information is lost, so if you need that, you’ll have to rebuild OO using initial values you need to pass from the runspace.

Ex, pass .fullname to identify a file system object across the runspace boundary and then use get-item to get the filesystemobject instance.

Or, well, just start a new process. Of course you’ll still need a way to pass results.

1

u/tingnossu 17d ago

Worth clarifying though, that single AppDomain limitation is really a Windows PowerShell 5. 1 problem.