I have a Windows Service that needs to start a process to send a file to the printer (I found that solution there https://stackoverflow.com/a/4875755/1228738) . I do this using the Process.Start().
My problem is that nothing happens.
The service is actually installed on my developer machine (win7, x64). I tried installing it as LOCAL SYSTEM, NETWORK SERVICE, LOCAL SERVICE with the same result every time.
I tried those way of starting my process :
Process p = new Process();
p.StartInfo.FileName = "C:\\Program Files (x86)\\Foxit Software\\Foxit Reader\\Foxit Reader.exe";
p.StartInfo.Arguments = "-p myFile.pdf";
p.Start();
and
Process.Start("C:\\Program Files (x86)\\Foxit Software\\Foxit Reader\\Foxit Reader.exe", "-p myFile.pdf");
and also
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "C:\\Program Files (x86)\\Foxit Software\\Foxit Reader\\Foxit Reader.exe";
startInfo.Arguments = "-p myFile.pdf";
Process.Start(startInfo);
When I execute the same code in a winform application, everything works fine, the file is sent to the printer. But in the Windows Service, nothing happens.
I saw that post https://stackoverflow.com/a/6271309/1228738, which explains why I would not see the UI, that's fine I don't have any UI anyway. But as said in the comment section, a process with no user input should be OK. The process that I start don't need any user input.
The only thing I can think of right now, is that because of session isolation (https://stackoverflow.com/a/5063750/1228738), the service can't find any installed printers... Can that be the case ? If so, any suggestion how to work around that ? And if not, any idea of what's wrong ?
Thanks!
EDIT #1
I tried running the service with my user account, and it's working, so I guess my fears are confirmed... the users LOCAL SYSTEM and NETWORK SERVICE have no installed printers.
So I'll refine my question a little bit. Is there a way for those account to access printers installed on the computer ?
EDIT #2
We finally decided that a user will be created for running that service and in that user accounts we'll install the printer on which to print.
I guess this question can be closed now.
Thank you all for your help.
I had this issue too, this trick solved it
Go to services ---> Double click the required service ---> proceed to logon tab
Supply the Log-in credentials from which printer was installed.
Run your service, then check the printer queue.
Reason: Local system account does not have those printer installed !
See screen shot below.
Check out this MSDN Page: http://support.microsoft.com/kb/324565
According to this page, you cannot print from ASP.NET pages or Windows services using .NET.
The solution here is tho share your local printer and call Foxit with
-/t yourfile.pdf \\localhost\YourSharedPrinter
That way your service does not need an UserProfile and no DefaultPrinter.
Related
I am trying to run an antivirus scan on an uploaded file in an ASP.Net web app. We are using Sophos so have access to their command line API sav32cli. In the code I use:
Process proc = new Process();
proc.StartInfo.FileName = #"C:\Program Files (x86)\Sophos\Sophos Anti-Virus\sav32cli.exe";
proc.StartInfo.Arguments = #"-remove -nc " + SavedFile;
proc.StartInfo.Verb = "runas";
proc.Start();
proc.WaitForExit();
int exitCode = proc.ExitCode;
When stepping through the code, when attached to the w3wp process on dev server, the code just jumps from one line to the next seemingly doing nothing at all. When running from code on dev server, it performs as expected scanning file and deleting if it is seen as a virus.
The server is running IIS 8.0, and the app built in .Net Framework 4. I have changed the machine config to allow the process to run as SYSTEM account, in accordance to these instructions. https://support.microsoft.com/en-us/kb/317012#%2Fen-us%2Fkb%2F317012
<processModel userName="SYSTEM" password="AutoGenerate" />
Is there something I'm missing? What is the best practice for this kind of implementation?
EDIT: When called, the Process returns an ExitCode of 2 (Error stopped execution), rather than the expected 0 (Scan worked, no viruses), or 3 (Scan worked, viruses found).
EDIT 2: As per comment below I changed the code to:
Process proc = new Process();
proc.StartInfo.FileName = #"C:\Program Files (x86)\Sophos\Sophos Anti-Virus\sav32cli.exe";
proc.StartInfo.Arguments = #"-remove -nc " + SavedFile;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
StringBuilder output = new StringBuilder();
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
output.AppendLine(line);
}
proc.WaitForExit();
int exitCode = proc.ExitCode;
ASPxMemo2.Text = exitCode.ToString() + Environment.NewLine + output.ToString();
output is always empty when run over IIS, but is populated correctly when running from code.
EDIT 3: Instead of looking at StandardOutput we looked at StandardError and it revealed this error:
Error initialising detection engine [0xa0040200]
(Possible insufficient user Admin rights.)
For the time being we are going to move to another method of virus checking, but would still like to know a possible solution if anyone has it.
You will need to make sure that the application pool that is running your .NET application inside IIS has execute permissions to your file
"C:\Program Files (x86)\Sophos\Sophos Anti-Virus\sav32cli.exe"
You may also need to add this permission to the folder location where the file to be scanned is uploaded (c:\temp) for example
You may also need to have administrator privileges to run the anti virus scan since IIS8 does not run as an administrator. When you are debugging visual studio uses your current logged in windows user(unless you use runas) so this will explain why it would work when debugging.
Have you tried running your web process in elevated trust?
Configuring .NET Trust Levels in IIS 7
<system.web>
<securityPolicy>
<trustLevel name="Full" policyFile="internal"/>
</securityPolicy>
</system.web>
ASP.NET Trust Levels and Policy Files
Most likely the permissions are not configured correctly on the content being scanned (the uploads folder) or the worker process user doesn't have the full permissions it needs to use Sophos. You know the executable itself is accessible by the worker process because you are getting exit codes and error messages that are specific to Sophos.
Because your process will delete files that are perceived as threats you need to grant the user running the process modify or full control permissions on the folders that store the uploaded files.
By default you could use the IIS_IUSRS group for ApplicationPoolIdentity processes, but you can verify (and modify) the user in IIS Manager > App Pools > Advanced.
This answer has more details
Here are some ideas:
Create the process using a different user with elevated privileges on the folder, see for reference start-a-net-process-as-a-different-user
If the previous suggestion fails, login one time on the server using the credentials used in point 1. It will configure registry entries connected to the user profile, some programs requires it.
Develop a simple .net service running on the server and monitoring the upload folder. The service has more probability running the Sophos scan succesfully. Here is a reference on service creation using .net.
The service may also talk to your web page using DB/file system/ etc.. so the operation may seem synchronous.
These are my 4 cents :-)
I made new project (ASP.NET MVC Web Application) using Visual Studio Web 2013 Express Edition. Loading index page, redirects and everything works fine, except that in some part of my code I need to create Process and execute it, wait for it to finish, parse output of that external application and show that output to the user. However I get nothing. While debugging the code line by line:
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = Tool;
info.Arguments = filename + " " + avArray;
info.CreateNoWindow = true;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
Process p = new Process();
p.StartInfo = info;
p.Start();
p.WaitForExit();
Process exits immediately, someone would say it is pretty fast program, but application needs at least 5 seconds (sometimes 20 seconds) to complete.
What I think is happening is that process is not created in the first place, as my IIS settings or whatever other settings are not allowing me to run this EXE. What do I do to change this?
I've been trying to this for the past 2 weeks, I've read probably every post about it, and tried every solution suggested. I am choosing to write on this post since it is the most recent.
First of all, I am using VS2013, testing on IIS Express, and then on IIS 8.5., the webpages version is 3, and the target framework 4.5. And I am assuming that (as with my case) the goal is to launch the process on the server.
What I learned:
Using IIS Express should allow you to run the process without problems. You can try to allow it to launch the window, or start your process through the shell just to be sure that it is actually launching (a shell window should popup and close). If this happens, verify that you are giving the correct path to to your program, etc. So far so good.
Going into the IIS 8.5 is a totally different matter. Theoretically, the bad way of doing it should be preatty straight-forward: you create an app-pool for that server, give it a high privileged account (local system or network system, for instance); go to AdministrativeTools->Services->IIS, LogOn tab, and allow interaction with the desktop. You should be able to do the same as in IISExpress, but in my case is just the same as with a low privilege account.
I actually started by trying just to use impersonation, but also was not able to launch the process with IIS8.5. EDIT: I retried this again today, and the api won't even run if I enable impersonation.
I've spent more time than I would like with this, any input on why I can't get this to work properly with IIS8.5 (#clzola: IIS Express should do the job) is very welcome.
OK,
So I'm trying to figure out a way to launch a ClickOnce application from a Windows Service. I wanted to do it via the "Local System" (So no log in information prompts were done) account without the "Interact with desktop" option checked (since MS has been trying to get rid of that feature for a while).
I knew that I could launch a application to the desktop without that checked. So I dug a CreateProcessAsUserWrapper from the TechNet Blog. The wrapper can be found here http://code.msdn.microsoft.com/windowsdesktop/CSCreateProcessAsUserFromSe-b682134e/file/50832/8/Interactive%20Windows%20Service%20(CSCreateProcessAsUserFromService).zip
I then created the services application and a small exe with a copy of the .appref-ms of the ClickOnce applicaiton. The server then looks every 10 minutes to see if the ClickOnce app is running. If not it fires off the small exe with the CreateProcessAsUserWrapper which then in turn .appref-ms
Up to this point everything is running smoothly. The problem I've run into is that with the ClickOnce App starts up. It asks if it wants to install, despite being installed.
This is the code starting up the ClickOnce app:
string startupPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
startupPath = Path.Combine(startupPath, "app.appref-ms");
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "\"" + startupPath + "\"";
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
I don't know if there is anything i do to prevent it from asking to install. I have even tired switching the server over to run under the user account, but then I get errors Querying the User Token for when trying to interact with the desktop.
Anyone have any ideas?
I am trying to print a document which is working fine in my Visual studio 2010 application but when i am publishing my project on IIS 7 then printing is not working and i cant see any error in the event viewer .
MyProcess = new Process();
MyProcess.StartInfo.CreateNoWindow = false;
MyProcess.StartInfo.Verb = "print";
MyProcess.StartInfo.FileName = destinationPath;
MyProcess.Start();
MyProcess.WaitForExit(10000);
MyProcess.Close();
When you're running in Visual Studio, you're running as a logged-in, interactive user.
When you're running in IIS, well, you're not any of the above.
The way this is normally done in a web application is to:
Display the document to the user in the browser
Print the document by using the 'window.print' function from JavaScript.
If anyone still cares for an answer..
I had the same problem, solution was to give IIS user access to use installed printers on the computer. When you print from IIS , you're logged in as a system default user who by default doesn't have proper printer access setup in the registry.You need to give printer access to the default system user by adding few entries in the registry. Just follow this tutorial like I did http://support.microsoft.com/?kbid=184291.
It will fix it.
If the printer is not installed on the server, nothing is going to happen.
If you're trying to print from ASP.NET code to a printer attached to the client computer it's never going to work. The server cannot get to and use any resources on the client computers.
2nd and important thing change to LoadUserProfile to true in IIS Application pool.
This is code from a class library:
proc.StartInfo = new ProcessStartInfo(CmdPath, "+an -b");
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
proc.WaitForExit();
This works perfectly as I would expect when called from a console test app. When I take the same library and call the method from an ASP .NET web service it just hangs.
Is there something I am missing here, perhaps permissions? The ASPNET service has access to the folder where the EXE is, and I see it running in Task Manager, though it isn't doing anything.
If anyone could tell me what I'm doing wrong, I would appreciate it. Thanks.
EDIT: Sorry for the lack of information. CmdPath goes to the command line interface for our scheduling software. I'm passing in commands based on the documentation they provided. I have one method to get a list of jobs, and another method to run a job. ...hmm idea. The client normally uses Active Directory to login, I think impersonation is going to be necessary. Going to test now.
EDIT 2: Ok, now the client is blowing up with AccessViolation issues. This is obviously a permissions thing. If the software uses integrated AD authorization, and I impersonate my AD account, will that be sufficient? I'm doing impersonation using the tag in web.config.
I think you will face a lot of problems launching an executable server side using the ASPNET identity, have you tried impersonating an identity with appropriate priveleges (this does work btw), but again launching an executable on the server side is probably not a good idea to begin with.
The ASP.Net user account probably doesn't have permissions to execute. Can you give a bit more information as to why you are trying to do this as there may be a better way of doing it.
It could be a permissions issue. The ASPNET service may have permissions to the executable, but does it have permissions for everything the executable does.
For example, if the executable copies files, does the ASPNET account have full rights to the source and destination paths of those files? The same questions need to be asked of everything the executable does.
If you need to get around this, you can use impersonation, or assign the web site to run under a different account in IIS, but those are not recommended practices, and more trouble than they're worth in most cases.
By default the ASP.NET worker process has less security than most local account (certainly an account that a developer uses or the logged in account on a server.)
There are two main ways to move forward:
Give the asp.net process more priviledges. See This Link for a good explanation of how to do that.
Have asp.net run under an account with more priviledges. See This Link for a good explanation and how to get that process running under a different account.
Either will work for you.
When you redirect standard output don't you need to use ReadToEnd to read the response from StandardOutput?
You probably should check what is your executable performs, cos ASP.NET works under user with limited rights (NETWORK SERVICE on IIS 6.0) and you executable also gets this rights and runs under same user. As far as you waiting on until it finishes its work, probably something wrong in the executable you are trying to run. I suggest you to make a simple experiment - switch your WebApplication to build-in in VS web server, called "Casini" and check your code behavior. By means of this you can prove yourself that it's not ASP.NET's fault. If I am right the only thing you will need to do is to investigate problems of you executable and determine what rights it needs.
Instead of Impersonation or giving Asp.net more privileges, how about launching the process under different credentials.
In the sample below, UserWithVeryLimitedRights would be a new account that you create with just enought rights to run the app.
Doing so may minimize the security risks.
ProcessStartInfo StartInfo = new ProcessStartInfo();
SecureString ss = new SecureString();
string insecurePassword = "SomePassword";
foreach(char passChar in insecurePassword.ToCharArray()) {
ss.AppendChar(passChar);
}
StartInfo.RedirectStandardInput = true;
StartInfo.RedirectStandardError = true;
StartInfo.RedirectStandardOutput = true;
StartInfo.CreateNoWindow = true;
StartInfo.UseShellExecute = false;
StartInfo.Password = ss;
StartInfo.UserName = #"UserWithVeryLimitedRights";
StartInfo.FileName = #"c:\winnt\notepad.exe";
Process.Start(StartInfo);