以指定的用户名和密码运行mstsc.exe

35

我知道在Windows 7中不可能保存同一主机的不同凭据,但我需要找到一些解决方法。

我能否在代码中手动提供用户名和密码?将它们存储在临时.rdp文件中?


5
基本思路是执行CMDKEY.EXE在存储的凭据库中创建临时凭据,然后执行MSTSC.EXE。MSTSC应该能够找到这些凭据并使用它们。您可以使用Process.Start从C#中执行这些程序;您不需要Powershell。 - Robert Harvey
7个回答

45
Process rdcProcess = new Process();
rdcProcess.StartInfo.FileName = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\system32\cmdkey.exe");
rdcProcess.StartInfo.Arguments = "/generic:TERMSRV/192.168.0.217 /user:" + "username" +  " /pass:" + "password";
rdcProcess.Start();

rdcProcess.StartInfo.FileName = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\system32\mstsc.exe");
rdcProcess.StartInfo.Arguments = "/v " + "192.168.0.217"; // ip or name of computer to connect
rdcProcess.Start();

上述代码与.217建立了连接,但我没有被提示输入密码。感谢帮助。


2
如果您不想在存储库中保留存储的凭据,在此代码后,您可以再次调用cmdkey.exe并使用参数/delete:TERMSRV/192.168.0.217. - chopikadze
1
我仍然被要求输入密码。我的机器正在使用Vista商业版。 - Parth Soni
我仍然被提示输入密码。我的机器正在使用Windows 8。 - Marek Bar
它提示我直到我指定了域 -- /user:MyDomain\MyUser - J.H.
工作。有一种方法可以确定mstsc已完全登录到另一个系统,这将非常酷。 - Arsen Zahray
1
Process类继承自实现IDisposable的Component类,因此在启动进程实例后应该将其处理掉。 - Sasha Yakobchuk

38
如果您想使用PowerShell,可以使用以下方式添加凭据:
cmdkey /generic:DOMAIN/"computername or IP" /user:"username" /pass:"password"

然后使用以下方式调用RDP连接

Start-Process -FilePath "$env:windir\system32\mstsc.exe" -ArgumentList "/v:computer name/IP" -Wait

如果您想删除凭据,请运行以下命令

cmdkey /delete:DOMAIN/"Computer name or IP"

记得删除 ""


我喜欢这个!我已经让它在Windows Server 2008 R2上运行了。 - Alain
请参考 https://dev59.com/bGIj5IYBdhLWcg3wCxF0#29984647 了解如何禁用证书警告。 - lvmeijer

9

这是Krzysiek帖子的更新版本。

var rdcProcess = new Process
    {
        StartInfo =
            {
                FileName = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\system32\cmdkey.exe"),
                Arguments = String.Format(@"/generic:TERMSRV/{0} /user:{1} /pass:{2}", 
                            fp.ipAddress,
                            (String.IsNullOrEmpty(fp.accountDomain)) ? fp.accountUserName : fp.accountDomain + "\\" + fp.accountUserName,
                            fp.accountPassword),
                            WindowStyle = ProcessWindowStyle.Hidden                                
            }
    };
rdcProcess.Start();
rdcProcess.StartInfo.FileName = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\system32\mstsc.exe");
rdcProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
rdcProcess.StartInfo.Arguments = String.Format("/f /v {0}", fp.ipAddress); // ip or name of computer to connect
rdcProcess.Start();

它差不多成功了,但我仍需要输入密码。 - Marek Bar
2
@MarekBar 您的域可能有一个GPO,禁止存储远程桌面连接的密码。 - Craig Tullis

1

接受的答案解决了问题,但会留下凭据在用户凭据存储中的副作用。我最终创建了一个IDisposable,这样我就可以在using语句中使用凭据。

using (new RDPCredentials(Host, UserPrincipalName, Password))
{
    /*Do the RDP work here*/
}

internal class RDPCredentials : IDisposable
{
    private string Host { get; }

    public RDPCredentials(string Host, string UserName, string Password)
    {
        var cmdkey = new Process
        {
            StartInfo =
            {
                FileName = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\system32\cmdkey.exe"),
                Arguments = $@"/list",
                WindowStyle = ProcessWindowStyle.Hidden,
                UseShellExecute = false,
                RedirectStandardOutput = true
            }
        };
        cmdkey.Start();
        cmdkey.WaitForExit();
        if (!cmdkey.StandardOutput.ReadToEnd().Contains($@"TERMSRV/{Host}"))
        {
            this.Host = Host;
            cmdkey = new Process
            {
                StartInfo =
            {
                FileName = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\system32\cmdkey.exe"),
                Arguments = $@"/generic:TERMSRV/{Host} /user:{UserName} /pass:{Password}",
                WindowStyle = ProcessWindowStyle.Hidden
            }
            };
            cmdkey.Start();
        }
    }

    public void Dispose()
    {
        if (Host != null)
        {
            var cmdkey = new Process
            {
                StartInfo =
            {
                FileName = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\system32\cmdkey.exe"),
                Arguments = $@"/delete:TERMSRV/{Host}",
                WindowStyle = ProcessWindowStyle.Hidden
            }
            };
            cmdkey.Start();
        }
    }
}

1
@echo off

cmdkey /generic:TERMSRV/"*IP or Server Name*" /user:%username%

start mstsc /v:*IP or Server Name*

cmdkey /delete:TERMSRV/"*IP or Server Name*"

quit

3
虽然这段代码片段可能是解决方案,但包括一些解释真的有助于提高您的帖子质量。请记住,您正在回答未来读者的问题,这些人可能不知道您建议使用该代码的原因。 - Adam

1
大多数答案都是不正确的,它仍然需要密码,这是因为在同一进程实例上执行不同的进程。使用命令行可以完美地工作:
        string command = "/c cmdkey.exe /generic:" + ip 
        + " /user:" + user + " /pass:" + password + " & mstsc.exe /v " + ip;

        ProcessStartInfo info = new ProcessStartInfo("cmd.exe", command);
        info.WindowStyle = ProcessWindowStyle.Hidden;
        info.CreateNoWindow = true;

        Process proc = new Process();
        proc.StartInfo = info;
        proc.Start();

显然(根据发布的非答案回答),这与被接受的答案相同。(我不知道)。 - starball
几乎,这只使用一个进程并执行2个命令。 - Proxytype

1
在尝试弄清如何让用户进入我们的网络而不给他们完全的权限时,我为我的团队中的几个成员启用了远程桌面访问。在更深入地思考后,我很快想起了几年前在国防部工作时的一个项目。该项目要求我们“锁定”只有必要人员才能访问服务器上的程序。在花费了一些时间在微软的知识库上之后,我们意识到可以为那些使用RDP连接的员工创建桌面“快捷方式”,登录并将其访问权限限制在该服务器上的一个特定应用程序上。

1
那是斯诺登获取信息的方式吗 :) (开玩笑) - Zuzlx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接