Search code examples
windowspowershellcase-sensitiventfs

How to format an existent but case-confused path to the real one in NTFS of Windows?


I'm working on a cross-platform project and want to deal with some paths that can support multi-platforms by PowerShell.

For example, I need to transfer a string of a path from an NTFS of Windows to Linux, access the path from Linux by mounting the NTFS, and deal with the path for other normal purposes.

The procedures can be the following:

  • Given a path string that represents an existent item within an NTFS of Windows from a source
  • Transfer this path's string to Linux
  • Mount the NTFS and deal with the path.

The problem is:

  1. The path may be from an untrusted source and be case-confused, i.g., maybe elaborately, c:\uSeRs\usER\TesT.tXt, even though it represents the real one C:\Users\User\test.txt
  2. If I transfer the case-confused one to Linux without any process, it will bring some potential risks:
    • On the Linux side, I cannot distinguish c:\uSeRs\usER\TesT.tXt from C:\Users\User\test.txt by literal, since they both represent the same resource.
    • Also on the Linux side, I have to perform some additional operations to determine if the above 2 paths are the same:
      • Access the mounted NTFS, using its own mechanism
      • Mimic NTFS's normal behavior
      • ...
  3. Any additional operation on the Linux side about the transferred path seems very unnecessary. Why I cannot transfer a normalized (formatted) path from Windows to Linux?
  4. Although usually we use NTFS in a case-insensitive way, actually it has the ability to be case-sensitive.
  5. And, since we can see the true case of a path by Explorer.exe, it means the information of the original case-sensitive path is just recorded somewhere. From a case-confused path, we can locate a specific item, but how to get its original information that contains its case-sensitive path?

There may be too many points. But my key problem can be described as the following target:

  • Use PowerShell 7.0+ on Windows
  • There is a file C:\Users\User\test.txt already.
  • Only Given c:\uSeRs\usER\TesT.tXt
  • Get the string C:\Users\User\test.txt as we can see from explorer.exe

I have tried Get-Item, Get-ItemProperty and something like here, but they do not work:

#Requires -Version 7.0
$target = 'C:\Users\User\test.txt'
New-Item -Path $target -ItemType File
$known = 'c:\uSeRs\usER\TesT.tXt'

(Get-Item $known).FullName
# C:\uSeRs\usER\TesT.tXt  
# 'c' has been converted to `C` but the other parts have not been converted to the target

(Get-Item $known).FullName -eq $target
# False

# see https://stackoverflow.com/a/48845935/17357963
(Get-Item $known).Target 
# return $null or empty

(Get-ItemProperty $known).FullName -eq $target
# False

(Get-ItemProperty $known).Target 
# return $null or empty

Thanks in advance.


Solution

  • Based on the comments, we worked out the anwser as:

    (Get-ChildItem (Split-Path $known) | Where-Object Name -eq (Split-Path $known -leaf)).FullName