【问题标题】:PSCustomObject incorrectly formatting outputPSCustomObject 错误地格式化输出
【发布时间】:2020-04-24 03:15:40
【问题描述】:

我在将数据添加到 PSCustomObject 时遇到问题。

我的脚本使用 Invoke-RestMethod 从 API 请求数据,然后我将其存储在一个变量中,并使用 Select-Object 和 Format-Table 很好地输出它。我遇到的最初问题是响应中返回的日期和时间是 ISO8601 格式,看起来不太好看。因此,使用下面的代码,我将日期和时间格式化为更易读的格式并将其存储在它自己的 PSCustomObject 中,但是在将格式化的日期时间返回到原始 PSCustomObject 时遇到了问题。

在使用 Add-Member 将数据添加到 PSCustomObject 变量之前,数据显示效果很好,但是一旦重新添加,我就会尝试运行诸如 Select-Object 或 Format-Table 之类的命令添加了填充,这完全弄乱了我的输出,但当直接访问它按预期显示的值时。我完全被困在这里如何解决这个问题。 (下面的代码在我使用 Invoke-RESTMethod 并将返回的数据存储到变量之后开始)。

## Extracts the time property from the PSCustomObject and re-formats it to an easily readable format.
$datetime = $HTTPResponse.psobject.Properties.value | Select-Object -Property time
$uDateTimeRegex = $datetime -replace "[@]" -replace "[}]" -replace "[=]" -replace "[{]" -replace "time" -replace "[Z]" -split ' '

ForEach ($SplitTime in $uDateTimeRegex){
    $FormattedDateTimeArray = ($uDateTimeRegex).split('.') | Select-String -Pattern '[a-z]'
}

$CorrectDateTime = @()
$CorrectDateTime = for ($i=0; $i -lt $FormattedDateTimeArray.count; $i++) {
    [datetime]::ParseExact($FormattedDateTimeArray[$i], 'yyyy-MM-ddTHH:mm:ss', $null).ToString('HH:mm dd-MM-yyyy')
}

## Converts the newly created $CorrectDateTime array into a PSCustomObject
$CaseTimeObj = ForEach ($dt in $CorrectDateTime){

    [PSCustomObject]@{
        CaseDateTime = $dt
    }
}
## Uses a foreach loop and Add-Member to add the contents of PSCustomObject $CaseTimeObj to the pre-existing PSCustomObject created from the HTTP reponse
$objProperties = Get-Member -InputObject $CaseTimeObj -MemberType Property
foreach ($p in $objProperties){
    $HTTPResponse | Add-Member -MemberType NoteProperty -Name CaseDateTime -Value $CaseTimeObj.$($p.Name) -Force
}

## Selects required values from PSCustomObject variable and formats them for output
$HTTPOutput = $HTTPResponse.psobject.Properties.value | Select-Object -Property Title, userAssigned, id, CaseDateTime, environment | Format-Table @{L='Case Name';E={$_.Title}}, @{L='Assigned User';E={$_.userAssigned}}, @{L='Case ID';E={$_.id}}, @{L='Creation Time';E={$_.CaseDateTime}}, @{L='Client';E={$_.environment}} 

$HTTPOutput

Output using above code

Output with default HTTP response, no modifying datetime stuff

Directly accessing the values

Accessing the values using Select-Object

按要求编辑,$datetime 变量的内容:

PS > $datetime

time
----
2020-04-23T16:26:44.626Z
2020-04-23T16:27:47.511Z
2020-04-23T16:28:29.394Z
2020-04-23T16:28:58.413Z
2020-04-23T16:29:24.936Z
2020-04-23T16:29:59.462Z
2020-04-23T16:30:31.927Z
2020-04-23T16:31:07.173Z
2020-04-23T16:40:23.39Z

【问题讨论】:

  • 您能否发布一个来自 invoke-restmethod 的 http 响应正文示例、您的预期输出以及您当前以文本而不是图像获得的输出?
  • @mclayton - 很遗憾,我不能,图片不清晰是怎么回事,我可以帮你澄清一下?
  • 要启用测试您的代码,请发布$datetime 集合的前 3 或 4 行的示例。请勿将其作为图像发布,并放入包含在代码中的问题中格式化。 [咧嘴一笑]
  • @Lee_Dailey 添加了该输出。
  • @takeoff127 - 我们的代码显示了一个正则表达式替换,它针对许多不在您显示的示例数据中的字符。这真的是$uDateTimeRegex的内容吗?

标签: powershell


【解决方案1】:

在我看来,你真的过于复杂了。

$HTTPResponse 中的日期采用 ISO8601 格式,因此很容易转换为日期时间对象

您可以使用Get-Date '2020-04-23T16:26:44.626Z'[datetime]::Parse('2020-04-23T16:26:44.626Z') 来执行此操作。

这两种方法都会产生一个日期时间对象,转换为本地时间。 如果您需要日期以保持 UTC,请使用 (Get-Date '2020-04-23T16:26:44.626Z').ToUniversalTime()([datetime]::Parse('2020-04-23T16:26:44.626Z')).ToUniversalTime()

创建一个日期时间对象可以让你以任何你喜欢的方式来格式化它,甚至是(IMO 很奇怪的)'HH:mm dd-MM-yyyy' 字符串格式。

所有这些都可以在计算属性中完成:

$HTTPOutput = $HTTPResponse.psobject.Properties.value | 
              Select-Object -Property @{Name = 'Case Name'; Expression = {$_.Title}}, 
                                      @{Name = 'Assigned User'; Expression = {$_.userAssigned}}, 
                                      @{Name = 'Case ID'; Expression = {$_.id}}, 
                                      @{Name = 'Creation Time'; Expression = { '{0:HH:mm dd-MM-yyyy}' -f [datetime]::Parse($_.time)}}, 
                                      @{Name = 'Client'; Expression = {$_.environment}}

# output on screen
$HTTPOutput | Format-Table -AutoSize

# if you like, output to CSV file
$HTTPOutput | Export-Csv -Path 'X:\TheOutput.csv' -NoTypeInformation

如果您不关心创建 $HTTPOutput 对象数组而只是想在屏幕上显示,那么您可以直接在 Format-Table 上使用相同的计算属性。

这不会返回任何其他内容,而是以表格格式显示在屏幕上的数据:

$HTTPResponse.psobject.Properties.value |
Format-Table @{Name = 'Case Name'; Expression = {$_.Title}}, 
             @{Name = 'Assigned User'; Expression = {$_.userAssigned}}, 
             @{Name = 'Case ID'; Expression = {$_.id}}, 
             @{Name = 'Creation Time'; Expression = { '{0:HH:mm dd-MM-yyyy}' -f [datetime]::Parse($_.time)}}, 
             @{Name = 'Client'; Expression = {$_.environment}}

【讨论】:

  • 是的,所以代码完全符合我的要求......我想我的问题源于没有正确理解 datetime 对象,事实上我并不完全理解你发布的代码,但我会去离开并做进一步的学习。非常感谢您的时间。 (ps为什么我想要的时间格式很奇怪?:D)
  • @takeoff127 谢谢。对我来说很奇怪,因为我以前从未在任何上下文中看到实际日期部分之前的小时和分钟部分。通常,它类似于“dd-MM-yyyy HH:mm”。无论如何,如果这是您在输出中需要的,那就去做吧。
  • 在这种情况下,日期并不重要首先显示。再次感谢,毫不夸张地说,我在发帖之前花了 5 个多小时努力解决这个问题。
猜你喜欢
  • 2017-07-29
  • 1970-01-01
  • 2020-06-09
  • 2019-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多