none
C# Remote PowerShell Running Multiple Commands in Runspace RRS feed

  • Question

  • Hi,

    I have a simple console app trying to create a distribution group and add a few members to it. 

    Code:

     

    class Program
        {
            static void Main(string[] args)
            {
                string userName = "foo";
                string password = "pwd";
    
                // Encrypt password using SecureString class
                SecureString securePassword = new SecureString();
    
                foreach (char c in password)
                {
                    securePassword.AppendChar(c);
                }
    
                PSCredential credential = new PSCredential(userName, securePassword);
    
                // Connection information object required to connect to the service
                WSManConnectionInfo connectionInfo = new WSManConnectionInfo(
                    new Uri("https://ps.outlook.com/powershell"), 
                    "http://schemas.microsoft.com/powershell/Microsoft.Exchange", 
                    credential);
    
                connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
                connectionInfo.MaximumConnectionRedirectionCount = 2;
    
    
    
                // Create runspace on remote Exchange server
                using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
                {
                    runspace.Open();
    
                    using(PowerShell ps = PowerShell.Create())
                    {
                        ps.Runspace = runspace;
    
                        Command newDG = new Command("New-DistributionGroup");
                        newDG.Parameters.Add(new CommandParameter("Name", "Test"));
                        ps.Commands.AddCommand(newDG);
    
                        Command addDGMember1 = new Command("Add-DistributionGroupMember");
                        addDGMember1.Parameters.Add(new CommandParameter("Identity", "Test"));
                        addDGMember1.Parameters.Add(new CommandParameter("Member", "testuser1@somecompany.com"));
                        ps.Commands.AddCommand(addDGMember1);
    
                        Command addDGMember2 = new Command("Add-DistributionGroupMember");
                        addDGMember2.Parameters.Add(new CommandParameter("Identity", "Test"));
                        addDGMember2.Parameters.Add(new CommandParameter("Member", "testuser2@somecompany.com"));
                        ps.Commands.AddCommand(addDGMember2);
    
    
                        try
                        {
                            // Invoke command and store the results in a PSObject
                            Collection<PSObject> results = ps.Invoke();
    
                            if (ps.Streams.Error.Count > 0)
                            {
                                foreach (ErrorRecord error in ps.Streams.Error)
                                {
                                    Console.WriteLine(error.ToString());
                                }
                            }
    
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                        finally
                        {
                            Console.WriteLine("Operation completed.");
                        }
                        
                    }
                }
    
                Console.ReadKey();
            }
        }
    


     

    When I run my app it throws this error: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.

    But the distribution group actually gets created. 

    Also, I notice that when I comment out the command to create a new distribution group and run the commands to add the distribution group members, only the first member is added. I'm really confused as to how I should proceed on this and I have the following questions:

    1. How can I get my code to run all the commands successfully?

    2. What would be the best way to do multiple remote PowerShell commands? Do I run each command separately, check the return object if it was successful, and then proceed to the next command. Any performance issues to be aware of?

    3. Does the runspace run only one command at a time?

    Any help is greatly appreciated.

     

    Thanks,

    Mike.

    Sunday, October 9, 2011 9:13 PM

Answers

All replies

  • When you use AddCommand what you doing is creating one large Pipeline to execute or in Powershell it would be one large oneliner which is okay for some things as long as what your pipeline-ing to accepts and output the particular objects you need. What you trying to do wont work for more the one user because of the Output of Add-DistributionGroupMember is null. If you want to execute multiple commands you need to close the pipeline and create a new one the runspace will only run one pipeline at a time.

    But you don't really need to use Add-DistributionGroupMember because you can specify the members as a array when you create the group with New-DistributionGroup (note you can't use an array in add-DistributionGroupMember you need to always spec a single recipient but you can pipe and array to it for multiple adds).

                    Command newDG = new Command("New-DistributionGroup");
                    newDG.Parameters.Add(new CommandParameter("Name", "Test-DL"));
                    newDG.Parameters.Add(new CommandParameter("Members", new String[]{"glen@domain.com","fred@domain.com"}));
                    ps.Commands.AddCommand(newDG);
    
    Cheers
    Glen

    Monday, October 10, 2011 5:04 AM
  • Glen,

    Thank you! Your answer works. Before reading your post I was trying to see if I can use the AddScript method like so:

     

                using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
                {
                    runspace.Open();
    
                    using (PowerShell ps = PowerShell.Create())
                    {
                        ps.Runspace = runspace;
    
                        Pipeline pipe = runspace.CreatePipeline();
                        pipe.Commands.AddScript("New-DistributionGroup -Name TestDL");
    
                        try
                        {
                            Collection<PSObject> results = pipe.Invoke();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                }
    


     

    But when I tried this, I got this error:The syntax is not supported by this runspace. This might be because it is in no- language mode.

    I searched for this error and so far it seems to be rectifiable only by an IIS setting. Any ideas on this?

    Also I have a few more questions:

    1. Is it possible to do what you suggested above via the AddScript method?

    2. If not, what would be the best way to add/remove members from a DG... say I have to add 100+ members to  a DG.

     

    Thanks again for your help.

    Cheers,

    Mike.

    Monday, October 10, 2011 5:54 AM
  • 1. If you want to use script blocks have a look at the second sample on http://blogs.technet.com/b/exchange/archive/2009/11/02/3408653.aspx

    2 use an Array and pipe the array to add-distributiongroupmember eg Get-Content user.txt | Add-DistributionGroupMember -Identity Test-dl

    Cheers

    Glen

    • Marked as answer by preambleMe Tuesday, October 11, 2011 3:33 PM
    Tuesday, October 11, 2011 2:15 AM
  • I too have a similar problem, but instead of Distribution group I am trying to access Room Custom Properties. Please Help

    SecureString secureString = new SecureString();
               
                foreach (char c in OlivesSetting.Default.Password)
                    secureString.AppendChar(c);
    
                PSCredential credential = new PSCredential(OlivesSetting.Default.AdminCredentials, secureString);
                WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri("https://outlook.office365.com/powershell-liveid"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credential);
                connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
                connectionInfo.SkipCACheck = true;
                connectionInfo.SkipCNCheck = true;
                connectionInfo.MaximumConnectionRedirectionCount = 4;
                try
                {
                    Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
                    runspace.Open();
    
                    Command gmGetMailbox = new Command("Get-Mailbox oliveroom@olivesmonday.onmicrosoft.com | fl CustomAttribute*", true);
                    //gmGetMailbox.Parameters.Add("ResultSize", "Unlimited");
                    Pipeline plPileLine = runspace.CreatePipeline();
                    
                    plPileLine.Commands.Add(gmGetMailbox);
                    Collection<PSObject> RsResultsresults = plPileLine.Invoke();
                  
                    plPileLine.Stop();
                    plPileLine.Dispose();
    
                    runspace.Close();
                }
                catch (Exception ex)
                {
                   throw ex;
                }


    • Edited by Mohit Mishra Wednesday, December 17, 2014 2:09 PM
    Wednesday, December 17, 2014 2:08 PM
  • oliveroom@olivesmonday.onmicrosoft.com | fl CustomAttribute*", true);
                   

    That won't work that is not a Command the Command is Get-Mailbox and the parameter is Identity. The rest is redundant because this isn't PowerShell so you just access the property from the Result collection

    Command gmGetMailbox = new Command("Get-Mailbox");
    gmGetMailbox.Parameters.Add(new CommandParameter("Identity", "oliveroom@olivesmonday.onmicrosoft.com"));
    Pipeline plPileLine = runspace.CreatePipeline();
    plPileLine.Commands.Add(gmGetMailbox);
    Collection<PSObject> RsResultsresults = plPileLine.Invoke();
    foreach (PSObject obj in RsResultsresults)
    {
      Console.WriteLine(obj.Properties["CustomAttribute"].Value.ToString());
    }
    Cheers
    Glen



    Thursday, December 18, 2014 2:44 AM
  • It's for exchange 2016 or exchange 2013?
    Wednesday, January 3, 2018 4:50 PM