How Can We Help?
Here string and variable substitution
As mentioned in another Dive (see Here strings and the ExpandString method) Here strings are a convenient way to prepare scripts you are submitting through Invoke-VMScript or Invoke-VMScriptPlus.
But there are some caveats you should be aware off. Most of these are how the variable substitution will work when you call the ExpandString method.
- For variables you don’t want to be substituted, you need to escape the dollar sign with a back-tick. Note that this is also true for the Booleans $true and $false.
1 2 3 4 5 6 7 8 |
$data = @' `$var1 = $val1 `$var2 = `$true '@ $val1 = 1 $ExecutionContext.InvokeCommand.ExpandString($data) |
- Put strings in quotes, otherwise PowerShell will try to interpret them as cmdlets or functions.
1 2 3 4 5 6 7 |
$data = @' `$var1 = '$str1' '@ $str1 = 'A string' $ExecutionContext.InvokeCommand.ExpandString($data) |
- When referencing properties from an object, use the correct notation.
1 2 3 4 5 6 7 8 9 |
$data = @' `$var1 = '$($obj.Field1)\Temp' '@ $obj = New-Object PSObject -Property @{ Field1 = 'C:' } $ExecutionContext.InvokeCommand.ExpandString($data) |
Another Rhoads
LucD,
I’ve followed you for many years now and have appreciated you sharing your expertise.
Nowadays I’m still finding your help!
My example:
Tried to use escaped variables embedded into the here-string but could
not get the string to update during the ForEach-Object loop so using
“{0} -f placeholders”
*** Example – NOW working – of using escaped variables:
${HelpTop} = @”
\\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help
$(
${PSItem}.Name) cmdlet.txtOpen explorer to all help files
Start \\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\
Get-Help
$(
${PSItem}.Name) -Full | clip“@
${HelpTop}
———-
\\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\$(${PSItem}.Name) cmdlet.txt
Open explorer to all help files
Start \\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\
Get-Help $(${PSItem}.Name) -Full | clip
———-
(Get-Command -Verb Write).Where({${PSItem}.CommandType -eq “Cmdlet”}) |
ForEach-Object {
$ExecutionContext.InvokeCommand.ExpandString(${HelpTop} )
}
Get-Command -Module RobocopyPS |
ForEach-Object {
$ExecutionContext.InvokeCommand.ExpandString(${HelpTop} )
}
*** Example – working – of using placeholders (just one {0}):
${HelpTop} = @”
\\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\{0} cmdlet.txt
Open explorer to all help files
Start \\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\
Get-Help {0} -Full | clip
“@
(Get-Command -Verb Write).Where({${PSItem}.CommandType -eq “Cmdlet”}) |
ForEach-Object {
${HelpTop} -f $(${PSItem}.Name)
}
Get-Command -Module RobocopyPS |
ForEach-Object {
${HelpTop} -f $(${PSItem}.Name)
}
Get-Command -Module RobocopyPS |
ForEach-Object {
${HelpTop} -f $(${PSItem}.Name) | Out-File -FilePath \\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\”$(${PSItem}.Name) cmdlet.txt” -Force
Get-Help $(${PSItem}.Name) -Full |
Out-File -FilePath \\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\”$(${PSItem}.Name) cmdlet.txt” -Append
“==========
n
nn" | Out-File -FilePath \\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\"$(${PSItem}.Name) cmdlet.txt" -Append
}
(Get-Command -Verb Write).Where({${PSItem}.CommandType -eq "Cmdlet"}) |
ForEach-Object {
${HelpTop} -f $(${PSItem}.Name)
}
(Get-Command -Verb Write).Where({${PSItem}.CommandType -eq "Cmdlet"}) |
ForEach-Object {
${HelpTop} -f $(${PSItem}.Name) | Out-File -FilePath \\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\"$(${PSItem}.Name) cmdlet.txt" -Force
Get-Help $(${PSItem}.Name) -Full |
Out-File -FilePath \\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\"$(${PSItem}.Name) cmdlet.txt" -Append
"========== n
n
n” | Out-File -FilePath \\hshome\Shared\IS\TSS\ESG\Backup\!\Dev\PowerShell\Help\”$(${PSItem}.Name) cmdlet.txt” -Append}
Levent
THANK YOU SIR, that worked perfectly 🙂
Levent
Hi, Thanks for your work.
I’m trying to use Invoke-VMScript to run the linux sed command on VM guest.
I could really do with your expertise to help ?
Problem I’m having, is that it doesn’t like the double-quotes ” and is not using the variable :
$scripttext1=”sed -i -e “s/$vm.templateip/$vm.guestip/g” /etc/sysconfig/network-scripts/ifcfg-eth0 && cat /etc/sysconfig/network-scripts/ifcfg-eth0″
Write-host “$scripttext1”
Get-VM $vm.guestname | Invoke-VMScript -ScriptText $($scripttext1) -GuestCredential $template_root_credential
=====
Output :
PS F:\vmscripts> .\test_script.ps1
At F:\vmscripts\test_script.ps1:61 char:27
+ … “sed -i -e “s/$vm.templateip/$vm.guestip/g” /etc/sysconfig/network-sc …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected token ‘s/$vm.templateip/$vm.guestip/g” /etc/sysconfig/network-scripts/ifcfg-eth0 && cat /etc/sysconfig/network-scripts/ifcfg-eth0″‘ in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
I would sincerely appreciate any assistance you may be able to provide ?
THANKS
LucD
Hi Levent,
When you want to mention properties of an object in a string, you need to enclose them in $().
That way PowerShell knows how to substitute them.
Try something like this
$scripttext = @'
sed -i -e "s/$($vm.templateip)/$($vm.guestip)/g" /etc/sysconfig/network-scripts/ifcfg-eth0; cat /etc/sysconfig/network-scripts/ifcfg-eth0
'@
$scripttext1 = $ExecutionContext.InvokeCommand.ExpandString($scripttext)
Write-host "$scripttext1"
Get-VM $vm.guestname |
Invoke-VMScript -ScriptText $scripttext1 -GuestCredential $template_root_credential