Skip to main content

Changing what OutlookAnywhere proxy a pc is using remotely via a script

During the course of migrating from one version of Exchange to the another version of Exchange or just moving between servers you might come across the need to shift some of your OultookAnywhere users who are proxying through one CAS server to another without taking the existing CAS server offline and letting autodiscover sort it out. Well i did so here's how you can do it

First of all this script only works if you can connect to the target pc via WMI remotly and access the registry. If this is all good here's what the script needs to do .

First things first is you need to work out the machine name of the PC you want to connect to and the username of the user you want to move. Eg Get-Logonstatitics | select Username,ClientIpAddress should provide that (you may have to use the IISlog files to workout if they are using OutlookAnywhere).

Now we have the hostname orIpAddress of the machine we want to target we now need to work out the SID of the user. Why you ask well where going to be using the Hkey_User key in the registry to make the change so the path to access the users profile setting includes the SID of that user. To work out the SID of the user we take the username and then using ADSI find the AD object and then thanks to a script from Richard Mueller from this ng post we can get the SID from this user object in the format needed to use in the registry path.

Okay great so now we can use WMI to connect to registry Keys that belong to the user we are targeting but which keys do we need to change ? . Thanks to Vinay's script and Oz for his PRF script this helped work out the two entries we are intersted in which are the

RPCProxyServer=PT_UNICODE,0x6622
RPCProxyPrincipalName=PT_UNICODE,0x6625

Now to start glueing this all together I've added some code the first enums all these keys for all profiles for that user and reads those registry entries so the script can specifically target one proxy setting to change (eg only change those values that equal the old proxy server setting) in all profiles. To write the registry entries theres some code the first converts the string you entry for the proxyname into a binary array that can be written to the registry finally this code came out of another script of Sue Mosher's for doing signatures in Outlook.

Okay so to run this script it would look something like this.

cscript changeprx.vbs hostname username oldproxy.com.au newproxy.com.au

I've posted a copy of this script here the script itself looks like

SourceServer = wscript.arguments(2)
TargetServer = wscript.arguments(3)

strComputer = wscript.arguments(0)
strUser = wscript.arguments(1)

set conn = createobject("ADODB.Connection")
set com = createobject("ADODB.Command")
Set iAdRootDSE = GetObject("LDAP://RootDSE")
strNameingContext = iAdRootDSE.Get("defaultNamingContext")
Conn.Provider = "ADsDSOObject"
Conn.Open "ADs Provider"
mbQuery = "<LDAP://" & strNameingContext & ">;(&(objectclass=person)(samaccountname=" & strUser & "));name,distinguishedName;subtree"
Com.ActiveConnection = Conn
Com.CommandText = mbQuery
Set Rs = Com.Execute
While Not Rs.EOF
Userdn = rs.fields("distinguishedName")
wscript.echo Userdn
rs.movenext
Wend
Set objUser = GetObject("LDAP://" & Userdn)
usrsid = ObjSidToStrSid(objUser.objectSid)

wscript.echo "UserSid : " & usrsid

Const HKEY_USERS = &H80000003


Set oReg =GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\default:StdRegProv")

prProxyVal = "001f6622"
crcertVal = "001f6625"

strKeyPath = usrsid & "\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles"

oReg.EnumKey HKEY_USERS, strKeyPath, arrSubKeys

For Each subkey In arrSubKeys
strFullPath = strKeyPath & "\" & subkey & "\13dbb0c8aa05101a9bb000aa002fc45a"
oReg.GetBinaryValue HKEY_USERS,strFullPath,prProxyVal,prProxyValRes
sval = ""
if not IsNull(prProxyValRes) then
For Each byteValue in prProxyValRes
sval = sval & ChrB(byteValue)
Next
if mid(sval,1,len(SourceServer)) = SourceServer then
newarrValue = StringToByteArray(TargetServer, True)
newarrValue2 = StringToByteArray(("msstd:" & TargetServer), True)
oReg.SetBinaryValue HKEY_USERS,strFullPath,prProxyVal,newarrValue
oReg.SetBinaryValue HKEY_USERS,strFullPath,crcertVal,newarrValue2
wscript.echo "Changed : " & sval
end if
end if

Next

Public Function StringToByteArray _
(Data, NeedNullTerminator)
Dim strAll
strAll = StringToHex4(Data)
If NeedNullTerminator Then
strAll = strAll & "0000"
End If
intLen = Len(strAll) \ 2
ReDim arr(intLen - 1)
For i = 1 To Len(strAll) \ 2
arr(i - 1) = CByte _
("&H" & Mid(strAll, (2 * i) - 1, 2))
Next
StringToByteArray = arr
End Function


Public Function StringToHex4(Data)
' Input: normal text
' Output: four-character string for each character,
' e.g. "3204" for lower-case Russian B,
' "6500" for ASCII e
' Output: correct characters
' needs to reverse order of bytes from 0432
Dim strAll
For i = 1 To Len(Data)
' get the four-character hex for each character
strChar = Mid(Data, i, 1)
strTemp = Right("00" & Hex(AscW(strChar)), 4)
strAll = strAll & Right(strTemp, 2) & Left(strTemp, 2)
Next
StringToHex4 = strAll
End Function

