Using System.DirectoryServices.Protocols from Powershell

This simple Powershell module demonstrates how to use robust and powerfull objects from System.DirectoryServices.Protocols (S.DS.P) from Powershell.
4.5 Star
10,337 times
Add to favorites
Active Directory
E-mail Twitter Digg Facebook
  • Proposed improvements
    4 Posts | Last post February 08, 2017
    • From a design perspective, I think it is far better to not intermingle the "bind/connection" with the "search" functionality. Why not split this out to a separate function within the same module?
      That would also allow future extension to create/update/delete objectsion using same connection object via additional functions.
    • Hi Oz,
      this is consolidated reply for your recent posts to different threads below.
      originally, the sample was meant to showcase S.DS.S to support people to switch from ADSI/DirectoryEntry objects. I noticed it gained some popularity - which is great as it shows the original purpose was reached.
      It's tested mostly against AD/AD LDS - while I'm in consulting business, I rarely meet other directories to the extent that would allow to test the script against.
      I also have code samples written that allow adding new objects, and editing and deleting existing - however, did not have enought time to test them to meet expected quality bar.
      Maybe you would be interested in helping with development? I have a workspace on Github, so let's move the source code there, for better cooperation on adding new features by people who have better access to various brands of directory servers.
      This site can still host recent, tested versions for wide public
    • Jiri,
      I've only written very basic code for adding new objects as that was required by my current project.
      Happy to contribute my changes back to a central workspace, and can readily test against some other LDAP implementations (primarily NetIQ eDirectory).
    • Hi Alex,
      I will create a github repo with sources this week and let you know.
      Also, I have some code ready that allows addin/modifying LDAP objects - based on passing dictionary with props. Will create skeleton implementation for you to work on
      Would be great to have someone to test on other LDAP server platforms
  • Retrieve all Properties
    3 Posts | Last post February 04, 2017
    • Hi Jiri,
      Working with the -propertiestoLoad:@() parameter how would you retrieve all the properties assigned to an object?
    • Hi Lachlan,
      well, current implementation expects that you ask for specific properties and returns list of objects with those properties, forming a table. when retrieving all available props, output would not be a table as objects may have different props defined.
      However, let me look at this request; I may implement it in next versio of cmdlet
    • I have played a bit with tweaking the code to retrieve all properties assigned to an object.
      There are some significant downsides with this approach. Jiri covered some of these,
      However one additional issue is regarding constructed attributes. Constructed attributes are only returned if you request them. If you simply query for all attributes on an object, these attributes will never be returned. One must explicitly request them if they wish to see them.
  • find-ldapobject returning empty results
    3 Posts | Last post January 12, 2017
    • I have a rather complex ldap setup that includes certificates and authentication.  I have been able to get the connection to successfully bind and I can send requests.  So I used the find-ldapobject commandlet to return the results
      However, when I return the results using the line: 
      $results = find-ldapobject -ldapconnection $LDAPconnection -searchfilter "(ou=arch,*)" -searchbase "ou=people,dc=umich,dc=edu" -pagesize 0 -PropertiesToLoad @("cn","mobile") | select-object *
      I get a bunch of blank lines.  It seems to be working because when I limit the query down to 1 result, it only returns 1 blank line.  When it is set to the ou=arch,*  it returns about the number of blank lines as people in the ou.
      I had to set the pagesizse to 0 because when I ran it with the pagesize of 100, it said 0
      Exception calling "SendRequest" with "2" argument(s): "The server does not support the control. The control is critical."  So 0 (non-paged) seemed to be the only option.
      I know cn and mobile are valid properties because I can see them when I connect to the ldap directory with Windows' LDAPAdmin.exe
    • Hi Jeff,
      hard to tell what's wrong in your case - generally it is expected to work against any LDAP server (I tested against AD and AD LDS, and I have successful reports from non-MS LDAP servers usage as well)
      If you give me remote access to your lab, I will give it some time to debug to see what's wrong there.
      Regarding not supported controls: yes, different LDAP servers support different controls, so this error is expected for servers that do not support this control
    • As a feature request, the code should interrogate the supported controls for the specified LDAP server and gracefully degrade if some options are not supported. The current implementation seems mostly tested against AD which supports several controls (and authentication mechanisms) that aren't widely used elsewhere.
  • Converting type of results (objectSID, msRTCSIP-originatorSID...)
    2 Posts | Last post December 05, 2016
    • Hi,
      Thanks for this great script, it helps a lot.
      Just one question. When I do this request :
      Find-LdapObject -searchFilter:"(displayname=TEST*)" -searchBase:"DC=xxxx,DC=xxxx,DC=xx" -LdapServer:"xxxxx" -PageSize 1000 -propertiesToLoad:@("objectsid")
      It returns that :
      objectsid                               distinguishedName
      ---------                               -----------------
      ☺♣     ♣§   ??~/???L?;+☻?☻             CN=XXXXXXX,OU=XXXX,DC=XXXXX,DC=XXXX,...
      ☺♣     ♣§   ??~/???L?;+►?☻             CN=YYYYYYY,OU=YYYY,DC=YYYYY,DC=YYYY,...
      ☺♣     ♣§   ??~/???L?;+??♦             CN=ZZZZZZZ,OU=ZZZZ,DC=ZZZZZ,DC=ZZZZ,...
      How to translate objectSID to something readable (like 00 1F 2C 00 ... or S-1-5-21-14544...) ?
    • Hello AT,
      try like this:
      Find-LdapObject -searchFilter "(&(objectClass=user)(objectSid=*))" -searchBase "dc=xx,dc=xy,dc=yz" -PropertiesToLoad @("objectSid") -BinaryProperties @("objectSid") | %{$_.objectSid=new-object System.Security.Principal.SecurityIdentifier($_.objectSid,0);$_}
      - SID is binary value, so you need to instruct cmdlet to treat it as binary - do it by passing the objectSid property name in both PropertiesToLoad and BinaryProperties parameter
      - to get real SID, you need to transform binary data fetched to SID - I just do it by constructing .NET SecurityIdentifier object using the binary data retrieved from AD
      Hope this helps,
  • Not sure how to build the credential
    3 Posts | Last post May 27, 2016
    • Hi Jiri,
      Thanks for this script, it seems to work great against the domain my host machine lives on.  
      Unfortunately when I try to target a specific LDAP server outside my domain, I'm having issues getting it to accept a -Credential.  I tried using Get-Credential, but it appears the module is looking for a System.String value rather than a System.Management.Automation.PSCredential.
      Can you tell me what format to put my username/password in for the -Credential parameter to digest it properly?
    • Hi Justen,
      actually, type of Credential parametr is [System.Net.NetworkCredential]. You build it with one of constructors available, as described here:
      Such as $cred=new-object System.Net.NetworkCredential("MyUserName", "myPassword", "myDomain")
      Hope this helps,
    • That was exactly it!  Thanks Jiri, hopefully my question wasn't too silly.
  • Getting error while import on 2008R2 DC
    2 Posts | Last post May 24, 2016
    • Hello Jiri,
      When i try to import this module in 2008R2 DC i am getting the below error message in powershell
      PS C:\> import-module .\S.DS.P.psd1
      Import-Module : The 'C:\S.DS.P.psd1' module cannot be imported because its manifest contains one or more members that a
      re not valid. The valid manifest members are ('ModuleToProcess', 'NestedModules', 'GUID', 'Author', 'CompanyName', 'Cop
      yright', 'ModuleVersion', 'Description', 'PowerShellVersion', 'PowerShellHostName', 'PowerShellHostVersion', 'CLRVersio
      n', 'DotNetFrameworkVersion', 'ProcessorArchitecture', 'RequiredModules', 'TypesToProcess', 'FormatsToProcess', 'Script
      sToProcess', 'PrivateData', 'RequiredAssemblies', 'ModuleList', 'FileList', 'FunctionsToExport', 'VariablesToExport', '
      AliasesToExport', 'CmdletsToExport'). Remove the members that are not valid ('RootModule'), then try to import the modu
      le again.
      At line:1 char:14
      + import-module <<<<  .\S.DS.P.psd1
          + CategoryInfo          : InvalidData: (C:\S.DS.P.psd1:String) [Import-Module], InvalidOperationException
          + FullyQualifiedErrorId : Modules_InvalidManifestMember,Microsoft.PowerShell.Commands.ImportModuleCommand
      Could you please let me know why ?
    • Hi Meera,
      most likely your DC is still using older version of PowerShell. Just replace 'RootModule' keyword by 'ModuleToProcess' keyword and give it a try
      PowerShell team replaced ModuleToProcess by RootModule keyword in PowerShell 3.0 and newer (ModuleToProcess is still there for backward compatibility)
      And yes, you're right - I've forgotten to update required PS Host version accordingly. Will upload updated version soon)
      Hope this helps,
  • Cannot connect
    4 Posts | Last post December 02, 2015
    • Hi, first sorry for asking a noobish question, but I can't make this cmdlet to work for me. I have an LDAP, that allows anonymous binds, and I cannot connect to it with the following:
      Find-LdapObject -LdapServer ldapserver01 -searchBase "ou=Users,dc=domain,dc=com" -searchFilter "(uid=myusername)"
      It's the same if I try to auth as user, adding username and password.
      The error I always recieve is Exception calling "SendRequest" with "2" argument(s): "An unknown error occurred."
      At C:\Windows\system32\WindowsPowerShell\v1.0\Modules\S.DS.P\S.DS.P.psm1:245 char:17
      +                 $rsp = $LdapConnection.SendRequest($rq, (new-object System.Times ...
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
          + FullyQualifiedErrorId : DirectoryOperationException
      Which I see is realted to psm1 of the module, but I don't know what's wrong. I get the same error when I try to connect with Basic auth.
      Thanks in advance!
    • Hello,
      hard to tell what may be wrong with the connection. Exception thrown from SendRequest() contains error passed by underlying LDAP provider, and is not helpful in this case.
      I guess your LDAP server is not a MS LDAP (AD/ADAM)? I did not test with 3rd party LDAP servers; I have feedback from users of this module it works for them with 3rd party.
      In case it's MS LDAP, please share your configursation details, I will look for repro
    • No, it's not, it's openLDAP, but it allows anonymous cotions and I get results just running ldapsearch on Linux (#ldapsearch -x -h ldapserver01 -b "dc=domain,dc=com". Also, Windows tool call LDAPSearch (GUI app) works fine as well, but my idea was to get data from PowerShell and then use EPPlus to format it in Excel. 
      Do you have any references besides than comments here of users using it with OpenLDAP? Really don't want to switch to another solution, this one seems just fine from the start :)
    • Never tested with OpenLDAP; will look into it when time permits. If you have an interface to bind to, I will test against
  • Looking up every object it finds?
    2 Posts | Last post October 23, 2015
    • So I have to ask, I can run a single LDAP query using same directoryservices dirsearcher etc. and before I findall simply add all the properties to load. If I run it with 3 properties, it's scrolling so fast you can't read it yet with your module looking at the code I had to ask why on earth such good structure yet you perform the initial search using standard passed LDAP filter (ie. (&(objectClass=user)(objectCategory=Person)) ) yet then your code loops through the results and THEN performs ANOTHER query on every DN to get whatever properties.  Why?
      Add the properties make it a single query with 3 or 30 however many, execute it once get the 9000 results in an array or hash table.  Now, you perform 9001 queries 1 to get the list and 9000 lookups and it's really slow.
      Thoughts/comments?  I love the function I think it's cleanly written but I can't for the life of me figure out why the mult calls and would love to hear your thought process behind it maybe I'm just missing something!
    • Hi Collin,
      thanks for thinking on the article and apologies for answering that late - notification about your post got lost among other emails.
      Reasons why I developed script the way it is are:
      - multivalued propertis: search that returns multiple objects is subject of MaxValRange LDAP Query policy, so multival props with large amount of vals may never return all the pop unless loaded via ranged property retrieval as demostrated in this sample
      - computed props: they aren't returned unless baseDN is object itself
      So the script offers slower performance, but at the same time guaranteed results and unified behavior.
      BTW performance is not that bad anyway (on fast network) - see measurement Steve Renard recently performed:
      Hope this will help,
  • Comment and Feature Request
    1 Posts | Last post October 20, 2015
    • Great script.  I've added a few items to make it work in my mixed AD/eDirectory environment such as the "Determine if using AD" code below.  I needed this because eDirectory had issue when using "range=" as part of the attribute name during a search -- nothing was returned.  
      I'd like to see an Add and Delete Object Function.  
      Keep up the good work.
      # Determine if using AD
      $ADInUse = $False
      $rq=New-Object System.DirectoryServices.Protocols.SearchRequest
      $rq.Filter = "(objectClass=*)"
      $rq.Scope = [System.DirectoryServices.Protocols.SearchScope]::Base
      $rq.Attributes.Add("highestCommittedUSN") | Out-Null
      $rsp = $LDAPConnection.SendRequest($rq, (New-Object System.Timespan(0,0,$TimeoutSeconds))) -as [System.DirectoryServices.Protocols.SearchResponse];		
      If ([int]$rsp.Entries[0].Attributes.count -gt 0) { $ADInUse = $True;Write-Verbose "Using Active Directory" -Verbose}
  • How do you load this?
    2 Posts | Last post September 02, 2014
    • I apologize for not knowing this, but I'm NOT a programmer. However, this is exactly what I'm looking for. Something that can simply connect over TCP 389 regardless of it's Active Directory, OpenLDAP, eDirectory, iPlanet, etc. The thing is... I'm not sure if I just open a powershell console, import-module of this or what? It isn't working as it should so obviously I'm doing something wrong. Could you offer a little more guidance on how to get this working?
    • Hello,
      usage is pretty simple:
      - you just create folder %Systemroot%\system32\WindowsPowershell\v1.0\Modules\S.DS.P
      - download the file from here
      - extract both files in downloaded archive into newly created folder
      - open PowerShell window
      - run cmdlet Import-Module S.DS.P
      - and you're ready (you may need to set PS execution policy to something like RemoteSigned so as the module could load
      You can then use Find-LdapObject cmdlet to connect to any LDAP server and fetch data from it - see examples in the article
      Do you receive any errors or why it does not work for you?
      Hope this helps,
11 - 20 of 21 Items