2

I was working with OU's and just trying to find out

Is there any way I can check whether OU is protected from accidental deletion or not?

I googled it but couldn't found any solution.

I am looking for solution in C# not scripting.

Thanks in advance

sunder
  • 1,803
  • 4
  • 29
  • 50

5 Answers5

2

You need to open the ACL on the object (the ntSecurityDescriptor attribute) and look for a Deny Everyone Delete. The ActiveDirectorySecurity class gives you a managed wrapper around this - http://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectorysecurity.aspx.

Brian Desmond
  • 4,473
  • 1
  • 13
  • 11
1

To protect an AD object there are two ACEs neccessary. One is "deny Delete + DeleteTree" which must be set on the object to protect, the second one "deny DeleteChild" must be set on the parent object. If the protection should removed, only the ACE on the object must deleted. The ACE on the parent object must remain, because otherwise other objects in the same OU will not protected anymore!

Here ist my Code which is working perfectly:

    //using System.Security.Principal
    //using System.DirectoryServices;


    public static void SetProtectADObject(DirectoryEntry ent, bool Protect = true)
    {
        //get parent object
        var parentEnt = new DirectoryEntry(ent.Parent.Path);

        //refresh objects
        ent.RefreshCache();
        parentEnt.RefreshCache();

        if (Protect)
        {
            #region Protect
            try
            {
                IdentityReference everyOneAccount = new NTAccount("Everyone").Translate(typeof(SecurityIdentifier)); //S-1-1-0
                var objAce = new ActiveDirectoryAccessRule(everyOneAccount, ActiveDirectoryRights.Delete | ActiveDirectoryRights.DeleteTree, AccessControlType.Deny);
                var parentAce = new ActiveDirectoryAccessRule(everyOneAccount, ActiveDirectoryRights.DeleteChild, AccessControlType.Deny);

                //check if ace present on object
                var objACL = ent.ObjectSecurity;
                bool acePresent = false;
                foreach (ActiveDirectoryAccessRule ace in objACL.GetAccessRules(true, false, typeof(NTAccount)))
                {
                    if (ace.IdentityReference.Value == "Everyone")
                    {
                        if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteTree | ActiveDirectoryRights.Delete)) { acePresent = true; break; }
                        else if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteChild | ActiveDirectoryRights.DeleteTree | ActiveDirectoryRights.Delete)) { acePresent = true; break; }
                    }
                }

                if (!acePresent)
                {
                    //set ace to object
                    objACL.AddAccessRule(objAce);

                    //commit changes
                    ent.CommitChanges();
                }

                //check if ace present on parent object
                var parentACL = parentEnt.ObjectSecurity;
                bool parentAcePresent = false;
                foreach (ActiveDirectoryAccessRule ace in parentACL.GetAccessRules(true, false, typeof(NTAccount)))
                {
                    if (ace.IdentityReference.Value == "Everyone")
                    {
                        if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteChild)) { parentAcePresent = true; break; }
                        else if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteChild | ActiveDirectoryRights.DeleteTree | ActiveDirectoryRights.Delete)) { parentAcePresent = true; break; }
                    }
                }

                if (!parentAcePresent)
                {
                    //set ace to parent object
                    parentACL.AddAccessRule(parentAce);

                    //commit changes
                    parentEnt.CommitChanges();
                }
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("Error protecting object {0}", ent.Path), ex);
            }
            #endregion
        }
        else
        {
            #region Unprotect
            //to remove the protection we remove only the ACE from the object, not from the parent. 
            //The ACE on the parent must be in place because otherwise other objects on the same level will not protected anymore!

            try
            {
                IdentityReference everyOneAccount = new NTAccount("Everyone").Translate(typeof(SecurityIdentifier)); //S - 1 - 1 - 0
                var objAce = new ActiveDirectoryAccessRule(everyOneAccount, ActiveDirectoryRights.Delete | ActiveDirectoryRights.DeleteTree, AccessControlType.Deny);

                //check if ace present on object
                var objACL = ent.ObjectSecurity;
                bool acePresent = false;
                foreach (ActiveDirectoryAccessRule ace in objACL.GetAccessRules(true, false, typeof(NTAccount)))
                {
                    if (ace.IdentityReference.Value == "Everyone")
                    {
                        if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteTree | ActiveDirectoryRights.Delete)) { acePresent = true; break; }
                        else if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteChild | ActiveDirectoryRights.DeleteTree | ActiveDirectoryRights.Delete)) { acePresent = true; break; }
                    }
                }

                //set ace to object
                if (acePresent)
                {
                    ent.ObjectSecurity.RemoveAccessRule(objAce);
                    ent.CommitChanges();
                }
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("Error unprotecting object {0}", ent.Path), ex);
            }
            #endregion 
        }
    }

    public static bool IsADObjectProtected(DirectoryEntry ent)
    {
        //get parent object
        var parentEnt = new DirectoryEntry(ent.Parent.Path);

        //refresh objects
        ent.RefreshCache();
        parentEnt.RefreshCache();

        //get current ACLs
        ActiveDirectorySecurity acl = ent.ObjectSecurity;
        ActiveDirectorySecurity parentAcl = ent.Parent.ObjectSecurity;
        AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));
        AuthorizationRuleCollection parentRules = parentAcl.GetAccessRules(true, false, typeof(NTAccount));

        //check object acl
        bool acePresent = false;
        foreach (ActiveDirectoryAccessRule ace in rules)
        {
            Console.WriteLine(ace.AccessControlType.ToString());
            if (ace.AccessControlType == AccessControlType.Deny)
            {
                if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteTree | ActiveDirectoryRights.Delete)) { acePresent = true; break; }
                else if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteChild | ActiveDirectoryRights.DeleteTree | ActiveDirectoryRights.Delete)) { acePresent = true; break; }
            }
        }

        //check parent acl
        bool parentAcePresent = false;
        foreach (ActiveDirectoryAccessRule ace in parentRules)
        {
            if (ace.AccessControlType == AccessControlType.Deny)
            {
                if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteChild)) { parentAcePresent = true; break; }
                else if (ace.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteChild | ActiveDirectoryRights.DeleteTree | ActiveDirectoryRights.Delete)) { parentAcePresent = true; break; }
            }
        }

        return parentAcePresent && acePresent;
    }
