0

I'm having trouble trying to call a Powershell function from C#. Specifically, I'm getting stuck trying to pass a generic list of Project's to a powershell module function. Here is the code:

var script = @". \\server01\Modules\Runspace.ps1; Get-MyCommand";
var allProjects = _pmRepository.GetAllProjects();
using (Runspace runSpace = RunspaceFactory.CreateRunspace())
{
    runSpace.Open();
    PowerShell posh = PowerShell.Create();
    posh.Runspace = runSpace;
    posh.AddScript(script);
    posh.AddArgument(allProjects);

    Collection<PSObject> results = posh.Invoke();
}

The GetAllProjects() method returns a generic list of Project's and Project is a custom class. My module function signature looks like this:

function Get-MyCommand
{
    [CmdletBinding()]
    Param
    (
        [Parameter(ValueFromPipeline = $true)]
        [PSCustomObject[]] $Projects
    )
    Begin
    {}
    Process
    {
        $consumables = New-GenericList "Company.Project.Entities.Project"
        foreach($project in $projects)
        {
            if ($project.State -eq $ProjectStates.Development)
            {
                $consumables.Add($project)
            }
        }
    }
}

I'm getting this error when I try to iterate over the array:

{"Property 'State' cannot be found on this object. Make sure that it exists."}

Is it possible to do what I'm trying to do?

Edit: I used the below code for a while, but ended up consuming the back-end C# code for this web application. The load time to create a powershell session was just too great for our situation. Hope this helps.

    private void LoadConsumableProjects()
    {
        var results = new Collection<PSObject>();
        InitialSessionState iss = InitialSessionState.CreateDefault();
        iss.ImportPSModule(_modules);

        using (Runspace runSpace = RunspaceFactory.CreateRunspace(iss))
        {
            runSpace.Open();
            using (var ps = PowerShell.Create())
            {
                ps.Runspace = runSpace;
                ps.AddScript("Get-LatestConsumableProjects $args[0]");
                ps.AddArgument(Repository.GetAllProjects().ToArray());

                results = ps.Invoke();
                if (ps.Streams.Error.Count > 0)
                {
                    var errors = "Errors";
                }
            }
        }

        _projects = new List<Project>();
        foreach (var psObj in results)
        {
            _projects.Add((Project)psObj.BaseObject);
        }
    }
drohm
  • 226
  • 2
  • 15
  • In your script, you dot source 'Runspace.ps1' and then call your function Get-MyCommand, without arguments you don't fortget $args ? – JPBlanc Sep 16 '11 at 03:58
  • The argument is passed in when I'm constructing the Runspace and Powershell object. `posh.AddArgument(allProjects);` – drohm Sep 16 '11 at 04:22
  • Ok, but I was thinking that you have to write something like this `var script = @". \\server01\Modules\Runspace.ps1; Get-MyCommand $args";` for the argument be passed tou your function `Get-MyCommand` – JPBlanc Sep 16 '11 at 05:51
  • @Kiquenet I'll try to dig it up this afternoon for you. – drohm Jun 11 '12 at 19:16
  • 1
    @Kiquenet I updated the original question with the solution I used at the time. I ended up consuming the back end C# code as the time penalty for creating a powershell session was too great for our needs. Hope this helps. – drohm Jun 12 '12 at 18:49

1 Answers1

1

Ok I put it as an answer because, I think you can test it. As I understand your code your pass an argument to your script :

posh.AddArgument(allProjects);

But inside your script you don't use this argument to pass to your Function. For me you can test :

var script = @". \\server01\Modules\Runspace.ps1; Get-MyCommand $args[0]";

In your script, you dot source 'Runspace.ps1' and then call your function Get-MyCommand without parameters. PowerShell get into the foreach loop with $project equal to null. Just beep if $Projects is null.

JPBlanc
  • 70,406
  • 17
  • 130
  • 175
  • I see what you mean now. I was under the impression that the AddArgument method was passing that argument to the function, not the script I'm asking it to run in the Runspace. I got further but I'm not getting this error: `Cannot process argument transformation on parameter 'Projects'. Cannot convert the "Company.Project.Entities.Project[]" value of type "Company.Project.Entities.Project[]" to type "Company.Project.Entities.Project".` – drohm Sep 16 '11 at 13:35
  • Also, the powershell function parameter is defined like this `[Parameter(ValueFromPipeline = $true)] [Company.Project.Entities.Project[]] $Projects` – drohm Sep 16 '11 at 13:41
  • It looks like `_pmRepository.GetAllProjects()` return only one project. Can you just declare `$Projects` without type and use `$Projects.gettype ` to have a look to the type. – JPBlanc Sep 16 '11 at 14:26
  • I removed the type constraint on the function parameter and added $paramType = $Projects.GetType() and reran and I'm getting this again: `Property 'State' cannot be found on this object. Make sure that it exists.` – drohm Sep 16 '11 at 14:37