Wednesday, October 15, 2008

Migrating your users to a new server

Recently I have been working on migrating Windows servers from Win2K to Win2K3. During our adventure we have across the usual issues that you would expect during a migration. So far these have been quickly addressed and fixes documented. Unfortunately migrating Offline Files in a seamless manner has not been as easy to to overcome.

After much hair pulling and googling I found enough information to put together a solution that is working for us. Since I have had the benefit of the knowledge of so many others on the Internets I thought I'd post my findings for your perusal.

Before I begin let me start by saying if this does not work for you or it breaks something you are on your own.

If you are here you may not know that Microsoft actually provides a tool for this purpose. It is in the Win2K3 Resource Kit and is called CSCCMD.EXE. If you have it, good for you! It's crap. But there is a new and improved version that is mentioned in this 2 year old article. From a scripting standpoint it isn't much better but it will have to do. If you checked out the KB article you will also notice that you have to call them to get it. Apparently two years isn't long enough to test it sufficiently. If you search the Internet via Google you will find it (or call them). You will need it for this to work. You will also need KIXTART. I wrote the script in KIXTART so I could add it to a login script. It should be easy to port to the scripting language of your choice. If you are running Vista then you don't need to do any of this since you can now manipulate it with WMI. You can find a VBScript to do that here.

The script expects CSCCMD.EXE to be in the path.

Below is the code. Good Luck!


;Function MigOfflineFiles()
;
;Author Mark Melanson
;
;Contributors
;
;Action Repoints the Offline Files cache to another server
;
;Assumptions Old share and new share are the same name
;
;Syntax MigOfflineFiles("ServerOld", "ServerNew")
;
;Version 2.3
;
;Date 03-07-2008
;
;Date Revised 03-13-2008
;
;Revision Reason Added error checking and return codes
; Added logging of FAILURES ONLY
; Removed dependency on Temp files by using the WSHPipe UDF
; Fixed error checking in log creation
; Changed some variable names
; Restructured code to move If statement into SELECT CASE
; Restructured return codes
;
;Remarks Tested on 2000/XP
;
;Returns 0 - Offline Files are DISABLED
; 1 - NOTHING TO DO (Targeted Server not found to be configured on the client)
; 2 - ALL Targeted Offline Files were repointed successfully
; 3 - SOME Targeted Offline Files were repointed successfully
; Check the log for what failed at: $Temp\@UserID_OfflineFail.log
; 4 - NONE of the Targeted Offline Files were repointed successfully
; Check the log for what failed at: $Temp\@UserID_OfflineFail.log
; 5 - SOME Targeted Offline Files were repointed successfully
; Log Creation FAILED
; 6 - NONE of the Targeted Offline Files were repointed successfully
; Log Creation FAILED
; 7 - UNKNOWN ERROR
;
;Dependencies KiXtart v4.53
; WSHPipe KIXTART UDF
; Microsoft CSCCMD.EXE v1.1 - http://support.microsoft.com/kb/884739
;
;License: Creative Commons Attribution 3.0 United States
; http://creativecommons.org/licenses/by/3.0/us/
;
;Source


Function MigOfflineFiles($OldSrv, $NewSrv)
Dim $Temp, $Index, $CSCSrvShr, $CSCSrv, $CSCShr, $NUL, $RetCode
Dim $MigFail, $MigSuccess, $MigStat, $LogStat, $WinDir, $x, $Result
DIM $KeyName[2] ; Note : declaration of an array of 3 elements.
$MigOfflineFiles = ""
$Temp = EXPANDENVIRONMENTVARS ("%TEMP%")

; Is Offline Files enabled?
$RetCode = WSHPipe("csccmd /IsEnabled",1)
If UCase($RetCode[0]) = "DISABLED"
; Return 0 to indicate Offline Files is not enabled
$MigOfflineFiles = 0
; Exit Function
Exit 0
EndIf

$LogStat = 0
$MigStat = ""
$Index = 0
Do
; enumerate the CSC Shares
$KeyName = ENUMKEY("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\NetCache\Shares\", $Index)
If @ERROR = 0
; parse the server and share
$CSCSrvShr = Split(UCase($KeyName),"/",-1)
$CSCSrv = $CSCSrvShr[2]
$CSCShr = $CSCSrvShr[3]
; Are we pointing at the old server?
If $CSCSrv = UCASE($OldSrv)
$RetCode = ""
$MigStat = 1
$MigFail = "FALSE"
$MigSuccess = "FALSE"
; Run CSCCMD and log failures
$RetCode = WSHPipe("csccmd /MOVESHARE:\\" + $CSCSrv + "\" + $CSCShr + " \\" + $NewSrv + "\" + $CSCShr,1)
$Result = Ucase($RetCode[0])
If UCase($Result) = "THE COMMAND COMPLETED SUCCESSFULLY."
$MigSuccess = 1
; CSCCMD does not cleanup the registry entries (I don't like loose ends)
; Switched to DELTREE as DELKEY did not always work even with no subkeys
$NUL = DELTREE("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\NetCache\Shares\" + $KeyName)
Else
$MigFail = 1
IF Open( 3, $Temp + "\" + @UserID + "_OfflineFail.log", 5 ) = 0
$x = WriteLine( 3 ,@Date + " " + @Time + " " + "\\" + $CSCSrv + "\" + $CSCShr + " \\" + $NewSrv + "\" + $CSCShr + " " + $Result + @CRLF)
If $x <> 0
$LogStat = $LogStat + 1
ENDIF
$NUL = Close(3)
ENDIF
EndIf
EndIf
$Index = $Index + 1
EndIf
Until $KeyName = ""

; Check our return codes
SELECT
; If there was NOTHING TO DO
CASE $Migstat <> 1
; Return 1 to indicate NOTHING TO DO
$MigOfflineFiles = 1
; If the migration had no failures and good logs
CASE $MigFail = "FALSE" AND $MigSuccess = 1
; Return 2 to indicate SUCCESS
; You should reboot the computer for the changes to take effect
$MigOfflineFiles = 2
; If the migration had success and failure and good logs
CASE $MigFail = 1 AND $MigSuccess = 1 AND $LogStat = 0
; Failure log is left at $Temp\@UserID_OfflineFail.log
; Return 3 to indicate SUCCESS and FAILURE
; You should reboot the computer for the changes to take effect
$MigOfflineFiles = 3
; If the migration completely failed and had good logs
CASE $MigFail = 1 AND $MigSuccess = "FALSE" AND $LogStat = 0
; We had one or more failures
; Failure log is left at $Temp\@UserID_OfflineFail.log
; Return 4 to indicate one or more FAILURES
$MigOfflineFiles = 4
; If the migration had success and failure and questionable logs
CASE $MigFail = 1 AND $MigSuccess = 1 AND $LogStat <> 0
; We had one or more failures
; FAILURE LOG WAS NOT CREATED OR IS INCOMPLETE
; Return 5 to indicate SUCCESS and FAILURE
; You should reboot the computer for the changes to take effect
$MigOfflineFiles = 5
; If the migration completely failed and questionable logs
CASE $MigFail = 1 AND $MigSuccess = "FALSE" AND $LogStat <> 0
; We had one or more failures
; FAILURE LOG WAS NOT CREATED OR IS INCOMPLETE
; Return 6 to indicate one or more FAILURES
$MigOfflineFiles = 6
CASE 1
; You should not be here
; UNKNOWN ERROR
$MigOfflineFiles = 7
ENDSELECT
EndFunction