Get the current working directory for cmd.exe

30,235

Solution 1

Untested, a possible approach:

Create a DLL with a DllMain that uses GetThreadStartInformation() to find the address of the buffer, and then uses GetCurrentDirectory to populate it. This should be OK, because both of those functions are in kernel32, which is always present. You will need to have some structure there to return success/failure.

  1. Get a handle to the cmd.exe process.
  2. Allocate some memory there (VirtualAllocEx)
  3. Put the path to your DLL in the memory. (WriteProcessMemory)
  4. Load your dll into the cmd.exe address space. (CreateRemoteThread with an entry point of LoadLibrary, the argument is the memory you allocated earlier.)
  5. WaitForSingleObject followed by GetExitCodeThread(), gives you the HMODULE of your DLL in the cmd.exe process.
  6. ReadProcessMemory to get the current directory.
  7. Unload your dll from the cmd.exe address space. CreateRemote Thread with an entry point of FreeLibrary, the argument is the HMODULE.
  8. WaitForSingleObject to wait for the DLL to unload.

Broad sketch: Details left as an excercise! Risks: Allocates memory in the cmd.exe address space, changes its state. Care must be taken with the functions called in DllMain.

Solution 2

Do you mean the %CD% variable in a batch file ?

Like this:

set OLDDIR=%CD%
.. do stuff ..
chdir /d %OLDDIR% &rem restore current directory

Try echo %CD% in a command prompt. :)

Well as this is what you need, there here is a PowerShell function to do it:

$(get-location)

Hope this helps.

I found it all from here.

Solution 3

Maybe this forum entry on the Sysinternals Forum contains a hint to the solution. Look for this in the GetProcessStrings function:

// Get Command Line Block

// At offset 0x00020498 is the process current directory followed by

// the system PATH. After that is the process full command line, followed

// by the exe name and the windows station it's running on.

This CodeProject article "Read Environment Strings of Remote process" could be useful too.

Solution 4

UPDATE: This is not the solution, see the comments to this answer: "As Janm said .Modules[0].FileName (or MainModuile.FileName) gives the location of the executable running in that process. I'm looking to find the current working directory (that can be changed using the CD or CHDIR commands)."

You could use System.Diagnostics Namespace. Here an example as C# console application. From the filename you can easily extract the Path information (System.IO.Path...).

You would make sure to have the permissions (run as admin) to do this.

Hope this helps. Here is the working code (tested):

using System;
using System.Diagnostics;
using System.IO;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Process[] procList =  Process.GetProcessesByName("cmd");

            string sFileName;

            for (int i = 0; i < procList.Length; i++ )
            {
                Console.Write(procList[i].Id);
                Console.Write(" ");

                try
                {
                    sFileName = procList[i].Modules[0].FileName;
                    Console.Write("(");
                    Console.Write(Path.GetFileName(sFileName));
                    Console.Write("): ");
                    Console.WriteLine(Path.GetDirectoryName(sFileName));
                }
                catch (Exception ex)
                {
                    // catch "Access denied" etc.
                    Console.WriteLine(ex.Message);
                }


            }

        }
    }
}

Here the the output on my machine (I've opened four command lines):

alt text http://img236.imageshack.us/img236/3547/processworkingdirvn4.png

Share:
30,235
Ash
Author by

Ash

"nosce te ipsum"

Updated on August 14, 2020

Comments

  • Ash
    Ash almost 4 years

    How can I retrieve the current working directory of cmd.exe?

    This seems possible. For example using ProcessExplorer, select CMD.exe, right click, properties, Image tab, "Current Directory" relects the directory set using the CD or CHDIR commands.

    I've looked at the .NET Process and ProcessStartInfo classes (ProcessStartInfo.WorkingDirectory always returns "") and can't seem to find a way of determining this. Nothing at PInvoke stands out either.

    As an example I'm looking to programmatically be able to say something like: Process.GetCurrentWorkingDirectory(processID) where processID is a Windows process ID of another running process.

    Is there any solution, WinAPI or .NET?

    [Update]

    Reason for asking this question:

    I've used the "Command Prompt Explorer Bar" for a while and it's great except if I "CD" to a new directory, the current Explorer window does not also change. (ie the Sync is only 1 way from Explorer to the commmand prompt). I'm looking to make this 2 way.

  • Ash
    Ash over 15 years
    I'm looking to programmatically be able to say something like: Process.GetCurrentWorkingDirectory(processID) where processID is a windows process ID.
  • janm
    janm over 15 years
    That doesn't work! That gives the directory of the module, not the current directory of the process. In your test, one of the lines should have been C:\Users\stefan.
  • Ash
    Ash over 15 years
    Thanks, I'll look into GetProcessStrings. I thought it could be something to do with that.
  • Ash
    Ash over 15 years
    Thanks for the detailed response. It does appear a bit more complex than say looking at GetProcessStrings(), but I might give it a go if that does not work out.
  • Ash
    Ash over 15 years
    As Janm said .Modules[0].FileName (or MainModuile.FileName) gives the location of the executable running in that process. I'm looking to find the current working directory (that can be changed using the CD or CHDIR commands).
  • splattne
    splattne over 15 years
    D'oh! That happens, if you research and then forget the core question. I apologize...
  • janm
    janm over 15 years
    No problem. The GetProcessStrings approach might work in the cmd.exe special case, but I'm not sure. See my comments above. My approach will work with processes that don't modify environment variables are they change directories.
  • janm
    janm over 15 years
    Possible issues with this approach: 1. Races between reading the target process's env and the target process modifying it. 2. Magic numbers change between releases of Windows. 3. %CD% seems to be special in cmd.exe and might not be an envvar. eg. Try "set CD=blah"; it stops changing on cd.
  • Christian.K
    Christian.K over 15 years
    Basically, you shouldn't do anything in DllMain() except for TlsAlloc() maybe, because of the "loader lock". Just google for "loader lock dllmain" for plenty of reasons why it is a bad idea.
  • janm
    janm over 15 years
    Note my comment: "This should be OK, because both of those functions are in kernel32 ..." You must be careful not to trigger a DLL load otherwise you will have problems with the loader lock. You are very constrained, but that doesn't mean you are restricted to nothing by TlsAlloc.