Fun With PowerShell String Formatting

Introduction

In last Monday’s blog post, Fun With PowerShell Strings, I covered a lot of the basics around PowerShell Strings. One thing we didn’t get into though was some of the special formatting commands you can use with PowerShell.

Specifically, this can control the output when we embed a numeric value inside a string. Passing in special formatting instructions will make it easy to display values with commas, as currency, or even as hexidecimal.

For all of the examples, we’ll display the code, then under it the result of our code. In this article I’ll be using PowerShell Core, 7.1.3, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

To run a snippet of code highlight the lines you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of an array variable (or any variable) by highlighting it and using F8/F5.

How it Works

PowerShell supports the C# / C / C++ style of string formatting. Let’s take a look at this example.

[string]::Format("There are {0} items.", $items)

Inside our string we have {0}. This is a placeholder, when a C style language sees this it will look for the first variable after the string and put that into placeholder 0.

PowerShell of course always wants to make life easier on us, so we can use this much simpler format.

"There are {0} items." -f $items

In PowerShell we have our string, including the placeholder. After it we have a -f to let PowerShell know the following items will be copied into the placeholders. In this case, the value in $items will be inserted into the {0} placeholder.

It’s not necessary to use a variable, we could have just hardcoded a value.

"There are {0} items." -f 33

What if we had multiple items? Well we’d just use multiple placeholders (all on one line).

"There are {0} items in the location {1}." -f $items, $loc

In this example, $items will go into the {0} and the value in $loc will get inserted into placeholder {1}.

You can even repeat a placeholder.

"There's {0} items in {1}. {0} is a lot of items!" -f $items, $loc

Now, if you’ve read my previous post you’re probably thinking “wait, wouldn’t string interpolation make all these unnecessary?”

And in these examples you are correct, with string interpolation you could have used the much easier to read syntax.

"There are $items items."

So why use the placeholder style? Well it turns out the placeholder syntax includes some extra syntax which will allow you to format values passed in. Let’s take a look at some examples.

Number

In the placeholder, after the placeholder position ( 0 in these examples ) you can put a colon : , then a letter that indicates the formatting style. Then another number which indicates the decimal places to retain.

"N0 {0:N0} formatted" -f 12345678.119    

Result:
N0 12,345,678 formatted

In this example, after the colon we have the letter N. This lets PowerShell know we want this to be formatted as a numeric value, and to include commas to separate the numbers.

In this example after the letter N we have another number, a 0. This indicates how many decimal places to retain in the output.

Here’s another example where we’ll include two decimal places.

"N2 {0:N2} formatted" -f 12345678.119

Result:
N2 12,345,678.12 formatted

As you can see, it follows the normal rules for rounding up the output. The next to the last last number, 1, was rounded up to 2 since the number after it was a 9.

Often we want to display numbers as right aligned, so the last digit will line up in our output. This means we want to display a number of spaces in front of it. PowerShell includes a feature for this too.

"N0 {0,8:N0} formatted" -f 123.119

Result:
N0      123 formatted

After the place holder we have a comma then a number ( here 0,8 ). This tells PowerShell we want the value for this placeholder to be eight characters in width.

In the output, PowerShell saw the final value, 123, was three characters wide. So it subtracted three from eight and put five spaces in front of the 123 so the entire output became eight characters in width.

A common question is “what if the output is longer than the width passed in?”. For example, you used 0,3 but your input to the placeholder was a value of 123456? In that case PowerShell will still format it as 123,456 but will not add any spaces before the number. This could result in some misaligned output in your display, but at least the accurate value will still be shown.

Currency

Using the C format instruction, PowerShell can display the results in currency format. It will use the default currency symbol for your computer’s language / location. Since I’m in the United States it will use a dollar sign.

"C0 {0:C0} formatted" -f 12345678.1234
"C2 {0:C2} formatted" -f 12345678.1234
"C2 {0,20:C2} formatted" -f 12345678.1234

Result:
C0 $12,345,678 formatted
C2 $12,345,678.12 formatted
C2       $12,345,678.12 formatted

Currency acts very similar to the Number format, the only real difference is the addition of your location’s currency symbol in the formatted output.

Percentage

