Installing a MSI as administrator silently - c#

I am trying to create an application which will install the msi from the c# windows application, here i wanna take the input from user for UserName, Domain and password so that i can run the application in that user account. in the below code if i only give startInfo.Verb = "runas" its working but i want to provide the user name and password of admin and run it. can you guyz help me out.
private void InstallProbe()
{
try
{
bool gdfg= IsRunAsAdmin();
//processObj.InitializeProcess(txtUserName.Text, txtPassword.Text);
string installcmd = "/c msiexec /i \"{0}\" /quiet TARGETDIR=\"{1}\" HOST=\"{2}\" PORT=\"{3}\" USEHTTPS=\"{4}\" STEALTHMODE=\"{5}\" ORGCODE=\"{6}\"";
installcmd = string.Format(installcmd, txtFilePath.Text, #"%PROGRAMFILES%\ProHance Mate", "services.jamochatech.com", "8080", false, 0, "PHSALE");
string uname, domain = string.Empty;
//RunCommand("cmd", installcmd, processObj);
if (txtUserName.Text.IndexOf("\\") > 0)
{
string[] strarr = txtUserName.Text.Split('\\');
uname = strarr[1];
domain = strarr[0];
}
else
{
uname = txtUserName.Text;
domain = ".";
}
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
//startInfo.Verb = "runas";
startInfo.Domain = domain;
startInfo.UserName = uname;
startInfo.Password = ToSecureString(txtPassword.Text);
startInfo.FileName = "cmd";
startInfo.Arguments = installcmd;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.LoadUserProfile = true;
MessageBox.Show(installcmd);
process.StartInfo = startInfo;
process.Start();
process.WaitForExit(60000);
}
catch (Exception ex)
{
MessageBox.Show("Exception occured while installing the ProHance Mate " + ex.Message);
}
}

Disregarding the MSI context, you are simply trying to launch a new process (msiexec.exe) under a specific user context. Check the thread below and others alike.
In Windows: How do you programatically launch a process in administrator mode under another user context?

Related

Start second instance of Application as Admin

I want my application not to need an Admin to use it.
I should be usable for a normal user.
When a user wants to change some settings of the app I need Admin Rights.
So I want to launch a second instance of the application which requires Admin Rights.
(with user agreement request and so on)
Is there any way to accomplish that?
I tried:
Process p = new Process();
p.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
p.StartInfo.FileName = Application.ExecutablePath;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
if (System.Environment.OSVersion.Version.Major >= 6)
{
p.StartInfo.Verb = "runas";
}
p.Start();
But it seems not to work.
You can to create an account with admin rights,
Then populate the user,password properties on the ProcessStartInfo instance with the corresponding values for the admin account.
Something like:
var psi = new ProcessStartInfo
{
FileName = "notepad.exe",
UserName = "admin",
Domain = "",
Password = pass,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};
Process.Start(psi);
Turns out i have to use the UseShellExecute in the ProcessStartInfo and not the Process.
More explanation here.
ProcessStartInfo proc = new ProcessStartInfo();
proc.UseShellExecute = true;
proc.WorkingDirectory = Environment.CurrentDirectory;
proc.FileName = Application.ExecutablePath;
proc.Verb = "runas";
try
{
Process.Start(proc);
}
catch
{
return; //U have a BIG problem!
}

Diagnostic Process ends with exit code 1 but same action on command prompt works

My code uses a C# Diagnostic Process to run a GDAL process.
This process ends with an exit code 1.
But running from a command prompt works.
Where's my mistake?
Already tested (see code below):
files to transform exists,
directory to write to exists and "My programme" has access rights,
the GDAL library exists.
This is my code:
private string AddSrs(string tempFile, string User)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
string geoserverDatadir = ConfigurationManager.AppSettings["geoserverDatadir"];
string dirOut = Path.Combine(geoserverDatadir, User, Guid.NewGuid().ToString());
string fileOut = Path.Combine(dirOut, (Path.GetFileNameWithoutExtension(tempFile) + ".geoTiff"));
Directory.CreateDirectory(dirOut);
if (File.Exists(fileOut))
{
File.Delete(fileOut);
}
string binDirectory = ConfigurationManager.AppSettings["binDirectory"];
startInfo.FileName = Path.Combine(binDirectory, "gdal_translate.exe");
string args = String.Format(#"-a_srs EPSG:28992 {0}{1}{0} {0}{2}{0}", "\"", tempFile, fileOut);
startInfo.Arguments = args;
process.StartInfo = startInfo;
if(!File.Exists(startInfo.FileName))
{
_log.Error("file not exists: " + startInfo.FileName));
}
if (!File.Exists(tempFile))
{
_log.Error("file not exists: " + tempFile));
}
if (!Directory.Exists(dirOut))
{
_log.Error("directory not exists: " + dirOut));
}
try
{
// Attempt to get a list of security permissions from the folder.
// This will raise an exception if the path is read only or do not have access to view the permissions.
System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(dirOut);
}
catch (UnauthorizedAccessException ex)
{
_log.Error("no access rights for directory: " + dirOut));
}
try
{
process.Start();
int processTimeOut = 1000;
if (!process.WaitForExit(processTimeOut))
{
process.Kill();
_log.Error("Process killed by timeOut: " + processTimeOut));
return string.Empty;
}
else
{
var exitCode = process.ExitCode;
_log.Error("Process ended. Exitcode: " + exitCode));
return fileOut;
}
}
catch (Exception ex)
{
_log.Error(ex.Message));
_log.Error(ex.StackTrace));
return string.Empty;
}
}
EDIT:
This is the full command as logged in my logfile:
D:\OSGeo4W64\bin\gdal_translate.exe -a_srs EPSG:28992 "D:\data\Temp\Merkator\Hengelo Veldwijk Zuid Revisie.temp" "D:\data\Geoserver\data\Merkator\aa84dc6d-aff2-4254-975a-3ede8eea5c6d\Hengelo Veldwijk Zuid Revisie.geoTiff"
And this is the same command pasted in commandline (works with and without admin rights):
C:\Users\Administrator>D:\OSGeo4W64\bin\gdal_translate.exe -a_srs EPSG:28992 "D:\data\Temp\Merkator\Hengelo Veldwijk Zuid Revisie.temp" "D:\data\Geoserver\data\Merkator\aa84dc6d-aff2-4254-975a-3ede8eea5c6d\Hengelo Veldwijk Zuid Revisie.geoTiff"
Input file size is 1273, 378
0...10...20...30...40...50...60...70...80...90...100 - done.
INFO:
The problem exists on a (virtual) server. On my computer (debug-mode) this code works fine.

