繁体   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