Variables play a key role in PowerShell since they do in most scripting technologies. A variable is a placeholder for some value. The value of the placeholder might change based on script actions or intentional changes. In other words, the value is variable.
In VBScript, variables are typically set with string values. Consider the following code fragment:
Set objNetwork=CreateObject("wscript.network") strUserName=objNetwork.UserName wscript.echo "Current user is " & strUsername
The variable strUserName contains the string value that is returned from the Username property of the objNetwork object. It is often easier to use the variable strUserName instead of constantly calling objNetwork. Username. We can use variables in PowerShell the same way.
PowerShell variable names must begin with $:
PS C:\> $name="SAPIEN Technologies, Inc." PS C:\> $name SAPIEN Technologies, Inc. PS C:\>
In this example, we have created a variable, $name, with a value of "SAPIEN Technologies, Inc." We can display the value of the variable by invoking the variable name. This variable will maintain this value until we close the shell or set $name to something else.
There are two important things to note in this example.
We never had to formally declare the variable.
We're not writing a script.
PowerShell allows variables to be used "within the shell" or interactively without requiring you to write a script. Variables used interactively stay in memory for the duration of the PowerShell session.
Variables can contain numbers as the following example demonstrates:
PS C:\> $pi=3.1416 PS C:\> {decimal]$R=Read-host "Enter a radius value" Enter a radius value: 4 PS C:\> $Area=$pi*($R*$R) PS C:\> Write-host "The Area of a circle with a radius of $R is $Area The Area of a circle with a radius of 4 is 50.2656 PS C:\>
The example is pretty straightforward. We begin by defining a variable called $pi. A value for the radius variable, $R, is set by calling Read-Host. We specifically cast it as a decimal type otherwise $R will be treated as a string, which would cause the mathematical expressions to not be properly interpreted. A variable, $Area, is set with the appropriate mathematical formula. Finally, we use Write-Host to display the results.
Note | If you've been coding VBScript for awhile you might get a little confused. PowerShell doesn't require any concatenation symbols like & or + to join strings and variables together. With PowerShell you simply wrap anything you want displayed in quotes and type out the expression. |
If we want to run this again, all we need to do is press the up arrow a few times to reset $R and rerun the Write-Host cmdlet. If you're thinking this is a cumbersome method to use variables and repeat code - you're right! A better approach would be to create a function, which we'll cover in Chapter 11:
We can also set a variable to hold the results of a cmdlet:
PS C:\> $proc500=get-process | where {$_.handles -gt 500} PS C:\> $proc500 Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName ------- ------ ----- ----- ----- ------ -- ----------- 684 7 1680 4580 27 3.96 868 csrss 578 13 26112 38372 104 33.44 2024 explorer 680 76 12024 4896 114 4.39 3916 Groove 1926 54 47988 9536 187 39.28 1228 iTunes 541 12 15092 9892 91 79.01 1896 Smc 1228 42 12900 19756 88 15.61 1860 svchost 1141 0 0 220 2 23.15 4 System 527 21 6716 3488 52 2.04 892 winlogon PS C:\>
In this example we create a variable called $proc500. The value of this variable is created by taking the object output of a Get-Process cmdlet and piping it to the Where cmdlet. The Where cmdlet returns any process with a handle count greater than 500. When you type $proc500 at the next prompt, PowerShell displays the variable's contents in formatted output. It is important to remember that this is not a function or a cmdlet. The value of $proc500 is not reevaluated every time it is invoked.
However, the value of $proc500 is more than a collection of strings. In fact, it is an object that can be further manipulated. For example, if you run $proc500. count, PowerShell returns a value of 8, which is the number of processes in $proc500. We'll cover variables as objects in more detail later in this chapter.
PowerShell includes several cmdlets for working with variables that you can see by asking for help:
PS C:\> help *var* Name Category Synopsis ---- -------- -------- get-variable Command Gets a PS variable new-variable Command Creates a new variable. set-variable Command Sets a variable and a ... remove-variable Command Removes a variable and... clear-variable Command Removes the value from... about_Automatic_variables HelpFile Variables automaticall... about_Environment_variable HelpFile Accessing Windows envi... about_Shell_variable HelpFile Variables defined auto... PS C:\>
Recall that you can get a variable's value by typing out the variable name. But what if you forgot the variable name? If you can remember at least part of it, you can use Get-Variable to list all matching variables and their values:
PS C:\> get-variable v* Name Value ---- ----- var 9.42 VerbosePreference SilentlyContinue PS C:\>
In this example we are finding all the variables that begin with the letter "v". Notice we didn't' need to use $v*. The $ symbol is used in conjunction with the variable name when used in the shell.
Run Get-Variable * to see all the defined variables:
PS C:\> get-variable * Name Value ---- ----- Error {System.Management.Automation.ParseExce DebugPreference SilentlyContinue PROFILE C:\Documents and Settings\admin\My HOME C:\Documents and Settings\admin Host System.Management.Automation.Internal.H MaximumHistoryCount 64 MaximumAliasCount 4096 pi 3.1416 input System.Array+SZArrayEnumerator var 9.42 StackTrace at System.Number.StringToNumber(Stri ReportErrorShowSource 1 proc {csrss, explorer, Groove,.. ExecutionContext System.Management.Automation.EngineIntr true True VerbosePreference SilentlyContinue PSHOME C:\Program Files\Windows PowerShell\v1. ShellId Microsoft.PowerShell false False null MaximumFunctionCount 4096 ErrorActionPreference Continue ConsoleFileName ReportErrorShowStackTrace 0 r 5 ? True PWD C:\ ^ get-variable _ ReportErrorShowExceptionClass 0 ProgressPreference Continue MyInvocation System.Management.Automation.Invocation args {} MaximumErrorCount 256 Area 13961.2704 WhatIfPreference 0 $ $v* ReportErrorShowInnerException 0 WarningPreference Continue PID 2280 ConfirmPreference SilentlyContinue MaximumDriveCount 4096 MaximumVariableCount 4096 PS C:\>
You will recognize some of these variables from our earlier examples. However, note that variables such as MaximumErrorCount or PSHOME are PowerShell's automatic variables that are set by the shell. Table 5-1 lists these variables. Keep in mind that you should not create a variable that uses one of these default automatic variable names.
Variable | Description |
---|---|
$$ | Contains the last token of the last line received by the shell. |
$? | Contains the success/fail status of the last operation. |
$^ | Contains the first token of the last line received by the shell. |
$_ | Contains the current pipeline object, used in script blocks, filters, and the where statement. |
$Args | Contains an array of the parameters passed to a function. |
$DebugPreference | Specifies the action to take when data is written using write-debug in a script or WriteDebug in a cmdlet or provider. |
$Error | Contains objects for which an error occurred while being processed in a cmdlet. |
$ErrorActionPreference | Specifies the action to take when data is written using write-error in a script or WriteError in a cmdlet or provider. |
$foreach | Refers to the enumerator in a foreach loop. |
$Home | Specifies the user's home directory. Equivalent of %homedrive%%homepath%. |
$Input | Use in script blocks that are in the middle of a pipeline. |
$LASTEXITCODE | Contains the exit code of the last Win32 executable execution. |
$MaximumAliasCount | Contains the maximum number of aliases available to the session. |
$MaximumDriveCount | Contains the maximum number of drives available, excluding those provided by the underlying operating system. |
$MaximumFunctionCount | Contains the maximum number of functions available to the session. |
$MaximumHistoryCount | Specifies the maximum number of entries saved in the command history. |
$MaximumVariableCount | Contains the maximum number of variables available to the session. |
$PsHome | The directory where Windows PowerShell is installed. |
$Host | Contains information about the current host. |
$OFS | Output Field Separator, used when converting an array to a string. By default, this is set to the space character. The following example illustrates the default setting and setting OFS to a different value:
|
$ReportErrorShowException Class | When set to TRUE, shows the class names of displayed exceptions. |
$ReportErrorShowInnerException | When set to TRUE, shows the chain of inner exceptions. The display Of each exception is governed by the same options as the root Exception, that is, the options dictated by $ReportErrorShow* will be used to display each exception. |
$ReportErrorShowSource | When set to TRUE, shows the assembly names of displayed exceptions. |
$ReportErrorShowStackTrace | When set to TRUE, emits the stack traces of exceptions. |
$StackTrace | Contains detailed stack trace information about the last error. |
$VerbosePolicy | Specifies the action to take when data is written using Write-verbose in a script or WriteVerbose in a cmdlet or provider. |
$WarningPolicy | Specifies the action to take when data is written using Write-warning in a script or WriteWarning in a cmdlet or provider. |
Windows has its own set of environmental variables such as %Path% and %Windir%. You can access these variables with the env provider in PowerShell. A provider acts as an interface between PowerShell and an internal data source. In this case, you can access the environmental variables that are stored in the registry. When accessing a variable in expression mode, which is also referred to as the prompt, you type $env:variablename. Don't let this confuse you - we're just using the $ character to prefix the env: provider. Note the colon at the end of the provider name.
Here is an example of how to use the provider:
PS C:\> $env:systemroot E:\WINDOWS PS C:\> $env:path E:\Program Files\Windows Resource Kits\Tools\;E:\WINDOWS\system32;E:\WINDOWS;E: \WINDOWS\System32\Wbem;E:\Program Files\Support Tools\;E:\Program Files\Common Files\Roxio Shared\DLLShared;E:\Program Files\Common Files\GTK\2.0\bin;E:\Program Files\Windows Power Shell\v1.0\ PS C:\>
When used with a cmdlet, you only need to use just env: instead of $env:.
If you want to see all of the current Windows environmental variables in PowerShell, type:
Get-Childitem env:
This is the equivalent of the SET command in the traditional Cmd shell. If you want the variables sorted by name use:
Get-Childitem env: | sort {$_.key}
PowerShell has a specific cmdlet for creating variables called Set-Variable that has an alias of Set. The syntax is as follows:
PS C:\> set-variable var "Computername" PS C:\> $var Computername PS C:>
This is the same as typing $var="Computername". This cmdlet has several parameters for which you might find some need. For one thing, you can define a read-only or constant variable:
PS C:\> set-variable -option "constant" -name pi -value 3.1416 PS C:\> get-variable pi Name Value ---- ----- pi 3.1416 PS C:\> $pi=0 Cannot overwrite variable pi because it is read-only or constant. At line:1 char:4 + $pi= <<<< 0 PS C:\>
By using the -option parameter, you can specify that you want the variable to be a constant. Once set, you cannot change the value or clear or remove the variable. It will exist for as long your PowerShell session is running. If you close the shell and reopen it, the constant no longer exists.
Variable Already Exists
If you've been following along with the chapter in your own PowerShell session, you may already have a variable called pi. If so, when you try to run the previous code, you'll get an error that an existing variable cannot be made constant. You can only set the constant option when the variable is first created. In this instance, use Remove-Variable to delete pi and try to run this code again. It should now work with no errors.
The -scope parameter allows you to define the variable's scope or where it can be used. Typically, you will set the scope to global, local, or script.
PS C:\>set-variable -scope "global" -name var -value 1
Although it is not required, you can create variables with additional parameters such as -option and -scope. We also recommend that you use -name and -value, which helps remove any ambiguity about your intentions.
If you want to define a variable with a cmdlet's output you need to pipe the cmdlet to set-variable:
PS C:\> get-service |where {$_.status -EQ "stopped"} | set-variable -scope "private" -name StoppedServices PS C:\> get-variable stoppedServices Name Value ---- ----- StoppedServices {Alerter, ALG, AppMgmt, aspnet_state,… PS C:\>
This is a little more complicated than:
PS C:\>$stoppedServices= get-service |where {$_.status -EQ "stopped"}
However, it is necessary if you want to specify additional set-variable parameters.
This cmdlet is almost identical to Set-Variable. You can specify the variable's scope and option as follows:
PS C:\> new-variable -option "constant" -name myZip -value 13078 PS C:\> get-variable myzip Name Value ---- ----- myZip 13078
However, if you attempt to use New-Variable again to create the same variable but with a different name, PowerShell will refuse:
PS C:\> new-variable myZip 89123 new-variable : A variable with name 'myZip' already exists. At line:1 char:13 + new-variable <<<< myZip 89123
If you needed to change the variable value, you need to use Set-Variable. However, even that will not work in this example because myZip was created as a constant.
You might wonder how you will know when various cmdlets should be used. The answer is that it probably depends on what type of variables you are creating and how they will be used. For example, you may want to create all the empty variables you will need at the beginning of a script with New-Variable, and then use Set-Variable to define them as needed. Using different cmdlets may help you keep track of what is happening to a variable throughout the script.
The process of retaining a variable while changing its value is straightforward:
PS C:\> $var="apple" PS C:\> $var apple PS C:\> $var="orange" PS C:\> $var orange PS C:\>
This example creates the variable, $var, and then sets it to a value. In this case the value was set it to "apple." Changing the value to "orange" is just as easy. If for some reason you want to retain the variable but remove the value, you can use the Clear-Variable cmdlet:
PS C:\> clear-variable var PS C:\> $var PS C:\>
Notice we didn't need to use $var, just var. We also could have set $var="":
PS C:\> $var orange PS C:\> $var="" PS C:\> $var PS C:\>
Technically Speaking
Technically, setting $var="" is not the same thing as using the Clear-Variable cmdlet. The cmdlet actually erases the value. The expression $var="" is really setting the value of $var to a string object with a length of 0. In most instances this shouldn't be an issue, but if in doubt, use Clear-Variable.
You can also clear multiple variables with a single command:
PS C:\> $var=1 PS C:\> $var2=2 PS C:\> $var3=3 PS C:\> get-variable var* Name Value ---- ----- var 1 var3 3 var2 2 PS C:\> clear-variable var* PS C:\> get-variable var* Name Value ---- ----- var var3 var2 PS C:\>
In this example we created variables, var, var2, and var3. We used Get-Variable to display the values, followed by Clear-Variable var* to clear the values of any variables that started with var.
The last item to understand about Clear-Variable, is that invoking Clear-Variable in a child scope has no effect on variables in the parent scope. In fact, this is typically true of most cmdlets. Refer back to Chapter 1 for a refresher on PowerShell scopes:
PS C:\> $var=3 PS C:\> &{clear-variable var} PS C:\> $var 3 PS C:\>
The first line of this example is considered the parent scope. Using the ampersand character invokes a child scope and attempts to clear var. But as you can see, that cmdlet had no effect. Var remains untouched.
When you want to remove the variable and its value, then call the Remove-Variable cmdlet. The syntax is essentially the same as Clear-Variable. You can remove a single variable:
PS C:\> $var="foobar" PS C:\> $var foobar PS C:\> remove-variable var PS C:\> $var PS C:\>
Alternatively, you can remove multiple variables with a wildcard:
PS C:\> get-variable var* Name Value ---- ----- var 5 var3 980 var2 78 PS C:\> remove-variable var* PS C:\> get-variable var* PS C:\>