Share via


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.  

↑ Return to Top


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.

↑ Return to Top


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 
 List installed modules 
 Show commands in a module 
 Load a specific module 

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 
 List installed snap-ins
 Show commands in a snap-in 
 Load a specific snap-in

↑ Return to Top


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

↑ Return to Top


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 folder

This 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 folder

To 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:

 

      ps:\>$env:psmodulepath = $env:psmodulepath +     ";c:\PowerShellGUI;"  


      PS:\> Import-Module -Name C:\PowerShellGUI.psm    1  
      PS:\>Get-Module PowerShellGUI  

PS:\>Get-Command -Module PowershellGUI

Output

↑ Return to Top


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  

↑ Return to Top


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'

↑ Return to Top


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:N2}" -f ($_.freespace/1GB)}}  
      } #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.

↑ Return to Top


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  

↑ Return to Top


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

↑ Return to Top


References

↑ Return to Top