Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I check if a file is under a given directory, in PowerShell?

I want to check if a file path is in a given directory (or one of its subdirectories), from PowerShell.

Right now I'm doing:

$file.StartsWith(  $directory, [StringComparison]::InvariantCultureIgnoreCase )

but I'm sure there are better ways.

I could do take $file.Directory and iterate over all .Parents, but I was hoping for something simpler.

EDIT: the file may not exist; I'm just looking at the path.

like image 805
Jay Bazuzi Avatar asked Jun 22 '09 21:06

Jay Bazuzi


People also ask

How do you check if a file exists in a directory in PowerShell?

Test-Path cmdlet is used to check existence of a file.

How do I search for a file in a directory in PowerShell?

To search the content in the file in PowerShell, you need to first get the content from the file using Get-Content command and then you need to add Select-String pipeline command. In the below example, we need to search the lines which contain the Get word. You can use multiple patterns to search for the result.

How do I get a list of files in a directory and subfolders in PowerShell?

If you want to list files and directories of a specific directory, utilize the “-Path” parameter in the “Get-ChildItem” command. This option will help PowerShell list all the child items of the specified directory. The “-Path” parameter is also utilized to set the paths of one or more locations of files.

How do you check if a file does not exist in PowerShell?

Using Test-Path. The first way is the Test-Path cmdlet, specifically designed to determine whether a path or file exists. When using this cmdlet to test whether a file exists, the result is true or false. The result indicates whether the file exists or not.


2 Answers

How about something as simple as:

PS> gci . -r foo.txt

This implicitly uses the -filter parameter (by position) specifying foo.txt as the filter. You could also specify *.txt or foo?.txt. The problem with StartsWith is that while you handle the case-insensitive compare there is still the issue that both / and \ are valid path separators in PowerShell.

Assuming the file may not exist and both $file and $directory are absolute paths, you can do this the "PowerShell" way:

(Split-Path $file -Parent) -replace '/','\' -eq (Get-Item $directory).FullName

But that isn't great since you still have to canonical the path / -> \ but at least the PowerShell string compare is case-insensitive. Another option is to use IO.Path to canonicalize the path e.g.:

[io.path]::GetDirectoryName($file) -eq [io.path]::GetFullPath($directory)

One issue with this is that GetFullPath will also make a relative path an absolute path based on the process's current dir which more times than not, is not the same as PowerShell's current dir. So just make sure $directory is an absolute path even if you have to specify it like "$pwd\$directory".

like image 74
Keith Hill Avatar answered Oct 01 '22 08:10

Keith Hill


Since the path might not exist, using string.StartsWith is fine for doing this type of test (though OrdinalIgnoreCase is a better representation of how the file system compares paths).

The only caveat is that the paths need to be in a canonical form. Otherwise, paths like C:\x\..\a\b.txt and C:/a/b.txt would fail the "is this under the C:\a\ directory" test. You can use the static Path.GetFullPath method to get the full names of the paths before you do the test:

function Test-SubPath( [string]$directory, [string]$subpath ) {
  $dPath = [IO.Path]::GetFullPath( $directory )
  $sPath = [IO.Path]::GetFullPath( $subpath )
  return $sPath.StartsWith( $dPath, [StringComparison]::OrdinalIgnoreCase )
}

Also note that this does not cover logical containment (e.g. if you have \\some\network\path\ mapped to Z:\path\, testing whether \\some\network\path\b.txt is under Z:\ will fail, even though the file can be accessed through Z:\path\b.txt). If you need to support this behavior, these questions might help.

like image 30
Emperor XLII Avatar answered Oct 01 '22 09:10

Emperor XLII