Как стать автором
Обновить

Windows, PowerShell и длинные пути

Время на прочтение4 мин
Количество просмотров25K


Думаю, вам, как и мне, не раз приходилось видеть пути вида \!!! Важное\____Новое____\!!! Не удалять!!!\Приказ №98819-649-Б от 30 февраля 1985г. о назначении Козлова Ивана Александровича временно исполняющим обязанности руководителя направления по сопровождению корпоративных VIP-клиентов и организации деловых встреч в кулуарах.doc.

И зачастую открыть такой документ в Windows сходу не получится. Кто-то практикует workaround в виде мапирования дисков, кто-то использует файловые менеджеры, умеющие работать с длинными путями: Far Manager, Total Commander и им подобные. А еще многие с грустью наблюдали, как созданный ими PS-скрипт, в который было вложено немало труда и который в тестовом окружении работал на ура, в боевой среде беспомощно жаловался на непосильную задачу: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
Как оказалось, 260 символов хватит «не только лишь всем». Если вам интересно выйти за границы дозволенного — прошу под кат.

Вот лишь некоторые из печальных последствий ограничения длины файлового пути:


Немного отклоняясь от темы, замечу, что для DFS Replication рассматриваемая в статье проблема не страшна и файлы с длинными именами успешно путешествуют с сервера на сервер (если, конечно, в остальном вы всё сделали правильно).

Еще хотелось бы обратить внимание на очень полезную и не раз меня выручавшую утилиту robocopy. Ей тоже не страшны длинные пути, да и умеет она многое. Поэтому если задача сводится к копированию/переносу файловых данных, можно остановиться на ней. Если нужно пошаманить со списками контроля доступа в файловой системе (DACL), посмотрите в сторону subinacl. Несмотря на солидный возраст, отлично себя показала на Windows 2012 R2. Тут рассмотрены способы применения.

Мне же было интересно научить работать с длинными путями PowerShell. С ним почти как в бородатом анекдоте про Ивана-Царевича и Василису Прекрасную.

Быстрый способ


Перейти на Linux и не париться Windows 10/2016/2019 и включить соответствующий параметр групповой политики/твикнуть реестр. Подробно на этом способе останавливаться не буду, т.к. в сети уже много статей на эту тему, например, эта.

Учитывая, что в большинстве компаний много, мягко говоря, не свежих версий операционных систем, способ этот быстрый только для написания на бумаге, если, конечно, вы не из тех счастливчиков, у которых мало legacy-систем и царят Windows 10/2016/2019.

Долгий способ


Тут сразу оговоримся, что изменения не затронут поведение проводника Windows, а дадут возможность использовать длинные пути в командлетах PowerShell, таких как Get-Item, Get-ChildItem, Remove-Item и др.

Для начала обновим PowerShell. Делается на раз-два-три.

  1. Обновляем .NET Framework до версии не ниже 4.6 (вообще, PowerShell 5.1 установится и на 4.5, но, судя по жалобам на форумах, некоторые PS-командлеты при такой конфигурации могут работать неправильно). Операционная система должна быть не ниже Windows 7 SP1/2008 R2. Актуальную версию загрузить можно здесь, дополнительную информацию почитать тут.
  2. Скачиваем и устанавливаем Windows Management Framework 5.1
  3. Перезагружаем машину.

Трудолюбивые могут сделать описанные выше шаги вручную, ленивые — с помощью SCCM, политик, скриптов и эникеев других средств автоматизации.

Текущую версию PowerShell можно узнать из переменной $PSVersionTable. После обновления должно быть примерно так:



Теперь при использовании командлетов Get-ChildItem и ему подобных вместо привычного Path будем использовать LiteralPath.

Формат путей при этом будет немного другим:

Get-ChildItem -LiteralPath "\\?\C:\Folder"
Get-ChildItem -LiteralPath "\\?\UNC\ServerName\Share"
Get-ChildItem -LiteralPath "\\?\UNC\192.168.0.10\Share"

Для удобства преобразования путей из привычного формата в формат LiteralPath можно использовать вот такую функцию:

Function ConvertTo-LiteralPath {
Param([parameter(Mandatory=$true, Position=0)][String]$Path)
    If ($Path.Substring(0,2) -eq "\\") {Return ("\\?\UNC" + $Path.Remove(0,1))}
    Else {Return "\\?\$Path"}
}

Обратите внимание, что при задании параметра LiteralPath нельзя использовать подстановочные символы (*, ? и т.д.).

Помимо параметра LiteralPath, в обновленной версии PowerShell командлет Get-ChildItem получил параметр Depth, с помощью которого можно задавать глубину вложенности для рекурсивного поиска, я пару раз его использовал и остался доволен.

Теперь можно не бояться, что ваш PS-скрипт собьется с долгого тернистого пути и не разглядит далекие файлы. Меня, например, очень выручил этот подход при написании скрипта для сбрасывания атрибута «временный» у файлов в DFSR-папках. Но это уже другая история, о которой я постараюсь рассказать в другой статье.
UPD 06.07.2019: Обещанная статья
От вас же жду интересных комментариев и предлагаю пройти опрос.
UPD 23.07.2020: Если командлет Get-ChildItem выдает ошибку «путь содержит недопустимые знаки», обновите .NET Framework до актуальной версии (за уточнение спасибо mordaden).

Полезные ссылки:
docs.microsoft.com/ru-ru/dotnet/api/microsoft.powershell.commands.contentcommandbase.literalpath?view=powershellsdk-1.1.0
docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-5.1
stackoverflow.com/questions/46308030/handling-path-too-long-exception-with-new-psdrive/46309524
luisabreu.wordpress.com/2013/02/15/theliteralpath-parameter
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Актуальна ли для вас проблема длинных путей?
25.28% Да45
13.48% Была актуальна, но уже решил24
23.6% Мешает, но не сильно42
15.73% Не думал об этом, вроде все работает28
21.35% Нет38
0.56% Другое (укажите в комментариях)1
Проголосовали 178 пользователей. Воздержались 27 пользователей.
Теги:
Хабы:
Всего голосов 19: ↑16 и ↓3+13
Комментарии18

Публикации

Истории

Работа

Ближайшие события

2 – 18 декабря
Yandex DataLens Festival 2024
МоскваОнлайн
11 – 13 декабря
Международная конференция по AI/ML «AI Journey»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань