如何在安装期间使用.NET授予文件夹的读/写权限

本文关键字:文件夹 权限 NET 安装 | 更新日期: 2023-09-27 18:07:29

我有一个使用Visual Studio 2010构建的安装项目。

安装程序可以很好地将应用程序及其所有依赖项安装到相应的子目录和程序数据目录中。

然而,我注意到安装程序创建的每个目录(根文件夹及其所有子目录(都没有授予"写入"权限。添加到"用户"组目录中的唯一权限是:

  • 阅读&执行
  • 列出文件夹内容
  • 读取

无论用户是否以"管理员"身份安装应用程序,都会发生这种明显的默认权限设置。

对我来说,安装程序没有给正在安装的应用程序使用的文件夹"写入"权限似乎很奇怪——更令人困惑的是,安装程序在应用程序数据库的ProgramData文件夹中创建的文件夹没有获得"写入"权限。

我的问题是,是否有一种方法可以配置安装项目,以便在它创建文件夹时,我们可以告诉它应该授予什么类型的权限以及授予谁。在我的情况下,我需要为(应用程序的(根目录及其所有子目录,以及放置在ProgramData文件夹中的文件夹授予"用户组"的"读/写"权限。从技术上讲,我对将目录"完全控制"交给"用户组"很酷。

如何在安装期间使用.NET授予文件夹的读/写权限

我想我的另一篇帖子因为有点过于笼统而被删除了,所以我在下面对其进行了改进:

要做的事情是制作一个自定义动作。这非常简单,请查看MSDN演练,在这里编写C#自定义操作。您将在Install方法中放入更改权限的代码:

按照链接中的前几个步骤,获取从安装程序解决方案中引用的新安装程序项目。你必须这样做,这样你就可以建立一个dll,在安装结束时调用。

实际上,为用户设置读/写权限有点棘手,我能得到的最接近的是为Authenticated Users设置权限。我拼凑了一些我在互联网上找到的其他解决方案,想出了这个:

public override void Install(IDictionary stateSaver)
{
    // This gets the named parameters passed in from your custom action
    string folder = Context.Parameters["folder"];
    // This gets the "Authenticated Users" group, no matter what it's called
    SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
    // Create the rules
    FileSystemAccessRule writerule = new FileSystemAccessRule(sid, FileSystemRights.Write, AccessControlType.Allow);
    if (!string.IsNullOrEmpty(folder) && Directory.Exists(folder))
    {
        // Get your file's ACL
        DirectorySecurity fsecurity = Directory.GetAccessControl(folder);
        // Add the new rule to the ACL
        fsecurity.AddAccessRule(writerule);
        // Set the ACL back to the file
        Directory.SetAccessControl(folder, fsecurity);
    }
    // Explicitly call the overriden method to properly return control to the installer
    base.Install(stateSaver);
}

然后,当您创建自定义操作时,编辑其属性,并在CustomActionData属性下添加类似的内容:

/folder="[CommonAppDataFolder][ProductName]"

默认情况下,用户组在每台机器的位置(如程序文件(中没有写访问权限。这是一个与安装无关的Windows标准。但是,在安装过程中,您可以设置所需的任何权限。

Windows安装程序确实支持自定义权限,但Visual Studio没有提供设置权限的方法。因此,VisualStudio中唯一的解决方案就是自定义操作。

很遗憾,Visual Studio不支持附加的自定义操作。因此,只有在包中包含XCACLS.EXE(它将与文件一起安装在目标计算机上(时,才可以使用XCACLS.EXE设置权限。

一个更干净但更复杂的解决方案是自己编写一个自定义操作(使用自定义代码(来设置所需的权限。

最快、最干净的解决方案是使用不同的设置创作工具,该工具提供对权限的更多控制。

private static void GrantAccess(string file)
{
    bool exists = System.IO.Directory.Exists(file);
    if (!exists)
    {
        DirectoryInfo di = System.IO.Directory.CreateDirectory(file);
        Console.WriteLine("The Folder is created Sucessfully");
    }
    else
    {
        Console.WriteLine("The Folder already exists");
    }
    DirectoryInfo dInfo = new DirectoryInfo(file);
    DirectorySecurity dSecurity = dInfo.GetAccessControl();
    dSecurity.AddAccessRule(new FileSystemAccessRule(
            new SecurityIdentifier(WellKnownSidType.WorldSid, null), 
            FileSystemRights.FullControl, 
            InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit,
            PropagationFlags.NoPropagateInherit, 
            AccessControlType.Allow));
    dInfo.SetAccessControl(dSecurity);
   
}

上面的代码将文件夹的访问权限设置为对每个用户(每个人(的完全控制/读写。

行为是经过设计的。程序不应该为了更新而修改自己(因此它们的安装目录((同样可以使用Windows安装程序毫无问题地完成(。如果您使用的是.NET,则隔离存储是存储用户数据的绝佳位置。

DirectoryInfo info = new DirectoryInfo(path[x]);
DirectorySecurity security = info.GetAccessControl();
security.AddAccessRule(new FileSystemAccessRule(logonName, FileSystemRights.Modify, InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow));
security.AddAccessRule(new FileSystemAccessRule(logonName, FileSystemRights.Modify, InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow));
info.SetAccessControl(security); 

如果要在ProgramData文件夹中保存和访问多个文件,则设置继承零件也很重要。

如上所述,用户组在程序文件中没有写入权限。如果你不想处理安装程序类或Wix(如果它是一个简单的程序(,只需要在Windows Volume下安装你的软件。

我说的是Visual Studio安装向导:更改应用程序文件夹">DefaultLocation"属性从目标计算机上文件系统中的[ProgramFilesFolder]到[WindowsVolume][Manufacturer][ProductName]。

将defaultLocation更改为:C: [制造商][ProductName]你可以用你喜欢的任何驱动器更换驱动器C。请参阅此图片

在安装应用程序后,我在尝试写入SQLite数据库时也遇到了文件系统权限问题。

正如本线程中提到的,数据文件可以放在用户的AppData文件夹中,而不是修改程序文件等中的权限。AppData还将用户权限设置为允许默认写入。

在Setup项目中,这是通过添加";"用户的应用程序数据文件夹";进入设置文件系统,在该系统下可以创建应用程序文件夹。然后将数据库文件添加到此应用程序文件夹中。安装期间,将在AppData文件夹中创建包含数据库文件的应用程序文件夹。

创建指向AppData文件夹的数据库连接字符串的代码如下:

public static Environment.SpecialFolder DataPath = Environment.SpecialFolder.ApplicationData;
public static string ConnectionString = "Data Source=" + Environment.GetFolderPath(DataPath) + "''ApplicationName''database.SQLite";

我在Visual Studio 2019中使用了此解决方案。

我将要复制的文件夹放在安装向导的"应用程序文件夹"部分的文件夹中,该部分位于C:''Program Files(x86(目录中。

然后,当程序运行时,它会检查所需的文件夹是否在正确的位置,如果没有,则会将它们复制到正确的目录中。

所以代码是:

If Not My.Computer.FileSystem.DirectoryExists("directory") And My.Computer.FileSystem.DirectoryExists("directory") Then
    My.Computer.FileSystem.CopyDirectory("C:'Program Files (x86)'APPFOLDER", "C:'ProgramData'APPFOLDER")
Else
End If

希望这能有所帮助。