Eric Brown - Cal
Eric Brown - Cal

Reputation: 14399

Code to run a PowerShell cmdlet (function?) that lives in a .ps1 file of cmdlets (functions?)

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...

Upvotes: 0

Views: 7491

Answers (2)

cineam mispelt
cineam mispelt

Reputation: 423

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;
}

Upvotes: 0

CB.
CB.

Reputation: 60928

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

Upvotes: 2

Related Questions