如何从PowerShell运行SQL Server查询?


161

有没有办法在本地计算机上使用Powershell在SQL Server上执行任意查询?

Answers:


166

对于仅需要使用.net和PowerShell(未安装其他SQL工具)来执行此操作的其他人,这里是我使用的功能:

function Invoke-SQL {
    param(
        [string] $dataSource = ".\SQLEXPRESS",
        [string] $database = "MasterData",
        [string] $sqlCommand = $(throw "Please specify a query.")
      )

    $connectionString = "Data Source=$dataSource; " +
            "Integrated Security=SSPI; " +
            "Initial Catalog=$database"

    $connection = new-object system.data.SqlClient.SQLConnection($connectionString)
    $command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
    $connection.Open()

    $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
    $dataset = New-Object System.Data.DataSet
    $adapter.Fill($dataSet) | Out-Null

    $connection.Close()
    $dataSet.Tables

}

我一直在使用它很长时间,我不知道是谁编写了哪些部分,但这是从其他示例中摘录的,但是为了清楚起见简化了,只需要什么而没有额外的依赖关系或功能。

我经常使用和共享它,以至于我已经在GitHub上将其变成了脚本模块,因此您现在可以转到模块目录并执行git clone https://github.com/ChrisMagnuson/InvokeSQL,从那时起,您将在使用它时自动加载invoke-sql(假设您使用的是Powershell v3或更高版本)。


在这里还是在Powershell中处置都没有关系?
马斯洛2014年

2
@Maslow我不能肯定地说,我知道在不处理对象的情况下可以正常工作,但是如果您有单个powershell.exe进程,它将在数周内多次调用此命令而不关闭,则最终可能是一个问题,但是您将不得不测试。
克里斯·马格努森

1
请注意,如果脚本依赖于从依赖于用户输入的源中读取查询数据,则这将迫使您编写可能受到sql注入攻击的脚本。
Joel Coehoorn 2014年

4
@AllTradesJack Google Sql注入。Invoke-Sql命令没有办法将参数与命令文本分开。这几乎可以保证您使用字符串连接来构建查询,这是一个很大的禁忌。
Joel Coehoorn

1
对我来说效果很好。对于任何想知道的人,要放置一个对象,只需添加$connection.dispose()等即可。我不知道它是否有任何不同
Nick.McDermaid

101

您可以使用Invoke-Sqlcmdcmdlet

Invoke-Sqlcmd -Query "SELECT GETDATE() AS TimeOfQuery;" -ServerInstance "MyComputer\MyInstance"

http://technet.microsoft.com/zh-CN/library/cc281720.aspx


22
有人应该提到,如果您使用的是sql server,这可能很棒,但是如果您使用的是工作站,那么就不算什么了……
aikeru 2013年

10
您可以在安装了SQL Server客户端工具(SSMS)的任何位置运行此命令。无论是否在运行SQL Server,它都可以在任何工作站上正常运行。
alroc

3
使用以下导入使cmdlet可用: Import-Module "sqlps" -DisableNameChecking
xx1xx 2014年

1
如果您仍在使用SQL 2008 R2,则需要使用替代
Vincent De Smet

2
Invoke-SqlCmd是奇怪的边缘情况和行为不一致的无尽噩梦。为什么有时会输出列而不是其他时间?我的错误信息在哪里?为什么在一台计算机上或另一台计算机上没有?如何安装?每个问题的答案都比最后一个答案差。
Pxtl

28

这是我在此Blog上找到的示例。

$cn2 = new-object system.data.SqlClient.SQLConnection("Data Source=machine1;Integrated Security=SSPI;Initial Catalog=master");
$cmd = new-object system.data.sqlclient.sqlcommand("dbcc freeproccache", $cn2);
$cn2.Open();
if ($cmd.ExecuteNonQuery() -ne -1)
{
    echo "Failed";
}
$cn2.Close();