.Net Core open external terminal

I'm migrating batch script to .Net core and I'm trying to open another terminal from current terminal and run a command (I don't need stderr o stout).
With batch only needs this command: start cmd /K gulp. I'm trying to do the same with .Net core but only found the way to run the command inside current terminal.
private static string Run (){
var result = "";
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "cmd.exe";
startInfo.Arguments = $"/c \"gulp browserSync\"";
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
using (Process process = Process.Start(startInfo))
{
result = process.StandardError.ReadToEnd();
process.WaitForExit();
}
}
catch (Exception Ex)
{
Console.WriteLine(Ex.Message);
Console.ReadKey();
}
return result;
}
I'm trying changing this properties in order to open in another terminal:
startInfo.RedirectStandardOutput = false;
startInfo.RedirectStandardError = false;
startInfo.UseShellExecute = true;
But make an exception:
UseShellExecute must always be set to false.
From the MSDN docs:
UseShellExecute must be false if the UserName property is not null or an empty string, or an InvalidOperationException will be thrown when the Process.Start(ProcessStartInfo) method is called.
startInfo.UserName = null;
edit: I'm not sure why you have to pass in the arguments, but if all you want is a new CMD window try this:
try
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
WorkingDirectory = #"C:/users/replace/where_gulp_is_located",
Arguments = #"/c gulp", // add /K if its required, I don't know if its for gulp for to open a new cmd window
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true
};
Process proc = new Process();
proc.StartInfo = startInfo;
proc.Start();
if (showOut)
{ ///code }
}catch(Exception ex)
{
Console.WriteLine(ex);
}
You wont need startInfo.UserName in this case because you are specifying a working directory.
Thanks to #bender-bending answer I found a way to solve it. Due security limitations need user/password credentials in order to autorice current terminal to open a new one.
WorkingDirectory, user, password and domain are required.
Create no window, redirect output and redirect error must be false, in order to see command result in new window.
public static void Sample(){
try
{
Console.Write("Password: ");
StringBuilder password = new StringBuilder();
while (true)
{
var key = System.Console.ReadKey(true);
if (key.Key == ConsoleKey.Enter) break;
password.Append(key.KeyChar);
}
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
WorkingDirectory = "C:/path_to/Gulp",
Arguments = $"/c \"gulp browserSync\"",
UseShellExecute = false,
RedirectStandardOutput = false,
RedirectStandardError = false,
UserName = Machine.User(),
PasswordInClearText = password.ToString(),
Domain = Machine.Domain(),
CreateNoWindow = false
};
Process proc = new Process();
proc.StartInfo = startInfo;
proc.Start();
//proc.WaitForExit();
} catch (Exception ex)
{
System.Console.WriteLine(ex);
System.Console.ReadKey();
}
}
.Net Core doesn't have a method to obtain user and domain. We can use this class to get this values from environment variables.
public static class Machine
{
public static string User(){
return Environment.GetEnvironmentVariable("USERNAME") ?? Environment.GetEnvironmentVariable("USER");
}
public static string Domain(){
return Environment.GetEnvironmentVariable("USERDOMAIN") ?? Environment.GetEnvironmentVariable("HOSTNAME");
}
}
Hope it helps!

