我正在与 OU 合作,只是想找出答案
有什么方法可以检查 OU 是否受到意外删除的保护?
我用谷歌搜索但找不到任何解决方案。
我正在寻找 C# 中的解决方案而不是脚本。
提前致谢
我正在与 OU 合作,只是想找出答案
有什么方法可以检查 OU 是否受到意外删除的保护?
我用谷歌搜索但找不到任何解决方案。
我正在寻找 C# 中的解决方案而不是脚本。
提前致谢
您需要打开对象(ntSecurityDescriptor
属性)上的 ACL 并查找拒绝所有人删除。该类ActiveDirectorySecurity
为您提供了一个托管包装器 - http://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectorysecurity.aspx。
要保护 AD 对象,需要两个 ACE。一种是“拒绝删除+DeleteTree”,必须在要保护的对象上设置,第二种“拒绝DeleteChild”必须在父对象上设置。如果要删除保护,则只需删除对象上的 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#。
您可以在 powershell 中使用活动目录 cmdlet Get-ADObject -Filter * -Properties ProtectedFromAccidentalDeletion | 执行简单的一行。其中 {$_.ProtectedFromAccidentalDeletion -eq $true}
稍后,如果您想更改它-将其通过管道传输到 | 设置 ADObject -ProtectedFromAccidentalDeletion:$false
这是获取 OU 并查找 ACL 的代码片段,该 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;
我针对我的一个根 OU 运行了这个,应用了超过 150 个 ACL,它在一两秒内返回了答案。