Learn about Windows PowerShell
Hey, Scripting Guy! I need to be able to write double quotation marks to a text file using Windows PowerShell. I know that in VBScript it was really annoying to do this because the quotation marks ended up getting confused with the quotation mark that was used to indicate the start of a string; when the next quotation mark was seen, VBScript would end the string and that caused problems. I found an old, Hey Scripting Guy! post titled, How Can I Write Double Quotes to a Text File? but it is talking about VBScript. I am not certain it applies to Windows PowerShell, particularly Windows PowerShell 2.0. Can you help me out?
Microsoft Scripting Guy Ed Wilson here. One of the great things about working with Windows PowerShell is that you never knows what you will discover. It is this sense of the unexpected that keeps me from becoming bored. The experience is not unlike when I was walking around the Taronga Zoo in Sydney, Australia—after wandering up and down myriad paths, I spotted a sudden opening in the foliage and a giraffe appeared backlit by the Sydney skyline. Here’s the photo I took that day.
DM, the easiest way to work with double quotation marks in Windows PowerShell is to use the single quotation mark—the so-called literal quotation mark. When using the single quotation mark, anything that is contained within is interpreted literally. This means that a pair of double quotation marks will be seen as string indicators. This is shown here:
PS C:\> $a = 'His name is "Ken Myers"' PS C:\> $a His name is "Ken Myers" PS C:\>
If you want to write a pair of double quotation marks to a text file, all you need to do is use a single quotation mark and direct the output to a text file, as shown here:
PS C:\> $a > c:\fso\ken.txt PS C:\>
The text file that is created is shown in the following image.
The double quotation mark in Windows PowerShell is the expanding string character. This means that variable values and subexpressions are evaluated inside the double quotation marks. Using expanding strings offers some really interesting possibilities. For example, using the environmental provider from Windows PowerShell, I can easily obtain access to the values of environmental variables, such as the username. By using the username, you can personalize string values. The problem is that literal strings do not allow for substitution. When placed inside a pair of single quotation marks, $env:USERNAME is not evaluated; it is returned as a string. This is shown here:
PS C:\> $env:USERNAME ed PS C:\> $b = 'My name is "$env:UserName"' PS C:\> $b My name is "$env:UserName" PS C:\>
By placing the environmental variable inside the double quoted string, you will run into the same problem that was experienced in BLOCKED SCRIPT
$c = "My name is "$env:UserName""
The first double quotation mark opens the string. The second double quotation mark ends the string. An error is then generated. The error is shown in the following image.
Because this problem is similar to the one experienced with VBScript (quotation marks ending strings), you can approach the problem in the same manner as in BLOCKED SCRIPT add an extra set of quotation marks around the portion to be quoted. This is shown here:
PS C:\> $c = "My name is ""$env:UserName""" PS C:\> $c My name is "ed" PS C:\>
The Hey, Scripting Guy! post that talked about writing double quotation marks to a text file recommended using the CHR function to write ASCII character 34 to the file. ASCII character 34 is a double quotation mark. The reason for using the CHR function instead of using double quotation marks, the article states, is for improved readability. The [char] (system.char .NET Framework class) can be used to convert a number into an ASCII character. You would use [char]34 to create a double quotation mark. However, this does not work well when placed directly inside an expanding string. The results are shown here:
PS C:\> $c = "My name is [char]34$env:UserName[char]34" PS C:\> $c My name is [char]34ed[char]34 PS C:\>
The problem is that [char]34 is not being evaluated; instead, it is being treated as if it is a string. To force the evaluation, a subexpression is used. This is shown here:
PS C:\> $c = "My name is $([char]34)$env:UserName$([char]34)" PS C:\> $c My name is "ed" PS C:\>
Using a subexpression does not make the code very readable. Another VBScript approach is to use concatenation. This results in code that is fairly readable:
PS C:\> $c = "My name is " + [char]34 + $env:UserName + [char]34 PS C:\> $c My name is "ed" PS C:\>
My personal favorite is to use the double quotation marks to create an expanding string. I then escape the required internal quotation marks by using the backtick (`) character, as shown here:
PS C:\> $c = "My name is `"$env:UserName`"" PS C:\> $c My name is "ed" PS C:\>
Another way to get double quotation marks into the string is to use a here-string. Just like regular strings, there are the literal and the expanding variety. The advantage of a here-string is that it ignores things such as quotation marks and other special characters. Essentially, what you type in a here-string is exactly what you get. But with the expanding variety of here-string, you also have the opportunity to bring in the value of variables. This is shown here:
PS C:\> $c = @" >> My name is "$($env:UserName)" >> "@ >> PS C:\> $c My name is "ed" PS C:\>
DM, that is all there is to using Windows PowerShell to work with strings and double quotation marks. String Week will continue tomorrow when we will talk about working with XML files.
We invite you to follow us on Twitter and Facebook. If you have any questions, send email to us at email@example.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys
Nice post makes things makes things make sense
Really useful as I used this $chr[34) in the creation of a SharePoint Calculated field using PowerShell
I was able to do the same with the help of
$Report = @"
add-content $path -value "$report"
That preserved the duble quotes around the values variables between @" "@ and my CSV did not have to be delemited anymore.