这几天由于工作需要,需要用C#开发一个设置文件夹共享,并为共享的文件夹设置共享权限的功能。在开发过程中发现了一些有趣的问题,

就是如果用程序的方式创建一个共享目录,那么就是无法直接用程序的方式设置它的共享权限。更为奇怪的是如果手动去改下下共享权限 (改前和改后的设置都一样),

就可以以程序的方式设置 共享权限了。

  这里我贴出创建共享目录的代码

/// <summary> 
  
 
  

            /// 共享目录 
  
 
  

            /// </summary> 
  
 
  

            /// <param name="folderPath">目录地址</param> 
  
 
  

            /// <param name="shareName">共享名称</param> 
  
 
  

            /// <param name="description">描述</param> 
  
 
  

            /// <param name="tempShareName">临时共享目录</param> 
  
 
  

            /// <param name="returnMsg">返回消息</param> 
  
 
 
        /// <returns></returns> 
 public static bool ShareFolder(string folderPath, string shareName, string description, out string returnMsg)
 
 

            { 
  
 
  

                bool bRet = false; 
  
 
  

                try 
  
 
  

                { 
  
 
  

                    returnMsg = ""; 
  
 
  

                    if (Directory.Exists(folderPath)) 
  
 
  

                    { 
  
 
  

                        ManagementBaseObject oSecurityDescriptor = GetSecurityDescriptorFromBinary(user); 
  
 
  

                        ManagementClass oManagementClass = new ManagementClass("Win32_Share"); 
  
 
  

                        ManagementBaseObject oInParams = oManagementClass.GetMethodParameters("Create"); 
  
 
  

                        ManagementBaseObject oOutParams = null; 
  
 
  

                        oInParams["Description"] = description; 
  
 
  

                        oInParams["Name"] = shareName; 
  
 
  

                        oInParams["Path"] = folderPath; 
  
 
  

                        oInParams["Type"] = DISK_DRIVE; 
  
 
  
 //默认的共享权限是Everyone 
  
 
  
        /*
如果oInParams["Access"] 不设置或者设置为null,你就会奇怪的发现,当你先要用程序再去设置共享权限时就不行了(xp和2003下,win7,win2008缺可以)
*/ 
 
   
  

                        oOutParams = oManagementClass.InvokeMethod("Create", oInParams, null); 
  
 
  

                        if ((uint)(oOutParams.Properties["ReturnValue"].Value) != 0) 
  
 
  

                        { 
  
 
  

                            returnMsg = string.Format("无法共享目录[{0}]!", folderPath); 
  
 
  

                        } 
  
 
  

                        else 
  
 
  

                        { 
  
 
  

                            bRet = true; 
  
 
  

                        } 
  
 
  

                    } 
  
 
  

                    else 
  
 
  

                    { 
  
 
  

                        returnMsg = string.Format("不存在目录[{0}]!", folderPath); 
  
 
  

                    } 
  
 
  

                } 
  
 
  

                catch (Exception ex) 
  
 
  

                { 
  
 
  

                    returnMsg = ex.Message; 
  
 
  

                } 
  
 
  

                return bRet; 
  
 
  

            }

 设置权限的普通方法:

