2

I have a need to put a PowerShell script into a variable with double quotes like so. However I am not aware of the correct syntax for this as I see syntax errors with $script variable when I try this.

$script = "Invoke-Command -ComputerName $hostname -Credential $cred -ScriptBlock {Import-Module sqlserver; invoke-sqlcmd -ServerInstance $Using:hostname\MSSQLServer; invoke-sqlcmd "create login [$Using:sqluser] from windows";invoke-sqlcmd "alter server role sysadmin add member [$Using:sqluser]"}"

$runscript = Invoke-VMScript -VM $vm -ScriptText $script -GuestUser $tmpl_user -GuestPassword $tmpl_pass -ToolsWaitSecs 300 
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
1JS1-2
  • 23
  • 2
  • 2
    Are you hoping to pass the script to `Invoke-VMScript` _as-is_? If so, use `'` single-quotes instead of double-quotes. If you need to have _some_ of the variables in the string expanded by PowerShell before invocation, you should keep the double-quotes, but make sure you escape the `$` in front of any variable that you _don't_ want PowerShell to expand – Mathias R. Jessen Oct 06 '21 at 15:26

1 Answers1

2

Invoke-VMScript -ScriptText accepts only a string containing PowerShell code, and has no support for separately passing arguments to that code.

The implications are:

  • In order to include variable values from the caller's scope you indeed need to use string interpolation (via an expandable string, "..."), as you have attempted.

    • Note that this situationally requires embedded quoting around reference to caller variables whose values may contain spaces or other special characters; e.g.
      "... -Foo '$foo' ...")
  • As Mathias R. Jessen points out, variable references you want to be evaluated on the target machine must have their $ sigil escaped as `$ so as to prevent premature interpolation on the caller's side; e.g. `$Using:sqluser

There's a catch, however:

  • Use of string interpolation imposes limits on what data types may be embedded in the string, as not all data types have string-literal representations that are recognized as the original type.

    • In your case, the caller-side $cred variable contains a [PSCredential] instance, which does not stringify meaningfully (and cannot, for security reasons): it meaninglessly expands to a verbatim string value of System.Management.Automation.PSCredential, i.e. the instance's type name.
      In other words: you cannot pass credentials this way.

    • A potential workaround requires up-front work on the target machine: You can try to save the credentials in encrypted form to a file and then deserialize that file at invocation time via Import-Clixml.

mklement0
  • 382,024
  • 64
  • 607
  • 775