rdpterminal-servicesremoteapp

Is there a way to change command-line arguments in a signed RDP file?


I need to specify command line arguments for a RemoteApp using the remoteapplicationcmdline property of a signed RDP file.

However, after the RDP file is signed, I cannot change the value for remoteapplicationcmdline. If I remove remoteapplicationcmdline from the signscope, I can't specify any parameters.

This is the same question asked by Chupkb on Technet.

I might be able to do as Naraen suggested on this question, but before I do that I'm hoping there is a simpler way.


Solution

  • The route I eventually took was to gather the command line arguments from a previous page (perhaps a login page) and then on the next page I dynamically create an rdp file, sign it, and embed the contents into the javascript on the html page. The code below is ASP.NET and c# but it should be a good starting point for other languages as well.

    First, the html (notice the <%= RdpFileContents %> in LaunchRemoteApp():

    <html>
    <head>
        <title>RD Web Access</title>
    
        <script type="text/javascript" language="javascript">
            var g_workspace = null;
    
            var workspaceID = "[RemoteAppMachineName]";
            var domainUserName = "[RemoteAppMachineName]\\[RemoteAppUserName]";
    
            // This is the certificate's thumbprint.
            var rdpCertificates = "04b83503a710cad89f25d3e15a48245f490773c4";
            var machineType = "public";
    
            function onAutoDisconnect() {
                var workspace = null;
    
                if (workspaceID != null && workspaceID != "") {
                    try {
                        workspace = GetWorkspaceObject();
                        workspace.ClearWorkspaceCredential(workspaceID);
                    }
                    catch (objException) {
                        workspace = null;
                    }
                }
            }
    
            function onUserDisconnect() {
                var workspace = null;
    
                try {
                    workspace = GetWorkspaceObject();
                    workspace.DisconnectWorkspace(workspaceID);
                }
                catch (objException) {
                    workspace = null;
                }
            }
    
            function onAuthenticated() {
                var workspace = null;
                var isOnAuthenticatedCalled = false;
    
                if (workspaceID != null && workspaceID != "") {
                    try {
                        workspace = GetWorkspaceObject();
                        workspace.StartWorkspace(workspaceID, domainUserName, password, rdpCertificates, 1200000, 0);
    
                        var countUnauthenticatedCredentials = true;
                        var isWorkspaceCredentialSpecified = workspace.IsWorkspaceCredentialSpecified(workspaceID, countUnauthenticatedCredentials);
    
                        if (isWorkspaceCredentialSpecified) {
                            isOnAuthenticatedCalled = true;
                            workspace.OnAuthenticated(workspaceID, domainUserName);
                        }
    
                        setTimeout("onAutoDisconnect()", 1200000);
                    }
                    catch (objException) {
                        workspace = null;
                        var errorCode = (objException.number & 0xFFFF);
    
                        if (isOnAuthenticatedCalled) {
                            if (errorCode == 183) { 
                                // 183 = ERROR_ALREADY_EXISTS.
                            }
                            else if (errorCode == 1168) { 
                                // 1168 = ERROR_NOT_FOUND.
                            }
                        }
                    }
                }
            }
    
            function GetWorkspaceObject() {
                var objClientShell = null;
    
                if (g_workspace == null) {
                    objClientShell = new ActiveXObject("MsRdpWebAccess.MsRdpClientShell");
                    g_workspace = objClientShell.MsRdpWorkspace;
                }
    
                return g_workspace;
            }
    
            function LaunchRemoteApp() {
                var msRdpClientShell = document.all.MsRdpClient;
    
                msRdpClientShell.PublicMode = true;
                msRdpClientShell.RdpFileContents = <%= RDPContents %>;
    
                try {
                msRdpClientShell.Launch();
                }
                catch (e) {
                   throw e;
                }
            }
        </script>
    </head>
    <body onload="onAuthenticated();">
        <form name="form1" method="post" action="default.aspx" id="form1">
            <object name="MsRdpClient" width="0" height="0" id="MsRdpClient" classid="CLSID:6A5B0C7C-5CCB-4F10-A043-B8DE007E1952" type="application/x-oleobject"></object>
            <a href="javascript:LaunchRemoteApp();">YourAppName</a>
        </form>
    </body>
    </html>
    

    Then I created a template RDP file with all the correct content. Notice the remoteapplicationcmdline value has some dummy command line parameters (FirstName, LastName, CustomerID). You'll replace these as appropriate in your code.

    redirectclipboard:i:0
    redirectposdevices:i:0
    redirectprinters:i:0
    redirectcomports:i:0
    redirectsmartcards:i:0
    devicestoredirect:s:
    drivestoredirect:s:
    redirectdrives:i:0
    session bpp:i:32
    prompt for credentials:i:0
    span monitors:i:0
    use multimon:i:0
    remoteapplicationmode:i:1
    server port:i:3389
    allow font smoothing:i:1
    promptcredentialonce:i:1
    authentication level:i:2
    gatewayusagemethod:i:2
    gatewayprofileusagemethod:i:0
    gatewaycredentialssource:i:0
    full address:s:[RemoteAppMachineName]
    alternate shell:s:||[YourAppName]
    remoteapplicationprogram:s:||[YourAppName]
    gatewayhostname:s:
    remoteapplicationname:s:[YourAppName]
    remoteapplicationcmdline:s:/FirstName:{0} /LastName:{1} /CustomerID:{2}
    Workspace Id:s:[RemoteAppMachineName]
    

    Then in the code behind, I load the template rdp file, replace the command line arguments, write to a temp rdp file, sign the temp rdp file, and embed the resulting contents into the javascript at <%= RdpFileContents %>

    private string GetRDPContents()
    {
        FileInfo fileInfo = new FileInfo(Path.Combine(Server.MapPath("~"), "Template.rdp"));
    
        string[] unsignedRDPContents = File.ReadAllLines(fileInfo.FullName);
    
        for (int i = 0; i < unsignedRDPContents.Length; i++)
        {
            if (unsignedRDPContents[i].IndexOf("remoteapplicationcmdline") != -1)
            unsignedRDPContents[i] = String.Format(unsignedRDPContents[i], FirstName, LastName, CustomerID);
        }
    
        string tempFileName = Path.Combine(Server.MapPath("~"), Guid.NewGuid().ToString() + ".rdp");
        File.WriteAllLines(tempFileName, unsignedRDPContents);
    
        InvokeRDPSign(tempFileName, certificateThumbprint);
    
        string[] signedRDPContents = File.ReadAllLines(tempFileName);
    
        File.Delete(tempFileName);
    
        // This escape function is identical to the javascript escape function.
        return String.Format("unescape('{0}')", Microsoft.JScript.GlobalObject.escape(String.Join("\r\n", signedRDPContents)));
    }
    
    // This is the certificate's thumbprint.
    private const string certificateThumbprint = "04a85503a810cad89f25d3f14c48245f499773c4";
    private void InvokeRDPSign(string fileName, string certificateThumbPrint)
    {
        Process rdpSign = new Process();
        rdpSign.StartInfo.FileName = "rdpsign.exe";
    
        rdpSign.StartInfo.Arguments = String.Format("/sha1 {0} \"{1}\"", certificateThumbPrint, fileName);
        rdpSign.StartInfo.UseShellExecute = false;
        rdpSign.StartInfo.RedirectStandardOutput = true;
        rdpSign.StartInfo.RedirectStandardInput = true;
        rdpSign.StartInfo.RedirectStandardError = true;
    
        rdpSign.StartInfo.WorkingDirectory = Server.MapPath("~");
        rdpSign.Start();
    
        string signingOutput = rdpSign.StandardOutput.ReadToEnd();
        rdpSign.WaitForExit();
        int exitCode = rdpSign.ExitCode;
    }
    

    The final javascript will look something like this:

    function LaunchRemoteApp() {
        var msRdpClientShell = document.all.MsRdpClient;
    
        msRdpClientShell.PublicMode = true;
        msRdpClientShell.RdpFileContents = unescape('redirectclipboard%3Ai%3A0%0D%0A%0D%0Aredirectposdevices%3Ai%3A0%0D%0A%0D%0Aredirectprinters%3Ai%3A0%0D%0A%0D%0Aredirectcomports%3Ai%3A0%0D%0A%0D%0Aredirectsmartcards%3Ai%3A0%0D%0A%0D%0Adevicestoredirect%3As%3A%0D%0A%0D%0Adrivestoredirect%3As%3A%0D%0A%0D%0Aredirectdrives%3Ai%3A0%0D%0A%0D%0Asession%20bpp%3Ai%3A32%0D%0A%0D%0Aprompt%20for%20credentials%3Ai%3A0%0D%0A%0D%0Aspan%20monitors%3Ai%3A0%0D%0A%0D%0Ause%20multimon%3Ai%3A0%0D%0A%0D%0Aremoteapplicationmode%3Ai%3A1%0D%0A%0D%0Aserver%20port%3Ai%3A3389%0D%0A%0D%0Aallow%20font%20smoothing%3Ai%3A1%0D%0A%0D%0Apromptcredentialonce%3Ai%3A1%0D%0A%0D%0Aauthentication%20level%3Ai%3A2%0D%0A%0D%0Agatewayusagemethod%3Ai%3A2%0D%0A%0D%0Agatewayprofileusagemethod%3Ai%3A0%0D%0A%0D%0Agatewaycredentialssource%3Ai%3A0%0D%0A%0D%0Afull%20address%3As%3A[YourMachineName]%0D%0A%0D%0Aalternate%20shell%3As%3A%7C%7C[YourAppName]%0D%0A%0D%0Aremoteapplicationprogram%3As%3A%7C%7C[YourAppName]%0D%0A%0D%0Agatewayhostname%3As%3A%0D%0A%0D%0Aremoteapplicationname%3As%3A[YourAppName]%0D%0A%0D%0Aremoteapplicationcmdline%3As%3A/FirstName%3AJon%20/LastName%3ADoe%20/CustomerID%3A7921385%0D%0A%0D%0Aworkspace%20id%3As%3A[YourMachineName]%0D%0A%0D%0Aalternate%20full%20address%3As%3A[YourMachineName]%0D%0A%0D%0Asignscope%3As%3AFull%20Address%2CAlternate%20Full%20Address%2CServer%20Port%2CGatewayHostname%2CGatewayUsageMethod%2CGatewayProfileUsageMethod%2CGatewayCredentialsSource%2CPromptCredentialOnce%2CAlternate%20Shell%2CRemoteApplicationProgram%2CRemoteApplicationMode%2CRemoteApplicationName%2CRemoteApplicationCmdLine%2CPrompt%20For%20Credentials%2CAuthentication%20Level%2CRedirectDrives%2CRedirectPrinters%2CRedirectCOMPorts%2CRedirectSmartCards%2CRedirectPOSDevices%2CRedirectClipboard%2CDevicesToRedirect%2CDrivesToRedirect%0D%0A%0D%0Asignature%3As%3AAQABAAEAAADgEgAAMIIS3AYJKoZIhvcNAQcCoIISzTCCEskCAQExCzAJBgUrDgMC%20%20GgUAMAsGCSqGSIb3DQEHAaCCEQMwggPFMIICraADAgECAhACrFwmagtAm48LefKu%20%20RiV3MA0GCSqGSIb3DQEBBQUAMGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp%20%20Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xKzApBgNVBAMTIkRp%20%20Z2lDZXJ0IEhpZ2ggQXNzdXJhbmNlIEVWIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAw%20%20WhcNMzExMTEwMDAwMDAwWjBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl%20%20cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdp%20%20Q2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMIIBIjANBgkqhkiG9w0BAQEF%20%20AAOCAQ8AMIIBCgKCAQEAxszlc+b71LvlLS0ypt/lgT/JzSVJtnEqw9WUNGeiChyw%20%20X2mmQLHEt7KP0JikqUFZOtPclNY823Q4pErMTSWC90qlUxI47vNJbXGRfmO2q6Zf%20%20w6SE+E9iUb74xezbOJLjBuUIkQzEKEFV+8taiRV+ceg1v01yCT2+OjhQW3cxG42z%20%20xyRFmqesbQAUWgS3uhPrUQqYQUEiTmVhh4FBUKZ5XIneGUpX1S7mXRxTLH6YzRoG%20%20FqRoc9A0BBNcoXHTWnxV215k4TeHMFYE5RG0KYAS8Xk5iKICEXwnZreIt3jyygqo%20%20OKsKZMK/Zl2VhMGhJR6HXRpQCyASzEG7bgtROLhLywIDAQABo2MwYTAOBgNVHQ8B%20%20Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUsT7DaQP4v0cB1Jgm%20%20GggC72NkK8MwHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDQYJKoZI%20%20hvcNAQEFBQADggEBABwaBpfc15yfPIhmBghXIdshR/gqZ6q/GDJ2QBBXwYrzetkR%20%20ZY41+p78RbWe2UwxS7iR6EMsjrN4ztvjU3lx1uUhlAHaVYeaJGT2imbM3pw3zag0%20%20sWmbI8ieeCIrcEPjVUcxYRnvWMWFL04w9qAxFiPI5+JlFjPLvxoboD34yl6LMYtg%20%20CIktDAZcUrfE+QqY0RVfnxK+fDZjOL1EpH/kJisKxJdpDemM4sAQV7jIdhKRVfJI%20%20adi8KgJbD0TUIDHb9LpwJl2QYJ68SxcJL7TLHkNoyQcnwdJc9+ohuWgSnDycv578%20%20gFybY83sR6olJ2egN/MAgn1U16n46S4To3foH0owggZYMIIFQKADAgECAhAKXxFN%20%20A1sXkRfS79QDjD87MA0GCSqGSIb3DQEBBQUAMGwxCzAJBgNVBAYTAlVTMRUwEwYD%20%20VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xKzAp%20%20BgNVBAMTIkRpZ2lDZXJ0IEhpZ2ggQXNzdXJhbmNlIEVWIFJvb3QgQ0EwHhcNMDgw%20%20NDAyMTIwMDAwWhcNMjIwNDAzMDAwMDAwWjBmMQswCQYDVQQGEwJVUzEVMBMGA1UE%20%20ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSUwIwYD%20%20VQQDExxEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBDQS0zMIIBIjANBgkqhkiG9w0B%20%20AQEFAAOCAQ8AMIIBCgKCAQEAv2EKKRAfXv40N1EI+B77Iu1hvgsNcExQYyZ1FblB%20%20iJe28KAVuwhg4ELoBSkQhzaKKGWo7zEHdG02ly8oRmYExyp5JnqZ1Y7DbU+gXq28%20%20PZHCWXteNmzAU88ACDI+EGRYEBNpxwzunEJRAPkFRO4kznof7YwRvRKo8xX0HHox%20%20aQEbp+ZdwJpsfgme51JEShA6I+SbtgOvqJy0W5/US62SjM61ESqqNxiNtMK42FwG%20%20jPj/I701XtR8Pn6DDpGWBZjDsh/jyGXrqXtdoCzM/DzZbe3M+ktDjMnUuKVhHLJA%20%20tigS37n4X/7TssnvPbQeS3wcTJk2nj3r7KdoXh3fZ25e+wIDAQABo4IC+jCCAvYw%20%20DgYDVR0PAQH/BAQDAgGGMIIBxgYDVR0gBIIBvTCCAbkwggG1BgtghkgBhv1sAQMA%20%20AjCCAaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1j%20%20cHMtcmVwb3NpdG9yeS5odG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAA%20%20dQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAA%20%20YwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8A%20%20ZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4A%20%20ZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUA%20%20ZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwA%20%20aQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQA%20%20IABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wEgYDVR0T%20%20AQH/BAgwBgEB/wIBADA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6%20%20Ly9vY3NwLmRpZ2ljZXJ0LmNvbTCBjwYDVR0fBIGHMIGEMECgPqA8hjpodHRwOi8v%20%20Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0Eu%20%20Y3JsMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdo%20%20QXNzdXJhbmNlRVZSb290Q0EuY3JsMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoI%20%20Au9jZCvDMB0GA1UdDgQWBBRQ6nOJ2yn7EI+e5QEg1N55mUiD9zANBgkqhkiG9w0B%20%20AQUFAAOCAQEAHuKlSJ5s21M4D++mGiqs4gND7Zq8Po51G/D9LiJZrBPAYeLn+umZ%20%20zYcJdVQov0Zg3L5RLJLzG5F8MQhw4je5wVuovaMLAPsaFf0DrVhqxcckmUhHRjEe%20%20ku+0X040x5C/McH4sYSG0JwBqt+KVgbOOukOrpd0XddxmkJ0X96NQ3ze6VXtaQDL%20%20BeB6YWEz0RlN+QjuoDnFJTW3K8QPst3xpbcOJMQmKI15d/Uv8Fe6fAfU4fzNWjBX%20%20foYQR90xH9f8osK/MHxdJKro+a5fanTCzmuzRtghvinUjl4V1kJK5zJvpLFrUYNY%20%20vj9tx/vaAyHLahYZTgrwrYTKXZSzWnb3YTCCBtowggXCoAMCAQICEA8mTuUj65Gh%20%20pZUfZncYkKUwDQYJKoZIhvcNAQEFBQAwZjELMAkGA1UEBhMCVVMxFTATBgNVBAoT%20%20DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTElMCMGA1UE%20%20AxMcRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2UgQ0EtMzAeFw0xMjAxMTEwMDAwMDBa%20%20Fw0xMzAxMTUxMjAwMDBaMIGBMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFjAU%20%20BgNVBAcTDUFtZXJpY2FuIEZvcmsxFzAVBgNVBAoTDkNlcnRpcG9ydCwgSW5jMQ8w%20%20DQYDVQQLEwZJVCBPcHMxIzAhBgNVBAMTGnd3dy5jZXJ0aXBvcnRzb2x1dGlvbnMu%20%20bmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnVQMQG4UrUIHOrLi%20%20dl4tk3n+WJ5qYt7L9uW0qqGjLN2m7G0hJ8kFiuzBzZJ+HwuSV1SMomBBPR3pdZP6%20%205w/41+Che1Mo1yw5eu3L8UgANSFsUaRw+3DZesCxnWOsW1AZB2lQ7fxfQH3ZZZiA%20%20/ONBIiWBNEos8rZk/Rme+mN0LwrzpQJMCoQCJqFCuix9w4ZXC9qRX72BkWNJGRHt%20%20pnhYIePkuSDN3mrK8SWuU3FMX6aHe0rDr/81skzFptPJXWcarjYF3nNgvlY5luPw%20%20iKZwj/viVtYa3m8ClkgCBJSwjNIMjRsmVuKA2fqrxnnfikwXszzDp4Jwpmt4pRJF%20%200RlspQIDAQABo4IDZjCCA2IwHwYDVR0jBBgwFoAUUOpzidsp+xCPnuUBINTeeZlI%20%20g/cwHQYDVR0OBBYEFMfKlt05WQQBtb5oJ/hY81x2XkznMD0GA1UdEQQ2MDSCGnd3%20%20dy5jZXJ0aXBvcnRzb2x1dGlvbnMubmV0ghZjZXJ0aXBvcnRzb2x1dGlvbnMubmV0%20%20MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw%20%20XwYDVR0fBFgwVjApoCegJYYjaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL2NhMy1n%20%20My5jcmwwKaAnoCWGI2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9jYTMtZzMuY3Js%20%20MIIBxAYDVR0gBIIBuzCCAbcwggGzBglghkgBhv1sAQEwggGkMDoGCCsGAQUFBwIB%20%20Fi5odHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRt%20%20MIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABo%20%20AGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0%20%20AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBn%20%20AGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBs%20%20AHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABp%20%20AGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABh%20%20AHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABi%20%20AHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMHsGCCsGAQUFBwEBBG8wbTAkBggrBgEF%20%20BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEUGCCsGAQUFBzAChjlodHRw%20%20Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlQ0Et%20%20My5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQUFAAOCAQEAS0sxic3EpcQ/%20%20p8ROF68Y6jpAb8RzESB5vN2YJgEljSBf53wQ090F+c8+VMZfFEw2jlsILu6vHTlw%20%20LC6ZPvwn9DvBvEAF3KZHe0Hv+2SFgdK8UgCSc2qgS8Kry/F/TlzSCe2fBjRPMwzg%20%20FdSd62d5QmneyaJ4bjyA+leyl+aLAUke4XLJM1qiPPmOE+R2Pb/97XADUW4kdbGt%20%207bvAsacHW0XQSgyU4w3QozSw0ot88y9lM2tWX9XtffTNsAW8GiGDR2q94ZzGulxn%20%20VMk1usccLy4rtzDs66y1NZjm8bknYdEOWhsod+A/4HGHgL/Z3febiyhTaIyp9hMY%20%20x0xLArDbcjGCAaEwggGdAgEBMHowZjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERp%20%20Z2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTElMCMGA1UEAxMc%20%20RGlnaUNlcnQgSGlnaCBBc3N1cmFuY2UgQ0EtMwIQDyZO5SPrkaGllR9mdxiQpTAJ%20%20BgUrDgMCGgUAMA0GCSqGSIb3DQEBAQUABIIBAJGNkWq+QeMYRPJZG3+Kwen96uy3%20%208V+6iE5pnGAFzrBPuN1BhvmkhiSDKLcT4ZSI07PNAsuZFLFz7g8yAuVWyWkfCJkn%20%20TAzj7kFCZBUP82ousA+Pp0VMdmfKjKfqOlJKPMpNJ6AKSHT1aAw4N2ZuzhnddZ/I%20%20HzrOoIJ9McvrMzGQSmhA4MefBg1ppqbudo1QCvVfOdwWg5KijHKIkVOe9BI8Dyic%20%20+cLu3iJ1jF3IMwMQb2Q4JX/FgIFMy9Hf12uhx9HP0JnR2sp5AnwfAGqPj2RSCmoA%20%20Px1XJxuea7WjMBnfTCUuQjuD/hfYdyTmj95G2nuZZM2Za4438JWPMPMW5ro%3D%20%20%0D%0A');
    
        try {
            msRdpClientShell.Launch();
        }
        catch (e) {
            throw e;
        }
    }
    

    I tried to escape the rdp contents myself but could never get it to work. If you don't have access to Microsoft.JScript.GlobalObject.escape() function, you can try it yourself. Here are some of the character entity references I know of:

    Replace : with %3A
    Replace | with %7C
    Replace \r\n with %0D%0A
    Replace spaces with %20
    No extra spaces after lines.