Cannot start process from IIS - c#

the issue I'm facing is this:
I'm trying to start AcrobatReader from my C# WebApplication using a Process.
https://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx
When I'm running the application in IIS Express(running under my default user account) everything goes right and I can open the file I want on Acrobat Reader.
Instead, when I'm trying to deploy on IIS(running under IIS APPPOOL\xxx) the process can't start AcrobatReader.
I've already tried to assign permissions on AcrobatReader to IIS_IUSRS and also to IIS APPPOOL\xxx but nothing change
Tried also to add IIS APPPOOL\xxx to administrators group but no luck
` `ProcessStartInfo info = new ProcessStartInfo();
info.FileName = Constants.ACROBAT_READER_PATH;
info.Arguments = args;
info.Verb = "Printto";
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
info.UseShellExecute = false;
info.Domain = Environment.MachineName;
info.UserName = "AdminUser";
string password = "AdminPassword";
System.Security.SecureString securePassword = new System.Security.SecureString();
foreach (char c in password)
securePassword.AppendChar(c);
info.Password = securePassword;
try
{
//The following security adjustments are necessary to give the new
//process sufficient permission to run in the service's window station
//and desktop. This uses classes from the AsproLock library also from
//Asprosys.
IntPtr hWinSta = GetProcessWindowStation();
WindowStationSecurity ws = new WindowStationSecurity(hWinSta,
System.Security.AccessControl.AccessControlSections.Access);
ws.AddAccessRule(new WindowStationAccessRule("AdminUser",
WindowStationRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
ws.AcceptChanges();
IntPtr hDesk = GetThreadDesktop(GetCurrentThreadId());
DesktopSecurity ds = new DesktopSecurity(hDesk,
System.Security.AccessControl.AccessControlSections.Access);
ds.AddAccessRule(new DesktopAccessRule("AdminUser",
DesktopRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
ds.AcceptChanges();
using (Process process = Process.Start(info))
{
}
}
catch (Exception ex)
{
}
Thank you for your time

Related

How to use printer on server [duplicate]

This question already has an answer here:
How to run console application which is send pdf to printer in server?
(1 answer)
Closed 2 years ago.
I download .zip file from outlook then send pdf files to printer. It works on my local machine while compiling, However I setup published app on server, it downloads .zip file from outlook and open it but it can not send to printer . How can I handle that?
This is my code:
static void Main(string[] args)
{
ExchangeService exchange = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
exchange.Credentials = new WebCredentials("mail#", "password");
exchange.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
if (exchange != null)
{
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
FindItemsResults<Item> result = exchange.FindItems(WellKnownFolderName.Inbox, sf, new ItemView(1));
foreach (Item item in result)
{
EmailMessage message = EmailMessage.Bind(exchange, item.Id);
message.IsRead = true;
message.Update(ConflictResolutionMode.AutoResolve);
List<Attachment> zipList = message.Attachments.AsEnumerable().Where(x => x.Name.Contains(".zip")).ToList();
foreach (Attachment Attachment in zipList)
{
if (Attachment is FileAttachment)
{
FileAttachment f = Attachment as FileAttachment;
f.Load("C:\\TEST\\" + f.Name);
string zipPath = #"C:\TEST\" + f.Name;
string extractPath = #"C:\TEST\" + Path.GetRandomFileName();
ZipFile.ExtractToDirectory(zipPath, extractPath);
string[] filePaths = Directory.GetFiles(extractPath, "*.pdf",
SearchOption.TopDirectoryOnly);
foreach (string path in filePaths)
{
SendToPrinter(path);
}
}
}
}
}
}
static void SendToPrinter(string path)
{
try
{
var printerName = "EPSON L310 Series";
ProcessStartInfo info = new ProcessStartInfo(path);
info.Verb = "PrintTo";
info.UseShellExecute = false;
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
info.Arguments = "\"" + printerName + "\"";
Process p = new Process();
p.StartInfo = info;
p.Start();
p.WaitForInputIdle();
System.Threading.Thread.Sleep(3000);
if (false == p.CloseMainWindow())
p.Kill();
}
catch (Exception ex)
{
Console.WriteLine("error:", ex.Message);
Console.ReadLine();
}
}
As I said, everything is work fine but printer not working. I can print pdf manually I mean machine works. Also this app works on my local machine
You need to change:
info.UseShellExecute = false;
to:
info.UseShellExecute = true;
since the path is a path to a PDF file, not an executable.
As per the docs:
When you use the operating system shell to start processes, you can
start any document (which is any registered file type associated with
an executable that has a default open action) and perform operations
on the file, such as printing, by using the Process object. When
UseShellExecute is false, you can start only executables by using the
Process object.
Additionally:
If you set the WindowStyle to ProcessWindowStyle.Hidden,
UseShellExecute must be set to true.
You are using Hidden - thus UseShellExecute must be true.

Executing Process on a remote Machine c#

i connected over WMI on a remote Machine.
username and password is correctly set.
var options = new ConnectionOptions();
servicePath = "\\\\Testserver\\root\\cimv2";
options.EnablePrivileges = true;
options.Username = username;
options.Password = pwd;
serviceScope = new ManagementScope(servicePath, options);
serviceScope.Connect();
this is the code sequence i want to run on the remote machine
Process process = new Process();
process.StartInfo.FileName = "diskpart.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
process.StandardInput.WriteLine("list volume");
process.StandardInput.WriteLine("exit");
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
// extract information from output
string table = output.Split(new string[] { "DISKPART>" }, StringSplitOptions.None)[1];
var rows = table.Split(new string[] { "\n" }, StringSplitOptions.None);
for (int i = 3; i < rows.Length; i++)
{
if (rows[i].Contains("Volume"))
{
int index = Int32.Parse(rows[i].Split(new string[] { " " }, StringSplitOptions.None)[3]);
string label = rows[i].Split(new string[] { " " }, StringSplitOptions.None)[8];
Console.WriteLine($#"Volume {index} {label}:\");
}
}
if i am going to call the process over wmi like this...
object[] theProcessToRun = { "diskpart" };
using (var managementClass = new ManagementClass(serviceScope, new ManagementPath("Win32_Process"), new ObjectGetOptions()))
{
managementClass.InvokeMethod("Create", theProcessToRun);
}
i can call the process, but havent the possibilites to hand over the commands i would like to execute in this process...
How to solve this ?
You can use a script to be passed in as part of the command line arguments that will contain your command.
Reference: https://www.computerhope.com/diskpart.htm
Also you should redirect your output to a file using cmd as you should get your output directly either.
For script, make sure you use a unc that other machine/user has access to. For output file, make sure you use a unc that other machine/user can write to and you can read from via the program.

Run PSEXEC process in ASP.NET as different user

I'm trying to connect from my ASP web application published on IIS server to some servers using psExec, start application and get the output.
When I try to start process without setting credentials I get this error:
Access is denied
but if I do the same as administrator, I'm only getting empty fields for output, errors and exception variables. Also, when I do it from my local pc using visual studio it works properly.
What am I doing wrong? Here is my code:
try
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(866);
p.StartInfo.StandardErrorEncoding = Encoding.GetEncoding(866);
p.StartInfo.FileName = #"C:\inetpub\wwwroot\Monitoring\bin\PsExec.exe";
server = "dp-next.b42";
p.StartInfo.Arguments = #" \\" + server + " \"c:\\program files\\omniback\\bin\\omnirpt.exe\" -report list_sessions -timeframe 12 12";
p.StartInfo.UserName = "admin";
p.StartInfo.Domain = "domain";
string pass = "password";
SecureString s = new SecureString();
foreach(char c in pass)
{
s.AppendChar(c);
}
p.StartInfo.Password = s;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.Start();
output = output + p.ProcessName;
//output = p.StandardOutput.ReadToEnd();
while ((res = p.StandardOutput.ReadLine()) != null)
{
i++;
output = output + res;
}
errors = p.StandardError.ReadToEnd();
p.Close();
}
catch (Exception ex)
{
exe = ex.ToString();
}
I once had to develop something very similar. Here is what I did.
Instead of using:
p.StartInfo.UserName = "admin";
p.StartInfo.Domain = "domain";
p.StartInfo.Password = s;
I put username and password directly inside PsExec command arguments (respectively with -u and -p). In your case:
p.StartInfo.Arguments = #" \\" + server + " -u YOUR_DOMAIN\\YOUR_USERNAME -p YOUR_PASSWORD \"c:\\program files\\omniback\\bin\\omnirpt.exe\" -report list_sessions -timeframe 12 12";
More info on PsExec usage here.

How do I run a shell command in C# (on a webserver) with elevated credentials?

I have a web service, and I want to be able to run a shell command which requires admin privileges. (The command is DJOIN, to pre-stage AD with a computer account and create a file.)
I am testing this as follows:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
System.Security.SecureString ssPwd = new System.Security.SecureString();
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = "/C echo %username% > c:\\test\\user.txt";
proc.StartInfo.Domain = "mydomain";
proc.StartInfo.UserName = "myadmin";
string password = "mypassword";
for (int x = 0; x < password.Length; x++)
{
ssPwd.AppendChar(password[x]);
}
proc.StartInfo.Password = ssPwd;
proc.Start();
The c:\test folder on the web server has the correct permissions, and the code-block runs fine if I run it without specifying credentials. However, it fails when I add them in.
I have also tried including:
proc.StartInfo.Verb = "runas"
but this doesn't work either.
How can I run the command as an elevated user?
The way I got this working was to use this code:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
System.Security.SecureString ssPwd = new System.Security.SecureString();
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = "/C echo %username% > c:\\test\\user.txt";
proc.StartInfo.Domain = "mydomain";
proc.StartInfo.Verb = "runas";
proc.StartInfo.UserName = "myadmin";
string password = "mypassword";
for (int x = 0; x < password.Length; x++)
{
ssPwd.AppendChar(password[x]);
}
proc.StartInfo.Password = ssPwd;
proc.Start();
And also setting the application pool Identity in IIS to use this same user.

How to add authentication property for login to directory path when running batch file in WCF?

I have class in my WCF service to execute batch file. when I test to run the batch file in shared directory, everything is fine, the batch was executed, but when I try to run the batch file from secure diretory, I get error "ACCESS DENIED". How to add login property so I can access my secured directory to execute my batch file?
here is my code:
public string ExecuteBat()
{
string hasil = "";
ProcessStartInfo processInfo = new ProcessStartInfo(#"D:\Secure\command.bat");
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
Process process = Process.Start(processInfo);
process.WaitForExit();
if (process.ExitCode == 0)
{
hasil = "BAT EXECUTED!";
}
else
{
hasil = "EXECUTE BAT FAILED";
}
return hasil;
}
The ProcessStartInfo class has properties for Domain,UserName and Password that, when set, start the process under those credentials, something like this:
ProcessStartInfo processInfo = new ProcessStartInfo(#"D:\Rpts\SSIS_WeeklyFlash_AAF_1.bat");
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.Domain= "MyCompanyDomain";
processInfo.UserName = "username";
//Secure string is an odd beast, so you need something like this:
SecureString ss = new SecureString();
string password = "p#$$w0rd";
foreach (char c in password)
{
ss.AppendChar(c);
}
processInfo.Password = ss;
...

Categories