The Microsoft Technet Guru Award (August 2016) winning article – Silver
PowerShell: Extending Modules – System Parameter measurement
PowerShell: Extending Modules – System Parameter measurement
Abstract
The objective of this post to illustrate the various methods of creating PoSH Modules. To explain different methods, have considered PoSH GUI functions which are used measure system metrics such as Disk, Memory, and Top resource consumption Process. It need not be a function; any valid PowerShell script is an eligible object for creating a Module. The three functions are encapsulated in a PowerShell Module.
When Do I Create A PowerShell Module?
You can easily decide whether to create a module by answering the following questions while writing a script
- Will the code I’m writing need to be used more than once?
- Does this code essentially manage a single object or entity?
- As I write this code, do I find that I’m breaking it apart into functions because it’s getting too complex to be in a single script?
- Do I need to share the code with others?
If you answered yes to at least three of these four questions, it’s a good bet you should be writing a module instead of a PS1 script.
Modules and Snap-Ins
In PowerShell there are 2 main ways to extend the shell, these are:
Modules – A package that contains Windows PowerShell commands in the form of functions, cmdlets, and workflows, in addition, it may contain variables, aliases, and providers. Modules can be written in PowerShell and/or compiled as DLLs.
For example,
Import-Module SQLPS
You don’t need to register the module, need to just import it. on the other hand, the modules can additionally load functions, variables, aliases to your session.
List loaded modules | Get-Module |
List installed modules | Get-Module -ListAvailable |
Show commands in a module | Get-Command -Module “ModuleName” |
Load a specific module | Import-Module -Name “ModuleName” |
Snap-Ins – Are compiled cmdlets into a DLL written in a .Net language and need to register before they can be used. Snap-ins can add cmdlets and providers to your session.
For example,
Add-PSSnapin SqlServerCmdletSnapin
100
List Loaded Snap-Ins | Get-PSSnapin |
List installed snap-ins | Get-PSSnapin -Registered |
Show commands in a snap-in | Get-Command -Module “SnapinName” |
Load a specific snap-in | Add-PSSnapin “SnapinName” |
PoSH Modules
At its simplest, a module is a collection of PowerShell script contained in a file with a .PSM1 extension. A module is some chunk of code that you can import into PowerShell. Once imported, any cmdlets, scripts, or providers can be accessed.
Types of PowerShell modules:
- Script Modules
- Binary Modules
- Manifest Modules
- Dynamic Modules
Script Modules
PSM1 files that typically contain mostly functions, but can contain any valid PowerShell code. In this case simply take any valid Powershell script *.ps1 and rename it to *.psm1 file and place it in a folder. The paths where you can install your module are located in the $ENV:PSModulePath global variable. You can save the file in a default module path that can be identified using the environmental variable.
PS:\>$ENV:PSModulePath
For example, a common path to save a module on a system would be
- %SystemRoot%\users\<user>\Documents\WindowsPowerShell\Modules\<modName>
- %windir%\System32\WindowsPowerShell\v1.0\Modules
- %UserProfile%\Documents\WindowsPowerShell\Modules (preferred).
Be sure to create a folder for your module. If you did not save your module to one of these paths, you would have to pass in the location of your module in the call to Import-Module. Starting with PowerShell 3.0, if you have placed your module on one of the PowerShell module paths, you do not need to explicitly import it: simply having a user call your function will automatically load it.
Pre-requisites
- Powershell 2.0 and Above
- Microsoft Chart Controls for Microsoft .NET Framework 3.5 Setup
- .Net framework 3.0 or 3.5
- MS charter for GUI modules which displays Graph
Download
Installation
Installation of a module is now very simple. Download and save the content of file in PowerShellGUI.psm1(Append) to any of the above-mentioned path or save it to a specific folderThis PowerShellGUI.psm1 module going to consists of three functions
- Get-DiskSpaceGUI
- Get-MemoryGUI
- Get-ProcessGUI
Import-Module
There are many ways to load a PowerShell Module. The preferred way is to create folder and save the Module in that folderTo import module and loading a module is as follows.
- Using Relative Path
- Using Absolute Path
Using Relative Path
Follow the below steps to load the module from a system path
- Download the module code
- Create a folder PowerShellGUI (Same name as that of a Module name) file at any of the below location %windir%\System32\WindowsPowerShell\v1.0\Modules OR %UserProfile%\Documents\WindowsPowerShell\Modules (preferred)
- Save the PowerShellGUI.psm1 %UserProfile%\Documents\WindowsPowerShell\Modules\PowerShellGUI\ (preferred)
- Once done with step 1, 2 and 3 open a PowerShell window and run below commands.
PS:\>Import-Module -Name PowerShellGUI
This will import the module and functions into PowerShell
PS:\>Get-Module -ListAvailable
This will list down all available modules in PowerShell
PS:\>Get-Command -Module PowerShellGUI
Using Absolute Path
Save the module to C:\PowerShellGUI.psm1
If we want to add another path for PowerShell to look at we just add that path to the current environment variable:
$env:psmodulepath = $env:psmodulepath +
";c:\PowerShellGUI;"
PS:\> Import-Module -Name C:\PowerShellGUI.psm
1
PS:\>Get-Module PowerShellGUI
PS:\>Get-Command -Module PowershellGUI
Output
Binary Modules
Compiled DLL files typically not created by IT pros; these are usually left up to developers.A binary module is a .NET Framework assembly (.dll) that contains compiled code. Cmdlet developers can use this type of module to create modules that contain cmdlets, providers, and more. (Existing snap-ins can also be used as binary modules.)Compiling Binary cmdlets
$
code
= @'
using System;
using System.Collections.Generic;
using System.Management.Automation;
namespace CustomCmdlet
{
[Cmdlet(
"Get"
,
"Magic"
, SupportsTransactions = false)]
public class test : PSCmdlet
{
private int _Age;
[Alias(new string[]
{
"HowOld"
,
"YourAge"
}), Parameter(Position =
0
,ValueFromPipeline = true)]
public int Age
{
get { return _Age; }
set { _Age = value; }
}
private string _Name;
[Parameter(Position =
1
)]
public string Name
{
get { return _Name; }
set { _Name = value; }
}
protected override void BeginProcessing()
{
this.WriteObject(
"Good morning..."
);
base.BeginProcessing();
}
protected override void ProcessRecord()
{
this.WriteObject(
"Your name is "
+ Name +
" and your age is "
+ Age);
base.ProcessRecord();
}
protected override void EndProcessing()
{
this.WriteObject(
"That's it for now."
);
base.EndProcessing();
}
}
}
'@
# compile C#
code
to DLL
# use a timestamp to create unique file names
# while testing, when a DLL was imported before, it is in use until PowerShell closes
# so to do repeated tests, use different DLL file names
$datetime = Get-Date -Format yyyyMMddHHmmssffff
$DLLPath =
"$env:temp\myCmdlet($datetime).dll"
Add-Type -TypeDefinition $
code
-OutputAssembly $DLLPath
# import a module
Import-Module -Name $DLLPath -Verbose
Manifest Modules
Script modules that contain a manifest.
How to load Multiple Modules
Load Multiple Modules (.psm1) or *.ps1 using a single psd1 file. You can edit the psd1 file and add the modules or files under NestedModule tag. The New-ModuleManifest cmdlet is used to create a module manifest. As shown below, in PowerShell version 3, the only field that you’re required to provide a value for is the path
- 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>>
New-ModuleManifest -Path .\PowerShellGUI\PowershellGUI.psd
1
-Author
'Prashanth Jayaram'
-CompanyName
'CTS'
-Copyright
'(c)2016 Prashanth Jayaram'
-ModuleVersion
1.0
-PowerShellVersion
2.0
-NestedModules
'.\PowerShellGUI\PowerShellGUI.PSM1'
,
'\PowerShellGUI\Get-DiskUsage.psm1'
Dynamic Modules
Modules that are never written to disk and are only available in memory.Dynamic modules are basically an extension of script block concept.For Example, Let’s create a script block. It has two functions, one to retrieve disk space and another one to get the Uptime of a given machine
$scriptblock={
Function Get-DiskSpace([string[]]$server)
{
Get-WmiObject -Class win
32
_volume -cn $server |Select-Object @{LABEL='Comptuer';EXPRESSION={$server}},driveletter, label,@{LABEL='GBfreespace';EXPRESSION={"{
0:
N
2
}" -f ($_.freespace/
1
GB)}}
} #end function Get-DiskSpace
Function Get-Uptime([string[]]$server) {
$os = Get-WmiObject win
32
_operatingsystem -ComputerName $server
$uptime = (Get-Date) - ($os.ConvertToDateTime($os.lastbootuptime))
$Display =
"Uptime: "
+ $Uptime.Days +
" days, "
+ $Uptime.Hours +
" hours, "
+ $Uptime.Minutes +
" minutes"
return $Display
}
}
Create a module using New-Module cmdlet
PS P:\> $server=New-Module -ScriptBlock $scriptblock -AsCustomObject
The New-Module cmdlet creates a module in memory using the script block. The -AsCustomObject parameter tells the PowerShell to pass the module as a PowerShell Object.
To retrieve the attributes of the New-Module
$server|Get-Member
Call the module
PS P:\> $SERVER.
'Get-DiskSpace'
(
"HQDBSP18"
)
PS P:\> $SERVER.
'Get-DiskSpace'
(
"HQDBSP18"
)
How to import custom PowerShell module into the remote session?
Enable remoting on the source system by running Enable-PSRemoting on it. create and load the module on Server 1 and call the module Server 2.
PS C:\> $Session = New-PSSession -ComputerName SERVER
1
PS C:\> Import-Module -PSSession $foo -Name Get-DiskUsage
PS C:\> Get-DiskUsage
The above opens a PowerShell session on the server SERVER1 and import the Get-DiskUsage module on the remote computer. The command is run on the remote computer while it appears to be executed locally.
Profile
The Scope is limited to a session. If you want to load automatically then you need to create Profile. Rather than typing “Import-Module -Name PowerShellGUI” cmdlet every time you start Windows PowerShell, you can create a Windows PowerShell profile and add this cmdlet to the $profile global variable. After you create the profile, PowerShell Module is automatically added each time when you start Windows PowerShell.
Follow the below steps to create or edit the $profile.
PS:\> test-path $profile
True
PS:\> notepad $profile
PS:\> $profile
C:\Users\ccov
648
\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps
1
Conclusion
- Discussed various types of modules which help in understanding of build and package creation in PoSH
- The seamless approach to navigating remote modules helps in easy management and administration
- Day to day activities can be customized into modules
- Automatic loading of modules made easier with the help of profile creation
- Discussed various method and usage of each module which helps in creating and decision making about the need for module
References