none
Reset password with History resulting in - "The server does not support the control. The control is critical." RRS feed

  • Question

  • I've followed what I believe to be the right steps from this article (only in powershell). I can't however get it to work. I've tried both controls and verified through adsiedit and ldp that I have both controls that I need. I'm sure I'm missing something quit simple here but would appreciate some help.

    supportedControl (35):
      1.2.840.113556.1.4.2239 = ( POLICY_HINTS ); 
      1.2.840.113556.1.4.2066 = ( POLICY_HINTS_DEPRECATED );

    When I set isCritical ("1.2.840.113556.1.4.2239", $byte, $true, $true) to true I get a failure of ...

    Exception: System.Management.Automation.MethodInvocationException: Exception calling "SendRequest" with "1" argument(s): "The server does not support the control. The control is critical." ---> 
    	System.DirectoryServices.Protocols.DirectoryOperationException: The server does not support the control. The control is critical.
    	   at System.DirectoryServices.Protocols.LdapConnection.ConstructResponse(Int32 messageId, LdapOperation operation, ResultAll resultType, TimeSpan requestTimeOut, Boolean exceptionOnTimeOut)
    	   at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)
    	   at CallSite.Target(Closure , CallSite , Object , Object )
    	   --- End of inner exception stack trace ---
    	   at System.Management.Automation.ExceptionHandlingOps.ConvertToMethodInvocationException(Exception exception, Type typeToThrow, String methodName, Int32 numArgs, MemberInfo memberInfo)
    	   at CallSite.Target(Closure , CallSite , Object , Object )
    	   at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
    	   at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
    	   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

    When I don't set isCritical ("1.2.840.113556.1.4.2239", $byte, $false, $true) I get a Success returned but the password hasn't been changed.

    RequestId    : 
    MatchedDN    : 
    Controls     : {}
    ResultCode   : Success
    ErrorMessage : 
    Referral     : {}

    This is what I'm doing

    [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") | Out-Null [System.Reflection.Assembly]::LoadWithPartialName("System.Net") | Out-Null $SDPServer = $srv $SDPPort = 636 $SDPConnection = New-Object System.DirectoryServices.Protocols.LdapConnection -ArgumentList "$($SDPServer):$($SDPPort)" #Set session options $SDPConnection.SessionOptions.SecureSocketLayer = $true; $SDPConnection.SessionOptions.VerifyServerCertificate = { return $true;} #needed for self-signed certificates $SDPConnection.SessionOptions.ProtocolVersion = 3; $SDPConnection.AuthType = [System.DirectoryServices.Protocols.AuthType]::Basic #$SDPConnection.AuthType = [System.DirectoryServices.Protocols.AuthType]::Ntlm $netcred = new-object "System.Net.NetworkCredential" -ArgumentList $adsvc, $adpwd, $domain $SDPConnection.Bind($netcred) [byte]$byte = "0x1" #$control = new-object "System.DirectoryServices.Protocols.DirectoryControl" -ArgumentList "1.2.840.113556.1.4.2066", $byte, $true, $true $control = new-object "System.DirectoryServices.Protocols.DirectoryControl" -ArgumentList "1.2.840.113556.1.4.2239", $byte, $true, $true $request = new-object "System.DirectoryServices.Protocols.ModifyRequest" -ArgumentList $userDN $request.Controls.Add($control) | Out-Null $modification = New-Object "System.DirectoryServices.Protocols.DirectoryAttributeModification" $modification.Name = "userPassword" $modification.Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Replace $modification.Add($usrpwd) | Out-Null $request.Modifications.Add($modification) | Out-Null $result = $SDPConnection.SendRequest($request); $result

    Thursday, June 9, 2016 2:59 PM

Answers

  • The PoSh

    function TranslateEx([System.Exception] $ex)
    {
        try
        {
            [System.DirectoryServices.Protocols.DirectoryOperationException] $doex =  [System.DirectoryServices.Protocols.DirectoryOperationException] $ex

            [System.DirectoryServices.Protocols.DirectoryResponse] $err = $doex.Response

           
            Write-Host "Update pwd result: $($doex.Response.ResultCode.ToString())"
            [string] $hexstring = $doex.Response.ErrorMessage.Split(":")[0]
           
            [int] $hexint = -1
            try
            {
                $hexint = [System.Convert]::ToInt32($hexstring, 16)
            }
            catch { $hexint = -1 }
            $hexint
            if ($hexint -ne -1)
            {
           
                try
                {
                    [System.ComponentModel.Win32Exception] $wex = New-Object System.ComponentModel.Win32Exception -ArgumentList $hexint
                   
                    Write-Host "$($wex.Message) ($($doex.Response.ErrorMessage)) [$($doex.Message)]"
                }
                catch
                {
                    Write-Host "$($doex.Response.ErrorMessage) [$($doex.Message)]"
                }
            }
        }
        catch
        {
            $_.Exception
            "Unknown exception: $ex"
        }
    }
    function BuildBytePwd([string] $pwd)
    {
        [byte[]] $ret = $null
        [string] $formattedpwd = [char]34 + $pwd + [char]34
       
        $ret = [System.Text.Encoding]::Unicode.GetBytes($formattedpwd)
       
        return $ret
    }
    [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") | Out-Null
    [System.Reflection.Assembly]::LoadWithPartialName("System.Net") | Out-Null
    $SDPServer = $srv
    $SDPPort = 636
    [System.DirectoryServices.Protocols.LdapConnection] $SDPConnection = New-Object System.DirectoryServices.Protocols.LdapConnection -ArgumentList "$($SDPServer):$($SDPPort)"
    $SDPConnection.SessionOptions.ProtocolVersion = 3
    $SDPConnection.SessionOptions.SecureSocketLayer = $true
    $SDPConnection.SessionOptions.VerifyServerCertificate = { return $true;} #needed for self-signed certificates
    $SDPConnection.SessionOptions.QueryClientCertificate = { return $null; }
    $SDPConnection.AuthType = [System.DirectoryServices.Protocols.AuthType]::Basic
    $netcred = new-object "System.Net.NetworkCredential" -ArgumentList $adsvc, $adpwd, $domain
    $SDPConnection.Bind($netcred)
    [object[]] $berval = [object[]] ( 0x1 )
    [byte[]]$byte = [System.DirectoryServices.Protocols.BerConverter]::Encode("{i}", $berval);
    #[System.DirectoryServices.Protocols.DirectoryControl] $control = new-object System.DirectoryServices.Protocols.DirectoryControl -ArgumentList "1.2.840.113556.1.4.2066", $byte, $false, $true
    [System.DirectoryServices.Protocols.DirectoryControl] $control = new-object System.DirectoryServices.Protocols.DirectoryControl -ArgumentList "1.2.840.113556.1.4.2239", $byte, $false, $true
    [System.DirectoryServices.Protocols.ModifyRequest] $request = new-object System.DirectoryServices.Protocols.ModifyRequest -ArgumentList $userDN
    $request.Controls.Add([System.DirectoryServices.Protocols.DirectoryControl]$control) | Out-Null
    [System.DirectoryServices.Protocols.DirectoryAttributeModification] $modification = New-Object System.DirectoryServices.Protocols.DirectoryAttributeModification
    $modification.Name = "unicodePwd"
    $modification.Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Replace
    [byte[]] $bpwd = BuildBytePwd $usrpwd
    $modification.Add($bpwd) | Out-Null
    $request.Modifications.Add($modification) | Out-Null
    try
    {
        [System.DirectoryServices.Protocols.DirectoryResponse] $result = [System.DirectoryServices.Protocols.DirectoryResponse]$SDPConnection.SendRequest($request);
        $result
    }
    catch
    {
        TranslateEx $_.Exception.GetBaseException()
    }


    Tuesday, August 2, 2016 2:52 PM

All replies

  • I switched from using "userPassword" to using "unicodePWD" and am now getting a different error.

    Exception: System.Management.Automation.MethodInvocationException: Exception calling "SendRequest" with "1" argument(s): "The server cannot handle directory requests." ---> 
    System.DirectoryServices.Protocols.DirectoryOperationException: The server cannot handle directory requests.
       at System.DirectoryServices.Protocols.LdapConnection.ConstructResponse(Int32 messageId, LdapOperation operation, ResultAll resultType, TimeSpan requestTimeOut, Boolean exceptionOnTimeOut)
       at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)
       at CallSite.Target(Closure , CallSite , Object , Object )
       --- End of inner exception stack trace ---
       at System.Management.Automation.ExceptionHandlingOps.ConvertToMethodInvocationException(Exception exception, Type typeToThrow, String methodName, Int32 numArgs, MemberInfo memberInfo)
       at CallSite.Target(Closure , CallSite , Object , Object )
       at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
       at System.Management.Automation.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
       at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
    Again any and all help would be appreciated

    Thursday, June 9, 2016 5:52 PM
  • Hi GeoffGin,

    Thanks for your post.

    Did you use the ActiveDirectoryMembershipProvider class in an ASP.NET 2.0 application?

    If yes, the problem may be caused by ASP.NET 2.0 tries to put a Lightweight Directory Access Protocol (LDAP) connection into fast bind mode. However, because the LDAP connection is already bound to the directory service, the LDAP connection cannot be put into fast bind mode. Therefore, the directory request fails.

    To fix the problem, a supported hotfix is available from Microsoft.

    For more information, you could refer to the article below.

    FIX: DirectoryOperationException exception when you use the ActiveDirectoryMembershipProvider class in an ASP.NET 2.0 application: "The server cannot handle directory requests

    https://support.microsoft.com/en-us/kb/969876

    Best Regards,

    Jay


    Please remember to mark the replies as answers if they help and un-mark them if they provide no help. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    Monday, June 13, 2016 6:25 AM
    Moderator
  • Hi Jay,

    Thanks for the response, I'm not using asp.net client side also the client is on 2012r2. Any other thoughts?

    Tuesday, June 14, 2016 3:37 PM
  • Hi Geoff,
    sorry that I haven't seen your query before.

    Several things need to be changed in your PoSh:
        - You cannot use userPassword attribute to modify pwd -> you must use unicodePwd attribute

        - the pwd cannot be passed as string - it must be passed as byte array of the formatted pwd -> format should be double-quote + pwd + double-quote
           (see BuildbytePwd function)
        - the DirectoryControl for honoring pwd history is NOT critical -> don't use $true for the critical parameter in the DirectoryControl constructor

        - you should inspect the exception thrown - "The server cannot handle directory requests." will be thrown even if the operation worked and we get an error because of pwd history violation...
           (see TranslateEx function)

    see adjusted PoSh code (tested in my Lab) in the second post

    best regards

    Michael

    PFE | Have keyboard. Will travel.

    • Marked as answer by GeoffGin Tuesday, August 2, 2016 3:46 PM
    • Unmarked as answer by GeoffGin Tuesday, August 2, 2016 3:46 PM
    Tuesday, August 2, 2016 2:50 PM
  • The PoSh

    function TranslateEx([System.Exception] $ex)
    {
        try
        {
            [System.DirectoryServices.Protocols.DirectoryOperationException] $doex =  [System.DirectoryServices.Protocols.DirectoryOperationException] $ex

            [System.DirectoryServices.Protocols.DirectoryResponse] $err = $doex.Response

           
            Write-Host "Update pwd result: $($doex.Response.ResultCode.ToString())"
            [string] $hexstring = $doex.Response.ErrorMessage.Split(":")[0]
           
            [int] $hexint = -1
            try
            {
                $hexint = [System.Convert]::ToInt32($hexstring, 16)
            }
            catch { $hexint = -1 }
            $hexint
            if ($hexint -ne -1)
            {
           
                try
                {
                    [System.ComponentModel.Win32Exception] $wex = New-Object System.ComponentModel.Win32Exception -ArgumentList $hexint
                   
                    Write-Host "$($wex.Message) ($($doex.Response.ErrorMessage)) [$($doex.Message)]"
                }
                catch
                {
                    Write-Host "$($doex.Response.ErrorMessage) [$($doex.Message)]"
                }
            }
        }
        catch
        {
            $_.Exception
            "Unknown exception: $ex"
        }
    }
    function BuildBytePwd([string] $pwd)
    {
        [byte[]] $ret = $null
        [string] $formattedpwd = [char]34 + $pwd + [char]34
       
        $ret = [System.Text.Encoding]::Unicode.GetBytes($formattedpwd)
       
        return $ret
    }
    [System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols") | Out-Null
    [System.Reflection.Assembly]::LoadWithPartialName("System.Net") | Out-Null
    $SDPServer = $srv
    $SDPPort = 636
    [System.DirectoryServices.Protocols.LdapConnection] $SDPConnection = New-Object System.DirectoryServices.Protocols.LdapConnection -ArgumentList "$($SDPServer):$($SDPPort)"
    $SDPConnection.SessionOptions.ProtocolVersion = 3
    $SDPConnection.SessionOptions.SecureSocketLayer = $true
    $SDPConnection.SessionOptions.VerifyServerCertificate = { return $true;} #needed for self-signed certificates
    $SDPConnection.SessionOptions.QueryClientCertificate = { return $null; }
    $SDPConnection.AuthType = [System.DirectoryServices.Protocols.AuthType]::Basic
    $netcred = new-object "System.Net.NetworkCredential" -ArgumentList $adsvc, $adpwd, $domain
    $SDPConnection.Bind($netcred)
    [object[]] $berval = [object[]] ( 0x1 )
    [byte[]]$byte = [System.DirectoryServices.Protocols.BerConverter]::Encode("{i}", $berval);
    #[System.DirectoryServices.Protocols.DirectoryControl] $control = new-object System.DirectoryServices.Protocols.DirectoryControl -ArgumentList "1.2.840.113556.1.4.2066", $byte, $false, $true
    [System.DirectoryServices.Protocols.DirectoryControl] $control = new-object System.DirectoryServices.Protocols.DirectoryControl -ArgumentList "1.2.840.113556.1.4.2239", $byte, $false, $true
    [System.DirectoryServices.Protocols.ModifyRequest] $request = new-object System.DirectoryServices.Protocols.ModifyRequest -ArgumentList $userDN
    $request.Controls.Add([System.DirectoryServices.Protocols.DirectoryControl]$control) | Out-Null
    [System.DirectoryServices.Protocols.DirectoryAttributeModification] $modification = New-Object System.DirectoryServices.Protocols.DirectoryAttributeModification
    $modification.Name = "unicodePwd"
    $modification.Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Replace
    [byte[]] $bpwd = BuildBytePwd $usrpwd
    $modification.Add($bpwd) | Out-Null
    $request.Modifications.Add($modification) | Out-Null
    try
    {
        [System.DirectoryServices.Protocols.DirectoryResponse] $result = [System.DirectoryServices.Protocols.DirectoryResponse]$SDPConnection.SendRequest($request);
        $result
    }
    catch
    {
        TranslateEx $_.Exception.GetBaseException()
    }


    Tuesday, August 2, 2016 2:52 PM
  • Thanks Michael better late than never :),

    I quickly realized that unicodePwd was required and adjusted afterwards. I also realized the critical wasn't required. The pieces that I missed was the exception and bit encoding. I've actually moved this work to a web frontend/js backend (nodejs/ldajs) but I'll give your code a shot shortly. 

    Thanks again and I found your article very informative.

    Tuesday, August 2, 2016 3:43 PM
  • :-)

    Forgot to mention another important thing -> the byte[] value for the DirectoryControl must be BerEncoded from 0x1 (like it's done in the sample).

    The byte[] looks then like this: 48   132   0   0   0   3   2   1   1

    Tuesday, August 2, 2016 4:31 PM