Powershell 中的 Export-CSV 仅输出 numbers/length

Export-CSV in Powershell just outputs numbers/length

我已经调查过这个问题,因为其他人也遇到过这个问题,但我无法真正理解手头的问题,无法真正实施可能提供的任何修复。这是我正在处理的具体内容。

我正在从 API 中获取信息,解析并构建我自己的哈希表,然后将其推入数组。然后我想将该哈希数组导出为简单的 CSV。我在另一个脚本中完成了几乎完全相同的设置并且它没有问题,我无法弄清楚我在这里做错了什么......

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$user    = '*****'
$pass    = ConvertTo-SecureString '******' -AsPlainText -Force
$cred    = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $pass
$base    = '*********'
$url     = '*********'
$content = @()
$res     = $null

function fetch_data([String] $path) {
    $req        = Invoke-WebRequest -Credential $cred -Uri $path -Method GET
    $global:res = ConvertFrom-Json $req
}

function process_data([String] $arg) {
    fetch_data($arg)

    foreach($i in $res.data) {
       $subscription = @{
            'id'                  = $i.id
            'name'                = $i.name
            'sub_name'            = $i.subscriptionFormReference.name
            'owner_id'            = $i.owner.targetName
            'owner_firstName'     = $i.owner.firstName
            'owner_lastName'      = $i.owner.lastName
            'owner_recipientType' = $i.owner.recipientType    
       }

       foreach($x in $i.data.criteria.data) {
            $sub.lob_name   = $x.name
            $sub.lob_owner  = $x.operator
            $sub.lob_values = $x.value
       }
       $subscription = ConvertTo-Json $subscription
       $global:content.add($subscription)
    }

    if ($res.links.next) {
        $link = $base + $res.links.next
        process_data($link)
    }
}

process_data($url)


Write-Host $content


$content | Export-CSV "\*******\TEST_CSV.csv" -NoTypeInformation

输出的文件只是一个单列,数字随着上面数组中存在的对象(我构建的哈希)的数量而下降。我假设这可能是字符串形式的对象的长度,这就是它所识别的,所以它可能是格式问题?

现在,如果我在脚本中将数组打印到屏幕上,我会毫无问题地看到所有哈希表。唯一的区别是它们是 {} 而不是 @{} ,就像我之前提到的另一个脚本一样可以正常工作。

有什么想法吗?

Export-Csv 期望一个或多个 对象 具有构成 "columns" 的属性。您正在向它传递 字符串 .

的列表

在管道传输到 Export-Csv:

之前,您可以使用 Select-Object 从字符串轻松创建一个 属性 对象
$content |Select-Object @{Name='Json';Expression={$_}} |Export-Csv \path\to\test_csv.csv -NoTypeInformation

为了避免用空白字符填充您的 CSV 文件,我进一步建议您使用 ConvertTo-Json-Compress 参数开关:

   $subscription = ConvertTo-Json $subscription -Compress

这将导致 json 如:

{"id":123,"name":"MyName","sub_name":"MySubName","owner_lastName":"Doe","owner_firstName":"John","owner_recipientType":"Manager","owner_id":"Target Name"}

而不是:

{
    "id":  123,
    "name":  "MyName",
    "sub_name":  "MySubName",
    "owner_lastName":  "Doe",
    "owner_firstName":  "John",
    "owner_recipientType":  "Manager",
    "owner_id":  "Target Name"
}
  • 首先:在将 $subscription 实例添加到 $content 之前,不要调用 ConvertTo-Json,因为这会将它们转换为 字符串 ,并将字符串传递给 Export-Csv 只是导出 [string] 类型的唯一 属性、.Length -这就是你看到的。

  • 然而,正如 Lee_Daily 在评论中指出的那样,即使使用 $subscription 哈希表实例 原样 也不会无法解决问题,因为当您将 a hashtable 传递给 Export-Csv 时,它没有进行有意义的序列化;必须使用 [pscustomobject] 实例来代替 ,(在 PSv3+ 中)您可以通过 将哈希表文字 方便地创建为 [pscustomobject];也就是说,使用 $subscription = [pscustomobject] @{ ... } 而不是 $subscription = @{ ... }

  • 如果您的代码是 运行 在 脚本 中,$global:content 不会引用 script 的(顶级)$content 变量,但是,正如范围说明符所建议的,global 变量用那个名字。

  • 但是,即使您使用 $script:content 定位了正确的变量 - 调用 .Add() 来增大数组也不会起作用,因为数组是固定大小集合。

  • 但是,即使您通过 使用 += 而不是 .Add()[=97 来解决这个问题=] 这样的数组效率低下,因为 PowerShell 每次都需要重新创建 数组。

    • 相反,只需 让您的 process_data 函数 直接输出 $subscription 对象(哈希表),这您可以在 PowerShell 隐式为您创建的数组中收集 ,甚至可以直接通过管道传输到 Export-Csv.

总而言之:

# ...

function process_data([String] $arg) {
  fetch_data $arg # Note: Don't put (...) around function arguments.

  foreach($i in $res.data) {
    # Use a [pscustomobject] cast to create a custom object from the hashtable.
    $subscription = [pscustomobject] @{
          'id'                  = $i.id
          'name'                = $i.name
          'sub_name'            = $i.subscriptionFormReference.name
          'owner_id'            = $i.owner.targetName
          'owner_firstName'     = $i.owner.firstName
          'owner_lastName'      = $i.owner.lastName
          'owner_recipientType' = $i.owner.recipientType    
     }

     foreach($x in $i.data.criteria.data) {
          $subscription.lob_name   = $x.name
          $subscription.lob_owner  = $x.operator
          $subscription.lob_values = $x.value
     }
     # Directly output the $subscription custom object in each iteration.
     # This effectively outputs a collection (array) of objects.
     $subscription
  }

  if ($res.links.next) {
      $link = $base + $res.links.next
      process_data($link)
  }

}

# Call the function and collect the objects in an array.
$content = process_data $url # Note: Don't put (...) around function arguments

Write-Host $content

$content | Export-CSV "\*******\TEST_CSV.csv" -NoTypeInformation