首页 > 解决方案 > 创建新对象 PSObject 时出错

问题描述

此 powershell 脚本在 csv 文件中最多占用 8 行,并通过复制列将它们组合成一行,然后保存在结果文件中(第一个结果文件保存良好)。如果 csv 中有 16 行,则意味着保存第二个结果文件等。

例如在 rows.csv 中:

第一场 第二场 第三场 第四场

球拍球拍俱乐部

橙香蕉芒果梨

在 result1.csv 中:

第一1 第二1 第三1 第四1 第一2 第二2 第三2 第四2

球 蝙蝠 球拍 俱乐部 橙色 香蕉 芒果 梨

我收到一个错误:

New-Object : Cannot convert 'System.Object[]' to the type 'System.Collections.IDictionary' required by parameter 'Property'. Specified method is not supported.
At C:csv.ps1:19 char:42
+ $results = New-Object PSObject -Property $details
+                                          ~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [New-Object], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.NewObjectCommand

请注意,第 16 行的第一个新对象创建工作正常。在 Powershell ISE 中,如果我重新运行脚本,它也会在第 16 行出错。我不知道这里出了什么问题,但假设我需要在保存每个 csv 文件后销毁 PSObject?

$csvObjects = import-csv C:\rows.csv
$results = @()
$counter=1
foreach ($item in $csvObjects){
    $detailsnew = [ordered] @{            
        "first$counter" = $item.'First_field'          
        "second$counter" = $item.'Second_field'           
        "third$counter"  = $item.'Third_field'
        "fourth$counter" = $item.'Fourth_field'
    }   
    $details  +=  $detailsnew 
    # modulus comparison returns remainder - write out file every 8
    if ($counter % 8 -eq 0) {
        if ($counter -eq 8) {
            #works on line below on first run but fails on subsequent runs within Powershell ISE
            $results = New-Object PSObject -Property $details 
        }

        if ($counter -eq 16) {
            # fails on line below
            $results2 = New-Object PSObject -Property $details
        }

        $quotient = $counter / 8
        $results | export-csv -Path c:\result"$quotient".csv -noType
        $details = @()
        $results = @()
    }                     
    $counter++           
}
#write out final file if number not divisible by 8
if (-not($counter % 8 -eq 0)) {
    $results += New-Object PSObjectF -Property $details
    $modulo = $counter % 8
    $quotient_plus1 = (($counter-$modulo) / 8) +1
    $results | export-csv -Path C:\result"$quotient_plus1".csv -noType 
}

标签: powershellcsv

解决方案


tl;博士

  • $details = @()应该$details = [ordered] @{}

  • 要使ISE 的重复执行也按预期工作,请在循环之前放置另一个 $details = [ordered] @{}语句。


  • 在第一个循环迭代中,$details最初是undefined$details += $detailsnew并将$detailsnew(有序的)哈希表([ordered] @{ ... }PowerShell 中的哈希表类型为System.Collections.Specialized.OrderedDictionary按原样分配给$details(即,在$details未定义的情况下,+=实际上行为与 相同=)。

  • $detailsnew在接下来的 7 次迭代中创建的哈希表然后被合并+=到已经存储在$details.

  • 在第 8 次迭代之后,您错误地(重新)初始化$details数组(一个哈希表(或任何实现的字典类型)到's参数然后 - 可以预见地 - 失败。@()+=$detailsSystem.Collections.IDictionaryNew-Object-Property

    • 相反,(重新)初始化$details为有序哈希表:$details = [ordered] @{}

在 Powershell ISE 中,如果我重新运行脚本,它也会在第 16 行出错。

PowerShell ISE点源它运行的脚本,这意味着来自先前调用的变量可以保留

顺便说一句:这同样适用于带有PowerShell 扩展的Visual Studio Code,您应该考虑将其迁移到[1]。但是,您可以选择创建一个新的临时会话,如本答案底部所述。

在您的情况下,这意味着当您在 ISE 中重新执行脚本时,它$details已经是第一次迭代中的数组。


[1] PowerShell ISE不再积极开发有理由不使用它(底部)。


推荐阅读