Powershell Remove-Item and symbolic links

Let’s say you’ve got a symbolic link which points to another folder and you want to delete the symbolic link through Powershell. Prepare for some weird stuff! Consider the following test script:

New-Item "SymbolicTest" -Type Directory
Set-Location "SymbolicTest"
New-Item "Source" -Type Directory
Set-Location "Source"
New-Item "Test1.txt"  -Type File
New-Item "Test2.txt"  -Type File
New-Item "Test3.txt"  -Type File
Set-Location "../"
# now some cmd since Powershell can't natively create symbolic links
cmd /c mklink /J `"Target`" `"Source`" 
ls

Let’s check the structure: dir in powershell Okay, so no difference, both are considered directories. Now let’s check with cmd: dir in cmd Okay, weird, cmd understands it. Now let’s try to remove the Target link. Remember, we only want to delete the link, not the contents of the Target folder (and thus implicitly not the contents of the Source folder). With Remove-Item you can delete items. Let’s try it out:

Remove-Item .\Target

This yields the following output:

deletion powershell

Wait what? Deletion of the children. Just for the sake of it I typed Y. This yielded another error: deletion powershell force prompt Okay, again, with -Force powershell content gone Target was gone, however also the contents of Source. Auch? Now what? Well, reading through the documentation of Remove-Item I found nothing about symbolic links.

So what now? Seems that Powershell doesn’t have knowledge about symbolic links. It wasn’t taken into account. He just follows the link like it’s a normal directory.

So what’s the solution? I decided to use the good old cmd (from Powershell!):

cmd /c rmdir .\Target

rmdir works!

Marvelous. Problem solved!

Actually, in retrospect, since I needed to use cmd to create the link, it would have made more sense to also just delete the link with cmd!

Have a good one,

-Kristof

Powershell: switch is not boolean

I spent a lot of time on this, mostly because of the lack of documentation on Powershell, I wonder why there isn’t one like for C#.

Anyway, back to the title, 2 different words, their behavior in a function is the same, but the invocation is not. Let me show you:

function MyAwesomeFunction
{
    param
    (
        [string] $foo,
        [string] $bar,
        [switch] $someVariable 
    )

    Write-Host "someVariable = $someVariable"

    if($someVariable)
    {
        Write-Host $foo
    }
    else
    {
        Write-Host $bar
    }
}

MyAwesomeFunction -foo "Foo" -Bar "Bar" 

Invocation of this script yields the following result:

PS D:\Personal\Desktop> D:\Personal\Desktop\test.ps1
someVariable = False
Bar

Now if we change the ‘switch’ on line 7 to ‘bool’:

function MyAwesomeFunction
{
    param
    (
        [string] $foo,
        [string] $bar,
        [bool] $someVariable #or boolean
    )

    Write-Host "someVariable = $someVariable"

    if($someVariable)
    {
        Write-Host $foo
    }
    else
    {
        Write-Host $bar
    }
}

MyAwesomeFunction -foo "Foo" -Bar "Bar" 

The result is the following

PS D:\Personal\Desktop> D:\Personal\Desktop\test.ps1
someVariable = False
Bar

Right, the same. Both times the variable ‘someVariable’ is False.

However, when we want to set the variable ‘someVariable’, then the invocation differs. If we invoke it like this on the bool version:

MyAwesomeFunction -foo "Foo" -Bar "Bar" -someVariable $true

That works fine.

If we invoke that one on the switch version, we are presented with the following error:

Positional argument error

So I would suggest that you use the bool version for internal functions in modules, ones that when you can explicitly set the someVariable to true or false, whereas the switch version is more useful of external use when you’re invoking a module and want to print more messages (like -Verbose), no need to print -Verbose $true.

Have a good one,

-Kristof