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