簡體   English   中英

在C#中連接到Microsoft Exchange PowerShell

[英]Connect to Microsoft Exchange PowerShell within C#

我正在嘗試從C#.NET WinForms應用程序連接到遠程PowerShell。 我的目標是創建自己的Microsoft PowerShell ISE版本。 所以我需要一種從遠程計算機上的應用程序執行PowerShell腳本的方法。 我已經創建了幾種方法,並在我的應用程序中在本地計算機上進行了測試。 如果我不使用WSManConnectionInfo並使用(Runspace remoteRunspace = RunspaceFactory.CreateRunspace())我可以在本地執行腳本,就好像它是真的powershell(小腳本,變量的使用,輸出數據使用ftfl ,做了很多我通常用powershell做的其他事情。當我添加WSManConnectionInfo並將其指向我的Exchange Server而不是使用本地連接時,問題就出現了。似乎它能夠執行像“get-mailbox”這樣的基本內容但是只要我嘗試管道東西,使用一些腳本功能,如$ variables它打破說它不受支持。

同樣,我必須禁用powershell.AddCommand(“out-string”); 什么時候不在本地使用它。

System.Management.Automation.dll中發生了未處理的“System.Management.Automation.RemoteException”類型異常。

附加信息:術語“Out-String”不被識別為cmdlet,函數,腳本文件或可操作程序的名稱。 檢查名稱的拼寫,或者如果包含路徑,請驗證路徑是否正確,然后重試。

如果我不強制遠程連接但只是在本地執行,則不會出現相同的錯誤。 似乎SchemaUri只對執行基本命令非常嚴格。 我看到了其他使用非常直接信息的人的例子:

powershell.AddCommand("Get-Users");
powershell.AddParameter("ResultSize", count);

但是通過這種方法,我將不得不定義許多可能的選項,我不想通過定義參數和其他東西。 我只是想加載“腳本”並像在PowerShell窗口中那樣執行它。這是我現在使用的一個例子。

    public static WSManConnectionInfo PowerShellConnectionInformation(string serverUrl, PSCredential psCredentials)
    {
        var connectionInfo = new WSManConnectionInfo(new Uri(serverUrl), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", psCredentials);
        //var connectionInfo = new WSManConnectionInfo(new Uri(serverUrl), "http://schemas.microsoft.com/powershell", psCredentials);
        connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
        connectionInfo.SkipCACheck = true;
        connectionInfo.SkipCNCheck = true;
        connectionInfo.SkipRevocationCheck = true;
        connectionInfo.MaximumConnectionRedirectionCount = 5;
        connectionInfo.OperationTimeout = 150000;
        return connectionInfo;
    }
    public static PSCredential SecurePassword(string login, string password)
    {
        SecureString ssLoginPassword = new SecureString();
        foreach (char x in password) { ssLoginPassword.AppendChar(x); }
        return new PSCredential(login, ssLoginPassword);
    }
    public static string RunScriptPs(WSManConnectionInfo connectionInfo, string scriptText)
    {
        StringBuilder stringBuilder = new StringBuilder();
        // Create a remote runspace using the connection information.
        //using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace())
        using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo))
        {
            // Establish the connection by calling the Open() method to open the runspace. 
            // The OpenTimeout value set previously will be applied while establishing 
            // the connection. Establishing a remote connection involves sending and 
            // receiving some data, so the OperationTimeout will also play a role in this process.
            remoteRunspace.Open();
            // Create a PowerShell object to run commands in the remote runspace.
            using (PowerShell powershell = PowerShell.Create())
            {
                powershell.Runspace = remoteRunspace;
                powershell.AddScript(scriptText);
                //powershell.AddCommand("out-string");
                powershell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
                Collection<PSObject> results = powershell.Invoke();

                foreach (PSObject result in results) {
                        stringBuilder.AppendLine(result.ToString());
                }

            }
            // Close the connection. Call the Close() method to close the remote 
            // runspace. The Dispose() method (called by using primitive) will call 
            // the Close() method if it is not already called.
            remoteRunspace.Close();
        }

        // convert the script result into a single string
        return stringBuilder.ToString();
    }

