Published in Articles on by Michiel van Oosterhout ~ 4 min read

In the previous article we implemented two extensions for Windows Command Processor to add support to cd, chdir, and pushd for ~ to refer to the current user's home directory. These extensions served to illustrate the process of writing an extension, while also adding a somewhat useful feature. In this article we will create two more extensions, this time to improve working with folders on the command line.

rmdir .

The rmdir and rd built-in commands can be used to remove directories. But you can't remove the current directory (e.g. rmdir .), because Windows Command Processor itself has the directory in use:

You can't use the rmdir command to delete the current directory. If you attempt to delete the current directory, the following error message appears:

The process can't access the file because it is being used by another process.

If you receive this error message, you must change to a different directory (not a subdirectory of the current directory), and then try again.

rmdir

Compare this apparent limitation of Windows Command Processor to Windows Explorer, which automatically navigates to the parent directory if the currently opened directory is deleted.

The Windows PowerShell script below installs an extension named RmdirCurrent that adds a similar auto-navigating behavior to Windows Command Processor.

# Declare the filter script contents
$script = @"
@echo off
setlocal enabledelayedexpansion

for /f "delims=; tokens=1,*" %%a in ("%~1") do (
    if "%%~b"=="" (set next=%%~a) else (set next=call %%~a "%%b")
)

set current=false

shift
:loop

if "%~1"=="." (
    set current=true

    for /f "tokens=*" %%d in ('cd') do (
        set dir="%%d"
        set next=%next% !dir!
    )
) else (
    set next=%next% %1
)

shift && if not "%~1"=="" goto loop

endlocal && if %current%==false (%next%) else (
    cd .. && %next% || cd %dir%
)

endlocal
"@

# Ensure the extension's directory exists
$path = "$Env:LOCALAPPDATA\Commando\RmdirCurrent"
$_ = New-Item $path -Force -ItemType Directory

# Create the filter scripts
@("rd", "rmdir") | ForEach-Object {
    Set-Content -Path "$path\$_.filter.cmd" -Value $script
}

The script starts with some code to ensure the next filter (or the actual command in case this filter is the last filter) is executed correctly. This code is standard for all filters.

Then the script set a variable named current to false. When one of the parameters %1 in the loop labeled :loop is equal to ., then current is set to true and dir is set to the value of cd (the current directory).

Then, if current is false, next is executed. But if current is true the script navigates to the parent directory and executes next, which should delete the original directory stored in the dir variable. Should next fail, then the script navigates back to dir.

Removing the current directory on Windows with `rmdir .`
Removing the current directory on Windows with rmdir .

mkdir /g

Quite often you want to create a directory and then navigate to it. This is not too difficult: mkdir test && cd test but you have to type the path to the directory twice. The Windows PowerShell script below installs an extension named MkdirGo to make this easier.

# Declare the filter script contents
$script = @"
@echo off
setlocal enabledelayedexpansion

for /f "delims=; tokens=1,*" %%a in ("%~1") do (
    if "%%~b"=="" (set next=%%~a) else (set next=call %%~a "%%b")
)

set go=false

shift
:loop

if "%~1"=="/g" (
    set go=true
) else (
    if not "%~1"=="/?" if not "%~1"=="" (
        set dir="%~1"
    )
    set next=%next% %1
)

shift && if not "%~1"=="" goto loop

endlocal && %next% && if %go%==true cd %dir%

endlocal
"@

# Ensure the extension's directory exists
$path = "$Env:LOCALAPPDATA\Commando\MkdirGo"
$_ = New-Item $path -Force -ItemType Directory

# Create the filter scripts
@("mkdir") | ForEach-Object {
    Set-Content -Path "$path\$_.filter.cmd" -Value $script
}

The filter starts with the standard code to setup next. Then a loop processes all parameters and sets go to true if the parameter /g was present, and does not propagate that parameter. Other parameters are propagated, and the variable dir is set to the value of the [<drive>:]<path> parameter.

Then, if go is false, next is executed. But if go is true the script executes next and navigates to newly created directory.

Using `mkdir /g` to create a new directory and navigate to it on Windows
Using mkdir /g to create a new directory and navigate to it on Windows

Summary

Our extension system for Windows Command Processor can be used to create filters for existing commands. The filters can accept additional parameters and use them to change the apparent behavior of the filtered command. As long as the scope of a filter is limited to do only a single thing, the code can be kept relatively simple.