如何在PowerShell中获取具有正确(规范)案例的路径?

时间:2011-08-25 18:24:10

标签: powershell

我有一个脚本,它接受一个目录作为用户的参数。我想显示在Windows中显示的目录路径的名称。即,

PS C:\SomeDirectory> cd .\anotherdirectory
PS C:\AnotherDirectory> . .\myscript.ps1 "c:\somedirectory"
C:\SomeDirectory

如果给出“c:\ somedirectory”,如何检索“C:\ SomeDirectory”?

4 个答案:

答案 0 :(得分:6)

这应该有效:

function Get-PathCanonicalCase {
    param($path)

    $newPath = (Resolve-Path $path).Path
    $parent = Split-Path $newPath

    if($parent) {
        $leaf = Split-Path $newPath -Leaf

        (Get-ChildItem $parent| Where-Object{$_.Name -eq $leaf}).FullName
    } else {
        (Get-PSDrive ($newPath -split ':')[0]).Root
    }
}

答案 1 :(得分:6)

接受的答案只能获得正确的文件大小写。父路径留有用户提供的案例。这是我的解决方案。

$getPathNameSignature = @'
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern uint GetLongPathName(
    string shortPath, 
    StringBuilder sb, 
    int bufferSize);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
public static extern uint GetShortPathName(
   string longPath,
   StringBuilder shortPath,
   uint bufferSize);
'@
$getPathNameType = Add-Type -MemberDefinition $getPathNameSignature -Name GetPathNameType -UsingNamespace System.Text -PassThru


function Get-PathCanonicalCase
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        # Gets the real case of a path
        $Path
    )

    if( -not (Test-Path $Path) )
    {
        Write-Error "Path '$Path' doesn't exist."
        return
    }

    $shortBuffer = New-Object Text.StringBuilder ($Path.Length * 2)
    [void] $getPathNameType::GetShortPathName( $Path, $shortBuffer, $shortBuffer.Capacity )

    $longBuffer = New-Object Text.StringBuilder ($Path.Length * 2)
    [void] $getPathNameType::GetLongPathName( $shortBuffer.ToString(), $longBuffer, $longBuffer.Capacity )

    return $longBuffer.ToString()
}

我已将上述代码集成到Resolve-PathCase Carbon PowerShell模块的一部分中。 免责声明:我是Carbon的所有者/维护者。

答案 2 :(得分:1)

使用Christian的GetDirectories建议,这是另一个不太复杂的解决方案:

function Get-PathCanonicalCase
{
    param( $path )

    $newPath = (Resolve-Path $path).Path
    $root = [System.IO.Path]::GetPathRoot( $newPath )
    if ( $newPath -ne $root ) # Handle case where changing to root directory
        { $newPath = [System.IO.Directory]::GetDirectories( $root, $newPath.Substring( $root.Length ) )[ 0 ] }
    $newPath
}

编辑:感谢您的帮助。

顺便说一句,我想要的只是在一个小的实用程序脚本中使用,覆盖默认的cd别名,允许我指定一些搜索的“根”目录,如果相对于当前目录的路径不存在的话。也就是说,无论我当前的位置如何,它都允许我cd Documentscd trunkcd Release-10.4。在我输入的情况下,而不是实际情况,我很高兴得到提示。

# Usage: 
# Set up in $profile - define the functions and reassign 'cd'.  Example:
# -----
#  . .\Set-LocationEx.ps1 "c:\dev\Code", "c:\dev\Code\releases", "$HOME" -Verbose
# if (test-path alias:cd) { remove-item alias:cd > $null }
# Set-Alias cd Set-LocationEx
# -----

param( [parameter(Mandatory = $true)][string[]]$roots )

Set-StrictMode -Version Latest

Write-Verbose "Set-LocationEx roots: $(Join-String -Strings $roots -Separator ', ')"

function Set-LocationEx
{
    param( [Parameter( Mandatory="true" )]$path )

    process
    { 
        $verbose = ( $PSCmdlet.MyInvocation.BoundParameters.ContainsKey( "Verbose" ) -and $PSCmdlet.MyInvocation.BoundParameters[ "Verbose" ].IsPresent )
        if ( $verbose )
            { Write-Verbose( "$(Join-String -Strings $roots -Separator ', ')" ) }
        if ( !( Test-Path $path ) ) 
        {
            foreach ( $p in $roots )
            { 
                $newPath = Join-Path $p $path
                if ( $verbose ) { Write-Verbose "Looking for $newPath" }
                if ( Test-Path $newPath ) 
                { 
                    $newPath = Get-PathCanonicalCase( $newPath )
                    if ( $verbose ) { Write-Verbose "Found $newPath" }
                    Push-Location $newPath
                    return
                } 
            }
        }
        if ( Test-Path $path )
            { $path = Get-PathCanonicalCase( $path ) }
        Push-Location $path
    }
}

function Get-LocationExRoots
{
    process
    {
        Write-Output (Join-String -Strings $roots -NewLine)
    }
}

function Get-PathCanonicalCase
{
    param( $path )

    $newPath = (Resolve-Path $path).Path
    $root = [System.IO.Path]::GetPathRoot( $newPath )
    if ( $newPath -ne $root ) # Handle root directory
        { $newPath = [System.IO.Directory]::GetDirectories( $root, $newPath.Substring( $root.Length ) )[ 0 ] }
    $newPath
}

答案 3 :(得分:1)

我发现使用PowerShell通配符的方法更简单。

 $canonicalCasePath = Get-ChildItem -Path $wrongCasingPath.Replace("\","\*") | Where FullName -IEQ $wrongCasingPath | Select -ExpandProperty FullName
  • 管道的第一部分替换路径中的所有反斜杠 反斜杠和星号 \ \ * 并返回所有匹配的文件
  • where部分确保只返回所需的文件 没有任何其他潜在的匹配。 IEQ是案例中的等值
  • 最后一个选择部分提取规范案例路径 文件