Must Powershell modules be placed in separate folders? - powershell

Using PowerShell 2.0
According to what I've read online, user-created powershell modules must each reside in their own directory. For example if I create a module called MyModule.psm1 it must reside in a folder called MyModule and reside in any directory listed in $env:PSModulePath.
If I have many modules for a project, it seems silly to me to have to create a separate folder for each one. Is this really necessary? Why? Any elegant way around it?

If you want to just have the .psm1 file, you can import it by giving the path to the file itself rather than just the name of the module.
For example:
import-module c:\mymodules\folder\themodule.psm1
With this technique you can have as many modules as you want in the same folder. I don't know that I'd recommend this, but it does work.

PowerShell modules can consist of more than one file, for instance for providing multi-language help or by splitting the functionality into several files. So yes, it's necessary.

It's not ideal, but you could create junctions (MSDN) using Sysinternals junction.exe. That would allow you to store all of the actual data in one folder, but reference it using different paths.
[MSDN] Hard Links and Junctions
Assume that you had three (3) stand-alone .psm1 module files in a folder named Modules in your $env:UserProfile\Documents\WindowsPowerShell\Modules directory.
You can use several junction.exe commands to create junctions (links) that point to the "real" Modules folder on the filesystem.
$ModulePath = '{0}\Modules' -f (Split-Path -Path $Profile.CurrentUserCurrentHost -Parent);
junction.exe $ModulePath\Foo $ModulePath\Modules;
junction.exe $ModulePath\Bar $ModulePath\Modules;
junction.exe $ModulePath\Trevor $ModulePath\Modules;
Here is what it looks like when you navigate into one of the junctions, for example, Foo.
As far as Windows PowerShell is concerned, you are in the Foo directory, which matches the Foo.psm1 file name. It should ignore the rest of the files in that folder.
Now, you can run Get-Module -ListAvailable, and you should see a list of the modules in your user module directory.

Related

Proper installation of powershell modules for all users

I've looked at this document, and it lists $Env:ProgramFiles\WindowsPowerShell\Modules (%ProgramFiles%\WindowsPowerShell\Modules) as a good place for installing modules for all users. About naming, it says:
Use the Correct Module Directory Name
A "well-formed" module is a module that is stored in a directory that
has the same name as the base name of at least one file in the module
directory. If a module is not well-formed, Windows PowerShell does not
recognize it as a module.
The "base name" of a file is the name without the file name extension.
In a well-formed module, the name of the directory that contains the
module files must match the base name of at least one file in the
module.
For example, in the sample Fabrikam module, the directory that
contains the module files is named "Fabrikam" and at least one file
has the "Fabrikam" base name. In this case, both Fabrikam.psd1 and
Fabrikam.dll have the "Fabrikam" base name.
C:\Program Files Fabrikam Technologies
Fabrikam Manager
Modules
Fabrikam
Fabrikam.psd1 (module manifest)
Fabrikam.dll (module assembly)
However, I'm still unclear; suppose I have a module composed ABC.psd1 and ABC.psm1. Am I understanding correctly that it should be installed in $Env:ProgramFiles\WindowsPowerShell\Modules\ABC, with the .psd1 and .psm1 directly under that directory?
Looking at some of the microsoft modules, I see, for example:
C:\Program Files
WindowsPowerShell
Modules
AzureRM
5.7.0
AzureRM[.psd1,psm1]
So at least based on the referenced document, it breaks the rule of "well-formed module" since the statement does not seem to allow for that 5.7.0 directory, or does not talk about a recursive search. Is that a hierarchy specifically intended for versioning, is it of the developer's choice? Even for versioning, it doesn't match the recommendations in the above document, for "Using Multiple Versions of a Module" which suggest it is added to the directory name, not as a subdirectory.
The gist of my question is this:
Is there a better explanation on how powershell searches for modules in this directory, with respect to nesting?
Suppose as my product grows, I have a second module DEF.psd1. Should I group under a company or product folder, and will all versions of powershell be happy with this (that is, without me altering the PSModulePath).
e.g.:
C:\Program Files
WindowsPowerShell
Modules
My Company
ABC
ABC[.psd1,psm1]
DEF
DEF[.psd1,psm1]
I am looking to support Powershell 3.0 and later. Also, I am noticing that the powershell ISE module browser uses different rules for searching modules, than powershell itself. For example, using my proposed hierarchy with a company name works fine in powershell, ISE, and user scripts, but breaks the ISE module browser which gives a "cannot find module" error when clicking on "Show details".
Looks like you pretty much have this answered. Not sure why/how the AzureRM module has a versioning folder...but the module was created by Microsoft so maybe they know a loop hole.
In my experience and in the documentation I've read, the proper file structure is what you have in your example, except WITHOUT the 'My Company' folder. How you named the folders and the .psm1/psd1 files (with the same base name) is correct. In fact, for a minimal script based module, all you need is the .psm1 file and it will work (load whatever functions are in the file), although generating a module file with New-ModuleManifest doesn't hurt. As mentioned in the comments, versioning can then be tracked and recognized by PowerShell in the .psd1 file.
Now, I've never put a module in the ProgramFiles folder for all users but I imagine it uses the same rules as the user based folders (they are just paths in an enviroment variable that powershell looks at).
I've also used the link below as a method or template for building PowerShell modules that are easy to maintain:
http://ramblingcookiemonster.github.io/Building-A-PowerShell-Module/
You can ignore the parts you aren't interested in or not using (folders for tests or views or using a Git repo)...the base structure works as well as the technique for loading individual functions with the .psm1 file.

