I recently began a project which involved installing a .msi package on approximately 450 computers. The organization previously implemented projects like this by visiting each desktop, but I suggested AD group policy instead. For a number of reasons, I needed to implement the GPO on the computer node, but there were two main problems: I had a list of user accounts but not computers, and I needed to move the PCs from the Computers OU to the new OU that was linked with my software distribution GPO.
The first step was to start capturing which PCs were tied to my list of known users. I created a *simple* logon script that captured the user name and the computer name, and wrote that to a log file:
REM collect user name and computer name
echo %username%,%computername% >> \\servername\sharename\userpclog.txt
After about a month, I had 3500 entries. I imported the file into SQL Server, and then created a View to give me my PC-to-user list. There were 450 computers for 398 users (some users such as interns, temp staff, etc. use any available PC). I did not have info on 28 users but that I could deal with.
Move Active Directory Objects
The basic process for moving the PC from one OU to another is to create a connection to the database, get the list of PC names, then loop through the dataset and create a new
DirectoryEntry instance with the current record as the Common Name (CN) in the LDAP path.
First, create a new console application in Visual Studio 2005. You will need to add references to
System.Data. By default, you will have a file called Program.cs. Replace the contents of that file with the code below, and replace the connection to the database, command string, and LDAP paths as needed.
static void Main(string args)
string m_movetopath = "LDAP://OU=newtestou," +
DirectoryEntry DeMoveTo = new DirectoryEntry(m_movetopath);
string ConnectionString = "server=myservername;
string CommandString = "SELECT computername FROM vwUserpc";
SqlDataAdapter sda = new SqlDataAdapter(CommandString,
DataSet ds = new DataSet();
DataTable dt = ds.Tables;
foreach (DataRow dr in dt.Rows)
string pc = (string)dr["computername"].ToString();
string MovePath = "LDAP://CN=" + pc +
DirectoryEntry DeMoveFrom = new DirectoryEntry(MovePath);
catch (Exception ex)
One thing that is fairly important to note is that I am a domain admin, so creating the
DirectoryEntry instances works "without" security; otherwise, you will need to add the security parameters.
The code may seem pretty straightforward, yet I could not find any examples like this. So, I am writing it up for future reference. I hope you find it useful.
Note: Part of this project also involved scripting an ODBC connection in the registry. These scripts are included in the source files.