I ran into one of those strange situations the other day where you feel like you've been doing the same thing on your computer at some time in the distant past - kind of like déjà vu for geeks. In this specific case, I was moving some web sites that I am hosting for other people that still use FPSE from an older physical server to a new virtual server that is hosted through Hyper-V. (I'm also trying to convert them all to WebDAV, but that's another story.)
Anyway, I had dozens of custom FPSE roles set up for each of those sites that I didn't want to manually replicate on the new server. Unfortunately, FPSE doesn't have a way to migrate the roles from one server to another. All of those FPSE-related roles are kept in local groups with cryptic names like OWS_nnnnn_xxxxx, so I started thinking, "If only I could write a script that could migrate the OWS_nnnnn_xxxxx groups between the two servers..."
Then it dawned on me - I had written such a script several years ago! (Now if only I could find it...) Like many people that write code, I'm something of a code packrat - I tend to keep all of my old code around somewhere, just in case. Sparing you the details of my long search, I eventually found the script that I was looking for, and I thought that it would make a nice blog because I'm sure that someone else may need to migrate their FPSE roles.
Here's the script and a brief description of what script it will do:
object.Filter
Some additional notes:
With that in mind, here's the script code:
Option Explicit On Error Resume Next Dim objComputer1, objGroup1 Dim objComputer2, objGroup2 Dim objOBJECT Dim objUSER Dim strGroupName Dim strGroupDesc Const ERROR_SUCCESS = 0 ' Note: update the following server names. Const strComputer1 = "SERVER1" Const strComputer2 = "SERVER2" ' Note: update the following group stub. Const strGroupStub = "OWS_nnnnn" ' ---------------------------------------------------------------------- Set objComputer1 = GetObject("WinNT://" & strComputer1 & ",computer") If CLng(Err.Number) <> ERROR_SUCCESS Then HandleError Set objComputer2 = GetObject("WinNT://" & strComputer2 & ",computer") If CLng(Err.Number) <> ERROR_SUCCESS Then HandleError For Each objOBJECT in objComputer1 If UCase(objOBJECT.Class) = "GROUP" Then strGroupName = objOBJECT.Name If UCase(Left(strGroupName,Len(strGroupStub))) = UCase(strGroupStub) Then Err.Clear : Set objGroup1 = GetObject("WinNT://" & strComputer1 & "/" & strGroupName & ",group") If CLng(Err.Number) <> ERROR_SUCCESS Then HandleError strGroupDesc = objGroup1.Description WScript.Echo "Copying " & strGroupName & "..." Err.Clear : Set objGroup2 = GetObject("WinNT://" & strComputer2 & "/" & strGroupName & ",group") If CLng(Err.Number) <> ERROR_SUCCESS Then If CLng(Err.Number) <> -2147022676 Then HandleError Else Err.Clear : Set objGroup2 = objComputer2.Create("group",strGroupName) If CLng(Err.Number) <> ERROR_SUCCESS Then HandleError Err.Clear : objGroup2.SetInfo If CLng(Err.Number) <> ERROR_SUCCESS Then HandleError Err.Clear : objGroup2.Description = strGroupDesc If CLng(Err.Number) <> ERROR_SUCCESS Then HandleError Err.Clear : objGroup2.SetInfo If CLng(Err.Number) <> ERROR_SUCCESS Then HandleError End If End If For Each objUSER in objGroup1.Members WScript.Echo vbTab & "Adding " & objUSER.Name Err.Clear : objGroup2.Add objUSER.ADsPath If CLng(Err.Number) <> ERROR_SUCCESS And CLng(Err.Number) <> -2147023518 Then HandleError Err.Clear : objGroup2.SetInfo If CLng(Err.Number) <> ERROR_SUCCESS Then HandleError Next Set objGroup1 = Nothing Set objGroup2 = Nothing End If End If Next ' ---------------------------------------------------------------------- Sub HandleError() WScript.Echo vbCrLf & "FATAL ERROR:" WScript.Echo vbTab & "Number: " & CLng(Err.Number) & " (0x" & Hex(CLng(Err.Number)) & ")" WScript.Echo vbTab & "Description: " & Err.Description WScript.Quit End Sub
As usual, all of the normal caveats like "this code is totally unsupported" will apply, but I've used this code with great success on several severs over the years. The great thing about this code is that it's non-destructive because it doesn't delete anything on the source server - it only creates groups on the destination server.
You can also use Const strGroupStub = "OWS_" to migrate all FPSE role groups from one server to another, but that's a major operation. With that in mind, I'd try it out on a single FPSE site using "OWS_nnnnn" as a stub before trying out a full server by using "OWS_" as a stub; the latter is very time-consuming and CPU-intensive.
very interesting article.
If I manage to make it work it could save me hours of work.
Unfortunately I still do not understand how do you link the newly created local groups to the FPex in the target server.
The groups are all there but the ntfs acl of the folders (I migrated the website via IISMT) are still referring to a non-existent GUID.
How can I reestablish the links?
Thanks,
Roberto.
Thanks, Roberto - that's a great question. I should have mentioned earlier that the script simply migrates the FPSE groups so that they are available on the target computer, but does not apply permissions to the physical content. To actually apply the group permissions to the physical content you would need to make some sort of change using the “Microsoft SharePoint Administration” web site, such as opening the site’s administration pages, clicking “Check server health”, checking the “Repair” check box for “Reapply file security settings” and clicking “OK.”
If you are seeing blank GUIDs in your ACLs, did you use some sort of file copy that migrated physical ACLs between two computers? If so, what you are seeing is the remnants of permissions that will not mean anything on the target computer. The physical groups are separate entities as far as Windows permissions are concerned and as such they cannot be physically migrated. The script migrates groups by using the same name, but this is essentially creating new simple copies of the original groups.