PowerShell .ps1 file cmdlets in a module - powershell

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.

Related

How do I import a new PowerShell cmdlet?

I've written a PowerShell cmdlet in C#.
Where do I copy the library at this point?
And how do I import it into PowerShell so that I can use it?
There are two ways to load your new cmdlet.
Import Cmdlets Using Modules. Here you either put your cmdlet DLL into a system-recognized path that will allow you to load a module with a simple name (e.g. Import-Module MyModule), or you can put it in an arbitrary directory for which you need to specify a complete path (e.g. Import-Module C:\code\MyModule.dll). If you have only a single DLL and no dependencies, you can actually give the DLL as shown. Typically, though, you will also want to create a manifest using New-ModuleManifest (creating, e.g., a MyModule.psd1 file) then pass that psd1 file rather than the dll to Import-Module.
Create a Windows PowerShell Snap-in. This requires writing one additional C# class, quite small, that provides the glue necessary to treat your cmdlet as a snap-in. Then you have to register the snap-in with the installutil program and finally load the snapin with Add-SnapIn. (See also How to Register Snap-ins...)
Curiously, almost all articles that talk about writing cmdlets suggest the snap-in approach, but this is simply because that technique has been available since PowerShell version 1, while modules did not come along until version 2. Everything I have read, though, suggests essentially that the snap-in approach is deprecated to the simpler--and more flexible--module approach.

Must Powershell modules be placed in separate folders?

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.

What are .ps1 files for in PowerShell modules?

I'm currently learning about PowerShell modules. If you're using a .psd1 manifest file, you have the option to use .ps1 script files as well as .psm1 manfiest files. Why do you need both?
I created a module with both, with the .psm1 set as RootModule and the .ps1 set in ScriptsToProcess and I've noted some differences, but I'm not sure what they add up to.
If I add Write-Output statements to both, on import the output is displayed for .ps1, but suppressed for the .psm1. Write-Warnings are displayed for .psm1.
If I run the Get-Command prefix for the module prefix, functions from the .psm1 are listed with the module name whereas functions from the .ps1 file are listed with a blank module name.
The section of your manifest in which you place the references to the Ps1 files determines how they are executed.
In your case:
The ScriptsToProcess will execute the listed PowerShell scripts in the caller's environment prior to importing the module. This makes me think of them as prep scripts.
This is because files listed here are not meant to contain functions; it's meant to be a script. If you want additional functions accessible by your module you have a few options:
List them in NestedModules
Include them in your module
Try listing them in the functions to the export section of the manifest. (I have not tried this method, but it's my understanding that it will work the way you want no matter where the function is located.)

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.

Load Multiple Modules (.psm1) using a single psd1 file

I want to organize functions into multiple .psm1 files and have them loaded by a single Module Manifest file (.psd1) -- such that Only the .psd1 file would need to have the same name as the module.
I think it should be possible. Can anyone help me out please ?
Launch the Powershell ISE
Use the New-ModuleManifest command
Follow the instructions here - How to Write a Module Manifest. When asked for nested modules, key in the module as Modulepath\Modulename.psm1
Finally, once the .psd1 file is created, load / import it using Import-Module <<module-name>>
You can load them manually in your main module psm1 file using Import-Module calls or by specifying them in the NestedModules key in the manifest file (psd1)