Tags:
When working with variables in PowerShell, you can leverage built-in support for PowerShell variable string substitution. In this article we'll look at some rules for working with string substitution, and some examples to leverage in your own PowerShell scripts.
Some Rules for String Substitution
String substitution is something you will use in scripts and other short PowerShell 1-liners where you have a variable that you want to expand in a message. For example:
PS C:\Users\Sec504> $name = Read-Host "Tell me your name" Tell me your name: Josh PS C:\Users\Sec504> Write-Host "Nice to meet you, $name" Nice to meet you, Josh
Instead of using string concatenation to merge static strings and variables together, you can embed the variable inside of the quoted string. There are a few rules though:
PS C:\Users\Sec504> $name = Read-Host "Tell me your name" Tell me your name: Mick PS C:\Users\Sec504> Write-Host 'Nice to meet you, $name' Nice to meet you, $name
Rule 1: Variables are expanded in strings with double quotes.
If you specify a string with single quotes, it will treat the variable $name a literal value, and not a variable to substitute. Also:
PS C:\Users\Sec504> Write-Host "Do you love PowerShell, $name?" Do you love PowerShell, PS C:\Users\Sec504> Write-Host "Do you love PowerShell, $name, or whoever you are?" Do you love PowerShell, Mick, or whoever you are?
Rule 2: Add curly braces to be explicit around variable names
Some characters around variables are treated as part of the variable name, and not punctuation in the string, but this isn't always intuitive. The Microsoft documentation on PowerShell variables says:
Variable names begin with a dollar ($) sign and can include alphanumeric characters and special characters.
In the case of "Do you love PowerShell, $name?", PowerShell interprets the variable name as $name?, which doesn't exist and returns an empty string. In cases like this, you can surround the variable name in curly braces to force PowerShell to interpret the variable name in the way you want:
PS C:\Users\Sec504> Write-Host "Do you love PowerShell, ${name}?" Do you love PowerShell, Mick?
Rule 3: Be careful with the backtick
PowerShell also offers support for escape sequences, starting with a backtick followed by a letter. This is most often seen as n `` to add a newline:
PS C:\Users\Sec504> $age = Read-Host "Please enter your age.`nBe honest please" Please enter your age. Be honest please: 47 PS C:\Users\Sec504> Write-Host "The user is $age." The user is 47.
The backtick can also be used to escape a literal character in a string. Let's say you needed to have a literal " in your string -- you can escape the " with a preceding backtick:
PS C:\Users\Sec504> $pass = Read-Host -AsSecureString "Enter your password (do not include `" in the string)" Enter your password (do not include " in the string): **********
Examples
Let's apply these concepts into some practical examples.
User Messages
Let's say you want to allow a user to specify a directory name, and you report on the number of files in the directory. Here's a short script, countfiles.ps1:
$dirName = Read-Host "Enter the directory name" $count = (Get-ChildItem -Path $dirName | Measure-Object).Count Write-Host "There are $count files in the directory $dirName"
Invoking the script the user specifies the directory, and they get the answer. No string concatenation needed!
PS C:\Users\Sec504> .\countfiles.ps1 Enter the directory name: C:\Windows There are 101 files in the directory C:\Windows PS C:\Users\Sec504> .\countfiles.ps1 Enter the directory name: C:\Tools There are 46 files in the directory C:\Tools
Escape Sequences
Let's say you have a script that is about to do something that is irrevocable, like deleting thousands of users from Active Directory. You might want to give the script user a heads-up, and a chance to terminate the script before the damage is done.
Write-Host "Press CTRL+C before the timer expires to stop the script." For ($i = 9 ; $i -ne 0; $i--) { Write-Host -NoNewline "$i`b" ; Start-Sleep 1 } Write-Host "Deleting users now..." # Not actually deleting any users
These lines use a ForEach-Object loop (shortened to For, here), decrementing the variable $i from 9 to 0. The Write-Host line suppresses the automatic newline with NoNewline and moves the cursor back to the beginning of the line after displaying the current value of $i. This gives us a dramatic countdown allowing the user to press CTRL+C to stop the script.
Summary
In this article we looked at a topic all PowerShell users should understand: string substitution. PowerShell allows us to expand the value stored in a variable within a string, often eliminating the need to perform string concatenation. There are a few rules though: the string must be specified in double quotes, it is sometimes necessary to surround the variable name with curly braces, and the backtick character has special meaning. Keep these rules in mind, and you'll be leverage this powerful feature in all of your future PowerShell work!
Until next time!
-Joshua Wright
Joshua Wright is the author of SANS SEC504: Hacker Tools, Techniques, and Incident Handling, a faculty fellow for the SANS Institute, and a senior technical director at Counter Hack.