title: Active Directory seems to return cached information
body: <p>We have an in-house windows console application that we use to update our Active Directory. This app has been running successfully for several years.</p>
  
  <p>Recently I was tasked to add code to disable users that have not logged in to the system in over 90 days.</p>
  
  <p>The code seems to be working correctly except that some users appear every time the app runs.</p>
  
  <p>Here is the search code:</p>
  
  <pre><code>public SearchResultCollection SearchAD(string szSearchOU, string szSearchArg, string szObjectClass)
  {
          if (szSearchOU == "")
          {
              ds.SearchRoot = c_DirectoryEntry;
          }
          else
          {
              if (!szSearchOU.StartsWith("LDAP://"))
              {
                  szSearchOU = "LDAP://" + szSearchOU;
              }
              ds.SearchRoot = new DirectoryEntry(szSearchOU);
          }
  
          string szFilter = "";
          if (szObjectClass == "")
              szFilter = "(objectClass=user)";
          else
              szFilter = "(objectClass=" + szObjectClass + ")";
          if (szSearchArg != "")
          {
              if (szSearchArg.Substring(0, 3) != "CN=")
                  szSearchArg = "CN=" + szSearchArg;
              szFilter = "(&amp;" + szFilter + "(" + szSearchArg + "))";
          }
          else
              ds.PageSize = 1001;
          ds.Filter = szFilter;
          SearchResultCollection results = ds.FindAll();
          return results;
   }
  </code></pre>
  
  <p>This method is used throughout the application so I am reasonably certain that it works OK.</p>
  
  <p>Here is the stub that calls the search and processes it:</p>
  
  <pre><code>SearchResultCollection src = SearchADUsers(szOU, "");
  clsDisableLog.WriteLog("Processing: " + src.Count.ToString());
  foreach (SearchResult r in src)
  {
      DirectoryEntry deUser = r.GetDirectoryEntry();
      if (c_Debug)
          clsDisableLog.WriteLog("Processing: " + deUser.Name + " Path: " + deUser.Path.ToString());
      PropertyCollection userAttribs = deUser.Properties;
      int flags = (int)deUser.Properties["userAccountControl"].Value;
      if (!Convert.ToBoolean((flags &amp; UF_DISABLED) == UF_DISABLED))
      {
          bool bDisableAccount = false;
          DateTime dLastLogon = GetLastLogon(deUser);
          if (dLastLogon != DateTime.MinValue)
          {
              TimeSpan diff = DateTime.Now - dLastLogon;
              int iDaysSince = diff.Days;
              if (iDaysSince &gt; iDays)
              {
                  clsDisableLog.WriteLog("\t" + deUser.Name);
                  clsDisableLog.WriteLog("\t\t" + "Has not logged in for " + iDaysSince.ToString() + " days.");
                  clsDisableLog.WriteLog("\t\t" + "Last logon date: " + dLastLogon.ToLongDateString() + " " + dLastLogon.ToLongTimeString());
                  clsDisableLog.WriteLog("\t\t" + deUser.Path.ToString());
                  bDisableAccount = true;
              }
          }
          else
          {
              clsDisableLog.WriteLog("\t" + deUser.Name);
              clsDisableLog.WriteLog("\t\t" + "Has never logged into domain.");
              clsDisableLog.WriteLog("\t\t" + "Created: " + deUser.Properties["whenCreated"].Value.ToString());
              clsDisableLog.WriteLog("\t\t" + deUser.Path.ToString());
              iAccountsNoLogin++;
          }
          if (bDisableAccount)
          {
              if (deUser.Path.Contains("UtilityAccounts"))
              {
                  bDisableAccount = false;
                  clsDisableLog.WriteLog("\t\t" + "NOT Disabling Utility Account: " + deUser.Name);
              }
              else
              {
                  if (UpdateUserFlag(deUser, UF_DISABLED, true))
                  {
                      clsDisableLog.WriteLog("\t\t" + "Disabled");
                      iAccountsDisabled++;
                  }
                  else
                      clsDisableLog.WriteLog("Error disabling " + deUser.Name);
                  if (deUser.Path.ToString().ToLower() != deInactiveOU.Path.ToLower())
                  {
                      if (MoveUser(deUser, deInactiveOU))
                      {
                          clsDisableLog.WriteLog("\t\t" + "Moved to: " + deInactiveOU.Name);
                          iAccountsMoved++;
                      }
                      else
                          clsDisableLog.WriteLog("Error moving " + deUser.Name + " to " + deInactiveOU.Name);
                  }
              }
          }
      }
  </code></pre>
  
  <p>There are about 14 accounts that are processed every time the app runs.</p>
  
  <p>Example:</p>
  
  <pre><code>    2/25/2014 12:56:27 PM:  CN=XXXXXXXX
      2/25/2014 12:56:27 PM:      Has not logged in for 252 days.
      2/25/2014 12:56:27 PM:      Last logon date: Tuesday, June 18, 2013 10:14:45 AM
      2/25/2014 12:56:27 PM:      LDAP://CN=XXXXXXXX,OU=XXXX User Accounts,DC=XXXXXXXX,DC=LOCAL
      2/25/2014 12:56:27 PM:      Disabled
      2/25/2014 12:56:27 PM:      Moved to: OU=Inactive
  </code></pre>
  
  <p>After the app runs, this account IS IN OU=Inactive and IS disabled; however, if I re-run the app, the user shows up again, exactly as here!</p>
  
  <p>Any suggestions?</p>
  
  <p>I have set DS.CacheResults = false however the loop never executes at all if I do that.</p>
  
  <p>Thanks,
  John</p>
  
  <pre><code>    public bool UpdateUserFlag(DirectoryEntry deUser, int iFlag, Boolean bSet)
      {
          bool bReturn = false;
          int flags = (int)deUser.Properties["userAccountControl"].Value;
          try
          {
              if (bSet)
                  deUser.Properties["userAccountControl"].Value = flags ^ iFlag;
              else
                  deUser.Properties["userAccountControl"].Value = flags &amp; ~iFlag;
              deUser.CommitChanges();
              deUser.RefreshCache();
              bReturn = true;
          }
          catch (Exception ex)
          {
              clsLog.WriteLog("Error updating user flag: " + deUser.Name);
              clsLog.Write(ex.Message);
              clsLog.WriteLog("");
          }
          return bReturn;
      }
      public bool MoveUser(DirectoryEntry deUser, DirectoryEntry deOU)
      {
          bool bReturn = false;
          try
          {
              deUser.MoveTo(deOU);
              deUser.CommitChanges();
              deUser.RefreshCache();
              bReturn = true;
          }
          catch (Exception ex)
          {
              clsLog.WriteLog("Error moving: " + deUser.Name.ToString() + " to: " + deOU.Path);
              clsLog.WriteLog(ex.Message);
          }
  
          return bReturn;
  
      }
      public bool MoveUser(DirectoryEntry deUser, string szOU)
      {
          bool bReturn = false;
          try
          {
              deUser.MoveTo(new DirectoryEntry(szOU));
              deUser.CommitChanges();
              deUser.RefreshCache();
              bReturn = true;
          }
          catch (Exception ex)
          {
              clsLog.WriteLog("Error moving: " + deUser.Name.ToString() + " to: " + szOU);
              clsLog.WriteLog(ex.Message);
          }
  
          return bReturn;
      }
  
      public DateTime GetLastLogon(DirectoryEntry deUser)
      {
          DateTime dtLL = DateTime.MinValue;
          try
          {
              if (deUser.Properties["lastLogonTimeStamp"].Count != 0)
                  dtLL = GetDateTimeFromLargeInteger((IADsLargeInteger)deUser.Properties["lastLogonTimeStamp"][0]);
          }
          catch (Exception ex)
          {
              clsLog.WriteLog("Error Retrieving Last Logon Time Stamp for: " + deUser.Name.ToString());
              clsLog.Write(ex.Message);
              clsLog.WriteLog("");
          }
          return dtLL;
      }
  </code></pre>
  
  <p>As per one answer, I have posted the code for the methods called in the stub - although they are not relevant to the question because I have confirmed that they function as necessary. The accounts ARE DISABLED and they ARE moved to the relevant OU. </p>
  
  <p>The issue is NOT that the code is not doing what it is supposed to do - it is that AD finds the users account NOT disabled and NOT in the OU even though I can confirm both using Active Directory Users and Computers.</p>
  
  <p>John</p>