Как я могу запросить временный PS-Drive, возвращая файлы с именем относительно диска?

Я пытаюсь создать script, где я буду искать файловые серверы для не унаследованных разрешений. В результате я столкнулся с предел 260 символов для имен файлов. Предложение, которое я видел, что, по моему мнению, помогло бы, пару раз состояло в том, чтобы создать несколько ненастоящих PS-накопителей на пару уровней и запросить их.

Проблема в том, что когда я использую Get-ChildItem для новых PS Drives, он возвращает объект с полным сетевым путем и не использует имя, которое я ему назначил.

# Cycle the folders
Get-ChildItem $rootPath -Directory | select -first 1 | ForEach-Object{
    $target = $_

    # Create a PS Drive for each sub directory and get all the folders
    [void](New-PSDrive -Name $target.Name -PSProvider FileSystem $target.FullName)

    # Get the file objects. 
    Get-ChildItem "$($target.Name):\" -Recurse
}

Я уверен, что если бы я создал несколько подходящих сетевых дисков с буквой диска, у меня не было бы этой проблемы.

Надеюсь, я просто не пропустил его, но Technet for New-PSDrive не был на 100% понятен в этом сценарии.

Я ищу способ сделать ps-диск и ссылаться на папки, возвращая пути относительно нового имени диска. Рассмотрим выход из psdrive, который я сделал (G:), затем один из моих подключенных сетевых дисков (M:).

PS M:\> Get-ChildItem G:\

    Directory: \\server01\COMMON\Folder

Mode                LastWriteTime     Length Name                                                                                                            
----                -------------     ------ ----                                                                                                            
d----         6/18/2011   8:14 AM            Folder 1                                                                                                          
d----         6/18/2011   8:14 AM            Folder 2 

PS M:\> Get-ChildItem M:\

    Directory: M:\

Mode                LastWriteTime     Length Name                                                                                                            
----                -------------     ------ ----                                                                                                            
d----          5/8/2015  11:00 AM            Backup                                                                                                          
d----          5/8/2015  11:00 AM            covers                                                                                                          
d----          5/8/2015  11:00 AM            drop                                                                                                            
d----          5/8/2015  11:00 AM            Expense         

Я знаю, что для моей точной ситуации существует множество обходных путей, но я хотел бы понять поведение, которое я показываю с помощью New-PSDrive.

Ответ 1

Похоже, вы смешиваете две разные вещи: путь PowerShell и путь провайдера. Пути PowerShell не видны вне PowerShell.

New-PSDrive X FileSystem C:\Windows
(Get-Item X:\System32\notepad.exe).get_Length() #OK
([IO.FileInfo]'X:\System32\notepad.exe').get_Length() #Error

Но Get-Item X:\System32\notepad.exe удалось создать объект FileInfo, представляющий некоторый файл. Итак, какой файл представлен результирующим объектом FileInfo?

(Get-Item X:\System32\notepad.exe).FullName
# C:\Windows\System32\notepad.exe

Так как объект FileInfo ничего не знает о драйвере PowerShell X:, он должен хранить путь, который внутренне использует API файловой системы, который он может понять. Командлет Convert-Path можно использовать для преобразования пути PowerShell к пути поставщика:

Convert-Path X:\System32\notepad.exe
# C:\Windows\System32\notepad.exe

То же самое происходит при создании диска PowerShell, указывающего на какой-то сетевой путь:

New-PSDrive Y FileSystem \\Computer\Share
Get-ChildItem Y:\

Возвращенные объекты FileInfo и DirectoryInfo ничего не знают о Y:, поэтому они не могут иметь путей относительно этого диска PowerShell. Внутренне используемый API файловой системы не будет их понимать.

Все меняется, когда вы используете опцию -Persist. В этом случае будут созданы реальные сопоставленные диски, которые могут быть поняты API-интерфейсом файловой системы вне PowerShell.

New-PSDrive Z FileSystem \\Computer\Share -Persist|Format-Table *Root
# Root        : Z:\
# DisplayRoot : \\Computer\Share

Как вы можете видеть, Root будет не \\Computer\Share по вашему запросу в командлете New-PSDrive, а Z:\. Поскольку Z: является реальным приводом в этом случае, объекты FileInfo и DirectoryInfo, возвращаемые Get-Item или Get-ChildItem cmdlet, могут иметь пути относительно него.

Ответ 2

не тестировались, но если вы не против использования "subst", то что-то вроде этого может сработать для вас

function Get-FreeDriveLetter {
    $drives = [io.driveinfo]::getdrives() | % {$_.name[0]}
    $alpha = 65..90 | % { [char]$_ }
    $avail = diff $drives $alpha | select -ExpandProperty inputobject
    $drive = $avail[0] + ':'
    $drive
}

$file = gi 'C:\temp\file.txt'
$fullname = $file.FullName

if ($fullname.length -gt 240) {
    $drive = Get-FreeDriveLetter
    $path = Split-Path $fullname
    subst $drive $path
    $subst = $true
    rv path
    $fullname = Join-Path $drive $(Split-Path $fullname -Leaf)
}

$fullname