First of all, the forum has given me very good ideas and solutions just by reading along.
To my current case I willnot really looking for it.
I have written a WPF application that works perfectly in debug and release mode. However, as soon as I publish you, no more.
I tried different ways to publish.
The application is provided by CD, DVD or stick.
The clickonce method was once used sometimes not.
It should be created as independently executable. And the framework is included.
My problem is that after publishing via the release build, I have no permission to write to files in Environment.CurrentDirectory or outside.
In one case, the affected file is supplied but cannot be changed. As soon as I exchange the file after installation, I can change it.
In another case, I can't create a file using the directive. The StreamWriter is used. But also creating folders using System.IO is not possible.
The application is run by an administrator. Only when the application is executed with RunAsAdmin does it run without problems.
The file is a txt file that acts as a log file. However, users without administrator rights should also be able to update the log file if necessary.
What can I do so that my application can generally generate files, regardless of the user rights?
Thank you very much.
You can check my code snippet:
private bool HasPathAccessable(string path)
{
DirectorySecurity sec = Directory.GetAccessControl(path);
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
foreach (FileSystemAccessRule acr in sec.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)))
{
//Console.WriteLine("{0} | {1} | {2} | {3} | {4}", acr.IdentityReference.Value, acr.FileSystemRights, acr.InheritanceFlags, acr.PropagationFlags, acr.AccessControlType);
if (acr.IdentityReference.Value == currentIdentity.Name)
{
if (acr.FileSystemRights == FileSystemRights.FullControl && acr.AccessControlType == AccessControlType.Allow)
{
Console.WriteLine($"{currentIdentity.Name} accessable to {path}");
return true;
}
}
}
Console.WriteLine($"{currentIdentity.Name} inaccessable to {path}");
return false;
}
private void ChangePathAccessControlCurrentUser(string path, bool isFile)
{
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
if (isFile)
{
var pathAccessControl = File.GetAccessControl(path);
pathAccessControl.AddAccessRule(new FileSystemAccessRule(currentIdentity.Name, FileSystemRights.FullControl, AccessControlType.Allow));
File.SetAccessControl(path, pathAccessControl);
Console.WriteLine($"AddAccessRule File : {path}");
}
else
{
var pathAccessControl = Directory.GetAccessControl(path);
pathAccessControl.AddAccessRule(new FileSystemAccessRule(currentIdentity.Name, FileSystemRights.FullControl, AccessControlType.Allow));
Directory.SetAccessControl(path, pathAccessControl);
Console.WriteLine($"AddAccessRule Directory : {path}");
}
}
Related
I've been trying with number of ways but I'm unable to avoid the alert which says 'Do you want to open the application as administrator'. can some one suggest such piece of code which avoids/handles the alert to add new entry into hosts file.
Thanks in advance..
public bool ModifyHostsFile(string sEntryIPAddr, string sEntryURL)
{
try
{
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
bool administrativeMode = principal.IsInRole(WindowsBuiltInRole.Administrator);
if (!administrativeMode)
{
//ProcessStartInfo startInfo = new ProcessStartInfo();
//startInfo.Verb = "runas";
//startInfo.FileName = Application.ExecutablePath;
//Process.Start(startInfo);
//bool bStatus = GrantAccess(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), #"drivers\etc\hosts"));
using (StreamWriter w = File.AppendText(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), #"drivers\etc\hosts")))
{
w.WriteLine(sEntryIPAddr + " " + sEntryURL);
}
Application.Exit();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
private bool GrantAccess(string fullPath)
{
DirectoryInfo dInfo = new DirectoryInfo(fullPath);
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);
return true;
}
No, you definitely need admin access to modify the file - Or else any virus could hijack the hosts file and redirect all browsers requests to a malicious site.
I don't have the rep to comment to ask some question I have but instead I will answer based on assumptions.
Your goal
To run an application with administrative rights
Why the UAC popup?
The popup you get asking for Admin Rights is to prevent applications from simply taking admin rights without your knowledge and thereby modifying your system's critical files
How to prevent it?
I HIGHLY recommend not taking this step but the first option that comes to mind is to disable UAC (User Account Controls) from your control panel
Alternative
An alternative could be to run the program as a scheduled task, set to run with the highest privileges. Then you can execute the program by running the scheduled task and have admin access without the UAC popup.
This can be done via command-line or via the GUI and still requires admin privileges for the creation of the schedules task
I was successfully able to remove read only attribute on a file using the following code snippet:
In main.cs
FileSystemInfo[] sqlParentFileSystemInfo = dirInfo.GetFileSystemInfos();
foreach (var childFolderOrFile in sqlParentFileSystemInfo)
{
RemoveReadOnlyFlag(childFolderOrFile);
}
private static void RemoveReadOnlyFlag(FileSystemInfo fileSystemInfo)
{
fileSystemInfo.Attributes = FileAttributes.Normal;
var di = fileSystemInfo as DirectoryInfo;
if (di != null)
{
foreach (var dirInfo in di.GetFileSystemInfos())
RemoveReadOnlyFlag(dirInfo);
}
}
Unfortunately, this doesn't work on the folders. After running the code, when I go to the folder, right click and do properties, here's what I see:
The read only flag is still checked although it removed it from files underneath it. This causes a process to fail deleting this folder. When I manually remove the flag and rerun the process (a bat file), it's able to delete the file (so I know this is not an issue with the bat file)
How do I remove this flag in C#?
You could also do something like the following to recursively clear readonly (and archive, etc.) for all directories and files within a specified parent directory:
private void ClearReadOnly(DirectoryInfo parentDirectory)
{
if(parentDirectory != null)
{
parentDirectory.Attributes = FileAttributes.Normal;
foreach (FileInfo fi in parentDirectory.GetFiles())
{
fi.Attributes = FileAttributes.Normal;
}
foreach (DirectoryInfo di in parentDirectory.GetDirectories())
{
ClearReadOnly(di);
}
}
}
You can therefore call this like so:
public void Main()
{
DirectoryInfo parentDirectoryInfo = new DirectoryInfo(#"c:\test");
ClearReadOnly(parentDirectoryInfo);
}
Try DirectoryInfo instead of FileInfo
DirectoryInfo di = new DirectoryInfo(#"c:\temp\content");
di.Attributes = FileAttributes.Normal;
To clean up attrbutes on files-
foreach (string fileName in System.IO.Directory.GetFiles(#"c:\temp\content"))
{
System.IO.FileInfo fileInfo = new System.IO.FileInfo(fileName);
fileInfo.Attributes = FileAttributes.Normal;
}
The dialog just works in a fairly bizarre way. It always shows up the way you see it in your screen shot, whatever the state of the ReadOnly attribute. The checkbox is in the 'indetermined' state. You have to click it and either clear or check it to make it perform its action. And in spite of the prompt text (but not the hint next to the checkbox), it only changes the ReadOnly attribute on the files in the directory, not the directory itself.
Use the attrib command line command to see what is really going on. In all likelihood, your code fails because the directory contains files that have their ReadOnly attribute set. You'll have to iterate them.
The read-only flag on directories in Windows is actually a misnomer. The folder does not use the read-only flag. The issue is going to be with the customization. The flag is used by Windows to identify that there are customizations on the folder.
This is an old post, with an issue that is sunsetting, but, figured people might still run into it, as it is pretty annoying when you hit it.
Microsoft's Explanation
IEnumerable / Lambda solution for recursively removing readonly attribute from directories and files:
new DirectoryInfo(#"some\test\path").GetDirectories("*", SearchOption.AllDirectories).ToList().ForEach(
di => {
di.Attributes &= ~FileAttributes.ReadOnly;
di.GetFiles("*", SearchOption.TopDirectoryOnly).ToList().ForEach(fi => fi.IsReadOnly = false);
}
);
Set the Attributes property on the original dirInfo:
dirInfo.Attributes = FileAttributes.Normal;
FileSystemInfo[] sqlParentFileSystemInfo = dirInfo.GetFileSystemInfos();
foreach (var childFolderOrFile in sqlParentFileSystemInfo)
{
RemoveReadOnlyFlag(childFolderOrFile);
}
Just in case any one happens across this later...
ALL of the other answers posted before mine are either wrong or use unnecessary recursion.
First of all the "Read Only" check box in the property dialog of windows always has the tri-state marker for folders. This is because the folder itself is not read only but the files inside can be.
If you want to set/unset read only flag for ALL files. you can do it simply as follows:
void SetReadOnlyFlagForAllFiles(DirectoryInfo directory, bool isReadOnly)
{
// Iterate over ALL files using "*" wildcard and choosing to search all directories.
foreach(FileInfo File in directory.GetFiles("*", SearchOption.All.Directories))
{
// Set flag.
File.IsReadOnly = isReadOnly;
}
}
I see that #DotnetDude said in comments that solutions of guys don't work. To my mind it is happens because guys don't mentioned that need to use File.SetAttributes method to apply new attributes.
This may or may not be directly related, but the root issue in your case may be caused by the underlying files. For example, I ran into this issue trying to delete a directory:
System.IO.Directory.Delete(someDirectory, true)
This results in "Access to the path 'blah' is denied". To resolve this underlying problem, I removed the read-only attribute on sub-files and was then able to remove the parent directory. In my case, I was using powershell, so you can use the .NET equivalent.
dir -r $PrePackageDirectory |% {if ($_.PSIsContainer -ne $true){$_.IsReadOnly = $false}}
Shell("net share sharefolder=c:\sharefolder/GRANT:Everyone,FULL")
Shell("net share sharefolder= c:\sharefolder/G:Everyone:F /SPEC B")
Shell("Icacls C:\sharefolder/grant Everyone:F /inheritance:e /T")
Shell("attrib -r +s C:\\sharefolder\*.* /s /d", AppWinStyle.Hide)
this code is working for me.. to share a folder to every one with read and write permission
I'm using Directory.Move(oldDir, newDir) to rename a directory. Every now and then I get a IOException saying "Access to the path "oldDir" is denied". However if I right click the directory in the explorer I can rename it without any issues. How's that and how can I get it to work?
EDIT
The program is still running, I get the exception and can rename it manually while my cursor is paused on the breakpoint. I also tried setting a breakpoint at Directory.Move, successfully renamed the directory in explorer (and back again), stepped over Directory.Move and ended up in the catch (IOException) again. So I don't see why my program should lock the directory at all. There must be something else.
Any ideas?
EDIT 2
Here is my code
public bool Copy()
{
string destPathRelease = ThisUser.DestPath + "\\Release";
if (Directory.Exists(destPathRelease))
{
try
{
string newPath = ThisUser.DestPath + '\\' + (string.IsNullOrEmpty(currBuildLabel) ? ("Release" + '_' + DateTime.Now.ToString("yyyyMMdd_HHmmss")) : currBranchName) + '.' + currBuildLabel;
Directory.Move(destPathRelease, newPath);
catch (IOException)
{
// Breakpoint
}
}
}
}
As you can see I just entered the method. I never touched the directory in my program before. Is there another way to rename a directory?
Without seeing more code I'd say your application is locking a file within the directory, you can see what is accessing the directory using Process explorer
from the intro to process explorer:
Ever wondered which program has a particular file or directory open? Now you can find out. Process Explorer shows you information about which handles and DLLs processes have opened or loaded.
It might also be worth making sure nothing else is copying files from/to that directory - e.g. dropbox. I had an issue recently where visual studio would stop debugging because of a file lock - in the end it was indexing on the drive which was temporarily locking the file. Process explorer only partially helped in that it showed 'system' had the file lock and not another application.
You need to check the User that is running the .net application. It don't have the right permission to execute the rename.
This is:
the user running the application pool for web applications
the logged application for console/winforms application
the configured user for services or scheduled tasks
If the parent directory of your destination directory does not exist, The Directory.Move operation with fail. I've just been trying to figure out something loosely similar to this.
This is the safest method to rename a directory in the C# .NET Core with cross-platform.
/// <summary>
/// Renames a folder name
/// </summary>
/// <param name="directory">The full directory of the folder</param>
/// <param name="newFolderName">New name of the folder</param>
/// <returns>Returns true if rename is successfull</returns>
public static bool RenameFolder(string directory, string newFolderName)
{
try
{
if (string.IsNullOrWhiteSpace(directory) ||
string.IsNullOrWhiteSpace(newFolderName))
{
return false;
}
var oldDirectory = new DirectoryInfo(directory);
if (!oldDirectory.Exists)
{
return false;
}
if (string.Equals(oldDirectory.Name, newFolderName, StringComparison.OrdinalIgnoreCase))
{
//new folder name is the same with the old one.
return false;
}
string newDirectory;
if (oldDirectory.Parent == null)
{
//root directory
newDirectory = Path.Combine(directory, newFolderName);
}
else
{
newDirectory = Path.Combine(oldDirectory.Parent.FullName, newFolderName);
}
if (Directory.Exists(newDirectory))
{
//target directory already exists
return false;
}
oldDirectory.MoveTo(newDirectory);
return true;
}
catch
{
//ignored
return false;
}
}
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)
We recently were forced to move to a new domain server half-way around the world. This may not seem like much of a change, but one of the processes that we run frequently has suddenly gone form a 2-second command to a 5-minute command.
The reason? We are updating the permissions on many directories based on a "template" directory structure.
We've discovered that XCOPY can update the majority of these settings in the same-old-two-second window. The remaining settings, of course, get left off.
What I'm trying to figure out is, how can XCopy do faster what .NET security classes should do natively? Obviously I'm missing something.
What is the best method for copying a directory's ACL information without pinging (or minimal pinging) the domain/Active Directory server?
Here's what I have:
...
DirectorySecurity TemplateSecurity = new DirectorySecurity(TemplateDir, AccessControlSections.All);
...
public static void UpdateSecurity(string destination, DirectorySecurity TemplateSecurity)
{
DirectorySecurity dSecurity = Directory.GetAccessControl(destination);
// Remove previous security settings. (We have all we need in the other TemplateSecurity setting!!)
AuthorizationRuleCollection acl_old = dSecurity.GetAccessRules(true, true, typeof(NTAccount));
foreach (FileSystemAccessRule ace in acl_old)
{
// REMOVE IT IF YOU CAN... if you can't don't worry about it.
try
{
dSecurity.RemoveAccessRule(ace);
}
catch { }
}
// Remove the inheritance for the folders...
// Per the business unit, we must specify permissions per folder.
dSecurity.SetAccessRuleProtection(true, true);
// Copy the permissions from TemplateSecurity to Destination folder.
AuthorizationRuleCollection acl = TemplateSecurity.GetAccessRules(true, true, typeof(NTAccount));
foreach (FileSystemAccessRule ace in acl)
{
// Set the existing security.
dSecurity.AddAccessRule(ace);
try
{
// Remove folder inheritance...
dSecurity.AddAccessRule(new FileSystemAccessRule(
ace.IdentityReference, ace.FileSystemRights,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None,
ace.AccessControlType));
}
catch { }
}
// Apply the new changes.
Directory.SetAccessControl(destination, dSecurity);
}
Okay... I have a working prototype after A TON OF DIGGING on the internet. Needless to say, there's alot of mis-information about ACL online. I'm not exactly certain if this bit of info will be a godsend, or more mis-information. I'll have to leave that for you, the user, to decide.
What I ended up with is clean, slick, and very, very fast since it doesn't ever TOUCH the domain server. I'm copying the SDDL entries directly. Wait, you say... you can't do that on a directory because you get the dreaded SeSecurityPrivilege error!
Not if you restrict the copy to ONLY the Access Control Lists (ACL).
Here's the code:
public static void UpdateSecurity(string destination, DirectorySecurity templateSecurity)
{
DirectorySecurity dSecurity = Directory.GetAccessControl(destination);
string sddl = templateSecurity.GetSecurityDescriptorSddlForm(AccessControlSections.Access);
try
{
// TOTALLY REPLACE The existing access rights with the new ones.
dSecurity.SetSecurityDescriptorSddlForm(sddl, AccessControlSections.Access);
// Disable inheritance for this directory.
dSecurity.SetAccessRuleProtection(true, true);
// Apply these changes.
Directory.SetAccessControl(destination, dSecurity);
}
catch (Exception ex)
{
// Note the error on the console... we can formally log it later.
Console.WriteLine(pth1 + " : " + ex.Message);
}
// Do some other settings stuff here...
}
Note the AccessControlSections.Access flags on the SDDL methods. That was the magic key to make it all work.