Working with Windows PowerShell 2.0 advanced functionality

hey everyone, today i have a guest poster on my blog. Laurie McKnight from the VMM team will illustrate some of the advanced functionality you can achieve with Script Functions, Script Modules and Binary Modules in PowerShell.

How to save a PS 2.0 advanced function

 

CAUTION: Methods that work but are **NOT** recommended are included but struck out.

                 These method are included to clarify that using that method is not appropriate or not recommended.

 

To distinguish one type of advanced function from others based on file type, the following examples use these (arbitrary) naming conventions:

  • ScriptFunction1.ps1 [referred to in text below as a "script-function"]
  • ScriptModule1.psm1 [referred to in text below as a "script-module"]
  • BinaryModule1.dll [referred to in text below as a "binary-module"]

 

Type an advanced function directly into a PS Profile file

Location / Action

PERSONAL PATH and PROFILE:

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Profile.ps1

 

Type the advanced function directly into Profile.ps1 (your personal profile file).

 

ALL USERS PATH and PROFILE:

<C>:\Windows\System32\WindowsPowerShell\V1.0\Microsoft.PowerShell_profile.ps1

 

NOTE: PowerShell 2.0 will still use "V1.0" in this path.

 

Type the advanced function directly into the Microsoft.PowerShell_profile.ps1 (all users profile file).

 

 

Call an advanced function (.ps1 or .psm1) from within a PS Profile file

Location / Action

PERSONAL PATH and PROFILE + .ps1 FILE:

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Profile.ps1

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\ScriptFunction1.ps1

 

  • 1. Save the advanced function as a script (a .ps1 file) in the same folder as your personal Profile.ps1 file.
  • 2. Add the following line inside Profile.ps1:

 

. .\ScriptFunction.ps1

 

NOTE: When the script is in the same directory as the profile file, notice that the syntax to use is "dot space dot." The dot followed by a space followed by a second dot and then the script/function name calls the script/function, that is, causes the script/function to act as if the entire advanced function had been typed into the profile file. When you use "dot sourcing," everything you define in the .ps1 file runs in the same shared session state; therefore, variables, functions, etc, are visible globally.

 

Alternatively, you "dot source" a script by using a dot, then a space, then the complete path as follows:

 

. C:\MyScripts\MyAdvFunc1.ps1

 

PERSONAL PATH and PROFILE + psm1 FILE -- OK only for informal testing; this is **NOT** the recommended way to store modules:

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Profile.ps1

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\ScriptModule1.psm1

 

  • 1. Save the advanced function as a module (a .psm1 file) in the same folder as your personal Profile.ps1.
  • 2. Import the advanced function by adding the following line inside Profile.ps1:

Import-Module ScriptModule1.psm1

 

NOTE: You might assume that the Import-Module command calls the module/function, that is, causes the module/function to act as if the entire module/function had been typed into the profile file. However, modules have their own session state (part of memory that stores things such as values of variables, etc.) and therefore behave differently from the dot sourcing of .ps1 files.

In the module case, only those things that you export from the module are visible globally; everything else is private to the module's session state (this is like a C# class). You specify what to export using Export-ModuleMember cmdlet in your .psm1 file.

Example: At the end of a .psm1 file named NewDiffDiskVMModlue.psm1 that defines a function named New-DiffVM, after the final "}", you can add the following command:

Export-ModuleMember -Function New-DiffVM

In the absence of a call to Export-ModuleMember, all commands (functions + cmdlets) are exported by default (i.e. public) and variables and aliases are not exported (i.e. kept private to the module).

 

NOTE: The Import-Module cmdlet looks for files in the following order:

  • a. ModuleName.psd1
  • b. ModuleName.psm1
  • c. ModuleName.dll

 

ALL USERS PATH - CAUTION: Not recommended -- not secure!

<C>:\Windows\System32\WindowsPowerShell\V1.0\Microsoft.PowerShell_profile.ps1

 

Do **not** save the advanced function as a script file (.ps1 file) or as a module file (.psm1 file) in the same folder as the all users Microsoft.PowerShell_profile.ps1 and then call it from within the profile file.

 

