How do i execute an external exe using a specific user - c#

Im making an application which needs to monitor the filesystem using FileSystemWatcher, to detect how an installation affects the filesystem.
To get rid of noise i want to filter the events that are created by their creating user, and that code is working with the //BUILTIN //Administrator user, which is used by default when doing an installation. But still there are quite a bit of noise. Then i got the idea of creating a specific user that i can use for running the installation file, and filter on that specific user, and thereby getting rid of allmost all the noise.
this is my code for the process creation and start
private void executeInnoInstaller(string path, string fileName)
{
// Use ProcessStartInfo class
ProcessStartInfo installerProces = new ProcessStartInfo();
installerProces.CreateNoWindow = true;
installerProces.UseShellExecute = false;
installerProces.FileName = path + "\"" + fileName + "\"";
installerProces.WindowStyle = ProcessWindowStyle.Normal;
installerProces.UserName = "test";
System.Security.SecureString encPassword = new System.Security.SecureString();
foreach (System.Char c in "test")
{
encPassword.AppendChar(c);
}
encPassword.MakeReadOnly();
installerProces.Password = encPassword;
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(installerProces))
{
exeProcess.WaitForExit();
//int exitCode = exeProcess.ExitCode;
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
this code exits with a access denied.
OS=Windows
Ive already tried to run the installer.exe from the OS filehandler with SHIFT - Rightclick using the specified user, and it works.
VisualStudio is run as administrator.
Ive tried to run the build project exe file as administrator, but it does not work.
Without the user credentials, the code works and uses the //BUILTIN //Administrator account
Does anybody have any idea ?
Thank you beforehand for your time and effort.

This code works if i turn down the UAC securitylevel to the lowest.

Related

Run bat file with UWP C#

I'm trying to build UWP app and I'm struggling with an issue:
I have noticed there is now way to launch external executable, but I can open file with its default application using LaunchFile (Like mentioned here https://learn.microsoft.com/en-us/uwp/api/Windows.System.Launcher#Windows_System_Launcher_LaunchFileAsync_Windows_Storage_IStorageFile_).
Should it work for a .bat file too? Where should i place the .bat file if it is.? Because i tried to give a path to a .bat file i wrote and I got an exception.
Thanks!!
Its not going to work. If you can get some 3rd party application to open and handle bat files by default then maybe, but otherwise nothing the OS handles like cmd or vbscript will run. Not sure what your goal is, but a 3rd party scripting app like Autohotkey does work.
From .NET 4 there is and Process and ProcessStartInfo
classes under the System.Diagnostics namespace which allow you
to Win32 applications from C#.
public static Task<bool> ExecuteBatchFile(string BatchFilePath, string BatchFileDirectory)
{
try
{
Task<bool> executeBatchFileTask = Task.Run<bool>(() =>
{
bool hasProcessExited = false;
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = BatchFilePath,
CreateNoWindow = false,
UseShellExecute = true,
WindowStyle = ProcessWindowStyle.Normal,
WorkingDirectory = BatchFileDirectory
};
// Start the process with the info we specified.
// Call WaitForExit and then the using-statement will close.
using (System.Diagnostics.Process exeProcess = System.Diagnostics.Process.Start(startInfo))
{
while (!exeProcess.HasExited)
{
//Do nothing
}
hasProcessExited = true;
}
return hasProcessExited;
});
return executeBatchFileTask;
}
catch (Exception ex)
{
throw;
}
}
And call this method in your code by:
bool hasBatchFileExecuted = await ExecuteBatchFile(BatchFilePath, BatchFilePathDirectory);
Create your own batch file like:
1) Create a text file in notepad and save it as run.bat under save as category and all files.
2) Write the following code to execute a C# program/However you can write your own commands also:
csc someRandomCode.cs
pause
3) Save and quit.

How do I call a python script from a network drive using c#

