You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell远程传递System.Data.DataTable遇问题,求简化或无转换方案

PowerShell远程传递System.Data.DataTable的问题与解决

问题场景

尝试通过Invoke-Command向远程主机传递System.Data.DataTable类型变量时,两种传递方式均报错,且在PowerShell 5.1和7.2版本中问题一致。

尝试1:使用ArgumentList传递

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

执行报错:

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

尝试2:使用$using:传递变量

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

执行报错:

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

问题原因

PowerShell远程传输时,会自动将System.Data.DataTable序列化为XML格式,在远程主机反序列化后,原类型信息丢失,被转换为System.Collections.ArrayList,无法直接转回DataTable,这是PowerShell远程序列化机制的已知限制。

现有手动序列化实现

通过手动将DataTable序列化为带Schema的XML,传递后再反序列化还原,实现了类型保留,但代码依赖临时文件,较为繁琐:

方案1:ArgumentList传递XML字符串

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

方案2:$using:传递XML字符串

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

简化方案与结论

1. 简化手动序列化实现(无需临时文件)

可以直接在内存中完成XML的序列化与反序列化,省去磁盘操作,代码更简洁高效:

function Send-DataTableRemotely {
    param(
        [Parameter(Mandatory)]
        [System.Data.DataTable]$Table,
        [Parameter(Mandatory)]
        [string]$ComputerName
    )

    # 内存中序列化DataTable为带Schema的XML字符串
    $xmlWriter = New-Object System.IO.StringWriter
    $Table.WriteXml($xmlWriter, [System.Data.XmlWriteMode]::WriteSchema)
    $xmlContent = $xmlWriter.ToString()
    $xmlWriter.Dispose()

    # 远程执行反序列化并处理
    Invoke-Command -ComputerName $ComputerName -Authentication Negotiate -ScriptBlock {
        param($XmlContent)
        $xmlReader = New-Object System.IO.StringReader($XmlContent)
        $ds = New-Object System.Data.DataSet
        $ds.ReadXml($xmlReader, [System.Data.XmlReadMode]::ReadSchema)
        $xmlReader.Dispose()
        
        $remoteTable = $ds.Tables[0]
        Write-Host "远程端DataTable类型: $($remoteTable.GetType().FullName)"
        # 在此添加对remoteTable的业务操作
        return $remoteTable
    } -ArgumentList $xmlContent
}

# 测试示例
$testTable = New-Object System.Data.DataTable "TestTable"
$testTable.Columns.Add("ID", [int])
$testTable.Rows.Add(1)
Send-DataTableRemotely -Table $testTable -ComputerName '192.168.0.5'

2. 是否存在无需转换的传递方法?

没有。PowerShell远程使用的CLIXML序列化机制无法保留System.Data.DataTable的完整类型信息,传输后必然会被转换为ArrayList,因此必须通过手动序列化/反序列化的方式来保留类型。

内容的提问来源于stack exchange,提问作者Vladimir1211

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:25:55