This does work if, for example, you want to openly share scripts within an organization, but is a potential security risk if sensitive processes are contained in the scripts.

 

 

Recommended method for individual advanced functions:

Save an advanced function as a script-module (.psm1) or binary-module (.dll) in a sub-folder under Modules, & then import the module

REQUIRED:

  • (1) Add a subfolder under the Modules folder.
  • (2) Use the same name for the subfolder and for the (primary) module file.
  • (3) Use a separate folder for each module.

OPTIONAL:

  • A module manifest (.psd1 file) is optional but strongly recommended for complex modules, especially if more than one .psm1 file (or more than one DLL file) exists.
  • If you do include a .psd1 file, its name must be the same as the folder and module file names.

DEFAULT MODULE PATHS:

  • PS looks for modules in the default directories if you do not specify the full path to a module. The default value of $env:PSModulePath is:

$home\Documents\WindowsPowerShell\Modules; $pshome\Modules

  • You can customize the module path by using the PSModulePath environment variable. For more information, type Get-Help about_Environment_Variables.

Location / Action

PERSONAL PATH + .psm1 MODULE:

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\ScriptModule1\ScriptModule1.psm1 [ REQUIRED ]

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\ScriptModule1\ScriptModule1.psd1  [ OPTIONAL ]

 

  • 1. Save ScriptModule1.psm1 in your private path in a subfolder also named ScriptModule1.
  • 2. Next, import the module:

Import-Module ScriptModule1

 

PERSONAL PATH + .dll MODULE:

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\BinaryModule1\BinaryModule1.dll      [ REQUIRED ]

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\BinaryModule1\BinaryModule1.psd1 [ OPTIONAL ]

 

  • 1. Save BinaryModule1.dll in your private path in a subfolder also named BinaryModule1.
  • 2. Next, import the module:

Import-Module BinaryModule1

 

ALL USERS PATH + .psm1 MODULE -- Do NOT put your module here unless it is a Windows component (Active Directory, IIS BITS, etc)

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\ScriptModule1\ScriptModule1.psm1

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\ScriptModule1\ScriptModule.psd1  

 

  • 1. Save ScriptModule1.psm1 in the all users path in a subfolder also named ScriptModule1.
  • 2. Next, import the module:

Import-Module ScriptModule1

 

IF YOUR MODULE IS **NOT** A WINDOWS COMPONENT, USE ONE OF THESE METHODS INSTEAD:

  • Put user modules in <C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\
  • Put product specific modules under Program Files and add that path to the PSModulePath environment variable. See

https://msdn.microsoft.com/en-us/library/dd878350(VS.85).aspx

 

ALL USERS PATH + .dll MODULE -- Do NOT put your module here unless it is a Windows component (Active Directory, IIS BITS, etc)

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\BinaryModule1\BinaryModule1.dll      

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\BinaryModule1\BinaryModule.psd1    

 

  • 1. Save BinaryModule1.dll in the all users path in a subfolder also named BinaryModule1.
  • 2. Next, import the module:

Import-Module BinaryModule1

 

IF YOUR MODULE IS **NOT** A WINDOWS COMPONENT, USE ONE OF THESE METHODS INSTEAD:

  • Put user modules in <C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\.
  • Put product specific modules under Program Files and add that path to the PSModulePath environment variable. See

https://msdn.microsoft.com/en-us/library/dd878350(VS.85).aspx.

 

 

Recommended method for a set of advanced functions:

Save a set of advanced functions in a sub-folder under Modules; create a script-module to call the set of functions; & then import the module:

NOTE: The information on this page is **not** about product specific modules.

           A product specific module is saved under Program Files, and its path is added to the PSModulePath environment variable. See:

           https://msdn.microsoft.com/en-us/library/dd878350(VS.85).aspx

Location / Action

PERSONAL PATH + FUNCTIONS + .psm1 MODULE:

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\ScriptModule1\ScriptModule1.psm1 [REQUIRED]

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\ScriptModule1\ScriptModule1.psd1  [ OPTIONAL ]

 

