C# System.Diagnostics.Process.针对不同域启动进程

C# System.Diagnostics.Process.针对不同域启动进程,c#,.net,process,C#,.net,Process,我们有一个场景,需要用户能够启动SQLServer,并使用与当前登录的域不同的域进行身份验证。因此,为了澄清这种设置方式: 用户到达办公室并登录到corporate domain,为简单起见,我们将其称为LOCALDOMAIN 他们希望连接到另一个域上的远程数据库,我们称之为REMOTEDOMAIN 首先,他们启动了VPN工具,该工具建立了通向REMOTEDOMAIN的VPN隧道。这一切都经过了测试,效果很好 但是,如果他们在默认情况下启动SSM,它将只允许通过LOCALDOMAIN进行Wind

我们有一个场景,需要用户能够启动SQLServer,并使用与当前登录的域不同的域进行身份验证。因此,为了澄清这种设置方式:

用户到达办公室并登录到corporate domain,为简单起见,我们将其称为LOCALDOMAIN 他们希望连接到另一个域上的远程数据库,我们称之为REMOTEDOMAIN 首先,他们启动了VPN工具,该工具建立了通向REMOTEDOMAIN的VPN隧道。这一切都经过了测试,效果很好 但是,如果他们在默认情况下启动SSM,它将只允许通过LOCALDOMAIN进行Windows身份验证,选择REMOTEDOMAIN的选项甚至不可用 我们发现,从命令行运行此命令将起作用:

RUNAS /user:REMOTEDOMAIN\AUserName /netonly "C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Ssms.exe
它将提示您输入REMOTEDOMAIN\AUserName的密码:如果您提供了正确的密码,将启动SSMS并可以连接到远程dbs。然而,当我尝试在C中使用更好的界面来做同样的事情时,我得到了登录失败:未知的用户名或错误的密码,下面是我的代码:

System.Security.SecureString password = new System.Security.SecureString();
foreach(char c in txtPassword.Text.ToCharArray()){
    password.AppendChar(c);
}
System.Diagnostics.ProcessStartInfo procInfo = new System.Diagnostics.ProcessStartInfo();
procInfo.Arguments = "/netonly";
procInfo.FileName = @"C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Ssms.exe"; ;
procInfo.Domain = "REMOTEDOMAIN";
procInfo.Verb = "runas";
procInfo.UserName = txtUsername.Text;
procInfo.Password = password;
procInfo.UseShellExecute = false;
System.Diagnostics.Process.Start(procInfo);

我尝试了用户名,有域名和没有域名,但都不起作用。有人试过做类似的事情吗?谢谢

您应该删除以下行:

// Not passing /netonly to SMSS, it was passed to RunAs originally.
procInfo.Arguments = "/netonly";
// Again, SMSS is not getting the verb, it's being run
procInfo.Verb = "runas";
基本上,您将/netonly参数传递给SMS,而在命令行上,您运行的是runas而不是SMS。和动词一样,你没有运行runas


此时调用Start应该会成功,因为您将使用正确的凭据指向正确的可执行文件。

我做了一些可能相关的事情。我登录到一个域并尝试获取另一个域上共享文件夹的目录列表。为此,我使用LogonUser和Impersonate。代码如下所示抱歉,我没有SQL server来尝试您的确切场景

public class Login : IDisposable
{
    public Login(string userName, string domainName)
    {
        _userName = userName;
        _domainName = domainName;
    }

    string _userName = null;
    string _domainName = null;

    IntPtr tokenHandle = new IntPtr(0);
    IntPtr dupeTokenHandle = new IntPtr(0);
    WindowsImpersonationContext impersonatedUser = null;

    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_LOGON_INTERACTIVE = 2;
    const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

    [DllImport("advapi32.dll", SetLastError = true, EntryPoint = "LogonUser")]
    public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
        int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    [DllImport("advapi32.dll", SetLastError = true, EntryPoint = "LogonUser")]
    public static extern bool LogonUserPrompt(String lpszUsername, String lpszDomain, IntPtr lpszPassword,
        int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

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

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
        int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

    public void AccessShare(string password)
    {
        tokenHandle = IntPtr.Zero;

        bool returnValue = LogonUser(_userName, _domainName, password,
            LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT,
            ref tokenHandle);

        if (false == returnValue)
        {
            int ret = Marshal.GetLastWin32Error();
            throw new System.ComponentModel.Win32Exception(ret);
        }

        // Use the token handle returned by LogonUser.
        WindowsIdentity newId = new WindowsIdentity(tokenHandle);
        impersonatedUser = newId.Impersonate();
    }

#region IDisposable Members
    public void  Dispose()
    {
        impersonatedUser.Undo();

        // Free the tokens.
        if (tokenHandle != IntPtr.Zero)
            CloseHandle(tokenHandle);
    }
#endregion
}
我在Directory.GetDirectoriesUNCPath中使用了这个选项,其中的路径指向另一个域上的机器,并且在那里工作。我还没有尝试过用它来实现runas

我这样称呼它

using(var login = new Login("myname","mydomain))
{
    login.AccessShare("mypassword");
    // do stuff
}

也许你可以调整它以适应你的问题。LMK

我尝试了我能找到的各种用户模拟代码示例。他们都没有工作

最后,我提出了以下代码。它使用/C参数执行cmd.exe,该参数执行字符串指定的命令,然后终止。我执行的命令是runas/netonly

警告 不幸的是,密码必须手动输入。我的下一步是调查将key stokes发送到流程中。我尝试重定向标准输入并写入它,但没有成功。我在某个地方读过,所以大多数密码提示只接受直接来自键盘的输入

此外,当SSMS打开时,“连接到服务器”对话框将显示您当前的域\用户名,但它将使用您提供给runas的域\用户名进行身份验证

最后,如果您的广告帐户被锁定,则在尝试连接到SQL Server之前不会出现错误。我忘了抄下我收到的错误信息,但它没有提到帐户被锁定

密码
小心这个。由此打开的SSMS实例可能不具有本地计算机用户在本地拥有的任何权限。包括所有未永久化的映射网络驱动器。添加作为注释,因为我不想因为回答错误而愤怒。如果有文件需要恢复,SSMS将自动关闭。我和你有相同的场景,我的解决方法是手动打开SSM处理恢复的文件,然后按正常方式继续我尝试了,但我得到了相同的错误,我可以看到你说的,但是有很多例子是通过提升权限运行EXE,使用runas作为动词感谢你的回复,实际上,我也尝试过类似的东西,我也尝试过你的代码,但无论是什么原因,我的场景似乎都无法做到:登录失败:未知用户名或错误密码
    public static void RunAsNetonly(string username, string domain, string exePath)
    {

        var psi = new ProcessStartInfo();

        psi.FileName = "cmd.exe";
        psi.Arguments = $"/C runas /netonly /user:{domain}\\{username} \"{exePath}\"";            
        psi.UseShellExecute = false;

        var process = Process.Start(psi);

        // not sure if this is required
        process.WaitForExit();

    }        
    
    // usage example
    public static void RunSSMS()
    {
        RunAsNetonly("walter", "domain123", @"C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\ssms.exe");
    }