I'm calling a python script from a C# tool. I based my code on this post. I use ProcessStartInfo to start python and pass a .py file and some argument to it. The code runs fine when the .py, CreateAssessorMap.py, file is on the c drive but not when it is on a mapped network drive. No error is thrown but no python code is executed as far as I can see. If I manually do the same operation from the command line it runs fine.
The code below the first procStartInfo.Arguments will fail as CreateAssessorMap.py is on a network drive. The commented out line below it would work as the script is on the C drive.
private void btnPrint_Click(object sender, EventArgs e)
{
try
{
ProcessStartInfo procStartInfo = new ProcessStartInfo();
procStartInfo.FileName = "python";
procStartInfo.Arguments = string.Format("{0} {1} {2}", #"D:\Map_Generate_Scripts\CreateAssessorMap.py", this.txtSheet.Text, txtDestinationFolder.Text);
//procStartInfo.Arguments = string.Format("{0} {1} {2} ", #"C:\Projects\Map_Generate_Scripts\CreateAssessorMap.py", this.txtSheet.Text, txtDestinationFolder.Text);
procStartInfo.UserName = null;
procStartInfo.UseShellExecute = false;
procStartInfo.RedirectStandardOutput = true;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now you create a process, assign its ProcessStartInfo, and start it.
using (Process process = Process.Start(procStartInfo))
{
using (System.IO.StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
Console.Write(result);
}
}
}
catch (Exception ecpt)
{
Console.WriteLine(ecpt.Message);
}
this.Parent.Hide();
}
Edit
I added some error handling and the python code is failing with the message that the .py file cannot be found.
python: can't open file 'D:\Map_Generate_Scripts\CreateAssessorMapCreateAssessorMap.py': [Errno 2] No such file or directory
I know it exists since I can run the file from the command line with the same arguments. So it seems that when I run from C# the python process can't find the d drive.
I assume that when it runs from a network drive it takes longer and your program does not wait for Python script's completion. I suggest adding proces.Wait() before reading the output stream.
As stated in the comments, the solution for Dowlers was to use the full path instead of the mapped network drive.
Change
#"D:\Map_Generate_Scripts\CreateAssessorMap.py"
To
#"\\[network path]\Map_Generate_Scripts\CreateAssessorMap.py"

Start hidden Internet Explorer

my company is using Sharepoint and ADFS. For the use of WebDav however we need the users to get some tokens which they only get by opening the Internet Explorer and navigate to two sites. However they will lose the token every ~30 Minutes, so it has to be a recurring task.
So now my job is to:
Open 2 Websites with IE
Every 30 Minutes
Don't annoy the user
My current solution is "kinda" working but I am not really satisfied with it.
I have only VSExpress so no Services.
I have a minimized max opacity visible false Windows Form.
I have a GPO which copies an EXE file to the computer and then creates a timed job that starts it every 30 minutes after login. However it is not really working out, people still have trouble accessing webdav if they don't run the EXE manually. Also whenever the EXE is running the current application the user is working in loses focus which is kinda annoying when you are typing something and have to click back in.
My current code is looking like this:
private void Form1_Load(object sender, EventArgs e)
{
MainMethod();
}
private void MainMethod()
{
RegistryKey root = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Classes\InternetExplorer.ApplicationMedium\CLSID", false);
if (root!=null)
{
opensite();
Application.Exit();
}
}
private void opensite()
{
try
{
SHDocVw.InternetExplorer _ie1 = (SHDocVw.InternetExplorer)Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.ApplicationMedium"));
SHDocVw.InternetExplorer _ie2 = (SHDocVw.InternetExplorer)Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.ApplicationMedium"));
_ie1.Visible = false;
_ie2.Visible = false;
_ie1.Navigate("SITENAME1.html");
_ie2.Navigate("SITENAME2.html");
System.Threading.Thread.Sleep(10000);
_ie1.Quit();
_ie2.Quit();
}
catch(Exception e)
{
}
}
However, I feel there is a much more elegant way to do this. I heard the only way to open a hidden IE is via
(SHDocVw.InternetExplorer)Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.ApplicationMedium"));
But with this I rely on the registry key which not all clients have.
Can you help me open the IE in a reliable way and maybe have some tipps on how I should set the recurring task to just start every 30 minutes (because I think it is not doing it correctly atm).
Thank you all in advance.
EDIT:
Thanks to https://stackoverflow.com/users/5065008/daniel-waghorn
I now replaced the opensite bit with:
private void Form1_Load(object sender, EventArgs e)
{
MainMethod();
}
private void MainMethod()
{
openProc("SITE1.html");
openProc("SITE2.html");
Application.Exit();
}
private void openProc(string site)
{
ProcessStartInfo startInfo = new ProcessStartInfo();
string ProgramFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
startInfo.FileName = ProgramFiles + #"\Internet Explorer\iexplore.exe";
startInfo.Arguments = "" + site + "";
startInfo.CreateNoWindow = true;
startInfo.ErrorDialog = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo);
}
Thanks again!
You can use ProcessStartInfo to create a new instance of IE:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = ""C:\Program Files\Internet Explorer\iexplore.exe"";
startInfo.Arguments = "" + url + "";
startInfo.CreateNoWindow = true;
startInfo.ErrorDialog = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo);
You could use Environment.SpecialFolder.ProgramFiles to get the user's Program Files directory path if you don't want to hard-code it.
I must point out that startInfo.WindowStyle will start Internet Explorer hidden although if at any point IE decides to alter that value for any reason it may show.
Ideally if you aren't tied to using Internet Explorer to get the tokens another alternative would be to use the above code but target cURL or something similar. With this it will run in the command line which you can guarantee not to show or steal focus with startInfo.CreateNoWindow.
I think you'll find your answer in one of these links:
Handle IE To filling a form c#
Opening a Hidden Internet Explorer Window without it getting Focus?

