Can't export HKLM registry key in C#/.NET - c#

I need to export a registry key from the HKLM hive to a file. This is a key which I've successfully created just a few lines back in the same program. I am using a Process object to have my C# program execute the shell command:
cmd.exe /c regedit.exe /e C:\temp\CDPRegExport.txt HKEY_LOCAL_MACHINE\SOFTWARE\NPTMigration
If I execute my program, the file C:\temp\CDPRegExport.txt is not created. However, if I run the command above directly (in this same administrative console window) it works fine!
I tried adding an application manifest to ensure that my .NET program is running as an administrator.
I tried invoking reg.exe export instead of regedit.exe /e but the result is the same (I'm guessing the same DLL is ultimately being used by these 2 programs).
Here's the main Registry Export method:
static bool RegistryExport(string regKey, string destFile)
{
Cmd cmd = new Cmd()
{
CreateNoWindow = true
};
cmd.Exec(#"regedit.exe", #"/e", destFile, regKey);
Console.WriteLine("Standard Out:\r\n" + cmd.StandardOut);
Console.WriteLine("Standard Error:\r\n" + cmd.StandardErr);
if (!File.Exists(destFile))
{
AppContext.log.Critical(#"Registry export file ({0}) not found!", destFile);
return false;
}
return true;
}
...And here's Cmd.Exe():
public void Exec(string command, params string[] Parameters)
{
string fullyQualifiedCommand = #"/c " + command + GetParameters(Parameters);
Console.WriteLine(fullyQualifiedCommand);
try
{
psi = new ProcessStartInfo(#"cmd", fullyQualifiedCommand)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
};
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
using (Process process = new Process())
{
process.StartInfo = psi;
process.Start();
if (RedirectIOStreams)
{
StandardOut = process.StandardOutput.ReadToEnd();
StandardErr = process.StandardError.ReadToEnd();
}
process.WaitForExit();
}
NormalExit = true;
}
catch (Exception ex)
{
StandardOut = string.Empty;
StandardErr = ex.ToString();
}
}
private static string GetParameters(string[] Parameters)
{
string expression = string.Empty;
if (Parameters.Length == 0)
return string.Empty;
for (int index=0; index<Parameters.Length; index++)
{
if (Parameters[index].Contains(" "))
expression += " \"" + Parameters[index] + "\"";
else
expression += " " + Parameters[index];
}
return expression;
}
When the program uses regedit.exe both standard out and standard error are simply blank.
When it uses reg.exe export however, standard error shows:
"ERROR: The system was unable to find the specified registry key or value."
Again, this is odd because if I invoke the exact same reg.exe or regedit.exe syntax directly via the command window, it works fine!

If 32-bit process on 64-bit OS, you must disable the WOW64 file system redirection
This test works for me (Windows 10, VS 2015 ) =>
bool bWow64 = false;
IsWow64Process(Process.GetCurrentProcess().Handle, out bWow64);
if (bWow64)
{
IntPtr OldValue = IntPtr.Zero;
bool bRet = Wow64DisableWow64FsRedirection(out OldValue);
}
string sKey = #"HKEY_LOCAL_MACHINE\SOFTWARE\NPTMigration";
string sFile = #"C:\temp\CDPRegExport.txt";
using (Process process = new Process())
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.FileName = "reg";
psi.Arguments = "export " + "" + sKey + "" + " " + "" + sFile + "";
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;
process.StartInfo = psi;
process.Start();
using (StreamReader reader = process.StandardOutput)
{
string sResult = reader.ReadToEnd();
Console.Write(sResult);
}
}
with declarations :
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool IsWow64Process(IntPtr hProcess, out bool Wow64Process);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool Wow64DisableWow64FsRedirection(out IntPtr OldValue);

Related

Process.Start cannot run batch file properly

I am trying to run a batch file using C#
The batch file for the test purposes contains
msg * Test
It works if I run it manually.
Then I use the following code to run this .bat file
filePath = full path to batch file
var startInfo = new ProcessStartInfo
{
Arguments = "/C \"" + filePath + "\"",
FileName = "cmd.exe",
UseShellExecute = true
};
Process p = Process.Start(startInfo);
and it does not work ->
cannot find msg
What I am doing wrong?
P.S. the batch file should not be changed.
Try this way:
batchfile:
set "msg=%SystemRoot%\System32\msg.exe"
if not exist "%msg%" set "msg=%SystemRoot%\Sysnative\msg.exe"
"%msg%" * Hello
code:
string sFile = <full path to batch file>;
Process.Start("cmd.exe", "/c " + sFile);
Probably need some authorization, you may try the following code:
static void ExecuteCommand(string command)
{
int exitCode;
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.CreateNoWindow = true;
processInfo.Domain = "domain"; // Your own domain
processInfo.UserName = "userName"; // Your own user name
System.Security.SecureString s = new System.Security.SecureString();
s.AppendChar('p'); // Your own password
s.AppendChar('a');
s.AppendChar('s');
s.AppendChar('s');
s.AppendChar('w');
s.AppendChar('o');
s.AppendChar('r');
s.AppendChar('d');
processInfo.Password = s;
processInfo.UseShellExecute = false;
// *** Redirect the output ***
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.WaitForExit();
// *** Read the streams ***
// Warning: This approach can lead to deadlocks, see Edit #2
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
exitCode = process.ExitCode;
Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" :
output));
Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" :
error));
Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
process.Close();
}
static void Main()
{
ExecuteCommand(#"C:\displayMsg.bat");
}
You may check your domain in Control Panel >> User Account >> Manage User Accounts
Source of reference: source
The problem is the location of the file (msg.exe) in the different OS versions (32bit/64bit)
I suppose it helps How can I execute msg.exe by C# in windows?
Edited:
It works fine -
class Program
{
static void Main(string[] args)
{
int ExitCode;
try
{
var returnedMsgPath = string.Empty;
if (LocateMsgExe(out returnedMsgPath))
{
var startInfo = new ProcessStartInfo()
{
FileName = returnedMsgPath,
Arguments = #"* /v Hello",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true
};
var p = Process.Start(startInfo);
p.WaitForExit();
// *** Read the streams ***
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
ExitCode = p.ExitCode;
MessageBox.Show("output >>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
p.Close();
}
else
{
MessageBox.Show("Not found");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public static bool LocateMsgExe(out string returnedMsgPath)
{
returnedMsgPath = null;
string[] msgPaths = new string[] { Environment.ExpandEnvironmentVariables(#"%windir%\system32\msg.exe"),
Environment.ExpandEnvironmentVariables(#"%windir%\sysnative\msg.exe") };
foreach (string msgPath in msgPaths)
{
if (File.Exists(msgPath))
{
returnedMsgPath = msgPath;
return true;
}
}
return false;
}
}

C# Get Session Processes Without Showing CMD Prompt

Current attempt at WTSEnumerateProcesses:
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern Int32 WTSEnumerateProcesses(
IntPtr serverHandle, // Handle to a terminal server.
Int32 reserved, // must be 0
Int32 version, // must be 1
ref IntPtr ppProcessInfo, // pointer to array of WTS_PROCESS_INFO
ref Int32 pCount // pointer to number of processes
);
public struct WTS_PROCESS_INFO
{
public int SessionID;
public int ProcessID;
// This is spointer to a string...
public IntPtr ProcessName;
public IntPtr userSid;
}
public static void ListProcs(String ServerName)
{
IntPtr serverHandle = IntPtr.Zero;
List<string> resultList = new List<string>();
serverHandle = OpenServer(ServerName);
IntPtr ProcessInfoPtr = IntPtr.Zero;
Int32 processCount = 0;
Int32 retVal = WTSEnumerateProcesses(serverHandle, 0, 1, ref ProcessInfoPtr, ref processCount);
Int32 dataSize = Marshal.SizeOf(typeof(WTS_PROCESS_INFO));
Int32 currentProcess = (int)ProcessInfoPtr;
uint bytes = 0;
if (retVal != 0)
{
WTS_PROCESS_INFO pi = (WTS_PROCESS_INFO)Marshal.PtrToStructure((System.IntPtr)currentProcess, typeof(WTS_PROCESS_INFO));
currentProcess += dataSize;
for (int i = 0; i < processCount; i++)
{
MessageBox.Show(pi.ProcessID.ToString());
}
WTSFreeMemory(ProcessInfoPtr);
}
}
I am obviously missing something pretty crucial here, as my listProcs method just returns the same ID over and over again. I need to read up on C APIs and work out what WTSEnumeratEProcesses is actually doing, and how I can query these processes.
Possible solution example code (top answer)
I am creating a self-help IT app for my organisation, where users have the ability to log off their own session as well as display all active processes and select one to terminate.
Users have no problem logging off, but I am having an issue when enumerating processes. Due to the fact that I am using a log in name and password to query active processes, the CMD window is displayed briefly every time this occurs. I can't find any solution to this in the documentation, and was hoping someone could point me in the right direction.
The code is below:
using System.Drawing;
using System;
using System.ComponentModel;
using System.Security;
using System.Diagnostics;
using System.DirectoryServices;
using System.Collections.Generic;
using System.Windows.Forms;
namespace ITHelp
{
class funcs
{
///////////////////////////////////////////////////// GET SERVERS
public static List<string> get_Servers()
{
// Get servers using AD directory searcher
List<string> serverList = new List<string>();
DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE");
string domainContext = rootDSE.Properties["defaultNamingContext"].Value as string;
DirectoryEntry searchRoot = new DirectoryEntry("LDAP://OU=XA76-2012,OU=Servers,OU=XenApp,dc=MYDOMAINNAME1,dc=co,dc=uk");
using (DirectorySearcher searcher = new DirectorySearcher(
searchRoot,
"(&(objectClass=computer)(!(cn=*MASTER*)))",
new string[] { "cn" },
SearchScope.Subtree))
{
foreach (SearchResult result in searcher.FindAll())
{
foreach (string server in result.Properties["cn"])
{
serverList.Add(server);
}
}
}
return serverList;
}
///////////////////////////////////////////////////// GET SESSION
public static string[] get_Session(List<string> servers, string name)
{
string[] sessionDetails = new string[3];
// Iterate through serverList to find the correct connection - then add this to the sessionDetails array
string current = "";
for (int i = 0; i < servers.Count; i++)
{
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/c QUERY SESSION " + name + " /SERVER:" + servers[i] + ".MYDOMAINNAME1.co.uk ")
{
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process getsess = Process.Start(startInfo);
getsess.OutputDataReceived += (x, y) => current += y.Data;
getsess.BeginOutputReadLine();
getsess.WaitForExit();
if (current.Length != 0)
{
// Session ID
// Better to use this as an identifer than session name, as this is always available
sessionDetails[0] = current.Substring(119, 4);
// Server Name
sessionDetails[1] = servers[i] + ".MYDOMAINNAME1.co.uk";
// Session Name (ica-)
// This is only available if the session is not disconnected
//sessionDetails[2] = current.Substring(76, 11);
// Removed this as it is not used - BUT COULD BE HELPFUL FOR CHECKING SESSION EXISTENCE/DETAILS
break;
}
}
return sessionDetails;
}
///////////////////////////////////////////////////// GET PROCESSES
public static Dictionary<string, string> getProc(string server, string sessID)
{
var ss = new SecureString();
ss.AppendChar('M');
ss.AppendChar('y');
ss.AppendChar('p');
ss.AppendChar('a');
ss.AppendChar('s');
ss.AppendChar('s');
ss.AppendChar('w');
ss.AppendChar('o');
ss.AppendChar('r');
ss.AppendChar('d');
ss.MakeReadOnly();
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/C tasklist /S " + server + " /FI \"SESSION eq " + sessID + "\" /FO CSV /NH")
{
WindowStyle = ProcessWindowStyle.Minimized,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
WorkingDirectory = #"C:\windows\system32",
Verb = "runas",
Domain = "MYDOMAINNAME1",
UserName = "XATest",
Password = ss
};
List<string> procList = new List<string>();
Process proc = Process.Start(startInfo);
proc.OutputDataReceived += (x, y) => procList.Add(y.Data);
proc.BeginOutputReadLine();
proc.WaitForExit();
// Create a new ditionary ...
Dictionary<string, string> procDict = new Dictionary<string, string>();
for (int i = 0; i < procList.Count - 1; i++)
{
if (procDict.ContainsKey(procList[i].Split(',')[0].Trim('"')))
{
// Do nothing
}
else
{
procDict.Add(procList[i].Split(',')[0].Trim('"'), procList[i].Split(',')[1].Trim('"'));
}
}
return procDict;
}
///////////////////////////////////////////////////// RESET SESSION
public static void reset_Session(string sessID, string servName, string name)
{
// Ensure the sesion exists
if (sessID != null)
{
// Log session off
logoff_Session(sessID, servName);
// While isLoggedIn returns true, wait 1 second (checks 50 times)
for (int i = 0; i < 50; i++)
{
if (isLoggedIn(name, servName) == true)
{
System.Threading.Thread.Sleep(1000);
}
else
{
break;
}
}
// Wait here to prevent starting a session while still logged in
System.Threading.Thread.Sleep(3000);
}
// Finally, start the session (Outlook)
start_Session(name);
}
///////////////////////////////////////////////////// LOGOFF SESSION
public static void logoff_Session(string sessID, string servName)
{
Process logoff = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C LOGOFF " + sessID + " /SERVER:" + servName;
logoff.StartInfo = startInfo;
logoff.Start();
}
///////////////////////////////////////////////////// START SESSION
public static void start_Session(string name)
{
// Start Outlook
Process.Start("C:\\Users\\" + name + "\\AppData\\Roaming\\Citrix\\SelfService\\Test_Outlook2013.exe");
}
///////////////////////////////////////////////////// IS LOGGED IN
private static bool isLoggedIn(string name, string server)
{
string current = " ";
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/c QUERY SESSION " + name + " /SERVER:" + server)
{
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process logcheck = Process.Start(startInfo);
logcheck.OutputDataReceived += (x, y) => current += y.Data;
logcheck.BeginOutputReadLine();
logcheck.WaitForExit();
if (current.Contains(userName()))
{
return true;
}
else
{
return false;
}
}
///////////////////////////////////////////////////// USERNAME
public static string userName()
{
// Get userName
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
userName = userName.Remove(0, 8);
return userName;
}
///////////////////////////////////////////////////// KILL PROCESS
public static void killProc(string server, string procid)
{
var ss = new SecureString();
ss.AppendChar('M');
ss.AppendChar('y');
ss.AppendChar('p');
ss.AppendChar('a');
ss.AppendChar('s');
ss.AppendChar('s');
ss.AppendChar('w');
ss.AppendChar('o');
ss.AppendChar('r');
ss.AppendChar('d');
ss.MakeReadOnly();
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/C taskkill /S " + server + " /PID " + procid + " /F")
{
WorkingDirectory = #"C:\windows\system32",
Verb = "runas",
Domain = "MYDOMAINNAME1",
UserName = "XATest",
Password = ss,
WindowStyle = ProcessWindowStyle.Minimized,
UseShellExecute = false,
CreateNoWindow = true
};
Process proc = Process.Start(startInfo);
proc.WaitForExit();
}
///////////////////////////////////////////////////// KILL BUSYLIGHT
public static void killBL()
{
foreach (KeyValuePair<string, string> entry in Program.proclist)
{
if (entry.Key == "Busylight.exe")
{
killProc(Program.servName, entry.Value);
System.Threading.Thread.Sleep(3000);
Process.Start("C:\\Users\\" + Program.name + "\\AppData\\Roaming\\Citrix\\SelfService\\Test_Busylight.exe");
return;
}
// Start BUSYLIGHT - the above method should close the application instantly
}
}
///////////////////////////////////////////////////// KILL LYNC
public static void killLync()
{
foreach (KeyValuePair<string, string> entry in Program.proclist)
{
if (entry.Key == "lync.exe")
{
killProc(Program.servName, entry.Value);
Process.Start("C:\\Users\\" + Program.name + "\\AppData\\Roaming\\Citrix\\SelfService\\Test_SkypeforBusiness.exe");
System.Threading.Thread.Sleep(3000); /////////////////////////////////////////////////////////
return;
}
}
}
///////////////////////////////////////////////////// CHECK RUNNING
public static bool checkRunning(string procName)
{
var ss = new SecureString();
ss.AppendChar('M');
ss.AppendChar('y');
ss.AppendChar('p');
ss.AppendChar('a');
ss.AppendChar('s');
ss.AppendChar('s');
ss.AppendChar('w');
ss.AppendChar('o');
ss.AppendChar('r');
ss.AppendChar('d');
ss.MakeReadOnly();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C tasklist /S " + Program.servName + " /FI \"SESSION eq " + Program.sessID + "\" /FO CSV /NH";
startInfo.WorkingDirectory = #"C:\windows\system32";
startInfo.Verb = "runas";
startInfo.Domain = "MYDOMAINNAME1";
startInfo.UserName = "XATest";
startInfo.Password = ss;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.CreateNoWindow = true;
string strCheck = " ";
Process proc = Process.Start(startInfo);
proc.OutputDataReceived += (x, y) => strCheck += y.Data;
proc.BeginOutputReadLine();
proc.WaitForExit();
if (strCheck.Contains(procName))
{
return true;
}
else
{
return false;
}
}
}
}
Any suggestions or feedback on this much appreciated!
Many thanks
The Remote Desktop Services APIs can certainly do all the things you want. However I'm not sure whether non-admin users are allowed to manipulate their own sessions on other machines.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa383464%28v=vs.85%29.aspx
WTSOpenServer to get a handle to a particular server.
WTSEnumerateProcesses to get a list of processes.
WTSEnumerateSessions to get a list of sessions.
WTSLogoffSession to logoff a specific session.
WTSTerminateProcess to kill a specific process.
Here's some example code using the APIs to enumerate sessions. This is using the constant WTS_CURRENT_SESSION to open the current server, but you can use WTSOpenServer to talk to some other remote server. This is code I hacked out of a live app so it won't compile as-is.
If you program C# long enough you will come across APIs that just don't exist in C# and you have to pinvoke the C versions of the API. I suggest you have a look at http://pinvoke.net if you want help learning how to pinvoke C APIs.
public const int WTS_CURRENT_SESSION = -1;
[StructLayout(LayoutKind.Sequential)]
public struct WTS_SESSION_INFO
{
public Int32 SessionID;
public IntPtr pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}
[DllImport("wtsapi32.dll")]
public static extern bool WTSEnumerateSessions(
IntPtr hServer,
Int32 Reserved,
Int32 Version,
ref IntPtr ppSessionInfo,
ref Int32 pCount);
[DllImport("wtsapi32.dll")]
public static extern void WTSFreeMemory(IntPtr pMemory);
IntPtr pSessions = IntPtr.Zero;
int count = 0;
if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessions, ref count))
{
unsafe
{
WTS_SESSION_INFO* pHead = (WTS_SESSION_INFO*)pSessions.ToPointer();
for (int i = 0; i < count; ++i)
{
WTS_SESSION_INFO* pCurrent = (pHead + i);
var session = new Session(pCurrent->SessionID, pCurrent->State);
_activeSessions[pCurrent->SessionID] = session;
session.Id, session.IsConnected, session.IsLoggedOn, session.User.UserName);
}
}
WTSFreeMemory(pSessions);
}
From MSDN site on ProcessStartInfo.CreateNoWindow Property :
Remarks
If the UseShellExecute property is true or the UserName and Password
properties are not null, the CreateNoWindow property value is ignored
and a new window is created.
There is no workaround or resolution mentioned, and I have been unable to find one anywhere.
I have had to resort to me application briefly displaying CMD windows when running certain processes (The CreateNoWindow property works when not using UserName and Password).
Found another solution to this.
As Donovan mentioned, this can be done using WTSEnumerateProcesses.
However, if someone wanted to list remote processes (for a specific session) without marshalling c++ methods, you could also use qprocess:
qprocess /id:10 /server:servername
This lists all processes running on that session.
For more details see here

How I can execute a exe file with parameter in C# with my User ?

net application that use the process class for execute a exe with parameter. My Problem is that it works a few day good but now I dont can execute this exe with the parameter -.-
If I try it manuell with a terminal than it works but if I do it with C# Code than I get a message that I dont can create the file.
*** ERROR *** Cannot create qrun.inf file
Here is my c# code:
string cmd = Server.MapPath(#"~/exe/lstc_qrun.exe -s server01 -R");
string output = ExecuteCommand(cmd);
//Output = "*** ERROR *** Cannot create qrun.inf file"
here is the ExecuteCommand Method:
public static string ExecuteCommand(string command)
{
int exitCode;
ProcessStartInfo processInfo;
Process process;
try
{
processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
using (process = Process.Start(processInfo))
{
string output = process.StandardOutput.ReadToEnd();
exitCode = process.ExitCode;
return output;
}
}
catch (Exception ex)
{
return "error: " + ex.Message;
}
}
What can I do ..I work on my local machine :(
Check this reference of Process.Start() :
public static Process Start(
string fileName,
string arguments,
string userName,
SecureString password,
string domain
)
or you can just fill the ProcessStartInfo members :
processInfo.Username = 'Username' ;
processInfo.Password = 'Password' ;
processInfo.Domain = 'MyDomain' ;

C# programmatic install of a filter driver?

I'm currently using setup.dll to install a filter driver in a programmatic way.
the following is my code:
protected bool INFSetup(string path_to_inf, bool Install)
{
string exe = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "rundll32.exe");
if (File.Exists(exe) && File.Exists(path_to_inf))
{
try
{
Process proc = new Process();
proc.EnableRaisingEvents = true;
string FileName = exe;
string Arguments = #"SETUPAPI.DLL,InstallHinfSection " + (Install ? "DefaultInstall" : "DefaultUninstall") + " 128 " + path_to_inf;
Debug.Writeline("Executing: '" + FileName + "' with arguments: " + Arguments);
ProcessStartInfo StartInfo = new ProcessStartInfo(FileName, Arguments);
StartInfo.CreateNoWindow = true;
StartInfo.UseShellExecute = false;
proc.StartInfo = StartInfo;
if (proc.Start())
{
if (proc.WaitForExit(10000))
{
return (proc.ExitCode == 0);
}
else
{
Debug.Writeline("INFSetup: proc.WaitForExit() returned false");
}
}
else
{
Debug.Writeline("INFSetup: proc.Start() returned false");
}
}
catch (Exception e)
{
Debug.Writeline("Caught Execption while installing INF: " + e.ToString());
return false;
}
}
return false;
}
although the code works fine, I was wondering if there is a way to do the same with native Win32 calls?
it would be great if anyone has a sample c# code?
Thanks
Henry
As the rundll command line suggests InstallHinfSection is also exported from SETUPAPI.DLL and is thus p/invokable. An MSFT bod posted a p/invoke signature here:
using System.Runtime.InteropServices;
[DllImport("Setupapi.dll", EntryPoint="InstallHinfSection", CallingConvention=CallingConvention.StdCall)]
public static extern void InstallHinfSection(
[In] IntPtr hwnd,
[In] IntPtr ModuleHandle,
[In, MarshalAs(UnmanagedType.LPWStr)] string CmdLineBuffer,
int nCmdShow);
InstallHinfSection(IntPtr.Zero, IntPtr.Zero, "my path", 0);

Run Active Directory shell commands using C#

I am writing a module which will be executing any kind of shell commands related to Active Directory and other shell commands on a particular domain controller.
Some of command are working but some of commands are not working properly.
Here is the code
public static void ExecuteShellCommand(string _FileToExecute, string _CommandLine, ref string _outputMessage, ref string _errorMessage)
{
System.Diagnostics.Process _Process = null;
try
{
_Process = new System.Diagnostics.Process();
string _CMDProcess = string.Format(System.Globalization.CultureInfo.InvariantCulture, #"{0}\cmd.exe", new object[] { Environment.SystemDirectory });
string _Arguments = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", new object[] { _FileToExecute });
_Arguments = string.Format(" /C \"{0}\"", _Arguments);
Console.WriteLine("---aruguments quering : cmd.exe" + _Arguments);
System.Diagnostics.ProcessStartInfo _ProcessStartInfo = new System.Diagnostics.ProcessStartInfo(_CMDProcess, _Arguments);
_ProcessStartInfo.CreateNoWindow = true;
_ProcessStartInfo.UseShellExecute = false;
_ProcessStartInfo.RedirectStandardOutput = true;
_ProcessStartInfo.RedirectStandardInput = true;
_ProcessStartInfo.RedirectStandardError = true;
_Process.StartInfo = _ProcessStartInfo;
//_ProcessStartInfo.Domain = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain().Name;
_Process.Start();
_errorMessage = _Process.StandardError.ReadToEnd();
_Process.WaitForExit();
_outputMessage = _Process.StandardOutput.ReadToEnd();
_Process.WaitForExit();
}
catch (Exception _Exception)
{
Console.WriteLine("Exception caught in process: {0}", _Exception.ToString());
}
finally
{
_Process.Close();
_Process.Dispose();
_Process = null;
}
}
CommandExecutionEngine.ExecuteShellCommand("nltest", "/logon_query /server:india.cobra.net", ref output, ref error);
Console.WriteLine("output for dir : " + output + " error : " + error);
Commands:
repadmin /showrepl
dcdiag
dcdiag /s:<dcname
command nltest executing but not returning any result. Where the other mentioned commands giving error is not recognized as internal or external command. Where if I execute command directly from console its working fine.
Here I am invoking a process under the context of domain administrator account so that I will not be have any permission issues.
Please suggest.
Possibly since UseShellExecute = false, the application location is not being found. Use the full path.

Categories

Resources