關於為什么會發生這種情況的任何建議,並解決如何讓它以相同的方式運行? 我見過很多像這樣的博客,但定義每個簡單的命令對我來說都沒有意義。 我還看到了創建本地連接然后在其中執行遠程連接的選項但這必須是最后的手段,因為它依賴於多個其他因素。

檢查https://blogs.msdn.microsoft.com/akashb/2010/03/25/how-to-migrating-exchange-2007-powershell-managed-code-to-work-with-exchange-2010/

Exchange 2010通過PowerShell提供的管理體驗已從Local更改為Remote。 [...]只有交換cmdlet才能在此遠程處理方案中運行, 您將無法運行大多數PowerShell cmdlet [...]是的,這確實意味着您將無法在遠程運行空間中運行Where-Object和.PS1腳本等cmdlet

這是一個限制嗎? 我不這么認為。 我們可以通過創建一個新的Session並導入它來輕松解決它


所以你需要做這樣的事情

PSCredential creds = new PSCredential(userName, securePassword);
System.Uri uri = new Uri("http://Exchange-Server/powershell?serializationLevel=Full");

Runspace runspace = RunspaceFactory.CreateRunspace();

PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("ConnectionUri", uri);
command.AddParameter("Credential", creds);
command.AddParameter("Authentication", "Default");
powershell.Commands = command;
runspace.Open(); powershell.Runspace = runspace;
Collection<PSSession> result = powershell.Invoke<PSSession>();

powershell = PowerShell.Create();
command = new PSCommand();
command.AddCommand("Set-Variable");
command.AddParameter("Name", "ra");
command.AddParameter("Value", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();

powershell = PowerShell.Create();
command = new PSCommand();
command.AddScript("Import-PSSession -Session $ra");
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();

# now you can use remote PS like it's local one

從Exchange Server 2010開始,您需要使用遠程PowerShell會話,而不是直接添加交換PowerShell管理單元(由於在Exchange 2010中使用RBAC而不是ACL)。 因此,您需要創建新的PowerShell會話(使用New-PSSession),然后導入它(使用Import-PSSession)。 您可以使用這樣的代碼來執行遠程PowerShell命令:

void ExecutePowerShellUsingRemotimg()
{
    RunspaceConfiguration runspaceConfig = RunspaceConfiguration.Create();
    PSSnapInException snapInException = null;

    Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfig);
    runspace.Open();

    Pipeline pipeline = runspace.CreatePipeline();


    string serverFqdn = "FQDN of you server";
    pipeline.Commands.AddScript(string.Format("$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://{0}/PowerShell/ -Authentication Kerberos", serverFqdn));
    pipeline.Commands.AddScript("Import-PSSession $Session");
    pipeline.Commands.AddScript("your PowerShell script text");
    pipeline.Commands.Add("Out-String");
    Collection<PSObject> results = pipeline.Invoke();
    runspace.Close();

    StringBuilder sb = new StringBuilder();

    if (pipeline.Error != null && pipeline.Error.Count > 0)
    {
        // Read errors
        succeeded = false;
        Collection<object> errors = pipeline.Error.ReadToEnd();
        foreach (object error in errors)
            sb.Append(error.ToString());
    }
    else
    {
        // Read output
        foreach (PSObject obj in results)
            sb.Append(obj.ToString());
    }

    runspace.Dispose();
    pipeline.Dispose();
}

看起來你遇到了雙跳認證問題,我在嘗試這個問題時遇到了同樣的問題。

搞亂之后,我最終在本地安裝了Exchange Powershell插件,並使用它們遠程連接到Exchange服務器。

粗略的例子:

    RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
    PSSnapInInfo info = runspaceConfiguration.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out snapInException);                                    

    Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
    runspace.Open();

    using (PowerShell powershell = PowerShell.Create())
    {
        powershell.Runspace = runspace;

        string script = string.Format(@"Get-Mailbox -Server {0} -Identity {1}", serverName, identity);
        powershell.AddScript(script);

        powershell.Invoke();

       // Do something with the output

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM