Belac
Belac

Reputation: 1083

Escaping dollar signs in PowerShell path is not working

Why doesn't this work?


$drvrInstFilePath = "$sharePath\$imageName\ISO`$OEM$`$1\RPKTools\RPKDriverInst.bat"
echo $drvrInstFilePath
$drvrInstContent = Get-Content -LiteralPath "$sharePath\$imageName\ISO`$OEM$`$1\RPKTools\RPKDriverInst.bat"  | Out-String

The echo shows the right path, but the Get-Content command expands the $oem and $1 to blank strings, even though they are escaped. Why?

Upvotes: 85

Views: 101923

Answers (4)

Michael
Michael

Reputation: 2414

You used double quotes with simple backtick. This is an incorrect combination for the type of call used. Your successful options to escape the dollar sign ($) in this type of PowerShell call are:

  1. use double quotes with backslash-backtick combination ( "\`$find" );
  2. use single quotes with simple backslash ( '\$find' ).

Note the exceptions at the end about function call parameters.

For those unfamiliar with the distinction, it is important not to confuse the backtick character (`) with the single-quotation character (') in these escapes.

Examples:

[SUCCESS] Double quotes as container with backslash-backtick as escape:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_ -replace "\`$old", "(New)"}
What is (New)?

[FAIL] Double quotes as container with backslash-apostrophe as escape:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_ -replace "\'$old", "(New)"}
What is $old?

[SUCCESS] Single quotes as container with simple backslash as escape:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_ -replace '\$old', "(New)"}
What is (New)?

[FAIL] Single quotes as container with backslash-backtick as escape:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_ -replace '\`$old', "(New)"}
What is $old?

Overall, the easiest option may be to use single quotes as the container and a single backslash as the escape: '\$old'

Update 1: Single quotes in function calls are different, requiring no escape. Trying to use an escape on the function call parameter will not work:

[FAIL] Using single quotes plus escape in function parameter:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_.ToString().Replace('\$old', "(New)");}
What is $old?

[SUCCESS] Using single quotes without escape in function parameter:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_.ToString().Replace('$old', "(New)");}
What is (New)?

Update 2: Double quotes in function calls are further different, requiring merely a simple backtick for escape:

[FAIL] Using double quotes with backslash-backtick in function parameter:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_.ToString().Replace("\`$old", "(New)");}
What is $old?

[SUCCESS] Using double quotes with simple backtick in function parameter:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_.ToString().Replace("`$old", "(New)");}
What is (New)?

Upvotes: 25

vonPryz
vonPryz

Reputation: 24071

Instead of messing around with escaping dollar signs, use single quotes ' instead of double quotes ". It prevents PowerShell expanding $ into a variable. Like so,

$p = "C:\temp\Share\ISO$OEM$"
# Output
C:\temp\Share\ISO$


$p = 'C:\temp\Share\ISO$OEM$'
# Output
C:\temp\Share\ISO$OEM$

If you need to create a path by using variables, consider using Join-Path. Like so,

$s = "Share"
join-path "C:\temp\$s" '\ISO$OEM$' 
# Output
C:\temp\Share\ISO$OEM$

Upvotes: 129

barak m.
barak m.

Reputation: 826

You can actually just use a tick mark to escape the $ like so:

`$

Example:

$number = 5
Write-Host "`$${number}"
# Output: $5

Upvotes: 80

Jeremy Thompson
Jeremy Thompson

Reputation: 65554

In my case I needed to escape some $'s used in a string but not others that are variables.

For example, my SSRS instance name has a $ sign:

[ReportServer$SSRS]

To escape the $ sign I use single quotes. Otherwise I use the -join statement to concatenate variables with the strings containing actual $ signs.

 $sql = -join('ALTER DATABASE [ReportServer$', $instanceName,'TempDB]
  SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
  GO

  USE [master]
  RESTORE DATABASE [ReportServer$', $instanceName,'TempDB] FROM  DISK = N''C:\temp\ReportServerTempDB.BAK'' WITH  FILE = 1,
    MOVE N''ReportServerTempDB'' TO N''', $sqlDataDrive + "\data_" + $instanceName, '\ReportServer$', $instanceName,'TempDB.mdf'', 
    MOVE N''ReportServerTempDB_log'' TO N''', $sqlLogDrive + "\log_" + $instanceName, '\ReportServer$', $instanceName,'_TempDBlog.LDF'',  NOUNLOAD,  REPLACE, RECOVERY,  STATS = 5
  GO

  ALTER DATABASE [ReportServer$', $instanceName,'TempDB]
  SET MULTI_USER;
  GO
  ')

Upvotes: 2

Related Questions