NOTE: In this case, it is the .psm1 file name (not the .ps1 file names) that matches the folder name.

 

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\ScriptModule1\Script-Function1.ps1

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\ScriptModule1\Script-Function2.ps1

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\ScriptModule1\Script-Function3.ps1

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\ScriptModule1\Script-Function4.ps1

<C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\ScriptModule1\Script-Function5.ps1

 

  • 1. Create a sub-folder under Modules and an (empty, at first) script-module file (.psm1 file with the same name.
  • 2. Save a set of advanced functions as script-function files (.ps1 files) in the same sub-folder.
  • 3. Open the script-module file (.psm1) file and call the script-function files (aka "dot source the script-function files") like this:

 

. $psSScriptRoot\ScriptFunction1.ps1

. $psSScriptRoot\ScriptFunction2.ps1

. $psSScriptRoot\ScriptFunction3.ps1

. $psSScriptRoot\ScriptFunction4.ps1

. $psSScriptRoot\ScriptFunction5.ps1

 

NOTE: Each entry must be on a new line.

 

  • 4. Next, import the module:

Import-Module ScriptModule1

 

NOTE: This command imports the script-module file (.psm1 file) -AND- all of the script-function files (.ps1 files) listed in the script-module file, all in one step.

 

LATER:

If you add another script-function to this sub-folder later, use the following command to reload the module with the new file:

Import-Module ScriptModule1 -Force

 

ALL USERS PATH + FUNCTIONS + .psm1 MODULE -- Do NOT put your module here unless it is a Windows component (Active Directory, IIS BITS, etc)

 

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\ScriptModule1\ScriptModule1.psm1

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\BinaryModule1\ScriptModule.psd1    

 

NOTE: In this case, it is the .psm1 file name (not the .ps1 file names) that matches the folder name.

 

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\ScriptModule1\Script-Function1.ps1

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\ScriptModule1\Script-Function2.ps1

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\ScriptModule1\Script-Function3.ps1

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\ScriptModule1\Script-Function4.ps1

<C>:\Windows\System32\WindowsPowerShell\V1.0\Modules\ScriptModule1\Script-Function5.ps1

 

  • 1. Create a sub-folder under Modules and an (empty, at first) script-module file (.psm1 file with the same name.
  • 2. Save a set of advanced functions as script-function files (.ps1 files) in the same sub-folder.
  • 3. Open the script-module file (.psm1) file and call the script-function files (aka "dot source the script-function files") like this:

 

. $psSScriptRoot\ScriptFunction1.ps1

. $psSScriptRoot\ScriptFunction2.ps1

. $psSScriptRoot\ScriptFunction3.ps1

. $psSScriptRoot\ScriptFunction4.ps1

. $psSScriptRoot\ScriptFunction5.ps1

 

NOTE: Each entry must be on a new line.

 

  • 4. Next, import the module:

Import-Module ScriptModule1

 

NOTE: This command imports the script-module file (.psm1 file) -AND- all of the script-function files (.ps1 files) listed in the script-module file, all in one step.

 

LATER:

If you add another script-function to this sub-folder later, use the following command to reload the module with the new file:

Import-Module ScriptModule1 -Force

 

IF YOUR MODULE IS **NOT** A WINDOWS COMPONENT, USE ONE OF THESE METHODS INSTEAD:

  • Put user modules in <C>:\Users\<YourAlias>\Documents\WindowsPowerShell\Modules\.
  • Put product specific modules under Program Files and add that path to the PSModulePath environment variable. See

https://msdn.microsoft.com/en-us/library/dd878350(VS.85).aspx.

 

For more information, type:

  • Get-Help about_Scripts
  • Get-Help about_Scopes
  • Get-Help about_Modules
  • Get-Help about_Profiles
  • Get-Help about_Functions
  • Get-Help about_Functions_Advanced
  • Get-Help about_Functions_Advanced_Methods
  • Get-Help about_Functions_Advanced_Parameters
  • Get-Help about_Functions_CmdletBindingAttribute