#186063 - 2008-03-08 02:23 PM
Migrate Offline Files to a New Server
|
MarkMelanson
Fresh Scripter
Registered: 2006-10-09
Posts: 24
|
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 the difficulties of 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. I know the code is ugly. KIXTART is not my forte. Suggestions are welcomed to improve it.
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 a 2 year old article (KB884739). 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. 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 at http://blogs.technet.com/filecab/pages/cscrenameitem-vbs.aspx
Links to the stuff you need can be found at http://www.markmelanson.com/migratingyouruserstoanewserver
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.4
;
;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 (NOT backward compatible)
; Fixed condition where registry key was skipped
;
;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)
; Since we deleted the registry key we have to decrement the counter
; to avoid multiple runs to get all the data
$Index = $Index - 1
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
Edited by MarkMelanson (2008-03-13 07:00 PM)
|
Top
|
|
|
|
#186071 - 2008-03-09 06:35 PM
Re: Migrate Offline Files to a New Server
[Re: MarkMelanson]
|
MarkMelanson
Fresh Scripter
Registered: 2006-10-09
Posts: 24
|
I have made some updates but I probably won't get to test it until tomorrow.
Below is what t expect:
;Function MigOfflineFiles()
;
;Author Mark Melanson
;
;Contributors
;
;Action Repoints the Offline Files cache to another server
;
;Syntax MigOfflineFiles("ServerOld", "ServerNew")
;
;Version 1.1 BETA
;
;Date 03-07-2008
;
;Date Revised 03-09-2008
;
;Revision Reason
;
;Remarks Tested on 2000/XP
;
;Returns 0 on Offline Files disabled
; 1 on migration success
; 2 on one or more migration failures, check the log for what failed at:
; $Temp\@UserID_OfflineFail.log
;
;Dependencies KiXtart v4.x, Microsoft CSCCMD.EXE v1.1
; Written and tested with KiXtart v4.53
|
Top
|
|
|
|
#186072 - 2008-03-09 06:59 PM
Re: Migrate Offline Files to a New Server
[Re: MarkMelanson]
|
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
|
Mark,
Couple of quick comments to enhance this a bit...
1. for posting, break your long lines to prevent left/right scrolling. This line is too big even for my 19" widescreen monitor! You can change this one:
$RC = MessageBox(@CRLF + "Your PC MUST be rebooted to ensure that your Offline Files " +
@CRLF + "are configured properly." + @CRLF + @CRLF + "Click OK To Reboot", "Logon Script", 4112)
to
$Msg = @CRLF + "Your PC MUST be rebooted to ensure that your Offline Files "
$Msg = $Msg + @CRLF + "are configured properly." + @CRLF + @CRLF + "Click OK To Reboot"
$RC = MessageBox($Msg , "Logon Script", 4112)
You might be able to take advantage of Kixtart's forgiving nature and simply break the line after the "+" sign. I'm torn between convenience and good coding practice on that, though.
2. "RETURN" is used for Gosub. To exit a function, use "Exit", followed by the exit code. The exit code you return can be examined by the @ERROR macro. If your function succeeds, use "Exit 0", otherwise use "Exit 1" for generic errors, or a more appropriate code if possible.
3. You might want to revisit your return value choices. Since there are three possible return states, you might want to return 1 or 2 for the various success states (Migrate Successful or Disabled), and 0 to indicate error - check @ERROR status. Thus, you can do something like
If MigOffLineFiles(old,new)
'OK!'
Else
@SERROR ?
EndIF
for simple migration tests.
4. Reference the source of the CSCCMD.EXE in the UDF header so someone that downloads the function can later recall where the dependent file is.
When it's done and tested, post it (code only) in the UDF forum. Put any commentary in a secondary post in the same topic, as the topmost posts are replicated to UDF mirror sites.
Looking forward to the finished UDF!
Glenn
_________________________
Actually I am a Rocket Scientist!
|
Top
|
|
|
|
#186083 - 2008-03-10 03:13 PM
Re: Migrate Offline Files to a New Server
[Re: MarkMelanson]
|
MarkMelanson
Fresh Scripter
Registered: 2006-10-09
Posts: 24
|
Hi Glenn,
I think I have it completed. I have not tested the log failures.
Below is the updated code. Give it the once over (again) please.
;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 1.4
;
;Date 03-07-2008
;
;Date Revised 03-10-2008
;
;Revision Reason Added error checking and return codes
; Added logging of FAILURES ONLY
; Updated and REMed Shutdown notification code (You may want to use it)
; Check for files from a previous run and delete
; Removed dependency on Temp files by using the WSHPipe UDF
;
;Remarks Tested on 2000/XP
;
;Returns 0 - ALL Targeted Offline Files were repointed successfully
; 1 - SOME Targeted Offline Files were repointed successfully
; Check the log for what failed at: $Temp\@UserID_OfflineFail.log
; 2 - NONE of the Targeted Offline Files were repointed successfully
; Check the log for what failed at: $Temp\@UserID_OfflineFail.log
; 3 - NOTHING TO DO (Targeted Server not found to be configured on the client)
; 4 - Offline Files are DISABLED
; 5 - NONE of the Targeted Offline Files were repointed successfully
; Log Creation FAILED
; 6 - SOME Targeted Offline Files were repointed successfully
; Log Creation FAILED
;
;
;Dependencies KiXtart v4.x
; WSHPipe KIXTART UDF
; Microsoft CSCCMD.EXE v1.1 - http://support.microsoft.com/kb/884739
; Tested with KiXtart v4.53
;
;License: Creative Commons Attribution 3.0 United States
; http://creativecommons.org/licenses/by/3.0/us/
;
;Source
Function MigOfflineFiles($OldSrv, $NewSrv)
Dim $Temp, $Index, $KeyName, $DrvSrvShr, $DrvSrv, $DrvShr, $NUL, $RetCode, $MigFail, $MigSuccess, $MigStat, $LogStat
$MigOfflineFiles = ""
$Temp = EXPANDENVIRONMENTVARS ("%TEMP%")
; Is Offline Files enabled?
$RetCode = WSHPipe("csccmd /IsEnabled",1)
If UCase($RetCode[0]) = "DISABLED"
; Return 4 to indicate Offline Files is not enabled
$MigOfflineFiles = 4
; Exit Function
Exit 4
EndIf
$MigStat = ""
$Index = 0
:OLoop
; enumerate the CSC Shares
$KeyName = ENUMKEY("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\NetCache\Shares\", $Index)
If @ERROR = 0
If $Index = 0
; CLS
EndIf
; parse the server and share
$DrvSrvShr = Split(UCase($KeyName),"/",-1)
$DrvSrv = $DrvSrvShr[2]
$DrvShr = $DrvSrvShr[3]
; Are we pointing at the old server?
If $DrvSrv = UCASE($OldSrv)
$RetCode = ""
$MigStat = 1
$MigFail = "FALSE"
$MigSuccess = "FALSE"
? "Pointing Offline Files to New Server..."
; Run CSCCMD and log failures
$RetCode = WSHPipe("csccmd /MOVESHARE:\\" + $DrvSrv + "\" + $DrvShr + " \\" + $NewSrv + "\" + $DrvShr,1)
If $RetCode[0] = "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 , \\" + $DrvSrv + "\" + $DrvShr + " \\" + $NewSrv + "\" + $DrvShr + " " + $RetCode[0])
$LogStat = 1
ELSE
$LogStat = "FAIL"
ENDIF
EndIf
EndIf
$Index = $Index + 1
goto OLoop
EndIf
; If there was NOTHING TO DO
If Not $Migstat = 1
; We did not have anything to migrate
; Return 3 to indicate NOTHING TO DO
$MigOfflineFiles = 3
; Exit Function
Exit 3
Endif
; $Msg = @CRLF + "Your PC MUST be rebooted to ensure that your Offline Files "
; $Msg = $Msg + @CRLF + "are configured properly." + @CRLF + @CRLF + "Click OK To Reboot"
SELECT
; If the migration had no failures
CASE $MigFail = "FALSE" AND $MigSuccess = 1
; CLS
; $NUL = MessageBox($Msg , "Logon Script", 4112);
; $NUL = Shutdown("", "System is being rebooted to enable new settings.", 5, 1, 1)
; Return 0 to indicate SUCCESS
$MigOfflineFiles = 0
; If the migration had success and failure and good logs
CASE $MigFail = 1 AND $MigSuccess = 1 AND $LogStat = 1
; CLS
; $NUL = MessageBox($Msg , "Logon Script", 4112);
; $NUL = Shutdown("", "System is being rebooted to enable new settings.", 5, 1, 1)
; Failure log is left at $Temp\@UserID_OfflineFail.log
; Return 1 to indicate SUCCESS and FAILURE
$MigOfflineFiles = 1
; If the migration completely failed but had good logs
CASE $MigFail = 1 AND $MigSuccess = "FALSE" AND $LogStat = 1
; We had one or more failures
; Failure log is left at $Temp\@UserID_OfflineFail.log
; Return 2 to indicate one or more FAILURES
$MigOfflineFiles = 2
; If the migration had success and failure and no logs
CASE $MigFail = 1 AND $MigSuccess = 1 AND $LogStat = "FAIL"
; CLS
; $NUL = MessageBox($Msg , "Logon Script", 4112);
; $NUL = Shutdown("", "System is being rebooted to enable new settings.", 5, 1, 1)
; FAILURE LOG WAS NOT CREATED
; Return 5 to indicate SUCCESS and FAILURE
$MigOfflineFiles = 5
; If the migration completely failed but had no logs
CASE $MigFail = 1 AND $MigSuccess = "FALSE" AND $LogStat = "FAIL"
; We had one or more failures
; FAILURE LOG WAS NOT CREATED
; Return 6 to indicate one or more FAILURES
$MigOfflineFiles = 6
ENDSELECT
EndFunction
|
Top
|
|
|
|
#186090 - 2008-03-10 10:29 PM
Re: Migrate Offline Files to a New Server
[Re: MarkMelanson]
|
NTDOC
Administrator
Registered: 2000-07-28
Posts: 11623
Loc: CA
|
Hi Mark,
Just a few comments (I'll leave Glenn to help with the coding)
KiXtart v4.x Unless you've tested it with KiXtart 4.0, 4.02, 4.22, etc... then I'd enter the version you did test under dependencies.
;License: Creative Commons Attribution 3.0 United States ; http://creativecommons.org/licenses/by/3.0/us/ Though this is not a bad deal I don't think we can accept it as a posted UDF with this license We've never actually used any type of license (probably should have) but have basically used the principal that ALL publicly posted code on the site is free to use in any shape form or manner one wishes to.
:OLoop The use of GOTO and LABELS is considered [old school, out of date] coding practice. Though quite valid to use, we would rather it be coded to prevent it's use especially for a posted UDF.
Though not required you may want to either code for it or make a point that the SERVER names should not contain a UNC path
If wanted the use of HKEY_CURRENT_USER can be shortened to: HKCU
As mentioned about making the UDF silent, I would remove some of the minor items still left in that were not silent such as CLS ? "Pointing Offline Files to New Server..." etc...
I'm not actually sure what's it's official name is but you may want to preload your arrays in case of an invalid read it would abend KiX
$DrvSrvShr = Split(UCase($KeyName),"/",-1)
$DrvSrv = $DrvSrvShr[2]
$DrvShr = $DrvSrvShr[3]
You should also have a CASE1 in case none of your expected results are there in your Select statement.
Good luck and I'll let Glenn carry on from here
.
|
Top
|
|
|
|
Moderator: Glenn Barnas, NTDOC, Arend_, Jochen, Radimus, Allen, ShaneEP, Ruud van Velsen, Mart
|
0 registered
and 515 anonymous users online.
|
|
|