Windows Vista Forums

Current Directories for External Executables

  1. #1


    William C. McCain Guest

    Current Directories for External Executables

    I recently noticed that PowerShell does not set up quite the same "execution
    environment" for external executables as would normally be expected (that is,
    as one is accustomed to from CMD.EXE). Specifically, the external executable
    "sees" the current directory (as set by "Set-Location", or its alias "cd")
    for the current drive only. For all other drives, the external executable
    "sees" the root, rather than the actual current directory that has been set
    in PowerShell.

    For example, suppose that "cd c:\abc" and "cd d:\xyz" have been issued and
    the current drive is the "C:" drive. If you issue the external command:

    comp c: d:

    .... you would expect it will compare the "c:\abc" folder with the "d:\xyz"
    folder ... and in a CMD.EXE shell, that is what happens. But under
    PowerShell, it compares the "c:\abc" folder with "d:\". If you then make the
    "D:" drive your current drive, in PowerShell, and issue the same command, it
    will compare "c:\" with "d:\xyz".

    The same thing happens in batch files run under PowerShell, because the
    child instance of CMD.EXE that runs that batch file "sees" the current
    PowerShell directory on the current drive only.

    One can easily compensate for this peculiarity. Just remember, when running
    external executables, to always specify the fully-qualified path for any
    drives other than the current drive. For example, when the current drive is
    the "C:" drive:

    comp c: d:\xyz



    But such a workaround is unnecessary when running PowerShell cmdlets, and
    PowerShell scripts that do not call external executables.

    Bill
    Palo Alto, California

      My System SpecsSystem Spec

  2. #2


    William C. McCain Guest

    RE: Current Directories for External Executables

    After discussing this issue with one of my regular correspondents, I have
    come to the conclusion that it is "not a bug" — although it is a bit
    surprising, given that it differs significantly from what happens when
    running external executables under CMD.EXE. And it also differs from what
    happens when running cmdlets and "cmdlet scripts" under PowerShell.

    According to my correspondent, PowerShell handles external executables by
    using the "CreateProcess" API, invoking them much like a "Windows shortcut"
    would (except that it creates a child process of PowerShell). When calling
    the "CreateProcess" API, PowerShell passes the current drive and its current
    directory, as the "working directory", via the lpCurrentDirectory field in
    the "CreateProcess" control block. That is all that is available!

    (In other words, the "CreateProcess" API does not provide for passing in a
    whole ARRAY of "current directories", one for each drive.)

    Thus, for PowerShell to do OTHERWISE would require building a whole
    CMD.EXE-like environment for each invoked external executable, and they
    obviously have good reasons for not doing THAT.

    Bill
    Palo Alto, California

      My System SpecsSystem Spec

  3. #3


    William C. McCain Guest

    RE: Current Directories for External Executables

    There is a "workaround" for this issue. It involves writing a PowerShell
    script for each external executable that needs "current directory support on
    multiple drives". In the script, "Resolve-Path" is used to provide the
    "missing" current directory information.

    This turned out to be a bit more challenging than just sticking something
    like "Resolve-Path $parm" in the script. The main obstacle is that you only
    want to apply "Resolve-Path" to the drive letter/colon portion, and then only
    when it is not followed by a "\". That is because you want the target
    executable to handle its own wildcard expansion — you can't be passing it an
    array of filenames!

    So here is a script for "comp.exe" that actually "does the job":

    param ([string]$source = $($missing_source = $true),
    [string]$dest = $($missing_dest = $true))
    function apply_cd ([string]$s)
    {
    if ($s.Length -lt 2 -or $s.get_Chars(1) -ne ':' `
    -or ($s.Length -gt 2 -and $s.get_Chars(2) -eq '\'))
    {
    return $s
    }
    [char]$c = $s.ToUpperInvariant().get_Chars(0)
    if ($c -lt 'A' -or $c -gt 'Z')
    {
    return $s
    }
    [string]$x = (Resolve-Path $s.Substring(0, 2)).ToString()
    if ($s.Length -gt 2)
    {
    $x += '\' + $s.Substring(2)
    }
    return $x
    }
    if ($missing_source)
    {
    Write-Host "Missing first argument (source)." -f red
    return
    }
    if ($missing_dest)
    {
    Write-Host "Missing second argument (destination)." -f red
    return
    }
    $source = apply_cd($source)
    $dest = apply_cd($dest)
    return (comp.exe $source $dest)

    I saved this script as "compcd.ps1" in a folder in my executable path, and
    then in my PowerShell profile, I defined "comp" as an alias for "compcd.ps1".
    Now I am "back in business with a "comp" command that works the way I
    expected it to work!

    Bill
    Palo Alto, California

      My System SpecsSystem Spec

  4. #4


    William C. McCain Guest

    RE: Current Directories for External Executables

    There was an error in the "compcd.ps1" script that I posted here, earlier in
    this thread. It did not handle the case in which the current directory on a
    drive is, in fact, the root. Consequently, something like "d:abc" could get
    incorrectly expanded as "d:\\abc". Here is the corrected script:

    param ([string]$source = $($missing_source = $true),
    [string]$dest = $($missing_dest = $true))
    function apply_cd ([string]$s)
    {
    if ($s.Length -lt 2 -or $s.get_Chars(1) -ne ':' `
    -or ($s.Length -gt 2 -and $s.get_Chars(2) -eq '\'))
    {
    return $s
    }
    [char]$c = $s.ToUpperInvariant().get_Chars(0)
    if ($c -lt 'A' -or $c -gt 'Z')
    {
    return $s
    }
    [string]$x = (Resolve-Path $s.Substring(0, 2)).ToString()
    if ($s.Length -gt 2)
    {
    if ($x.get_Chars($x.Length - 1) -ne '\')
    {
    $x += "\"
    }
    $x += $s.Substring(2)
    }
    return $x
    }
    if ($missing_source)
    {
    Write-Host "Missing first argument (source)." -f red
    return
    }
    if ($missing_dest)
    {
    Write-Host "Missing second argument (destination)." -f red
    return
    }
    $source = apply_cd($source)
    $dest = apply_cd($dest)
    return (comp.exe $source $dest)

    Bill
    Palo Alto, California

      My System SpecsSystem Spec

Current Directories for External Executables

Similar Threads
Thread Thread Starter Forum Replies Last Post
Executables Not Recognized Sammich Software 2 02 Oct 2011
Programs and executables vanishing Xanadwayne General Discussion 5 14 Jun 2009
powershell and calling external executables Sam Leibowitz PowerShell 5 02 Sep 2007
OperationContext.Current or HttpContext.Current in MembershipProvider within WCF Service = null? dgilbert@cragmonttech.com Indigo 4 18 May 2007
Downloading third party executables =?Utf-8?B?VmlzdGEgaW4gVGFtcGE=?= Vista installation & setup 0 15 Jul 2006