Click here to Skip to main content
15,881,812 members
Articles / Programming Languages / C#

OU Transporter

Rate me:
Please Sign up or sign in to vote.
4.40/5 (5 votes)
1 Nov 200615 min read 34K   292   19  
A simple console utility to export the OU structure from one domain, and import it into another. It may also be used to specify an arbitrary OU structure to be created in any domain.
using System;
using System.DirectoryServices;
using System.IO;
using System.Collections;
 

namespace ActiveDirectorySearch1 {

    // This class reads a file containing an OU structure to be imported.
    // The file lines are read into an ArrayList.  Methods are provided to return the
    // next line or the previous line from the ArrayList.  The class has no
    // knowledge of a file line's syntax or meaning.
    public class OUFile{
	private static ArrayList OULines = new ArrayList(); // complete lines (tabs & name) of OUs to import
	private static int curLineNum = -1;

	// Open the file that contains the OU strucure to be imported
	// and get a StreamReader to it.  Then read all its lines into the ArrayList OULines.
	// Comment and blank lines are skipped.
	public static void OpenOUFile( string fileName) {
	    StreamReader SR = File.OpenText( fileName);
	    string input;
	    while ((input = SR.ReadLine()) != null) {
		if ((input != "") && (input[0] != '#') )	// not a blank line or comment
		    OULines.Add(input);
	    } // while
	    SR.Close();
	    if (OULines.Count == 0) {
		Console.WriteLine( "Error - " + fileName + " is empty.");
		System.Environment.Exit(1);
	    }
	} //OpenOUFile()

	public static string NextLine() {
	    if (curLineNum == OULines.Count -1)
		return null;
	    return (string) OULines[++curLineNum];
	} // NextLine()
	
	public static string PrevLine() {
	    if (curLineNum == 0) {
		Console.WriteLine( "ERROR - attempted to access line number -1.");
		System.Environment.Exit(1);
	    }
	    return (string) OULines[--curLineNum];
	} // PrevLine()
    } // class OUFile



    // All knowledge of AD is confined to this class.
    // This class uses recursive methods to Export an AD's OU structure
    // or IMport an OU structure from a file to the AD.
    public class ADSearch {
	public static string DomainDN;		//example,  DC=Doug,DC=org
	private static string curLine;		//Last line returned by OUFile class

	//Init Class0 and return the Domain as a string
	public static void InitAD() {
	    DirectoryEntry DomainDE = new DirectoryEntry("LDAP://rootDSE");
	    DomainDN = (DomainDE.Properties["defaultNamingContext"])[0].ToString();
	} // InitAD()

	//Given a path to the Parent Container, search for all OUs in the parent (children)
	private static SearchResultCollection SearchOneLevel( string path ) {
	    DirectoryEntry entry = new DirectoryEntry(path );
	    DirectorySearcher mySearcher = new DirectorySearcher(entry);
	    mySearcher.Filter = ("(objectClass=organizationalUnit)");
	    mySearcher.SearchScope = SearchScope.OneLevel; //enum to restrict search
	    return mySearcher.FindAll();
	} // SearchOneLevel()

	// recursively go down OU structure.  The SearchResultCollection level of
	// the pervious level is passed as a parameter.
	private static void OUExport(SearchResultCollection srcCollection, int level) {
	    foreach(SearchResult resEnt in srcCollection) {
		for (int i=level; i>0; i--) Console.Write("\t");
		// get rid of leading "OU=" in Name, just want only the name output.
		Console.WriteLine(resEnt.GetDirectoryEntry().Name.ToString().Remove(0,3));
		OUExport( SearchOneLevel(resEnt.GetDirectoryEntry().Path), level+1);
	    }
	} // OuExport()

	public static void KickoffOUExport() {
	    OUExport( SearchOneLevel( "LDAP://" + DomainDN), 0);
	} // KickoffOUExport()

//	------------------- IMPORTING -------------------

	//return the level of curLine by counting leading tabs
	//spaces are ignored.
	private static int GetLineLevel() {
	    int lvl = 0;
	    int i = 0;
	    while ((curLine[i] == ' ') || (curLine[i] == '\t') ) {
		if (curLine[i] == '\t') lvl++;
		i++;
	    }
	    return lvl;
	}

	//return only the OU name in curLine by deleting leading
	// and trailing white space.
	private static string GetLineName() {
	    return curLine.Trim();
	}

	// Creates an OU if it does not already exist
	private static void OUCreate ( string p_curLvlPath, string OUName) {
	    // Do nothing if OU already exists.
	    if (DirectoryEntry.Exists("LDAP://OU=" + OUName + "," + p_curLvlPath) )
	        return; // outta here.
	    //Verify that parent container exists so you can create a child
	    if (!DirectoryEntry.Exists("LDAP://" + p_curLvlPath)) {
		Console.WriteLine( "ERROR - parent container for new OU does not exist.");
		Console.WriteLine( "        parent: " + p_curLvlPath);
		System.Environment.Exit(1);
	    } //parent does not exist
	    DirectoryEntry curDE = new DirectoryEntry( "LDAP://" + p_curLvlPath);
	    DirectoryEntries children = curDE.Children;
	    DirectoryEntry OUDE = children.Add( "OU="+OUName, "organizationalUnit");
	    OUDE.CommitChanges();
	    Console.WriteLine( OUName + " created.");
	} // OUCreate
	    
	//p_curLvl is level of parent, p_curLvlPath is parent's path
	//started at (0, domain) so there is no real parent when started.
	public static void OUImport( int p_curLvl, string p_curLvlPath) {
	    int lvl;
	    while ( (curLine = OUFile.NextLine()) != null ) {
		lvl = GetLineLevel();	// The level for the new OU
		if (lvl == p_curLvl) {
		    OUCreate( p_curLvlPath, GetLineName() );
		}
		else if (lvl > p_curLvl) {
		    curLine = OUFile.PrevLine();
		    string newPath = "OU=" + GetLineName() + "," + p_curLvlPath;
		    OUImport( p_curLvl+1, newPath);
		}
		else {
		    int commaIndex = p_curLvlPath.IndexOf(",");
		    string newPath = p_curLvlPath.Remove(0,commaIndex+1);
		    curLine = OUFile.PrevLine();
		    OUImport( p_curLvl-1, newPath);
		}
	    } //while NextLine()
	} // OUImport()
    } // ADSearch



    class MainProg {
	static void Main (string[] args) {
	    Console.WriteLine("#OUTransport Version 0.0");

	    ADSearch.InitAD(); //

	    if (args.Length == 0) {
		Console.WriteLine("#Exporting from domain: " + ADSearch.DomainDN);
		ADSearch.KickoffOUExport( );
	    }
	    else {
		Console.WriteLine( "#Importing from file: " + args[0]);
		OUFile.OpenOUFile( args[0]);
		ADSearch.OUImport(0, ADSearch.DomainDN);
	    }
	} // Main()
    } // MainProg
} // namespace

 

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions