【问题标题】:Reading Local Group Policy / Active Directory Settings读取本地组策略/Active Directory 设置
【发布时间】:2026-01-25 16:50:01
【问题描述】:

我正在编写一个 C# 程序,它将根据 Windows 组策略设置“密码必须满足复杂性要求”来强制执行密码复杂性。具体来说,如果该策略在本地计算机(如果它不是域的一部分)或域安全策略(对于域成员)上设置为启用,那么我的软件需要为自己的内部安全强制执行复杂的密码。

问题是我不知道如何读取该 GPO 设置。 Google 搜索表明我可以使用以下两个 API 之一读取 GPO 设置:.NET Framework 中的 System.DirectoryServices 库和 Windows Management Instrumentation (WMI),但到目前为止我还没有成功。

任何见解都会有所帮助。

【问题讨论】:

    标签: c# .net active-directory group-policy


    【解决方案1】:

    似乎没有用于此任务的文档化 API,不管是托管的还是其他的。

    托管尝试

    我使用System.Management 程序集尝试了托管路由:

            ConnectionOptions options = new ConnectionOptions();
            ManagementScope scope = new ManagementScope(@"\\.\root\RSOP\Computer", options);
    
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, new ObjectQuery("SELECT * FROM RSOP_SecuritySettingBoolean"));
            foreach(ManagementObject o in searcher.Get())
            {
                Console.WriteLine("Key Name: {0}", o["KeyName"]);
                Console.WriteLine("Precedence: {0}", o["Precedence"]);
                Console.WriteLine("Setting: {0}", o["Setting"]);
            }
    

    但这不会返回结果。这似乎不是权限问题,因为向 ConnectionOptions 提供用户名/密码对会导致异常告诉您在本地连接时无法指定用户名。

    非托管尝试

    我看了NetUserModalsGet。虽然这会返回一些关于密码设置的信息:

    typedef struct _USER_MODALS_INFO_0 {
      DWORD usrmod0_min_passwd_len;
      DWORD usrmod0_max_passwd_age;
      DWORD usrmod0_min_passwd_age;
      DWORD usrmod0_force_logoff;
      DWORD usrmod0_password_hist_len;
    } USER_MODALS_INFO_0, *PUSER_MODALS_INFO_0, *LPUSER_MODALS_INFO_0;
    

    ..它不会告诉Password Complexity 策略是否启用。

    工具输出抓取“成功”

    所以我求助于解析secedit.exe 输出。

        public static bool PasswordComplexityPolicy()
        {
            var tempFile = Path.GetTempFileName();
    
            Process p = new Process();
            p.StartInfo.FileName = Environment.ExpandEnvironmentVariables(@"%SystemRoot%\system32\secedit.exe");
            p.StartInfo.Arguments = String.Format(@"/export /cfg ""{0}"" /quiet", tempFile);
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.UseShellExecute = false;
            p.Start();
            p.WaitForExit();
    
            var file = IniFile.Load(tempFile);
    
            IniSection systemAccess = null;
            var passwordComplexityString = "";
            var passwordComplexity = 0;
    
            return file.Sections.TryGetValue("System Access", out systemAccess)
                && systemAccess.TryGetValue("PasswordComplexity", out passwordComplexityString)
                && Int32.TryParse(passwordComplexityString, out passwordComplexity)
                && passwordComplexity == 1;
        }
    

    完整代码在这里:http://gist.github.com/421802

    【讨论】:

    • WMI RSOP_Xxx 方法似乎不适用于本地系统(未找到实例)。它适用于域驱动系统。
    【解决方案2】:

    您可以使用策略结果集 (RSOP) 工具。例如。这是一个 VBScript(来自here),它将告诉您您需要了解的内容。将其翻译成 C# 应该很简单。

    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\rsop\computer")
    Set colItems = objWMIService.ExecQuery _
        ("Select * from RSOP_SecuritySettingBoolean")
    For Each objItem in colItems
        Wscript.Echo "Key Name: " & objItem.KeyName
        Wscript.Echo "Precedence: " & objItem.Precedence
        Wscript.Echo "Setting: " & objItem.Setting
        Wscript.Echo
    Next
    

    【讨论】:

      【解决方案3】:

      我偶然发现了你的这个微软论坛答案http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/f3f5a61f-2ab9-459e-a1ee-c187465198e0

      希望这对将来遇到此问题的人有所帮助。

      【讨论】: