Running Windows PowerShell Scripts
Few things in life are as exciting as getting a brand-new command shell and scripting language; in fact, getting a brand-new command shell and scripting language is soexciting that you can barely get the thing out of the box before you want to take it for a spin. Those of you who’ve downloaded Windows PowerShell know exactly what we’re talking about: if you’re like most people, the very moment the installation process finished you double-clicked a .PS1 file (.PS1 being the file extension for Windows PowerShell scripts), sat back, and waited for the magic to happen.
As it turned out, however, thisis what happened:
Hmmm, instead of
running, your script opened up in Notepad. Interesting, but not
exactly what you had in mind. Oh wait, you think, I get it: you
probably have to run Windows PowerShell before you can run a
Windows PowerShell script. OK, that makes sense. And so, with that
in mind, you open up Windows PowerShell and type the path to the
.PS1 file at the command prompt. You press ENTER and wait for the
magic to happen:
As it turned out,
however,
thisis what happens:
File C:\scripts\test.ps1
cannot be loaded because the execution of scripts is disabled on
this system. Please see "get-
Wow; how nice. A new
command shell and scripting environment that doesn’t even let you
run scripts. What will those guys at Microsoft think of next?
Listen, don’t panic;
believe it or not, everything is fine. You just need to learn a few
little tricks for running Windows PowerShell scripts. And the
Scripting Guys are here to help you learn those tricks.
Running Scripts From Within Windows
PowerShell
Let’s start with
running scripts from within Windows PowerShell itself. (Which,
truth be told, is probably the most common way to run Windows
PowerShell scripts.) Why do you get weird error messages when you
try to run a script? That’s easy. The security settings built into
Windows PowerShell include something called the “execution policy;”
the execution policy determines how (or if) PowerShell runs
scripts. By default,
PowerShell’sexecution policy is set to
Restricted; that means that scripts – including those you
write yourself – won’t run.
Period.
Note. You can verify the settings for your execution policy
by typing the following at the PowerShell command prompt and then
pressing ENTER:
Get-
ExecutionPolicy
Now, admittedly,
this might seem a bit severe. After all, what’s the point of having
a scripting environment if you can’t even run scripts with it? But
that’s OK. If you don’t like the default execution policy (and you
probably won’t) then just go ahead and change it. For example,
suppose you want to configure PowerShell to run – without question
– any scripts that you write yourself, but to run scripts
downloaded from the Internet only if those scripts have been signed
by a trusted publisher. In that case, use this command to set your
execution policy to
RemoteSigned
:
Set-
ExecutionPolicy
RemoteSigned
Alternatively, you
can set the execution policy to
AllSigned
(all scripts, including those you write yourself, must be
signed by a trusted publisher) or
Unrestricted(
allscripts will run, regardless of where they come from and
whether or not they’ve been signed).
See? No need to need
to panic at all, is there?
Note. Not sure what we mean by “signing scripts?” Then open
up PowerShell, type the following, and press ENTER:
Get-Help
About_Signing
Or, even better, use our
Windows PowerShell Graphical Help Fileand read the same
topic in standard Windows help format. After you change
your execution policy settings it’s
possibleto run scripts. However, you still might run into
problems. For example, suppose you change directories from your
Windows PowerShell home directory to C:\Scripts (something you can
do by typing
cd
C:\Scripts). As it turns out, the C:\Scripts folder contains
a script named Test.ps1. With that in mind you type the following
and the
press ENTER:
Test.ps1
And here’s the
response you get:
The term 'test.ps1' is not
recognized as a cmdlet, function, operable program, or script file.
Verify the term and try again.
We know what you’re
thinking: didn’t we just change the execution policy? Yes, we did.
However, this has nothing to do with the execution policy. Instead,
it has to do with the way that PowerShell handles file paths. In
general, you need to type
the complete file pathin order to run a script. That’s true
regardless of your location within the file system. It doesn’t
matter if you’re in C:\Scripts; you still need to type the
following:
C:\Scripts\Test.ps1
Now, we said “in
general” because there are a couple of exceptions to this rule. For
example, if the script happens to live in the current directory you
can start it up using
the
.
\notation, like so:
.\Test.ps1
Note. There’s no space between
the .\ and the script name. And while PowerShell
won’t search the current directory for scripts it
willsearch all of the folders found in your Windows PATH
environment variable. What does that mean? That means that if the
folder C:\Scripts is in your path then you
canrun the script using this command:
Test.ps1
But be careful here.
Suppose C:\Scripts is
notin your Windows path. However, suppose the folder
D:\Archive
isin the path, and that folder also contains a script named
Test.ps1. If you’re in the C:\Scripts directory and you simply type
Test.ps1and press ENTER, guess which script will run? You
got it: PowerShell won’t run the script in C:\Scripts, but it
willrun the script found in D:\Archive. That’s because
D:\Archive is in your path.
Just something to keep in mind.
Note. Just for the heck of it, here’s a command that
retrieves your Windows PATH environment variable and displays it in
a readable fashion:
$a = $
env
:path; $
a.Split(";")
Even More
AboutFile Paths
Now we know that all
we have to do is type in the full path to the script file and we’ll
never have to worry about getting our scripts to run, right?
Right.
Well,
almostright. There’s still the matter of scripts whose path
name includes a blank space. For example, suppose you have a script
stored in the folder C:\My Scripts. Try typing this command and see
what happens:
C:\My
Scripts\Test.ps1
Of course, by now
you’ve come to expect the unexpected, haven’t you? Here’s what you
get back:
The term 'C
:\My' is not recognized as a cmdlet,
function, operable program, or script file. Verify the term and try
again.
This one you were
able to figure out on your own, weren’t you? Yes, just like good
old Cmd.exe, PowerShell has problems parsing file paths that
include blank spaces. (In part because blank spaces are how you
separate command-line arguments from the call to a script.) In
Cmd.exe all you can work around this problem by enclosing the path
in double quotes. Logically enough, you try the same thing in
PowerShell:
"C:\My
Scripts\Test.ps1"
And here’s what you
get back:
"C:\My
Scripts\Test.ps1"
Um, OK …. You try it
again. And here’s what you get back:
"C:\My
Scripts\Test.ps1"
You try it – well,
look, there’s no point in trying it again: no matter how many times
you try this command, PowerShell will simply display the exact same
string value you typed in. If you actually want to
executethat string value (that is, if you want to run the
script whose path is enclosed in double quotes) you need to preface
the path with the Call operator (the ampersand). You know, like
this:
& "C:\My
Scripts\Test.ps1"
Note. With this particular command you can either leave a
space between the ampersand and the path name or not leave a space
between the ampersand and the path name; it doesn’t matter. To summarize,
here’show you run from scripts from within Windows
PowerShell:
·
Make sure you’ve changed your execution policy. By
default, PowerShell won’t run scripts at all, no matter how you
specify the path.
·
To run a script, specify the entire file path, or
either: 1) use
the .\ notation to run a script in the
current directory or 2) put the folder where the script resides in
your Windows path.
·
If your file path includes blank spaces, enclose
the path in double quote marks and preface the path with an
ampersand.
And, yes, that all
takes some getting used to. However, you
willget used to it. (To make life easier for you, we
recommend that you keep all your scripts in one folder, such as
C:\Scripts, and add that folder to your Windows path.)
Note. So can you use
PowerShellto add a folder to your Windows Path? Sure; here’s
a command (that we won’t bother to explain in this introductory
article) that tacks the folder C:\Scripts onto the end of your
Windows path:
$
env
:path= $
env:path+ ";c:\scripts"
Bonus: “Dot Sourcing” a Script
Admittedly, up to
this point the news hasn’t been all that good: you can’t run a
PowerShell script by double-clicking the script icon; PowerShell
doesn’t automatically look for scripts in the current working
directory; spaces in path names can cause all sorts of problems;
etc. etc. Because of that, let’s take a moment to talk about one
very cool feature of Windows PowerShell scripting: dot
sourcing.
Suppose we have a
very simple VBScript script like this one:
A = 5
If you run this
script from the command window, the script will run just fine.
However, because we forgot to include an Echo statement we won’t
see anything happen onscreen. Because of that we’ll never know the
value of C. Sure, we could
trytyping
Wscript.Echo
Cat the command prompt, but all we’ll get back is the
following error message:
'
Wscript.echo' is not recognized as an
internal or external command
,
That should come as
no surprise: scripts are scripts, the command window is the command
window, and ne’er the twain shall meet. Sure, it would be
niceif the command window had access to values that were
assigned in a script (and vice-versa), but it
ain’t
gonnahappen.
At least not in VBScript.
Now, let’s consider
a Windows PowerShell counterpart to our VBScript script:
$A = 5
Suppose we run this script, then type
$Cat the command prompt.What do you think we’ll get
back? If you guessed nothing, then you guessed correctly:
In other words, we
don’t get back anything at all.
Which, again, should come as no great
surprise.Come on, Scripting Guys; shouldn’t this be leading
us somewhere?
Yes, it should. And
believe it or not, it is. Let’s run our PowerShell script again,
only this time let’s “dot source” it; that is, let’s type a period
and a blank space and
thentype the path to the script file. For example:
.
c:\scripts\test.ps1
When we run the
script nothing will
seemto happen; that’s because we didn’t include any code for
displaying the value of $C. But now try typing $C at the command
prompt .Here’s what you’ll get back:
15
Good heavens! Was
this a lucky guess on the part of the PowerShell console, or is
this some sort of magic?
Surprisingly enough,
it’s neither. Instead,
thisis dot sourcing. When you dot source a script (that is,
when you start the script by prefacing the path to the script file
with a dot and a blank space) any variables used in the script
become global variables that are available in multiple scopes. What
does
thatmean? Well, a script happens to represent one scope; the
console window happens to represent another scope. We started the
script Test.ps1 by dot sourcing it; that means that the variable $C
remains “alive” after the script ends. In turn, that means that
this variable can be accessed via the command window. In addition,
these variables can be accessed from other scripts.
(Or at least from other scripts started from
this same instance of Windows PowerShell.)
Suppose we have a
second script (Test2.ps1) that does nothing more than
displaythe value of the variable $C:
$C
Look what happens
when we run Test2.ps1 (even if we don’t use dot sourcing when
starting the script):
15
Cool. Because $C is
a global variable everyone has access to it.
And, trust us here:
this
ispretty cool. For example, suppose you have a database that
you periodically like to muck around with. If you wanted to, you
could write an elaborate script that includes each and every
analysis you might ever want to run on that data. Alternatively,
you could write a very simple little script that merely connects to
the database and returns the data (stored in a variable). If you
dot source that script on startup you can then sit at the command
prompt and muck around with the data all you want. That’s because
you have full access to the script variables and their values.
Note. OK, sure, this
couldcause you a few problems as well, especially if you
tend to use the same variable names in all your scripts. But that’s
OK; if you ever need to wipe out the variable $C just
runthe following command (note that,
with the
Remove-Variablecmdlet, we need to leave off the $ when
indicating the variable to be removed):
Remove-Variable C
Play around with
this a little bit and you’ll start to see how useful dot sourcing
can be.
Running Scripts
WithoutStarting Windows
PowerShell
We realize that it’s
been awhile, but way back at the start of this article we tried
running a Windows PowerShell script by double-clicking a .PS1 file.
That didn’t go quite the way we had hoped: instead of running the
script all we managed to do was open the script file in Notepad.
Interestingly enough, that’s the way it’s
supposedto work: as a security measure you can’t start a
PowerShell script by double-clicking a .PS1 file. So apparently
that means that you
dohave to start PowerShell before you can run a PowerShell
script.
In a somewhat
roundabout way, that’s technically true. However, that doesn’t mean
that you can’t start a PowerShell script from a shortcut or from
the
Rundialog box; likewise you
canrun a PowerShell script as a scheduled task.
The secret?Instead of calling the script
you need to call the PowerShell executable file, and then pass the
script path as an argument to PowerShell.exe. For example, in the
Rundialog box you might type a command like
powershell.exe –
noexitc:\scripts\test.ps1:
There are actually
three parts to this command:
·
Powershell.exe, the Windows PowerShell
executable.
·
-
noexit, an optional parameter that
tells the PowerShell console to remain open after the script
finishes. Like we said, this is optional: if we leave it out the
script will still run. However, the console window will close the
moment the script finishes, meaning we won’t have the chance to
view any data that gets displayed to the screen.
·
C:\Scripts\Test.ps1, the path to the script
file.
What if the path to
the script file contains blank spaces? In that case you need to do
the ampersand trick we showed you earlier; in addition, you need to
enclose the script path in
singlequote marks, like so:
powershell.exe -
noexit&'c
:\my scripts\test.ps1'
Strange, but
true!
Note. Here’s an interesting variation on this same theme:
instead of starting PowerShell and asking it to run a particular
script you can start PowerShell and ask it to run a particular
command. For example, typing the following in the
Rundialog box not only starts PowerShell but also causes it
to run the Get-
ChildItemcmdlet against the folder
C:\Scripts:
powershell.exe -
noexitget-
childitemc:\scripts
It’s possible to get
even
moreelaborate when starting Windows PowerShell, but this
will do for now. If you’d like more information on PowerShell
startup options just type
powershell.exe /?
fromeither the Windows PowerShell or the
Cmd.exe command prompt.
By the way, this is
the same approach you need to use if you want to run a Windows
PowerShell script as part of a logon script. You can’t simply
assign a .PS1 file as a logon script; the operating system won’t
know what to do with that. Instead, you’ll need to create a
VBScript script that calls the PowerShell script:
Set
objShell=
CreateObject
("
Wscript.Shell")
Assign this VBScript
script as the logon script and everything should work just fine.
(Assuming, of course, that you’ve installed Windows PowerShell on
any computers where this logon script is going to run.)
See? That Wasn’t So Bad
Admittedly, running
Windows PowerShell scripts might not be as straightforward and
clear-cut as it could be. On the other hand, it won’t take you long
to catch on, and you’ll soon be running PowerShell scripts with the
best of them. Most important, you’ll also be able to say things
like, “You know, you really ought to dot source that script when
you run it.” If
thatdoesn’t impress your colleagues then nothing will.
help
about_signing" for more details.
At line
:1char:19
+ c:\scripts\test.ps1
<<<<
At line
:1char:7
+ test.ps1
<<<<
At line
:1char:8
+ C:\My
<<<< Scripts\Test.ps1
B = 10
C = A + B
operable program or batch
file.
$B = 10
$C = $A + $B
Incidentally, the –
noexitparameter must immediately follow
the call to the PowerShell executable. Otherwise the parameter will
be ignored and the window will close anyway.
objShell.Run
("powershell.exe –
noexitc:\scripts\test.ps1")