检查 OU 是否受到保护以防止意外删除



>我正在与OU合作,只是想找出答案

有什么方法可以检查OU是否受到保护以防止意外删除?

我用谷歌搜索了它,但找不到任何解决方案。

我正在寻找 C# 而不是脚本的解决方案。

提前致谢

您需要

打开对象上的 ACL(ntSecurityDescriptor 属性)并查找拒绝所有人删除。ActiveDirectorySecurity类为您提供了一个围绕此的托管包装器 - http://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectorysecurity.aspx。

若要保护 AD 对象,需要两个 ACE。一个是"拒绝删除+删除树",必须在要保护的对象上设置,第二个是"拒绝删除子"必须在父对象上设置。如果应删除保护,则只需删除对象上的 ACE。父对象上的 ACE 必须保留,否则同一 OU 中的其他对象将不再受保护!

这是我的代码,它运行良好:

    //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;
    }

检查 systemFlags 属性。ADS_SYSTEMFLAG_ENUM上的 MS 页面有C++示例,应该很容易将其适应 C#。

您可以使用 active directory cmdlet 在 powershell 中执行简单的行获取 ADObject -过滤器 * -属性保护免受意外删除 |其中 {$_.ProtectedPreventAccidentalDelete-eq $true}

稍后,如果您想更改它 - 将其管道传输到 |设置-ADObject -保护免受意外删除:$false

下面是一个代码片段,用于获取 OU 并查找确定其是否受到保护以防止意外删除的 ACL。
这是使用 [System.DirectoryServices]、[System.Security.AccessControl] 和 [System.Security.Principal] 命名空间。

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;

我对应用了 150 多个 ACL 的根 OU 之一运行了这个,它在一两秒钟内返回了答案。

最新更新