In PowerShell you have two ways of including ‘other’ code in your script. Other code can be someone else’s code, your code from another project, or simply the way you organize your code into different files. Before we dive into dot sourcing and modules, let’s revisit why you don’t want to pack all your code into one monolithic script. Separating different parts of your application has a number of benefits.
1. Organization
It is far easier to find code you need to change or adapt sometime down the road if the relevant bits are organized in separate files with names that somewhat hint at their purpose. Just to make this clear, using file1.ps1, file2.ps1 in folders that are named project1, project2 etc. is probably not the best idea. Imagine your future self, staring at files and trying to remember what is where.
It is Programming 101 to separate your presentation from your processing. So, at a minimum, anything interacting with the user should be in one file, anything processing data, accessing databases etc. should be in another. Obviously, how religious you are about that depends very much on the size of your project. Separating processing from presentation is overkill if your script is only 15 lines or so.
2. Collaboration
If you are working with someone else on a project, it is much easier to split up work by files. True, Git will merge (usually) what one or more people contributed to a single file. But only if you do not collide, meaning you do not modify the same stretch of code. You can avoid merging problems by not working on the same files at the same time entirely.
3. Code re-use
It is much easier to copy or better share a file with a desired functionality to another project. Sure, you can copy and paste the relevant chunks from one script to another, but that means sifting through a lot of code to find the parts that belong together. Placing things that can potentially be re-used in separate files also tends to make you think more about that aspect while writing that code.
A bonus is that if you fix a bug in one project, the fix is automatically applied to all other projects that share that file. Even if you copy and paste files between projects, it is still easier than finding all relevant stretches of code in other projects.
To make this easier for you, in PrimalScript’s and PowerShell Studio’s File Browser Panel, just pressing Shift while dragging and dropping will insert a dot source statement for that file.
4. Localization
If you need to create a user interface, graphical or command line, and you need to support multiple languages, it will be much easier to separate that into language specific files. You can have your French translator work on it at the same time as your Italian and German counterparts do their thing. If you bunch it all up in one file, organizing changes will get much harder.
Now back to modules and dot sourcing.
Modules are intended to allow shared code. A module generally is a public entity. You create and distribute a module to share its interface and functionality with the rest of the world. Well, your world at least.
How and where your module is published determines how many people will see it. Publishing to the PowerShell Gallery makes it public for everyone and publishing to a corporate repository means it is public within your organization.
If you are just copying modules between your projects without ever publishing them to anyone else, you are obviously free to do so. But that is not the intended use of modules and you do a lot of extra work for no reason. If you use modules correctly and install them properly, you do not need to copy them to each and every project you create.
Additionally, let’s not forget that sharing functionality also means a public interface. Whether you share your module with the general public or your fellow corporate developers, the interface you design is what they should see and use.
It is very important to point out that the interface, the set of functions and/or classes you created to access your module’s functionality, must be immutable. That means you can only add to it, but not change existing functions.
If you dot source a script, it is purely a private matter. You can use this to include functions you share across all your projects. You can share this “include file” with your co-worker so they can utilize the same set of functions. Changing function signatures, removing obsolete code etc. is only affecting you and while it might be wise to not introduce breaking changes all the time, it is really up to you.
If you publish your application in any fashion, you simply include the scripts you dot source with your other files. No repositories or separate installers get involved.
Packaging and deploying your application.
If you dot sourced any code in your application and you are packaging it as an executable with PowerShell Studio or PrimalScript, simply check the box to resolve dot sourced files.If you created a module or modules, you can include a module installer in your application and install or update the module, if needed. The official way, however, would be to publish your module to the repository you use and have your application fetch it from there, if needed, on first start. That is the way PowerShell modules are intended to be used. You can of course use your own scheme as you see fit, but the lines do get a bit blurry then.
Done. Nothing else to do.
If you created a module or modules, you can include a module installer in your application and install or update the module, if needed. The official way however, would be to publish your module to the repository you use and have your application fetch it from there, if needed, on first start. That is the way PowerShell modules are intended to be used. You can of course use your own scheme as you see fit, but the lines do get a bit blurry then.
Comment? Questions? Please don’t hold back.
I think the best way is to combine both worlds. So write function and save them in ps1 scripts and automatically generate modules from them. Like https://doitpsway.com/automate-powershell-module-creation-the-smart-way
Worth mentioning, dot sourcing is really slow when working with dozens of ps1 files.
I agree that is always best to have code organized so that functions that logically belong together are in separate files.
The use of modules versus dot sourcing should generally be determined by the individual use. The main point of the article was to point folks way from copying modules repeatedly between projects.
I have not noticed any particular delay when dot sourcing files. Do you have any data that illustrates this?
I have to point out of course that resolving dot sourced file when packaging for an executable carries no penalty as that resolves the files at packaging and not at runtime. 😀
I didn’t mean to be rude. Article is very nice
About the speed. I had this issue few years back when I had all my functions in ps1 and dot source them in my powershell profile. That was one of the reasons I moved to modules. There is also important thing related to speed of importing modules and that is don’t use wildcard in export-modulemember. It make the import a lot slower.
Maybe worth mentioning my generated modules have thousands of lines, so on smaller ones it doesn’t have to be such noticeable problem..
Oh sorry if you felt I insinuated you were rude. That was not my intention, not at all.
I thought the comment about speed was intriguing and worthwhile exploring, so I asked if you have any specific test data.
If not, I will try to set up some tests with the profiler to see what we can measure.
ok ok 🙂
give me 30 minutes, I will send some measurement results
ok so here it is https://www.dropbox.com/s/626h9n5obv3xm0e/speed%20comparison.JPG?dl=0
dot sourcing 568 miliseconds, module loading 42 miliseconds
both contain same data (from these ps1 scripts a generate that module) and it is 9332 lines of code each.
according to usage of wildcard in Export-ModuleMember. If I use it instead of explicit list of functions to export, it took 126 miliseconds instead of 42.
So you may say, that few hundred miliseconds isnt much, but if you load several of such modules, it makes difference 🙂