My application uses the .NET object Directory.GetFiles()
The actual overload I'm using is
var allFiles = Directory.GetFiles("C:\\Users\\Dave", "*.*", SearchOption.AllDirectories);
The issue is when the source folder is C:\Users\UserName as it then tries to look through application data folder.
When it tries to read from the application data folder, an exception is thrown:
"Access to the path 'C:\Users\Dave\AppData\Local\Application
Data' is denied."
So, my question is does any one have an opinion as to my options? I would assume I have to either change the way I collect all the files or, there may be a built in overload or method which will allow me to continue this (which I clearly don't know about).
If it helps, the goal of this is to take all the files retrieved by Directory.GetFiles() and 'paste' them else where (a glorified copy and paste/back up). I'm actually not too worried about system files, just 'user files'.
The directory %AppData% is a system-protected directory. Windows will try to block any access to this directory as soon as the access was not authorized (An access from another user than the Administrator).
Only the Administrator by default has privileges to read and write from/to this directory.
Alternatively, you can catch the exception and see if the result is Access Denied. Then, you may prompt the user to run as an Administrator to complete this step. Here's a simple example to prompt the user to run as Administrator
try
{
var allFiles = Directory.GetFiles("C:\\Users\\Dave", "*.*", SearchOption.AllDirectories);
}
catch (Exception EX)
{
if (EX.Message.ToLower().Contains("is denied."))
{
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = Application.ExecutablePath;
proc.Verb = "runas"; //Required to run as Administrator
try
{
Process.Start(proc);
}
catch
{
//The user refused to authorize
}
}
}
However, you may always prompt the user to authorize when your application launches which is NOT always RECOMMENDED. To do this, you'll have to edit your project app.manifest file
Locate and change the following line
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
to
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Thanks,
I hope you find this helpful :)
It is better to use a foreach loop to get the folder names that you can acces:
DirectoryInfo dI = new DirectoryInfo(#"C:\Users\Dave");
List<string> files = new List<string>();
foreach (DirectoryInfo subDI in dI.GetDirectories())
{
if ((subDI.Attributes & (FileAttributes.ReparsePoint | FileAttributes.System)) !=
(FileAttributes)0)
continue;
files.Add(subDI.FullName);
}
Related
I have a console application that is either impersonating the Domain Admin or runs as the domain admin. It is supposed to read all of the directory names in a folder with Access based enumeration enabled and then apply some permissions on the folders. The part of the application getting the directories is:
string dirPath = ConfigurationManager.AppSettings["EPath"] + #"2019 Working Files";
DirectoryInfo di = new DirectoryInfo(dirPath);
DirectoryInfo[] directories = di.GetDirectories();
foreach (DirectoryInfo dir in directories)
{
// Doing something...
}
I have logged into the server where this needs to run as both the local and domain admins and run this. I have also tried impersonating the same users and all that is retrieved is 45 of over 6500 directory information items. The code I use for impersonating the administrator is:
string impersonatedUserName = ConfigurationManager.AppSettings["EstimatingPathUser"].ToString();
string impersonationDomain = ConfigurationManager.AppSettings["EstimatingPathDomain"].ToString();
string impersonatedUserPassword = ConfigurationManager.AppSettings["EstimatingPathPassword"].ToString();
SafeTokenHandle safeTokenHandle;
string dirPath = ConfigurationManager.AppSettings["EPath"] + #"2019 Working Files";
DirectoryInfo di = new DirectoryInfo(dirPath);
DirectoryInfo[] directories = di.GetDirectories();
if (LogonUser(impersonatedUserName, impersonationDomain, impersonatedUserPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle))
{
directories = di.GetDirectories();
}
foreach (DirectoryInfo dir in directories)
{
// Doing something...
}
I have even tried impersonating the Owner of all of the folders. Nothing seems to work.
generally its no problem to do that - just tested
maybe you can check your permissions to one of the missing folders like this:
System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(folderPath);
You could also try to run your app 'as administrator' maybe that helps
Please let me know
Overnight the server was rebooted and the application runs properly now. All 6519 folders were found and processed.
Iam asking this question as a series to the below link
Unable to delete .exe file through c#
While i was debugging the application,iam able to delete the .exe file.But when i try to delete the application after installing in the desktop,again iam getting the exception message as "Access is denied".
Edit:-
The code i am using to delete the file
public bool deleteAppExecutable(string filePath)
{
try
{
if (File.Exists(filePath))
{
var di = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
di.Attributes &= ~FileAttributes.ReadOnly;
SetAccessRule(filePath);
File.SetAttributes(filePath, File.GetAttributes(filePath) & ~FileAttributes.ReadOnly);
File.Delete(filePath);
}
return true;
}
catch (Exception ex)
{
return false;
}
}
public static void SetAccessRule(string filePath)
{
FileInfo dInfo = new FileInfo(filePath);
FileSecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(Environment.UserName, FileSystemRights.Delete, AccessControlType.Allow));
dInfo.Refresh();
dInfo.SetAccessControl(dSecurity);
}
I found the solution why i am getting the "access is denied" exception in my application.
Since i am deleting a file inside the application through code i need to have the privilege of "Administrator".
One way is to make the user login manually as administrator.But that is not a better option.
Another way is to create an App Manifest file within your project and set the level as "administrator."
Creating App Manifest--> Right click on the project->Add new item-->Select App Manifest option from the right pane->Click ok
Open the manifest file and change the level to "requireAdministartor".
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
This will solve the issue while running the application,it will prompt user to run as administrator.
Hope this will be helpful to someone in future. :)
Check that you have full permissions on the folder the exe is contained in (and all of it's child objects)
I have server-client application, it's a file manager
my problem is when I go inside a folder which requires access control like system folders, it becomes to read-only, but I need to move/delete or create new folder, how can I get the permission to do that?
here's how I create a new folder at the server side
public void NewFolder(string path)
{
try
{
string name = #"\New Folder";
string current = name;
int i = 0;
while (Directory.Exists(path + current))
{
i++;
current = String.Format("{0} {1}", name, i);
}
Directory.CreateDirectory(path + current);
Explore(path); //this line is to refresh the items in the client side after creating the new folder
}
catch (Exception e)
{
sendInfo(e.Message, "error");
}
}
There are often directories on a drive that even a user with administrator privileges cannot access. A directory with a name like "HDDRecovery" is quite likely to be troublesome like this. Surely it contains sensitive data that helps the user recover from disk failure. Another directory that fits this category is "c:\system volume information", it contains restore point data.
An admin can change the permissions on folders like this. But of course that doesn't solve the real problem nor is it a wise thing to do. Your user can't and shouldn't. Be sure to write code that deals with permission problems like this, simply catch the IOExeption. Keep the user out of trouble by never showing a directory that has the Hidden or System attribute set. They are the "don't mess with me" attributes.
If you want to remove directory read-only attribute use this: http://social.msdn.microsoft.com/Forums/en/vblanguage/thread/cb75ea00-f9c1-41e5-ac8e-296c302827a4
If you want to access system folders you can run your program as local administrator.
I had a similar problem (asp.net MVC vs2017) with this code:
Directory.CreateDirectory("~/temp");
Here is my solution:
// Create path on your web server
System.IO.Directory.CreateDirectory(System.Web.HttpContext.Current.Server.MapPath("~/temp"));
I also ran into an issue similar to this, but I was able to manually navigate through Windows Explorer and create directories.
However, my web app, running in VS on my laptop, hosted through my local IIS and not the built-in IIS deal for VS, was triggering the Access Denied issue.
So when I was hitting the error in code, I drilled down to glean more data from the System.Environment object and found the user, which of course was the App Pool that my app was running under in IIS.
So I opened IIS and opened the Advanced Settings for the app pool in question and changed the Identity to run under Network Service. Click OK. "cmd -> iisreset" for good measure. Try the app again, and SUCCESS!!!!
I had the same issue when creating a directory. I used DirectorySecurity as shown below:
DirectorySecurity securityRules = new DirectorySecurity();
securityRules.AddAccessRule(new FileSystemAccessRule(#"Domain\AdminAccount1", FileSystemRights.Read, AccessControlType.Allow));
securityRules.AddAccessRule(new FileSystemAccessRule(#"Domain\YourAppAllowedGroup", FileSystemRights.FullControl, AccessControlType.Allow));
DirectoryInfo di = Directory.CreateDirectory(path + current, securityRules);
Also keep in mind about the security as explained by Hans Passant's answer.
Full details can be found on MSDN.
So the complete code:
public void NewFolder(string path)
{
try
{
string name = #"\New Folder";
string current = name;
int i = 0;
while (Directory.Exists(path + current))
{
i++;
current = String.Format("{0} {1}", name, i);
}
//Directory.CreateDirectory(path + current);
DirectorySecurity securityRules = new DirectorySecurity();
securityRules.AddAccessRule(new FileSystemAccessRule(#"Domain\AdminAccount1", FileSystemRights.Read, AccessControlType.Allow));
securityRules.AddAccessRule(new FileSystemAccessRule(#"Domain\YourAppAllowedGroup", FileSystemRights.FullControl, AccessControlType.Allow));
DirectoryInfo di = Directory.CreateDirectory(path + current, securityRules);
Explore(path); //this line is to refresh the items in the client side after creating the new folder
}
catch (Exception e)
{
sendInfo(e.Message, "error");
}
}
My suspicion is that when you are running the application in client/server mode, the server portion needs to be running as Administrator, in addition to possibly removing read-only or system flags, to be able to do what you want.
That said, I agree with #HansPassant- it sounds like what you are trying to do is ill-advised.
Solved:
Directory created on remote server using below code & setting.
Share folder and give the full permission rights also in Advance
setting in the folder.
DirectoryInfo di = Directory.CreateDirectory(#"\\191.168.01.01\Test\Test1");
Test is destination folder where to create new Test1 folder(directory)
Problems
UnAuthorizedAccessException: When searching a directory recursively such as C:\
A "Access to the path 'c:\Documents and Settings\' is denied." Occurs even with UAC Priveledges upgraded & Administrator group access.
Attempted Methods
Try & Catch: Using either one of these methods(Exception, UnAuthorizedAccessException, Blank Catch, continue)
Questions
How do you handle this kind of exception and continue running your program as normal? This needs to work both on non-admin and administrator accounts.
Example Code
using System;
using System.IO;
namespace filecheck
{
class Program
{
static void Main(string[] args)
{
int i = 0;
int html = 0;
try
{
string[] filePaths = Directory.GetFiles(#"c:\", "*.html", SearchOption.AllDirectories);
foreach (string files in filePaths)
{
if (Convert.ToBoolean(files.IndexOf("html")))
{
html++;
}
Console.WriteLine(files);
i++;
}
Console.Write("# Files found: {0} Html: {1)", i, html);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
}
}
Unfortunately the only way to handle this is by doing the recursion manually. Even in Microsoft's own sample code they do it this way, just to avoid that the whole search fails because one or more directories can not be accessed.
So in other words, only use SearchOption.AllDirectories when you're searching a limited subset of directories which you're certain won't contain any directories which you won't have access to.
To get your program working with both admin and non-admin users you either need to impersonate the user or re-build your application to "Run as Administrator" every time it is being executed or used by any user. To build this kind of application you need to add app.manifest file to your project and un-comment the following line of setting in app.manifest
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
For more read here: http://midnightprogrammer.net/post/How-To-Build-UAC-Compatible-Application-In-NET.aspx
I am using the following code to fire the iexplore process. This is done in a simple console app.
public static void StartIExplorer()
{
var info = new ProcessStartInfo("iexplore");
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
string password = "password";
SecureString securePassword = new SecureString();
for (int i = 0; i < password.Length; i++)
securePassword.AppendChar(Convert.ToChar(password[i]));
info.UserName = "userName";
info.Password = securePassword;
info.Domain = "domain";
try
{
Process.Start(info);
}
catch (System.ComponentModel.Win32Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The above code is throwing the error The system cannot find the file specified. The same code when run without specifying the user credentials works fine. I am not sure why it is throwing this error.
Can someone please explain?
Try to replace your initialization code with:
ProcessStartInfo info
= new ProcessStartInfo(#"C:\Program Files\Internet Explorer\iexplore.exe");
Using non full filepath on Process.Start only works if the file is found in System32 folder.
You can't use a filename like iexplore by itself because the path to internet explorer isn't listed in the PATH environment variable for the system or user.
However any path entered into the PATH environment variable allows you to use just the file name to execute it.
System32 isn't special in this regard as any directory can be added to the PATH variable. Each path is simply delimited by a semi-colon.
For example I have c:\ffmpeg\bin\ and c:\nmap\bin\ in my path environment variable, so I can do things like new ProcessStartInfo("nmap", "-foo") or new ProcessStartInfo("ffplay", "-bar")
The actual PATH variable looks like this on my machine.
%SystemRoot%\system32;C:\FFPlay\bin;C:\nmap\bin;
As you can see you can use other system variables, such as %SystemRoot% to build and construct paths in the environment variable.
So - if you add a path like "%PROGRAMFILES%\Internet Explorer;" to your PATH variable you will be able to use ProcessStartInfo("iexplore");
If you don't want to alter your PATH then simply use a system variable such as %PROGRAMFILES% or %SystemRoot% and then expand it when needed in code. i.e.
string path = Environment.ExpandEnvironmentVariables(
#"%PROGRAMFILES%\Internet Explorer\iexplore.exe");
var info = new ProcessStartInfo(path);
Also, if your PATH's dir is enclosed in quotes, it will work from the command prompt but you'll get the same error message
I.e. this causes an issue with Process.Start() not finding your exe:
PATH="C:\my program\bin";c:\windows\system32
Maybe it helps someone.
I had the same problem, but none of the solutions worked for me, because the message The system cannot find the file specified can be misleading in some special cases.
In my case, I use Notepad++ in combination with the registry redirect for notepad.exe. Unfortunately my path to Notepad++ in the registry was wrong.
So in fact the message The system cannot find the file specified was telling me, that it cannot find the application (Notepad++) associated with the file type(*.txt), not the file itself.
I know it's a bit old and although this question have accepted an answer, but I think its not quite answer.
Assume we want to run a process here C:\Program Files\SomeWhere\SomeProcess.exe.
One way could be to hard code absolute path:
new ProcessStartInfo(#"C:\Program Files\SomeWhere\SomeProcess.exe")
Another way (recommended one) is to use only process name:
new ProcessStartInfo("SomeProcess.exe")
The second way needs the process directory to be registered in Environment Variable Path variable. Make sure to add it in System Variables instead of Current User Variables, this allows your app to access this variable.
You can use the folowing to get the full path to your program like this:
Environment.CurrentDirectory