将字符串集合中的 $_ 项传递给从 Select-Object 调用的函数

Passing $_ item from a string collection into a function called from Select-Object

好的...所以我有一个 System.Data.DataRow 对象。我已经将列名放入一个字符串集合中。然后我想将相应的值放入第二个集合中。

我确定我只是在做一些愚蠢的事情,但我这辈子都弄不明白。 采取以下代码...

$cols = $drFrom.Table.Columns
$colNames = $cols | Where-Object { $_.ColumnName -ne "ROWID" } | Select-Object $_.ColumnName
Write-Host $colNames
$colValues = $colNames | Select-Object $drFrom.Item($_).ToString()

请注意 Write-Host 显示 $colNames 包含预期的列名称,并在控制台中输出:

CLIENTID MESSAGE AMOUNT PAIDBY PAIDBYEMAIL ACTIVE

因此,我们的目的是将 $colNames 通过管道传输到 Select-Object,并且对于每个列名,从 DataRow 中获取值。但出于某种原因,当它从 Select-Object 变为 运行 时,$_ 似乎返回为空,而不是已知存在于 $colNames 集合中的字符串值.当它运行第 4 行时,做管道,它抛出这个异常:

Exception getting "Item": "Exception calling "get_Item" with "1" argument(s): "'column' argument cannot be null.
Parameter name: column""
At D:\MyScripts\MyScript.ps1:145 char:5
+     $colValues = $colNames | Select-Object $drFrom.Item($_).ToString( ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], GetValueInvocationException
    + FullyQualifiedErrorId : CatchFromBaseParameterizedPropertyAdapterGetValue

我也试过在引号中嵌入迭代变量,就像这样...

$colValues = $colNames | Select-Object $drFrom.Item("$_").ToString()

然后异常发生相应变化,但仍然反映 $_:

的空值
Exception getting "Item": "Exception calling "get_Item" with "1" argument(s): "Column '' does not belong to table .""
+     $colValues = $colNames | Select-Object $drFrom.Item("$_").ToStrin ...

如何获取迭代变量以在管道传输时实际反映 $colNames 中的字符串值?

通过Select-Object, you must use calculated properties, which involve a hashtable that defines a property name and a script block ({ ... }) that defines the property value, in which you can refer to the pipeline input object at hand via the automatic $_ variable动态定义属性

但是,您不是要定义计算的 属性,而是要输出计算的 value,为此您需要调用 ForEach-Object:

$colNames = $cols | 
              Where-Object ColumnName -ne ROWID |
                ForEach-Object ColumnName

$colValues = $colNames |
               ForEach-Object { $drFrom.Item($_).ToString() }

请注意,第一个管道使用 simplified syntax,用于 Where-ObjectForEach-Object 调用。

你说

I want to get the corresponding values into a second collection.

你有:

$cols = $drFrom.Table.Columns

$colNames = $cols | 
    Where-Object { $_.ColumnName -ne "ROWID" } | 
    Select-Object $_.ColumnName

哪个有效(但可以简化)。

现在有两件事你想做:

  • Select 列
  • 将列转换为字符串

单独做这些要简单得多。

首先select你想要的属性:

$colValues = $drFrom |
    Select-Object $colNames

现在您在 PSCustomObject 中有了所需的列。这很重要,因为我们可以使用隐藏的 PSObject 属性:

$colValues.PSObject.Properties.Name |
    ForEach {$colValues.$_ = [string]$colValues.$_}

这里我已经从调用 .ToString() 切换到使用转换运算符 [string],因为它可以毫无错误地处理 $null。

我想这会给你想要的。

您的列名计算可以简化为

$colNames = drFrom.Table.Columns.ColumnName | 
    Where-Object {$_ -ne "ROWID"}

如果 drFrom 有可能是一个列表,那么:

$colNames = drFrom[0].Table.Columns.ColumnName | 
    Where-Object {$_ -ne "ROWID"}

当你只想消除列时,似乎是这种情况,你可以简化为:

$colValues = $drFrom |
    Select-Object * -ExcludeProperty "ROWID"

并将剩余的属性转换为字符串:

$colValues.PSObject.Properties.Name |
    ForEach {$colValues.$_ = [string]$colValues.$_}

当你写:

I want to get the corresponding values into a second collection.

不清楚您想要该集合的形式。上面我生成了一个具有命名属性的对象,因为我发现它在 PowerShell 中更有用。您提供的代码似乎试图提取一个字符串列表。如果那是您想要的,请将上面的最后一行代码替换为:

$stringList = $colValues.PSObject.Properties.Name |
    ForEach {[string]$colValues.$_}

希望对您有所帮助。