Powerpoint Process works in standalone console project, but not integrated project

I'm trying to run a local process using C# to call Powerpoint and convert a .pdf to a .ppt.
I made a standalone console app, in hopes of reproducing and isolating the problem.
Unfortunately, it works for the standalone version, but not with the integrated version.
When it doesn't work, it throws no exceptions. It just silently fails to create the .pdf file.
NEW:
I'm getting an error on the event log:
Microsoft PowerPoint
PowerPoint can't do this because a dialog box is open. Please close the dialog box to continue.
P1: 400205
P2: 15.0.4420.1017
I don't see any sort of dialog box when running the console commands, the standalone console application, or running the integrated web project on my local machine.
The /pt command is supposed to be silent, as per the official documentation.
I can set the Identity of the ApplicationPool the project is running under to the user that I log in as, and I no longer get the above error in the event log. However, I get no other errors (that I can tell are related) from the event log.
It still doesn't work, however. Powerpoint or PDFCreator still crashes, and doesn't create the .pdf.
I also tried to run my working console app by calling it as a Process from my integrated issue, and that didn't work either.
The working console application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Diagnostics;
using System.Text;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
var psi = new ProcessStartInfo();
psi.FileName = "\"C:\\Program Files\\Microsoft Office\\Office15\\POWERPNT.exe\"";
psi.Arguments = "/pt \"PDFCreator\" \"\" \"\" dd0e03ff-f386-4e65-b89d-72c7f1ee502d.pptx";
psi.WorkingDirectory = "C:\\Temp";
psi.CreateNoWindow = true;
psi.ErrorDialog = true;
psi.UseShellExecute = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = false;
psi.RedirectStandardError = true;
try
{
using (Process exeProcess = Process.Start(psi))
{
exeProcess.PriorityClass = ProcessPriorityClass.High;
var outString = new StringBuilder(100);
exeProcess.OutputDataReceived += (s, e) => outString.AppendLine(e.Data);
exeProcess.BeginOutputReadLine();
var errString = exeProcess.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(errString))
{
Console.WriteLine("errors reported 1");
}
}
}
catch (Exception ex)
{
ex.ToString();
Console.WriteLine("Errors reported 2 ");
Console.WriteLine(ex.ToString());
}
Console.WriteLine(psi.FileName);
Console.WriteLine(psi.Arguments);
Console.WriteLine(psi.WorkingDirectory);
}
}
}
It prints
"C:\Program Files\Microsoft Office\Office15\POWERPNT.exe"
/pt "PDFCreator" "" "" dd0e03ff-f386-4e65-b89d-72c7f1ee502d.pptx
C:\Temp
The not working integrated application:
using System;
using System.Diagnostics;
using System.Text;
namespace CT.Services.Helper
{
public static class ExecutableRunner
{
public static ExecutableResult RunExeNamed(string exeFilename, string commandLineArgs)
{
return RunExeNamed(exeFilename, commandLineArgs, null);
}
public static ExecutableResult RunExeNamed(string exeFilename, string commandLineArgs, string workingDirectory)
{
var result = new ExecutableResult { WasSuccessful = true };
var psi = new ProcessStartInfo();
psi.FileName = "\""+exeFilename+"\"";
psi.Arguments = commandLineArgs;
if(!string.IsNullOrEmpty(workingDirectory))
{
psi.WorkingDirectory = workingDirectory;
}
psi.CreateNoWindow = false;
psi.ErrorDialog = true;
psi.UseShellExecute = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = false;
psi.RedirectStandardError = true;
try
{
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(psi))
{
exeProcess.PriorityClass = ProcessPriorityClass.High;
var outString = new StringBuilder(100);
// use ansynchronous reading for at least one of the streams
// to avoid deadlock
exeProcess.OutputDataReceived += (s, e) => outString.AppendLine(e.Data);
exeProcess.BeginOutputReadLine();
// now read the StandardError stream to the end
// this will cause our main thread to wait for the
// stream to close (which is when ffmpeg quits)
var errString = exeProcess.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(errString))
{
result.WasSuccessful = false;
result.ErrorMessage = errString;
}
}
}
catch (Exception ex)
{
result.WasSuccessful = false;
result.ErrorMessage = ex.ToString();
}
Debug.WriteLine(psi.FileName);
Debug.WriteLine(psi.Arguments);
Debug.WriteLine(psi.WorkingDirectory);
return result;
}
}
public class ExecutableResult
{
public bool WasSuccessful { get; set; }
public string ErrorMessage { get; set; }
}
}
it prints
"C:\Program Files\Microsoft Office\Office15\POWERPNT.exe"
/pt "PDFCreator" "" "" dd0e03ff-f386-4e65-b89d-72c7f1ee502d.pptx
C:\Temp
I would think that one of the strings I'm using as the file path or console command would be wrong, so I had them printed to the console, but you can see that those aren't the issue.
Last try ;-)
You could use Interop, open the file and afterwards save it as pdf.
For this little example to work you need to reference the Microsoft.Office.Interop.PowerPoint assembly and the Microsoft.Office.Core namespace (found in the "Microsoft Office 14.0 Object Library" assembly which is located under the COM assemblies).
Little Example:
/// <summary>
/// Converts the specified source file and saves it as pdf with the
/// specified destination filename.
/// </summary>
/// <param name="sourceFilename">The filename of the file to be converted into a pdf.</param>
/// <param name="destinationFilename">The filename of the pdf.</param>
/// <exception cref="System.IO.FileNotFoundException">Is thrown if the specified source file does not exist.</exception>
/// <exception cref="System.Exception">Is thrown if something went wrong during the convertation process.</exception>
public static void SaveAsPDF(string sourceFilename, string destinationFilename)
{
if (!File.Exists(sourceFilename))
{
throw new FileNotFoundException(string.Format("The specified file {0} does not exist.", sourceFilename), sourceFilename);
}
try
{
Microsoft.Office.Interop.PowerPoint.Application app = new Microsoft.Office.Interop.PowerPoint.Application();
app.Presentations.Open(sourceFilename).SaveAs(destinationFilename, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsPDF);
app.Quit();
}
catch (Exception e)
{
throw new Exception(string.Format("Unable to convert {0} to {1}", sourceFilename, destinationFilename), e);
}
}
Could it be a problem with the permissions of the application pool? Maybe it does not have permissions to perform all the actions you want to - you could check that by executing your console application under the same context as the application pool is running.
Just another idea (not sure if it is a stupid one or not). As far as I remember powerpoint (at least since 2010) is able to save directly to pdf. For 2007 you can use a microsoft plugin called "Save as PDF" which can be found here 2007 Microsoft Office Add-in: Microsoft Save as PDF or XPS.
Using the provided Solution from Todd Main you could (theoretically) execute a macro at startup which could store the file directly as PDF (without printing and hopefully without dialog box).
Update:
I've tried it right now - problem is you have to store the macro in the presentation, therfore you have to use the pptm file format. Next you have to open the file once and activate the macro execution (is shown on the top of the editing screen). After that you can simply execute it from the command line like
POWERPNT.EXE /M Filename.pptm SaveAsPDF
The macro looks like this:
Sub SaveAsPDF()
Dim ap As Presentation: Set ap = ActivePresentation
ap.SaveAs ap.Path & "\" & ap.Name, ppSaveAsPDF
PowerPoint.Application.Quit
End Sub
The integrated version of the code is part of a web application
Provide access to the current working directory where this file is being created for the app pool user and verify it has Read/Write.
Check the Temp directory on the server for the app-pool process user and verify that the process has read/write access to the temp directory.
Edit Upon seeing the event log.
Asp.net should not be using any application which is a user interactive process. You need to find a different application to create these powerpoint slides that is asp.net friendly or determine what Powerpoint is trying to do when it opens a dialog.
Odds are you are seeing this problem because you've never actually opened up Powerpoint under the user that is running the application in the environment where it's failing.
This will be the user that the application pool is running under and, as I see you've mentioned to OmegaMan, that user is LocalSystem.
When LocalSystem tries to open Powerpoint, then Powerpoint will be doing that thing that all Office applications do where they complete their install the first time a new user runs them.
You are not seeing this installation box in your console app or on your local system because you're running those under your own account and you've previously opened PowerPoint.
As OmegaMan rightly says Powerpoint is meant to be an interactive process so it is probably going to cause trouble even if you're very very careful. You'll end up with instances of Powerpoint staying open after they're supposed to have closed and loads of instances building up in the
That said, if you really want to get this running then you either need to get the application pool running as a user that has opened Powerpoint interactively, or change your code to use impersonation at the point where you need to run Powerpoint and then impersonate a user that has used it interactively to do what you need.

