看到有人问了这个问题,查询并实验后发现确实有这个问题,测试代码如下:
static void Main(string[] args) { try { string folderPath = @"e:\testSecurity"; Directory.CreateDirectory(folderPath); DirectorySecurity defaultFSec = Directory.GetAccessControl(folderPath); IdentityReference newUser = new NTAccount("User2"); defaultFSec.SetOwner(newUser); Directory.SetAccessControl(folderPath, defaultFSec); } catch(Exception ex) { Console.WriteLine(ex); } Console.ReadLine(); }
结果是System.InvalidOperationException: The security identifier is not allowed to be the owner of this object.
2005年在Microsoft Connect上就有人提出了这个问题,微软说下个版本将会考虑添加这个功能,然而现在似乎还不行。
当然总是有什么其他办法的,既然资源管理器可以做到,那么直接调用API就是一个可行的办法。Richard Willis给出了一个实现方法,我这里把他的代码转贴一下:
sealed class UnmanagedCode { [DllImport("kernel32.dll", SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool CloseHandle(IntPtr hObject); // Use this signature if you do not want the previous state [DllImport("advapi32.dll", SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool AdjustTokenPrivileges(IntPtr tokenHandle, [MarshalAs(UnmanagedType.Bool)]bool disableAllPrivileges, ref TOKEN_PRIVILEGES newState, UInt32 bufferLength, IntPtr previousState, IntPtr returnLength); [DllImport("kernel32.dll", ExactSpelling = true)] static extern IntPtr GetCurrentProcess(); [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] static extern bool OpenProcessToken (IntPtr processHandle, int desiredAccess, ref IntPtr phtok); [DllImport("advapi32.dll", SetLastError = true)] static extern bool LookupPrivilegeValue (string host, string name, ref LUID lpLuid); [StructLayout(LayoutKind.Sequential, Pack = 1)] struct TOKEN_PRIVILEGES { public UInt32 PrivilegeCount; public LUID Luid; public UInt32 Attributes; } [StructLayout(LayoutKind.Sequential)] public struct LUID { public uint LowPart; public int HighPart; } const int SE_PRIVILEGE_ENABLED = 0x00000002; const int TOKEN_QUERY = 0x00000008; const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; //http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx const string SE_RESTORE_PRIVILEGE = "SeRestorePrivilege"; public static void GiveRestorePrivilege() { TOKEN_PRIVILEGES tokenPrivileges; tokenPrivileges.PrivilegeCount = 1; tokenPrivileges.Luid = new LUID(); tokenPrivileges.Attributes = SE_PRIVILEGE_ENABLED; IntPtr tokenHandle = RetrieveProcessToken(); try { bool success = LookupPrivilegeValue (null, SE_RESTORE_PRIVILEGE, ref tokenPrivileges.Luid); if (success == false) { int lastError = Marshal.GetLastWin32Error(); throw new Exception( string.Format("Could not find privilege {0}. Error {1}", SE_RESTORE_PRIVILEGE, lastError)); } success = AdjustTokenPrivileges( tokenHandle, false, ref tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero); if (success == false) { int lastError = Marshal.GetLastWin32Error(); throw new Exception( string.Format("Could not assign privilege {0}. Error {1}", SE_RESTORE_PRIVILEGE, lastError)); } } finally { CloseHandle(tokenHandle); } } static IntPtr RetrieveProcessToken() { IntPtr processHandle = GetCurrentProcess(); IntPtr tokenHandle = IntPtr.Zero; bool success = OpenProcessToken(processHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref tokenHandle); if (success == false) { int lastError = Marshal.GetLastWin32Error(); throw new Exception( string.Format("Could not retrieve process token. Error {0}", lastError)); } return tokenHandle; } }