[英]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.