通过函数调用从 PSObject 进行奇怪的 Object[] 转换
Weird Object[] casting from PSObject through a function call
我目前正在编写一个能够将 ADO(来自电子邮件的 EML 附件)转换为 PSObject 的函数。代码存根如下所示:
function Get-OriginalMailAttributes([__ComObject]$email){
#.DESCRIPTION Downloads in Temp the attachment and open it.
# Returns PSObjectwith values.
#STEP 1: Download EML
$TEMPFILE = "..."
if($email.Attachments.Count){
$attachment=$email.Attachments|?{$_.Filename.endsWith(".eml")} | select -First 1
$fileName = $TEMPFILE + $(New-Guid | select -exp Guid) + ".eml"
$attachment.SaveAsFile($fileName)
#STEP2 : Retrieve EML Objects
$adoDbStream = New-Object -ComObject ADODB.Stream
$adoDbStream.Open()
$adoDbStream.LoadFromFile($fileName)
$cdoMessage = New-Object -ComObject CDO.Message
$cdoMessage.DataSource.OpenObject($adoDbStream, "_Stream")
#STEP 3: Bind values
$attributes = New-Object PSObject -Property @{
From = [string]($cdoMessage.Fields.Item("urn:schemas:mailheader:from").Value.toString())
}
#STEP 4: Cleanup
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($cdoMessage)
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($adoDbStream)
Remove-Item $fileName
return $attributes
# Note that the debugger acknowledge the fact that $attributes is PSObject.
}
}
然后我会在某个时候调用该函数:
$sender_raw = Get-OriginalMailAttributes $email
$sender_raw.getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
$sender_raw
0
0
From
----
"Bob" <dummy@contoso.com>
$sender_raw.From # Crashes.
这种行为从何而来?
通常,当您在函数的输出中有“额外”值时,这是因为您正在调用具有 return 值的方法,而不是处理这些值。
.Add() 方法因输出已添加项目的索引而臭名昭著。
为避免此问题,您有以下几种选择:
- 转换为无效:[void]$collection.Add($item)
- 分配给 $null:$null=$collection.Add($item)
- 管道到 out-null:$collection.Add($item) | out-null
我在您的代码中没有看到任何明显的方法,但是在整个代码中添加 Write-output 'Before Step 1'
等应该可以清楚地说明违规语句的位置。
这种奇怪的行为来自 multi-returns 来自 PowerShell 函数。
PS> function f() {
1+1
return 4
}
PS> f
2
4
简而言之,如果 one-liners 是 returning 值,它们将作为 Object[]
数组添加到输出中。
虽然这是处理函数的 return 值的一种特别混乱的方式,但我对我的代码的解决方案是重定向输出 NULL:
stub...
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($cdoMessage) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($adoDbStream) | Out-Null
我目前正在编写一个能够将 ADO(来自电子邮件的 EML 附件)转换为 PSObject 的函数。代码存根如下所示:
function Get-OriginalMailAttributes([__ComObject]$email){
#.DESCRIPTION Downloads in Temp the attachment and open it.
# Returns PSObjectwith values.
#STEP 1: Download EML
$TEMPFILE = "..."
if($email.Attachments.Count){
$attachment=$email.Attachments|?{$_.Filename.endsWith(".eml")} | select -First 1
$fileName = $TEMPFILE + $(New-Guid | select -exp Guid) + ".eml"
$attachment.SaveAsFile($fileName)
#STEP2 : Retrieve EML Objects
$adoDbStream = New-Object -ComObject ADODB.Stream
$adoDbStream.Open()
$adoDbStream.LoadFromFile($fileName)
$cdoMessage = New-Object -ComObject CDO.Message
$cdoMessage.DataSource.OpenObject($adoDbStream, "_Stream")
#STEP 3: Bind values
$attributes = New-Object PSObject -Property @{
From = [string]($cdoMessage.Fields.Item("urn:schemas:mailheader:from").Value.toString())
}
#STEP 4: Cleanup
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($cdoMessage)
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($adoDbStream)
Remove-Item $fileName
return $attributes
# Note that the debugger acknowledge the fact that $attributes is PSObject.
}
}
然后我会在某个时候调用该函数:
$sender_raw = Get-OriginalMailAttributes $email
$sender_raw.getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
$sender_raw
0
0
From
----
"Bob" <dummy@contoso.com>
$sender_raw.From # Crashes.
这种行为从何而来?
通常,当您在函数的输出中有“额外”值时,这是因为您正在调用具有 return 值的方法,而不是处理这些值。
.Add() 方法因输出已添加项目的索引而臭名昭著。
为避免此问题,您有以下几种选择:
- 转换为无效:[void]$collection.Add($item)
- 分配给 $null:$null=$collection.Add($item)
- 管道到 out-null:$collection.Add($item) | out-null
我在您的代码中没有看到任何明显的方法,但是在整个代码中添加 Write-output 'Before Step 1'
等应该可以清楚地说明违规语句的位置。
这种奇怪的行为来自 multi-returns 来自 PowerShell 函数。
PS> function f() {
1+1
return 4
}
PS> f
2
4
简而言之,如果 one-liners 是 returning 值,它们将作为 Object[]
数组添加到输出中。
虽然这是处理函数的 return 值的一种特别混乱的方式,但我对我的代码的解决方案是重定向输出 NULL:
stub...
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($cdoMessage) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($adoDbStream) | Out-Null