C# process start impersonation error - c#

I am trying to run the process with different user. When I run normal "notepad.exe" it works fine. But when I change the file to any other executable with full path(C:\\Program Files\\Microsoft Office\\Office15\\Excel.exe) or (C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroRd32.exe) it doesn't work. Instead gives errors like attached in pic.
Any suggestions...??
static void Main(string[] args)
{
SecureString securePwd = new SecureString();
string password = "P#ssw0rd";
SecureString sec_pass = new SecureString();
Array.ForEach(password.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();
Process p = new Process();
ProcessStartInfo ps = new ProcessStartInfo();
p.StartInfo.FileName = "notepad.exe";
p.StartInfo.Arguments = "C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\welcome.pdf";
p.StartInfo.WorkingDirectory = "C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\";
p.StartInfo.ErrorDialog = true;
p.StartInfo.EnvironmentVariables.Add("TempPath", "C:\\Temp");
p.StartInfo.Domain = "testdom";
p.StartInfo.UserName = "testuser";
p.StartInfo.Password = sec_pass;
p.StartInfo.RedirectStandardError = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.Start();
StreamReader myStreamReader = p.StandardOutput;
// Read the standard error of net.exe and write it on to console.
Console.WriteLine(myStreamReader.ReadLine());
p.Close();
}

Notepad doesn't store any user-specific settings. I'm certain all of the Office products do, and it wouldn't surprise me if Acrobat does too.
So, first thing to fix is to make sure that your ProcessStartInfo sets LoadUserProfile to true. That may be sufficient.
However, sometimes applications also act quite differently when run for the first time versus any subsequent launches, so I'd also make sure that you have, at least once, launched each of these applications as the intended target user, whilst you're actually logged onto the machine as that user (versus just launching a single process as that user).

In your code example your trying to open a pdf document in notepad.
Just checking, what happens when you change the file name to the adobe exe (you may need to add the path to the exe) instead of notepad.exe

Related

How to run multiple cmd commands from c# console app

I'm looking to automate nupkg creation in a c# app. I'm aiming to include nuget.exe in my project and use System.Diagnostics to launch cmd.exe as a process and then pass the required commands, which would be 'cd project\path\here', 'nuget spec something.dll' and 'nuget pack something.nuspec'.
The code I have so far is:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo(#"C:\Windows\System32\cmd.exe", #"mkdir testdir");
p.StartInfo = info;
p.Start();
Console.ReadLine();
However, it doesn't even create the testdir, and I've got no idea how to chain those commands. There is a method called WaitForInputIdle on my p Process, but it raises events and I've got no idea how to handle those to be honest.
A perfect solution would also let me read output and input. I've tried using StreamWriter p.StandardInput, but then there's the problem of checking whether a command is finnished and what was the result.
Any help would be much appreciated.
Edit: Success! I've managed to create a directory :)
Here's my code now:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo(#"C:\Windows\System32\cmd.exe");
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
sw.WriteLine("mkdir lulz");
}
Still no idea how to await for input and follow up with more commands, though.
You can do this by three ways
1- The easiest option is to combine the two commands with the '&' symbol.
var processInfo = new ProcessStartInfo("cmd.exe", #"command1 & command2");
2- Set the working directory of the process through ProcessStartInfo.
var processInfo = new ProcessStartInfo("cmd.exe", #"your commands here ");
processInfo.UseShellExecute = false;
processInfo.WorkingDirectory = path;
3- Redirecting the input and output of the process. (Also done through the ProcessStartInfo).This is required when you like to send more input to the process, or when you want to get the output of the process
Also see this answer

C# System.Diagnostics.Process launches on my local IIS, but doesn't launch on the server

I'm trying to make my program to run a bat file, that launches an exe file. It works fine on my local computer, but doesn't work on the server IIS. It doesn't work regardless of whether I specify the username and password in the ProcessStartInfo or not. I've searched forums and applied different stuff, but none of them help.
In Windows event viewer it doesn't give me any errors as well as the process output. If I change a directory and it can't find the bat file, the output gives me an error, but when it finds the file, it doesn't return anything and just doesn't launch the program.
Now, if I provide a credentials for the process, specifying psi.Domain, psi.UserName and psi. Password, the StandartOutput doesn't return any error, but Windows Events gives me two following errors:
Application popup: cmd.exe - Application Error : The application was unable to start correctly (0xc0000142). Click OK to close the application.
And
Application popup: conhost.exe - Application Error : The application was unable to start correctly (0xc0000142). Click OK to close the application.
Here's the code:
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(#"C:\inetpub\CopyToAD\pspasswd\passchange.bat");
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardError = true;
psi.CreateNoWindow = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
System.Diagnostics.Process listFiles;
listFiles = new System.Diagnostics.Process();
listFiles.EnableRaisingEvents = false;
listFiles.StartInfo = psi;
listFiles.Start();
System.IO.StreamReader myOutput = listFiles.StandardOutput;
listFiles.WaitForExit(2000);
myOutput.ReadToEnd();
string output = myOutput.ReadToEnd();
ViewBag.View6 += output + "***";
if (listFiles.HasExited)
{
output = myOutput.ReadToEnd();
ViewBag.View6 += output;
}

Running Phantomjs using C# to grab snapshot of webpage

I'm trying to grab snapshots of my own website using phantomjs - basically, this is to create a "preview image" of user-submitted content.
I've installed phantomjs on the server and have confirmed that running it from the command line against the appropriate pages works fine. However, when I try running it from the website, it does not appear to do anything. I have confirmed that the code is being called, that phantom is actually running (I've monitored the processes, and can see it appear in the process list when I call it) - however, no image is being generated.
I'm not sure where I should be looking to figure out why it won't create the images - any suggestions? The relevant code block is below:
string arguments = "/c rasterize.js http://www.mysite.com/viewcontent.aspx?id=123";
string imagefilename = #"C:\inetpub\vhosts\mysite.com\httpdocs\Uploads\img123.png";
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.CreateNoWindow = false;
p.StartInfo.FileName = #"C:\phantomjs.exe";
p.StartInfo.Arguments = arguments + " " + imagefilename;
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
I check the errors that phantomjs throws during its process.
You can read them from Process.StandardError.
var startInfo = new ProcessStartInfo();
//some other parameters here
...
startInfo.RedirectStandardError = true;
var p = new Process();
p.StartInfo = startInfo;
p.Start();
p.WaitForExit(timeToExit);
//Read the Error:
string error = p.StandardError.ReadToEnd();
It will give you an idea of what happened
The easiest way for executing phantomjs from C# code is using wrapper like NReco.PhantomJS. The following example illustrates how to use it for rasterize.js:
var phantomJS = new PhantomJS();
phantomJS.Run( "rasterize.js", new[] { "https://www.google.com", outFile} );
Wrapper API has events for stdout and stderr; also it can provide input from C# Stream and read stdout result into C# stream.

how to copy a file from any directory to c drive using cmd in c#

i tried an image file to copy in c:(operating sys) drive,but it says error wid access denied,i have used as
string strCmdLine;
strCmdLine = #" /c xcopy d:\123.png C:\windows\system32";
Process.Start("CMD.exe", strCmdLine);
you probably dont have enough permissions....
try adding credentials :
Process p = new Process();
process.StartInfo.UserName = "aaaa";
process.StartInfo.Password = "xxxxx";
...
...
also , verify that :
read permissions for : d:\123.png
write permissions for : C:\windows\system32
Access Denied may be caused by several reasons, such as user permissions or file being in use. Since the command line seems to be OK, I suggest to check whether your application was run by a Windows user that has permission to write to C:\windows\system32.
you need to run CMD.exe as admin try following
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Verb = "runas";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.Start();
p.StandardInput.WriteLine(#"/c xcopy d:\123.png C:\windows\system32");
You can check This post which shows how to run program as admin.

Printing a PDF Silently with Adobe Acrobat

I'm having 2 issues when trying to print a pdf silently in C# using adobe acrobat. I'm printing the pdfs using Process.Start().
The first issue is that I cannot launch Adobe Acrobat without specifying the full path to the executable. I assume it doesn't add it to your path when you install it. Is there an easy way to launch the newest version of acrobat on a machine without specifying full path names? I'm worried that the client is going to do an update and break my code that launches this. I'm also concerned with them installing this on machines with different versions of windows (install paths are different in 64 bit environment vs. 32 bit).
My second problem is the fact that whenever I launch acrobat and print it still leaves the acrobat window open. I thought that the command line parameters I was using would suppress all of this but apparently not.
I'm trying to launch adobe acrobat from the command line with the following syntax:
C:\Program Files (x86)\Adobe\Reader 10.0\Reader>AcroRd32.exe /t "Label.pdf" "HP4000" "HP LaserJet 4100 Series PCL6" "out.pdf"
It prints out fine but it still leaves the acrobat window up. Is there any other solution besides going out and killing the process programmatically?
I ended up bailing on Adobe Acrobat here and going with FoxIt Reader (Free pdf reader) to do my pdf printing. This is the code I'm using to print via FoxIt in C#:
Process pdfProcess = new Process();
pdfProcess.StartInfo.FileName = #"C:\Program Files (x86)\Foxit Software\Foxit Reader\Foxit Reader.exe";
pdfProcess.StartInfo.Arguments = string.Format(#"-p {0}", fileNameToSave);
pdfProcess.Start();
The above code prints to the default printer but there are command line parameters you can use to specify file and printer. You can use the following syntax:
Foxit Reader.exe -t "pdf filename" "printer name"
Update:
Apparently earlier versions of acrobat do not have the problem outlined above either. If you use a much older version (4.x or something similar) it does not exhibit this problem.
Some printers do support native pdf printing as well so it's possible to send the raw pdf data to the printer and it might print it. See https://support.microsoft.com/en-us/kb/322091 for sending raw data to the printer.
Update 2
In later versions of our software we ended up using a paid product:
http://www.pdfprinting.net/
Nick's answer looked good to me, so I translated it to c#. It works!
using System.Diagnostics;
namespace Whatever
{
static class pdfPrint
{
public static void pdfTest(string pdfFileName)
{
string processFilename = Microsoft.Win32.Registry.LocalMachine
.OpenSubKey("Software")
.OpenSubKey("Microsoft")
.OpenSubKey("Windows")
.OpenSubKey("CurrentVersion")
.OpenSubKey("App Paths")
.OpenSubKey("AcroRd32.exe")
.GetValue(String.Empty).ToString();
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = processFilename;
info.Arguments = String.Format("/p /h {0}", pdfFileName);
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
//(It won't be hidden anyway... thanks Adobe!)
info.UseShellExecute = false;
Process p = Process.Start(info);
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
int counter = 0;
while (!p.HasExited)
{
System.Threading.Thread.Sleep(1000);
counter += 1;
if (counter == 5) break;
}
if (!p.HasExited)
{
p.CloseMainWindow();
p.Kill();
}
}
}
}
I've tried both Adobe Reader and Foxit without luck. The current versions of both are very fond of popping up windows and leaving processes running. Ended up using Sumatra PDF which is very unobtrusive. Here's the code I use. Not a trace of any windows and process exits nicely when it's done printing.
public static void SumatraPrint(string pdfFile, string printer)
{
var exePath = Registry.LocalMachine.OpenSubKey(
#"SOFTWARE\Microsoft\Windows\CurrentVersion" +
#"\App Paths\SumatraPDF.exe").GetValue("").ToString();
var args = $"-print-to \"{printer}\" {pdfFile}";
var process = Process.Start(exePath, args);
process.WaitForExit();
}
The following is tested in both Acrobat Reader 8.1.3 and Acrobat Pro 11.0.06, and the following functionality is confirmed:
Locates the default Acrobat executable on the system
Sends the file to the local printer
Closes Acrobat, regardless of version
string applicationPath;
var printApplicationRegistryPaths = new[]
{
#"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Acrobat.exe",
#"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRD32.exe"
};
foreach (var printApplicationRegistryPath in printApplicationRegistryPaths)
{
using (var regKeyAppRoot = Registry.LocalMachine.OpenSubKey(printApplicationRegistryPath))
{
if (regKeyAppRoot == null)
{
continue;
}
applicationPath = (string)regKeyAppRoot.GetValue(null);
if (!string.IsNullOrEmpty(applicationPath))
{
return applicationPath;
}
}
}
// Print to Acrobat
const string flagNoSplashScreen = "/s";
const string flagOpenMinimized = "/h";
var flagPrintFileToPrinter = string.Format("/t \"{0}\" \"{1}\"", printFileName, printerName);
var args = string.Format("{0} {1} {2}", flagNoSplashScreen, flagOpenMinimized, flagPrintFileToPrinter);
var startInfo = new ProcessStartInfo
{
FileName = printApplicationPath,
Arguments = args,
CreateNoWindow = true,
ErrorDialog = false,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden
};
var process = Process.Start(startInfo);
// Close Acrobat regardless of version
if (process != null)
{
process.WaitForInputIdle();
process.CloseMainWindow();
}
got another solution .. its combination of other snippets from stackOverflow. When I call CloseMainWindow, and then call Kill .. adobe closes down
Dim info As New ProcessStartInfo()
info.Verb = "print"
info.FileName = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("App Paths").OpenSubKey("AcroRd32.exe").GetValue(String.Empty).ToString()
info.Arguments = String.Format("/p /h {0}", "c:\log\test.pdf")
info.CreateNoWindow = True
info.WindowStyle = ProcessWindowStyle.Hidden
info.UseShellExecute = False
Dim p As Process = Process.Start(info)
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
Dim counter As Integer = 0
Do Until p.HasExited
System.Threading.Thread.Sleep(1000)
counter += 1
If counter = 5 Then
Exit Do
End If
Loop
If p.HasExited = False Then
p.CloseMainWindow()
p.Kill()
End If
Problem 1
You may be able to work your way around the registry. In HKEY_CLASSES_ROOT\.pdf\PersistentHandler\(Default) you should find a CLSID that points to a value found in one of two places. Either the CLSID folder of the same key, or (for 64 bit systems) one step down in Wow6432Node\CLSID then in that CLSID's key.
Within that key you can look for LocalServer32 and find the default string value pointing to the current exe path.
I'm not 100% on any of this, but seems plausible (though you're going to have to verify on multiple environments to confirm that in-fact locates the process you're looking for).
(Here are the docs on registry keys involved regarding PersistentHandlers)
Problem 2
Probably using the CreateNoWindow of the Process StartInfo.
Process p = new Process();
p.StartInfo.FileName = #"C:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe";
p.StartInfo.Arguments = "/t \"Label.pdf\" \"HP4000\" \"HP LaserJet 4100 Series PCL6\" \"out.pdf\"";
p.CreateNoWindow = true;
p.Start();
p.WaitForExit();
(only a guess however, but I'm sure a little testing will prove it to work/not work)
If you use Acrobat reader 4.0 you can do things like this:
"C:\Program Files\Adobe\Acrobat 4.0\Reader\Acrord32.exe" /t /s "U:\PDF_MS\SM003067K08.pdf" Planning_H2
BUT if the PDF file has been created in a newer version of Acrobat an invisible window opens
For Problem 2
Using /h param will open the Acrobat or Adobe Reader in minimized window.
Example:
C:\Program Files (x86)\Adobe\Reader 10.0\Reader>AcroRd32.exe **/h** /t "Label.pdf" "HP4000" "HP LaserJet 4100 Series PCL6" "out.pdf"
Related Documentation: https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/Acrobat_SDK_developer_faq.pdf#page=24
You have already tried something different than Acrobat Reader, so my advice is forget about GUI apps and use 3rd party command line tool like RawFilePrinter.exe
private static void ExecuteRawFilePrinter() {
Process process = new Process();
process.StartInfo.FileName = "c:\\Program Files (x86)\\RawFilePrinter\\RawFilePrinter.exe";
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.Arguments = string.Format("-p \"c:\\Users\\Me\\Desktop\\mypdffile.pdf\" \"Canon Printer\"");
process.Start();
process.WaitForExit();
if (process.ExitCode == 0) {
//ok
} else {
//error
}
}
Latest version to download: https://bigdotsoftware.pl/rawfileprinter

Categories