bashing my head against the wall with this one, tried adding an app manifest and elevating, but whenever my program tries to read c:\users\username\appdata\roaming\microsoft\teams\logs.txt
it throws an exception.
If I use PowerShell, I can read this file with no permissions issues.
Edit - what is interesting is if I compare the security of two folders at the same level, s ay the Excel Folder and the teams folder under /appdata/roaming/Microsoft. Both are identical, and I can access the Excel one but not the teams one. Even Elevating does not help. Yet outside of Visual Studio, I can browse and access these paths quite happily as a user..
Here is the code snippet:
private static string GetTeamsLog()
{
string homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
// Code to read the log files and return the contents as a string
// Path to the log file(s)
string logPath = homeDir + #"\AppData\Roaming\Microsoft\Teams\";
string logFile = logPath + "logs.txt";
string log = "";
try
{
if (!File.Exists(logFile))
{
throw new FileNotFoundException("The log file was not found.");
}
if ((File.GetAttributes(logFile) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
{
throw new UnauthorizedAccessException("The application doesn't have the necessary permissions to access the file.");
}
if (Path.GetFullPath(logFile).Length > 260)
{
throw new PathTooLongException("The specified path is too long.");
}
if (!DriveInfo.GetDrives().FirstOrDefault(x => x.RootDirectory.Name == Path.GetPathRoot(logFile)).IsReady)
{
throw new DriveNotFoundException("The specified drive is not valid or not ready.");
}
// Read the contents of the log file
log = System.IO.File.ReadAllText(logFile);
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.Message);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine(e.Message);
}
return log;
}
The error triggered by log = System.IO.File.ReadAllText(logfile); is
System.UnauthorizedAccessException: 'Access to the path 'C:\Users\jimmy\AppData\Roaming\Microsoft\Teams\logs.txt' is denied.'
This exception was originally thrown at this call stack:
Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(string, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, System.IO.FileOptions)
Microsoft.Win32.SafeHandles.SafeFileHandle.Open(string, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, System.IO.FileOptions, long, System.IO.UnixFileMode?)
System.IO.Strategies.OSFileStreamStrategy.OSFileStreamStrategy(string, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, System.IO.FileOptions, long, System.IO.UnixFileMode?)
System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(string, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, System.IO.FileOptions, long, System.IO.UnixFileMode?)
System.IO.StreamReader.ValidateArgsAndOpenPath(string, System.Text.Encoding, int)
System.IO.File.ReadAllText(string, System.Text.Encoding)
TeamsMonitor.Form1.GetTeamsLog() in Form1.cs
It might be used by Teams. So read it this way:
using(FileStream logFileStream = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using(StreamReader logFileReader = new StreamReader(logFileStream))
{
string text = logFileReader.ReadToEnd();
// Your code..
}
}
For completeness, it appears Acronis Cyber Protect was messing with the permissions. Even though the "protection" was disabled, the Acronis Cyber Protect service was still running. Once killed, I no longer had any issues.
Related
I know this is a common problem with a lot of related topics on here. But none of them seem to work for me.
I have code that works on a production system that I've copied across to my local home computer:
private static void WriteToLog(string logText, string logPath)
{
try
{
using (StreamWriter outputFile = File.AppendText(logPath))
{
outputFile.WriteLine(DateTime.Now.ToString() + "|| " + Regex.Replace(logText, #"\t|\n|\r", ""));
}
}
catch (IOException ex)
{
//what do?
throw ex;
}
}
The line using (StreamWriter outputFile = File.AppendText(logPath)) throws the classic exception:
System.UnauthorizedAccessException: 'Access to the path
'C:\Users\Jaso\Documents\DataChecker_Logs\schema_a-academic_attainment.txt'
is denied.'
At runtime the path variable contains "C:\\Users\\Jaso\\Documents\\DataChecker_Logs\\schema_a-academic_attainment.txt"
The Security of the folder in question looks like this:
When I find the user the process is run under using WindowsIdentity.GetCurrent().Name;, the value returned is "DESKTOP-LMMBET3\\Jaso" which according to the folder's settings (above screenshot) is a principal with full control!!
Windows 10 machine.
GRRR!!!
Check the permission of the file itself not the folder
if you don't have the permission to access the file this error will be thrown
System.UnauthorizedAccessException
I have the following trivial C# application that simply attempts to launch "jconsole.exe", which on my machine is located in C:\Programs\jdk16\bin.
using System;
using System.Diagnostics;
namespace dnet {
public class dnet {
static void Main( string[] args ) {
try {
Process.Start("jconsole.exe");
Console.WriteLine("Success!");
} catch (Exception e) {
Console.WriteLine("{0} Exception caught.", e);
}
}
}
}
If my PATH environment variable is set to
c:\windows;c:\windows\sytem32;c:\programs\jdk16\bin
it works perfectly. However, if the PATH environment variable is set to
c:\windows;c:\windows\sytem32;c:\\programs\jdk16\bin
(note the two backslashes between "c:" and "programs"), it fails with a win32 exception.
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at dnet.dnet.Main(String[] args)
Interestingly, in the same command prompt where I run the .NET program and get the exception, I can simply type "jconsole.exe", and the program will start. Windows appears to have no trouble finding the executable with the double backslash in the PATH, but Process.Start() does.
Why is the extra backslash in the PATH causing problems, and how I can get around the problem? I don't know where the executable I want to call will be located at runtime, so I'd rather rely on the PATH variable.
Not quite sure why the problem occurs. Though, I can think of one solution that works on my machine:
var enviromentPath = System.Environment.GetEnvironmentVariable("PATH");
Console.WriteLine(enviromentPath);
var paths = enviromentPath.Split(';');
var exePath = paths.Select(x => Path.Combine(x, "mongo.exe"))
.Where(x => File.Exists(x))
.FirstOrDefault();
Console.WriteLine(exePath);
if (string.IsNullOrWhiteSpace(exePath) == false)
{
Process.Start(exePath);
}
I did find one para which gave me the idea for this solution. From the documentation for Process.Start
If you have a path variable declared in your system using quotes, you
must fully qualify that path when starting any process found in that
location. Otherwise, the system will not find the path. For example,
if c:\mypath is not in your path, and you add it using quotation
marks: path = %path%;"c:\mypath", you must fully qualify any process
in c:\mypath when starting it.
The way I read it, even though the PATH variable contained a valid path that Windows is able to use, Process.Start is unable to use it and needs the fully qualified path .
You can solve it if you first create a ProcessStartInfo.
ProcessStartInfo psi = new ProcessStartInfo("jconsole.exe");
StringDictionary dictionary = psi.EnvironmentVariables;
// Manipulate dictionary...
psi.EnvironmentVariables["PATH"] = dictionary.Replace(#"\\", #"\");
Process.Start(psi);
You'll have to find out yourself how to manipulate the PATH to let it work for you. But this should solve any issues you might have with your PATH variable.
The accepted answer is incorrect.
cmd.exe will find applications with executable extensions first.
So when you have the files puma and puma.bat in C:\Ruby\bin\, then puma.bat will take precedence over puma.
If you start c:\ruby\bin\puma.bat from c:\redmine, it will start puma with current working directory c:\ruby\bin, and your web application will work.
However, if you start c:\ruby\bin\puma directly, it will start puma with the current working directory in c:\redmine and will subsequently fail.
So a corrected version looks more or less like this:
// FindAppInPathDirectories("ruby.exe");
public string FindAppInPathDirectories(string app)
{
string enviromentPath = System.Environment.GetEnvironmentVariable("PATH");
string[] paths = enviromentPath.Split(';');
foreach (string thisPath in paths)
{
string thisFile = System.IO.Path.Combine(thisPath, app);
string[] executableExtensions = new string[] { ".exe", ".com", ".bat", ".sh", ".vbs", ".vbscript", ".vbe", ".js", ".rb", ".cmd", ".cpl", ".ws", ".wsf", ".msc", ".gadget" };
foreach (string extension in executableExtensions)
{
string fullFile = thisFile + extension;
try
{
if (System.IO.File.Exists(fullFile))
return fullFile;
}
catch (System.Exception ex)
{
Log("{0}:\r\n{1}",
System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture)
, "Error trying to check existence of file \"" + fullFile + "\""
);
Log("Exception details:");
Log(" - Exception type: {0}", ex.GetType().FullName);
Log(" - Exception Message:");
Log(ex.Message);
Log(" - Exception Stacktrace:");
Log(ex.StackTrace);
} // End Catch
} // Next extension
} // Next thisPath
foreach (string thisPath in paths)
{
string thisFile = System.IO.Path.Combine(thisPath, app);
try
{
if (System.IO.File.Exists(thisFile))
return thisFile;
}
catch (System.Exception ex)
{
Log("{0}:\r\n{1}",
System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture)
, "Error trying to check existence of file \"" + thisFile + "\""
);
Log("Exception details:");
Log(" - Exception type: {0}", ex.GetType().FullName);
Log(" - Exception Message:");
Log(ex.Message);
Log(" - Exception Stacktrace:");
Log(ex.StackTrace);
} // End Catch
} // Next thisPath
return app;
} // End Function FindAppInPathDirectories
I have a C# application which uses log4net to write some log outputs in a file names "logfile.txt" residing in the application directory. I want to empty the contents of the file as soon as it reaches a size of 10GB.
For that I'm using a timer which keeps checking whether the size of the file crosses 10GB.
But I cannot perform any operation on "logfile.txt" since it is being used by other threads to write log outputs and it's throwing me,
System.IO.IOException "The process cannot access the file 'C:\Program Files\MyApps\TestApp1\logfile.txt' because it is being used by another process."
Here is the code of the timer which checks the size of the file "logfile.txt"
private void timer_file_size_check_Tick(object sender, EventArgs e)
{
try
{
string log_file_path = "C:\\Program Files\\MyApps\\TestApp1\\logfile.txt";
FileInfo f = new FileInfo(log_file_path);
bool ex;
long s1;
if (ex = f.Exists)
{
s1 = f.Length;
if (s1 > 10737418240)
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
File.Delete(log_file_path);
//File.Create(log_file_path).Close();
//File.Delete(log_file_path);
//var fs = new FileStream(log_file_path, FileMode.Truncate);
}
}
else
{
MDIParent.log.Error("Log file doesn't exists..");
}
}
catch (Exception er)
{
MDIParent.log.Error("Exceptipon :: " + er.ToString());
}
}
You shouldn't delete a log file on your own because log4net can do it for you. If you use RollingFileAppender you can specify the maximum file size (maximumFileSize property). Additionally if you set maxSizeRollBackups property to 0, then the log file will be truncated when it reaches the limit. Please look at this question for an example.
I have the following trivial C# application that simply attempts to launch "jconsole.exe", which on my machine is located in C:\Programs\jdk16\bin.
using System;
using System.Diagnostics;
namespace dnet {
public class dnet {
static void Main( string[] args ) {
try {
Process.Start("jconsole.exe");
Console.WriteLine("Success!");
} catch (Exception e) {
Console.WriteLine("{0} Exception caught.", e);
}
}
}
}
If my PATH environment variable is set to
c:\windows;c:\windows\sytem32;c:\programs\jdk16\bin
it works perfectly. However, if the PATH environment variable is set to
c:\windows;c:\windows\sytem32;c:\\programs\jdk16\bin
(note the two backslashes between "c:" and "programs"), it fails with a win32 exception.
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at dnet.dnet.Main(String[] args)
Interestingly, in the same command prompt where I run the .NET program and get the exception, I can simply type "jconsole.exe", and the program will start. Windows appears to have no trouble finding the executable with the double backslash in the PATH, but Process.Start() does.
Why is the extra backslash in the PATH causing problems, and how I can get around the problem? I don't know where the executable I want to call will be located at runtime, so I'd rather rely on the PATH variable.
Not quite sure why the problem occurs. Though, I can think of one solution that works on my machine:
var enviromentPath = System.Environment.GetEnvironmentVariable("PATH");
Console.WriteLine(enviromentPath);
var paths = enviromentPath.Split(';');
var exePath = paths.Select(x => Path.Combine(x, "mongo.exe"))
.Where(x => File.Exists(x))
.FirstOrDefault();
Console.WriteLine(exePath);
if (string.IsNullOrWhiteSpace(exePath) == false)
{
Process.Start(exePath);
}
I did find one para which gave me the idea for this solution. From the documentation for Process.Start
If you have a path variable declared in your system using quotes, you
must fully qualify that path when starting any process found in that
location. Otherwise, the system will not find the path. For example,
if c:\mypath is not in your path, and you add it using quotation
marks: path = %path%;"c:\mypath", you must fully qualify any process
in c:\mypath when starting it.
The way I read it, even though the PATH variable contained a valid path that Windows is able to use, Process.Start is unable to use it and needs the fully qualified path .
You can solve it if you first create a ProcessStartInfo.
ProcessStartInfo psi = new ProcessStartInfo("jconsole.exe");
StringDictionary dictionary = psi.EnvironmentVariables;
// Manipulate dictionary...
psi.EnvironmentVariables["PATH"] = dictionary.Replace(#"\\", #"\");
Process.Start(psi);
You'll have to find out yourself how to manipulate the PATH to let it work for you. But this should solve any issues you might have with your PATH variable.
The accepted answer is incorrect.
cmd.exe will find applications with executable extensions first.
So when you have the files puma and puma.bat in C:\Ruby\bin\, then puma.bat will take precedence over puma.
If you start c:\ruby\bin\puma.bat from c:\redmine, it will start puma with current working directory c:\ruby\bin, and your web application will work.
However, if you start c:\ruby\bin\puma directly, it will start puma with the current working directory in c:\redmine and will subsequently fail.
So a corrected version looks more or less like this:
// FindAppInPathDirectories("ruby.exe");
public string FindAppInPathDirectories(string app)
{
string enviromentPath = System.Environment.GetEnvironmentVariable("PATH");
string[] paths = enviromentPath.Split(';');
foreach (string thisPath in paths)
{
string thisFile = System.IO.Path.Combine(thisPath, app);
string[] executableExtensions = new string[] { ".exe", ".com", ".bat", ".sh", ".vbs", ".vbscript", ".vbe", ".js", ".rb", ".cmd", ".cpl", ".ws", ".wsf", ".msc", ".gadget" };
foreach (string extension in executableExtensions)
{
string fullFile = thisFile + extension;
try
{
if (System.IO.File.Exists(fullFile))
return fullFile;
}
catch (System.Exception ex)
{
Log("{0}:\r\n{1}",
System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture)
, "Error trying to check existence of file \"" + fullFile + "\""
);
Log("Exception details:");
Log(" - Exception type: {0}", ex.GetType().FullName);
Log(" - Exception Message:");
Log(ex.Message);
Log(" - Exception Stacktrace:");
Log(ex.StackTrace);
} // End Catch
} // Next extension
} // Next thisPath
foreach (string thisPath in paths)
{
string thisFile = System.IO.Path.Combine(thisPath, app);
try
{
if (System.IO.File.Exists(thisFile))
return thisFile;
}
catch (System.Exception ex)
{
Log("{0}:\r\n{1}",
System.DateTime.Now.ToString(m_Configuration.DateTimeFormat, System.Globalization.CultureInfo.InvariantCulture)
, "Error trying to check existence of file \"" + thisFile + "\""
);
Log("Exception details:");
Log(" - Exception type: {0}", ex.GetType().FullName);
Log(" - Exception Message:");
Log(ex.Message);
Log(" - Exception Stacktrace:");
Log(ex.StackTrace);
} // End Catch
} // Next thisPath
return app;
} // End Function FindAppInPathDirectories
I am making a software that will move files from the downloads folder to a specific sub folder in a directory. The sub folder is selected by the user by a combobox. I keep getting this error: System.IO.IOException: Cannot create a file when that file already exists. Also, these error come up on people's computer who install my program...exceptions and things. How do i turn it off. Also, why do i get this error? Here is my code:
string pathUser4 = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string pathDownload4 = (pathUser4 + #"\Downloads\");
string sourceFile = pathDownload4 + listBox1.Text;
string pathdoc5 = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string pathDownload5 = (pathdoc5 + #"\iracing\setups\");
string destinationFile = pathDownload5 + comboBox1.Text;
File.Move(sourceFile, destinationFile);
if (comboBox1.Text == "Select File Destination")
{
MessageBox.Show("Please Select A Destination Folder", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Each File.Move should be wrapped in a try/catch block as you can never expect an IO operation to execute without error. It could be something as simple as the user having a file handle open, or the file existing in the destination folder, either way, you don't want a single file to throw an exception that stops the entire operation. You will want to catch the exceptions and log them either to an error log file or to the event log, this way you can see the errors that occurred but it will not interrupt anything.
Secondly, for any desktop application I would add global error handling to log any uncaught errors. You can do this by putting this code at the beginning of your program,
AppDomain.CurrentDomain.UnhandledException += (a, exception) => File.AppendAllText("errorlog.txt", exception.ToString() + "\n"
This will keep the user from ever seeing ugly exceptions being thrown. Also be sure you are not giving the users the .pdb files as this will cause exceptions to contain paths of the computer it was compiled on which can contain your username and other sensitive information you wouldn't want a client to see.
You can register the global exception handling when the main window is initialized, you want it to be the first thing you do before any thing else because again you never know when an exception will be thrown so you have to think defensively.
public partial class MainWindow : Window
{
public MainWindow()
{
AppDomain.CurrentDomain.UnhandledException += (a, exception) => File.AppendAllText("errorlog.txt", exception.ToString() + "\n");
InitializeComponent();
}
}
C# uses exceptions extensively so it will be good concept for you to study up on if you are not familiar with this type of error handling. All exceptions derive from the Exception class so when you write catch (Exception e) this will catch all exceptions (because a base reference can hold an object of a derived type), however if you know the specific exception a method will throw you can catch a more specific exception (always before the more general catch) and handle it in a specific way. In this example you may have an IOException from the File.Move() that you want to catch and handle differently.
try
{
string pathUser4 = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string pathDownload4 = (pathUser4 + #"\Downloads\");
string sourceFile = pathDownload4 + listBox1.Text;
string pathdoc5 = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string pathDownload5 = (pathdoc5 + #"\iracing\setups\");
string destinationFile = pathDownload5 + comboBox1.Text;
File.Move(sourceFile, destinationFile);
if (comboBox1.Text == "Select File Destination")
{
MessageBox.Show("Please Select A Destination Folder", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception e)
{
File.AppendAllText("ErrorLog.txt", e.ToString() + "\n");
}
The example code from MSDN for File.Move should get you pointed at the various things you need to deal with, such as an already existing file and basic error handling.
using System;
using System.IO;
class Test
{
public static void Main()
{
string path = #"c:\temp\MyTest.txt";
string path2 = #"c:\temp2\MyTest.txt";
try
{
if (!File.Exists(path))
{
// This statement ensures that the file is created,
// but the handle is not kept.
using (FileStream fs = File.Create(path)) {}
}
// Ensure that the target does not exist.
if (File.Exists(path2))
File.Delete(path2);
// Move the file.
File.Move(path, path2);
Console.WriteLine("{0} was moved to {1}.", path, path2);
// See if the original exists now.
if (File.Exists(path))
{
Console.WriteLine("The original file still exists, which is unexpected.");
}
else
{
Console.WriteLine("The original file no longer exists, which is expected.");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
}
The error may caused by your code, or by some invalid input.
As #Despertar mentioned, I suggest all the program include error handling and log features in your code. It will be very helpful for your debug.
But I suggest use open source log library, not do it by yourself. For example, log4net, NLog, etc.