Во-первых, если вы просто выполняете какую-то быструю и грязную работу с SQL Server или запускаете скрипты на основе файлов, избавьте себя от массы проблем и просто используйте Invoke-Sqlcmd
. Он написан и поддерживается действительно умными людьми, так что, вероятно, сослужит вам хорошую службу.
Если вам нужно выполнить много запросов за короткий период и вы можете извлечь выгоду из повторного использования вашего соединения. Или хотите безопасность/целостность параметризованных запросов, SqlConnection
, SqlCommand
и SqlDataReader
имеют больше смысла.
Принимая во внимание, что PowerShell является конструкцией, ориентированной на конвейер, нам надлежит думать с точки зрения конвейера и эффективно использовать его. Тем не менее, вместо того, чтобы сбрасывать все записи в DataTable
только для повторной итерации их ниже по течению, почему бы не использовать динамическую природу PowerShell и передать «обратный вызов» (то есть [ScriptBlock]
) для выполнения некоторой операции над каждым IDataRecord
при повторении IDataReader
.
Для следующей функции Invoke-SqlCommand
требуются: строка подключения, запрос и обратный вызов, которые можно использовать для прогнозирования/анализа строк и т. д.
Примечание. Если требуется постоянное значение SqlConnection
, просто замените параметр $ConnectionString
на $Connection
.
function Invoke-SqlCommand {
param(
[Parameter(Mandatory=$True,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True,
HelpMessage="The connection string.")]
[string] $ConnectionString,
[Parameter(Mandatory=$True,
HelpMessage="The query to run.")]
[string] $Query,
[Parameter(Mandatory=$True,
HelpMessage="The work to perform against each IDataRecord.")]
[scriptblock] $ScriptBlock
)
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = $ConnectionString
$cmd = $conn.CreateCommand()
$cmd.CommandText = $Query
try {
$conn.Open()
$rd = $cmd.ExecuteReader()
while($rd.Read()){
Write-Output (Invoke-Command $ScriptBlock -ArgumentList $rd)
}
}
finally {
$conn.Close()
}
}
Пожалуйста, не используйте это в рабочей среде без указания catch {...}
, опущенного здесь для краткости.
Этот формат дает вам возможность выполнять некоторые операции и проекции для каждого IDataRecord
И передавать его в конвейер для последующей обработки.
$connectionString = "your connection string"
$query = "SELECT * FROM users"
Invoke-SqlCommand $connectionString $query {
param(
[Parameter(Mandatory=$True)]
[System.Data.SqlClient.SqlDataReader]$rd)
$obj = New-Object -TypeName PSObject -Property @{ user_id = $rd.GetValue($rd.GetOrdinal("geoname_id"))}
$obj.psobject.typenames.insert(0,'MyAwesome.Object')
Write-Output $obj
}
Использование New-Object
здесь просто для обеспечения согласованного порядка полей без необходимости полагаться на упорядоченную хеш-таблицу и помогает нам легче идентифицировать наши пользовательские PSObject
при запуске таких вещей, как Get-Member
.
person
pim
schedule
16.05.2019
+=
. Вот пример - person KyleMit   schedule 15.01.2016