File.Exists not working on network drive - c#

My console app checks for the presence of a file on a network drive and logs a message when it does not exist. Today I deployed my app to a QA machine and File.Exists() has been returning false for files that do exist. I am running the app via windows task scheduler. When I ran it from the command line it seems to work fine. But either way I don't trust it now. Has anyone seen this behavior or have any insight?:
Using System.IO;
private static void Main()
{
var fileName = #"x:\folder\file1.txt"; //be a network share
If (!File.Exists(fileName)
{
LogMessage("File is not on disk.");
}
else
{
LogMessage("File is on disk.");
}
}

I suspect that the drives are not mapped when running from task scheduler. Try a UNC path
var fileName = #"\\server\share\folder\file1.txt";

Related

c# Process.Start doesn't execute in production

I have some code looking like this:
public async Task Create(string filename)
{
try
{
Process.Start(new ProcessStartInfo { FileName = #"c:\bat\" + filename, UseShellExecute = true });
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace.ToString());
}
}
I'm triggering the code through an api call and the command window opens and the batch file executes fine.
But when I do exactly the same on the production server (Windows Server 2019, IIS 10) the process never starts. The api call is successful but the bat file never executes.
I've changed the permissions of the folder (even to everyone to test)
I've tried to add Local
I've allowed the World Wide Web Publishing service to interact with desktop
I've changed and tried all the different app pool permissions
But I can't get it to work.
Grateful for help!

Accessing Files from UNC Network Path in C# Application

I have a desktop application in which the user is able to specify the input and output directories.Things work fine for local directories;but people have started complaining about network locations accessed using UNC Naming Conventions.
If the user pastes the UNC Path,the code checks if the Directory exists using the following method
if(Directory.Exists(selecteddir)
{
// all good
}
This method returns false for some network locations situated on other machines.I have tested using default local machine UNC Path \\?\C:\my_dir and the code works fine.
The application runs with administrative rights .
Im new to accessing network locations in C# Code.Is there any specific way to do this? If the user has already performed windows based authentication for the UNC Shares,wont these shares be accessible by the c# application?
Please advice on how to go forward.
Update:
I have also tried using directory info
DirectoryInfo info1 = new DirectoryInfo(#textbox.Text);
if (info1.Exists)
{
return true;
}
I have faced this situation many times. In the end, I believe that there is some issue with Directory.Exist method and I leave it.
Now, I am using DirectoryInfo class to check that like this.
DirectoryInfo info = new DirectoryInfo(#"Your Path");
if (info.Exists)
{
}
It is working fine for now. So there are other reasons too but it works for me. And of course, it does not resolve the impersonation issue.

FileVersionInfo GetVersionInfo() returns empty result

I've written a simple C# program that compares the file version of the local file with that of server and if there is a mismatch it should overwrite the local copy with that of server. Code snippet below.
using System;
using System.Diagnostics;
using System.Security.Principal;
namespace Test
{
public class FileVersionComparer
{
public static void Main()
{
// Print the user name
Console.WriteLine("This app is launched by - {0}",WindowsIdentity.GetCurrent().Name);
// Get the server file version
string serverFilePath = #"\\myserver\folder\test.exe";
FileVersionInfo serverVersionInfo = FileVersionInfo.GetVersionInfo(serverFilePath);
string serverFileVersion = serverVersionInfo.FileVersion;
Console.WriteLine("Server file version : {0}", serverFileVersion);
// Get the local file version
string localFilePath = #"C:\Windows\test.exe";
FileVersionInfo localVersionInfo = FileVersionInfo.GetVersionInfo(localFilePath);
string localFileVersion = localVersionInfo.FileVersion;
Console.WriteLine("Local file version : {0}", localFileVersion);
// Compare and overwrite if version is not same
if(!string.Equals(localFileVersion, serverFileVersion,StringComparison.OrdinalIgnoreCase))
{
File.Copy(serverFilePath, localFilePath, true);
}
else
Console.WriteLine("File version is same");
}
}
}
This program is launched as a child process and the parent application and hence the child runs under NT AUTHORITY\SYSTEM account. The program is working fine on my machine but failing to retrieve the local file version (returns empty string, no exception) on couple of machines. On the machines where it is returning empty file version, if I run the program from command prompt as a normal user and as an independent process, it is able to retrieve the local file version correctly.
NOTE: It is able to retrieve the server file version even when launched as child process on all machines.
I also tried to copy the local file from C:\Windows to C:\Temp (using the File.Copy() API) to test if the properties can be read when the same file is in a different location. But then the program throws a File Access exception (when run from the parent app). There are no access restrictions on C:\Temp. Also, from technical forums, I understand that NT AUTHORITY\SYSTEM is an Admin account.
I don't understand why the program is not able to retrieve the local file version when it is run under NT AUTHORITY\SYSTEM account and why it is successful when run with my account as a normal process (NOT as a child process).
Can somebody please help? Thanks.

DirectoryInfo.Exists cannot find my mapped network drive C#

protected void btnAutomaticUpload_Click(object sender, EventArgs e)
{
DirectoryInfo dir = new DirectoryInfo(#"\\space-bar\UZ\UZ Dept\Management\Data\directory_exists_here\");
bool atLeastOneSuccessfulUpload = false;
bool possibleFormatChange = false;
lblMessages.Text = string.Empty;
lblResults.Text = "<span style='font-size:large; font-weight:bold'><u>Results Log</u></span><br><br>";
//If our destination directory does not exist, exit
if (!dir.Exists)
{
lblResults.Text += "<span style='color:Red'>Expected directory does not exist!</span><br>" + dir.FullName;
return;
}
So I have been trying to run this code on a live server with a mapped network drive but it always seems to not be able to find the folder. Although when I am running this on Debug or LocalHost mode, it seems to be able to find the directory with no problem. Any idea as to why it's not working even with a UNC path coded? Does it have anything to do with permissions if any?
I am trying to build an automatic file upload parser.
If you are running under IIS it almost certainly doesn't have the rights to access a network resource. Check the Application Pool identity in IIS to determine which user your application is running under - its likely be a very restricted system account. This can be changed by altering the Application Pool settings in IIS Manager.

How to start an exe from a .NET Windows Service for updating the service

I have a windows service that I would like to be automatically and silently updated. I started using wyBuild to implement this, but have had some issues with it, and decided to try to build my own. I've written a standalone exe that can be called to do the update procedure: checks for a new zip file with the update, downloads it, unzips, stop the windows service, copy files from the zip, then restart the service. This exe works fine when I run it from the commandline and wasn't really difficult to write.
However, now I would like the service (the same one being updated) to shell out to the updater exe to update itself. I first tried Process.Start:
var proc = Process.Start(pathToUpdaterExe);
proc.WaitForExit(60000);
This called the updater, but when the updater stops the service, the process is killed and the update stops. I did some searching and it sounds like the solution is to use a separate AppDomain. This is what I have now:
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence objEvidence = new System.Security.Policy.Evidence(baseEvidence);
AppDomainSetup setup = new AppDomainSetup();
var updateDomain = AppDomain.CreateDomain("updateDomain", objEvidence, setup);
updateDomain.ExecuteAssembly(updater);
AppDomain.Unload(updateDomain);
However, now I get the error System.IO.IOException: "The process cannot access the file 'C:\Program Files (x86)\Company\Service\Service.dll' because it is being used by another process" when attempting to copy over the new Service.dll
Again, I've stopped the service at this point. I've confirmed this with logging. I can't imagine what would have Service.dll still locked, so I added code to check to see what is locking it:
public static IEnumerable<Process> GetProcessesLocking(string filePath)
{
var result = new List<Process>();
result.Clear();
var processes = Process.GetProcesses();
foreach (Process proc in processes)
{
try
{
if (proc.HasExited) continue;
foreach (ProcessModule module in proc.Modules)
{
if ((module.FileName.ToLower().CompareTo(filePath.ToLower()) == 0))
{
result.Add(proc);
break;
}
}
}
catch (Exception ex)
{
Log(ex.ToString());
Log("There was an error checking " + proc.ProcessName );
}
}
return result;
}
However this code indicates that nothing has a lock on the dll (result is empty and nothing is logged indicating an error).
I suspect I'm running afoul of some UAC issue that is the real cause of the IOException. The windows service runs as LocalSystem. All that to ask: How should I be running the update exe from the windows service such that it has rights to copy files in c:\Program Files?
Update
As the comments and answer suggest, Process.Start can work, but there is some nuance. You have to start cmd.exe and use it to start the updater. I also found I could not use a full path for the updater exe and that I needed to set UseShellExecute=false. This is my final working code that launches the updater from the .NET service:
var cmd = "/c start updater.exe";
var startInfo = new ProcessStartInfo("cmd.exe");
startInfo.Arguments = cmd;
startInfo.WorkingDirectory = AssemblyDirectory;
startInfo.UseShellExecute = false;
var proc = Process.Start(startInfo);
I did this exact thing - using a simpler (some might say kludgy) approach. The service:
Produces a batch command,
Downloads the new executables to a staging location,
Starts a process: cmd.exe which, in turn, runs the batch script w/o waiting for it to complete, and then
Immediately terminates itself.
The batch command:
Pings 127.0.0.1 five times,
Copies the executables to the final location and,
Restarts the service.
Works like clockwork. The ping is a reliable 5 second delay - lets the service shutdown before copying the files.
Edit:
Just for completeness - I realized that by batch cmd is pinging 127.0.0.1 not 128.0.0.1 and so I edited this answer to reflect that. I suppose either works - but 128.0.0.1 pings timeout, where 127.0.0.1 resolves to "me". Since I'm only using it as a poor-man's delay, it serves the purpose either way.

Categories