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!
Related
The environment is Windows Server 2016 Standard, using a C# Console Application developed in Visual Studio 2019 and published via the VS2019 Publish Wizard. The weird thing is this seemed to work fine on our old instance of Windows Server 2008, but has not worked properly since we upgraded to 2016.
I've developed a C# Console Application to add data to my SQL Server database. It is published and running directly on the DB server using Task Scheduler. If I'm logged in when the scheduled task runs, no problems. But if I am not logged in, the console application does not run and I'm having trouble seeing how far it even gets.
Any advice on how to get this to run with a non-logged in user, or how to better troubleshoot where the hold-up is would be greatly appreciated.
Currently as a test, all I am trying to do is start the app, write to the event viewer application log and to a text file (neither happen unless logged in).
static void Main()
{
using (EventLog eventLog = new EventLog("Application"))
{
eventLog.Source = "Application";
eventLog.WriteEntry("Log message example", EventLogEntryType.Information, 101, 1);
}
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
string status = "Start: " + DateTime.Now.ToString() + "...";
Log(status);
status = "Complete: " + DateTime.Now.ToString() + ". Press Enter to exit.";
Log(status);
}
public static void Log(string message)
{
// Create a writer and open the file:
StreamWriter log;
string LogFilePath = "C:\\[folder]\\LogFile.txt";
if (!File.Exists(LogFilePath))
{
log = new StreamWriter(LogFilePath);
}
else
{
log = File.AppendText(LogFilePath);
}
// Write to the file:
log.WriteLine(DateTime.Now);
log.WriteLine(message);
log.WriteLine();
// Close the stream:
log.Close();
Console.WriteLine("-Log Entry Added");
}
Interestingly, I do see a ClickOnce process added to the Task Manager when I run as a non-logged in user, but still doesn't work appropriately.
Here are some of the things I've tried so far:
Run as my own domain account, system and as a local administrator account
Call a .bat file with the following command to open the console application: "START /B "Name" CMD /c "E:\setup.exe"" The call to the .bat file works but the Console Application does not run properly
Call setup.exe or ConsoleApplication.application directly from task scheduler
Changing the output type from "Console Application" to "Windows Application"
Below are screenshots to show my selected settings in Task Scheduler:
Something that fixed my problem: I re-created the console application from scratch, but created using .NET Core 3.0 framework. Copied my code in and re-added packages. I then published this new application to the server and it worked as expected. Still not sure what to attribute this to, but this fixed my issue
So I developed an application using .net-core, I run this software on a linux machine as a daemon service using systemd. Now the problem is that when an error happen in the app, it enters in a "limbo", infact each activity of the application is logged using Console.WriteLine and I can see this log typing that command on linux machine: journalctl -fu app.service.
When the error happen the log doesn't write anything, but at the same time the application keep running and this is really strange because I setup the service with the following configuration:
[Unit]
Description = Daemon service
[Service]
ExecStart = /usr/bin/dotnet /home/my username/Desktop/publish/SimpleApp.dll
WorkingDirectory= /home/foo/Desktop/publish
Restart = always
RestartSec = 3
[Install]
WantedBy = multi-user.target
as you can see the Restart = always should restart the app when an error is raised. When an exception is raised the method Error() write the error inside a file and then kill the software in the following way:
public void Error(Exception ex)
{
File.WriteAllText("error.txt", ex.ToString());
Environment.Exit(1);
}
Must be some problem on Environment.Exit with the Linux environment, or I did something wrong calling Environment.Exit. There are other ways to close an application like this which run as system service?
Thanks
Try the following:
public void Error(Exception ex)
{
File.WriteAllText("error.txt", ex.ToString());
throw new Exception ("This is a test to see if restart is working");
}
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";
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.
Having an issue with a program that is launched by a windows service.
The process flow is
exe launches
renames itself to *.bak
downloads the latest version of itself
calls Restart()
does a bunch of file and SQL operations (updating our main software suite)
then calls Restart()
Process flow starts again. IF there were no software updates for the main suite it does not restart
this all works perfect except for one customer site
On one site, the first Restart() works, but the second one always throws an exception.
System.ComponentModel.Win32Exception (0x80004005): No such interface supported
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at UpdateCompanionService.Program.Restart()
It is a WS2008 standard server.
public static void Restart()
{
try
{
var procPath = Path.Combine(Config.UpdateCompanionDirectory, "UpdateCompanionService.exe");
Logger.Debug("Starting procecss {0}", procPath);
var proc = new Process
{
StartInfo = {FileName = procPath, WorkingDirectory = Config.UpdateCompanionDirectory, Arguments = "/noupdate", UseShellExecute = true}
};
proc.Start();
Environment.Exit(-1);
}
catch (Exception e)
{
Logger.Fatal("Error restarting update companion", e);
}
}
Try using
UseShellExecute = false
Its been known to fix this problem
You can try to set UseShellExecute = false in your code.
I remember some own problems long ago, where I even recompiled the original .NET framework code to find out that setting this flags uses a completely different method of starting.
For me it seems you do not need UseShellExecute = true in your case.
If this does not work, you should check security context / GPO settings, e.g.
"Is this service running as SYSTEM or (domain) user ?"
Also be sure that your new EXE with all additional components is "ready" at the time where you try to restart it (maybe you use a background thread which did not complete).
I had similar issue with an executable which is called by a Web Application running on IIS. In my case the solution was to restart the Application Pool for to current Web Application.