How to get the login id of a user logged in remote computer?

I am using the following code to get the current logged in user through remote desktop
public string connect(string machineName)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = "cmd.exe";
string command = "/C tasklist /v /fo list /fi \"imagename eq explorer.exe\" /s " + machineName;
startInfo.Arguments = command;
process.StartInfo = startInfo;
startInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
string strOutput = process.StandardOutput.ReadToEnd();
if(strOutput.Contains("\\"))
{
int qindex = strOutput.IndexOf("\\");
int rindex = strOutput.IndexOf("\r", qindex);
string substring = strOutput.Substring((qindex + 1), (rindex - qindex));
return substring;
}
}
But this process is taking unusually long time (more than 1 min) to get the remote user name. I cant run wmic since RPC is not enabled in the remote computer.
I also tried the following
string UNC = "\\\\";
UNC += machineName;
UNC += "\\C$\\Users";
DirectoryInfo di = new DirectoryInfo(UNC);
DirectoryInfo[] dirs = di.GetDirectories("*", SearchOption.TopDirectoryOnly);
var Myfile = dirs.OrderByDescending(f => f.LastWriteTime).First();
But this not always reliable because the user name directory is not getting updated even though the user is logged in.
Is there any simpler process to get the remote user name

Create Windows User Using c# code

I want to create a windows user using c# code. Below methods works fine when the logged in user is having Administratorive privilage. It is not working with the limited user. Note that I can pass the windows user name and password of the administrator user. Basically I want to impersonate. I tried impersonation it did not work. I tried passing user namd and password to the processinfo. I got the error "The stub received bad data". So can any one help me on how to create the windows user using c# code by impersonation.
public static void CreateUser(string userName, string password, string description, string adminUserName, string adminPassword)
{
Process process = new Process();
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.WorkingDirectory = Environment.SystemDirectory;
processInfo.FileName = "net.exe";
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardInput = true;
processInfo.RedirectStandardOutput = true;
processInfo.WindowStyle = ProcessWindowStyle.Hidden;
processInfo.Arguments = #" user " + userName + #" " + password + #" /ADD /ACTIVE:YES " +
#"/EXPIRES:NEVER /FULLNAME:" + userName + #" /PASSWORDCHG:NO /PASSWORDREQ:YES";
if (!string.IsNullOrEmpty(adminUserName))
{
processInfo.UserName = adminUserName;
processInfo.Password = WindowsSecurityHelper.GetSecuredString(adminPassword);
}
process.StartInfo = processInfo;
process.Start();
process.WaitForExit();
process.Close();
}
or
public static void CreateUser(string userName, string password, string description, string userGroup = "Users")
{
PrincipalContext pc = new PrincipalContext(ContextType.Machine, null);
GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, userGroup);
if (gp != null)
{
UserPrincipal u = new UserPrincipal(pc);
u.SetPassword(password);
u.Name = userName;
u.Description = description;
u.UserCannotChangePassword = true;
u.PasswordNeverExpires = true;
u.Save();
gp.Members.Add(u);
gp.Save();
}
}
You can use the Process class with different credentials - instead of setting it directly, use ProcessStartInfo.
You can set a UserName and Password on the ProcessStartInfo class for the user you wish to execute as (Password is a SecureString, by the way) - pass this to the Process constructor and you are good to go.
ProcessStartInfo startInfo = new ProcessStartInfo("net.exe");
startInfo.UserName = Administrator;
startInfo.Password = ...;
...
Process.Start(startInfo);
I had the same error and found that I needed to specify the Domain parameter in the ProcessStartInfo.

Categories

Resources