Copy NT user accounts between servers

I've created about 50 user accounts on a Windows 2003 Server, and I'd like to copy those accounts to a new server, is this possible? I'm not using Active Directory.

Patrick

Edit 1 : Thanks for the answers, however I should have been more specific in my original question. I'd like to copy the user accounts and maintain the existing passwords. Also, I'd like to copy the accounts between two servers across the internet and firewalls. Is it possible to simply backup and restore user accounts?


Solution 1:

The command "net user" will display a list of all user accounts. If you run this an pipe the output to a file you can then edit the file to convert it to a script to create the accounts of the new server. use "net help user" to see how to create accounts from a batch file. You'll probably have to do some manual tweaking of the accounts after creating them, but it's still a time saver compared to using the GUI.

NB you won't be able to extract the old passwords. If you don't know what your users passwords are you'll have to set them all to some default value then change them one by one.

JR

John's post has just reminded me: there's an applet from MS called AddUsers that helps with this sort of thing. See http://support.microsoft.com/kb/199878 for the details.

Solution 2:

Here's a VBscript program to copy local groups and user accounts from a source computer to a destination computer:

Option Explicit

Dim dictGroupsNotToCreate, dictPropertiesToCopy, dictUsersToIgnore, objNetwork
Dim colSourceGroups, colDestinationGroups, objSourceGroup, objDestinationGroup, objUser
Dim colSourceAccounts, colDestinationAccounts, objSourceUser, objDestinationUser, property

' Debugging
Const DEBUGGING = True

' Source and destination computers
Const SOURCE_COMPUTER = "PC00623"
Const DESTINATION_COMPUTER = "PC00619"

' Password to set on newly create user accounts
Const DEFAULT_PASSWORD = "rh1n0s!!!"

' Constants for comparison of accounts to ignore list
Const MATCH_EXACT = 1
Const MATCH_LEFT = 2

Set dictGroupsNotToCreate = CreateObject("Scripting.Dictionary")
dictGroupsNotToCreate.Add "Administrators", MATCH_EXACT
dictGroupsNotToCreate.Add "Backup Operators", MATCH_EXACT
dictGroupsNotToCreate.Add "Guests", MATCH_EXACT
dictGroupsNotToCreate.Add "Network Configuration Operators", MATCH_EXACT
dictGroupsNotToCreate.Add "Power Users", MATCH_EXACT
dictGroupsNotToCreate.Add "Remote Desktop Users", MATCH_EXACT
dictGroupsNotToCreate.Add "Replicator", MATCH_EXACT
dictGroupsNotToCreate.Add "Users", MATCH_EXACT
dictGroupsNotToCreate.Add "Debugger Users", MATCH_EXACT
dictGroupsNotToCreate.Add "HelpServicesGroup", MATCH_EXACT

' Properties of user accounts to copy
Set dictPropertiesToCopy = CreateObject("Scripting.Dictionary")
dictPropertiesToCopy.Add "Description", True
dictPropertiesToCopy.Add "FullName", True
dictPropertiesToCopy.Add "HomeDirDrive", True
dictPropertiesToCopy.Add "HomeDirectory", True
dictPropertiesToCopy.Add "LoginHours", True
dictPropertiesToCopy.Add "LoginScript", True
dictPropertiesToCopy.Add "Profile", True

' Accounts to ignore during copying
Set dictUsersToIgnore = CreateObject("Scripting.Dictionary")
dictUsersToIgnore.Add "SUPPORT_", MATCH_LEFT
dictUsersToIgnore.Add "IUSR_", MATCH_LEFT
dictUsersToIgnore.Add "IWAM_", MATCH_LEFT
dictUsersToIgnore.Add "Administrator", MATCH_EXACT
dictUsersToIgnore.Add "Guest", MATCH_EXACT
dictUsersToIgnore.Add "HelpAssistant", MATCH_EXACT
dictUsersToIgnore.Add "ASPNET", MATCH_EXACT

' Should this account be ignored
Function IgnoreObject(Name, dictNames)
    Dim strToIgnore

    IgnoreObject = False

    For Each strToIgnore in dictNames

        ' Match Exact
        If (dictNames.Item(strToIgnore) = MATCH_EXACT) and (UCase(Name) = UCase(strToIgnore)) Then
            IgnoreObject = True
            Exit Function
        End If

        ' Match left
        If (dictNames.Item(strToIgnore) = MATCH_LEFT) and (Left(UCase(Name), Len(strToIgnore)) = UCase(strToIgnore)) Then
            IgnoreObject = True
            Exit Function
        End If

    Next' strToIgnore
