Active Directory security groups Search application optimization
Let us first review the code.


Stacking usings will reduce the level of indentation.
The Filter of the DirectorySearcher can be passed to the constructor 
If the expected result of the FindAll() call will be huge, you should consider to return only needed properties, by using this overloaded constructor of the DirectorySearcher class.
The SearchResultCollection returned by DirectorySearcher.FindAll() implements the IDisposable interface hence it should be enclosed in a using as well. The remarks section of the documentation states: 


  Due to implementation restrictions, the SearchResultCollection class
  cannot release all of its unmanaged resources when it is garbage
  collected. To prevent a memory leak, you must call the Dispose method
  when the SearchResultCollection object is no longer needed.



Implementing some of this changes could look like so  

DirectoryEntry root = GetDirectoryEntry();
using (var groups = root.Children.Find("OU=Sample Security Groups"))
using (var directory = groups.Children.Find("OU=Permissions"))
using (var searcher = new DirectorySearcher(directory, "filter condition"))
using (var results = searcher.FindAll())
{
    foreach (SearchResult result in results)
    {
        if (result != null)
        {
            using (var group = result.GetDirectoryEntry())
            {
                items.Add((string)group.Properties["sAMAccountName"].Value);
            }
        }
    }
}




If you only need to get the SamAccountName's of the groups a specific user is a member of you can use UserPrincipal.FindByIdentity() like so  

UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain, "domain", "username", "password"), IdentityType.SamAccountName, "loginUser");

foreach (GroupPrincipal group in user.GetGroups())
{
    Console.Out.WriteLine(group.SamAccountName);
}