http://www.infini-tec.de/InfiniTec - Henning Krauses Blog - DirectoryServices library2010-11-29T19:40:37+00:00Don't adjust your mind - it's reality that is malfunctioning Henning KrauseBlogEngine.Net Syndication Generatorhttp://www.infini-tec.de/opml.axdHenning KrauseDon't adjust your mind - it's reality that is malfunctioning en-USInfiniTec - Henning Krauses Blog 0.0000000.000000http://www.infini-tec.de/post/2009/08/11/InfiniTecDirectoryServices-now-on-CodePlex.aspxInfiniTec.DirectoryServices now on CodePlex2009-08-11T19:14:58+00:00hkrause<p>I’ve just created my second CodePlex project (the first one being my PushNotification Lister on <a title="http://exchangenotification.codeplex.com/" href="http://exchangenotification.codeplex.com/">http://exchangenotification.codeplex.com/</a>). It’s the DirectoryServices.Protocols wrapper I created a while ago. The last version was still based on my old InfiniTec.Threading library which is seriously broken. The new one runs rather flawlessly and is very stable.</p> <p>I will add example programs soon, I hope.</p>2009-08-11T19:14:58+00:00hkrausehttp://www.infini-tec.de/pingback.axdhttp://www.infini-tec.de/post.aspx?id=55bb83cc-41fb-4223-b193-3758ef7a61ca0http://www.infini-tec.de/trackback.axd?id=55bb83cc-41fb-4223-b193-3758ef7a61cahttp://www.infini-tec.de/post/2009/08/11/InfiniTecDirectoryServices-now-on-CodePlex.aspx#commenthttp://www.infini-tec.de/syndication.axd?post=55bb83cc-41fb-4223-b193-3758ef7a61cahttp://www.infini-tec.de/post/2006/09/18/Another-update-for-the-DirectoryServices-library.aspxAnother update for the DirectoryServices library2006-09-17T22:00:00+00:00hkrause<div xmlns="http://www.w3.org/1999/xhtml"><p>This update fixes some serious bugs and adds the ability to save changes made to an item back to the directory server:</p><div class="clsCode" style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #f0f0f0"><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 1</span> <span style="color: #008080;">ActiveDirectoryUser</span> user;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 2</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 3</span> <span style="color: #0000ff;">using</span> (<span style="color: #008080;">Connection</span> connection = <span style="color: #0000ff;">new</span><span style="color: #008080;">Connection</span>(<span style="color: #800000;">"contoso.local"</span>, <span style="color: #008080;">DirectoryIdentifierType</span>.Server, <span style="color: #0000ff;">false</span>, <span style="color: #0000ff;">new</span><span style="color: #008080;">NetworkCredential</span>(<span style="color: #800000;">"administrator"</span>, <span style="color: #800000;">"password"</span>, <span style="color: #800000;">"contoso"</span>), <span style="color: #008080;">AuthType</span>.Basic))</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 4</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 5</span> user = <span style="color: #0000ff;">new</span><span style="color: #008080;">ActiveDirectoryUser</span>(<span style="color: #800000;">"CN=Alice, CN=Users, DC=contoso, DC=local"</span>, connection);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 6</span> user.Refresh();</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 7</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 8</span> user.Description = <span style="color: #800000;">"The quick brown fox jumps over the lazy dog"</span>;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 9</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 10</span> user.Save(<span style="color: #0000ff;">false</span>);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 11</span> }</span></p></div><p>The Save and SaveAsync methods both accept one boolean parameter. If set to true, the save operation will return before the changes have been committed to disk by the directory server (known as lazy commit). This improves performance, but increases the likelihood of data loss.</p></div><h2 xmlns="http://www.w3.org/1999/xhtml">ChangeLog</h2><div xmlns="http://www.w3.org/1999/xhtml"><p align="left">Changes made from version 1.0 to version 1.1:</p><ul style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px" type="disc"><li><p align="left">Added a static Open method to the ActiveDirectoryPrinicipal object, which either returns an ActiveDirectoryUser or an ActiveDirectoryGroup object</p></li><li><p align="left">Added the ability to save changes back to server.</p></li><li><p align="left">Fixed a bug with integrated authentication when using the Translator class</p></li><li><p align="left">Fixed a bug which occured when an ActiveDirectoryEntry was refreshed a second time.</p></li><li><p align="left">Fixed a bug with the ActiveDirectoryGroup class</p></li><li><p align="left">Fixed a bug when an DirectoryOperation threw an exception.</p></li></ul></div><h2 xmlns="http://www.w3.org/1999/xhtml">Downloads</h2><table xmlns="http://www.w3.org/1999/xhtml"><tr><td><img style="border:none; vertical-align: middle;" src=file.axd?file=directoryservices_helper_1_1/zip.gif /></td><td><a href=file.axd?file=directoryservices_helper_1_1/Release.zip>Release.zip</a> (117,601 Bytes)<br />Binaries of version 1.1 signed with the InfiniTec private key</td></tr><tr><td><img style="border:none; vertical-align: middle;" src=file.axd?file=directoryservices_helper_1_1/zip.gif /></td><td><a href=file.axd?file=directoryservices_helper_1_1/InfiniTec.DirectoryServices.zip>InfiniTec.DirectoryServices.zip</a> (108,984 Bytes)<br />Source files</td></tr><tr><td><img style="border:none; vertical-align: middle;" src=file.axd?file=directoryservices_helper_1_1/zip.gif /></td><td><a href=file.axd?file=directoryservices_helper_1_1/Documentation.zip>Documentation.zip</a> (367,358 Bytes)<br />Documentation as CHM file.</td></tr></table>2006-09-17T22:00:00+00:00hkrauseThis update fixes some serious bugs and adds the ability to save changes made to an item back to the directory server: 1 ActiveDirectoryUser user; 2 3 using (Connection connection = newConnection("contoso.local", DirectoryIdentifierType.Server, false, newNetworkCredential("administrator", "password", "contoso"), AuthType.Basic)) 4 { 5 user = newActiveDirectoryUser("CN=Alice, CN=Users, DC=contoso, DC=local", connection); 6 user.Refresh(); 7 8 user.Description = "The quick brown fox jumps over the lazy dog"; 9 10 user.Save(false); 11 }The Save and SaveAsync methods both accept one boolean parameter. If set to true, the save operation will return before the changes have been committed to disk by the directory server (known as lazy commit). This improves performance, but increases the likelihood of data loss.http://www.infini-tec.de/pingback.axdhttp://www.infini-tec.de/post.aspx?id=607f6ec6-7982-4d07-b872-c39b9b42abbc0http://www.infini-tec.de/trackback.axd?id=607f6ec6-7982-4d07-b872-c39b9b42abbchttp://www.infini-tec.de/post/2006/09/18/Another-update-for-the-DirectoryServices-library.aspx#commenthttp://www.infini-tec.de/syndication.axd?post=607f6ec6-7982-4d07-b872-c39b9b42abbchttp://www.infini-tec.de/post/2006/09/17/DirectoryServices-revisited.aspxDirectoryServices revisited2006-09-16T22:00:00+00:00hkrause<div xmlns="http://www.w3.org/1999/xhtml">As promised in the first article (See <a href="libraries/directoryservices">here</a>), here is another article on the classes in my DirectoryServices package. Here we go...<h3>Lost in translation...</h3><div><p>Ever wanted to translate an accountname like contoso\jdoe to the corresponding distinguished name? The Translator class comes to the rescue:</p><div class="clsCode" style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #f0f0f0"><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 1</span> <span style="color: #008080;">Translator</span> translator;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 2</span> <span style="color: #008080;">TranslationResult</span> result;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 3</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 4</span> <span style="color: #0000ff;">using</span> (<span style="color: #008080;">Connection</span> connection = <span style="color: #0000ff;">new</span><span style="color: #008080;">Connection</span>(<span style="color: #800000;">"contoso.local"</span>, <span style="color: #008080;">DirectoryIdentifierType</span>.DnsDomain, <span style="color: #0000ff;">false</span>, </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 5</span> <span style="color: #0000ff;">new</span><span style="color: #008080;">NetworkCredential</span>(<span style="color: #800000;">"administrator"</span>, <span style="color: #800000;">"password"</span>, <span style="color: #800000;">"contoso"</span>), <span style="color: #008080;">AuthType</span>.Basic))</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 6</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 7</span> translator = <span style="color: #0000ff;">new</span><span style="color: #008080;">Translator</span>(connection);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 8</span> translator.InputFormat = <span style="color: #008080;">NameFormat</span>.NT4AccountName;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 9</span> translator.OutputFormat = <span style="color: #008080;">NameFormat</span>.DistinguishedName;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 10</span> translator.Translate(<span style="color: #800000;">"contoso\\administrator"</span>);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 11</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 12</span> result = translator.Results[0];</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 13</span> <span style="color: #0000ff;">if</span> (result.Status == <span style="color: #008080;">TranslationStatus</span>.Success)</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 14</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 15</span> <span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"The "</span> + translator.OutputFormat + <span style="color: #800000;">" of "</span> + result.InputName + <span style="color: #800000;">" is "</span> + result.TranslatedName);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 16</span> }</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 17</span> <span style="color: #0000ff;">else</span></span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 18</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 19</span> <span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Could not translate the name. Error: "</span> + result.Status);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 20</span> }</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 21</span> }</span></p></div><p>This class wraps around the DsCrackNames function of the Win32 Directory Services API. Basically, you can translate between these name formats:</p><ul style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px" type="disc"><li>DistinguishedName</li><li>NT4AccountName</li><li>DisplayName</li><li>UniqueId</li><li>CanonicalName</li><li>UserPrincipalName</li><li>CanonicalNameEx</li><li>ServicePrincipalName</li><li>SidOrSidHistory</li><li>DnsDomainName</li><li>ListNamingContexts</li></ul><p> </p><p>Not every nameformat can be translated to every other. You will get a TranslationStatus.NoMapping error in this case.</p><p>The last entry, <strong>ListNamingContext</strong>, can be used to enumerate all naming contexts in the forest. To use this, set the InputFormat to ListNamingContext. Then, call the Translate method with at least one name (content is completely irrelevant):</p><div class="clsCode" style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #f0f0f0"><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 1</span> <span style="color: #008080;">Translator</span> translator;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 2</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 3</span> <span style="color: #0000ff;">using</span> (<span style="color: #008080;">Connection</span> connection = <span style="color: #0000ff;">new</span><span style="color: #008080;">Connection</span>(<span style="color: #800000;">"contoso.local"</span>, <span style="color: #008080;">DirectoryIdentifierType</span>.Server, <span style="color: #0000ff;">false</span>, </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 4</span> <span style="color: #0000ff;">new</span><span style="color: #008080;">NetworkCredential</span>(<span style="color: #800000;">"administrator"</span>, <span style="color: #800000;">"password"</span>, <span style="color: #800000;">"sub"</span>), <span style="color: #008080;">AuthType</span>.Basic))</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 5</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 6</span> translator = <span style="color: #0000ff;">new</span><span style="color: #008080;">Translator</span>(connection);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 7</span> translator.InputFormat = <span style="color: #008080;">NameFormat</span>.ListNamingContexts;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 8</span> translator.Translate(<span style="color: #800000;">"any_value"</span>);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 9</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 10</span> <span style="color: #0000ff;">foreach</span> (<span style="color: #008080;">TranslationResult</span> result <span style="color: #0000ff;">in</span> translator.Results)</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 11</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 12</span> <span style="color: #008080;">Console</span>.WriteLine(result.TranslatedName);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 13</span> }</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 14</span> }</span></p></div><p>If the InputFormat is set to NameFormat.Unknown, the directory server tries to determine the format of the name(s) to translate. This causes some performance degration - If you know the format, you should supply it.</p></div><h3>Unleashing the power of ambiguous name resolution...</h3><div><p>Outlook has a handy feature called ambiguous name resolution: You can type only a part of a name, and Outlook resolves the given name to a complete name, if possible. Active Directory also implements this feature, and it's possible to use it with a special LDAP query: <strong>(anr=jo*)</strong> will find all items in the Active Directory with a special set of properties (per default, givenName, surname, displayName, legacyExchangeDN, msExchMailNickname, RDN, physicalDeliveryOfficeName, , proxyAddress, sAMAccountName) matches the specified filter.</p><p>The <strong>PrincipalResolver</strong> encapsulates this feature and extends it with an additional feature: If the name being searched for is exactly two characters long, the filter is set to (|<strong>(anr=value)(&(givenName=value[0]*)(sn=value[1]*)))</strong>, which effectively resolves initials. Here an example:</p><div class="clsCode" style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #f0f0f0"><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 1</span> <span style="color: #008080;">PrincipalResolver</span> resolver;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 2</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 3</span> <span style="color: #0000ff;">using</span> (<span style="color: #008080;">Connection</span> connection = <span style="color: #0000ff;">new</span><span style="color: #008080;">Connection</span>(<span style="color: #800000;">"contoso.local"</span>, <span style="color: #008080;">DirectoryIdentifierType</span>.Server, <span style="color: #0000ff;">false</span>, <span style="color: #0000ff;">new</span><span style="color: #008080;">NetworkCredential</span>(<span style="color: #800000;">"administrator"</span>, <span style="color: #800000;">"password"</span>, <span style="color: #800000;">"sub"</span>), <span style="color: #008080;">AuthType</span>.Basic))</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 4</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 5</span> resolver = <span style="color: #0000ff;">new</span><span style="color: #008080;">PrincipalResolver</span>(connection);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 6</span> resolver.FindAll(<span style="color: #800000;">"al"</span>, <span style="color: #008080;">ResolveTypes</span>.User);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 7</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 8</span> <span style="color: #0000ff;">foreach</span> (<span style="color: #008080;">ActiveDirectoryUser</span> entry <span style="color: #0000ff;">in</span> resolver.SearchResult)</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 9</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 10</span> <span style="color: #008080;">Console</span>.WriteLine(entry.DisplayName);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 11</span> }</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 12</span> }</span></p></div><p>If the domaincontroller, to which the connection object is bound is a global catalog, the entire forest will be searched. To search only a part of the forest, specify these settings:</p><div class="clsCode" style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #f0f0f0"><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 1</span> resolver.ResolveScope = <span style="color: #008080;">ResolveScope</span>.Domain;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 2</span> resolver.SearchRoot = <span style="color: #008080;">Searcher</span>.RootDomain;</span></p></div><p>The first line restricts the search to the specified domain, while the second line sets the domain for the search. Two default values are available: Searcher.RootDomain, which searches the root domain of the forest, and Searcher.DefaultDomain, which searches the default domain of the domain controller the current connection is bound to.</p><p>The PrincipalSearcher can search either for users, groups or both types. Note, that users do include contacts as well.</p></div><h3>Speaking of users and groups</h3><div><p>To simplify the handling of users and groups, there are two classes to handle these to types: The ActiveDirectoryUser and the ActiveDirectoryGroup:</p><p><a href=file.axd?file=directoryservicesrevisited/240b3f0316c744a2.jpg style="margin-right: 10px; display: block;"><img src=file.axd?file=directoryservicesrevisited/preview_240b3f0316c744a2.jpg float="false" style=";border: none;" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xd="http://schemas.microsoft.com/office/infopath/2003" /><br /><span style="font-size: 8pt;font-style: italic;text-align: right;clear: left;"> (click to enlarge)</span></a></p><p>The base class for both classes is the ActiveDirectoryEntry, which contains some properties and methods for handling Active Directory entries. Based on the ActiveDirectoryEntry is the ActiveDirectoryPrincipal, which contains some properties regarding group membership and SIDs.</p><p>Both, the ActiveDirectoryUser and the ActiveDirectoryGroup inherit from this class: The ActiveDirectoryUser exposes mst the properties available on user objects. The same is true fro the ActiveDirectoryGrup.</p><p>For performance reasons, the group memberships are only exposed in SID form (the group memberships are stored in this way). The TranslateSids method can be used to translate those sids to a more readable form.</p></div><div>Thats it for now... I hope this library is of some use to anyone...</div></div>2006-09-16T22:00:00+00:00hkrauseAs promised in the first article (See here), here is another article on the classes in my DirectoryServices package. Here we go...Ever wanted to translate an accountname like contoso\jdoe to the corresponding distinguished name? The Translator class comes to the rescue: 1 Translator translator; 2 TranslationResult result; 3 4 using (Connection connection = newConnection("contoso.local", DirectoryIdentifierType.DnsDomain, false, 5 newNetworkCredential("administrator", "password", "contoso"), AuthType.Basic)) 6 { 7 translator = newTranslator(connection); 8 translator.InputFormat = NameFormat.NT4AccountName; 9 translator.OutputFormat = NameFormat.DistinguishedName; 10 translator.Translate("contoso\\administrator"); 11 12 result = translator.Results[0]; 13 if (result.Status == TranslationStatus.Success) 14 { 15 Console.WriteLine("The " + translator.OutputFormat + " of " + result.InputName + " is " + result.TranslatedName); 16 } 17 else 18 { 19 Console.WriteLine("Could not translate the name. Error: " + result.Status); 20 } 21 }This class wraps around the DsCrackNames function of the Win32 Directory Services API. Basically, you can translate between these name formats:DistinguishedNameNT4AccountNameDisplayNameUniqueIdCanonicalNameUserPrincipalNameCanonicalNameExServicePrincipalNameSidOrSidHistoryDnsDomainNameListNamingContexts Not every nameformat can be translated to every other. You will get a TranslationStatus.NoMapping error in this case.The last entry, ListNamingContext, can be used to enumerate all naming contexts in the forest. To use this, set the InputFormat to ListNamingContext. Then, call the Translate method with at least one name (content is completely irrelevant): 1 Translator translator; 2 3 using (Connection connection = newConnection("contoso.local", DirectoryIdentifierType.Server, false, 4 newNetworkCredential("administrator", "password", "sub"), AuthType.Basic)) 5 { 6 translator = newTranslator(connection); 7 translator.InputFormat = NameFormat.ListNamingContexts; 8 translator.Translate("any_value"); 9 10 foreach (TranslationResult result in translator.Results) 11 { 12 Console.WriteLine(result.TranslatedName); 13 } 14 }If the InputFormat is set to NameFormat.Unknown, the directory server tries to determine the format of the name(s) to translate. This causes some performance degration - If you know the format, you should supply it.Outlook has a handy feature called ambiguous name resolution: You can type only a part of a name, and Outlook resolves the given name to a complete name, if possible. Active Directory also implements this feature, and it's possible to use it with a special LDAP query: (anr=jo*) will find all items in the Active Directory with a special set of properties (per default, givenName, surname, displayName, legacyExchangeDN, msExchMailNickname, RDN, physicalDeliveryOfficeName, , proxyAddress, sAMAccountName) matches the specified filter.The PrincipalResolver encapsulates this feature and extends it with an additional feature: If the name being searched for is exactly two characters long, the filter is set to (|(anr=value)(&(givenName=value[0]*)(sn=value[1]*))), which effectively resolves initials. Here an example: 1 PrincipalResolver resolver; 2 3 using (Connection connection = newConnection("contoso.local", DirectoryIdentifierType.Server, false, newNetworkCredential("administrator", "password", "sub"), AuthType.Basic)) 4 { 5 resolver = newPrincipalResolver(connection); 6 resolver.FindAll("al", ResolveTypes.User); 7 8 foreach (ActiveDirectoryUser entry in resolver.SearchResult) 9 { 10 Console.WriteLine(entry.DisplayName); 11 } 12 }If the domaincontroller, to which the connection object is bound is a global catalog, the entire forest will be searched. To search only a part of the forest, specify these settings: 1 resolver.ResolveScope = ResolveScope.Domain; 2 resolver.SearchRoot = Searcher.RootDomain;The first line restricts the search to the specified domain, while the second line sets the domain for the search. Two default values are available: Searcher.RootDomain, which searches the root domain of the forest, and Searcher.DefaultDomain, which searches the default domain of the domain controller the current connection is bound to.The PrincipalSearcher can search either for users, groups or both types. Note, that users do include contacts as well.To simplify the handling of users and groups, there are two classes to handle these to types: The ActiveDirectoryUser and the ActiveDirectoryGroup:The base class for both classes is the ActiveDirectoryEntry, which contains some properties and methods for handling Active Directory entries. Based on the ActiveDirectoryEntry is the ActiveDirectoryPrincipal, which contains some properties regarding group membership and SIDs.Both, the ActiveDirectoryUser and the ActiveDirectoryGroup inherit from this class: The ActiveDirectoryUser exposes mst the properties available on user objects. The same is true fro the ActiveDirectoryGrup.For performance reasons, the group memberships are only exposed in SID form (the group memberships are stored in this way). The TranslateSids method can be used to translate those sids to a more readable form.Thats it for now... I hope this library is of some use to anyone...http://www.infini-tec.de/pingback.axdhttp://www.infini-tec.de/post.aspx?id=dc6197e4-4062-4b3a-963c-039ee8d60e362http://www.infini-tec.de/trackback.axd?id=dc6197e4-4062-4b3a-963c-039ee8d60e36http://www.infini-tec.de/post/2006/09/17/DirectoryServices-revisited.aspx#commenthttp://www.infini-tec.de/syndication.axd?post=dc6197e4-4062-4b3a-963c-039ee8d60e36http://www.infini-tec.de/post/2006/09/03/A-high-level-wrapper-around-SystemDirectoryServiceProtocols.aspxA high-level wrapper around System.DirectoryService.Protocols2006-09-02T22:00:00+00:00hkrause<div xmlns="http://www.w3.org/1999/xhtml"><p>Thanks to <a href="http://www.joekaplan.net/">Joe Kaplan</a>, I spent some time recently playing around with the <a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.protocols.aspx">System.DirectoryServices.Protocols</a> (SDS.P) namespace. The main advantage of this namespace is control and flexibility: The developer decides when to close a connection. What to search, with which scope. This is possible because the SDS.P classes operate at a much lower level than the <a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.directoryentry.aspx">DirectoryEntry</a> or the <a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.directorysearcher.aspx">DirectorySearcher</a> class.</p><p>Nothing, however, comes without a price. In this case, the price is usability - There is simply no <a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.directoryentry.aspx">DirectoryEntry</a> in the SDS.P namespace - one has to do a search with a <a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.protocols.SearchScope.aspx">scope</a> of Base. Not quite simple. Additionally, the only datatypes supported on the properties returned from a search operation are byte[] and string. And no support for generics anywhere...</p><p>Therefore I created this wrapper around the <a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.protocols.aspx">SDS.P</a> namespace, to make it more usable. Additionally, I included a class to translate names between the various formats used throughout Windows. This class wraps around the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ad/ad/dscracknames.asp">DsCrackNames</a> function of the Win32 API, and makes <a href="http://msdn2.microsoft.com/en-us/library/ms180842.aspx">GUID binding</a> trivial - Just translate the security-identifier to the corresponding GUID and bind to the Active Directory object (Yes, I know, the SID can also be used to bind to the Active Directory object - but this is limited to the current domain - one cannot bind to an object outside the current domain).</p><p><a href=file.axd?file=directoryservices_helper/6a66f7d3231a4327.jpg style="margin-right: 10px; display: block;"><img src=file.axd?file=directoryservices_helper/preview_6a66f7d3231a4327.jpg title="The Connection class" float="false" style=";border: none;" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xd="http://schemas.microsoft.com/office/infopath/2003" /><br /><span style="font-size: 8pt;font-style: italic;text-align: right;clear: left;">The Connection class (click to enlarge)</span></a>When using this class, you will always start with the connection object. The connection class can either bind to a specific server or to a domain name. Server-less binding is also supported.</p><p>If you want to perform your own requests using this class, just call the GetSendRequestOperation() which issues the request aynchronously using my <a href="libraries/threading/infinitec.threading.aspx">InfiniTec.Threading</a> library. This is not trivial if you are not familiar with the library - if you need advice on this topic, drop me a note and I will post an additional article on this topic.</p><p>The code used is something like this:</p><div class="clsCode" style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #f0f0f0"><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 1</span> <span style="color: #0000ff;">using</span> (<span style="color: #008080;">Connection</span> connection = <span style="color: #0000ff;">new</span><span style="color: #008080;">Connection</span>(<span style="color: #800000;">"entdcsub"</span>, <span style="color: #008080;">DirectoryIdentifierType</span>.Server, <span style="color: #0000ff;">false</span>))</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 2</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 3</span> <span style="color: #008000;">// Do something interesting here...</span></span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 4</span> }</span></p></div><h3>Binding to specific objects</h3><div><p>Once you have connection, you can simply bind to a known object:</p><div class="clsCode" style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #f0f0f0"><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 1</span> <span style="color: #0000ff;">using</span> (<span style="color: #008080;">Connection</span> connection = <span style="color: #0000ff;">new</span><span style="color: #008080;">Connection</span>(<span style="color: #800000;">"dcaw"</span>, <span style="color: #008080;">DirectoryIdentifierType</span>.Server, <span style="color: #0000ff;">false</span>))</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 2</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 3</span> item = <span style="color: #0000ff;">new</span><span style="color: #008080;">Item</span>(<span style="color: #800000;">"CN=Doe\, John, CN=Users, DC=AdventureWorks, DC=local"</span>, connection);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 4</span> item.Refresh();</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 5</span> displayName = item.Properties.GetProperty<<span style="color: #0000ff;">string</span>>(<span style="color: #800000;">"displayName"</span>).Value;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 6</span> }</span></p></div><p>It's as simple as this...</p><p>The Item class has the following characteristics:</p><p><div class="margin-right: 10px; display: block; width:600px;"><img src=file.axd?file=directoryservices_helper/85d7fc696074588.jpg float="false" style=";border: none;" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xd="http://schemas.microsoft.com/office/infopath/2003" /><br /><span style="font-size: 8pt;font-style: italic;text-align: right;clear: left;"></span></div></p></div><h3>But I don't know the distinguished name of the object....</h3><div><p>... don't panic. The Searcher class will help you here. This class is by far the most complex class in this library:</p><p><div class="margin-right: 10px; display: block; width:600px;"><img src=file.axd?file=directoryservices_helper/976dd07f6a8d41ce.jpg float="false" style=";border: none;" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xd="http://schemas.microsoft.com/office/infopath/2003" /><br /><span style="font-size: 8pt;font-style: italic;text-align: right;clear: left;"></span></div></p><p>The search operation which will be performed by the Searcher class can be extensively customized. Here are the main option:<br /><strong>Constraints</strong> - This property accepts a standard LDAP filter like <strong>"(mail=*)"</strong> or similar.<br /><strong>IncludeDeletedItems</strong> - If true, deleted items are returned.<br /><strong>NamingContextScope</strong> - This is important. You can specifiy if you want to search the current naming context only, or search the current and all subordinate contexts.<br /><strong>PageSize</strong> - Doing a paged search reduces the resources used during the search. This property let you specify the number of items returned per page.<br /><strong>PropertiesToLoad</strong> - Which properties should be populated during the search?<br /><strong>Scope</strong> - Do you want to search only the search root, the direct descendents of the searchroot, or all levels below the search root?<br /><strong>SearchRoot</strong> - Where does the search begin? If <strong>NamingContextScope</strong> is set to domain scope, a search root must be specified. Otherwise, this property can be left blank. In this case, the entire forest ist searched.<br /><strong>SizeLimit</strong> - This property lets you specify the maximum number of items you want to get. But you should use this sparingly - if more items are returned than specified here, an exception is thrown.<br /><strong>SortKeys</strong> - Very handy. This allows server-side sorting of the result set</p><p>To start a search, populate the desired fields and call <strong>FindAll</strong> or <strong>FindPage</strong>. The first method, performs the search and returns once the search is completed. The <strong>FindPage</strong> method returns once the next page of items is returned by the server.</p><p>For scalability reaonse, you should use the <strong>FindAllAsync</strong> and <strong>FindPageAsync</strong> methods - these methods return immediately and thus don't block the current thread. The <strong>FindCompleted </strong>and <strong>ProgressChanged </strong>events are fired, whenever an operation completes.</p><p>The following example performs an ambiguous name resolution and finds all entries which start with the character a:</p><div class="clsCode" style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #f0f0f0"><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 1</span> <span style="color: #0000ff;">static</span><span style="color: #0000ff;">void</span> Main(<span style="color: #0000ff;">string</span>[] args)</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 2</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 3</span> <span style="color: #008080;">Searcher</span> searcher;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 4</span> <span style="color: #008080;">SearchToken</span> token;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 5</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 6</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 7</span> <span style="color: #0000ff;">using</span> (<span style="color: #008080;">Connection</span> connection = <span style="color: #0000ff;">new</span><span style="color: #008080;">Connection</span>(<span style="color: #800000;">"dcaw"</span>, <span style="color: #008080;">DirectoryIdentifierType</span>.Server, <span style="color: #0000ff;">false</span>))</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 8</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 9</span> searcher = <span style="color: #0000ff;">new</span><span style="color: #008080;">Searcher</span>(connection);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 10</span> searcher.PageSize = 1000;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 11</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 12</span> searcher.Constraints = <span style="color: #800000;">"(aNR=a*)"</span>;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 13</span> searcher.NamingContextScope = <span style="color: #008080;">NamingContextScope</span>.IncludeSubDomains;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 14</span> searcher.SearchRoot = <span style="color: #008080;">Constants</span>.<span style="color: #008080;">WellknownDistinguishedNames</span>.RootDse;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 15</span> searcher.ProgressChanged += searcher_ProgressChanged;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 16</span> searcher.FindCompleted += searcher_FindCompleted;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 17</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 18</span> _Event = <span style="color: #0000ff;">new</span><span style="color: #008080;">ManualResetEvent</span>(<span style="color: #0000ff;">false</span>);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 19</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 20</span> searcher.FindPageAsync();</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 21</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 22</span> _Event.WaitOne();</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 23</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 24</span> <span style="color: #008080;">Console</span>.ReadLine();</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 25</span> }</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 26</span> }</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 27</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 28</span> <span style="color: #0000ff;">static</span><span style="color: #0000ff;">void</span> searcher_FindCompleted(<span style="color: #0000ff;">object</span> sender, System.ComponentModel.<span style="color: #008080;">AsyncCompletedEventArgs</span> e)</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 29</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 30</span> <span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Finished"</span>);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 31</span> <span style="color: #0000ff;">if</span> (e.Error != <span style="color: #0000ff;">null</span>) <span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Error: "</span> + e.Error.ToString());</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 32</span> _Event.Set();</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 33</span> }</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 34</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 35</span> <span style="color: #0000ff;">static</span><span style="color: #0000ff;">void</span> searcher_ProgressChanged(<span style="color: #0000ff;">object</span> sender, <span style="color: #008080;">SearchProgressChangedEventArgs</span> e)</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 36</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 37</span> <span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"Found items: "</span> + e.Items.Count);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 38</span> <span style="color: #0000ff;">foreach</span> (<span style="color: #008080;">Item</span> item <span style="color: #0000ff;">in</span> e.Items)</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 39</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 40</span> <span style="color: #008080;">Console</span>.WriteLine(<span style="color: #800000;">"\t"</span> + item.DistinguishedName);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 41</span> }</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 42</span> <span style="color: #008080;">Console</span>.WriteLine();</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 43</span> }</span></p></div><p>If you want to get one page and continue the search at a later point in time (for example from an ASPX page), you can use the SearchToken class to recreate a search operation:</p><div class="clsCode" style="FONT-SIZE: 10pt; BACKGROUND-COLOR: #f0f0f0"><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 1</span> <span style="color: #0000ff;">using</span> (<span style="color: #008080;">Connection</span> connection = <span style="color: #0000ff;">new</span><span style="color: #008080;">Connection</span>(<span style="color: #800000;">"dcaw"</span>, <span style="color: #008080;">DirectoryIdentifierType</span>.Server, <span style="color: #0000ff;">false</span>))</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 2</span> {</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 3</span> searcher = <span style="color: #0000ff;">new</span><span style="color: #008080;">Searcher</span>(connection);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 4</span> searcher.PageSize = 1000;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 5</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 6</span> <span style="color: #008000;">// Create a searcher and perform the initial search</span></span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 7</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 8</span> <span style="color: #008000;">// Now, save the current search token.</span></span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 9</span> token = searcher.SearchToken;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 10</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 11</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 12</span> <span style="color: #008000;">// Create a new search operation from the saved token:</span></span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 13</span> searcher = <span style="color: #0000ff;">new</span><span style="color: #008080;">Searcher</span>(connection, token);</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 14</span> searcher.ProgressChanged += searcher_ProgressChanged;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 15</span> searcher.FindCompleted += searcher_FindCompleted;</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 16</span> </span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 17</span> <span style="color: #008000;">// Continue the search operation</span></span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 18</span> searcher.FindPageAsync();</span></p><p style="PADDING-RIGHT: 0px; MARGIN-TOP: 0px; PADDING-LEFT: 2cm; MARGIN-BOTTOM: 0px; TEXT-INDENT: -2cm"><span style="font-family: Courier New;"><span style="color: #2b91af;"> 19</span> }</span></p></div><p>The SearchToken is marked as serializable, so it can be persisted in the viewstate of an ASPX page.</p></div></div><h2 xmlns="http://www.w3.org/1999/xhtml">The other very interestingly looking classes...</h2><div xmlns="http://www.w3.org/1999/xhtml"><p>There are a number of classes in the library I will discuss in another post... those classes can be used to translate names, or provide a stongly-typed access to properties of ActiveDirectory principals (users, groups), and a search class used to find those principals...</p></div><h2 xmlns="http://www.w3.org/1999/xhtml">Limitations</h2><div xmlns="http://www.w3.org/1999/xhtml">I have barely touched the surface of the SDS.P namespace - the current classes are read-only, meaning that changes to the Item class cannot be written back to to directory. This will come with a later release.</div><h2 xmlns="http://www.w3.org/1999/xhtml">License</h2><div xmlns="http://www.w3.org/1999/xhtml">This library is published as freeware. You may use it in you own programs, commercial or freeware at no cost. You may also modify the classes. All I ask for is that you give credit (a link or something like that) to the InfiniTec website.</div><h2 xmlns="http://www.w3.org/1999/xhtml">Downloads</h2><table xmlns="http://www.w3.org/1999/xhtml"><tr><td><img style="border:none; vertical-align: middle;" src=file.axd?file=directoryservices_helper/zip.gif /></td><td><a href=file.axd?file=directoryservices_helper/Documentation.zip>Documentation.zip</a> (341,126 Bytes)<br />The documentation, as compiled help file</td></tr><tr><td><img style="border:none; vertical-align: middle;" src=file.axd?file=directoryservices_helper/zip.gif /></td><td><a href=file.axd?file=directoryservices_helper/InfiniTec.DirectoryServices_Release.zip>InfiniTec.DirectoryServices_Release.zip</a> (110,671 Bytes)<br />Release binaries, signed with the InfiniTec private key</td></tr><tr><td><img style="border:none; vertical-align: middle;" src=file.axd?file=directoryservices_helper/zip.gif /></td><td><a href=file.axd?file=directoryservices_helper/InfiniTec.DirectoryServices_Source.zip>InfiniTec.DirectoryServices_Source.zip</a> (66,783 Bytes)<br />The source code for this release</td></tr></table>2006-09-02T22:00:00+00:00hkrauseThanks to Joe Kaplan, I spent some time recently playing around with the System.DirectoryServices.Protocols (SDS.P) namespace. The main advantage of this namespace is control and flexibility: The developer decides when to close a connection. What to search, with which scope. This is possible because the SDS.P classes operate at a much lower level than the DirectoryEntry or the DirectorySearcher class.Nothing, however, comes without a price. In this case, the price is usability - There is simply no DirectoryEntry in the SDS.P namespace - one has to do a search with a scope of Base. Not quite simple. Additionally, the only datatypes supported on the properties returned from a search operation are byte[] and string. And no support for generics anywhere...Therefore I created this wrapper around the SDS.P namespace, to make it more usable. Additionally, I included a class to translate names between the various formats used throughout Windows. This class wraps around the DsCrackNames function of the Win32 API, and makes GUID binding trivial - Just translate the security-identifier to the corresponding GUID and bind to the Active Directory object (Yes, I know, the SID can also be used to bind to the Active Directory object - but this is limited to the current domain - one cannot bind to an object outside the current domain).When using this class, you will always start with the connection object. The connection class can either bind to a specific server or to a domain name. Server-less binding is also supported.If you want to perform your own requests using this class, just call the GetSendRequestOperation() which issues the request aynchronously using my InfiniTec.Threading library. This is not trivial if you are not familiar with the library - if you need advice on this topic, drop me a note and I will post an additional article on this topic.The code used is something like this: 1 using (Connection connection = newConnection("entdcsub", DirectoryIdentifierType.Server, false)) 2 { 3 // Do something interesting here... 4 }Once you have connection, you can simply bind to a known object: 1 using (Connection connection = newConnection("dcaw", DirectoryIdentifierType.Server, false)) 2 { 3 item = newItem("CN=Doe\, John, CN=Users, DC=AdventureWorks, DC=local", connection); 4 item.Refresh(); 5 displayName = item.Properties.GetProperty<string>("displayName").Value; 6 }It's as simple as this...The Item class has the following characteristics:... don't panic. The Searcher class will help you here. This class is by far the most complex class in this library:The search operation which will be performed by the Searcher class can be extensively customized. Here are the main option:Constraints - This property accepts a standard LDAP filter like "(mail=*)" or similar.IncludeDeletedItems - If true, deleted items are returned.NamingContextScope - This is important. You can specifiy if you want to search the current naming context only, or search the current and all subordinate contexts.PageSize - Doing a paged search reduces the resources used during the search. This property let you specify the number of items returned per page.PropertiesToLoad - Which properties should be populated during the search?Scope - Do you want to search only the search root, the direct descendents of the searchroot, or all levels below the search root?SearchRoot - Where does the search begin? If NamingContextScope is set to domain scope, a search root must be specified. Otherwise, this property can be left blank. In this case, the entire forest ist searched.SizeLimit - This property lets you specify the maximum number of items you want to get. But you should use this sparingly - if more items are returned than specified here, an exception is thrown.SortKeys - Very handy. This allows server-side sorting of the result setTo start a search, populate the desired fields and call FindAll or FindPage. The first method, performs the search and returns once the search is completed. The FindPage method returns once the next page of items is returned by the server.For scalability reaonse, you should use the FindAllAsync and FindPageAsync methods - these methods return immediately and thus don't block the current thread. The FindCompleted and ProgressChanged events are fired, whenever an operation completes.The following example performs an ambiguous name resolution and finds all entries which start with the character a: 1 staticvoid Main(string[] args) 2 { 3 Searcher searcher; 4 SearchToken token; 5 6 7 using (Connection connection = newConnection("dcaw", DirectoryIdentifierType.Server, false)) 8 { 9 searcher = newSearcher(connection); 10 searcher.PageSize = 1000; 11 12 searcher.Constraints = "(aNR=a*)"; 13 searcher.NamingContextScope = NamingContextScope.IncludeSubDomains; 14 searcher.SearchRoot = Constants.WellknownDistinguishedNames.RootDse; 15 searcher.ProgressChanged += searcher_ProgressChanged; 16 searcher.FindCompleted += searcher_FindCompleted; 17 18 _Event = newManualResetEvent(false); 19 20 searcher.FindPageAsync(); 21 22 _Event.WaitOne(); 23 24 Console.ReadLine(); 25 } 26 } 27 28 staticvoid searcher_FindCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 29 { 30 Console.WriteLine("Finished"); 31 if (e.Error != null) Console.WriteLine("Error: " + e.Error.ToString()); 32 _Event.Set(); 33 } 34 35 staticvoid searcher_ProgressChanged(object sender, SearchProgressChangedEventArgs e) 36 { 37 Console.WriteLine("Found items: " + e.Items.Count); 38 foreach (Item item in e.Items) 39 { 40 Console.WriteLine("\t" + item.DistinguishedName); 41 } 42 Console.WriteLine(); 43 }If you want to get one page and continue the search at a later point in time (for example from an ASPX page), you can use the SearchToken class to recreate a search operation: 1 using (Connection connection = newConnection("dcaw", DirectoryIdentifierType.Server, false)) 2 { 3 searcher = newSearcher(connection); 4 searcher.PageSize = 1000; 5 6 // Create a searcher and perform the initial search 7 8 // Now, save the current search token. 9 token = searcher.SearchToken; 10 11 12 // Create a new search operation from the saved token: 13 searcher = newSearcher(connection, token); 14 searcher.ProgressChanged += searcher_ProgressChanged; 15 searcher.FindCompleted += searcher_FindCompleted; 16 17 // Continue the search operation 18 searcher.FindPageAsync(); 19 }The SearchToken is marked as serializable, so it can be persisted in the viewstate of an ASPX page.http://www.infini-tec.de/pingback.axdhttp://www.infini-tec.de/post.aspx?id=5e9feb7c-1a34-4013-a39d-9b42e28e84bd1http://www.infini-tec.de/trackback.axd?id=5e9feb7c-1a34-4013-a39d-9b42e28e84bdhttp://www.infini-tec.de/post/2006/09/03/A-high-level-wrapper-around-SystemDirectoryServiceProtocols.aspx#commenthttp://www.infini-tec.de/syndication.axd?post=5e9feb7c-1a34-4013-a39d-9b42e28e84bdhttp://www.infini-tec.de/post/2005/08/27/Active-Directory-Helper-library.aspxActive Directory Helper library2005-08-26T22:00:00+00:00hkrause<div xmlns="http://www.w3.org/1999/xhtml"><p>When working with Exchange, it is often necessary to fetch some informations from Active Directory. This helper library has this functionality:</p><ul style="MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px" type="disc"><li>Find a user in a multi-domain forest based on his domain\username.</li><li>Construct the URL for mailbox of a given user, based on his domain\username. This URL can then be used for WebDAV queries.</li><li>Get a DirectorySearcher for the Global Address list and all the other defined address lists</li></ul><p>Full source included, and, believe it or not, documentation :-)</p></div><h2 xmlns="http://www.w3.org/1999/xhtml">Downloads</h2><table xmlns="http://www.w3.org/1999/xhtml"><tr><td><img style="border:none; vertical-align: middle;" src=file.axd?file=activedirectoryhelper/zip.gif /></td><td><a href=file.axd?file=activedirectoryhelper/InfiniTec%20Helper%20Library%20for%20Active%20Directory.zip>InfiniTec Helper Library for Active Directory.zip</a> (52,005 Bytes)<br />Documentation file as CHM file</td></tr><tr><td><img style="border:none; vertical-align: middle;" src=file.axd?file=activedirectoryhelper/zip.gif /></td><td><a href=file.axd?file=activedirectoryhelper/ActiveDirectoryHelperBinaries.zip>ActiveDirectoryHelperBinaries.zip</a> (61,371 Bytes)<br />Binaries, compiled in release version</td></tr><tr><td><img style="border:none; vertical-align: middle;" src=file.axd?file=activedirectoryhelper/zip.gif /></td><td><a href=file.axd?file=activedirectoryhelper/source.zip>source.zip</a> (388,464 Bytes)<br />Full Source</td></tr></table>2005-08-26T22:00:00+00:00hkrauseThis helper library contains several methods for working with Active Directory in conjuction with Exchange 2000/2003http://www.infini-tec.de/pingback.axdhttp://www.infini-tec.de/post.aspx?id=85528b42-37b2-45c1-9c6e-6ec463f8dbd60http://www.infini-tec.de/trackback.axd?id=85528b42-37b2-45c1-9c6e-6ec463f8dbd6http://www.infini-tec.de/post/2005/08/27/Active-Directory-Helper-library.aspx#commenthttp://www.infini-tec.de/syndication.axd?post=85528b42-37b2-45c1-9c6e-6ec463f8dbd6