C# 如何在 Powershell 中模拟 Active Directory 用户?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11806/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-07-31 17:41:12  来源:igfitidea点击:

How do you impersonate an Active Directory user in Powershell?

提问by Eldila

I'm trying to run powershell commands through a web interface (ASP.NET/C#) in order to create mailboxes/etc on Exchange 2007. When I run the page using Visual Studio (Cassini), the page loads up correctly. However, when I run it on IIS (v5.1), I get the error "unknown user name or bad password". The biggest problem that I noticed was that Powershell was logged in as ASPNET instead of my Active Directory Account. How do I force my Powershell session to be authenticated with another Active Directory Account?

我正在尝试通过 Web 界面 (ASP.NET/C#) 运行 powershell 命令,以便在 Exchange 2007 上创建邮箱/等。当我使用 Visual Studio (Cassini) 运行页面时,页面正确加载。但是,当我在 IIS (v5.1) 上运行它时,出现错误“未知用户名或密码错误”。我注意到的最大问题是 Powershell 是作为 ASPNET 而不是我的 Active Directory 帐户登录的。如何强制我的 Powershell 会话使用另一个 Active Directory 帐户进行身份验证?

Basically, the script that I have so far looks something like this:

基本上,我到目前为止的脚本看起来像这样:

RunspaceConfiguration rc = RunspaceConfiguration.Create();
PSSnapInException snapEx = null;
rc.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out snapEx);

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

Pipeline pipeline = runspace.CreatePipeline();
using (pipeline)
{
   pipeline.Commands.AddScript("Get-Mailbox -identity 'user.name'");
   pipeline.Commands.Add("Out-String");

   Collection<PSObject> results = pipeline.Invoke();

   if (pipeline.Error != null && pipeline.Error.Count > 0)
   {
       foreach (object item in pipeline.Error.ReadToEnd())
          resultString += "Error: " + item.ToString() + "\n";
   }

   runspace.Close();

   foreach (PSObject obj in results)
      resultString += obj.ToString();
}

return resultString;

采纳答案by Eldila

Exchange 2007 doesn't allow you to impersonate a user for security reasons. This means that it is impossible (at the moment) to create mailboxes by impersonating a user. In order to get around this problem, I created a web service which runs under AD user which has permissions to create email acounts, etc. You can then access this webservice to get access to powershell. Please remember to add the necessary security because this could potentially be a huge security hole.

出于安全原因,Exchange 2007 不允许您模拟用户。这意味着(目前)无法通过模拟用户来创建邮箱。为了解决这个问题,我创建了一个在 AD 用户下运行的 Web 服务,该用户有权创建电子邮件帐户等。然后您可以访问此 Web 服务以访问 powershell。请记住添加必要的安全性,因为这可能是一个巨大的安全漏洞。

回答by Kev

In your ASP.NET app, you will need to impersonate a valid AD account with the correct permissions:

在您的 ASP.NET 应用程序中,您需要模拟具有正确权限的有效 AD 帐户:

http://support.microsoft.com/kb/306158

http://support.microsoft.com/kb/306158

回答by Otto

Here is a class that I use to impersonate a user.

这是我用来模拟用户的类。

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace orr.Tools
{

    #region Using directives.
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    #endregion

    /// <summary>
    /// Impersonation of a user. Allows to execute code under another
    /// user context.
    /// Please note that the account that instantiates the Impersonator class
    /// needs to have the 'Act as part of operating system' privilege set.
    /// </summary>
    /// <remarks>   
    /// This class is based on the information in the Microsoft knowledge base
    /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158
    /// 
    /// Encapsulate an instance into a using-directive like e.g.:
    /// 
    ///     ...
    ///     using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
    ///     {
    ///         ...
    ///         [code that executes under the new context]
    ///         ...
    ///     }
    ///     ...
    /// 
    /// Please contact the author Uwe Keim (mailto:[email protected])
    /// for questions regarding this class.
    /// </remarks>
    public class Impersonator :
        IDisposable
    {
        #region Public methods.
        /// <summary>
        /// Constructor. Starts the impersonation with the given credentials.
        /// Please note that the account that instantiates the Impersonator class
        /// needs to have the 'Act as part of operating system' privilege set.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        public Impersonator(
            string userName,
            string domainName,
            string password)
        {
            ImpersonateValidUser(userName, domainName, password);
        }

        // ------------------------------------------------------------------
        #endregion

        #region IDisposable member.

        public void Dispose()
        {
            UndoImpersonation();
        }

        // ------------------------------------------------------------------
        #endregion

        #region P/Invoke.

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int LogonUser(
            string lpszUserName,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int DuplicateToken(
            IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool RevertToSelf();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(
            IntPtr handle);

        private const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_PROVIDER_DEFAULT = 0;

        // ------------------------------------------------------------------
        #endregion

        #region Private member.
        // ------------------------------------------------------------------

        /// <summary>
        /// Does the actual impersonation.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        private void ImpersonateValidUser(
            string userName,
            string domain,
            string password)
        {
            WindowsIdentity tempWindowsIdentity = null;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            try
            {
                if (RevertToSelf())
                {
                    if (LogonUser(
                        userName,
                        domain,
                        password,
                        LOGON32_LOGON_INTERACTIVE,
                        LOGON32_PROVIDER_DEFAULT,
                        ref token) != 0)
                    {
                        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                        {
                            tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                            impersonationContext = tempWindowsIdentity.Impersonate();
                        }
                        else
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
                    }
                    else
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                if (token != IntPtr.Zero)
                {
                    CloseHandle(token);
                }
                if (tokenDuplicate != IntPtr.Zero)
                {
                    CloseHandle(tokenDuplicate);
                }
            }
        }

        /// <summary>
        /// Reverts the impersonation.
        /// </summary>
        private void UndoImpersonation()
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
            }
        }

        private WindowsImpersonationContext impersonationContext = null;

        // ------------------------------------------------------------------
        #endregion
    }
}

回答by Sam Cogan

This article on MSDN blogs seems to show a way to do it, I've not been able to try it yet, but will let you know when I do.

MSDN 博客上的这篇文章似乎展示了一种方法,我还没有尝试过,但会在我尝试时通知您。

http://blogs.msdn.com/webdav_101/archive/2008/09/25/howto-calling-exchange-powershell-from-an-impersonated-thead.aspx

http://blogs.msdn.com/webdav_101/archive/2008/09/25/howto-calling-exchange-powershell-from-an-impersonated-thead.aspx

回答by Sam Cogan

You might need a patch.

你可能需要一个补丁。

From: http://support.microsoft.com/kb/943937

来自:http: //support.microsoft.com/kb/943937

An application cannot impersonate a user and then run Windows PowerShell commands in an Exchange Server 2007 environment

To resolve this problem, install Update Rollup 1 for Exchange Server 2007 Service Pack 1.

应用程序无法模拟用户,然后在 Exchange Server 2007 环境中运行 Windows PowerShell 命令

要解决此问题,请安装 Exchange Server 2007 Service Pack 1 的更新汇总 1。