Reputation: 14735
Currently we want to cover these 3 cases when retrieving file information:
To cover these 3 cases we created the following function:
Function Get-FilePathItemHC {
Param (
[Parameter(Mandatory)]
[String]$Path
)
$Params = @(
@{
# Path relative to the script root
LiteralPath = Join-Path -Path $PSScriptRoot -ChildPath $Path
}
@{
# Literal or path relative to the present work directory
Path = $Path
}
)
$Item = $null
foreach ($P in $Params) {
if ($Item = Get-Item @P -ErrorAction Ignore) {
$Item
Break
}
}
if (-not $Item) {
throw "Cannot find path '$Path' because it does not exist."
}
}
Is this the right way of doing it? It seems like we're reinventing the wheel here.
Upvotes: 0
Views: 585
Reputation: 21468
Make your -Path
Parameter a System.IO.FileInfo
object, and just pass in a relative path as the parameter. The file object will resolve with either a relative or full path, then you can use $path.FullName
to reference the full path to the file.
Function Get-FilePathItemHC {
Param (
[Parameter(Mandatory)]
[ValidateScript({ $_.Exists })]
[System.IO.FileInfo]$Path
)
# The ValidateScript attribute makes sure the file you passed in exists
# so your validation code no longer is required
}
If you want to handle both directories and files, you would want to have two separate variables in this case as directory paths would become a System.IO.DirectoryInfo
object, but you can make the arguments mutually exclusive:
Function Get-FilePathItemHC {
Param (
[Parameter(Mandatory=$true, ParameterSetName="FilePath")]
[ValidateScript({ $_.Exists })]
[System.IO.FileInfo]$FilePath,
[Parameter(Mandatory=$true, ParameterSetName="DirectoryPath")]
[ValidateScript({ $_.Exists })]
[System.IO.DirectoryInfo]$DirectoryPath
)
$Path = $FilePath
if( $DirectoryPath ) {
$Path = $DirectoryPath
}
# The ValidateScript attribute makes sure the file you passed in exists
# so your validation code no longer is required
}
Get-FilePathItemHC -Path .\path\to\file.txt
$PSScriptRoot
I'm not sure why you need the path relative to $PSScriptRoot
if you already have the full path to the file, but after getting the System.IO.FileInfo
or System.IO.DirectoryInfo
object, you can use Resolve-Path
from $PSScriptRoot
to get the relative path from that directory:
$file = Get-FilePathItemHC -Path .\path\to\file.txt
Push-Location $PSScriptRoot
$relativeFromScriptRootPath = Resolve-Path -Relative $file
Pop-Location
Push-Location
and Pop-Location
treat the location as a stack. The push
operation sets a new location and adds it to the stack, and the pop
operation removes the last added location from the stack and places you at the next most recent location. Works a bit like cd -
on Linux if you're familiar.
Resolve-Path
will return a file path, and the -Relative
switch will return a path relative to your current directory. You cannot pass in an alternate directory to resolve from, which is why we change the location to run this.
Upvotes: 1