39

I have a Setup project that I have build using Visual Studio 2010.

The installer works fine in terms of installing the application and all its dependencies into their proper sub directories and Program Data directories.

However, I noticed that each directory (the root folder and all of its sub directories) that the installer created does not give "Write" permissions. The only permissions that are added to the directories for the "Users" group are:

  • Read & Execute
  • List folder contents
  • Read

This, apparent default permissions setting, will happen regardless if the user installs the application as "Administrator" or not.

It seems odd to me that the installer doesn't give "Write" permissions to a folder that is being used by the application that is getting installed - It's even more confusing that the folder that the installer creates in the ProgramData folder for the application's database doesn't get "Write" permissions.

My question is, is there a way to configure the Setup project so that if and when it creates a folder, we can tell it what type of permissions to give it and to whom. In my case, I need give the root directory (of the application) and all of its sub directories, and the folder that is placed in the ProgramData folder "Read/Write" permissions for the "Users Group". Technically, I'm cool with giving the dirs "Full Control" to the "Users Group".

1
  • Maybe you should reconsider which is the right answer Commented Dec 21, 2016 at 7:36

9 Answers 9

39

I guess my other post was deleted for being a little too general, so I've refined it below:

The thing to do is make a custom action. It's pretty straightforward, check out the MSDN walkthrough for writing a C# custom action here. You'll put your permission-changing code inside the Install method:

Follow the first few steps from the link to get a new installer project referenced from your installer solution. You have to do it this way, so you can build a dll that is called at the end of installation.

Actually setting read/write privileges for Users was a little trickier, and the closest I could get was to set for Authenticated Users. I cobbled together a few other solutions I found on the Internet to come up with this:

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); } 

Then, when you create your custom action, edit its properties, and add something like this under the CustomActionData property:

/folder="[CommonAppDataFolder][ProductName]" 
Sign up to request clarification or add additional context in comments.

6 Comments

+1, except I had to add base.Install(stateSaver); at the end of the override method.
ACK for info [from your post] "and the closest I could get was to set for Authenticated Users". There is a BuiltinUsersSid which represents the Users collection.
I had to add some more rights to get it working. I used the rights posted in the code example here stackoverflow.com/a/4392394/433718
Broken MSDN link in original post (to C# custom action walkthrough). I believe this is the correct link: msdn.microsoft.com/en-us/library/vstudio/d9k65z2d(v=vs.100).aspx
As I have recently discovered, the docs seem to suggest placing base.Install(stateServer) at the beginning, not the end, of the overriding method. It sounds like this makes your dependencies install first (makes sense). From the docs: "If you override the Install method in a derived class, be sure to call the base class's Install method first in your derived method. The Install method calls the Install method of each installer contained in the Installers property of this instance." Source: msdn.microsoft.com/en-us/library/…
|
14

By default Users group doesn't have write access in per-machine locations like Program Files. This is a Windows standard which is not related to installations. However, during install you can set any permissions you want.

Windows Installer does support custom permissions, but Visual Studio doesn't offer a way for setting them. So the only solution in Visual Studio is a custom action.

Unfortunately Visual Studio doesn't support attached custom actions. So using XCACLS.EXE to set permissions would work only if you include it in your package (it will be installed on the target machine along with your files).

A cleaner, but more complex solution is to write a custom action yourself (using custom code) to set the permissions you want.

The fastest and cleanest solution would be to use a different setup authoring tool which offers more control over permissions.

1 Comment

Link is no longer alive
10
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); } 

The above code will set the access rights of the folder to full control/ read-write to every user (everyone).

1 Comment

This code doesnot need to install anything, just run your VS and copy the code, it just work fine for me for every user
4

The behavior is by design. The programs should not be modifying themselves (hence their installation directory) for anything but updates (which again can be done with Windows installer without a problem). If you're using .NET, isolated storage is an excellent location to store user data.

Comments

3
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); 

Setting the inherit part is also important if you want to save and access more than just one file in the ProgramData folder.

Comments

3

As it has been mentioned above Users group does not have write permission in Program Files. If you don't want to deal with installer class or Wix (if it is a simple program), just prefer installing your software under a Windows Volume.

I am talking about Visual Studio Setup Wizard: Change Application Folder 'DefaultLocation' Property from [ProgramFilesFolder] to [WindowsVolume][Manufacturer][ProductName] in File System on Target Machine.

Comments

3

Change the defaultLocation to: C:[Manufacturer][ProductName] you can change the drive C with whatever drive you like. See this picture

1 Comment

Missing backslash in the path. Otherwise works like a charm C:[Manufacturer][ProductName]
1

I stumbled also into filesystem permissions while trying to write into SQLite database after application was installed.

As mentioned in this thread, data files can be placed into user's AppData-folder instead of modifying permissions in Program Files and such. AppData also has user permissions set to allow writing as default.

In Setup project, this is done by adding "User's Application Data Folder" into setup File System, under which application folder can be created. Database file is then added into this application folder. Application folder with database file will be created during setup inside AppData-folder.

Code for creating a database connection string pointing to AppData-folder is as follows:

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

I used this solution with Visual Studio 2019.

Comments

0

I put the folders I want to copy in a folder in the Application Folder section of the Setup Wizard which is in the C:\Program Files (x86) directory.

Then when the program runs it checks if the folders needed are in the right place, and if not copies them to the correct directory.

So the code would be:

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 

Hope this helps.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.