Summary: Ed Wilson, Microsoft Scripting Guy, talks about creating and using a Windows PowerShell script.
Microsoft Scripting Guy, Ed Wilson, is here. This afternoon, it is raining—actually more like a thunderstorm because there is lightning and thunder. In the afternoon in central Florida, there is a really good chance that for 10 or 15 minutes, one will see an awesome thunderstorm. I think the weather people always have a standard line: "Chance of afternoon thunderstorms"—and there is a good chance they will be right.
Anyway, listening to Beethoven and watching a thunderstorm is awesome. I even decided to celebrate and to open one of my few Ale-8 sodas that we picked up on our way through Kentucky when we drove to Chicago for Ignite. Every time we are anywhere near the bluegrass state, we pick up a few bottles of Ale-8 and then ration them like gingerbread cookies.
I just noticed I can order them from Amazon, but that sort of spoils the effect. Besides that, they were selling it cans, and I can tell you from experience that you want it in a glass bottle. Otherwise, it doesn’t taste the same.
What is a PowerShell script?
Remember, that at its most basic form, a Windows PowerShell script is nothing more than a series of commands (even a single command) that could have been typed into the Windows PowerShell console. But instead of having to type the commands, they are stored in a .ps1 text file.
By default, Windows PowerShell scripting is turned off, and it needs to be enabled. To enable the Windows PowerShell script execution policy, I use the Set-ExecutionPolicy cmdlet. A normal user can use it to enable scripting by applying the –scope:currentuser token. This is shown here:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
Keep in mind that if there is a Group Policy setting for a different execution policy, the user will not be able to overwrite it.
None of this keeps me from opening a Windows PowerShell script, highlighting the commands in the Windows PowerShell ISE, and running the selected commands—nor does this prevent anyone from opening Windows PowerShell in “bypass” mode.
The script execution policy is a security convenience feature, not a security boundary. It is akin to the buzzer in your car that warns you to fasten your seatbelt. No one was ever saved by a seatbelt buzzer—unless they actually fastened their seat belt to silence the annoying buzzer. By the same token, the Windows PowerShell script execution policy is to help remind you to do the right thing when it comes to Windows PowerShell and security.
Elements of script
I like to add at least a couple of comments at the head of my script. The comments have the name of the script, when I wrote it, and a few notes that I might add. I have a function in my Windows PowerShell ISE profile modules that is called Add-HeaderToScript. The keywords that I add to my scripts are designed to make it easier for me to find my script by using Windows Search. I have changed my search settings so that I do a full text indexing of all of my .ps1 files. For example, if I type CIM in my search box, it would find all of my Windows PowerShell scripts where I added the CIM keyword in my keywords section.
The comments are free-form notes. For example, if I find a particularly helpful MSDN article, I might copy the URL for that article and paste it in my comments section. Absolutely, if I copied part or all of a script from someone else, I would provide credit to them in my comments section. If the script was used in one of my Hey, Scripting Guy! Blog posts, I would paste the URL to the post in the comments section (or at least, the date of the post). Armed with the date, I can find the URL for the Hey, Scripting Guy! Blog post.
I do not have a separate line for the version of the script. I add that into the comments section, but only when the script is a different version than 1.0. So if I revise a script, I will add a version to the comments section. But if it is the original version of the script, I do not have a version number at all. This is because I rarely revise my scripts.
If I add substantial new functionality to the script, the script becomes a new script. It is not that each script is perfect when I am done writing it. Far from it. It is simply the nature of my job to write hundreds of script samples, rather than to write one or two comprehensive, and ever evolving, script “applications.” When I think of script applications, I think of things like Clint Huffman’s PAL tool. Although it is a Windows PowerShell script, is much more like an application than a “simple Windows PowerShell script.”
One last thing...
I write narrow code so that I can use it in books and blog posts. The commented lines at the top and bottom of my header block are 80 characters long, and this is what I use as my limit when I am writing scripts. This is sometimes very problematic, especially because the longest Windows PowerShell cmdlet name currently in production is over half of that length—and unfortunately, it does not ship with an alias!
Here is the header that I have at the top of all of my scripts:
# -----------------------------------------------------------------------------
# Script: Untitled1.ps1
# Author: ed wilson, msft
# Date: 07/05/2015 15:02:13
# Keywords:
# Comments:
#
# -----------------------------------------------------------------------------
Making scripts more powerful
In addition to writing a quick one-off script, I also like to import modules, or even dot-source another Windows PowerShell script to make it easier to reuse functions. In this way, I do not have to copy the function into my script. I can simply call it and use it.
The disadvantage to this approach is that you now have an external dependency. But Windows Powershell 5.0 with the One-Git repository makes it easy to have access to modules that I might want to incorporate. In addition, updating modules is easier.
The disadvantage to using a script and dot-sourcing it is that it brings everything into your current scripting environment—all functions, variables, and other things that you may not want. So, if I have a script that I will use to dot-source, I copy only the functions I want into it.
But then, if I am going to go to all that trouble, I may as well copy the functions into a module, and simply use that. With a module, I can control what I bring in—one or more functions, all aliases, no aliases, all variables, no variables, or whatever. It is very flexible, and is not much different than creating a resource script that will hold your functions.
To Script or Not to Script Week will continue tomorrow when I will talk about Windows PowerShell functions.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy