Вы - жертва PowerShell, пытаясь быть слишком дружелюбным
Когда PowerShell видит DataTable
, передаваемую из функции в конвейере, он пытается распутать его и отправить отдельные строки в нисходящем направлении по очереди.
Это может быть чрезвычайно полезно при фильтрации набора данных, например, из запроса к базе данных, но, очевидно, крайне разочаровывает, если вы полагаетесь на некоторое внутреннее поведение DataTable
.
Чтобы PowerShell не распутывал строки, используйте Write-Output $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
{
[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)
}
Бонус проверки безопасности!
Я не могу с чистой совестью ответить на этот вопрос, не указав, что ваша функция в настоящее время подвержена простейшей форме внедрения SQL.
Что если пользователь должен передать нечисловое значение в качестве значения аргумента параметра $start
или $end
? Что делать, если кто-то решил сделать:
$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)
Лучшее решение - параметризовать ваш 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
Таким образом, никакие злые строковые значения не попадут в запрос без очистки