PowerShell also has the ability to display values in a percentage format.

"P0 {0:P0} formatted" -f 0.1234
"P2 {0:P2} formatted" -f 0.1234
"P2 {0,8:P2} formatted" -f 0.1234

Result:
P0 12% formatted
P2 12.34% formatted
P2   12.34% formatted

Make sure to notice that PowerShell will take the decimal amount and automatically convert the percentage for you. Thus, if you want to display 12%, you have to pass in 0.12.

Hex

Next up on the list is Hexadecimal notation. PowerShell supports two methods for doing Hex values. In the first, it will take a standard number (base 10) and convert it to hexadecimal then display it.

"X0 0x{0:X0} formatted" -f 1234

Result:
X0 0x4D2 formatted

In this case we passed in the number 1234. PowerShell converted it to hex then displayed it.

What if the value were already in hex format though, and we just wanted to display it? In PowerShell, we indicate a number is in hex by placing a 0x in front of it. So we just pass in our number with 0x in front to the string.

"X0 0x{0:X0} formatted" -f 0x4D2

Result:
X0 0x4D2 formatted

When PowerShell saw the 0x on the front of 0x4D2, it knew this value was already in hex format and didn’t try to convert it, it simply displayed our value.

Decimal

The name of the next formatter we’ll look at is Decimal. It’s a bit misnamed though, because it’s really just for formatting integer based numbers. As a matter of fact, if you try use with a non integer value, such as 33.42, it will error out.

Let’s look at the most basic form of Decimal.

"D0 {0:D0} formatted"   -f 123

Result:
D0 123 formatted

Pretty simple, it just displays the value. So you can guess D is the formatter for decimal, but what is D0? The number after the D indicates how many spaces we want to zero pad to.

In other words, we want the string to be a certain number of characters long, so the number indicates that length. It will then put zeros to the left to pad it out. Let’s look at this example to make it clear.

"D8 {0:D8} formatted"   -f 123

Result:
D8 00000123 formatted

In this case, the D8 indicated we wanted eight characters in decimal formatting. PowerShell converted 123 to a string that was three characters long, so it put five zero’s in front to make the total length eight.

You can also add the placeholder comma value formatting to make a value a certain width wide. In these two examples, the first will act like a Number format. The second though will let you use leading zeros, but still set the total space.

"D0 {0,9:D0} formatted" -f 123
"D0 {0,9:D6} formatted" -f 123

Result:
D0       123 formatted
D0   0000123 formatted

In the first example, it made the output nine characters wide by placing six spaces in front of the 123. In the second example, it first made the 123 six characters by placing 000 on front, resulting in 000123.

It then took the resulting 000123 and made that nine wide by placing three spaces in front. As you can see, PowerShell is very flexible when formatting this way.

A reminder, as stated earlier Decimal is only for integers. If I were to try using -f 123.1 as an input it would error out.

Custom Date Formatting

In addition to the other formats, PowerShell provides the ability to create custom date outputs. You do so using these characters, note they are case sensitive.

M / MMOne or Two character month number
d / ddOne or two character day of the month number.
yy / yyyyTwo or four digit year number.
h / hhOne or two digit hour of the day in 12 hour format
H / HHOne or two digit hour of the day in 24 hour format
m / mmOne or two digit minute of the hour
s / ssOne or two digit second of the minute

Let’s see these used in a series of examples.

"Today is {0:M/d/yy}."                 -f $(Get-Date)
"Today is {0,10:MM/dd/yyyy}."          -f $(Get-Date)
"Today is {0,10:dd/MM/yyyy}."          -f $(Get-Date)
"Today is {0,10:yyyyMMdd}."            -f $(Get-Date)
"Today is {0,10:MM/dd/yyyy hh:mm:ss}." -f $(Get-Date)
"Today is {0,10:MM/dd/yyyy HH:mm:ss}." -f $(Get-Date)

Result:
Today is 7/18/21.
Today is 07/18/2021.
Today is 18/07/2021.
Today is   20210718.
Today is 07/18/2021 04:59:56.
Today is 07/18/2021 16:59:56.

In all of these, I passed in the current date (as I’m writing this) using Get-Date, but any date based variable would have worked.

