Stefan Hattrell
Stefan Hattrell

Reputation: 510

Check if a path is a folder or a file in PowerShell

I'm trying to write a PowerShell script which goes through a list of values which are folder or file paths, and delete the files first, then remove the empty folders.

My script so far:

[xml]$XmlDocument = Get-Content -Path h:\List_Files.resp.xml
$Files =  XmlDocument.OUTPUT.databrowse_BrowseResponse.browseResult.dataResultSet.Path

Now I'm trying to test each line in the variable to see if it's a file and delete it first, and then go through and remove subfolders and folders. This is just so that it's a clean process.

I can't quite get this next bit to work, but I think I need something like:

foreach ($file in $Files)
{
    if (! $_.PSIsContainer)
    {
        Remove-Item $_.FullName}
    }
}

The next section can clean up the subfolders and folders.

Any suggestions?

Upvotes: 49

Views: 69372

Answers (6)

Vladimir1211
Vladimir1211

Reputation: 1

Yet another way is by using Get-ItemProperty:

$PathObject = (Get-ItemProperty 'C:\somefolder')
if ($PathObject.Attributes -like '*Directory*') {
    write-host 'It''s a directory'
} else {
    write-host 'It''s a file'
}

Upvotes: 0

Alicia
Alicia

Reputation: 884

I found a workaround for this question: use Test-Path cmdlet with the parameter -PathType equal to Leaf for checking if it is a file or Container for checking if it is a folder:

# Check if file (works with files with and without extension)
Test-Path -Path 'C:\Demo\FileWithExtension.txt' -PathType Leaf
Test-Path -Path 'C:\Demo\FileWithoutExtension' -PathType Leaf
 
# Check if folder
Test-Path -Path 'C:\Demo' -PathType Container

Demo

I originally found the solution here. And the official reference is here.

Upvotes: 58

c z
c z

Reputation: 9045

Yet another way is by using DirectoryInfo.

MWE from the file-name:

$(Get-Item c:\windows\system32) -is [System.IO.DirectoryInfo]

Upvotes: 3

Muhammad Murad Haider
Muhammad Murad Haider

Reputation: 1487

We can use get-item command and supply the path. Then you can check PSIsContainer (boolean) property that would determine whether the supplied path targets a folder or a file. e.g.

$target = get-item "C:\somefolder" # or "C:\somefolder\somefile.txt"
if($target.PSIsContainer) {
# it's a folder
}
else { #its a file }

Hope this helps any future visitors.

Upvotes: 19

Peter Hahndorf
Peter Hahndorf

Reputation: 11222

Consider the following code:

$Files = Get-ChildItem -Path $env:Temp

foreach ($file in $Files)
{
    $_.FullName
}

$Files | ForEach {
    $_.FullName
}

The first foreach is a PowerShell language command for looping, and the second ForEach is an alias for the ForEach-Object cmdlet which is something completely different.

In the ForEach-Object, the $_ points to the current object in the loop, as piped in from the $Files collection, but in the first foreach, $_ has no meaning.

In the foreach loop use the loop variable $file:

foreach ($file in $Files)
{
    $file.FullName
}

Upvotes: 4

JosefZ
JosefZ

Reputation: 30248

I think that your $Files object is an array of strings:

PS D:\PShell> $Files | ForEach-Object {"{0} {1}" -f $_.Gettype(), $_}
System.String D:\PShell\SO
System.String D:\PShell\SU
System.String D:\PShell\test with spaces
System.String D:\PShell\tests
System.String D:\PShell\addF7.ps1
System.String D:\PShell\cliparser.ps1

Unfortunately, the PSIsContainer property cannot be found on a string object but on a filesystem object, e.g.

PS D:\PShell> Get-ChildItem | ForEach-Object {"{0} {1}" -f $_.Gettype(), $_}
System.IO.DirectoryInfo SO
System.IO.DirectoryInfo SU
System.IO.DirectoryInfo test with spaces
System.IO.DirectoryInfo tests
System.IO.FileInfo addF7.ps1
System.IO.FileInfo cliparser.ps1

To get a filesystem object from a string:

PS D:\PShell> $Files | ForEach-Object {"{0} {1}" -f (Get-Item $_).Gettype(), $_}
System.IO.DirectoryInfo D:\PShell\SO
System.IO.DirectoryInfo D:\PShell\SU
System.IO.DirectoryInfo D:\PShell\test with spaces
System.IO.DirectoryInfo D:\PShell\tests
System.IO.FileInfo D:\PShell\addF7.ps1
System.IO.FileInfo D:\PShell\cliparser.ps1

Try next code snippet:

$Files | ForEach-Object 
  {
    $file = Get-Item $_               ### string to a filesystem object
    if ( -not $file.PSIsContainer)
        {
            Remove-Item $file}
        }
  }

Upvotes: 6

Related Questions