【问题标题】:Referencing targeted object in ForEach-Object in Powershell在 Powershell 中的 ForEach-Object 中引用目标对象
【发布时间】:2019-06-03 13:11:21
【问题描述】:

我对 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 命令中引用当前正在使用的对象?

【问题讨论】:

  • 大多数人使用$_,但$psitem 可以作为替代使用。检查 PowerShell 帮助总是值得的,因为它非常全面地介绍了语言的基础知识:ForEach-Object

标签: powershell


【解决方案1】:

我来自 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,这-有点令人困惑-可以被称为@ 987654329@,通过 alias - 只有 parsing mode 才能区分语句和 cmdlet 的别名。


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

传递给管道处理cmdlet 的脚本块 ({ ... }),例如 ForEach-ObjectWhere-Objectnot 具有显式迭代变量foreach 声明 提供。

相反,按照惯例,此类脚本块将当前管道输入对象视为automatic variable$_,或者更详细地说,为$PSItem


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

  • foreach 语句对预先收集在内存中的集合进行操作,

  • ForEach-Object cmdlet逐个对象的流式输入上运行,因为每个对象都通过管道接收。

    李>

这种差异相当于以下权衡

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

  • ForEach-Object cmdlet 用于恒定内存使用,也可能用于单个管道的语法优雅,在性能 - 然而,对于非常大的输入集,这可能是唯一的选择(假设您没有在 输出 的内存中收集非常大的数据集) .

【讨论】:

    【解决方案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
    }
    

    【讨论】:

      【解决方案3】:

      另一种方式...

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

      【讨论】:

        【解决方案4】:

        这是我的解决方案。令人讨厌的是 $_ 没有完整路径。 $gpath 比 $_.fullname 更容易使用 get-content 在下一行将两个字符串连接在一起。当我尝试备份 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   
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-13
          • 2012-05-03
          • 1970-01-01
          相关资源
          最近更新 更多