2

I'm running a PowerShell script from a .NET application, but it's failing because $PSScriptRoot is not set. How can I set it?

Code:

var ps = PowerShell.Create();
ps.Runspace.SessionStateProxy.Path.SetLocation(dir);
var withScript = ps.AddScript(File.ReadAllText(Path));
var results = ps.Invoke();

I have also attempted to set it using:

ps.Runspace.SessionStateProxy.SetVariable("PSScriptRoot", dir, "Script root");

but it remains empty in the script.

This also didn't work:

ps.Runspace.SessionStateProxy.SetVariable("PSScriptRoot", dir, "Script root", ScopedItemOptions.AllScope);

I tried using a different name to see if it's somehow reserved, or being overwritten, but it was also empty.

The following fails with an error that PSScriptRoot cannot be replaced because it has been optimized:

var test = new PSVariable("PSScriptRoot", dir, ScopedItemOptions.AllScope);
runspace.SessionStateProxy.PSVariable.Set(test);
Swoogan
  • 5,298
  • 5
  • 35
  • 47
  • I had this issue a couple of years ago. IIRC I gave up trying to figure out the problem due to time constraints and ended up hard-coding the path in the scripts. I hate this solution but it got things working. – Bill_Stewart Mar 09 '18 at 16:52
  • Text do not have path. File have path. `AddScript(File.ReadAllText(Path))` -> `AddCommand(Path)`. – user4003407 Mar 09 '18 at 23:11

2 Answers2

3

That's quite easy.

You need to use PowerShell.Runspace.SessionStateProxy.InvokeCommand.GetCommand() to get an InvocationInfo object for your external script.

Then use PowerShell.AddCommand() to add the InvocationInfo to your shell, add parameters or arguments if necessary, and finally call Invoke() to execute the script.

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

public class Program
{
    public static void Main(string[] args)
    {
        using (var runspace = RunspaceFactory.CreateRunspace())
        {
            // open runspace
            runspace.Open();

            using (var powershell = PowerShell.Create())
            {
                // use runspace
                powershell.Runspace = runspace;

                // set execution policy
                powershell.AddCommand("Set-ExecutionPolicy")
                    .AddParameter("-ExecutionPolicy", "Bypass")
                    .AddParameter("-Scope", "Process")
                    .Invoke();

                // add external script
                var scriptInvocation = powershell.Runspace.SessionStateProxy.InvokeCommand
                    .GetCommand("MyScript.ps1", CommandTypes.ExternalScript);
                powershell.AddCommand(scriptInvocation);

                // add parameters / arguments

                // invoke command
                powershell.Invoke();
            }

            // close runspace
            runspace.Close();
        }
    }
}
2

How about just setting the variable yourself:

ps.Runspace.SessionStateProxy.SetVariable("PSScriptRoot", dir);
briantist
  • 45,546
  • 6
  • 82
  • 127
  • 1
    @Swoogan please update your question with the things you've already tried. Giving the error messages and outcomes is helpful too. – briantist Mar 09 '18 at 16:30