One of the things that I’ve both appreciated about PowerShell but also been at times confused by PowerShell is its concepts of strings and variables. This article explains what you need to know when working with PowerShell strings.
For example, when you start writing in PowerShell, you may notice that you can use single quotes or double quotes to designate a string.
Starting simple
1 2 3 4 5 6 |
"A very simple string." $string1 = "This is a string variable." $string2 = 'This is also a string variable.' $string1, $string2 write-host $string1, $string2 write-host $string1 $string2 |
Save the above as SimpleStrings_demo.ps1. And as usual, examples are available at Github.
When you run the above, you will see the following output:
The first line is echoed as is because you haven’t told PowerShell to do anything special.
Then you have created two variables and assigned strings to them. Again, in the case where there’s no assignment and no cmdlet used, PowerShell simply echos out the contents of the variables, one to a line.
When you use the write-host variable, PowerShell will again write them out, but this time keep them on the same line. It doesn’t matter here if you use a comma or not to separate them.
So far, the strings with double quotes and single quotes act the same way. But there is a difference which you’ll see in the following example:
1 2 3 4 5 6 7 |
$name = "Greg" $age = 53 "My name is $name and my age is $age." $string1 = "DQ: My name is $name and my age is $age." $string2 = 'SQ: My name is $name and my age is $age.' write-host $string1 write-host $string2 |
Save the above as SimpleStrings_with_variables_demo.ps1 and run it.
Your output will look like:
You will immediately notice that in the case of the double quotes, PowerShell did replace the inline variables of $name
and $age
with their values. However, in the case of single quotes, it treated the variables as part of the string itself and did not replace them.
The upside is that it’s very easy to write out strings with the value of the variables embedded directly in the string. The downside is that you can’t easily print out the variable’s name, which you may want to do while debugging a script.
The following example, SimpleStrings_with_variables_demo_2.ps1 shows a few ways of solving that problem:
1 2 3 4 5 6 7 8 9 |
$name = "Greg" $age = 53 "My name is $name and my age is $age." $string1 = "The `$name value is $name and the `$age value is $age." $string2 = 'The $name value is ' + $name + ' and the $age value is ' + $age $string3 = 'The $name value is ' + $name + " and the `$age value is $age" write-host $string1 write-host $string2 write-host $string3 |
You will notice the backtick character ` allows you to escape the $ so that PowerShell does not treat the characters that follow as a variable name. That is generally the way I do it.
You may be tempted, and it’s perfectly legal, to build a string as shown in $string2
, however, I find that harder to read and more complex and see no value to it. $string3
is simply an example showing you can use both single-quoted strings and double-quoted strings when building up a larger string. However, I would definitely avoid that one.
Dealing with objects
You will often find yourself dealing with objects when working with PowerShell. Dealing with objects introduces an issue, but fortunately, like most things, PowerShell has a solution. The following examples can be found in the Github repository in the file Strings_with_object.ps1.
Start by creating an object. For the purposes of this demo, it will be a simple instantiation and assignment.
1 2 |
$person1= @{Name='Greg' Age=53} |
This object has two properties: a name and an age. Again if you simply hand the object to PowerShell and execute it, PowerShell will print something out, but a bit differently from the above examples.
Pass $person1
to PowerShell and hit enter, and you should see something like:
This method is not terrible, but also not terribly useful. However, if you try to use the write-host cmdlet as follows: write-host $person1
, you don’t get what you might expect. Instead, you get the curious response of:
That’s not overly helpful. If you try to put the object in between double quotes (since you know with single quotes, it will simply print out what it is handed), you will get the following:
1 |
write-host "This is all about $person1" |
Note the difference in the two responses. In the first case, PowerShell is attempting to parse the object and determine two properties within the object. In the second case, PowerShell doesn’t do any parsing but simply determines it is a hashtable.
The above responses provide the clues you need to get what you want. But before you get there, try the following:
1 |
$person1.Name, $person1.Age |
You will get:
This result makes sense because now you are specifying which property you want, but it’s still far from perfect.
You may try the following, which seems like it should work:
1 |
write-host "This is all about $person1.Name" |
But, curiously, this fails with the following:
Note that this message is a bit different from the above one that mentioned this being a Hashtable. It has .Name
appended to the end. It appears that PowerShell is correctly trying to expand the object, but it’s ignoring your reference to a specific property.
The solution here is to force PowerShell to evaluate the entire object before it gets to Write-Host
.
You may be tempted to try the following:
1 2 3 |
# A work around $personName = $person1.Name write-host "This is all about $personName" |
Executing this will work:
But, it’s wordy and, in my opinion, a bit messy. Imagine you had an object with a dozen or more properties you wanted to write out.
The solution is to take advantage of scoping and to use parentheses as follows:
1 |
write-host "This is all about $($person1.Name) who is $($person1.Age)" |
This code will return:
This result is most likely what you wanted. PowerShell starts with the object inside the parentheses (e.g. $person1.Name
) and evaluates that, and then treats it as a variable denoted by the outer $. Write-host then evaluates that variable and inserts it into the string.
Note this means you can do some additional fancy things such as the following
1 2 3 |
$person2 = @{Name="Joe" Age=78} write-host "Together $($person1.Name) and $($person2.Name) are a total of $($person1.Age + $person2.Age) years old." |
This will produce:
The summation of the ages of $person1
and $person2
happens before Write-host
evaluates the outer $.
Formatting strings
Imagine you are tasked with using PowerShell to print out invoices from an order management system. With your newfound knowledge, you sit down and write something like:
1 2 3 |
$cost = 144.56 $quantity = 11 Write-host "Your cost for $quantity will be: $($cost*$quantity)" |
Your output looks like:
It’s not quite perfect. You’d really like to include a currency character to the string, but you can come back to that later.
The more immediate issue is that when $quantity = 10
. Then you get the following:
Note the missing trailing 0.
This problem is fortunately easy to fix. PowerShell strings allow formatting using .NET standards.
One simple way of fixing the above is the code below:
1 2 |
$formatted = "Your cost for {0} will be: {1:f2}" -f $quantity, $($quantity*$cost) write-host $formatted |
This will print:
That’s an improvement. The f2
is an instruction to return 2 floating-point values after the period. Additionally, you may want to put a currency symbol in there and a comma.
A simple fix would simply to do the following:
1 2 |
$formatted = "Your cost for {0} will be: `${1:n2}" -f $quantity, $($quantity*$cost) write-host $formatted |
Note two essential parts here. The dollar sign was added with a backtick ` so PowerShell doesn’t interpret it as the start of a variable name. In addition, by changing the f
to n
, PowerShell will treat this as a number using a cultural separator. This code will work equally well in a machine set up in Europe, where they tend to reverse the use of the period and comma separators. However, the currency character is still an issue which can be fixed with slightly different formatting:
1 2 |
$formatted = "Your cost for {0} will be: {1:c2}" -f $quantity, $($quantity*$cost) write-host $formatted |
Note that the $
is no longer needed as part of the string.
PowerShell isn’t just limited to formatting currency; you can use it for other formats. For example, say you needed to generate a list of User IDs with a specific format:
1 |
1..15 | % { 'UserID_{0:d4}' -f $_ } |
The above will generate 15 User IDs of the format:
A common requirement is formatting dates. There’s a couple of ways of doing this. If you do nothing and simply accept the defaults as follows:
1 2 |
$exampledate = get-date write-host $exampledate |
The results depend on your regional settings. In the US, you will get:
You could format the date when you create it:
1 2 |
$fdate = get-date -Format "yyyy-MM-dd" write-host $fdate |
This will return:
Unfortunately, the variable $fdate
contains only the information shown. You can’t later reference the time if you want.
However, there are a lot of built-in formats available:
1 2 |
$fdate = get-date -Format "R" write-host $fdate |
This method returns:
If you want to store the full value of the returned date and later use only a formatted portion of it, you can do something like the following:
1 2 |
write-host $exampledate.ToString('yyyy-MM-dd') Write-Host $exampledate.ToString("hh:mm:ss") |
As you can see, there are plenty of ways to format your strings, dates, and other variables.
String padding and trimming
Often you may find yourself wanting to pad out or trim a string. You may want items to appear clearly in columns on the screen, or you may write to a file with fixed-length fields.
This task can be easily handled, as seen in the examples below. Save these as String_Padding_and_Trimming.ps1.
First, you need to generate some strings. Note that while the first variable claims to have three characters, it actually has a trailing space. This might go unnoticed in some cases if the value was read in from a database field.
1 2 3 4 |
$3char = "123 " # note space! $4char = "4567" write-host $3char Write-Host $4char |
This looks perfectly fine as is:
1 2 3 4 5 |
# But what if we want them to line up, and we expect someday we might even have longer strings. $padamount = 5 $padcharacter = ' ' write-host $3char.PadLeft($padamount,$padcharacter) Write-Host $4char.PadLeft($padamount,$padcharacter) |
This now almost works, but that trailing space is obvious:
Fortunately, this is fairly easy to fix using the trim()
method:
1 2 |
write-host $3char.trim().PadLeft($padamount,$padcharacter) Write-Host $4char.PadLeft($padamount,$padcharacter) |
You can also pad to the right and, of course, select other characters. Again notice the trailing space is an issue, so in the second example, you can eliminate it.
1 2 3 4 |
$padamount = 7 $padcharacter = '.' write-host $3char.PadRight($padamount,$padcharacter) Write-Host $4char.PadRight($padamount,$padcharacter) |
1 2 |
write-host $3char.trim().PadRight($padamount,$padcharacter) Write-Host $4char.PadRight($padamount,$padcharacter) |
You can do a lot more with the Pad and Trim methods once you fully understand them.
Adding some color to your life
Finally, what is life without some color, or, in this case, showing strings with color?
Like most things, PowerShell makes this very easy. Below is a script that was possibly written by a Hobbit to keep track of something near and dear to their stomach.
Save the following script as String_Color.ps1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
$tod = get-date if ($tod.Hour -ge 6 -and $tod.Hour -lt 9) { write-host "Time for Breakfast!" -ForegroundColor Yellow } elseif ($tod.Hour -ge 9 -and $tod.Hour -lt 11) { write-host "Time for 2nd Breakfast!" -ForegroundColor Red -BackgroundColor Green write-host "That's only if he knows about second breakfast!" } elseif ($tod.Hour -ge 11 -and $tod.Hour -lt 12) { write-host "Elevenses!" -BackgroundColor Red } elseif ($tod.Hour -ge 12 -and $tod.Hour -lt 14) { write-host "Luncheon" -ForegroundColor Red -BackgroundColor Yellow } else { Write-host "Afternoon Tea - 2:00 PM until 5:00 PM " -ForegroundColor Black -BackgroundColor DarkRed -NoNewline Write-host "Dinner - 7:00 PM until 9:00 PM " -ForegroundColor Red -BackgroundColor DarkBlue -NoNewline Write-host "Supper - 9:00 PM until 11:00 PM " -ForegroundColor Red -BackgroundColor DarkGreen } |
The above script will help any Hobbit keep track of what meal they should be planning for. Note that portion control in case 12 dwarves show up unexpectedly is not covered.
If it’s early in the day, the script will simply change the foreground color of the text to yellow. This color change is done merely by adding the –foreground parameter to write-host.
In the case of second breakfast, you can set both the foreground and background colors as you desire. You will also note that any color you set is only in effect for that particular write-host cmdlet. The following one will revert back to the host colors in your terminal or IDE.
You can, as demonstrated with Elevenses, set only the background color.
Finally, if you want to have multiple colors on the same line, you can take advantage of the –NoNewLine parameter for Write-Host and suppress adding a newline character to your output. This technique can be useful if you want to build a menu option such as below: (save as Select_Option_With_Color.ps1)
1 2 3 4 5 6 7 8 9 10 11 |
write-host "1) " -ForegroundColor Red -NoNewline write-host "select Option 1" -ForegroundColor Yellow write-host "2) " -ForegroundColor Red -NoNewline write-host "select Option 2" -ForegroundColor Yellow write-host "3) " -ForegroundColor Red -NoNewline write-host "select Option 3" -ForegroundColor Yellow $result = Read-host "Select an option above" if ($result -ge 1 -and $result -le 3) { Write-host "Thank you for selecting $result" } else { "You selected an invalid value $result" } |
PowerShell strings
In general, string handling in PowerShell is quite simple, but minor differences such as using double quotes or single quotes can make a difference. In addition, knowing how to escape a character or force the evaluation of a variable inside a string can make life simpler as you don’t need to add additional steps before you can output your string.
Additionally, most of the string operations shown in the article can be used when outputting to a file, making the creation of a CSV or file based on length delimited columns far easier to create.
If you like this article, you might also like PowerShell editors and environments part 2.
Load comments