Freigeben über


How to run an Active Directory (AD) cmdlet from .Net (C#)

Technorati Tags: AD,.NET

 

Hi there,

I am Syam Pinnaka, Dev in Identity and Access (IAM) team in Microsoft.  During a recent project, we had a requirement to delete and restore Active Directory (AD) Group objects by leveraging the new “Recycle bin” functionality provided in “Windows Sever 2008 R2”.  This looks like an easy task to start with but proved not so easy to go around when dug into details.  Lets examine the details in this blog post.

There may be a numbers of way to achieve this but here is how I started with.

Use Directory services API and issue a directory object modification request with two simultaneous changes.

  • First change attribute is a delete operation and set “isDeleted” to true and
  • Second change attribute is a replace operation and set ‘DN’ attribute to its original value.

However, this approach didn’t work as it seems like and I have issues getting this to work. So I started looking for alternatives and it didn’t take long to get to Active Directory (AD) PowerShell (PS) cmdlets. I tried using those PS cmdlets and they seems to work perfectly from a cmd prompt. So If I can run these cmdlets from .Net/C# my job is done.

However  the obvious way of “AddPSSnapIn” doesn’t seem to work to load “activedirectory” PS module. “AddPSSnapIn” is to load a powershell snap in where as what I needed was a method to load powershell module. After some search through MSDN and other online forums, I came across “InitialSessionState” and its “ImportPSModule” methods. This class and method is what I am precisely looking for and I could run the “AD” powershell cmdlets from C# when I used them. Here is how the code looks like.

 InitialSessionState iss = InitialSessionState.CreateDefault(); 
 iss.ImportPSModule(new string[] { "activedirectory" }); 
 Runspace myRunSpace = RunspaceFactory.CreateRunspace(iss); 
 myRunSpace.Open();
  
 Pipeline pipeLine = myRunSpace.CreatePipeline(); 
 Command myCommand = new Command("Get-ADObject"); 
 myCommand.Parameters.Add("Filter", "sAMAccountName -eq 'syamp-testSG01'"); 
 myCommand.Parameters.Add("IncludeDeletedObjects");   
  
 pipeLine.Commands.Add(myCommand);
  
 Command restoreCommand = new Command("Restore-ADObject"); 
 pipeLine.Commands.Add(restoreCommand);    
  
 Console.WriteLine("Before Invoke"); 
 Collection<PSObject> commandResults = pipeLine.Invoke(); 
 Console.WriteLine("After Invoke");
  
 foreach (PSObject cmdlet in commandResults) 
 { 
         //Console.WriteLine("Inside foreach");  
         string cmdletName = cmdlet.BaseObject.ToString(); 
         System.Diagnostics.Debug.Print(cmdletName); 
         Console.WriteLine(cmdletName); 
 }
  
 Console.WriteLine("Import-Module ActiveDirectory is loaded successfully!"); 

This has worked like a gem for my scenario and thought would be useful for anyone with a similar scenario. Happy coding!

Comments

  • Anonymous
    August 24, 2015
    awesome. thank goodness someone is working on these types of requirements from real world. this was exactly what i wanted today and i got it. thanks a ton.