簡體   English   中英

在 C# 中調用 Exchange PowerShell

[英]Calling Exchange PowerShell in C#

我有一個應用程序,它允許原本無法訪問 Exchange 的用戶執行某些委托功能。 這一切都適用於標准加入域的計算機上的用戶。 然而,我們正在獲得越來越多的由 MEM (Intune) 構建的設備,這些設備雖然根據策略進行管理,但不是域成員。 由於使用了 Kerberos 身份驗證,當我嘗試在代碼中創建 Exchange PowerShell 會話時,這會導致問題。 這是應用程序中一些代碼的示例:

internal static bool UpdateMailbox(string identity, out string reply)
{
    reply = string.Empty;
    try
    {
        string server = DatabaseManager.GetConfigOption("ExchangePowerShellURI"); // http://exc16-01.domain.com/PowerShell
        string uname = DatabaseManager.GetConfigOption("ADUser");  // user@domain.com
        SecureString password = GetPassword(); // makes a SecureString for the user password
        PSCredential creds = new PSCredential(uname, password);
        WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri(server), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", creds);
        connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
        using (Runspace rs = RunspaceFactory.CreateRunspace(connectionInfo))
        {
            rs.Open();
            using (PowerShell ps = PowerShell.Create())
            {
                ps.Runspace = rs;
                
                // do stuff with PowerShell
                
                return true;
            }
        }
    }
    catch (Exception ex)
    {
        reply = ex.Message;
        return false;
    }
}

我曾考慮使用基於證書的身份驗證,但我不知道這是否適用於 Exchange PowerShell,或者如何更改我的代碼以使用它而不是 Kerberos。 我知道我可以更改 WinRM 客戶端/服務器以允許未加密的流量並使用基本身份驗證,但我寧願不這樣做,除非沒有其他選擇。

我將不勝感激有關如何使其適用於未加入域的設備的任何建議,即使事實證明 Basic 是唯一的選擇。

如果它與我要問的任何事情相關,我們正在本地使用 Exchange 2016。

好的,經過大量試驗和錯誤,我有一個可行的解決方案。 在這里分享信息以防它對其他人有用,盡管這似乎是一個小眾需求。

首先,您需要確保 Exchange 服務器上的 WinRM 配置為 HTTPS,並且在服務上啟用了證書身份驗證。 運行快速配置將啟用 HTTPS 偵聽器,並且可以使用以下命令啟用啟用證書身份驗證的選項:

Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -Value $true

為此,您將需要為計算機標識頒發的證書,該證書頒發給 Exchange 服務器的 FQDN。 您的里程可能會有所不同,但我發現我必須使用我們企業 CA 的證書,因為自簽名證書由於某種原因不起作用。

接下來,在 Exchange 服務器上創建一個新的本地用戶帳戶並將其添加到遠程管理用戶組。

接下來,我們需要頒發給域用戶的證書。 同樣,對我來說,自簽名的不起作用,我不得不使用企業 CA 中的一個。 需要在想要使用該解決方案的所有客戶端計算機上安裝完整的 PFX(包括私鑰)。 獲得證書后,只需將其公共部分導出為 CER 文件,然后將其安裝在機器存儲的 Trusted People 容器中的 Exchange 服務器上。

在此之后,我們需要將新的本地用戶綁定到已導入的證書,這可以使用以下 PowerShell 命令完成:

New-Item -Path WSMan:\localhost\ClientCertificate -Subject <upn of the user it was issued to> -URI * -Issuer <thumbprint of the CA cert> -Credential (Get-Credential)

對於頒發者指紋,我使用了我導入的證書鏈中下一個證書的指紋。

在此之后,它的代碼:

internal static bool UpdateMailbox(string identity, out string reply)
{
    reply = string.Empty;
    try
    {
        string psURI = DatabaseManager.GetConfigOption("ExchangePowerShellURI"); // http://exc16-01.domain.com/PowerShell
        string server = new Uri(psURI).Host;
        string uname = DatabaseManager.GetConfigOption("ADUser");  // user@domain.com
        SecureString password = GetPassword(); // makes a SecureString for the user password
        PSCredential creds = new PSCredential(uname, password); // PowerShell credential object for later use
        string thumbPrint = DatabaseManager.GetConfigOption("CertificateThumbprint"); // thumbprint of the cert to use
        WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri($"https://{server}"), "", creds);
        connectionInfo.CertificateThumbprint = thumbPrint;
        connectionInfo.Port = 5986;
        connectionInfo.MaximumConnectionRedirectionCount = 5;
        connectionInfo.SkipCACheck = true;
        connectionInfo.SkipCNCheck = true;
        using (Runspace rs = RunspaceFactory.CreateRunspace(connectionInfo))
        {
            rs.Open();
            using (PowerShell ps = PowerShell.Create())
            {
                ps.Runspace = rs;
                
                // Add PowerShell credential object into our session as a variable to use later
                PSCommand addCreds = new PSCommand();
                addCreds.AddCommand("Set-Variable");
                addCreds.AddParameter("Name", "cred");
                addCreds.AddParameter("Value", creds);
                ps.Commands = addCreds;
                ps.Invoke();
                
                // Create a new session of the Exchange Management Shell in our session called $ra. Kerberos is OK here as the Exchange server is pointing to itself
                PSCommand addSnapin = new PSCommand();
                string newSession = $"$ra = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri {psURI} -Authentication Kerberos -Credential $cred";
                addSnapin.AddScript(newSession);
                ps.Commands = addSnapin;
                ps.Invoke();
                
                // Invoke a command in our Exchange session from earlier
                PSCommand setMbx = new PSCommand();
                string strSetMbx = $"{{ Set-Mailbox -Identity {identity} -GrantSendOnBehalfTo admin@doman.com }}";
                setMbx.AddScript($"Invoke-Command -ScriptBlock {strSetMbx} -Session $ra");
                ps.Commands = setMbx;
                var result = ps.Invoke();
                
                // Do any further processing
                
                return true;
            }
        }
    }
    catch (Exception ex)
    {
        reply = ex.Message;
        return false;
    }
}

簡而言之,我在上面所做的是通過證書身份驗證在 Exchange 服務器上以本地用戶身份創建一個新的 PowerShell 會話。 將在 Exchange 中具有權限的域用戶的憑據作為變量添加到會話中,然后使用它們創建可以調用命令的 Exchange PowerShell 會話。

我希望這可以幫助任何有類似要求的人。 它比簡單地選擇 Basic 稍微復雜一些,但它以更多的證書開銷為代價使事情更安全,特別是如果它們像我們一樣只有 12 個月。

暫無
暫無

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

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