3

See my code below. The script creates the variable $backupFile. How can I use that variable in the next statement as value for the path parameter of the New-Item commend?

        using (var ps = PowerShell.Create())
        {
            ps.RunspacePool = _runspacePool;
            ps.AddScript("$backupFile = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(),'{0}.bak')".FormatInvariant(databaseName));
            ps.AddStatement();
            ps.AddCommand("New-Item")
                .AddParameter("Force")
                .AddParameter("ItemType", "File")
                .AddParameter("Path", /* How to use $backupFile?? */));
            ps.Invoke();
        }

3 Answers 3

2

The variable won't be available until you invoke the first script. Try this:

ps.AddScript("$backupFile = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(),'{0}.bak')".FormatInvariant(databaseName));
ps.Invoke();
ps.Commands.Clear();
var backupFile = ps.Runspace.SessionStateProxy.PSVariable.Get("backupFile");
ps.AddCommand("New-Item")
  .AddParameter("Force")
  .AddParameter("ItemType", "File")
  .AddParameter("Path", backupFile ));
ps.Invoke();

If you go this route though, I don't think you can use the RunspacePool because you're likely to get different runspaces between each Invoke(). In that case, the variable won't be available to the other runspace. Do you really need to use the RunspacePool in this scenario? If you do then why not just do the first bit in C#:

var backupFile = Path.Combine(Path.GetTempPath(), databaseName +'.bak');
Sign up to request clarification or add additional context in comments.

4 Comments

AFAIK using a RunspacePool is the preferred way for remote connections. That's the reason I use a RunspacePool. That's also the reason why I can't do the first bit in C#, because that would be on the local computer.
A more fundamental question is, what the use case for AddCommand is. Seems you can't assign it's result to a variable. So you can only catch it in the output of the Invoke. So it seems to me that with the Powershell class you should execute one pipeline at a time. So a sequence with AddCommand(), AddStatement(), AddCommand(), AddStatement, .... is not the way to go (expect perhaps when it are independent commands). Calling Invoke after each command seems to me also not the best way in a remoting situation. So then just building a script would be best?
AddCommand is used to add a command to the currently "under construction" pipeline. BTW you made no mention of remoting and I don't see anywhere in your code where you've configured a remote connection. :-) But, to answer your question, yeah it is probably best to put the $backupFile logic and New-Item command within a script string that you add with AddScript() and then Invoke() that.
I did indeed not mention remoting because in my eye's it was not relevant for the question.
0

I would try using a different Invoke. If you use PowerShell.Invoke Method (PSDataCollection, PSDataCollection, PSInvocationSettings) then you can drop the required information out of the end of the Pipeline and use the values from the PSDataCollection<T> Output in the rest of the script.

1 Comment

Yes, I am aware that this is possible. I am just curious if in the AddParameter method I can refer to a variable set in a previous script line (with just one invoke)
0

Although the answers of Keith and Eris were helpful, I thought it would be more helpful for other people reading this, to compose my own answer with my conclusions so far.

The answer on my initial question seems to be that it is not possible (at least we did not find a way for it so far).

So it seems that the use case for AddCommand (with AddArgument, AddParameter(s)) is to compose just one pipeline with one or more command and then get the result as the output of the Invoke method. Eventually you can add additional pipelines (separated by AddStatement) as long as the don't depend on each other. You will get multiple results in the output collection of the Invoke method.

When you want to execute 2 pipelines and the second depends on the result of the first (and it is not possible to pipe the result (as in my code example), I think there are two options: 1) Call Invoke for the first pipeline and use the output when composing the second pipeline. Or 2) Compose a script (e.g. with StringBuilder) and execute that with one Invoke.

When you are working with a remote connection, the latter option is perhaps preferable because that is only one call to the remote server.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.