Ссылка на целевой объект в ForEach-Object в Powershell - PullRequest
1 голос
/ 02 июня 2019

Я довольно новичок в Powershell. Я пытаюсь переписать имена папок резервных копий объекта групповой политики, используя их понятное имя, а не GUID, ссылаясь на имя в файле gpresult.xml каждой резервной копии объекта групповой политики, который создается как часть резервной копии. Тем не менее, я не понимаю, как я могу ссылаться на конкретный объект (в данном случае, имя папки), который читается в цикл ForEach-Object для чтения в файл под этой папкой.

function Backup_GPO {

    $stamp = Get-Date -UFormat "%m%d" 
    New-Item -ItemType "directory" -Name $stamp -Path \\dc-16\share\GPO_Backups -Force | out-null # create new folder to specify day backup is made
    Backup-GPO -All -Path ("\\dc-16\share\GPO_Backups\" + "$stamp\" )
    Get-ChildItem -Path \\dc-16\share\GPO_Backups\$stamp | ForEach-Object {
        # I want to reference the current folder here
        [xml]$file = Get-Content -Path (folder that is being referenced in for loop)\gpresult.xml 
        $name = $file.GPO.Name
    }

Я пришел из Python, где, если я хочу сослаться на объект, который я сейчас перебираю, я могу сделать это очень просто -

for object in list:
    print(object)

Как вы ссылаетесь на текущий используемый объект в команде Forersach-Object от Powershell?

Ответы [ 4 ]

3 голосов
/ 03 июня 2019

Я пришел из Python, где, если я захочу сослаться на объект, который я сейчас перебираю, я могу сделать это очень просто -

for object in list: print(object)

прямым эквивалентом этого в PowerShell является оператор foreach (цикл) :

$list = 1..3  # create a 3-element array with elements 1, 2, 3
foreach ($object in $list) {
  $object  # expression output is *implicitly* output
}

Обратите внимание, что вы не можете напрямую использовать оператор foreach в конвейере PowerShell .

В конвейере необходимо использовать ForEach-Object командлет вместо , который - несколько запутанно - может также именоваться foreach через псевдоним -только режим синтаксического анализа различает оператор и псевдоним командлета.


Вы используете ForEach-Object командлет в конвейере , где применяются другие правила .

Блоки сценариев ({ ... }) передаются конвейерной обработке командлетов , напримеркак ForEach-Object и Where-Object сделать не имеет явную переменную итерации, которую обеспечивает оператор foreach .

Вместо этого, как правило, такие скриптовые блоки видят текущий входной объект конвейера как автоматическая переменная $_ - или, более подробно, как $PSItem.


В то время как оператор foreach и командлет ForEach-Object работают на одном уровне абстракции одинаково, есть принципиальная разница :

  • Оператор foreach работает с коллекциями , собранными сразу в памяти, полностью .

  • Командлет ForEach-Object работает на потоковом вводе, объект за объектом , поскольку каждый объект принимается по конвейеру.

Эта разницасоставляет следующий компромисс :

  • Использование оператора foreach для лучшей производительности за счет памятииспользование .

  • Использование ForEach-Object командлет для постоянное использование памяти и, возможно, также для синтаксическая элегантность одного конвейера за счет производительности - однако для очень больших входных наборов это может быть единственным вариантом (при условии, что вы также не собираете очень большой набор данных в памятина вывод ).

2 голосов
/ 02 июня 2019

Внутри скриптового блока ForEach-Object текущий итерируемый элемент копируется в $_:

Get-ChildItem -Filter gpresult.xml |ForEach-Object {
    # `$_` is a FileInfo object, `$_.FullName` holds the absolute file system path
    [xml]$file = Get-Content -LiteralPath $_.FullName
}

Если вы хотите указать пользовательское имя, вы можете указать -PipelineVariable name:

Get-ChildItem -Filter gpresult.xml -PipelineVariable fileinfo |ForEach-Object {
    # `$fileinfo` is now a FileInfo object, `$fileinfo.FullName` holds the absolute file system path
    [xml]$file = Get-Content -LiteralPath $fileinfo.FullName
}

или используйте оператор цикла foreach, очень похоже на for object in list в python:

foreach($object in Get-ChildItem -Filter gpresult.xml)
{
    [xml]$file = Get-Content -LiteralPath $object.FullName
}
0 голосов
/ 03 июня 2019

Вот мое решение.Раздражает, что у $ _ нет полного пути.С $ gpath легче работать, чем с $ _. fullname, для объединения двух строк на следующей строке с get-content.Я получаю файл gpreport.xml при попытке создать резервную копию gpo.Очевидно, вы не можете использовать относительные пути, такие как. \ Gpo_backups \ with backup-gpo.

mkdir c:\users\js\gpo_backups\
get-gpo -all | where displayname -like '*mygpo*' | 
  backup-gpo -path c:\users\js\gpo_backups\

Get-ChildItem -Path .\GPO_Backups\ | ForEach-Object {
  $gpath = $_.fullname
  [xml]$file = Get-Content -Path "$gpath\gpreport.xml"
  $file.GPO.Name   
}
0 голосов
/ 02 июня 2019

Другой способ ...

$dlist = Get-ChildItem -Path "\\dc-16\share\GPO_Backups\$stamp"
foreach ($dir in $dlist) {
    # I want to reference the current folder here
    [xml]$file = Get-Content -Path (Join-Path -Path $_.FullName -ChildPath 'gpresult.xml')
    $name = $file.GPO.Name
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...