/// <summary>
		/// Get a list of all groups of a certain user.
		/// </summary>
		/// <param name="adInfo">The user to query the groups from.</param>
		/// <returns>
		/// Returns an array of all groups the given user is
		/// member of.
		/// </returns>
		/// <remarks>
		/// From:
		/// http://72.14.221.104/search?q=cache:sywXEEFvZiYJ:www.411asp.net/func/goto%3Fid%3D5863210+memberOf+ad&hl=de&gl=de&ct=clnk&cd=2&client=firefox-a
		/// The property "MemberOf" does not supply the "Primary Group".
		/// See:
		/// http://dunnry.com/blog/EnumeratingTokenGroupsTokenGroupsInNET.aspx
		/// </remarks>
		public ADGroupInfo[] GetUserParentGroupsEx(
			ADUserInfo adInfo )
		{
			byte[] guidBytes = adInfo.Guid.ToByteArray();
			string guidString = HexEscape( guidBytes );

			DirectoryEntry entry = GetDirectoryEntry( LdapBaseString );

			DirectorySearcher searcher = new DirectorySearcher( entry );
			searcher.Filter =
				string.Format(
				@"(&(objectCategory=person)(objectGUID={0}))",
				guidString );

			searcher.PropertiesToLoad.Add( @"memberOf" );
			searcher.SizeLimit = adSizeReturn;

			SearchResult result = searcher.FindOne();
			if ( result == null )
			{
				LogCentral.Current.LogDebug(
					string.Format(
					@"GetUserGroups(): (B) searcher.FindOne() returned NULL, exiting with return value NULL."
					) );

				return null;
			}
			else
			{
				StringBuilder sb = new StringBuilder();

				//we are building an '|' clause
				sb.Append( @"(|" );

				using ( DirectoryEntry user = result.GetDirectoryEntry() )
				{
					//we must ask for this one first
					user.RefreshCache( new string[] { @"tokenGroups" } );

					PropertyValueCollection tokenGroups =
						user.Properties[@"tokenGroups"];

					if ( tokenGroups == null || tokenGroups.Count <= 0 )
					{
						LogCentral.Current.LogDebug(
							string.Format(
							@"GetUserGroups(): (C) No token groups for user '{0}' found, exiting with return value NULL.",
							adInfo.SamName
							) );

						return null;
					}

					foreach ( byte[] sid in tokenGroups )
					{
						//append each member into the filter
						sb.AppendFormat( @"(objectSid={0})", HexEscape( sid ) );
					}
				}

				//end our initial filter
				sb.Append( @")" );

				// --

				List<ADGroupInfo> list = new List<ADGroupInfo>();

				//now create and pull in one search
				using ( DirectorySearcher ds =
					new DirectorySearcher(
					GetDirectoryEntry( LdapBaseString ),
					sb.ToString(),
					new string[] { @"distinguishedName" } ) )
				{
					using ( SearchResultCollection srcs = ds.FindAll() )
					{
						foreach ( SearchResult src in srcs )
						{
							object val =
								src.Properties[@"distinguishedName"][0];

							ADGroupInfo info = GetGroupInfoByDN(
								Convert.ToString( val ) );

							Debug.Assert( info != null );
							if ( info != null )
							{
								list.Add( info );
							}
						}
					}
				}

				return list.ToArray();
			}
		}
		/// <summary>
		/// Get a list of all groups of a certain user.
		/// </summary>
		/// <param name="adInfo">The user to query the groups from.</param>
		/// <returns>
		/// Returns an array of all groups the given user is
		/// member of.
		/// </returns>
		/// <remarks>
		/// From: 
		/// http://72.14.221.104/search?q=cache:sywXEEFvZiYJ:www.411asp.net/func/goto%3Fid%3D5863210+memberOf+ad&hl=de&gl=de&ct=clnk&cd=2&client=firefox-a
		/// The property "MemberOf" does not supply the "Primary Group".
		/// </remarks>
		public ADGroupInfo[] GetUserParentGroups(
			ADUserInfo adInfo )
		{
			byte[] guidBytes = adInfo.Guid.ToByteArray();
			string guidString = HexEscape( guidBytes );

			DirectoryEntry entry = GetDirectoryEntry( LdapBaseString );

			DirectorySearcher searcher = new DirectorySearcher( entry );
			searcher.Filter =
				string.Format(
				@"(&(objectCategory=person)(objectGUID={0}))",
				guidString );

			searcher.PropertiesToLoad.Add( @"memberOf" );
			searcher.SizeLimit = adSizeReturn;

			SearchResult result = searcher.FindOne();
			if ( result == null )
			{
				LogCentral.Current.LogDebug(
					string.Format(
					@"GetUserGroups(): (B) searcher.FindOne() returned NULL, exiting with return value NULL."
					) );

				return null;
			}
			else if ( result.Properties[@"memberOf"] == null )
			{
				return null;
			}
			else
			{
				List<ADGroupInfo> list = new List<ADGroupInfo>();

				foreach ( object val in result.Properties[@"memberOf"] )
				{
					ADGroupInfo info = GetGroupInfoByDN(
						Convert.ToString( val ) );
					Debug.Assert( info != null );
					if ( info != null )
					{
						list.Add( info );
					}
				}

				return list.ToArray();
			}
		}
		/// <summary>
		/// Modifies the information of an EXISTING user in
		/// the ActiveDirectory.
		/// </summary>
		/// <param name="info">The information of the existing user.
		/// The Guid field must be valid.</param>
		/// <param name="oldPassword">The old password.</param>
		/// <param name="newPassword">The new password.</param>
		public void ChangePassword(
			ADUserInfo info,
			string oldPassword,
			string newPassword )
		{
			try
			{
				Impersonator impersonator = null;

				if ( configuration.DoImpersonate )
				{
					LogCentral.Current.LogDebug(
						string.Format(
						@"ChangePassword(): About to impersonate with domain name '{0}' and user name '{1}'.",
						configuration.ImpersonationDomainName,
						configuration.ImpersonationUserName ) );

					impersonator = new Impersonator(
						configuration.ImpersonationUserName,
						configuration.ImpersonationDomainName,
						configuration.ImpersonationPassword );

					LogCentral.Current.LogDebug(
						string.Format(
						@"ChangePassword(): Impersonation succeeded." ) );
				}

				try
				{
					byte[] guidBytes = info.Guid.ToByteArray();
					string guidString = HexEscape( guidBytes );

					string ldapString = LdapBaseString;
					string ldapFilter =
						string.Format(
						@"(&(objectCategory=person)(objectGUID={0}))",
						guidString );

					LogCentral.Current.LogDebug(
						string.Format(
						@"ChangePassword(): About to query LDAP server with LDAP string '{0}' and filter string '{1}'.",
						ldapString,
						ldapFilter ) );

					DirectoryEntry entry = GetDirectoryEntry( ldapString );

					DirectorySearcher searcher =
						new DirectorySearcher( entry );
					searcher.Filter = ldapFilter;
					searcher.SizeLimit = adSizeReturn;

					// --

					// Use this call only to fill the req. fields.
					ADUserInfo currentInfo = GetUserInfoBySearcher( searcher );

					SearchResult result = searcher.FindOne();
					DirectoryEntry e = result.GetDirectoryEntry();

					// --

					e.Invoke( @"setPassword", new object[] { newPassword } );
					//e.Invoke( "changePassword", new object[] { oldPassword, newPassword } );

					// --

					// Actually store back.
					e.CommitChanges();
				}
				finally
				{
					if ( impersonator != null )
					{
						impersonator.Dispose();
						impersonator = null;
					}
				}
			}
			catch ( Exception x )
			{
				LogCentral.Current.LogError(
					string.Format(
					@"ActiveDirectory.ChangePassword(): Exception occured for putting the user infos. The following values were set through SetWP(): '{0}'.",
					debugSettedWPValues ),
					x );

				throw;
			}
		}
			/// <summary>
			/// Add to the cache.
			/// </summary>
			/// <param name="item">The item.</param>
			public void Add(
				ADUserInfo item )
			{
				cachedItems.Add( item );
			}
		/// <summary>
		/// Write back to AD, but only certain information, since not all
		/// is modifiable or intented to be so.
		/// </summary>
		/// <param name="e">The e.</param>
		/// <param name="curInfo">The cur info.</param>
		/// <param name="newInfo">The new info.</param>
		private void PutUserInfo(
			DirectoryEntry e,
			ADUserInfo curInfo,
			ADUserInfo newInfo )
		{
			// Reset for accumulating.
			debugSettedWPValues = string.Empty;

			if ( curInfo.CN != newInfo.CN )
			{
				SetWP( e.Properties, @"cn", newInfo.CN );
			}
			if ( curInfo.CN != newInfo.Name )
			{
				SetWP( e.Properties, @"name", newInfo.Name );
			}

			if ( curInfo.FirstName != newInfo.FirstName )
			{
				SetWP( e.Properties, @"givenName", newInfo.FirstName );
			}
			if ( curInfo.LastName != newInfo.LastName )
			{
				SetWP( e.Properties, @"sn", newInfo.LastName );
			}
			if ( curInfo.Initials != newInfo.Initials )
			{
				SetWP( e.Properties, @"initials", newInfo.Initials );
			}
			if ( curInfo.Description != newInfo.Description )
			{
				SetWP( e.Properties, @"description", newInfo.Description );
			}

			if ( curInfo.StreetAddress != newInfo.StreetAddress )
			{
				SetWP( e.Properties, @"streetAddress", newInfo.StreetAddress );
			}
			if ( curInfo.PostOfficeBox != newInfo.PostOfficeBox )
			{
				SetWP( e.Properties, @"postOfficeBox", newInfo.PostOfficeBox );
			}
			if ( curInfo.Zip != newInfo.Zip )
			{
				SetWP( e.Properties, @"postalCode", newInfo.Zip );
			}
			if ( curInfo.City != newInfo.City )
			{
				SetWP( e.Properties, @"l", newInfo.City );
			}
			if ( curInfo.State != newInfo.State )
			{
				SetWP( e.Properties, @"st", newInfo.State );
			}
			if ( curInfo.CountryCode != newInfo.CountryCode )
			{
				SetWP( e.Properties, @"c", newInfo.CountryCode );
			}

			if ( curInfo.TelephoneNumber != newInfo.TelephoneNumber )
			{
				SetWP( e.Properties, @"telephoneNumber", newInfo.TelephoneNumber );
			}
			if ( curInfo.MobileNumber != newInfo.MobileNumber )
			{
				SetWP( e.Properties, @"mobile", newInfo.MobileNumber );
			}
			if ( curInfo.FaxNumber != newInfo.FaxNumber )
			{
				SetWP( e.Properties, @"facsimileTelephoneNumber", newInfo.FaxNumber );
			}
			if ( curInfo.EMail != newInfo.EMail )
			{
				SetWP( e.Properties, @"mail", newInfo.EMail );
			}
			if ( curInfo.WwwHomePage != newInfo.WwwHomePage )
			{
				SetWP( e.Properties, @"wwwHomePage", newInfo.WwwHomePage );
			}

			if ( curInfo.Title != newInfo.Title )
			{
				SetWP( e.Properties, @"title", newInfo.Title );
			}
			if ( curInfo.Department != newInfo.Department )
			{
				SetWP( e.Properties, @"department", newInfo.Department );
			}
			if ( curInfo.Company != newInfo.Company )
			{
				SetWP( e.Properties, @"company", newInfo.Company );
			}
			if ( curInfo.PrimaryGroupID != newInfo.PrimaryGroupID )
			{
				SetWP( e.Properties, @"primaryGroupID", newInfo.PrimaryGroupID );
			}
			if ( curInfo.Manager != newInfo.Manager )
			{
				SetWP( e.Properties, @"manager", newInfo.Manager );
			}
		}
		/// <summary>
		/// Gets the user info by searcher.
		/// </summary>
		/// <param name="searcher">The searcher.</param>
		/// <returns></returns>
		private ADUserInfo GetUserInfoBySearcher(
			DirectorySearcher searcher )
		{
			searcher.SizeLimit = adSizeReturn;

			searcher.PropertiesToLoad.Add( @"userAccountControl" );

			searcher.PropertiesToLoad.Add( @"objectGUID" );
			searcher.PropertiesToLoad.Add( @"objectSid" );
			searcher.PropertiesToLoad.Add( @"sAMAccountName" );
			searcher.PropertiesToLoad.Add( @"cn" );
			searcher.PropertiesToLoad.Add( @"name" );

			searcher.PropertiesToLoad.Add( @"givenName" );
			searcher.PropertiesToLoad.Add( @"sn" );
			searcher.PropertiesToLoad.Add( @"initials" );
			searcher.PropertiesToLoad.Add( @"description" );

			searcher.PropertiesToLoad.Add( @"streetAddress" );
			searcher.PropertiesToLoad.Add( @"postOfficeBox" );
			searcher.PropertiesToLoad.Add( @"postalCode" );
			searcher.PropertiesToLoad.Add( @"c" );
			searcher.PropertiesToLoad.Add( @"st" );
			searcher.PropertiesToLoad.Add( @"l" );

			searcher.PropertiesToLoad.Add( @"telephoneNumber" );
			searcher.PropertiesToLoad.Add( @"mobile" );
			searcher.PropertiesToLoad.Add( @"facsimileTelephoneNumber" );
			searcher.PropertiesToLoad.Add( @"mail" );
			searcher.PropertiesToLoad.Add( @"wwwHomePage" );

			searcher.PropertiesToLoad.Add( @"title" );
			searcher.PropertiesToLoad.Add( @"department" );
			searcher.PropertiesToLoad.Add( @"company" );
			searcher.PropertiesToLoad.Add( @"manager" );
			searcher.PropertiesToLoad.Add( @"primaryGroupID" );

			// --

			SearchResult result = searcher.FindOne();
			if ( result == null )
			{
				LogCentral.Current.LogDebug(
					string.Format(
					@"GetUserInfo(): (A) searcher.FindOne() returned NULL, exiting with return value NULL (The LDAP query was '{0}').",
					searcher.Filter
					) );
				return null;
			}
			else
			{
				ADUserInfo info = new ADUserInfo( this );

				// Add relative DN.
				string dn = result.Path;
				string basePath =
					string.Format( @"LDAP://{0}",
					configuration.LdapServer );
				if ( dn.StartsWith( basePath, StringComparison.InvariantCultureIgnoreCase ) )
				{
					dn = dn.Substring( basePath.Length ).Trim( '/' );
				}
				info.DN = dn;

				// --

				byte[] guidBytes = GetPropertyValueByteArray( result.Properties[@"objectGUID"] );
				byte[] sidBytes = GetPropertyValueByteArray( result.Properties[@"objectSid"] );

				info.Guid = new Guid( guidBytes );
				info.Sid = ConvertByteToStringSid( sidBytes );
				info.AccountControlFlags = (ADUserFlags)Convert.ToUInt32( GetRP( result.Properties[@"userAccountControl"] ) );
				info.SamName = ReadFieldString( GetRP( result.Properties[@"sAMAccountName"] ) );
				info.CN = ReadFieldString( GetRP( result.Properties[@"cn"] ) );
				info.Name = ReadFieldString( GetRP( result.Properties[@"name"] ) );

				info.FirstName = ReadFieldString( GetRP( result.Properties[@"givenName"] ) );
				info.LastName = ReadFieldString( GetRP( result.Properties[@"sn"] ) );
				info.Initials = ReadFieldString( GetRP( result.Properties[@"initials"] ) );
				info.Description = ReadFieldString( GetRP( result.Properties[@"description"] ) );

				info.StreetAddress = ReadFieldString( GetRP( result.Properties[@"streetAddress"] ) );
				info.PostOfficeBox = ReadFieldString( GetRP( result.Properties[@"postOfficeBox"] ) );
				info.Zip = ReadFieldString( GetRP( result.Properties[@"postalCode"] ) );
				info.City = ReadFieldString( GetRP( result.Properties[@"l"] ) );
				info.State = ReadFieldString( GetRP( result.Properties[@"st"] ) );
				info.CountryCode = ReadFieldString( GetRP( result.Properties[@"c"] ) );

				info.TelephoneNumber = ReadFieldString( GetRP( result.Properties[@"telephoneNumber"] ) );
				info.MobileNumber = ReadFieldString( GetRP( result.Properties[@"mobile"] ) );
				info.FaxNumber = ReadFieldString( GetRP( result.Properties[@"facsimileTelephoneNumber"] ) );
				info.EMail = ReadFieldString( GetRP( result.Properties[@"mail"] ) );
				info.WwwHomePage = ReadFieldString( GetRP( result.Properties[@"wwwHomePage"] ) );

				info.Title = ReadFieldString( GetRP( result.Properties[@"title"] ) );
				info.Department = ReadFieldString( GetRP( result.Properties[@"department"] ) );
				info.Company = ReadFieldString( GetRP( result.Properties[@"company"] ) );
				info.Manager = ReadFieldString( GetRP( result.Properties[@"manager"] ) );
				info.PrimaryGroupID = ReadFieldLong( GetRP( result.Properties[@"primaryGroupID"] ) );

				// --

				return info;
			}
		}