I’ve recently bumped into a need to verify certificates deployed for LDAPS on Active Directory. PowerShell remains my tool of choice for such occasions as this.

It is possible to very simply test an LDAPS connection using ADSI (System.DirectoryServices) as shown below:

$DirectoryEntry = [ADSI]"LDAP://someserver.domain.example"
$DirectoryEntry.AuthenticationType = "Secure, SecureSocketsLayer, ServerBind"

A big red error suggests LDAPS is not avaiable of there is some other problem with the LDAP service. Anything else means the connection must have succeeded. We can infer that SSL negotiation also succeeded since we asked for it. Note that Secure is used to bind using the current users credentials, it is not necessary to provide explicit credentials for this. ServerBind removes any chance of the DCLocator becoming involved.

This method doesn’t really reveal very much unless you run a packet sniffer in parallel. I’m much happier when I can dig a bit deeper.

Happily the System.DirectoryServices.Protocols assembly contains just the tools we need to dig. It contains:

  • A means of defining an LDAP connection with a reasonable amount of detail
  • A way of showing negotiated SSL values such as protocols, hashing algorithms, and so on.
  • A callback delegate which will let us take a look at the certificate used for the connection.

Before we start, System.DirectoryServices.Protocols must be imported into the current session.

Add-Type -Assembly System.DirectoryServices.Protocols

Constructing the LDAP connection is simple. I elected to use the LdapDirectoryIdentifier, it saves a bit of messing around constructing strings describing the end-point.

$ComputerName = "someserver.domain.example"
$Port = 636
$DirectoryIdentifier = New-Object DirectoryServices.Protocols.LdapDirectoryIdentifier(

Next task is to build the LdapConnection object. Using Kerberos as the AuthType allows us to continue without authenticating again.

$Connection = New-Object DirectoryServices.Protocols.LdapConnection($DirectoryIdentifier)
$Connection.AuthType = [DirectoryServices.Protocols.AuthType]::Kerberos

Next a few session options should be set. By default the connection will be plain text and LDAPv2 will be used.

$Connection.SessionOptions.ProtocolVersion = 3
$Connection.SessionOptions.SecureSocketLayer = $true

If you look at the Connection object you should see an SslInformation property. Once we’ve bound to the directory this will be filled with algorithm information assuming SSL is successfully negotiated.

Getting any information about the certificate back needs a Callback Delegate defining for the VerifyServerCertificate property. Happily doing this needs nothing more complex than a ScriptBlock. I’m going to use a global scoped variable to let that return something to the main code block.

New-Variable LdapCertificate -Scope Global -Force
$Connection.SessionOptions.VerifyServerCertificate = {
    $Global:LdapCertificate = $Certificate
    return $true

If you follow the link you’ll find the second argument passed into the delegate is X509Certificate (not X509Certificate2). Happily we can cast from one to the other, this exposes a few more properties we can immediately use.

Having assembled all of that, asking the connection to Bind will connect to the directory service and, hopefully, show us the certificate used.


As with the simple version at the top, a big red error suggests the directory service either doesn’t have a certificate or something else went wrong.

Having bound you can inspect these two to see what happened (note that LdapCertificate is the global variable):

$Connection.SessionOptions.SslInformation $LdapCertificate | Format-List *

Finally, I’ve taken all that and wrapped it into a function which will return that as a handy object.