Приложение C # запускает PowerShell несколькими удаленными командами

#powershell #powershell-remoting

#powershell #powershell-удаленное управление

Вопрос:

У меня есть простое консольное приложение, пытающееся создать группу рассылки в Exchange через PowerShell и добавить в нее несколько участников.

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

Когда я запускаю свое приложение, оно выдает эту ошибку: объект ввода не может быть привязан к каким-либо параметрам для команды либо потому, что команда не принимает конвейерный ввод, либо потому, что ввод и его свойства не соответствуют ни одному из параметров, которые принимают конвейерный ввод.

Но группа распространения фактически создается.

Кроме того, я замечаю, что когда я комментирую команду для создания новой группы рассылки и запускаю команды для добавления членов группы рассылки, добавляется только первый член. Я действительно не понимаю, как мне следует поступить с этим, и у меня есть следующие вопросы:

  1. Как я могу заставить свой код успешно выполнять все команды?

  2. Каков наилучший способ выполнения нескольких удаленных команд PowerShell? Должен ли я запускать каждую команду отдельно, проверять возвращаемый объект, если он был успешным, а затем переходить к следующей команде. Какие-либо проблемы с производительностью, о которых следует знать?

  3. Выполняет ли runspace только одну команду за раз?

Когда я пытаюсь выполнить следующий код, я сталкиваюсь с этой ошибкой: Синтаксис не поддерживается этим пространством выполнения. Это может быть связано с тем, что оно находится в режиме без языка.

 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 Test2");

                try
                {
                    Collection<PSObject> results = pipe.Invoke();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
      }
  

Комментарии:

1. @kiquenet библиотеку C # с полной реализацией можно найти здесь github.com/neutmute/exchange-client

Ответ №1:

Система.Управление.Автоматизация.Powershell:

Предоставляет методы, которые используются для создания конвейера команд и вызова этих команд синхронно или асинхронно в пространстве выполнения. Этот класс также предоставляет доступ к потокам вывода, которые содержат данные, генерируемые при вызове команд.

Важная часть заключается в том, что — create a pipeline . Что вы делаете, так это создаете конвейер и добавляете в него команды, используя ps.Commands.AddCommand и поскольку способ, которым вы их добавили, с дополнительными параметрами, которые вы указали, вы получаете ошибку, которую вы видите. Потому что выходной объект New-DistributionGroup не может быть передан Add-DistributionGroupMember и так далее.

Таким образом, выполняется первая команда в конвейере, а следующая завершается неудачно, потому что объект, который вы передаете ему, несовместим (особенно после добавленных вами параметров). Таким образом, создается группа рассылки, и когда вы ее комментируете, добавляется только первый участник.

Одна вещь, которую вы можете попробовать, это использовать Powershell.AddScript :

 string script = "New-DistributionGroup -Name Test; Add-DistributionGroupMember -Identity Test -Member testuser1@somecompany.com";
ps.AddScript(script);
ps.Invoke();
  

В противном случае, я думаю, вам придется добавить команду, вызвать ее, очистить команду ( ps.Commands.Clear() ) и добавить следующую команду, вызвать ее и так далее.