End Function

Set objNetwork = CreateObject("Wscript.Network")

' Get groups on source computer and loop through them, copying as necessary
Set colSourceGroups = GetObject("WinNT://" & SOURCE_COMPUTER)
Set colDestinationGroups = GetObject("WinNT://" & DESTINATION_COMPUTER)
colSourceGroups.Filter = Array("group")

For Each objSourceGroup in colSourceGroups

    If IgnoreObject(objSourceGroup.Name, dictGroupsNotToCreate) = False then
        If (DEBUGGING) Then WScript.Echo "Creating Group: " & objSourceGroup.Name
        Set objDestinationGroup = colDestinationGroups.Create("group", objSourceGroup.Name)
        objDestinationGroup.Put "Description", objSourceGroup.Get("Description")
        objDestinationGroup.SetInfo
    Else
        If (DEBUGGING) Then WScript.Echo "Ignoring Group: " & objSourceGroup.Name
    End If
Next ' objSourceGroup

' Get accounts on source computer and loop through them, copying as necessary
Set colSourceAccounts = GetObject("WinNT://" & SOURCE_COMPUTER)
set colDestinationAccounts = GetObject("WinNT://" & DESTINATION_COMPUTER)
colSourceAccounts.Filter = Array("user")
For Each objSourceUser In colSourceAccounts

    If IgnoreObject(objSourceUser.Name, dictUsersToIgnore) = False Then
        If (DEBUGGING) Then WScript.Echo "Copying account: " & objSourceUser.Name

        On Error Resume Next

        Set objDestinationUser = colDestinationAccounts.Create("user", objSourceUser.Name)
        objDestinationUser.SetPassword DEFAULT_PASSWORD
        objDestinationUser.SetInfo

        ' Copy properties from source user to destination user
        For Each property in dictPropertiesToCopy
            If (DEBUGGING) then WScript.Echo "   Copying property " & property & " (" &  objSourceUser.Get(property) & ")"
            objDestinationUser.Put property, objSourceUser.Get(property)
            objDestinationUser.SetInfo
        Next ' property

        ' Put user into destination groups
        For Each objSourceGroup In colSourceGroups
            For Each objUser In objSourceGroup.Members
                If UCase(objUser.Name) = Ucase(objSourceUser.Name) Then 
                    If (DEBUGGING) Then WScript.Echo "Adding user " & objSourceUser.Name & " to group " & objSourceGroup.Name
                    Set objDestinationGroup = GetObject("WinNT://" & DESTINATION_COMPUTER & "/" & objSourceGroup.Name & ",group")
                    objDestinationGroup.Add(objDestinationUser.aDSPath)
                Else
                    If (DEBUGGING) Then WScript.Echo "User " & objSourceUser.Name & " is not a member of group " & objSourceGroup.Name
                End If
            Next ' objUser
        Next 'objSourceGroup

    Else
        If (DEBUGGING) Then WScript.Echo "Ignoring account: " & objSourceUser.Name
    End If
Next ' objSourceUser

A quick tour:

  • Set the SOURCE_COMPUTER and DESTINATION_COMPUTER names
  • Set the DEFAULT_PASSWORD (which will be assigned to the newly created user accounts)
  • Add any local group names that should not be created on the destination computer to the dictGroupsNotToCreate list. MATCH_EXACT means that the name of the group is matched exactly. MATCH_LEFT means that only the leftmost portion of the group name will be matched (i.e. imagine that the name match has a "*" after it).
  • Add any local user names that should not be created on the destination computer to the dictUsersToIgnore LIST. MATCH_EXACT and MATCH_LEFT have the same meanings as with the dictGroupsNotToCreate list (i.e. "IUSR_" with MATCH_LEFT means that any user account starting with "IUSR_" will not be created on the destination computer).

You must execute this script with credentials that have rights to create accounts on the destination computer.

The properties copied for user accounts, by default, are listed in the dictPropertiesToCopy list. I chose the most common properties.

The script has been tested fairly well, but I haven't used it in a production environment. It makes NO changes to the source server, so you can run it w/o fear of damaging your source server.

(No, the group population algorith isn't effiicent in the slightest. If that bothers you then you know enough already to re-implement it better... >smile<)