0

我正在开发一个 Windows 8.1 kiosk 类型的应用程序,我需要将组策略自定义用户界面设置设置为应用程序的 .exe。当然,这可以手动完成,但我希望能够通过 c# 或安装程序来更改它(我现在正在使用 Visual Studio 安装程序)。

谢谢您的帮助!

4

1 回答 1

1

要走的路是:

  1. 创建自定义操作并将其添加到安装程序的安装部分。
  2. 使用非托管LsaAddAccountRights方法将任何策略设置为任何用户帐户或组(例如 Administrators、Users、Everyone)。您只需要知道正确的策略句柄和您要分配的用户权限。

现在,到实施:-)

请检查下面的代码。这是我通过分析和借用来自不同资源的不同代码片段而最终得到的实现:

public class LSAManager
{
    [DllImport("advapi32.dll", PreserveSig = true)]
    private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess, out IntPtr PolicyHandle);
    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
    private static extern uint LsaAddAccountRights(IntPtr PolicyHandle, IntPtr pSID, LSA_UNICODE_STRING[] UserRights, int CountOfRights);
    [DllImport("advapi32.dll")]
    public static extern void FreeSid(IntPtr pSid);
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
    private static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName, ref int cbdomainLength, ref int use);
    [DllImport("advapi32.dll")]
    private static extern bool IsValidSid(IntPtr pSid);
    [DllImport("advapi32.dll")]
    private static extern int LsaClose(IntPtr ObjectHandle);
    [DllImport("advapi32.dll")]
    private static extern int LsaNtStatusToWinError(int status);

    [DllImport("kernel32.dll")]
    private static extern int GetLastError();

    [StructLayout(LayoutKind.Sequential)]
    private struct LSA_UNICODE_STRING
    {
        public UInt16 Length;
        public UInt16 MaximumLength;
        public IntPtr Buffer;
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct LSA_OBJECT_ATTRIBUTES
    {
        public int Length;
        public IntPtr RootDirectory;
        public LSA_UNICODE_STRING ObjectName;
        public UInt32 Attributes;
        public IntPtr SecurityDescriptor;
        public IntPtr SecurityQualityOfService;
    }

    private enum LSA_AccessPolicy : long
    {
        POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L,
        POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
        POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
        POLICY_TRUST_ADMIN = 0x00000008L,
        POLICY_CREATE_ACCOUNT = 0x00000010L,
        POLICY_CREATE_SECRET = 0x00000020L,
        POLICY_CREATE_PRIVILEGE = 0x00000040L,
        POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
        POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
        POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
        POLICY_SERVER_ADMIN = 0x00000400L,
        POLICY_LOOKUP_NAMES = 0x00000800L,
        POLICY_NOTIFICATION = 0x00001000L
    }

    /// <summary>Adds a privilege to an account</summary>
    /// <param name="accountName">Name of an account - "domain\account" or only "account"</param>
    /// <param name="privilegeName">Name of the privilege</param>
    /// <returns>The windows error code returned by LsaAddAccountRights (0 = success)</returns>
    public static long SetRight(String accountName, String privilegeName)
    {
        long winErrorCode = 0; //contains the last error

        //pointer an size for the SID
        IntPtr sid = IntPtr.Zero;
        int sidSize = 0;
        //StringBuilder and size for the domain name
        StringBuilder domainName = new StringBuilder();
        int nameSize = 0;
        //account-type variable for lookup
        int accountType = 0;

        //get required buffer size
        LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);

        //allocate buffers
        domainName = new StringBuilder(nameSize);
        sid = Marshal.AllocHGlobal(sidSize);

        //lookup the SID for the account
        bool result = LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);

        // check SID if required: IsValidSid(sid));

        if (!result)
        {
            winErrorCode = GetLastError();
        }
        else
        {
            //initialize an empty unicode-string
            LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
            //combine all policies
            int access = (int)(
                LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
                LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
                LSA_AccessPolicy.POLICY_CREATE_PRIVILEGE |
                LSA_AccessPolicy.POLICY_CREATE_SECRET |
                LSA_AccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
                LSA_AccessPolicy.POLICY_LOOKUP_NAMES |
                LSA_AccessPolicy.POLICY_NOTIFICATION |
                LSA_AccessPolicy.POLICY_SERVER_ADMIN |
                LSA_AccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
                LSA_AccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
                LSA_AccessPolicy.POLICY_TRUST_ADMIN |
                LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
                LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION
                );
            //initialize a pointer for the policy handle
            IntPtr policyHandle = IntPtr.Zero;

            //these attributes are not used, but LsaOpenPolicy wants them to exists
            LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();
            ObjectAttributes.Length = 0;
            ObjectAttributes.RootDirectory = IntPtr.Zero;
            ObjectAttributes.Attributes = 0;
            ObjectAttributes.SecurityDescriptor = IntPtr.Zero;
            ObjectAttributes.SecurityQualityOfService = IntPtr.Zero;

            //get a policy handle
            uint resultPolicy = LsaOpenPolicy(ref systemName, ref ObjectAttributes, access, out policyHandle);
            winErrorCode = LsaNtStatusToWinError((int)resultPolicy);

            if (winErrorCode == 0)
            {
                //Now that we have the SID and the policy,
                //we can add rights to the account.

                //initialize an unicode-string for the privilege name
                LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
                userRights[0] = new LSA_UNICODE_STRING();
                userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
                userRights[0].Length = (UInt16)(privilegeName.Length * UnicodeEncoding.CharSize);
                userRights[0].MaximumLength = (UInt16)((privilegeName.Length + 1) * UnicodeEncoding.CharSize);

                //add the right to the account
                uint res = LsaAddAccountRights(policyHandle, sid, userRights, 1);

                winErrorCode = LsaNtStatusToWinError((int)res);

                LsaClose(policyHandle);
            }
            FreeSid(sid);
        }

        return winErrorCode;
    }
}

为方便起见,我将此代码放在名为LSAManager的单独类中。为了使用此代码,只需调用:

string userName = "alex";
// Set "Logon As a Service" privilege (for example):
if (LSAManager.SetRight(userName, "SeServiceLogonRight") != 0)
{
    // handle error here
}
于 2015-05-25T20:05:20.617 回答