/// <summary> 
   
        /// 设置共享目录的共享权限 
   
        /// </summary> 
   
        /// <param name="folderPath">共享目录名</param> 
   
        /// <param name="user">共享权限用户</param> 
   
        /// <param name="returnMsg">返回消息</param> 
   
        /// <returns></returns> 
   
        public static bool SetPermission(string shareName, string user, out string returnMsg) 
   
        { 
   
            bool bRet = false; 
   
            returnMsg = ""; 
   
            //判断用户是否存在 
   
            if (!IsUserExists(user)) 
   
            { 
   
                returnMsg = string.Format("用于[{0}]不存在", user); 
   
                return bRet; 
   
            } 
   
            // Step 1 - Getting the user Account Object 
   
            string sShareName =shareName; 
   
            ManagementObject oShareSecuritySetting=  null; 
   
            ManagementObjectSearcher oSearcher = new ManagementObjectSearcher("Select * from Win32_LogicalShareSecuritySetting where     Name = '" + sharedName + "'"); 
   
            //ManagementObjectSearcher oSearcher = new ManagementObjectSearcher("Select * from Win32_LogicalShareSecuritySetting"); 
   
            ManagementObjectCollection oResultOfSearch = oSearcher.Get(); 
   
            if (oResultOfSearch.Count > 0) 
   
            { 
   
                //The search might return a number of objects with same shared name. I assume there is just going to be one 
   
                foreach (ManagementObject sharedFolder in oResultOfSearch) 
   
                {                    
   
            oShareSecuritySetting= sharedFolder; 
   
                    break; 
   
                } 
   
            } 
   
            if (oShareSecuritySetting!= null) 
   
            { 
   
                ManagementBaseObject oSecurityDescriptorObject = oShareSecuritySetting.InvokeMethod("GetSecurityDescriptor", null, null); 
   
                if (oSecurityDescriptorObject != null) 
   
                { 
   
                    if ((uint)(oSecurityDescriptorObject.Properties["ReturnValue"].Value) == 0) 
   
                    { 
   
                        ManagementBaseObject oSecurityDescriptor = oSecurityDescriptorObject.Properties["Descriptor"].Value as ManagementBaseObject; 
   
                        // Step 2 --  Access Control List from the security descriptor 
   
                        int iExistingAcessControlEntriesCount = 0; 
   
                        ManagementBaseObject[] oAccessControlList = oSecurityDescriptor.Properties["DACL"].Value as ManagementBaseObject[]; 
   
                        if (oAccessControlList != null) 
   
                        { 
   
                            // Otherwise, resize the list to allow for all new users. 
   
                            iExistingAcessControlEntriesCount = oAccessControlList.Length; 
   
                            Array.Resize(ref oAccessControlList, oAccessControlList.Length + 1); 
   
                        } 
   
                        else 
   
                        { 
   
                            // If there aren't any entries in access control list or the list is empty - create one 
   
                            oAccessControlList = new ManagementBaseObject[1]; 
   
                        } 
   
                        // Step 3 - Getting the user Account Object 
   
                        string sUserDomain = Environment.UserDomainName; 
   
                        ManagementObject oUserAccountObject = GetUserAccountObject(sUserDomain, user); 
   
                        ManagementObject oSecurityIdentfierObject = new ManagementObject(string.Format("Win32_SID.SID='{0}'", (string)oUserAccountObject.Properties["SID"].Value)); 
   
                        oSecurityIdentfierObject.Get(); 
   
                        // Step 4 - Create Trustee Object 
   
                        ManagementObject oTrusteeObject = CreateTrustee(sUserDomain, user, oSecurityIdentfierObject); 
   
                        // Step 5 - Create Access Control Entry 
   
                        ManagementObject oAccessControlEntry = CreateAccessControlEntry(oTrusteeObject, false); 
   
                        // Step 6 - Add Access Control Entry to the Access Control List 
   
                        oAccessControlList[iExistingAcessControlEntriesCount] = oAccessControlEntry; 
   
                        // Step 7 - Assign access Control list to security desciptor 
   
                        oSecurityDescriptor.Properties["DACL"].Value = oAccessControlList; 
   
                        // Step 8 - Assign access Control list to security desciptor 
   
                        ManagementBaseObject oParameterForSetSecurityDescriptor = oSharedFolder.GetMethodParameters("SetSecurityDescriptor"); 
   
                        oParameterForSetSecurityDescriptor["Descriptor"] = oSecurityDescriptor; 
   
                        oShareSecuritySetting.InvokeMethod("SetSecurityDescriptor", oParameterForSetSecurityDescriptor, null); 
   
                        bRet = true; 
   
                    } 
   
                    else 
   
                    { 
   
                        returnMsg = string.Format("共享目录[{0}]的安全描述符(SecurityDescriptorObject)的返回值错误!", sShareName); 
   
                    } 
   
                } 
   
                else 
   
                { 
   
                    returnMsg = string.Format("无法获取共享目录[{0}]的安全描述符(SecurityDescriptorObject)", sShareName); 
   
                } 
   
            } 
   
            else 
   
            { 
   
                returnMsg = string.Format("无法获取共享目录[{0}]的共享安全设置!", sShareName); 
   
            } 
   
            return bRet; 
   
        } 
   
         /// <summary> 
    
        /// 获取账户对象 
    
        /// </summary> 
    
        /// <param name="domain">用户的域名</param> 
    
        /// <param name="alias">用户名称别名</param> 
    
        /// <returns></returns> 
    
        private static ManagementObject GetUserAccountObject(string domain, string alias) 
    
        { 
    
            ManagementObject oUserAccountObject = null; 
    
            ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(string.Format("select * from Win32_Account where Name = '{0}' and Domain='{1}'", alias, domain)); 
    
            ManagementObjectCollection oResultOfSearch = oSearcher.Get(); 
    
            if (oResultOfSearch.Count > 0) 
    
            { 
    
                foreach (ManagementObject userAccount in oResultOfSearch) 
    
                { 
    
                    oUserAccountObject = userAccount; 
    
                    break; 
    
                } 
    
            } 
    
            return oUserAccountObject; 
    
        } 
    

        /// <summary> 
    
        /// 创建指定用户的信任项 
    
        /// </summary> 
    
        /// <param name="domain">域名</param> 
    
        /// <param name="userName">用户名</param> 
    
        /// <param name="securityIdentifierOfUser">用户的权限标识</param> 
    
        /// <returns></returns> 
    
        private static ManagementObject CreateTrustee(string domain, string userName, ManagementObject securityIdentifierOfUser) 
    
        { 
    
            ManagementObject oTrusteeObject = new ManagementClass("Win32_Trustee").CreateInstance(); 
    
            oTrusteeObject.Properties["Domain"].Value = domain; 
    
            oTrusteeObject.Properties["Name"].Value = userName; 
    
            oTrusteeObject.Properties["SID"].Value = securityIdentifierOfUser.Properties["BinaryRepresentation"].Value; 
    
            oTrusteeObject.Properties["SidLength"].Value = securityIdentifierOfUser.Properties["SidLength"].Value; 
    
            oTrusteeObject.Properties["SIDString"].Value = securityIdentifierOfUser.Properties["SID"].Value; 
    
            return oTrusteeObject; 
    
        } 
    

        /// <summary> 
    
        /// 创建指定用户的访问控制项(Access Control Entry)对象 
    
        /// </summary> 
    
        /// <param name="trustee">用户的信任项对象</param> 
    
        /// <param name="deny">用户权限是拒绝还是允许</param> 
    
        /// <returns></returns> 
    
        private static ManagementObject CreateAccessControlEntry(ManagementObject trustee, bool deny) 
    
        { 
    
            ManagementObject oAceObject = new ManagementClass("Win32_ACE").CreateInstance(); 
    
            oAceObject.Properties["AccessMask"].Value = 0x1U | 0x2U | 0x4U | 0x8U | 0x10U | 0x20U | 0x40U | 0x80U | 0x100U | 0x10000U | 0x20000U | 0x40000U | 0x80000U | 0x100000U; // all permissions 
    
            oAceObject.Properties["AceFlags"].Value = 0x0U; // no flags 
    
            oAceObject.Properties["AceType"].Value = deny ? 1U : 0U; // 0 = allow, 1 = deny 
    
            oAceObject.Properties["Trustee"].Value = trustee; 
    
            return oAceObject; 
    
        } 
    
   
        /// <summary> 
   
        /// 检查用户是否存在 
   
        /// </summary> 
   
        /// <param name="user"></param> 
   
        /// <param name="returnMsg"></param> 
   
        /// <returns></returns> 
   
        public static bool IsUserExists(string userName) 
   
        { 
   
            bool bRet = false; 
   
            DirectoryEntry oLocalMachine = null; 
   
            DirectoryEntry oNewUser = null; 
   
            try 
   
            { 
   
                oLocalMachine = new DirectoryEntry("WinNT://" + Environment.MachineName); 
   
                oNewUser = oLocalMachine.Children.Find(userName, "user"); 
   
                bRet = true; 
   
            } 
   
            catch 
   
            { 
   
                bRet = false; 
   
            } 
   
            return bRet; 
   
        }

