1

What I'm trying to do

  • Launch PSExec to open CMD on a remote computer passing "Net Use * \Server\Share" command
  • Launch PSExec again and remove the share i just created.

I can't seem to figure out how to get the drive letter that the wild card used.

Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = @"\\Server\PStools\PSExec.exe";
p.StartInfo.Arguments = @"\\ComputerName -e -s cmd.exe ""/C Net USE * \\Server\Share /Persistent:NO""";            
p.Start();            
HiTech
  • 913
  • 1
  • 16
  • 34

1 Answers1

1

The net use command with a wildcard will pick the first available drive letter in the sequence from Z to A. It reports the selected drive letter in the console output like so:

C:\>net use * \\server\share
Drive Z: is now connected to \\server\share.

The command completed successfully.


C:\>_

So what you need is to capture the output of the PSExec command and parse it to find the allocated drive letter.

I haven't tried this with PSExec as yet, but this is the code I use for capturing the output of commands via cmd.exe:

static class CommandRunner
{
    static StringBuilder cmdOutput = new StringBuilder();

    public static string Run(string command)
    {
        if (string.IsNullOrWhiteSpace(command))
            return null;

        using (var proc = new Process())
        {
            proc.StartInfo.FileName = "cmd.exe";
            proc.StartInfo.Arguments = "/c " + command;

            proc.StartInfo.LoadUserProfile = false;
            proc.StartInfo.CreateNoWindow = true;

            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.RedirectStandardError = true;
            proc.StartInfo.UseShellExecute = false;
            proc.EnableRaisingEvents = true;

            proc.OutputDataReceived += proc_DataReceived;
            proc.ErrorDataReceived += proc_DataReceived;

            try
            {
                proc.Start();
                proc.BeginErrorReadLine();
                proc.BeginOutputReadLine();
                proc.WaitForExit();
            }
            catch (Exception e)
            {
                cmdOutput.AppendLine("***Exception during command exection***");
                cmdOutput.AppendLine(e.Message);
                cmdOutput.AppendLine("*** ***");
            }
        }

        return cmdOutput.ToString();
    }

    static void proc_DataReceived(object sender, DataReceivedEventArgs e)
    {
        if (e.Data != null)
            cmdOutput.AppendLine(e.Data);
    }
}

To get the output of a command on the local machine call it like this:

string output = CommandRunner.Run("net use");

Shouldn't be too hard to add a method that executes commands on a remote PC using PSExec instead of the local cmd.exe. Something similar to the following:

    public static string Remote(string target, string command, string peFlags = "-e -s")
    {
        if (string.IsNullOrWhiteSpace(command))
            return null;

        using (var proc = new Process())
        {
            proc.StartInfo.FileName = @"C:\PSTools\PSExec.exe";
            proc.StartInfo.Arguments = string.Format(@"\\{0}{1} cmd.exe ""/c {2}""", target, peFlags == null ? "" : " " + peFlags, command);

            proc.StartInfo.LoadUserProfile = false;
            proc.StartInfo.CreateNoWindow = true;

            proc.StartInfo.RedirectStandardOutput = true;
            proc.StartInfo.UseShellExecute = false;
            proc.EnableRaisingEvents = true;

            proc.OutputDataReceived += proc_DataReceived;

            try
            {
                proc.Start();
                proc.BeginOutputReadLine();
                proc.WaitForExit();
            }
            catch 
            { }
        }

        return cmdOutput.ToString();
    }

NOTE: I removed the stderr redirection here because I want only the output of the remote program, not the various lines added to the output by PSExec.

Corey
  • 15,524
  • 2
  • 35
  • 68