How to share a Powershell psm1 across Azure Functions

You can create a modules folder and place a psm1 file there for auto loading. Is there a way to share that psm1 across functions in the same App Service?
Yes, you may move your modules folder up the directory tree and place it under wwwroot, e.g. D:\home\site\wwwroot\mymodules. Auto-loading will not occur in this setup, so you will need to explicitly add the Import-Module command in your PowerShell script, e.g.
Import-Module "D:\home\site\wwwroot\mymodules\MyScript.psm1";
If you suspect that MyScript.psm1 is already installed on the system and need to override it with your version, add the -Global flag as follows
Import-Module "D:\home\site\wwwroot\mymodules\MyScript.psm1" -Global;

Where to put non-essential .pl files in a distribution?

I would like to include a few additional .pl files in my CPAN module. These files are not essential to use the module, but are provide useful functionality/glue when the module is used in some common frameworks and applications.
Currently, I just include the .pl files in a "extras" directory of the distribution. This has the drawback that the files are not installed on make install. Is there a way to include them in the installation and where should they go? (They aren't executables and don't belong in "bin".) Would "share" make sense? Or are these kinds of files usually just not installed and it is left to the user to get them out of the .tgz archive and use as needed?
I use Dist::Zilla to manage my distribution.
I would suggest the following:
If they're actual complete programs or are almost complete, polish then up and make them standalone items that could go into /bin with POD of their own.
If they're utility glue, make a ::Utils module for them to live in and document their usage.
If these are useful code snippets but not something you can install somewhere or are sample usages or handy idioms, create a ::Cookbook all-POD module and include them there with the appropriate illuminating explanation for each one.
I don't know exactly how Dist::Zilla works, but the resulting archive has to be compatible with what ExtUtils::MakeMaker creates.
When you create a module with module-starter, it creates a module template using ExtUtils::MakeMaker. It creates several files and directories like the lib directory where your module lives and the t directories where your tests live.
One thing it doesn't create is a bin directory. However, if you create a bin directory, and you put files under this directory (such as Perl scripts), these files will be installed under the bin directory in your Perl's distribution and linked to /usr/local/bin or /usr/bin. Would this be a good place for your scripts?
I liked #Joe's answer, except that in my case the files were WebWork macros -- individual .pl files that make my module callable from WebWork end-user's code. So they don't fit under any of the categories discussed here, and as .pl files can't be made a module.
This is what I ended up doing:
put all .pl macro files into 'extras/WebWork' in the distribution.
add to "dist.ini" file a [ShareDir] stanza with dir = extras property.
now the WebWork admin can install my distribution from CPAN and then use perl -MFile::ShareDir -e 'print File::ShareDir::dist_dir("Statistics-R-IO")' to find the macros and make them available in WebWork.

PowerShell .ps1 file cmdlets in a module

Right now I have a collection of .ps1 PowerShell script cmdlets (they can take parameters) that are related to each other, but each is fairly involved. I'd like to organize them into a module, preferably while keeping them in separate files.
What is the best way to do that? Can I keep them in separate .ps1 files, and use a module manifest to say they are part of the module? Do I need to dot source the files into a .psm1file in order to keep the files separated? Or is it unwise to separate them into separate files?
Ultimately you will need to have at least one .PSM1 file that either contains the variable and function definitions you want to export from your module OR dot sources in those definitions from .PS1 files. By default, variables are not exported while all functions are exported. If you want to modify that behavior, then use Export-ModuleMember -Variable MyExportedVariable -Function *-* at the end of the PSM1 file.
If much of the code in your PS1 files is internal implementation details it should be fine to keep in PS1 files. Just remember that the PSM1 would export the "public" facing interface of your module.

How to ship powershell module to production environment?

I have written all my powershell functions in a ps1 file.
In another ps1 file ,it is being dot sourced and function are being called.
When i look for better methods i came to know that putting all the functions as modules (.psm1) is better option.
But for .ps1 file i can simply it in a folder and ship it.
With .psm1 file ,it says i have to add it to particular location so that it can be imported.
how to provide .psm1 file to customer then ? should we instruct them to copy to the mentioned location before using it ? (if we don't ship via msi)
Technically you can import psm1 files via path but that isn't the best user experience. If you put the file in a folder under either $home\documents\WindowsPowerShell\Modules or $pshome\Modules then the user can import based on just the name of the psm1 file. Finally, you can put the psm1 file in any location you want and if you modify the PSModulePath environment variable to include that directory, PowerShell will search for modules in that dir.