Function ArrayToMB(A)
Dim I, MB
For I = LBound(A) To UBound(A)
MB = MB & ChrB(A(I))
Next
ArrayToMB = MB
End Function


Function ObjSidToStrSid(arrSid)
' Function to convert OctetString (byte array) to Decimal string (SDDL)
Dim strHex, strDec

strHex = OctetStrToHexStr(arrSid)
strDec = HexStrToDecStr(strHex)
ObjSidToStrSid = strDec
End Function ' ObjSidToStrSid

Function OctetStrToHexStr(arrbytOctet)
' Function to convert OctetString (byte array) to Hex string.
Dim k

OctetStrToHexStr = ""
For k = 1 To Lenb(arrbytOctet)
OctetStrToHexStr = OctetStrToHexStr _
& Right("0" & Hex(Ascb(Midb(arrbytOctet, k, 1))), 2)
Next
End Function ' OctetStrToHexStr

Function HexStrToDecStr(strSid)
Const BYTES_IN_32BITS = 4
Const SRL_BYTE = 0
Const IAV_START_BYTE = 2
Const IAV_END_BYTE = 7
Const RID_START_BYTE = 8
Const MSB = 3 'Most significant byte
Const LSB = 0 'Least significant byte

Dim arrbytSid, lngTemp, base, offset, i

ReDim arrbytSid(Len(strSid)/2 - 1)

' Convert hex string into integer array
For i = 0 To UBound(arrbytSid)
arrbytSid(i) = CInt("&H" & Mid(strSid, 2 * i + 1, 2))
Next

' Add SRL number
HexStrToDecStr = "S-" & arrbytSid(SRL_BYTE)

' Add Identifier Authority Value
lngTemp = 0
For i = IAV_START_BYTE To IAV_END_BYTE
lngTemp = lngTemp * 256 + arrbytSid(i)
Next
HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)
For base = RID_START_BYTE To UBound(arrbytSid) Step BYTES_IN_32BITS
lngTemp = 0
For offset = MSB to LSB Step -1
lngTemp = lngTemp * 256 + arrbytSid(base + offset)
Next
HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)
Next

End Function ' HexStrToDecStr

Popular posts from this blog

Testing and Sending email via SMTP using Opportunistic TLS and oAuth in Office365 with PowerShell

As well as EWS and Remote PowerShell (RPS) other mail protocols POP3, IMAP and SMTP have had OAuth authentication enabled in Exchange Online (Official announcement here ). A while ago I created  this script that used Opportunistic TLS to perform a Telnet style test against a SMTP server using SMTP AUTH. Now that oAuth authentication has been enabled in office365 I've updated this script to be able to use oAuth instead of SMTP Auth to test against Office365. I've also included a function to actually send a Message. Token Acquisition  To Send a Mail using oAuth you first need to get an Access token from Azure AD there are plenty of ways of doing this in PowerShell. You could use a library like MSAL or ADAL (just google your favoured method) or use a library less approach which I've included with this script . Whatever way you do this you need to make sure that your application registration  https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-

The MailboxConcurrency limit and using Batching in the Microsoft Graph API

If your getting an error such as Application is over its MailboxConcurrency limit while using the Microsoft Graph API this post may help you understand why. Background   The Mailbox  concurrency limit when your using the Graph API is 4 as per https://docs.microsoft.com/en-us/graph/throttling#outlook-service-limits . This is evaluated for each app ID and mailbox combination so this means you can have different apps running under the same credentials and the poor behavior of one won't cause the other to be throttled. If you compared that to EWS you could have up to 27 concurrent connections but they are shared across all apps on a first come first served basis. Batching Batching in the Graph API is a way of combining multiple requests into a single HTTP request. Batching in the Exchange Mail API's EWS and MAPI has been around for a long time and its common, for email Apps to process large numbers of smaller items for a variety of reasons.  Batching in the Graph is limited to a m

How to test SMTP using Opportunistic TLS with Powershell and grab the public certificate a SMTP server is using

Most email services these day employ Opportunistic TLS when trying to send Messages which means that wherever possible the Messages will be encrypted rather then the plain text legacy of SMTP.  This method was defined in RFC 3207 "SMTP Service Extension for Secure SMTP over Transport Layer Security" and  there's a quite a good explanation of Opportunistic TLS on Wikipedia  https://en.wikipedia.org/wiki/Opportunistic_TLS .  This is used for both Server to Server (eg MTA to MTA) and Client to server (Eg a Message client like Outlook which acts as a MSA) the later being generally Authenticated. Basically it allows you to have a normal plain text SMTP conversation that is then upgraded to TLS using the STARTTLS verb. Not all servers will support this verb so if its not supported then a message is just sent as Plain text. TLS relies on PKI certificates and the administrative issue s that come around certificate management like expired certificates which is why I wrote th
All sample scripts and source code is provided by for illustrative purposes only. All examples are untested in different environments and therefore, I cannot guarantee or imply reliability, serviceability, or function of these programs.

All code contained herein is provided to you "AS IS" without any warranties of any kind. The implied warranties of non-infringement, merchantability and fitness for a particular purpose are expressly disclaimed.