Friday, March 24, 2017

Using the PowerShell #requires statement in your script

A few years ago I was working with a team of sysadmins. We were all learning PowerShell together and were having a blast playing with different modules and trying to figure out what sort of things we can automate. One day I downloaded a module from PSGallery, installed it and wrote a nice little script. My colleague asked if he could borrow it to run it, so he installed the module, and ran the script but immediately his console threw a nasty error message. Something along the lines of...

PS /Users/dan> Get-Something                                                    
Get-Something : The term 'Get-Something' is not recognized as the name of a 
cmdlet, function, script file, or operable program. Check the spelling of the 
name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ Get-Something
+ ~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Get-Something:String) [], Comma 
   ndNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Ahh, the dreaded error of not recognizing a cmdlet, function, script file or operable program. We have all seen this before. For a novice to PowerShell this can be confusing and annoying. This error is getting thrown because my colleague did not have that module imported into his session. Fortunately, there is an easy way to ensure this doesn't happen again for him or any user who runs a script.

The #requires statement is something that we can place at the top of our script that will ensure that the script cannot run unless the conditions that #requires states are met. This can be done for modules, pssnapins, runasadministrator or a specific PowerShell version as the help explains.

    #Requires -Version <N>[.<n>] 
          #Requires –PSSnapin <PSSnapin-Name> [-Version <N>[.<n>]]
          #Requires -Modules { <Module-Name> | <Hashtable> } 
          #Requires –ShellId <ShellId>
          #Requires -RunAsAdministrator

So how could I have avoided the nasty error my colleague received? By sticking this at the top of my script:

#requires -Modules ModuleName

As long as the module is installed on the system the script is executing on, the module will automatically be imported and used into the session, and if it is not installed an error will get thrown stating the script cannot run because the modules specified are missing.

As an example I created a script called 'sample.ps1'. I placed #requires -Modules what at the top of the script so that the script will not run if the module 'what' is not in the session. So when I attempt to run sample.ps1 I get this error:

PS /Users/dan> ./sample.ps1                                                     
./sample.ps1 : The script 'sample.ps1' cannot be run because the following      
modules that are specified by the "#requires" statements of the script are 
missing: what.
At line:1 char:1
+ ./sample.ps1
+ ~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (sample.ps1:String) [], Scr 
   iptRequiresException
    + FullyQualifiedErrorId : ScriptRequiresMissingModules

Well at least that is a much more informative error than cmdlet, function, script file or operable program not recognized right? Now the user knows what module they need installed on their machine before they can run this script.

No comments:

Post a Comment

Recompiling Chocolatey packages

Chocolatey is a very popular tool among system administrators as it helps automate package management for Windows. Since Chocolatey can be u...