大概您可以在它表示的地方替换其他TSQL语句dbcc freeproccache


1
此解决方案为我工作,但是ExecuteNonQuery()成功返回零,我使用的条件是:if ($cmd.ExecuteNonQuery() -ne 0)
Gixabel

似乎返回受影响的行数。docs.microsoft.com/en-us/dotnet/api/…–
NicolasW,

27

此函数将查询结果作为Powershell对象数组返回,因此您可以在过滤器中使用它们并轻松访问列:

function sql($sqlText, $database = "master", $server = ".")
{
    $connection = new-object System.Data.SqlClient.SQLConnection("Data Source=$server;Integrated Security=SSPI;Initial Catalog=$database");
    $cmd = new-object System.Data.SqlClient.SqlCommand($sqlText, $connection);

    $connection.Open();
    $reader = $cmd.ExecuteReader()

    $results = @()
    while ($reader.Read())
    {
        $row = @{}
        for ($i = 0; $i -lt $reader.FieldCount; $i++)
        {
            $row[$reader.GetName($i)] = $reader.GetValue($i)
        }
        $results += new-object psobject -property $row            
    }
    $connection.Close();

    $results
}

为什么这比填充a更可取DataTable(请参见Adam的答案)?
alroc

2
可能并没有太大的区别,但是通常首选SqlDataReaders,因为它们消耗的资源更少。在这里这不太可能相关,但是最好找回实际对象而不是可以在foreach和where子句中使用的数据表,而不必担心数据源。
mcobrien

1
一个示例用法会很好。
埃里克·施耐德

有时没有足够的星星
Fred B

13

如果要在本地计算机上而不是在SQL Server上下文中执行此操作,则可以使用以下内容。这就是我们在公司使用的。

$ServerName = "_ServerName_"
$DatabaseName = "_DatabaseName_"
$Query = "SELECT * FROM Table WHERE Column = ''"

#Timeout parameters
$QueryTimeout = 120
$ConnectionTimeout = 30

#Action of connecting to the Database and executing the query and returning results if there were any.
$conn=New-Object System.Data.SqlClient.SQLConnection
$ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerName,$DatabaseName,$ConnectionTimeout
$conn.ConnectionString=$ConnectionString
$conn.Open()
$cmd=New-Object system.Data.SqlClient.SqlCommand($Query,$conn)
$cmd.CommandTimeout=$QueryTimeout
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
[void]$da.fill($ds)
$conn.Close()
$ds.Tables

只需填写$ ServerName$ DatabaseName$ Query变量,就可以了。

我不确定我们最初是怎么发现的,但是这里有一些非常相似的东西


12
Invoke-Sqlcmd -Query "sp_who" -ServerInstance . -QueryTimeout 3

它将显示powershell命令使用的sql中的连接数
arnav '16


0

为了避免使用varchar参数进行SQL注入,可以使用


function sqlExecuteRead($connectionString, $sqlCommand, $pars) {

        $connection = new-object system.data.SqlClient.SQLConnection($connectionString)
        $connection.Open()
        $command = new-object system.data.sqlclient.sqlcommand($sqlCommand, $connection)

        if ($pars -and $pars.Keys) {
            foreach($key in $pars.keys) {
                # avoid injection in varchar parameters
                $par = $command.Parameters.Add("@$key", [system.data.SqlDbType]::VarChar, 512);
                $par.Value = $pars[$key];
            }
        }

        $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
        $dataset = New-Object System.Data.DataSet
        $adapter.Fill($dataset) | Out-Null
        $connection.Close()
        return $dataset.tables[0].rows

    }

    $connectionString = "..."
    $sql = "select top 10 Message, TimeStamp, Level from dbo.log "+
        "where Message = @MSG and Level like @LEVEL ";
    $pars = @{
        MSG = 'this is a test from powershell'; 
        LEVEL = 'aaa%';
    };
    sqlExecuteRead $connectionString $sql $pars
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.