Summary: When writing a Windows PowerShell script, code reuse can speed up the process. Ed Wilson discusses best practices for reusing code.
Hey, Scripting Guy! I often write Windows PowerShell scripts, and when I need to use a function that I wrote for a different script, I copy and paste the function into my new script. Is this the best way to reuse a function, or should I use a different technique? I guess my question really is: What are the best practices surrounding reuse of functions in Windows PowerShell?
— JE
Hello JE,
Microsoft Scripting Guy Ed Wilson here. A couple years ago, I was delivering a Windows PowerShell workshop to a customer in Tampa, and I decided to pack my scuba gear and head to the Crystal River in Florida. For me the main attraction for diving in the 70-degree water, with visibility that is far less than the river’s name may imply, is the chance to get a picture of one of the most beautiful marine mammals around. It’s the manatee. Of course, you never want to approach or harass a manatee because it both violates Florida state law and is uncool. There is nothing to say that you cannot sit on the bottom of the river and wait for them to appear. Manatees can be nearly 12 feet long, and weigh more than 3000 pounds. When four or five of them come sniffing around, it gets downright spooky. The fellow seen in the following photo I took really wanted me to take his picture. He stopped, posed, and smiled for the camera.
JE, sometimes you need to sit and wait for inspiration to appear, such as when photographing manatee. On other occasions, it is better to do a little bit of experimentation. And this is one of those times when it is best to do some experimenting.
Suppose you have a Windows PowerShell script called include.ps1 that includes two functions. The first function adds one to the input value, and the second function adds two to the input value. You can include the two functions in a script by dot-sourcing the script. The Include.ps1 script is seen here.
Include.ps1
Function addOne($intIN)
{
$intIN + 1
}
Function addTwo($intIN)
{
$intIN + 2
}
To use the functions contained in the include.ps1 script, you can leverage the same methodology that was discussed in yesterday’s Hey, Scripting Guy! post—you dot-source the script. This is seen in the useInclude.ps1 script.
UseInclude.ps1
. “c:\fso\include.ps1”
addone -intIn 3
addTwo -intIn 3
When the script runs, both functions are available to the script, and can be called directly from the body of the script as if they had been copied and pasted into the script. The two functions from the Include.ps1 script are not on the function drive prior to execution of the UseInclude.ps1 script. After the script completes, they still are not on the function drive. The only way to have access to the functions inside the Windows PowerShell console is to dot-source them directly into the Windows PowerShell console as discussed in yesterday’s Hey, Scripting Guy! post. This is shown in the following image.
On the other hand, if the useInclude.ps1 script is run inside the Windows PowerShell ISE, a very different behavior occurs. As before, before executing the script, neither the addone nor the addtwo function exists on the function drive. This means the functions are unavailable to the current Windows PowerShell session. When the useInclude.ps1 script executes, the two functions are available to the executing script as the results indicate. What is interesting is that after the useInclude.ps1 script runs, the addone and the addtwo functions remain on the function drive. This is shown in the following image.
Because the functions still exist on the function drive, you can use them in a new script—even a script that has not been saved. You can use them in the command pane (bottom pane in default view), or you can use them in the script pane (top pane in default view). What you must keep in mind is that the functions only exist in your Windows PowerShell environment because you ran a script that contained the functions. As long as the Windows PowerShell ISE is not closed, the functions will be available (unless you explicitly remove them). In the following image, the useInclude.ps1 script has run, but the script pane that contains its code has been closed. A new script is in the progress of being written, and when it is run, it is able to use the two functions.
If you close the Windows PowerShell ISE however, and after reopening the Windows PowerShell ISE, you attempt to use the addone and the addtwo function in a new script, an error is generated. The error states that the “term ‘addone’ is not recognized as the name of a cmdlet, function, script file, or operable program.” Therefore, the Windows PowerShell ISE cannot execute the addone command. The exact error is shown in the following image.
This can be a frustrating source of errors that can be somewhat troublesome to troubleshoot. There are two ways that I deal with this potential for error. The first way is to save the script, and simply close the Windows PowerShell ISE and open it again. In this way, I have a fresh Windows PowerShell ISE environment with no pollution from leftover variables or functions.
The second way I deal with the problem of leftover functions is to run the script in the Windows PowerShell console (the blue interactive console). Because the Windows PowerShell console does not retrain functions after the script has run to completion, it is a safe place to check script execution and for external dependencies. By opening up a fresh Windows PowerShell console, I am granted a pristine Windows PowerShell environment in which to do testing. This also allows me to check for compatibility between scripts that execute in the Windows PowerShell ISE and scripts that execute in the Windows PowerShell console. There are differences between the two environments, and if you are not certain where or how the script will be used, you should test both environments.
Another way to deal with the specific problem of leftover functions hanging around in the Windows PowerShell ISE is to explicitly remove the functions in the script that uses them. An example of that is shown in the useIncludeRemoveFunction.ps1 script. Use the Remove-Item cmdlet to remove functions after using them.
useIncludeRemoveFunction.ps1
. “c:\fso\include.ps1”
addone -intIn 3
addTwo -intIn 3
Remove-Item function:\add*
When the useIncludeRemoveFunction.ps1 script runs, it adds the two functions by using the dot-source technique. The functions are available and are utilized. The Remove-Item cmdlet is then used to remove the functions from the function drive. As seen in the following image, the functions do not exist before the script executes, or after the script completes.
JE, that is all there is to using functions in Windows PowerShell scripts. Running Windows PowerShell Scripts Week will continue tomorrow when we will talk about masking passwords when running a Windows PowerShell script.
We invite you to follow us on Twitter or Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
Typo! in ‘Because the Windows PowerShell console does not “retrain” [retain] functions after the script has run to completion…’