运行代码上面这段代码时你会发现

ManagementObject oShareSecuritySetting=  null; 
               ManagementObjectSearcher oSearcher = new ManagementObjectSearcher("Select * from Win32_LogicalShareSecuritySetting where Name = '" + sharedName + "'"); 
               ManagementObjectCollection oResultOfSearch = oSearcher.Get(); 
               if (oResultOfSearch.Count > 0) 
               { 
                   //The search might return a number of objects with same shared name. I assume there is just going to be one 
                   foreach (ManagementObject sharedFolder in oResultOfSearch) 
                   {                    
               oShareSecuritySetting= sharedFolder; 
                       break; 
                   } 
               }

这句代码片段是无法找到有效的oShareSecuritySetting。但是实际情况是文件夹是共享的而且有一个默认的Everyone的共享权限。这是为啥我找了很久也没答案。

 鉴于无法获取oShareSecuritySetting这个“Win32_LogicalShareSecuritySetting”对象,下一步的权限设置也没法做了。

其实获取这个对象的最终目的是为了获取下面这个对象

ManagementBaseObject oSecurityDescriptor = oSecurityDescriptorObject.Properties["Descriptor"].Value as ManagementBaseObject;

 这就头疼了,这些功能代码的目的就是为了使用程序去设置共享及共享权限,如果需要手动去设置下权限那不是有点隔靴搔痒了。

