6

So the easiest way to explain my problem is for me to show you this simplified version of what I'm trying to do:

PS C:\> $a = 'hello'
PS C:\> $a
hello
PS C:\> $b = '$a world!'
PS C:\> $b
$a world!

Now what I really want is for the invokation of $b to return 'hello world!' but I apparently cannot call a variable within anther variable like this. Does anyone have any suggestions or work-arounds? I feel like I'm just missing something obvious here.

Edit: a more accurate version of what I'm trying to do:

PS C:\> $selHost = (get-content c:\scripts\hosts.txt)[0]
PS C:\> $selhost
spr-it-minion
PS C:\> $a = (get-content c:\scripts\config.txt)[1]
PS C:\> $a
$selhost Is Offline!
PS C:\> $b = "$a"
PS C:\> $b
$selhost Is Offline!

So I'm pulling the first line out of hosts.txt and setting it to $selhost which is just 'spr-it-minion'. I then pull the second line out of config.txt which is just the string '$selhost is offline!' in hopes that when I call $a I get 'spr-it-minion is offline!' and I'm not sure what to do.

Edit II: the contents of hosts.txt and config.txt respectively.

hosts.txt:

spr-it-minion
spr-saflok
spr-crosby
spr-vmhost01
spr-vmhost02
spr-vmhost03

config.txt:

172.31.1.124
$selhost Is Offline!
$selhost Is Offline!
[email protected]
[email protected]

Edit III: The Pastebin to my actual script if any of you are interested.

Line 15: I set $alertSubject to the string "$selhost is offline!" with no quotes or anything.

Line 82: I use $alertSubject as the subject line of an email alert hoping that that variable it contains will have it's value represented like: "spr-it-minion is offline!" but when I get the email or try to write-host $alertSubject anywhere in the script it just says "$selhost is offline!"

4
  • Please edit again to show us the actualy line [0] from the hosts.txt and line [1] from the config.txt. It'll help.. ;) May 1, 2015 at 19:29
  • While I do not know for sure, seeing as I'm not a PowerShell user, I am suspecting that you don't need to use quotes at all when assigning a variable to another variable. $a = $b should work too. Think of " as meaning "unpack what's here, including any variables". Can someone confirm that this is the case?
    – Jarmund
    May 1, 2015 at 19:32
  • Edited to include the contents of hosts.txt and config.txt. May 1, 2015 at 19:32
  • Edited to include the pastebin link to the actual script and the areas that are causing this issue. May 1, 2015 at 19:44

6 Answers 6

9

When defining variables in PowerShell, single quotes (') mean you want the literal version of the string. Use double-quotes (") if you want to allow variable expansion:

PS C:\> $a = "hello"
PS C:\> $a
hello
PS C:\> $b = "$a world!"
PS C:\> $b
hello world!

More info:

Edit after comments:

For your example where you're pulling the line from a file, that's a little trickier since it's pulling the line as a literal string.

The easiest way (IMO) would be to use the Replace method; something like:

$selHost = (get-content c:\scripts\hosts.txt)[0]
$a = ((get-content c:\scripts\config.txt)[1]).replace('$selhost', $selHost)
9
  • 1
    A noteworthy point is that this behavior of single- vs double-quotes isn't just PowerShell, but any language with sensible string-operations that I know of.
    – Jarmund
    May 1, 2015 at 19:14
  • @Jarmund Most "sensible" languages I've run into over the years don't allow mixing at all. Double quotes are for Strings, and single quotes are for Chars. In the end that doesn't really matter though, because this question is PowerShell specific. ;) May 1, 2015 at 19:17
  • @Techie007 True, this is somewhat redundant at this point, so I'll just leave this statement and walk away: A sensible language doesn't necessarily have sensible string operations. :P
    – Jarmund
    May 1, 2015 at 19:20
  • @Jarmund True enough, and any language can be considered "sensible" or not, depending on who's using it and for what. ;) May 1, 2015 at 19:23
  • Thanks! I'm pretty new to programming in general and I got the impression that ' and " were pretty interchangeable. Unfortunately, I might have simplified my example too much. Look at this example: PS C:\> $selHost = (get-content c:\scripts\hosts.txt)[0] PS C:\> $selhost spr-it-minion PS C:\> $a = (get-content c:\scripts\config.txt)[1] PS C:\> $a $selhost Is Offline! So I'm pulling a line out of hosts.txt and setting it to $selhost. I then pull a line out of config.txt which is just '$selhost is offline!' in hopes that when I call $a I get 'spr-it-minion is offline!' and nothing. May 1, 2015 at 19:24
1

When you read a string that contains a variable name out of a file and into a variable, you are going to need something other than double quotes to cause string expansion. There is a tool that's relevant here. It's called ExpandString. Take a look at this sample code:

$selhost = 'spr-it-minion'

$b = '$selhost is offline!'
$c = $ExecutionContext.InvokeCommand.ExpandString($b)

$c

What's going on here is that first I have given $selhost and $b literal values, similar to the ones you would read out of the files you are using. Of course, $b isn't right, because the reference to $selhost isn't resolved, as outlined in the accepted answer. But $c gets the value produced by expanding $selhost, which you can use in your output.

I'll leave applying this to your case as a coding exercise.

1

What you're trying to do here is dynamic Powershell i.e. create a string that holds a Powershell command, then have Powershell run that command. You can do this with Invoke-Expression e.g.:

$alertSubject = Invoke-Expression -Command "`"$((Get-Content '.\config.txt')[1])`""

Although, for maintainability, you may want to break it out into something like:

$config1 = (Get-Content '.\config.txt')[1]
$alertSubject = Invoke-Expression -Command "`"$config1`""

The backticks are there because the command you actually want to run is:

"$selhost is offline!"

The outer quotes allow $config1 to be expanded before the value is passed into Invoke-Expression. That value needs to include double-quotes so that $selhost can be expanded when the command is invoked.

Alternatively, you could put the double-quotes in the config file:

172.31.1.124
"$selhost Is Offline!"
"$selhost Is Offline!"
[email protected]
[email protected]

and then just have

$alertSubject = Invoke-Expression -Command $config1

In this pattern, the outer double-quotes around $config1 have been dropped as they are redundant.

0

Use $(

Example: $Var1 = $(Var2 | Select-Object -Property A)

$Var1 will equal the A property of Var2. Pretty robust.

0

The replace method works well for variable within variable substutition, even when calling powershell from Autohotkey:

uri = file$k.doc

psScript2 =
(
param($param1)
for($k=1; $k -le 6; $k++){
$uri = $param1.replace('$k',"$k")
echo $uri
}
)

Run PowerShell.exe -noexit -Command &{%psScript2%} '%uri%',, show
return

Note the use of single quotes to search for inner variable to be substituted with outer variable contents

Result is:

file1.doc
file2.doc
etc.
0

Had a similar hurdle. I wanted to run multiple unique vars through a FOR loop.

$animals = "dogs","cats"
$cats_rank = 100
$dogs_rank = 50

foreach ($animal in $animals){
# Show the animal's rank
$rank = $animal + "_rank"
Write-host "Rank for $animal is:"
(get-variable $rank).value
}

enter image description here

1
  • You may be giving a simplified example, but with what you're showing, I would think a hashtable of "animal" -> "Rank" pairs would eliminate string manipulation to create variable names. May 10, 2021 at 16:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .