Как я могу запросить временный 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