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.
Related
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?
I'm working with LibGit2Sharp to add a number of Git operations to an application. I've added the Microsoft.Alm.Authentication to help with Authentication and credential manager access. It works great for retrieving credentials that are already entered from the command line.
However is there any way to also hook into the Credential Manager's Login UI that prompts for username and password for Github, BitBucket and VSTS. This UI pops up automatically from the command line, but doesn't fire when using LibGit2Sharp.
I've looked at the GitCredentialManager project on Github and I can see the components that provide the UI, but before trying to figure out how to hook those in explicitly, is there some way I'm missing that this is provided as part of the Microsoft.Alm.Authentication (or related package)? Or can anybody point to an example or guidance on how to best hook this up?
I managed to get your solution working with some minor modifications. I paste here a sample code to push using git credentials. It works using the credentials already stored in the computer and prompts for credentials the first time with UI.
Only problem I'm having so far is when user is prompt for credentials and they enter an invalid user/password. Git writes to the console asking for user/pass and the process is not finished until you input that. Tried to monitor StandardError/Output with no success. I get the error text in stderror but only after filling that manually.
public void PushLibGit2Sharp(string repositoryFolder, string branch)
{
using (var repo = new Repository(repositoryFolder))
{
var options = new PushOptions
{
CredentialsProvider = (url, usernameFromUrl, types) =>
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = "git.exe",
Arguments = "credential fill",
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
Process process = new Process
{
StartInfo = startInfo
};
process.Start();
// Write query to stdin.
// For stdin to work we need to send \n instead of WriteLine
// We need to send empty line at the end
var uri = new Uri(url);
process.StandardInput.NewLine = "\n";
process.StandardInput.WriteLine($"protocol={uri.Scheme}");
process.StandardInput.WriteLine($"host={uri.Host}");
process.StandardInput.WriteLine($"path={uri.AbsolutePath}");
process.StandardInput.WriteLine();
// Get user/pass from stdout
string username = null;
string password = null;
string line;
while ((line = process.StandardOutput.ReadLine()) != null)
{
string[] details = line.Split('=');
if (details[0] == "username")
{
username = details[1];
}
else if (details[0] == "password")
{
password = details[1];
}
}
return new UsernamePasswordCredentials()
{
Username = username,
Password = password
};
}
};
repo.Network.Push(repo.Branches[branch], options);
}
}
Unfortunately, there's no functionality in libgit2 (or LibGit2Sharp) to talk directly to the git-credential-helper functionality, which is what git itself uses to perform this action.
Instead, you can set a CredentialsHandler on your PushOptions (or FetchOptions), eg:
options.CredentialsProvider = (url, usernameFromUrl, types) => {
string username, password;
Uri uri = new Uri(url);
string hostname = uri.Host;
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = false;
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.FileName = "git.exe";
startInfo.Arguments = "credential fill";
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.StandardInput.WriteLine("hostname={0}", hostname);
process.StandardInput.WriteLine("username={0}", usernameFromUrl);
while ((line = process.StandardOutput.ReadLine()) != null)
{
string[] details = line.Split('=', 2);
if (details[0] == "username")
{
username = details[1];
}
else if (details[0] == "password")
{
password = details[1];
}
}
return new UsernamePasswordCredentials(username, password);
};
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
With this code I see the login window prompting for a password but I can't seem to write the password to the shell window.
Process scp = new Process();
scp.StartInfo.FileName = #"c:\cygwin\bin\scp";
scp.StartInfo.Arguments = "/cygdrive/c" + path + " " + username + "#" + ServerName + ":/cygdrive/c/Temp/.";
scp.StartInfo.UseShellExecute = false;
scp.StartInfo.RedirectStandardOutput = true;
scp.StartInfo.RedirectStandardError = true;
scp.StartInfo.RedirectStandardInput = true;
scp.Start();
//I've tried this with no success:
using (StreamWriter sw = scp.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine(pass);
}
}
// Another failed attempt:
scp.StandardInput.Write(pass + Environment.NewLine);
scp.StandardInput.Flush();
Thread.Sleep(1000);
I know I can get this to work with cygwin expect but would rather use c# to interact with the windows input / output.
Try this:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
Process scp = new Process();
scp.StartInfo.FileName = #"c:\cygwin\bin\scp";
scp.StartInfo.Arguments = "/cygdrive/c" + path + " " + username + "#" + ServerName + ":/cygdrive/c/Temp/.";
scp.StartInfo.UseShellExecute = false;
scp.StartInfo.RedirectStandardOutput = true;
scp.StartInfo.RedirectStandardError = true;
scp.StartInfo.RedirectStandardInput = true;
scp.Start();
Process[] p = Process.GetProcessesByName("cmd");
SetForegroundWindow(p[0].MainWindowHandle);
SendKeys.SendWait(pass);
scp.WaitForExit();
EDIT: Be sure to include \n at the end of pass.
this code works fine as expected and with no need to call Flush or Sleep:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine("dir");
}
}
are you 100% sure that your cygwin is just waiting for the pwd?
I have an Windows Form application that supplies the User Name, Domain, and Password to the StartInfo, and it throws this:
System.ComponentModel.Win32Exception: The handle is invalid
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
When I allow the credentials to default to current user I get no such error, and the process I start works to the extent that it doesn't need to use credentials (the creds are necessary for mapping a drive in an MSBuild script). Here's the code that fills the start info:
Process p = new Process();
ProcessStartInfo si = new ProcessStartInfo(buildApp, buildArgs);
si.WorkingDirectory = msBuildWorkingDir;
si.UserName = txtUserName.Text;
char[] psw = txtPassword.Text.ToCharArray();
SecureString ss = new SecureString();
for (int x = 0; x < psw.Length; x++)
{
ss.AppendChar(psw[x]);
}
si.Password = ss;
si.Domain = "ABC";
si.RedirectStandardOutput = true;
si.UseShellExecute = false;
si.WorkingDirectory = txtWorkingDir.Text;
p.StartInfo = si;
p.Start();
It isn't that the user/psw isn't matching, because when I provide a bad psw, for example, it catches it. So, this "invalid handle" thing is happening after the cred is passed. Any ideas on what I might be omitting or screwing up?
You have to redirect your Input, Error, and Output.
for example:
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
info.UserName = dialog.User;
using (Process install = Process.Start(info)) {
string output = install.StandardOutput.ReadToEnd();
install.WaitForExit();
// Do something with you output data
Console.WriteLine(output);
}
Also microsoft has said the error should read, "Unable to redirect input." (used to have a link, but that no longer worked)