How do I escape curly braces {...} in powershell? - powershell

I need to generate multiple lines of xml tag with a GUID in them:
<xmltag_10 value="{ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ}"/>
<xmltag_11 value="{ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ}"/>
and so on
I have this line in a loop where $guid is generated each iteration, and it prints the guid without surrounding braces
Write-Host ('<xmltag_{0} value="{1}"/>' -f $i,$guid)
<xmltag_10 value="ZZZZZZZZ-ZZZZ-ZZZZ-ZZZZ-ZZZZZZZZZZZZ"/>
Adding a set of curly braces, I get
Write-Host ('<xmltag_{0} value="{{1}}"/>' -f $i,$guid)
<xmltag_10 value="{1}"/>
How do I escape the outer curly braces? I've tried using `{{1}`} to escape but I get
Error formatting a string: Input string was not in a correct format..
Adding my code for copying and testing:
$i=10
while($i -lt 21)
{
$guid = ([guid]::NewGuid()).ToString().ToUpper();
Write-Host ('<xmltag_{0} value="{1}"/>' -f $i,$guid)
$i++
}

To escape curly braces, simply double them:
'{0}, {{1}}, {{{2}}}' -f 'zero', 'one', 'two'
# outputs:
# zero, {1}, {two}
# i.e.
# - {0} is replaced by zero because of normal substitution rules
# - {{1}} is not replaced, as we've escaped/doubled the brackets
# - {2} is replaced by two, but the doubled brackets surrounding {2}
# are escaped so are included in the output resulting in {two}
So you could to this:
Write-Host ('<xmltag_{0} value="{{{1}}}"/>' -f $i,$guid)
However; in your scenario you don't need to use -f; it's a poor fit if you need to use literal curly braces. Try this:
$i=10
while($i -lt 21)
{
$guid = ([guid]::NewGuid()).ToString().ToUpper();
Write-Host "<xmltag_$i value=`"$guid`"/>"
$i++
}
This uses regular variable substitution in a double quoted string (but it does require escaping the double quotes using `" (the backtick is the escape character).
Another option would have been to use a format specifier. i.e. Format B causes a GUID to be surrounded by braces. Sadly it also formats the GUID in lowercase, so if the case of the output is part of your requirement, this would not be appropriate.
Write-Host ('<xmltag_{0} value="{1:B}"/>' -f $i, $guid)

Related

Powershell: How to remove space between $ and text[0]

Code:
$text=Get-Content -Path "E:\1.txt"
$text.GetType() | Format-Table -AutoSize
For($i=0; $i -le 5 ;$i++)
{
$var=Write-host '$'text[$i]
$var
}
Actual Result:
$ text[0]
$ text[1]
$ text[2]
$ text[3]
$ text[4]
$ text[5]
I need below Result:
$text[0]
$text[1]
$text[2]
$text[3]
$text[4]
$text[5]
If you must use the quotes, using -separator also works:
$text=Get-Content -Path "E:\1.txt"
$text.GetType() | Format-Table -AutoSize
For($i=0; $i -le 5 ;$i++)
{
$var=Write-host '$'text[$i] -Separator ''
$var
}
Your code fundamentally doesn't do what you intend it to do, due to the mistaken use of Write-Host:
# !! Doesn't capture anything in $var, prints directly to the screen.
$var=Write-host '$'text[$i]
$var # !! is effectively $null and produces no output.
See the bottom section for details.
Instead, what you want is an expandable string (aka interpolating string, "..."-enclosed), with selective `-escaping of the $ character you want to be treated verbatim:
$var= "`$text[$i]" # Expandable string; ` escapes the $ char., $i is expanded
$var
There are other ways to construct the desired string:
$var = '$text[{0}]' -f $i, using -f, the format operator.
$var = '$' + "text[$i]", using string concatenation with +
but the above approach is simplest in your case.
As for what you tried:
Write-Host is typically - and definitely in your case - the wrong tool to use, unless the intent is to write to the display only, bypassing the success output stream and with it the ability to send output to other commands, capture it in a variable, or redirect it to a file. To output a value, use it by itself; e.g., $value instead of Write-Host $value (or use Write-Output $value, though that is rarely needed); see this answer.
What you thought of as a single argument, '$'text[$i], was actually passed as two arguments, verbatim $ and expanded text[$i] (e.g., text[0]) and because Write-Host simply space-concatenates multiple arguments, a space was effectively inserted in the (for-display) output.
That '$'text[$i] becomes two arguments is a perhaps surprising PowerShell idiosyncrasy; unlike in POSIX-compatible shells such as bash, composing a single string argument from a mix of unquoted and (potentially differently) quoted parts only works if the argument starts with an unquoted substring or (mere) variable reference; for instance:
Write-Output foo'bar none' does pass a single argument (passes foobar none), whereas
Write-Output 'bar none'foo does not (passes bar none and foo)
See this answer for more information.

add quotation mark to a text file powershell

I need to add the quotation mark to a text file that contains 500 lines text.
The format is inconsistent. It has dashes, dots, numbers, and letters. For example
1527c705-839a-4832-9118-54d4Bd6a0c89
16575getfireshot.com.FireShotCaptureWebpageScreens
3EA2211E.GestetnerDriverUtility
I have tried to code this
$Flist = Get-Content "$home\$user\appfiles\out.txt"
$Flist | %{$_ -replace '^(.*?)', '"'}
I got the result which only added to the beginning of a line.
"Microsoft.WinJS.2.0
The expected result should be
"Microsoft.WinJS.2.0"
How to add quotation-mark to the end of each line as well?
There is no strict need to use a regex (regular expression) in your case (requires PSv4+):
(Get-Content $home\$user\appfiles\out.txt).ForEach({ '"{0}"' -f $_ })
Array method .ForEach() processes each input line via the script block ({ ... }) passed to it.
'"{0}"' -f $_ effectively encloses each input line ($_) in double quotes, via -f, the string-format operator.
If you did want to use a regex:
(Get-Content $home\$user\appfiles\out.txt) -replace '^|$', '"'
Regex ^|$ matches both the start (^) and the end ($) of the input string and replaces both with a " char., effectively enclosing the input string in double quotes.
As for what you tried:
^(.*?)
just matches the very start of the string (^), and nothing else, given that .*? - due to using the non-greedy duplication symbol ? - matches nothing else.
Therefore, replacing what matched with " only placed a " at the start of the input string, not also at the end.
You can use regex to match both:
The beginning of the line ^(.*?)
OR |
The End of the line $
I.e. ^(.*?)|$
$Flist = Get-Content "$home\$user\appfiles\out.txt"
$Flist | %{$_ -replace '^(.*?)|$', '"'}

To check for special characters in a string

I need to find special character in a string which has alphanumeric values in it.
I have tried the below code snippet but it doesn't work.
$Special_characters = ('\n|\r|\t|\a|\"|\`')
$Value = "g63evsy3swisnwhd83bs3hs9sn329hs\t"
if($Value -match $Special_characters)
{
Write-Host "Special characters are present"
}
else
{
Write-Host "special characters are absent"
}
The output says "special characters are absent" even though there are special characters at the end. How to resolve it?
$Special_Characters here is a string, so your code is searching for the whole word (\n|\r|\t|\a|\"|`) to be found in $Value, which is not found.
Instead of string, you have to use array as follows:
$Value = "g63evsy3swisnwhd83bs3hs9sn329hs\t"
$Special_Characters = #('\\n','\\r','\\t','\\a','\\"','\\`')
$Special_Characters | Foreach-Object {
if ($Value -match $_) {
"$_ is present"
} else {
"$_ is not present"
}
}
Note
You have to put double back-slash (\\) because backslash is considered as escape character in Powershell; Look here for further information about backslash in Powershell
There is a misunderstanding here.
The backslash is used to define a special character in a Regular Expression, as e.g. \t define a tab.
But this is not the case for PowerShell. To define a special character in PowerShell you need to use the backtick character (See: About Special Characters), e.g. a Tab is written as `t.
In other words, the regular expression pattern in the question is correct but the input string is not (in contrast to what the question/title suggests, there is in fact no special character in the given input string").
it should be:
"...hs9sn329hs`t" -match '\n|\r|\t|\a|\"|\`'
True
As it concerns a list of single (special) characters, you might also consider a bracket expression (rather than an OR "pipe" character) for this:
"...hs9sn329hs`t" -match '[\n\r\t\a\"\`]'
True
Visa versa: it is allowed to use special characters in a regular expression pattern using double quotes so that PowerShell will evaluate the string (but I recommend against this):
"...hs9sn329hs`t" -match "`n|`r|`t|`a|`"|``"
True
If the input string in the question is really the string you want to check upon (implying that you refer to the backslash as a special character, which formally is not), you want to check for a \t rather than a tab,. For this you will need to escape the backslashes in your regular expression to literally match the \t:
"...hs9sn329hs\t" -match '\\n|\\r|\\t|\\a|\\"|\\`'
True
Its an one-liner:
$Special_characters = '\n|\r|\t|\a|\"|\`'
$Value = "g63evsy3swisnwhd83bs3hs9sn329hs\t"
$result = #($Special_characters -split '\|' | % { $Value.Contains( $_ ) }).Contains( $true )
$result is true when a special character is found, otherwise false.
Here's all the special characters you referred to. You can try out a string by itself just to see if it works. It must be double quoted.
PS /Users/js> "`n`r`t`a`"``"
"`
You can also try out the -match operator by itself.
PS /Users/js> "`n`r`t`a`"``" -match '\n|\r|\t|\a|\"|\`'
True
About special characters: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_special_characters?view=powershell-6

Regex pattern with embedded double quotes in PowerShell

Following keyword need to be searched on document using PowerShell:
["Allowed Acquisition Clean-Up Period"
$keyword = ""
Get-Content $SourceFileName | Select-String -Pattern $keyword
String which I'm searching for has double quotes in it, so I'm struggling how to mention in this $keyword.
Apparently you not only have double quotes, but also an opening square bracket. Square brackets are meta-characters in regular expressions (for defining character classes), so you need to escape those too.
Define your expression in single quotes:
$keyword = '\["Allowed Acquisition Clean-Up Period"'
or escape nested double quotes with backticks:
$keyword = "\[`"Allowed Acquisition Clean-Up Period`""
To complement Ansgar Wiechers' helpful answer, which contains the correct solution:
Given that " is not a regex metacharacter (has no special meaning in a regular expression), your question boils down to:
How can I embed a " (double quote) in a string in PowerShell?.
As an aside: As stated, [ is a regex metacharacter, so it must be escaped as \[ inside a regex in order to be treated as a literal. As TheIncorrigible1 points out, you can let [regex]::Escape($string) handle that escaping for you; the result treats the content of $string literally in the context of a regex.
There are several options, demonstrated here with a simplified sample string, 3 " of rain - see also: Get-Help about_Quoting_Rules:
# Inside a *literal string* ('...'):
# The content of single-quoted strings is treated *literally*.
# Double quotes can be embedded as-is.
'3 " of rain'
# Inside an *expandable string* ("..."):
# Such double-quoted strings are subject to *expansion* (interpolation)
# of embedded variable references ("$var") and expressions ("$(Get-Date)")
# Use `" inside double quotes; ` is PowerShell's escape character.
"3 `" of rain" #"
# Inside "...", "" works too.
"3 "" of rain"
# Inside a *literal here-string* (multiline; end delimiter MUST be
# at the very beginning of a line):
# " can be embedded as-is.
#'
3 " of rain
'#
# Inside an *expanding here-string*:
# " can be embedded as-is, too.
#"
3 " of rain
"#
For the sake of completeness: you can create a double quote via its Unicode code point (the number that identifies each character), which is 0x22 (hex) / 34 (decimal), by casting it to [char], e.g.: [char] 0x22.
You can use this:
in string concatenations: '3 ' + [char] 0x22 + ' of rain'
in string-formatting expressions with the -f operator: '3 {0} of rain' -f [char] 0x22

Find and replace a string containing both double quotes and brackets

Let's say I have a test file named testfile.txt containing the below line:
one (two) "three"
I want to use PowerShell to say that if the entire string exists, place a line directly underneath it with the value:
four (five) "six"
(Notice that it includes both spaces, brackets and double quotes. This is important, as the problem I am having is I think with escaping the brackets and double quotes).
So the result would be:
one (two) "three"
four (five) "six"
I thought the easiest way of doing it would be to say that if the first string is found, replace it with the first string itself again, and the new string forming a new line included in the same command. I had difficulty putting the strings in line so I tried using a herestring variable whereby an entire text block with formatting is read. It still does not parse the full string with quotes into the pipeline. I'm new to powershell so don't hold back if you see something stupid.
$herestring1 = #"
one (two) "three"
"#
$herestring2 = #"
one (two) "three"
four (five) "six"
"#
if((Get-Content testfile.txt) | select-string $herestring1) {
"Match found - replacing string"
(Get-Content testfile.txt) | ForEach-Object { $_ -replace $herestring1,$herestring2 } | Set-Content ./testfile.txt
"Replaced string successfully"
}
else {
"No match found"}
The above just gives "No match found" every time. This is because it does not find the first string in the file.
I have tried variations using backtick [ ` ] and doubling quotes to try to escape, but I thought the point in a here string was that it should parse the text block including all formatting so I should not have to.
If I change the file to contain only:
one two three
and then change the herestring accordingly to:
$herestring1 = #"
one two three
"#
$herestring2 = #"
one two three
four five six
"#
Then it works ok and I get the string replaced as I want.
As Martin points out, you can use -SimpleMatch with Select-String to avoid parsing it as a regular expression.
But -replace will still be using a regex.
You can escape the pattern for RegEx using [RegEx]::Escape():
$herestring1 = #"
one (two) "three"
"#
$herestring2 = #"
one (two) "three"
four (five) "six"
"#
$pattern1 = [RegEx]::Escape($herestring1)
if((Get-Content testfile.txt) | select-string $pattern1) {
"Match found - replacing string"
(Get-Content testfile.txt) | ForEach-Object { $_ -replace $pattern1,$herestring2 } | Set-Content ./testfile.txt
"Replaced string successfully"
}
else {
"No match found"}
Regular expressions interpret parentheses () (what you are calling brackets) as special. By default, spaces are not special, but they can be with certain regex options. Double quotes are no problem.
In regex, the escape character is backslash \, and this is independent of any escaping you do for the PowerShell parser using backtick `.
[RegEx]::Escape() will ensure anything special to regex is escaped so that a regex pattern will interpret it as literal, so your pattern will end up looking like this: one\ \(two\)\ "three"
Just use the Select-String cmdlet with the -SimpleMatch switch:
# ....
if((Get-Content testfile.txt) | select-string -SimpleMatch $herestring1) {
# ....
-SimpleMatch
Indicates that the cmdlet uses a simple match rather than a regular
expression match. In a simple match, Select-String searches the input
for the text in the Pattern parameter. It does not interpret the value
of the Pattern parameter as a regular expression statement.
Source.