Request privileged rights and keep this with C# in Ubuntu Linux

I'm writing a tool that can be used to manage the virtual host a web server on Ubuntu. As for many of the features I need privileged rights, I look for ways to achieve this.
Currently I realize that with "gksu" or "gksudo". This also works. The problem is that the user is prompted for any activity that requires privileged rights to enter his password.
Is it possible to retrieve this password only once and remember for the rest of the duration of the program? Is there another way to implement this?
public void OnToogledVirtualHost(object o, ToggledArgs args)
{
VirtualHost host = (VirtualHost)store.GetNode(new TreePath(args.Path));
host.Enabled = !host.Enabled;
Process process = new Process();
process.StartInfo.UseShellExecute = false;
if (host.Enabled)
{
process.StartInfo.FileName = "gksu";
process.StartInfo.Arguments = "a2ensite " + System.IO.Path.GetFileName(host.FilePath);
}
else
{
process.StartInfo.FileName = "gksu";
process.StartInfo.Arguments = "a2dissite " + System.IO.Path.GetFileName(host.FilePath);
}
process.Start();
}
AFAIK, it is a security feature of 'su' not to cache the password (more properly the authentication ticket) for more than a few seconds, and thus this is designed not to be bypassed.
You can always gksu an intermediary process and try to make the sub-processes inherit its authorization, but you'll need to secure the IPC (the communication channel between your tool frontend and the intermediary process).
So my advice is to not try to lessen the security of the overall solution, so let the user be asked as many times as needed...
There are several (at least 3) "secure" solutions to this problem:
Use "sudo", that allows for password caching. This is my preferred solution if I can install and configure sudo on the machine. Pros: sudo will cache the password. Cons: it depends on having an external dependency (sudo) correctly configured.
Write different helper executables (for example a "modify configuration and restart apache" program) and when needed ask the user to authenticated using gksu, then launch them. Pros: user gets asked for the password only once for every group of actions. Cons: The user still get asked for the password multiple times AND you have to split the program in multiple pieces.
Write a separate service that runs with root privileges and use polkit/DBUS to authenticate the user and connect to it to require services (like, "restart apache please"). Pros: credential caching and authentication dialog is managed by dekstop/polkit. Cons: more code to write and you need to run a DBUS service.
"secure" is quoted because running code (and especially managed code that depends on a large application such as Mono) as root always has security implications.
Thanks for the useful approaches. Yesterday I arrived at a solution of the problem, which I have enclosed in a static class. First, a distinction is made between normal and privilligierten processes.
Whenever a process needs to be run with elevated privileges, I check if I know the user's password already. If not, I'll get it (gksudo -p) and store it in memory.
Now I can execute commands with privilligierten rights. The stored password is then transferred via the standard input (sudo -S).
What do you think? Do you have any safety concerns?
public static class SystemProcess
{
private static string output;
private static string error;
private static string password;
public static void Start (string filename, string arguments)
{
ProcessStartInfo startInfo = SystemProcess.Prepare(filename, arguments);
using (Process process = Process.Start(startInfo)) {
SystemProcess.output = process.StandardOutput.ReadToEnd();
SystemProcess.error = process.StandardError.ReadToEnd();
process.WaitForExit();
}
}
public static void StartPrivileged (string filename, string arguments)
{
ProcessStartInfo startInfo;
if (SystemProcess.password == default(string))
{
startInfo = SystemProcess.Prepare("gksudo", "-p true -D 'MyApplication'");
using (Process process = Process.Start(startInfo)) {
SystemProcess.password = process.StandardOutput.ReadToEnd();
process.WaitForExit();
}
}
startInfo = SystemProcess.Prepare("sudo", "-S " + filename + " " + arguments);
using (Process process = Process.Start(startInfo)) {
process.StandardInput.WriteLine(SystemProcess.password);
SystemProcess.output = process.StandardOutput.ReadToEnd();
SystemProcess.error = process.StandardError.ReadToEnd();
process.WaitForExit();
}
}
private static ProcessStartInfo Prepare (string filename, string arguments)
{
ProcessStartInfo startInfo = new ProcessStartInfo (filename, arguments);
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;
return startInfo;
}
public static string Output {
get {
return SystemProcess.output;
}
}
public static string Error {
get {
return SystemProcess.error;
}
}
}
You know, I'd not use gksu or sudo for any of this, sounds like you want to look at userv instead.
You can basically permit different users to run different programs,

Categories

Resources