question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ParameterBindingArgumentTransformationException while attempting to pass an array of class objects to a function

See original GitHub issue

Steps to reproduce

Module.psm1

class CosmosDbDatabase {
  [string]$Name;
  [bool]$Autoscale;
  [int]$Throughput;

  CosmosDbDatabase() {
  }

  CosmosDbDatabase([string]$Name, [bool]$Autoscale, [string]$Throughput) {
    $this.Name = $Name;
    $this.Autoscale = $Autoscale;
    $this.Throughput = $Throughput;
  }
}

function Invoke-MyFunction() {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $True)][CosmosDbDatabase[]]$Databases
  )

 # do stuff inside
}

Script.ps1

using module Module.psm1

Import-Module Module.psm1 -Force;

[hashtable]$arguments = @{
  "Databases" = @(
      # [CosmosDbDatabase]::new("Database1", $true, 4000),
      # [CosmosDbDatabase]::new("Database2", $false, 400)
    (New-Object CosmosDbDatabase -Property @{
      "Name"        = "Database1";
      "Autoscale"   = $true
      "Throughput"  = 4000;
    }),
    (New-Object CosmosDbDatabase -Property @{
      "Name"        = "Database2";
      "Autoscale"   = $false
      "Throughput"  = 400;
    })
  );
};

Invoke-MyFunction @arguments;

Expected behavior

I’m expecting the function to be invoked with all parameters bound successfully, given the fact that I’m using strong typing.

Actual behavior

I’m getting a ParameterBindingArgumentTransformationException saying

Cannot process argument transformation on parameter 'Databases'. Cannot convert the "CosmosDbDatabase" value of type "CosmosDbDatabase" to type "CosmosDbDatabase".
Trace-Command -Name ParameterBinding -Expression {Deploy-AzureCosmosDB @arguments} -PSHost;

yields

DEBUG: 2020-11-24 18:14:04.4883 ParameterBinding Information: 0 :     BIND arg [System.Object[]] to parameter [Databases]
DEBUG: 2020-11-24 18:14:04.4884 ParameterBinding Information: 0 :         Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: 2020-11-24 18:14:04.4887 ParameterBinding Information: 0 :             ERROR: DATA GENERATION: Cannot convert the "CosmosDbDatabase" value of type "CosmosDbDatabase" to type "CosmosDbDatabase".

Apparently I’m attempting to pass a [System.Object[]] ? How can I ensure that the type is as expected? I’ve checked Write-Host ($arguments["Databases"].GetType().FullName); before the invocation of my function and got [CosmosDbDatabase[]] in return as expected. Could this be happening during the splatting?

Callstack

"   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)"

Environment data

Name                           Value
----                           -----
PSVersion                      7.1.0
PSEdition                      Core
GitCommitId                    7.1.0
OS                             Darwin 19.6.0 Darwin Kernel Version 19.6.0: Thu Oc…
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:3
  • Comments:17 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
SeeminglySciencecommented, Jan 4, 2021
  1. Unlike functions, once a class is defined in a PS session it can NOT be modified.

It’s a little bit more complicated than that. They can be modified (well sort of, a new type is generated and type resolution is changed to point to the new version) if they weren’t imported using using module X. For example, if the class is used purely for internal module logic and not exposed as a public API, Import-Module X -Force will work in most cases. The new module session state will point to the new class just like expected.

On the subject of adding a using module X -Force, the complication there is that it’s a parse time concept. There are a lot of bits in the compiler where the type is currently cached that would need to be invalidated. That’s not impossible, but getting that to work right is a large work item.

Another problem that would need to be solved is subclasses. Lets say you have these files:

# ModuleX.psm1
class Foo { }
# Bar.ps1
using module ModuleX
class Bar : Foo { }
# Bar2.ps1
using module ModuleX -Force
class Bar2 : Foo { }
# Main.ps1
. ./Bar.ps1
. ./Bar2.ps1

Update-Module ModuleX
. ./Bar2.ps1

After the last line of Main.ps1, what does Bar inherit now? Is the type recreated because Bar2.ps1 has -Force? Or are they just now incompatible with each other? What if the new version has breaking changes that Bar2.ps1 expects, but Bar.ps1 doesn’t?

1reaction
SeeminglySciencecommented, Nov 24, 2020

Does your example repro the problem for you? I can’t get it to error.

Anyway, my guess without repro is that it’s related this these lines:

using module Module.psm1

Import-Module Module.psm1 -Force

Try taking out the Import-Module line. There are some circumstances where you could be creating two instances of the module, importing the types from the first, and importing the commands from the second. That shouldn’t really happen outside of design time though.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Trying and failing to pass an array of custom objects by ...
In the function the .Count I'm calling will increment as workstations are added to the list. But After the function is called the...
Read more >
[SOLVED] Passing array of objects to a function - PowerShell
Solution: You can't pass an array of objects to the Process block that way - it will process the entire array at once...
Read more >
Passing an array of objects to a function using the Pipleline
When I pass it an array of objects, I get "The input object cannot be found to any parameters for the command either...
Read more >
Passing array of objects as parameter in C++
In the main() function, objects of the Student class are created: Here, the first array of objects is s[3] and the other one...
Read more >
PowerShell - Few tricks about HashTables and Arrays I wish I ...
I've been working with PowerShell for a while now and like with most things I do I've learned it by doing and not...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found