Introduction
With the introduction of User Account Control (UAC) since Windows Vista, access to some system folders has been limited. Modifications to these folders are not permitted without administrator privileges. While UAC is essential for security, in some cases, we want to grant our users full access to certain folders (e.g. C:\ProgramData\[CompanyName]\[AppName], though not recommended by Microsoft). This simple command line program is designed to handle this issue.
Details
To reset access permission, first, we need to make sure that the program always runs as administrator. This can be achieved simply by adding an application manifest file, and add <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
as described in comment UAC Manifest Options.
Next, we need to make sure that access permission is properly inherited by all the subfolders and files in the folder that we want to reset. This is done by methods TraverseDirectory
, SetFileInheritance
, and SetDirectoryInheritance
.
In the end, let's check method SetDirectoryAccess
. Note that we use InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit
and PropagationFlags.None
, as we want our access rule to be applied to not only this folder, but also the subfolders and files. This article explains the relationship between the scope of our access rule and the corresponding flags.
?using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
namespace PermitAccess
{
class Program
{
static void Main(string[] args)
{
foreach (var arg in args)
{
var success = ResetDirectory(arg);
var msg = success ?
string.Format("Access permission has been reset for
all subfolders and files in directory {0}", arg) :
string.Format("Unable to reset access permission for directory {0}", arg);
Console.WriteLine(msg);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
public static bool ResetDirectory(string path)
{
bool accessSet = false;
try
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
TraverseDirectory(path);
accessSet = SetDirectoryAccess(path);
}
catch (IOException ex)
{
Console.WriteLine("An unexpected exception just occurred. Details:");
Console.WriteLine(ex.Message);
return false;
}
return accessSet;
}
private static void TraverseDirectory(string path)
{
SetDirectoryInheritance(path);
var files = Directory.GetFiles(path);
foreach (var f in files)
{
SetFileInheritance(f);
}
var directories = Directory.GetDirectories(path);
foreach (var d in directories)
{
TraverseDirectory(d);
}
}
private static void SetFileInheritance(string path)
{
var fileInfo = new FileInfo(path);
var fileSecurity = fileInfo.GetAccessControl();
fileSecurity.SetAccessRuleProtection(false, true);
fileInfo.SetAccessControl(fileSecurity);
}
private static void SetDirectoryInheritance(string path)
{
var directoryInfo = new DirectoryInfo(path);
var directorySecurity = directoryInfo.GetAccessControl();
directorySecurity.SetAccessRuleProtection(false, true);
directoryInfo.SetAccessControl(directorySecurity);
}
private static bool SetDirectoryAccess(string path)
{
var directoryInfo = new DirectoryInfo(path);
var directorySecurity = directoryInfo.GetAccessControl();
var securityIdentifier = new SecurityIdentifier
(WellKnownSidType.BuiltinUsersSid,
null);
var rule = new FileSystemAccessRule(
securityIdentifier,
FileSystemRights.FullControl,
InheritanceFlags.ContainerInherit |
InheritanceFlags.ObjectInherit,
PropagationFlags.None,
AccessControlType.Allow);
bool modified;
directorySecurity.ModifyAccessRule(AccessControlModification.Add, rule, out modified);
directoryInfo.SetAccessControl(directorySecurity);
return modified;
}
}
}
Using the Code
To use the code, you may first build this project, and copy PermitAccess.exe to the output folder of your own program. Inside your program, call:
Process uacProcess = new Process();
uacProcess.StartInfo.FileName = "PermitAccess.exe";
uacProcess.StartInfo.Arguments = @"[Directory to reset]";
uacProcess.Start();
Note that you don't need to force your program to be run as administrator. PermitAccess.exe itself will ask the user for administrator privileges.
You may also run PermitAccess.exe in Windows Command Prompt. Navigate to the folder where PermitAccess.exe is located, and call PermitAccess [Directory to reset]
.
History
- Version 1.0. July 30, 2017