Here is a script in which I am trying to pass a variable of type System.Data.DataTable via invoke-command to the remote host:
function Test1 { param ( [System.Data.DataTable] $Table ) process { [PSCustomObject]$OptionsInvokeCommand = @{ ComputerName = '192.168.0.5' Authentication = 'Negotiate' ArgumentList = [System.Data.DataTable]$Table } write-host $Table.GetType() write-host $OptionsInvokeCommand.ArgumentList[0].GetType() [System.Management.Automation.ScriptBlock]$ScriptBlock = { param ( [System.Data.DataTable]$Table ) process { write-host $Table.GetType() } } Invoke-Command @OptionsInvokeCommand -ScriptBlock $ScriptBlock } } $Table = New-Object System.Data.DataTable Test1 -Table $Table It says:
Cannot process argument transformation on parameter 'Table'. Cannot convert the "System.Collections.ArrayList" value of type "System.Collections.ArrayList" to type "System.Data.DataTable". + CategoryInfo : InvalidData: (:) [], ParameterBindin...mationException + FullyQualifiedErrorId : ParameterArgumentTransformationError + PSComputerName : 192.168.0.5 I also tried passing a variable without an ArgumentList:
function Test2 { param ( [System.Data.DataTable] $Table ) process { [PSCustomObject]$OptionsInvokeCommand = @{ ComputerName = '192.168.0.5' Authentication = 'Negotiate' } write-host $Table.GetType() [System.Management.Automation.ScriptBlock]$ScriptBlock = { process { [System.Data.DataTable]$Table = $using:Table write-host $Table.GetType() } } Invoke-Command @OptionsInvokeCommand -ScriptBlock $ScriptBlock } } $Table = New-Object System.Data.DataTable Test2 -Table $Table But It also says:
Cannot process argument transformation on parameter 'Table'. Cannot convert the "System.Collections.ArrayList" value of type "System.Collections.ArrayList" to type "System.Data.DataTable". + CategoryInfo : InvalidData: (:) [], ParameterBindin...mationException + FullyQualifiedErrorId : ParameterArgumentTransformationError + PSComputerName : 192.168.0.5 I tried Powershell versions 5.1 and 7.2.
How do I pass a variable System.Data.DataTable to remote host without converting it to another type?
Addition (2025.05.15):
I've read the information here (thanks @SantiagoSquarzon). PowerShell cannot transfer System.Data.DataTable to the remote server. And that's why PowerShell, hidden from the user, converts System.Data.DataTable to Xml (serialization) on the local host. And then PowerShell does the reverse conversion of Xml to System.Data.DataTable (deserialization) on the remote host. When PowerShell does this, it corrupts the data and the reverse transformation becomes impossible. This is a PowerShell bug! Don't say it's not true. You're just used to it, but it's a bug! Since PowerShell cannot correctly perform this operation on its own, I tried to do it for it. And I did it.:
function Test1 { param ( [System.Data.DataTable] $Table ) process { [string]$TmpPath = New-TemporaryFile $Table.WriteXml($TmpPath, [Data.XmlWriteMode]::WriteSchema) [string[]]$XmlString = Get-content $TmpPath Remove-Item -Force $TmpPath [PSCustomObject]$OptionsInvokeCommand = @{ ComputerName = '192.168.0.5' Authentication = 'Negotiate' ArgumentList = ,[string[]]$XmlString } write-host $Table.GetType() [System.Management.Automation.ScriptBlock]$ScriptBlock = { param ( [string[]]$XmlString ) process { [string]$TmpPath = New-TemporaryFile Out-File -InputObject $XmlString -FilePath $TmpPath -Encoding utf8 $Ds = New-Object Data.DataSet $Ds.ReadXml($TmpPath, [Data.XmlReadMode]::ReadSchema) $Table = $Ds.Tables[0] Remove-Item -Force $TmpPath write-host $Table.GetType() } } [void](Invoke-Command @OptionsInvokeCommand -ScriptBlock $ScriptBlock) } } $Table = New-Object System.Data.DataTable NameOfTable Test1 -Table $Table function Test2 { param ( [System.Data.DataTable] $Table ) process { [string]$TmpPath = New-TemporaryFile $Table.WriteXml($TmpPath, [Data.XmlWriteMode]::WriteSchema) [string[]]$XmlString = Get-content $TmpPath Remove-Item -Force $TmpPath [PSCustomObject]$OptionsInvokeCommand = @{ ComputerName = '192.168.0.5' Authentication = 'Negotiate' } write-host $Table.GetType() [System.Management.Automation.ScriptBlock]$ScriptBlock = { process { [string[]]$XmlString = $using:XmlString [string]$TmpPath = New-TemporaryFile Out-File -InputObject $XmlString -FilePath $TmpPath -Encoding utf8 $Ds = New-Object Data.DataSet $Ds.ReadXml($TmpPath, [Data.XmlReadMode]::ReadSchema) $Table = $Ds.Tables[0] Remove-Item -Force $TmpPath write-host $Table.GetType() } } [void](Invoke-Command @OptionsInvokeCommand -ScriptBlock $ScriptBlock) } } $Table = New-Object System.Data.DataTable NameOfTable Test2 -Table $Table But this greatly complicates the code. Can someone simplify this?
And again, maybe it's possible to do without converting variables?