Back in 2008, I wrote a piece called PowerShell Tips and Tricks, which covered the then-relatively new Windows scripting language and some cool things you could do with it. Although PowerShell has been important in the Microsoft ecosystem ever since its release, as Windows Server 10 comes closer to release, we find that many features and deployments are significantly easier and more full-featured when carried out with PowerShell. Simply put, learning the language, or at least being familiar with it, is now a must.
PowerShell is built into Windows, so there is no fee or additional licensing cost. In addition, different server products come with their own PowerShells, too, which expands the universe of things you can do with PowerShell.
I have put together a head-start guide to scripting in hopes that many administrators not yet proficient with PowerShell will use this opportunity to improve their skills and be ready for the next wave of Microsoft software.
An introduction to scripts
The basis of PowerShell is script processes and commands. Once we have the framework of creating our own scripts down, we can add in some of the more advanced logic that involves loops and conditionals.
Scripts in PowerShell are basically just text files with the special filename extension of ps1. To create a script, you enter a bunch of PowerShell commands in a sequence in a new Notepad file (or really, you could use any text editor you like), and then save that file as NAME.ps1, where NAME is a friendly description of your script -- with no spaces, of course.
To run a PowerShell script that you already have, you enter in a PowerShell window either:
- The full path (folder and file name) of the script, like so: c:\powershell\myscripthere.ps1
- If your script is in the current directory the console is looking at, use a period and then a backslash, like this: .\myscripthere.ps1
Other than that, there is nothing special needed for creating a script in PowerShell. You simply add the commands you like.
Of course, a script probably needs to do more than one thing or you wouldn’t need a script for it. Scripts are common in IT already; administrators have been using login scripts for years to get users' desktops and environments configured consistently every time a user logs on. As technology has gotten better, you can script almost anything, from the bare-metal installation of an operating system on a server fresh out of the factory box all the way up to server workloads, including installing Exchange or file server roles.
We obviously won't go that in depth in this piece, but the basic idea behind a script for our purposes is to do two or three things and then end.
To do that, we need to cover a few elements of a script. The first is the element that can change. The second is the element of the script that actually does the dirty work on everything. Let's look at each of the phases.
Making scripts useful, phase 1: Variables
Now if you buy that the whole point of scripting is to do things over and over again in a consistent way, then you have to buy the idea that you want to do the same action to different things. But how do you change the things that are being acted upon? Variables are how. Variables are kind of like holders, and you can put values, words, numbers -- basically anything -- within them.
In PowerShell, variables always have a dollar sign ($) before them.
Let me declare -- in other words, set up for the first time -- a few variables for you right now:
$name = 'Jon'
$number = 12345
$location = 'Charlotte'
$listofnumbers = 6,7,8,9
$my_last_math_grade = 'D+'
All I have to do to declare those variables is add a dollar sign, then use whatever name for the variable I want -- no spaces are allowed in the name itself -- and then a space, an equals sign, another space and then whatever I want the value of the variable to be.
If I want to have a variable with text as its value, I need to add a single quote on either side of the text. (There are some exceptions to this, but again my goal here is to keep it simple so we’ll stick with this for now.) You can also just declare a variable without putting a value in it. This kind of "reserves" the name, which is probably more helpful when you're in the middle of developing than it is at any other time.
You know what else you can put in a variable? The output of a cmdlet, which is a cute moniker that refers to the simplest bit of .Net-based code you can execute that actually returns a result, either from the PowerShell prompt or from a script. For example, the Get-Process cmdlet lists all processes, while the Get-PSSnapin cmdlet shows all current PowerShell snap-ins that enable new functionality.
To find out the total number of cmdlets available on the system, we can use:
And at least for the system on which I am writing today's piece, that returned a result of 1,338 cmdlets.
Let's declare a variable to store that count in. We’ll call it
And let's store in that variable the output of the (get-command).count entry.
$numberofcmdlets = (get-command).count
PowerShell will tell you the current value of any variable if you just type its name into the prompt, so let's see if that worked:
Success! Now you can use that variable as part of something else. For a simple example, let's look at the Write-Host cmdlet, which simply writes text to the screen of the machine hosting the PowerShell session. Write-Host has a bunch of capabilities, but in its simplest form, you can just say:
Write-Host "Whatever text I want, as long as it is inside double quotes."
Indeed, you can cut and paste that line into a PowerShell window and it’ll come out exactly like it goes in.
But you can integrate variables with Write-Host. You just call them with the dollar sign notation and work them right into your text. For example, I can say:
Write-Host "There are $numberofcmdlets commands available for use on this system."
And what does PowerShell return to us?
Let's put variables aside for now, and move on to the next element of scripting: Decision making and looping.
Making scripts useful, phase 2: If/Then, Do-While and ForEach
The next phase actually lets you do some magic. We know how to store values in variables now, but we need to do some things to those variables. Let's take a look.
The simplest form of decision making in PowerShell is the if/then mechanism; in PowerShell lingo, this is called the "construct." It basically works like this:
If something is some comparison to something else--> Then do this action.
You format it by putting your comparison in parenthesis, putting a left curly brace alone on a new line, adding the PowerShell cmdlets or actions to perform if that action is true beginning on another new line, and then ending with a right curly brace on a final new line. The key points here are that:
- The comparison statement must have a logical response of either TRUE or FALSE. Think of it as a yes or no question. If you need to do something not based on a yes or no question, then another loop construct is appropriate; we'll cover that in a bit.
- The code that runs if your statement is YES or NO must be within curly braces, and it is best practice to put these curly braces on lines by themselves so that you can match them up when you are writing more complicated scripts.
For example, if I wanted to compare two numbers -- let's say 5 and 10 -- and have PowerShell display whether 10 was greater than 5, then we could write the following if/then construct:
If (10 –gt 5)
You may already know that –gt is the PowerShell switch for "greater than." We used Write-Host in the previous example as well.
If we run this at a PowerShell prompt, we get:
That's kind of simple and probably not going to be a ton of use for you in your administrative duties. To make the construct a little more functional, you can add more "nests" to the If/Then block. Again, these execute in a progression -- in programming parlance, this is known as a serial construct, meaning one comparison has to finish, then the next one, and as soon as one finishes, the comparisons stop.
It would look like this:
If (10 –gt 11)
} elseif (11 –gt 10)
Write-Host "This time, yes"
You should be able to follow that one pretty easily; here is the result.
The first logical comparison (is 10 greater than 11? No) is false, so PowerShell moves on to the next one via the elseif comparison, which is PowerShell parlance for "next, please!" (is 11 greater than 10? Yes), and prints the Write-Host line I wrote for that test.
In constructs like these, when you're testing, it's best to have different output for each test. If I had chosen Yes for both constructs, and then run the script, I would not have been able to tell which comparison test was producing the Yes -- there's no differentiation. Here, I added "This time" so I could tell what was actually happening in the script.