如何在C#中以编程方式获取Windows密码策略设置
嘿,我之前刚好搞定过一模一样的需求!你说的WMI确实能拿到这些系统密码策略,只是没找对正确的类和命名空间~另外还有个更可靠的原生Windows API方案,两种方法都给你详细说说:
方法一:使用WMI获取密码策略
正确的WMI命名空间是root\CIMV2,对应的类是Win32_AccountPolicy,这个类里包含了你要的所有密码策略属性。下面是完整的C#代码示例:
using System.Management; public static void RetrieveWindowsPasswordPolicyViaWmi() { try { // 连接到本地系统的CIMV2命名空间 var managementScope = new ManagementScope(@"\\.\root\CIMV2"); managementScope.Connect(); // 查询账户策略信息 var query = new ObjectQuery("SELECT * FROM Win32_AccountPolicy"); using (var searcher = new ManagementObjectSearcher(managementScope, query)) { foreach (var policyObject in searcher.Get()) { // 解析并输出所有密码策略项,和gpedit里的一一对应 Console.WriteLine($"最小密码长度: {policyObject["MinPasswordLength"]}"); Console.WriteLine($"密码历史记录长度: {policyObject["PasswordHistoryLength"]}"); // WMI里的时间单位是100纳秒,转成天需要除以864000000000 Console.WriteLine($"最大密码有效期(天): {Convert.ToUInt32(policyObject["MaxPasswordAge"]) / 864000000000}"); Console.WriteLine($"最小密码有效期(天): {Convert.ToUInt32(policyObject["MinPasswordAge"]) / 864000000000}"); Console.WriteLine($"密码必须符合复杂性要求: {(Convert.ToBoolean(policyObject["PasswordComplexity"]) ? "是" : "否")}"); Console.WriteLine($"强制密码过期后注销: {(Convert.ToBoolean(policyObject["ForceLogoffWhenExpire"]) ? "是" : "否")}"); Console.WriteLine($"允许可逆加密存储密码: {(Convert.ToBoolean(policyObject["ClearTextPassword"]) ? "是" : "否")}"); } } } catch (ManagementException ex) { Console.WriteLine($"WMI查询出错: {ex.Message}"); } }
注意:这段代码需要管理员权限才能运行,因为访问系统级策略需要足够的权限。
方法二:调用Windows原生API(推荐,兼容性更强)
如果WMI在某些系统版本里出现兼容性问题,直接调用Windows的NetUserModalsGet原生API是更稳妥的选择,这个API从Windows XP到最新的Windows 11都支持,而且能直接拿到组策略里的所有密码/账户锁定设置。
下面是完整的P/Invoke实现代码:
using System; using System.Runtime.InteropServices; public static class WindowsPasswordPolicyHelper { // 定义API所需的结构,对应不同级别的策略信息 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct USER_MODALS_INFO_0 { public uint MinPasswordLength; public uint MaxPasswordAgeSeconds; public uint MinPasswordAgeSeconds; public uint PasswordHistoryLength; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct USER_MODALS_INFO_2 { public bool PasswordComplexityRequired; public bool ForceLogoffOnExpire; public bool AllowClearTextPasswords; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct USER_MODALS_INFO_1 { public uint LockoutDurationSeconds; public uint LockoutObservationWindowSeconds; public uint LockoutThreshold; } // P/Invoke声明NetUserModalsGet和内存释放函数 [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern uint NetUserModalsGet( string serverName, uint infoLevel, out IntPtr bufferPtr); [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern uint NetApiBufferFree(IntPtr bufferPtr); public static void GetSystemPasswordPolicy() { IntPtr buffer = IntPtr.Zero; try { // 获取基础密码策略(级别0) uint result = NetUserModalsGet(null, 0, out buffer); if (result == 0) { var basicPolicy = Marshal.PtrToStructure<USER_MODALS_INFO_0>(buffer); Console.WriteLine($"最小密码长度: {basicPolicy.MinPasswordLength}"); Console.WriteLine($"最大密码有效期(天): {basicPolicy.MaxPasswordAgeSeconds / 86400}"); Console.WriteLine($"最小密码有效期(天): {basicPolicy.MinPasswordAgeSeconds / 86400}"); Console.WriteLine($"密码历史记录长度: {basicPolicy.PasswordHistoryLength}"); NetApiBufferFree(buffer); buffer = IntPtr.Zero; } else { Console.WriteLine($"获取基础策略失败,错误码: {result}"); } // 获取密码复杂性等高级设置(级别2) result = NetUserModalsGet(null, 2, out buffer); if (result == 0) { var complexPolicy = Marshal.PtrToStructure<USER_MODALS_INFO_2>(buffer); Console.WriteLine($"密码必须符合复杂性要求: {(complexPolicy.PasswordComplexityRequired ? "是" : "否")}"); Console.WriteLine($"强制密码过期后注销: {(complexPolicy.ForceLogoffOnExpire ? "是" : "否")}"); Console.WriteLine($"允许可逆加密存储密码: {(complexPolicy.AllowClearTextPasswords ? "是" : "否")}"); NetApiBufferFree(buffer); buffer = IntPtr.Zero; } else { Console.WriteLine($"获取高级策略失败,错误码: {result}"); } // 如果需要账户锁定策略,可以获取级别1的信息 result = NetUserModalsGet(null, 1, out buffer); if (result == 0) { var lockoutPolicy = Marshal.PtrToStructure<USER_MODALS_INFO_1>(buffer); Console.WriteLine($"账户锁定持续时间(分钟): {lockoutPolicy.LockoutDurationSeconds / 60}"); Console.WriteLine($"账户锁定观察窗口(分钟): {lockoutPolicy.LockoutObservationWindowSeconds / 60}"); Console.WriteLine($"账户锁定阈值: {lockoutPolicy.LockoutThreshold}"); NetApiBufferFree(buffer); } else { Console.WriteLine($"获取锁定策略失败,错误码: {result}"); } } finally { // 确保释放内存 if (buffer != IntPtr.Zero) { NetApiBufferFree(buffer); } } } }
同样,这个方法也需要管理员权限才能正常调用。拿到这些值之后,你就可以在网站的密码校验逻辑里直接使用,完全自动匹配当前主机的Windows密码策略,不用任何硬编码配置。
内容的提问来源于stack exchange,提问作者Matthew C
相关产品推荐
相关产品推荐

