Как получить путь с правильным (каноническим) регистром в PowerShell? - PullRequest
6 голосов
/ 25 августа 2011

У меня есть скрипт, который принимает каталог в качестве аргумента от пользователя.Я хотел бы отобразить имя пути к каталогу, как оно отображается в Windows.Т.е.,

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

Как мне извлечь "C: \ SomeDirectory", когда ему дано "c: \ somedirectory"?

Ответы [ 4 ]

6 голосов
/ 08 февраля 2012

Принятый ответ получает только правильный регистр файла. Родительские пути остаются в регистре, предоставленном пользователем. Вот мое решение.

$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 , часть модуля PowerShell Carbon . Отказ от ответственности: я владелец / сопровождающий Carbon.

6 голосов
/ 25 августа 2011

Это должно работать:

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 голос
/ 14 февраля 2017

Я нашел другой и более простой подход с использованием подстановочных знаков PowerShell.

 $canonicalCasePath = Get-ChildItem -Path $wrongCasingPath.Replace("\","\*") | Where FullName -IEQ $wrongCasingPath | Select -ExpandProperty FullName
  • Первая часть канала заменяет все обратные косые черты в пути на обратную косую черту и звездочку \ \ * и возвращает все соответствующие файлы
  • Часть where гарантирует, что возвращается только нужный файл, а не любое другое потенциальное совпадение.IEQ является регистронезависимым равным
  • Последняя выделенная часть извлекает канонический путь к регистру файла
1 голос
/ 26 августа 2011

Используя предложение Кристиана 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 Documents, cd trunk, cd 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...