Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell 为什么DataTable.Load的结果只有一行,就好像它是DataRow而不是DataTable一样?_Powershell_Datatable - Fatal编程技术网

Powershell 为什么DataTable.Load的结果只有一行,就好像它是DataRow而不是DataTable一样?

Powershell 为什么DataTable.Load的结果只有一行,就好像它是DataRow而不是DataTable一样?,powershell,datatable,Powershell,Datatable,我想在不同服务器上的两个数据库中查询相同类型的信息,并将结果合并到一个列表中 我创建了这个示例,它可以工作,但前提是第一个服务器至少返回两行 该示例使用整数列表1。。5,但我的原始代码连接两个字符串列表也有同样的问题 # 'quick and dirty' sample # to be considered insecure, # do not use as a basis for production code. function GetData($dbserver, $start, $end

我想在不同服务器上的两个数据库中查询相同类型的信息,并将结果合并到一个列表中

我创建了这个示例,它可以工作,但前提是第一个服务器至少返回两行

该示例使用整数列表1。。5,但我的原始代码连接两个字符串列表也有同样的问题

# 'quick and dirty' sample
# to be considered insecure,
# do not use as a basis for production code.
function GetData($dbserver, $start, $end)
{
    $qry = "WITH q AS (SELECT  $start AS num UNION ALL SELECT num + 1 FROM q WHERE num < $end) SELECT * FROM q"
    $con = New-Object System.Data.SqlClient.SqlConnection
    $con.ConnectionString = "server=$dbserver;database=A2SDataCentral;Integrated Security=SSPI"
    $con.Open()
    $com = $con.CreateCommand()
    $com.CommandText = $qry
    $res = $com.ExecuteReader()
    $table = New-Object System.Data.DataTable
    $table.Load($res)
    return $table
}

$all = $null # erase any result remaining from a previous run
$t1 = GetData "(local)" 1 2
$t2 = GetData "(local)" 3 5
$all = $t1 + $t2
$all
它与

方法调用失败,因为[System.Data.DataRow]不包含名为“op_Addition”的方法

因此,如果结果中只有一行,则GetData函数返回的不是DataTable,而是DataRow

我试过这个,但也不是解决办法:

$all = $t1
$all.Rows.Add($t2)
这将抛出集合的固定大小$t1有2行,或者不能对空值表达式调用方法$t1有1行

有人能解释为什么只有一行的结果会导致多行的不同行为吗

编辑:请注意脚本的示例/不安全性质

您是PowerShell的受害者,试图表现得过于友好 当从管道上的函数传递PowerShell时,它会尝试分解它并逐个发送下游

例如,当从db查询中筛选数据集时,这可能非常有用,但如果您依赖于某些内在的DataTable行为,则显然非常令人沮丧

若要避免PowerShell分解行,请使用写入输出$table-NoEnumerator或-如果向函数添加CmdletBinding属性-可以直接调用$PSCmdlet.WriteObject$table,$false:

function GetData($dbserver, $start, $end)
{
    $qry = "WITH q AS (SELECT  $start AS num UNION ALL SELECT num + 1 FROM q WHERE num < $end) SELECT * FROM q"
    $con = New-Object System.Data.SqlClient.SqlConnection
    $con.ConnectionString = "server=$dbserver;database=A2SDataCentral;Integrated Security=SSPI"
    $con.Open()
    $com = $con.CreateCommand()
    $com.CommandText = $qry
    $res = $com.ExecuteReader()
    $table = New-Object System.Data.DataTable
    $table.Load($res)

    Write-Output $table -NoEnumerate
}
祝贺您,我现在拥有您的数据库服务器:

在此特定情况下,您可以轻松降低此风险,但必须键入以下参数:

function GetData([string]$dbServer, [int]$start, [int]$end)
{
...

更好的解决方案是参数化SQL查询:

$qry = "WITH q AS (SELECT @start AS num UNION ALL SELECT num + 1 FROM q WHERE num < @end) SELECT * FROM q"
# ...
$com.Parameters.Add('@start','Int').Value = $start
$com.Parameters.Add('@end','Int').Value = $end

这样一来,没有经过清理的恶意字符串值就不会潜入查询中

return$table->Write Output$table-NoEnumerate@Matthias:这确实解决了问题,但为什么?在调用之后,我已经将结果转储到控制台,结果仍然完全相同:第一次调用一个数据行,第二次调用4个数据行。为什么是DataRows数组而不是DataTable?我也添加了一个正确的答案,请清理SQL查询!你有没有找到其他不使用写输出的方法来实现循环?谢谢,这就解决了问题。关于清理SQL查询,一方面你是对的,但另一方面,这是Powershell,不是网站设计之类的。这是管理计算机上管理脚本中的本地函数。没有人能够访问该函数来执行sql注入,也没有人能够启动osql.exe或sqlcmd.exe以在一半的时间和十分之一的工作量内获得两倍的数据库访问。而且,示例代码中的sql被标记为一个伪sql,它的意思是作为一种快速且非常脏的方式来生成一些数据行,仅此而已。
function GetData
{
    [CmdletBinding()]
    param($dbserver, $start, $end)

    $qry = "WITH q AS (SELECT  $start AS num UNION ALL SELECT num + 1 FROM q WHERE num < $end) SELECT * FROM q"
    $con = New-Object System.Data.SqlClient.SqlConnection
    $con.ConnectionString = "server=$dbserver;database=A2SDataCentral;Integrated Security=SSPI"
    $con.Open()
    $com = $con.CreateCommand()
    $com.CommandText = $qry
    $res = $com.ExecuteReader()
    $table = New-Object System.Data.DataTable
    $table.Load($res)

    $PSCmdlet.WriteObject($table,$false)
}
$untrustedUserInput = '0 OR 1 = 1; xp_cmdshell "cmd /c calc.exe" --'
function GetData([string]$dbServer, [int]$start, [int]$end)
{
...
param([string]$dbServer, [int]$start, [int]$end)
$qry = "WITH q AS (SELECT @start AS num UNION ALL SELECT num + 1 FROM q WHERE num < @end) SELECT * FROM q"
# ...
$com.Parameters.Add('@start','Int').Value = $start
$com.Parameters.Add('@end','Int').Value = $end