0

I've got code to run a PowerShell cmdlet from a .ps1 file containing a lot of PowerShell cmdlets... when I execute it I get this exception:

The term 'New-BuildCVFromSql' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

private void RunPowerShellCommandToBuildCV()
{
    string BigWindow = "";
    string FileNamePopup = "";

    TestPopup(ref BigWindow, ref FileNamePopup);

    string psScriptPath = @"D:\Project Files\CIS3G\Webapp\_Powershell\JcdcCv.psm1";
    string psScript = string.Empty;

    if(File.Exists(psScriptPath))
        psScript = File.ReadAllText(psScriptPath);
    else
        throw new FileNotFoundException("Wrong path for the script file");

    // Init the PowerShell runspace and pipeline - EWB
    Runspace runSpace = RunspaceFactory.CreateRunspace();
    runSpace.Open();

    // Set execution policy - EWB
    RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(runSpace);
    runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted");

    Pipeline pipeline = runSpace.CreatePipeline();

    // I tried loading it both of the ways below and had no joy load the script from the string - EWB
    //pipeline.Commands.AddScript(psScript);

    // Load as file - EWB
    pipeline.Commands.AddScript(psScriptPath, false);

    // Add the outstring command to the pipeline.
    pipeline.Commands.Add("Out-String");

    Command myCommand = new System.Management.Automation.Runspaces.Command("New-BuildCVFromSql");

    CommandParameter SqlOrExcelFile                          = new CommandParameter("SqlOrExcelFile", @"C:\Documents and Settings\Brown.Ericw\My Documents\tempeval.sql");
    CommandParameter Js                                      = new CommandParameter("Js", "JCDC");
    CommandParameter FileName                                = new CommandParameter("FileName", @"Evaluation\EvaluationFormPartialListVM");

    myCommand.Parameters.Add(SqlOrExcelFile);
    myCommand.Parameters.Add(Js);
    myCommand.Parameters.Add(FileName);

    pipeline.Commands.Add(myCommand);

    Collection<PSObject> output = pipeline.Invoke();
    //foreach (PSObject psObject in output)
    //{

    //System.Diagnostics.Debug.WriteLine ("Object name: " + psObject.);
    //}
}

So apparently I'm not correctly loading this file of scripts. In PowerShell ISE/IDE I have to run the script before I can execute any of the commands. Is that what I'm doing wrong?

I'm just trying to put an interface on top of a bunch of PowerShell scripts written by someone else, so I can't really change his/her script files, as they are being used elsewhere by other folks...

Inside the .ps1 file the cmdlet I'm trying to call is defined thusly:

# Create CV Method #

function New-BuildCVFromSql {
  param([Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]$SqlFile,
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]$js,
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)]$FileName)

 ...

Addendum: I also tried using a PowerShell instead of a pipeline per this post:

Problem with calling a powershell function from c#

Like this, but I got the same exception:

private void RunPowerShellCommandToBuildCV()
{
    string BigWindow = "";
    string FileNamePopup = "";

    TestPopup(ref BigWindow, ref FileNamePopup);

    string psScriptPath = @"D:\Project Files\CIS3G\Webapp\_Powershell\JcdcCv.psm1";
    string psScript = string.Empty;

    if (File.Exists(psScriptPath))
        psScript = File.ReadAllText(psScriptPath);
    else
        throw new FileNotFoundException("Wrong path for the script file");

    // Init the PowerShell runspace and pipeline - EWB
    using (Runspace runSpace = RunspaceFactory.CreateRunspace())
    {
        runSpace.Open();

        // Set execution policy - EWB
        RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(runSpace);
        runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted");

        //Pipeline pipeline = runSpace.CreatePipeline();

        PowerShell ps = PowerShell.Create();
        ps.Runspace = runSpace;

        // Load as file - EWB
        ps.AddScript(psScriptPath);

        ps.AddCommand("New-BuildCVFromSql").AddParameters(new Dictionary<string, string>()
         {
             {"SqlOrExcelFile", @"C:\tempeval.sql"},
             {"Js", "JCDC"},
             {"FileName", @"Evaluation\EvaluationFormPartialListCV"}
         });

        foreach (PSObject result in ps.Invoke())
        {
            Debug.WriteLine ("Object : " + result);
        }
    }

Addendum 2:

Removing all the command stuff (because they only work for built in CmdLets, not user defined functions) and doing this instead seems to be calling the code though none of the dependencies are loaded when it's running... I am still looking into that.

ps.AddScript( @"New-BuildCVFromSql 'C:\Documents and Settings\Brown.Ericw\My Documents\tempeval.sql' JCDC 'Evaluation\EvaluationFormPartialListCV'" );

It seems to be calling the code though none of the dependencies are loaded when it's running... I am still looking into that. But if it's run from the ISE it works...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Eric Brown - Cal
  • 14,135
  • 12
  • 58
  • 97

2 Answers2

2

In your second version of RunPowerShellCommandToBuildCV() is missing an ps.invoke() after script is added:

    //load as file - EWB
    ps.AddScript( psScriptPath );
    ps.Invoke(); //<--------- !!!!
    ps.AddCommand( "New-BuildCVFromSql" ).AddParameters(new Dictionary<string, string>()
     {
         { "SqlOrExcelFile", @"C:\tempeval.sql" },
         { "Js", "JCDC" },
         { "FileName", @"Evaluation\EvaluationFormPartialListCV" }
     });

After the Invoke() the runspace know that there's a function called New-BuildCVFromSql

CB.
  • 58,865
  • 9
  • 159
  • 159
  • I figured it out ps.AddScript( psScriptPath ); needed to be ps.AddScript( psScript ); (load the text of thefile not load by file name) and it's executing though it does not see my parameters...looking into that – Eric Brown - Cal Jun 06 '12 at 20:26
  • @EricBrown-Cal Why are you passing a `Dictionary`. Seeing your function param declaration I seem to have all string. – CB. Jun 07 '12 at 07:47
0

This is how I do it, and it works a treat:

private static void Test()
{
    dynamic parameters = new ExpandoObject();
    parameters.test= "myImage";
    parameters.arg2= 2;

    var results = RunPowerShellFunction("My-Function", parameters);
    var obj = results[0];
    var str = results[1];
}

private static dynamic RunPowerShellFunction(string functionName, dynamic parameters)
{
    dynamic rv = null;

    try
    {
        InitialSessionState iss = InitialSessionState.CreateDefault();

        using (Runspace runspace = RunspaceFactory.CreateRunspace(iss))
        {
            runspace.Name = typeof(DockerManager).Name;
            runspace.Open();

            RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(runspace);
            runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted");

            using (var mainPowerShell = System.Management.Automation.PowerShell.Create())
            {
                mainPowerShell.Runspace = runspace;

                mainPowerShell.AddScript(LoadedScriptText, false);
                mainPowerShell.Invoke();

                var cmd = mainPowerShell.AddCommand(functionName);

                if (parameters != null)
                {
                    foreach (var parameter in parameters)
                    {
                        cmd.AddParameter(parameter.Key, parameter.Value);
                    }
                }

                rv = cmd.Invoke();
            }
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }

    return rv;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cineam mispelt
  • 393
  • 1
  • 8