首先,如果您只是在使用 SQL Server 进行一些快速而肮脏的工作或运行基于文件的脚本,那么您可以省去很多麻烦,只需使用Invoke-Sqlcmd
. 它是由非常聪明的人编写和维护的,因此可能会很好地为您服务。
如果您需要在短时间内运行大量查询并且可以从重用连接中受益。或者想要参数化查询的安全性/完整性SqlConnection
,SqlCommand
并且SqlDataReader
更有意义。
记住 PowerShell 是一个面向管道的结构,我们应该从管道的角度来思考并有效地利用它。也就是说,与其将所有记录转储到 aDataTable
中以再次在下游迭代它们,为什么不利用动态特性 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()
}
}
请不要在没有指定 a 的情况下在生产中使用它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
.