最后实在没办了,我只能想了个笨办法。既然手动创建的共享目录能够获取oSecurityDescriptor 这个对象,那能不能我把这个对象保存下来能,应为只要有了

oSecurityDescriptor这个对象,就可以在这个对象了设置我们自己想要的用户权限了,设置方法上面的代码中有例子的。

最后想出来办法是用.net的序列化方法去序列化一个实现获取到的oSecurityDescriptor对象,把这个对象保存在一个文件里,下次在进行反序列化获取这个对象。

需要注意一点的是。无法获取oShareSecuritySetting只会发生在第一次创建共享目录的时候(注意:使用代码创建的),如果第一次为这个共享目录设置了共享权限,那么下次次再设置权限就没有障碍了。烦啊。。。

好了,还是说序列化吧,如下代码:

private static void ObjectSerialize(object serObj) 
           { 
               using (FileStream oFileStream = new FileStream(@"C:\LogicalShareSecuritySetting.dat", FileMode.Create)) 
               { 
                   BinaryFormatter oFormatter = new BinaryFormatter(); 
                   oFormatter.Serialize(oFileStream, serObj); 
               } 
           } 
  
 
  
 
 
  

    ObjectSerialize(oSecurityDescriptor);

这样就把这个对象永久保存在C:\LogicalShareSecuritySetting.dat这个文件里了,为了部署方便,我们可以把这个文件作为一个嵌入的资源嵌入在我们的程序中,下次我们就可以这样反序列化这个对象了:

private const string LOGICAL_SHARESECURITY_SETTING=“Namespace.LogicalShareSecuritySetting.dat”; 
 
  

    ManagementBaseObject oSecurityDescriptor= null; 
   
            try 
   
            { 
   
                Assembly oAsm = Assembly.GetExecutingAssembly(); 
   
                using (Stream oStream = oAsm.GetManifestResourceStream(LOGICAL_SHARESECURITY_SETTING)) 
   
                { 
   
                    BinaryFormatter oFormatter = new BinaryFormatter();                    
   
  
        oSecurityDescriptor= oFormatter.Deserialize(oStream) as ManagementBaseObject;
                }
            }
            catch
            { }

 一旦反序列化成功这个oSecurityDescriptor,我们就可以为这个对象赋值一个我们想要的用户权限啦,如下:

if (oSecurityDescriptor != null) 
   
{ 
   
    ManagementBaseObject[] oAccessControlList = null; 
   
    oAccessControlList = new ManagementBaseObject[1]; 
   
    // Step 3 - Getting the user Account Object 
   
    string sUserDomain = Environment.UserDomainName; 
   
    ManagementObject oUserAccountObject = GetUserAccountObject(sUserDomain, user);  //这个user就是本地计算机的用户名,如Guest等。 
   
    ManagementObject oSecurityIdentfierObject = new ManagementObject(string.Format("Win32_SID.SID='{0}'", (string)oUserAccountObject.Properties["SID"].Value)); 
   
    oSecurityIdentfierObject.Get(); 
   
    // Step 4 - Create Trustee Object 
   
    ManagementObject oTrusteeObject = CreateTrustee(sUserDomain, user, oSecurityIdentfierObject); 
   
    // Step 5 - Create Access Control Entry 
   
    ManagementObject oAccessControlEntry = CreateAccessControlEntry(oTrusteeObject, false); 
   
    // Step 6 - Add Access Control Entry to the Access Control List 
   
    oAccessControlList[0] = oAccessControlEntry; 
   
    // Step 7 - Assign access Control list to security desciptor    
   
  
  oSecurityDescriptor.Properties["DACL"].Value = oAccessControlList;
}

 一旦设置成功了,那么我们返回第一段设置共享目录代码的地方,记得不记得这段代码

 oInParams["Access"] = null; //默认的共享权限是Everyone

我们就可以吧获取的

oSecurityDescriptor设置给 oInParams["Access"] = oSecurityDescriptor了。

OK,大家有兴趣试试。如果有什么更好的方法,请一定告诉我哦。我期待有更好的方式解决这个问题。