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:
- Create ADSI objects for the source and destination servers.
- Loop through the ADSI objects and only looks for groups.
- Note: You could also use an
object.Filterstatement for this.
- You will obviously need to update the server names for your source and destination servers.
- Note: You could also use an
- Compare each group name with the group stub and only process those groups that match the stub.
- By way of explanation, FPSE role groups have names like OWS_nnnnn_xxxxx, where nnnnn is a simple numeric hash that identifies the site, and the xxxxx denotes the individual FPSE role like admin, browser, author, etc.
- The script uses the OWS_nnnnn stub and will copy all of the role groups that it finds. For example: OWS_12345_admin, OWS_12345_author, OWS_12345_browser, etc.
- In the code I used OWS_nnnnn for the stub, so you would have to replace nnnnn with the numbers that you see in the list of groups using Computer Management on the source computer.
- Determine if the group exists on the destination server, and creates it if it doesn't already exist.
- Loop through the list of users in the group on the source server and adds those same users to the group on the destination server.
- Note: This will fail for any local users that were used on the source server that do not exist on the destination server. I only used domain accounts, so I didn't run into that problem.
Some additional notes:
- The person that runs this code must be an administrator on each server.
- The two computers must be on the same network or the ADSI calls will fail.
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.