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 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
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 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