PowerShell has several special operators that are capable of specialized tasks that can't be easily accomplished any other way.
The -replace operator can be used to substitute characters in a string. The operator essentially uses pattern matching to find a target string or character. If it is found, the substitution is made. The -replace syntax is:
"String-to-search" -replace "Search-for","Replace-with"
You can search and replace a single character or part of a word:
PS C:\> "PowerShell" -replace "e","3" Pow3rSh3ll PS C:\> "PowerShell" -replace "shell","tool" Powertool PS C:\> "PowerShell" -replace "k","m" PowerShell PS C:\>
In the first example all instances of the letter e are replaced with the number 3. In the second, the string "shell" is replaced with "tool". The last example shows that if no successful match is made, the string remains untouched.
You can use the -replace operator with variables, but be careful:
PS C:\> $var="PowerShell" PS C:\> $var -replace "p","sh" showerShell PS C:\> $var PowerShell PS C:\>
The -replace operator doesn't change the original variable - instead it only displays the replaced result. When we look at $var again we see it hasn't changed. If you want to change the variable value, you should use something like this:
PS C:\> $var=$var -replace "p","sh" PS C:\> $var showerShell PS C:\>
All we need to do is redefine $var by setting its value to the output of the
-replace operation.
The operator can also make replacements within collections and arrays:
PS C:\> $var=@("aaa","bbb","abab","ccc") PS C:\> $var aaa bbb abab ccc PS C:\> $var=$var -replace "a","z" PS C:\> $var zzz bbb zbzb ccc PS C:\>
We start with a simple array, then redefine $var using the -replace operator to change all occurrences of a to z.
There's really no limit when using this operator. You can even use it to make changes to text files:
PS C:\> $var=get-content "boot.ini" PS C:\> $var -replace "windows","WIN" [boot loader] timeout=15 default=multi(0)disk(0)rdisk(0)partition(2)\WIN [operating systems] multi(0)disk(0)rdisk(0)partition(2)\WIN="Microsoft WIN XP Professional" /fastdetect /NoExecute=OptIn multi(0)disk(0)rdisk(0)partition(1)\WIN="WIN Server 2003, Enterprise" /noexecute=optout /fastdetect C:\CMDCONS\BOOTSECT.DAT="Microsoft WIN Recovery Console" /cmdcons PS C:\>
Here we dumped the contents of our boot.ini file to $var and then replaced all instances of "Windows" with "WIN". Granted, this may not be the best production-oriented example, but it demonstrates the point.
Keep in mind that the -replace operator is case-insensitive. However, if you want to use this operator to make a case-sensitive search and replace, you can use the -creplace operator. Table 6.5 lists the replace special operators.
Operator | Definition | Example |
---|---|---|
-replace | Replace | "PowerShell" - replace "s","$" |
-ireplace | Case-insensitive replace. Essentially the same as | "PowerShell" - replace "s","$" |
-creplace | Case-sensitive replace. | "PowerShell" - creplace "p","t" |
When using -creplace, the replacement is only made when a case- sensitive match is made:
PS C:\> "PowerShell" -creplace "p","t" PowerShell PS C:\> "PowerShell" -creplace "P","t" towerShell PS C:\>
In the first example, since no lower case p is found, no replacement is made. However, in the second example a match is made, so the operator replaces P with t.
In Chapter 7 we will discuss how you can also use regular expressions for matching and replacing.
If you've been following along, by now you surely know that PowerShell is an object-oriented shell. As such, we may need to check if a variable is a particular type of object. PowerShell includes three type operators as shown in Table 6.6:
Operator | Definition | Example |
---|---|---|
-is | Check if object IS a specific type. | $var -is [string] |
-isnot | Check if object IS NOT a specific type. | $var -isnot [string] |
-as | Convert object to specified type. | 3.1416 -as string |
The operation result will be either TRUE or FALSE for -is and -isnot.
PS C:\> $now=get-date PS C:\> $now -is [datetime] True PS C:\> 1024 -is [int] True PS C:\> "Microsoft" -isnot [string] False PS C:\>
In the first example we create the variable $now from the output of the Get-Date cmdlet. Now we can use -is to validate that it is DateTime object. We do the same thing by verifying that 1024 is an integer. Both operations return TRUE. In the last example we checked to see if "Microsoft" is not a string. Since it is a strong, the operation returns FALSE.
The -as operator converts the object to the specified type:
PS C:\> $var=get-date PS C:\> $var.gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True DateTime System.ValueType PS C:\> if ($var -isnot [string]) { >> $var=$var -as [string] >> $var.gettype() >> $var.PadLeft(25) >> } >> IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object 5/21/2006 7:53:02 PM PS C:\>
In this example we created a DateTime object. To do this we called the GetType() method to show we have nothing hidden up our sleeves. However, we want to call the Padleft method of the string object. We check to see if $var is not a string. If so, then we use the -as operator to recreate $var as a string object. Again, we call GetType() to show the successful change and finally the Padleft method.
ToString
It is easier to convert an object to a string by using the ToString method. Most objects have this method. The end result is essentially the same as using the - as operator.
The Range operator (‥) is used to indicate a range of values. Keep in mind that you must specify the beginning and end points of the range:
PS C:\> $var=@(1..5) PS C:\> $var 1 2 3 4 5 PS C:\>
Here we created an array variable whose contents are 1 through 5 inclusive. The range operator only works with integer values. If you try this with string characters, PowerShell will complain:
PS C:\> $var=@("a".."j") Cannot convert value "a" to type "System.Int32". Error: "Input string was not in a correct format." At line:1 char:13 + $var=@("a".." <<<< j") PS C:\>
Call operators are used when you want to execute a command. Sometimes PowerShell can't tell if what you typed is a command. To force PowerShell to execute a statement, use the ampersand (&) character. For example, we might want to execute all PowerShell scripts in the current directory:
PS C:\> $all=get-childitem *.ps1 PS C:\> foreach ($s in $all) {&$s} PS C:\>#each Powershell script executes
You can also use the call operator to create a variable that holds the results of a cmdlet:
PS C:\> $j=get-process | where {$_.workingset -gt 5000000} PS C:\> &$j PS C:\> #an array of all processes with a workingset size greater than 5000 is returned.
In this example, when we force $j to run the output is little unfriendly. We can get a nicer output from $j using a command like this:
PS C:\> foreach ($item in $j) {$item.name}
In both of these examples, the variable we are creating is the output of the cmdlet we ran. In a significant manner this is slightly different than the following:
PS C:\> $j="get-process" PS C:\> $j get-process PS C:\> &$j | where {$_.workingset -gt 5000000} Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName ------- ------ ----- ----- ----- ------ -- ----------- 209 6 3696 6768 56 25.65 416 avgcc 873 21 34840 16820 161 1,282.25 1256 explorer 1056 24 97188 116708 464 247.16 4972 firefox 806 81 16636 21764 143 17.18 5264 Groove 659 20 28224 5284 264 75.64 1488 iexplore 234 10 10912 6116 68 17.09 1420 mmc 251 5 9308 4920 47 251.73 1552 MsMpEng 63 3 1696 5604 37 0.54 1372 notepad 1772 69 112832 31536 712 200.94 2304 OUTLOOK 553 11 49156 48388 163 7.16 532 powershell 393 61 15164 9952 89 94.55 596 Skype 559 12 16192 12808 97 5,118.91 1676 Smc 298 13 14816 6464 88 177.96 576 StatBar 1549 51 24640 15220 166 366.55 1596 svchost 351 30 14612 551216 653 3,497.73 5412 vmware-vmx 446 17 33656 53764 282 25.21 2600 WINWORD 592 21 21564 15984 106 11.52 4636 wmplayer PS C:\>
In this instance we set $j to a string of a cmdlet name. When we use the call operator, the value of $j is evaluated and executed. Notice that we added our workingset filter to the line where $j is executed. This is because the $_ variable doesn't exist until the cmdlet is run. All we've really done here is essentially create another alias for the Get-Process cmdlet.
Don't get too hung up on this operator. The only time you are likely to use it is when calling a PowerShell command from outside of PowerShell:
C:\powershell &c:\scripts\showservices.ps1
This command is run from a Windows CMD prompt. Using the & operator tells PowerShell to execute c:\scripts\showservices.ps1. This is one way you can integrate your PowerShell scripts into your Windows CMD environment.
The PowerShell format operator (-f) let's you format strings using the .NET string object format method. The syntax is a little backwards compared to what we worked with so far:
PS C:\ > FormatString -f "string to format"
.NET formatting is a way of specifying the format of a particular object. For example, a datetime object could be formatted as a short date (5/22/2006) or a long date (Monday, May 22, 2006). You can format a number as currency, number, or percent. To get the most out of this operator, you need to become very familiar with .NET formatting, most of which is outside the scope of this book. However, we'll provide a few examples that you will find useful.
PS C:\ > $now=get-date PS C:\> $now Monday, May 22, 2006 1:10:59 PM PS C:\> "{0:d}" -f $now 5/22/2006 PS C:\> "{0:D}" -f $now Monday, May 22, 2006 PS C:\> "{0:t}" -f $now 1:10 PM PS C:\> "{0:T}" -f $now 1:10:59 PM PS C:\>
In this example we created the variable $now that holds the current date and time. We can format this variable in a number of ways. First, we can use the format pattern {0:d} to display $now as a short date. Alternatively, we can use {0:D} to format $now as a long date. This is another example where PowerShell is case-sensitive. Using {0:t} or {0:T} will format for short or long time respectively.
Let's look at the examples of numeric formatting that are included below.
PS C:\> $var=12345.6789 PS C:\> "{0:N}" -f $var 12,345.68 PS C:\> "{0:N3}" -f $var 12,345.679 PS C:\> "{0:F}" -f $var 12345.68 PS C:\> "{0:F3}" -f $var 12345.679 PS C:\>
The numeric variable is being formatted in these examples. In the first example, the formatting patter {0:N} formats the variable as a number with a thousands separator. The default for this formatter for most English language systems is to specify two decimal places. This can be changed by using a precision modifier. In the second example, {0:N3} instructs PowerShell to format $var as a number to three decimal places. Using the F formatting string tells PowerShell to format the number in a fixed format. {0:F} is practically the same as {0:N} except there is no thousands separator. We can also specify a precision modifier such as {0:F3} to control the number of decimals.
Before we leave the formatting operator, here's a practical example:
PS C:\> $proc=get-process | where {$_.workingset -gt 5000000} PS C:\> foreach ($p in $proc) { >> $ws="{0:N4}" -f ($p.workingset/1048576) >> write-host $p.name `t $ws "MB" >> } >> $n=get-date >> $d="{0:T}" -f $n >> write-host "run at" $d >> avgcc 6.8984 MB avgemc 17.5781 MB explorer 32.0117 MB firefox 216.0430 MB Groove 11.1250 MB iexplore 76.4063 MB MsMpEng 5.0898 MB powershell 21.6094 MB Skype 11.8594 MB Smc 9.3828 MB StatBar 6.7344 MB svchost 30.1836 MB THUNDE~1 49.9141 MB WINWORD 54.8281 MB wmplayer 17.7539 MB wuauclt 19.0352 MB run at 10:07:47 PM PS C:\>
In this example we loop through $proc and display the process name, it's working set size in MB to four decimal places, and end with a time stamp. You will find it easier to create new variables when formatting. In the example below, we create $ws as the value of the working set size divided by 1048576 and formatted to four decimal places:
$ws="{0:N4}" -f ($p.workingset/1048576)
We perform a similar formatting task by setting $n to the current date and time, and then formatting $n in a short time pattern:
$d="{0:T}" -f $n
Online Help
MSDN documentation on .NET formatting is available at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconFormattingTypes.asp