Not that this is necessarily a good idea. But after way too much time googling this, I think I'll clear up the fact that it IS possible call the Microsoft RDP client with a username and password parameter.
Now, everyone out there will say, yeah - we know that. You key in the username and password and if you check off the "remember credentials" checkbox it will store that data.
Well the trick is that this data is stored in a place that's not easily accessed -Windows Stored UserNames and Passwords. This area is basically a secured area of windows where passwords are stored for remote connections. You can access this by going Control Panel\User Accounts\Manager your network passwords. Here's a screen snap.

Our management infrastructure tracks this username and password in a seperate secured database, and then when we call MSTSC.exe from our software we want to pass this information. Now, a little more information on how you can pass parameters to MSTSC is in order. When you call MSTSC you can pass as a parameter a .RDP file which contains information about how you want to connect to the remote computer. Same idea as every other document type in Windows, a .RDP file is associated with MSTSC and is used to contain information for that application. Fortunately the .RDP files are basically key value pairs. Check it out...
screen mode id:i:1
desktopwidth:i:1024
desktopheight:i:768
session bpp:i:16
winposstr:s:0,1,526,61,1566,865
full address:s:SomeIpAddress
compression:i:1
keyboardhook:i:2
audiomode:i:0
redirectdrives:i:0
redirectprinters:i:1
redirectcomports:i:0
redirectsmartcards:i:1
displayconnectionbar:i:0
autoreconnection enabled:i:1
alternate shell:s:
shell working directory:s:
disable wallpaper:i:0
disable full window drag:i:1
disable menu anims:i:1
disable themes:i:0
disable cursor setting:i:0
bitmapcachepersistenable:i:1
allow desktop composition:i:1
allow font smoothing:i:0
redirectclipboard:i:1
redirectposdevices:i:0
authentication level:i:2
prompt for credentials:i:0
negotiate security layer:i:1
remoteapplicationmode:i:0
gatewayhostname:s:
gatewayusagemethod:i:4
gatewaycredentialssource:i:4
gatewayprofileusagemethod:i:0
promptcredentialonce:i:1
drivestoredirect:s:
The imporant pieces here is the "full address" line... this points to the server we're connecting to.
Well... it turns out you can also pass parameters for domain, username, and password. You just need to add them to the bottom of your .rdp file like this
domain:s:MyDomain
username:s:MyUserName
password 51:b:MyPassword
But wait a second, saving a password in plain text in a .rdp file sounds like just about the worst security hole you could use! And you're right - you can't actually pass the password parameter as straight text. It needs to be encrypted binary.
(As an aside, that's what the second part of these key/value pairs is... the s, or b, or i character. That indicates whether the data is String, Binary or Integer).
Well it turns out that taking a straight text password and encrypting it ain't too bad. I'm not going to take credit for this code but the following vb dot net code uses the windows api to do just that.
Imports System
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.ComponentModel
Imports Microsoft.VisualBasic
Public Class DPAPI
<DllImport("Crypt32.dll", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)> Private Shared Function CryptProtectData( _
ByRef pPlainText As DATA_BLOB, _
ByVal szDescription As String, _
ByRef pEntropy As DATA_BLOB, _
ByVal pReserved As IntPtr, _
ByRef pPrompt As CRYPTPROTECT_PROMPTSTRUCT, _
ByVal dwFlags As Integer, _
ByRef pCipherText As DATA_BLOB _
) As Boolean
End Function
<DllImport("Crypt32.dll", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)> _
Private Shared Function CryptUnprotectData( _
ByRef pCipherText As DATA_BLOB, _
ByRef pszDescription As String, _
ByRef pEntropy As DATA_BLOB, _
ByVal pReserved As IntPtr, _
ByRef pPrompt As CRYPTPROTECT_PROMPTSTRUCT, _
ByVal dwFlags As Integer, _
ByRef pPlainText As DATA_BLOB _
) As Boolean
End Function
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Friend Structure DATA_BLOB
Public cbData As Integer
Public pbData As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Friend Structure CRYPTPROTECT_PROMPTSTRUCT
Public cbSize As Integer
Public dwPromptFlags As Integer
Public hwndApp As IntPtr
Public szPrompt As String
End Structure
Private Const CRYPTPROTECT_UI_FORBIDDEN As Integer = 1
Private Const CRYPTPROTECT_LOCAL_MACHINE As Integer = 4
Private Shared Sub InitPrompt _
( _
ByRef ps As CRYPTPROTECT_PROMPTSTRUCT _
)
ps.cbSize = Marshal.SizeOf(GetType(CRYPTPROTECT_PROMPTSTRUCT))
ps.dwPromptFlags = 0
ps.hwndApp = IntPtr.Zero
ps.szPrompt = Nothing
End Sub
Private Shared Sub InitBLOB _
( _
ByVal data As Byte(), _
ByRef blob As DATA_BLOB _
)
' Use empty array for null parameter.
If data Is Nothing Then
data = New Byte(0) {}
End If
' Allocate memory for the BLOB data.
blob.pbData = Marshal.AllocHGlobal(data.Length)
' Make sure that memory allocation was successful.
If blob.pbData.Equals(IntPtr.Zero) Then
Throw New Exception( _
"Unable to allocate data buffer for BLOB structure.")
End If
' Specify number of bytes in the BLOB.
blob.cbData = data.Length
Marshal.Copy(data, 0, blob.pbData, data.Length)
End Sub
Public Enum KeyType
UserKey = 1
MachineKey
End Enum
Private Shared defaultKeyType As KeyType = KeyType.UserKey
Public Shared Function Encrypt _
( _
ByVal keyType As KeyType, _
ByVal plainText As String, _
ByVal entropy As String, _
ByVal description As String _
) As String
If plainText Is Nothing Then
plainText = String.Empty
End If
If entropy Is Nothing Then
entropy = String.Empty
End If
Dim result As Byte()
Dim encrypted As String = ""
Dim i As Integer
result = Encrypt(keyType, _
Encoding.Unicode.GetBytes(plainText), _
Encoding.Unicode.GetBytes(entropy), _
description)
For i = 0 To result.Length - 1
encrypted = encrypted & Convert.ToString(result(i), 16).PadLeft(2, "0").ToUpper()
Next
Return encrypted.ToString()
End Function
Public Shared Function Encrypt _
( _
ByVal keyType As KeyType, _
ByVal plainTextBytes As Byte(), _
ByVal entropyBytes As Byte(), _
ByVal description As String _
) As Byte()
If plainTextBytes Is Nothing Then
plainTextBytes = New Byte(0) {}
End If
If entropyBytes Is Nothing Then
entropyBytes = New Byte(0) {}
End If
If description Is Nothing Then
description = String.Empty
End If
Dim plainTextBlob As DATA_BLOB = New DATA_BLOB
Dim cipherTextBlob As DATA_BLOB = New DATA_BLOB
Dim entropyBlob As DATA_BLOB = New DATA_BLOB
Dim prompt As _
CRYPTPROTECT_PROMPTSTRUCT = New CRYPTPROTECT_PROMPTSTRUCT
InitPrompt(prompt)
Try
Try
InitBLOB(plainTextBytes, plainTextBlob)
Catch ex As Exception
Throw New Exception("Cannot initialize plaintext BLOB.", ex)
End Try
Try
InitBLOB(entropyBytes, entropyBlob)
Catch ex As Exception
Throw New Exception("Cannot initialize entropy BLOB.", ex)
End Try
Dim flags As Integer = CRYPTPROTECT_UI_FORBIDDEN
If keyType = keyType.MachineKey Then
flags = flags Or (CRYPTPROTECT_LOCAL_MACHINE)
End If
Dim success As Boolean = CryptProtectData( _
plainTextBlob, _
description, _
entropyBlob, _
IntPtr.Zero, _
prompt, _
flags, _
cipherTextBlob)
If Not success Then
Dim errCode As Integer = Marshal.GetLastWin32Error()
Throw New Exception("CryptProtectData failed.", _
New Win32Exception(errCode))
End If
Dim cipherTextBytes(cipherTextBlob.cbData) As Byte
Marshal.Copy(cipherTextBlob.pbData, cipherTextBytes, 0, _
cipherTextBlob.cbData)
Return cipherTextBytes
Catch ex As Exception
Throw New Exception("DPAPI was unable to encrypt data.", ex)
Finally
If Not (plainTextBlob.pbData.Equals(IntPtr.Zero)) Then
Marshal.FreeHGlobal(plainTextBlob.pbData)
End If
If Not (cipherTextBlob.pbData.Equals(IntPtr.Zero)) Then
Marshal.FreeHGlobal(cipherTextBlob.pbData)
End If
If Not (entropyBlob.pbData.Equals(IntPtr.Zero)) Then
Marshal.FreeHGlobal(entropyBlob.pbData)
End If
End Try
End Function
End Class
Then in our .RDP file generator we just call out to our dot net encryptor like this.
DPAPI.Encrypt(DPAPI.KeyType.MachineKey, "MyPassword", Nothing, "psw")
Now, this is worth stressing again that exposing passwords for RDP clients can be a very dangerous idea. Someone can grab ahold of those and cause all sorts of havoc so your management of these security tools needs to be very well understood. Storage, access, and management of this data is one of the most critical components of your security strategy and anytime your exposing this information you need to be aware of the ramifications of that action.