How do I get the path with the correct (canonical) case in PowerShell?

I have a script that takes a directory as an argument from a user. I would like to display the directory path name as it appears on Windows. I.e.

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

How to get "C: \ SomeDirectory" when specifying "c: \ somedirectory"?

+6
source share
4 answers

The accepted answer receives only the correct file. Parental paths are left in the case provided by the user. Here is my solution.

 $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() } 

I have included the above code in Resolve-PathCase , part of the Carbon PowerShell Module. Disclaimer: I am the owner / custodian of Carbon.

+6
source

This should work:

 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 } } 
+6
source

Using Christian GetDirectories , here is another solution that is not quite right:

 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 } 

EDIT: Thanks for the help.

Btw, all I wanted was to use in a small script utility, overriding the default cd alias, allowing me to specify some "root" directories that are looked up if the path does not exist relative to the current directory, Ie, this allows me cd Documents , cd trunk , cd Release-10.4 regardless of my current location. And it annoyed me to get an invitation in the case when I entered it, and not its actual case.

 # 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 } 
+1
source

I found a different and simpler approach using wild PowerShell cards.

  $canonicalCasePath = Get-ChildItem -Path $wrongCasingPath.Replace("\","\*") | Where FullName -IEQ $wrongCasingPath | Select -ExpandProperty FullName 
  • The first part of the pipe replaces all backslashes in the path with a backslash and an asterisk \ β†’ \ * and return all the corresponding files
  • In the part in which only the desired file will be returned and not any other potential match. IEQ is case independent.
  • The last part of the selection retrieves the canonical file path
+1
source

Source: https://habr.com/ru/post/895904/


All Articles