In the output I’ve arranged the date parts in a variety of common manners. You can use these or create your own custom formats. For example you may wish to use a dash instead of a slash to separate the date parts.

Custom Number Formatting

Let’s say you lived in London, where the pound was your default currency. But you are part of a multinational company and need to produce output to send to your coworkers in the United States. You don’t want to have to change your computer to a US language just to get the $ symbol.

You can fix this by using custom formatting. In these examples, when it sees a character such as the $ it will just keep it in the output. When it sees #, (a pound sign followed by a comma) it will know to use commas in the output.

When it sees just a # sign it will put a number there if it has one, otherwise a space, and when it sees 0 it will put a number from the passed in data, or a zero if there is no number there. These examples will clarify it.

Note each one is on it’s own line, WordPress is wrapping the -f part to the next line for space reasons. Additionally, in this and other examples I’ve chosen to add spaces to line up the demos for readability, this isn’t a requirement and you can format however you need.

"Custom 0, 25 $ #,##0.0000  = {0,25:$ #,##0.0000} " -f 123456789.012000005
"Custom 0, 25 $ #,##0.0000  = {0,25:$ #,##0.00} "   -f 123456789.012000005
"Custom 0, 25 $ ##0.0000    = {0,25:$ ##0.00} "     -f 123456789.012000005

Result:
Custom 0, 25 $ #,##0.0000  =        $ 123,456,789.0120
Custom 0, 25 $ #,##0.0000  =          $ 123,456,789.01
Custom 0, 25 $ ##0.0000    =            $ 123456789.01

Using Formatting with Variables

It’s possible to create a formatted value, then assign that to a variable. Let’s take a look at this slightly more complex example.

$vTday = "{0,8:N0}" -f 134567
$vYest = "{0,8:N0}" -f 23546

$tday = "{0:MM/dd/yyyy}" -f $(Get-Date)
$yest = "{0:MM/dd/yyyy}" -f $((Get-Date).AddDays(-1))

$output = "Visitors to ArcaneCode.com`r`n"
$output += "$tday had $vTday visitors`r`n"
$output += "$yest had $vYest visitors"
$output

Result:
Visitors to ArcaneCode.com
07/18/2021 had  134,567 visitors
07/17/2021 had   23,546 visitors

The first two lines you’ve seen a few times by now. I’m simply taking a number, formatting it with commas and making it eight spaces wide.

The next line you’ve seen as well, I take the current date, format to MM/dd/yyyy format and assign to $tday.

The $yest line is slightly more complex, but only because I’m doing some date math. The (Get-Date) will get the current date, but create a date object from it. Essentially I have a date variable type but without a variable name.

Because I have a date datatype I can employ a method of the date datatype, AddDays. This will let me add a number of days to the date, or if you pass in a negative value subtract days. Thus AddDays(-1) will give me yesterday’s date. I then have to wrap it all in $() so PowerShell will evaluate the entire expression before passing it back to the placeholder.

Finally I’m using the += operand to concatenate several strings together for a nice output. Note the formatted dates, and how the visitors number right aligns nicely.

Conclusion

While string interpolation makes creating output strings easy, knowing how to use placeholders can make creating formatted output even easier, allowing you to create output with numeric values that align neatly, or creating custom date formatting.

The demos in this course came from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to https://pluralsight.com. At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site. Once there just search for my name, Robert Cain, to see all the courses I have.

Advertisement

Fun With PowerShell Strings

Introduction

PowerShell has some of the best, most flexible string handling of any language I’ve used. In this post we’ll look at some string basics, then some of the features that make it special.

Note in these demos I’m using PowerShell Core 7.1.3 and VSCode. Everything here should also work in the PowerShell 5.1 and the PowerShell IDE.

Basic Strings in PowerShell

Strings in PowerShell can be denoted with either single quote marks or double quote marks.

"This is a string"
'This is a string too!'

If you want to see the result, simply highlight the strings and press either F8 in VSCode, or F5 in the PowerShell IDE.

This is a string
This is a string too!

Multiline Strings, aka Here Strings

PowerShell has the ability to create a multiline string, also known as a “here” string. To create a here string, use an @ sign, followed by a quotation mark (either single or double) then hit Enter.