Marc
  • 21
  • 3
0

Check the systemFlags attribute. The MS page on ADS_SYSTEMFLAG_ENUM there is C++ example, it should be easy to adapt it for C#.

ShaMan-H_Fel
  • 2,139
  • 17
  • 24
  • i am not getting anything in the above but I will try to find the same enum in .net framework and try to convert code...do anyone know anything better. – sunder Aug 08 '12 at 09:52
  • This doesn't reflect the protect from accidental deletion checkbox. System flags will just reflect if the object is prevented from deletion at all (such as a critical system object). – Brian Desmond Aug 08 '12 at 19:40
  • @BrianDesmond you are right, so probably the full solution will be to check the _systemFlags_ **and** _nTSecurityDescriptor_? – ShaMan-H_Fel Aug 09 '12 at 07:50
  • Yes technically - that flag gets set on system objects though so I'm not sure what the OP would be looking at that would make it relevant. – Brian Desmond Aug 10 '12 at 18:56
0

You could do a simple line in powershell with active directory cmdlet Get-ADObject -Filter * -Properties ProtectedFromAccidentalDeletion | where {$_.ProtectedFromAccidentalDeletion -eq $true}

And later if you want to change it - pipe it to | Set-ADObject -ProtectedFromAccidentalDeletion:$false

0

Here is a code snippet for getting the OU and finding the ACL that determines if it is protected from accidental deletion.
This is using the [System.DirectoryServices], [System.Security.AccessControl] and [System.Security.Principal] namespaces

bool? protected = null;
DirectoryEntry de = new DirectoryEntry("LDAP://OU=TestOu,DC=Test,DC=Local", "Username", "Password");
ActiveDirectorySecurity ads = de.ObjectSecurity;
AuthorizationRuleCollection rules = ads.GetAccessRules(true, true, typeof(NTAccount);
foreach (ActiveDirectoryAccessRule rule in rules)
    if (rule.AccessControlType == AccessControlType.Deny)
        if (rule.ActiveDirectoryRights == (ActiveDirectoryRights.DeleteChild | ActiveDirectoryRights.DeleteTree | ActiveDirectoryRights.Delete))
            protected = true;
        else
            protected = false;

I ran this against one of my root OUs with over 150 ACLs applied and it returned the answer in a second or two.

Hive
  • 193
  • 1
  • 4
  • 17