You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:06:23