correct syntax for putting a powershell script into a variable with double quotes

290 Views Asked by At

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 
1

There are 1 best solutions below

1
mklement0 On

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.