IT:AD:Powershell:HowTo:Create a Powershell Module
Summary
Whereas *.ps1 scripts are cheaky little useful scripts that get things done, Modules are the modular building blocks of a maintainable and reusable strategy.
Essentially, a module is just a new namespace. Any data member or function that you declare inside of the module will be accessible by other module members. But, it’s out of scope for your interactive session. So, you just have to export the members that you’d like to be publicly accessible. (Basically just like Python’s import statement.)
There is some set up cost though.
Process
The process of creating powershell modules approximately is
* converting the extension from *.ps1 to *.psm1,
* adding to the bottom of the script a declaration of what methods in the script you are exposing as callable.
* installing in a WellKnown/ Modules directory.
* debugging is a little harder due to a feature of *.psm1 files in that reloading doesn't refresh the script – you have to unload/reload before you see the changes applied…a bit annoying.
* It's optional to add a description of the script's functionality as a *.psd1 in the same directory as the *.psm1
Script Security
Modules are controlled by the same security as Scripts.
So if you haven't already
Set-ExecutionPolicy Unrestricted
Creating a *.psm1 File
- Create a
*.psm1rather than a*.ps1file.- Unfortunately, stops being easily editable/refreshable in PS ISE (have to Unload/Reload everytime – see below).
Exporting Methods
You'll have to be stricter with the way you name files.
But once addressed, complete the file, with the following exporting of methods as the last lines of the file.
export-modulemember -function Show-Calendar
until you do, consider turning off import warnings: import-module <path-to-module> -DisableNameChecking
you can also export methods using wildcards, as shown here:
http://www.itidea.nl/index.php/powershell-export-functions-variables-and-aliases-with-wildcards/
Saving the Module in the PowerShell Module Root Path
Modules are saved in a folder under one of the “Powershell Module Root Paths”. By default there are 2 – one per User, one System wide one.
You can get your current “Powershell Module Root Paths” as follows:
# works much the same as the PATH Environment Variable: $env:PSModulePath
The default will be something like:
WindowsPowerShell\Modules;C:\windows\system32\WindowsPowerShell\v1.0\Modules\
In other words:
C:\windows\system32\WindowsPowerShell\v1.0\Modules\%userprofile%\documents\windowspowershell\modules\mymodule- Note that at MOE, the default path is a sibling, not child of the
Documentfolder:%userprofile%\windowspowershell\modules\mymodule
* WRONG:`%userprofile%\documents\windowspowershell\modules\mymodule` * CORRECT: `%userprofile%\windowspowershell\modules\mymodule` * `windows\system32\windowspowershell\V1.0\modules\mymodule`
You are not limited to use only those paths… You can update your environment as follows:
Custom Module Folder -- One per Module
In those root dirs, you create a folder with the same name (eg: “xact”) as the Module filename (eg: “xact”)
In that folder you place your xact.psm1 file, that is export-modulemember methods from it.
/{root}/
/{root}/xact/
/{root}/xact/xact.psm1
Loading / Unloading / Debugging
Whereas Scripts one just loads with 'dot' loading, *.psm1 files have to be loaded/unloaded.
# all following forms are valid:
import-module {path-needed-if-not-module-root}/untitled1.psm1
import-module untitled1.ps1
import-module untitled1
import-module <path-to-module> -DisableNameChecking #if you want it to shut up about not adhering to Get-Verb
It's easy.
But there's a catch … if you load A, which imports B and C, and B imports C as well, then the file is only loaded once. Makes sense. But it makes debugging harder than with *ps.1 files which you can just reload/refresh after every edit.
You have to unload files before you can reload them.
remove-module untitled1
Loading Sub *.ps1 files
See http://la11111.wordpress.com/2012/10/25/how-to-create-a-powershell-module-the-easy-way/
for an elegant solution.
Adding Documentation to your Scripts
If we're talking about *.ps1 script functions, one can document them by putting extended comments at the bottom of the function.
Something like:
<# .SYNOPSIS --TODO:Summary .DESCRIPTION --TODO:Describe .PARAMETER --TODO:ParamName-- --TODO: Describe .EXAMPLE .LINK http://skysigal.com .NOTES #>
Then you can
get-help myFunc
Generating Custom Description Documentation
Alternatively, for modules, consider:
New-ModuleManifest
See: https://www.simple-talk.com/sysadmin/powershell/an-introduction-to-powershell-modules/
Generating Custom Help Docs
http://msdn.microsoft.com/en-us/library/dd878343(v=vs.85).aspx
Automatic Loading in PS IDE
By default Scripts are not loaded.
You have to import-module... them into the IDE.
But Powershell looks for file in its $profile variable (it's going to be %userprofile\$profile – which ends up being
# per user $useprofile\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1. # All users (notice different filename) C:\Windows\System32\WindowsPowerShell\V1.0\Microsoft.PowerShell_profile.ps1
It's just the first script that's run when the IDE is loaded.
So you can just create the file, and add
import-module mytest
Listing Module Commands
get-command -type cmdlet *-*module* | select name
Get-Module pattern- Gets a list of the modules currently loaded in memory.
Import-Module- Loads a module into memory and imports the public commands from that module.
Remove-Module- Removes a module from memory and removes the imported members.
Export-ModuleMember- Used to specify the members of a module to export to the user of the module.
New-ModuleManifest- Used to create a new metadata file for a module directory.
Test-ModuleManifest- Run a series of tests on a module manifest validating its contents.
New-Module- Create a new dynamic module.
Resources
- http://msdn.microsoft.com/en-us/library/dd878340(v=VS.85).aspx