On the next lines, enter the value for your string. Finally hit Enter, then on the next line put the closing quotation mark then another @ sign.

This is important, the closing quotation mark and @ sign must be the first two characters on the line. If you attempt to indent them in any way the technique will not work!

$heretext = @"
Some text here
Some more here
     a bit more

a blank line above
"@

$heretext

Some text here
Some more here
     a bit more

a blank line above

Again, this works with single or double quotes. So what’s a common use?

One common thing I use it for is SQL queries. Here’s an example in a traditional language.

$sql = 'SELECT col1' `
     + '     , col2' `
     + '     , col3' `
     + '  FROM someTable ' `
     + ' WHERE col1 = ''a value'' '

Note the single ` (back tick) mark at the end of each line. This is the line continuation character in PowerShell.

As you can see, each line has to be connected with + signs. Now let’s contrast it with a here string version.

$sql = @'
SELECT col1
     , col2
     , col3
  FROM someTable
 WHERE col1 = 'a value'
'@

This is not only much more readable, but easier to work with. You can develop your SQL query in SQL Server Management Studio, or Azure Data Studio, then simply cut and paste it into PowerShell.

Another thing to notice, you can embed single or double quotes within a here string, and PowerShell will ignore them as denoting another string.

Embedded Quote Marks

If you need to embed a quotation mark in a string, you can simply double them up.

"ArcaneCode said ""PowerShell is awesome!"" and the crowd applauded."

ArcaneCode said "PowerShell is awesome!" and the crowd applauded.

This technique works with single quote marks as well. For example one’s used in common words such as shouldn’t.

'You shouldn''t miss the blog posts at arcanecode.com'

You shouldn't miss the blog posts at arcanecode.com

String Interpolation

You may be wondering what the difference between single and double quotes is. Double quotes allow you to use something called string interpolation. String interpolation will take any variables embedded in the string and expand them before returning the string.

Here’s a simple example. First we get the number of items in the current folder. Then we copy the current folder location into another variable. Finally we create a string with these variables in it, surrounding the string in double quote marks.

$items = (Get-ChildItem).Count 

$loc = Get-Location

"There are $items items are in the folder $loc."

There are 3 items are in the folder C:\PSCore-QuickStart.

As you can see in the result (the bottom line) it has taken the value in $items, a 3, and expanded it in the return result.

Likewise, it has taken the value in $loc and expanded it to the name of the current folder.

Now see the result if single quote marks had been used.

$items = (Get-ChildItem).Count 

$loc = Get-Location

'There are $items items are in the folder $loc.'

There are $items items are in the folder $loc.

With single quotes, the string interpolation engine does not kick in.

As a rule of thumb then, only use double quotes if you have to have interpolation. Otherwise use single quotes so you don’t incur the (admittedly minimal) amount of time for the string interpolation engine to needlessly process the string.

Escape Characters

PowerShell also has the concept of escape characters. These are special characters you can embed in the string that provide additional formatting instructions.

Note that escape characters only work inside double quote marked strings. If you use single quotes for your strings, it will just display the escape character.

There are four that are the most commonly used. Tab, Carriage Return, Line Feed, and escaping the $ (dollar sign) so it may be used.

Escape characters are preceded by a back tick ` then the character. Let’s look at the tab, which is a `t.

"`tThis is tabbed in"

        This is tabbed in

The next is the carriage return line feed sequence, which is `r`n.

"Here is some text`r`nAnd some more text`r`n`r`nA blank line before this"

Here is some text
And some more text

A blank line before this

You would most commonly use this when looping over data and building a new output string.

The final escape character we’ll look at allows you to embed a $ character in an double quoted string. Simply use a back tick followed by the dollar sign.

"The `$items variable is $items"

The $items variable is 3

We’ve only covered four here, but note there are many more escape sequences you can use in PowerShell.

Conclusion

In this post you saw all kinds of cool things you can do with PowerShell strings. With this knowledge you can take your PowerShell scripts to the next level, and be able to generate some creative output with your own PowerShell strings.

The demos in this course came from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to https://pluralsight.com. At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site. Once there just search for my name, Robert Cain, to see all the courses I have.