Как изменить атрибут чтения для списка файлов?

Я новичок PowerShell. Я использовал пример скрипта и сделал замену из get-item на get-content в первой строке. Модифицированный скрипт выглядит следующим образом:

$file = get-content "c:\temp\test.txt"
if ($file.IsReadOnly -eq $true)
{
$file.IsReadOnly = $false
}

По сути, я пытаюсь выполнить действия, содержащиеся в test.txt, которые хранятся как пути UNC.

\\testserver\testshare\doc1.doc
\\testserver2\testshare2\doc2.doc

При запуске скрипта об ошибках не сообщается и никакие действия не выполняются даже при первой записи.

2 ответа

Короткий ответ:

sp (gc test.txt) IsReadOnly $false

Длинный ответ ниже


Ну, некоторые вещи не так с этим.

$file на самом деле string[], содержащий строки вашего файла. Итак IsReadOnly собственность относится к string[] а не к фактическим файлам, представленным теми строками, которые оказываются именами файлов.

Итак, если я правильно вас понимаю, вы пытаетесь прочитать файл, содержащий другие имена файлов, по одному в каждой строке. И очистите атрибут "только для чтения" в этих файлах.

Начиная с Get-Content здесь не так. Нам определенно понадобится это:

$filenames = Get-Content test.txt

Теперь у нас есть список имен файлов. Чтобы получить доступ к атрибутам файла, нам нужно либо преобразовать эти имена файлов в реальные FileInfo объекты и оперируют на тех. Или мы передаем имена файлов -Path аргумент Set-ItemProperty,

Сначала я выберу первый подход, а затем перейду к другому. Таким образом, у нас есть куча имен файлов и хотим FileInfo объекты от них. Это можно сделать с помощью foreach цикл (так как нам нужно сделать это для каждого файла в списке):

$files = (foreach ($name in $filenames) { Get-Item $name })

Затем вы можете перебрать имена файлов и установить IsReadOnly собственность на каждого из них:

foreach ($file in $files) {
    $file.IsReadOnly = $false
}

Это был длинный и громоздкий вариант. Но тот, который, вероятно, больше всего подходит людям, не имеющим опыта работы с PowerShell. Вы можете уменьшить потребность в наличии нескольких коллекций вещей, используя конвейер. Конвейер переносит объекты из одного командлета в другой, и эти объекты по-прежнему имеют типы.

Итак, написав

Get-Content test.txt | Get-Item | ForEach-Object { $_.IsReadOnly = $false }

мы достигаем точно такого же результата. Мы читаем содержимое файла, получая кучу string s. Те переданы Get-Item который знает, что делать с конвейерным вводом: он обрабатывает эти объекты как пути к файлам; именно то, что нам нужно здесь. Get-Item затем отправляет FileInfo объекты далее по конвейеру, после чего мы зацикливаемся на них и устанавливаем свойство только для чтения в false,

Теперь это было короче и, с небольшой практикой, может быть, даже проще. Но это все еще далеко от идеала. Как я уже говорил, мы можем использовать Set-ItemProperty установить свойство "только для чтения" для файлов. И мы можем воспользоваться тем, что Set-ItemProperty может принять массив строк в качестве входных данных для его -Path параметр.

$files = Get-Content test.txt
Set-ItemProperty -Path $files -Name IsReadOnly -Value $false

Мы используем временную переменную здесь, так как Set-ItemProperty не будет принимать входящие строки в качестве значений для -Path непосредственно. Но мы можем встроить эту временную переменную:

Set-ItemProperty -Path (Get-Content test.txt) -Name IsReadOnly -Value $false

Скобки вокруг Get-Content вызов необходим для того, чтобы сообщить PowerShell, что это единственный аргумент, и его следует сначала оценить.

Затем мы можем воспользоваться тем фактом, что каждый из этих параметров используется в позиции, где Set-ItemProperty ожидает, что это так, поэтому мы можем опустить имена параметров и придерживаться только значений:

Set-ItemProperty (Get-Content test.txt) IsReadOnly $false

И затем мы можем сократить имена командлетов до их псевдонимов по умолчанию:

sp (gc test.txt) IsReadOnly $false

Мы могли бы на самом деле написать $false как 0 чтобы сэкономить еще больше места, так как 0 преобразуется в $false когда используется как логическое значение. Но я думаю, что здесь достаточно сокращения.

У Йоханнеса есть понимание теории проблемы, с которой вы сталкиваетесь. Я просто хотел отметить, что если вы используете расширения сообщества PowerShell, вы можете выполнить это с помощью команд Set-Writable и Set-ReadOnly, которые поддерживают конвейер, например:

Get-Content "c:\temp\test.txt" | Set-Writable

или краткая псевдоним:

gc "c:\temp\test.txt" | swr

Псевдоним для Set-ReadOnly является sro. Я использую эти команды еженедельно, если не ежедневно.

Другие вопросы по тегам