So I am trying to refine my PowerShell module skills.
There is a parameter in the module manifest (.psd1) called 'FileList'.
It has the helpful documentation
# List of all files packaged with this module
FileList = #()
So, I have a module that contains a few .psm1 files. Perfect! (I thought). Perhaps I should list these files there?
However, the files I do list in FileList seem to get resolved to full path names when the module is imported, but none of the functions they contain are available?
Does this mean I need to list the .psm1 files in two places?
I had been listing them in NestedModules, which did import the functions, but I'm unsure if this is right?
Does anyone have any insight on specifically what FileList does and does not do, and how it should be used with a PowerShell module?
This parameter isn't used at the moment by PowerShell.
From the documentation:
List of all files packaged with this module. As with ModuleList, FileList is to assist you as an inventory list, and is not otherwise processed.
You can give a full list of files included. But you still have to use the NestedModules parameter (depending on the structure of your module), because it has a different purpose.
Related
I read a lot of the answers here and I can't seem to find what I am looking for. So please bear with me.
Each psm1 is a class.
I have:
Main.ps1
Modules/module01.psm1
Modules/module02.psm1
DLL/dllInQuestion.dll
I am trying to load a dll to use inside module02.psm1. I know that in order to do so I have to require it inside a .psd1. I created a psd1 for module02 and put it in the same folder and imported it like this "Import-Module" before the code but it didn't work.
I also tried to create a psd1 for Main.ps1 but it didn't work.
Can I require (using using module statements and Add-Type) all modules and dll inside a .ps1 script and require it inside a .psd1 for Main.ps1?
Thank you.
I've gathered and created quite a few Powershell functions that I use daily on my job. To make things easier to maintain and organized, I've created modules. Each module has its own folder with several files in it. Each file has one or more functions.
In the past, I've organized things as such:
\Modules\
\SystemTools\
Hotfixes.psm1
Services.psm1
SystemTools.psd1
\NetworkTools\
ActiveDirectory.psm1
Connections.psm1
NetworkTools.psd1
with Export-ModuleMember -Function in each psm1 file, an empty RootModule line in the manifest (psd1) file and all my psm1 files as an array on the NestedModules line in the manifest file.
But I'm not sure that's how it was intended to be used, and if it follows best practices regarding modules with several files.
So I've recently changed my Modules folder as such:
\Modules\
\SystemTools\
Hotfixes.ps1
Services.ps1
SystemTools.psd1
SystemTools.psm1
\NetworkTools\
ActiveDirectory.ps1
Connections.ps1
NetworkTools.psd1
NetworkTools.psm1
So I've
renamed all psm1 files to ps1
added a psm1 file where I dot source all ps1 files in the same folder
set the psm1 file as RootModule and no NestedModules
Questions
Both seem to work, but which one is better ?
If a function defined in the SystemTools module needs to use a function defined in the NetworkTools module, should I use Import-Module ? Isn't there a risk of circular dependency ?
I've been strugling with this for a while now. I intend to create new PowerShell module for my project. Aim is to package several custom cmdlets into standalone unit, which I could deploy to other machines via our Nexus repository (or via anything else).
Problem: Everywhere I look, I see tutorials packaging all PowerShell functions/cmdlets into single *.psm1 file. File is stored inside equally named directory, which actually represents module itself.
Question: Is there a way, how to separate each cmdlet/function into standalone file? If I have a module consisting of several cmdlets, it's not very convenient to put them all in single *.psm1 file.
Thanks
Matthew
You could also use a manifest file. "A module manifest is a .psd1 file that contains a hash table. The keys and values in the hash table do the following things:
Describe the contents and attributes of the module.
Define the prerequisites
Determine how the components are processed.
Manifests are not required for a module. Modules can reference script files (.ps1), script module files (.psm1), manifest files (.psd1), formatting and type files (.ps1xml), cmdlet and provider assemblies (.dll), resource files, Help files, localization files, or any other type of file or resource that is bundled as part of the module. For an internationalized script, the module folder also contains a set of message catalog files. If you add a manifest file to the module folder, you can reference the multiple files as a single unit by referencing the manifest." (Source)
So you can use ps1 files instead of psm1 files directly from psd1 files:
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = 'Get-WUList.ps1','Add-WUOfflineSync.ps1'
# Functions to export from this module
FunctionsToExport = 'Get-WUList','Add-WUOfflineSync'
Following up on #MatthewLowe - I've made my .psm1 a "one liner" as follows; this seems to work, provided that none of the scriptlets depend on one whose name is alphabetically after itself:
Get-ChildItem -Path $psScriptRoot\*.ps1 | ForEach-Object { . $_.fullname; Export-ModuleMember -Function ([IO.PATH]::GetFileNameWithoutExtension($_.fullname)) }
Just posting this answer which I found as I was actually wrinting question itself :-). I downloaded few PowerShell modules from internet and looked inside, I found answer there. But since I got stuck on this for few hours (new to powershell ;-)), I decide to post this anyway, for future generations :-P.
You can put your cmdlets (*.ps1 files) EACH into separate file. Store them inside your module directory and create *.psm1 file. Then, dot-source your *.ps1 cmdlets/functions into this *.psm1.
However, reference to current module directory where your *.ps1 files are stored must be provided like this
". $psScriptRoot/moduleFunc1.ps1" AND NOT LIKE ". ./moduleFunc1.ps1"
Enjoy
Matthew
I can see that without a manifest the default module name is set to the .psm1 filename.
But is there a way to set it within the module's code?
Also I would like to set the version in code.
If you are importing a binary module then the module version is pulled from the assembly metadata. However the name is simply the DLL's filename. For a script module (.psm1), you can't provide this info to PowerShell other than via a module manifest as Ansgar has already pointed out.
BTW you can get at the Name and Version properties of the module from within the module ($MyInvocation.MyCommand.ScriptBlock.Module.Name) but those properties are read-only.
I'm confused as to how PowerShell modules work.
I have downloaded and copied a module from a blogger. I've unblocked and extracted the .zip to %USERPROFILE%\Documents\WindowsPowerShell\Modules\SomeModule
In this folder is a .NET assembly that the module uses, but doesn't not contain compiled CmdLets. Instead, the commands are functions in a .psm1 file and a .psd1 file describes the manifest.
If I open PowerShell, the functions are available and work but I want to add my own function, so I have added it, however I cannot see it. I've restarted all PowerShell instances, removed the module and imported it again.
As a test, I renamed an existing, working function. Interestingly, after remove and import the function disappears instead of adopting its new name. If I rename it back (just a single character change) and remove/import then it appears again.
I use help blahblah to list all commands in a set, since they all have the same prefix. The manifest exports all (*) functions. Clearly I don't understand how these type of script modules work, the functions are all listed even after I run Remove-Module! I've written a compiled module before in C# and that worked as expected.
What's going on? Why does renaming a function cause it to vanish? Thanks.
Found it. This line appears in some stuff I overlooked in the .psm1 file.
Export-ModuleMember X, Y, Z
So, I guess the manifest can overrule this or replace the need for it in a script? Who knows. Anyway, hope this helps someone.