在Powershell中的ForEach-Object中引用目标对象

时间:2019-06-02 18:28:58

标签: powershell

我对Powershell相当陌生。我试图通过引用作为备份一部分创建的每个GPO备份的“ gpresult.xml”文件中的名称来重写GPO备份文件夹的名称,以使用其友好名称而不是其GUID。但是,我不明白如何引用正在读入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)

如何在Powershell的ForEach-Object命令中引用当前正在使用的对象?

4 个答案:

答案 0 :(得分:3)

  

我来自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
}

请注意,您不能在PowerShell 管道 中直接使用foreach 声明

在管道中,必须改为使用ForEach-Object cmdlet ,这可能会引起混淆-在某些情况下可能会引用 foreach一样,通过alias-仅parsing mode才可以区分语句和cmdlet的别名。


您正在管道 中使用ForEach-Object cmdlet ,其中适用不同的规则

传递到管道处理 cmdlet 的脚本块({{ ... })(例如ForEach-ObjectWhere-Object确实没有显式的符号。 foreach 语句提供的迭代变量。

相反,按照惯例,此类脚本块将当前管道输入对象视为automatic variable $_-或更冗长的是$PSItem

>

虽然 foreach语句和ForEach-Object cmdlet 在一定的抽象级别上运行相同,但是存在根本区别

  • foreach 声明对内存中预先收集的完整集合进行操作

  • ForEach-Object cmdlet 流输入进行操作,逐个对象,因为每个对象都是通过管道接收的。

此差异等于以下权衡

  • 使用foreach 语句以获得更好的性能,但以牺牲内存使用为代价。

  • ForEach-Object cmdlet 用于恒定内存使用,并且还可能用于单个管道的句法优雅 ,而牺牲了 performance 的性能-但是,对于非常大的输入集,这可能是唯一的选择(假设您还没有在输出)。

答案 1 :(得分:2)

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名称:

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循环语句,就像python中的for object in list

foreach($object in Get-ChildItem -Filter gpresult.xml)
{
    [xml]$file = Get-Content -LiteralPath $object.FullName
}

答案 2 :(得分:0)

另一种方式...

$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
}

答案 3 :(得分:0)

这是我的解决方案。令人讨厌的是$ _没有完整的路径。 $ gpath比$ _。fullname更容易使用,因为在下一行使用get-content将两个字符串连接在一起。尝试backup-gpo时,我得到一个gpreport.xml文件。显然,不能将。\ gpo_backups \等相对路径与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   
}