Powershell — невозможно преобразовать значение типа System.Management.Automation.PSCustomObject в тип System.Management.Automation.PSCustomObject

Я работаю с Powershell 4 под Windows 7, и у меня есть командлет, определенный следующим образом:

 Function Transfer-File {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$true)]
        [System.Management.Automation.PSCustomObject]
        $source,

        # other parameters removed for brevity
    )

    # actual logic does not matter 

  }

Я вызываю это так:

$hasError = Transfer-File -source $source -destination $cfg.Destination -logfile $logFile

$source получается путем разбора файла JSON и выглядит так:

@{Path=some path string here; Pack=False}

Write-Host $source.GetType() выходы:

System.Management.Automation.PSCustomObject

Я получаю следующую ошибку:

Невозможно преобразовать значение "@{Path=некоторая строка пути здесь; Pack=False}" типа "System.Management.Automation.PSCustomObject" в тип "System.Management.Automation.PSCustomObject".

В отчаянной попытке решить ее эмпирическим путем я заменил System.Management.Automation.PSCustomObject на psobject, и, похоже, все работает нормально.

Вопрос. Почему мой System.Management.Automation.PSCustomObject не соответствует System.Management.Automation.PSCustomObject из прототипа командлета?


Полный код для создания объекта:

### Configuration ###
$cfg = New-Object –TypeName PSObject
$cfg | Add-Member -MemberType NoteProperty –Name Sources –Value @()

# get configuration from json file
$jsonContent = Get-Content .\config.json |  Out-String
$jsonObj = ConvertFrom-Json $jsonContent
$cfg.Sources = $jsonObj.Sources

Foreach ($source in $cfg.Sources)
{
    # Write-Host $source.GetType()
    $hasError = Transfer-File -source $source -destination $cfg.Destination -logfile $logFile
}

person Alexei - check Codidact    schedule 07.03.2018    source источник
comment
Проверьте это и эта ссылка!   -  person Vivek Kumar Singh    schedule 07.03.2018
comment
Как вы создали объект $source? Через New-Object?   -  person tukan    schedule 07.03.2018
comment
[System.Management.Automation.PSCustomObject] — это одноэлементный объект, экземпляр которого используется для представления того факта, что в [System.Management.Automation.PSObject] нет значимого базового объекта.   -  person user4003407    schedule 07.03.2018


Ответы (1)


Как следует из комментария @VivekKumarSingh, это ошибка, связанная с ускорителем.

Так не пойдет:

# Error
$y = [System.Management.Automation.PSCustomObject]@{Path='some path string here'; Pack=$False}

И это не сработает:

$y = [PSCustomObject]@{Path='some path string here'; Pack=$False}

function t ([System.Management.Automation.PSCustomObject]$x) { $x }

# Error
t $y

Это будет работать:

$y = [PSCustomObject]@{Path='some path string here'; Pack=$False}

function t ([PSCustomObject]$x) { $x }

t $y

Однако в приведенном выше примере ничего не будет приведено к типу PSCustomObject, потому что этот тип наследуется от Object:

PS> function t ([PSCustomObject]$x) { $x.GetType().FullName }
PS> t 5
System.Int32
PS> t 'asdf'
System.String
PS> t $(Get-ChildItem)
System.Object[]
PS> t $(Get-Item .)
System.IO.DirectoryInfo

Это также будет работать, но я не совсем уверен, что это эквивалентно 100%.

function t ([System.Management.Automation.PSObject]$x) { $x }

Причина, по которой я не уверен, заключается в этой странности:

PS> $a = New-Object -TypeName System.Management.Automation.PSObject -Property @{Path='some path string here'; Pack=$False}
PS> $a.GetType().FullName
System.Management.Automation.PSCustomObject

PS> $a = New-Object -TypeName System.Management.Automation.PSCustomObject -Property @{Path='some path string here'; Pack=$False}
New-Object : A constructor was not found. Cannot find an appropriate constructor for type System.Management.Automation.PSCustomObject.

PS> $a = [PSCustomObject]@{Path='some path string here'; Pack=$False}
PS> $a.GetType().FullName
System.Management.Automation.PSCustomObject

PS> $a = [System.Management.Automation.PSObject]@{Path='some path string here'; Pack=$False}
PS> $a.GetType().FullName
System.Collections.Hashtable

PS> $a = [PSObject]@{Path='some path string here'; Pack=$False}
PS> $a.GetType().FullName
System.Collections.Hashtable

Насколько мне известно, [PSCustomObject] и [PSObject] являются ускорителями для System.Management.Automation.PSObject. System.Management.Automation.PSCustomObject — это просто деталь реализации, которую они добавили, чтобы сделать [PSCustomObject] возможным, но, к сожалению, то, как все работает, кажется немного непоследовательным. Однако я не совсем понимаю, для чего нужен ускоритель типа [PSObject]. Кажется, что он ничего не делает, но он определенно существует:

PS> ([System.Management.Automation.Cmdlet]).Assembly.GetType('System.Management.Automation.TypeAccelerators')::Get.ContainsKey('psobject')
True
person Bacon Bits    schedule 07.03.2018