Building a module

I’ve been working on an API wrapper for a while, with all functions currently saved in the same .psm1 file. As it grows, I’m starting to wonder about breaking this into more manageable pieces (sub-modules, if you like) which reflect the structure of the application. It is a school management system, so these would be “Students”, “Teachers”, “Departments”,“Subjects” and so on, as well as more generic areas like “Authentication”,“Logging” etc.

What is the “correct” way to structure code within a module folder, and set up the manifest, so that it loads correctly, and the function code is broken into sub-modules?

Having multiple subfolders with PS1 files makes it easier to maintain.

Having one PSM1 file makes the module loading faster.
It is also easier to sign one PSM1 file than multiple PS1 files.

The current tendency is to have a one PS1 file per function during the development phase in Github,
and to compile all of them into PSM1 file for the final public version on PowerShell Gallery.

Here is an example showing how to compile them:

Get-ChildItem $ModulePath\*.ps1 |Get-Content | Add-Content $TargetDir\$ModuleName.psm1

Even if your module is private, the same principles can apply.

Mike Robbins has written a good post about that.

https://mikefrobbins.com/2016/01/14/powershell-script-module-design-placing-functions-directly-in-the-psm1-file-versus-dot-sourcing-separate-ps1-files

Luc

This is really helpful, thanks. I came across PSGSuite today as I also need to do some work with Google apps - their module is structured very much as you describe, and includes a build.ps1 function to create the final .psm1

Some interesting points in the discussion thread below Mike’s post. Thanks again!

Hey John,

I would highly recommend dot sourcing files versus cramming everything in a single PSM1. You should also look into Plaster:

https://mikefrobbins.com/2018/02/15/using-plaster-to-create-a-powershell-script-module-template/
https://powershellexplained.com/2017-01-21-powershell-module-continious-delivery-pipeline/?utm_source=blog&utm_medium=blog&utm_content=titlelink

As for the wrappers, I normally write a function for a session (e.g. New-MyAPISession). Then I write a wrapper for Invoke-RestMethod (e.g. Invoke-MyAPIRestMethod), this is so I can pass session information in a module variable (e.g. $MyInvocation.MyCommand.Module.PrivateData[‘MyAPIAuthorizationToken’] = $authRequest.authorizationToken) persisted globally in the background so I don’t have to pass it to every command. I also set TLS and accpeption of self-signed certificates, etc., but it give me one place where the API is actually being called. Then the rest of the functions just call the API methods.