Як запустити запит на SQL Server від PowerShell?


161

Чи є спосіб виконати довільний запит на SQL сервері за допомогою Powershell на моїй локальній машині?

Відповіді:


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 або новішої версії).


чи не має значення утилізація тут чи в оболонці?
— Маслоу

2
@Maslow Я не можу сказати точно, я знаю, що це прекрасно працює без викидання об'єктів, але якщо у вас є єдиний процес powershell.exe, який буде викликати це кілька разів протягом тижнів, не закриваючи, то, зрештою, це може бути проблемою, але ви доведеться це перевірити.
— Кріс Магнусон

1
Зауважте, що це змушує вас писати сценарії, які можуть бути вразливими до атак на введення sql, якщо вони залежать від зчитування даних для запиту з джерела, яке покладається на введення користувача.
— Joel Coehoorn

4
@AllTradesJack Інжекція Google Sql. Команда Invoke-Sql не має можливості включати параметри, окремо від тексту команди. Це в значній мірі гарантує, що ви використовували конкатенацію рядків для побудови запитів, і це велика ні-ні.
— Джоель Куехорн

1
Добре працює для мене. Для тих, хто цікавиться, як розпоряджатися об’єктом, просто додайте $connection.dispose()і т. Д. Я не знаю, чи має це значення, хоча
— Nick.McDermaid

101

Можна використовувати Invoke-Sqlcmdкомандлет

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

http://technet.microsoft.com/en-us/library/cc281720.aspx


22
Хтось повинен згадати про це, можливо, це чудово, якщо ви знаходитесь в контексті сервера sql, але не так багато, якщо ви використовуєте свою робочу станцію ...
— aikeru

10
Ви можете запустити це в будь-якому місці, де встановлені клієнтські інструменти SQL Server (SSMS). Він добре працює з будь-якої робочої станції, незалежно від того, працює він SQL Server чи ні.
— alroc

3
Використовуйте наступний імпорт, щоб мати доступ до командлету: Import-Module "sqlps" -DisableNameChecking
— xx1xx

1
Якщо ви все ще перебуваєте на SQL 2008 R2, вам потрібно скористатися модулем: sev17.com/2010/07/10/making-a-sqlps-module
— Vincent De Smet

2
Invoke-SqlCmd - це нескінченний кошмар химерних випадкових випадків та непослідовної поведінки. Чому він виводить стовпчики іноді, а не інший раз? Де мої повідомлення про помилки? Чому це на одному комп’ютері чи ні на іншому? Як це встановити? Відповідь на кожне питання гірша за останнє.
— Pxtl

28

Ось приклад, який я знайшов у цьому блозі .

$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()повернувся до нуля в разі успіху, умова , що використання I є: if ($cmd.ExecuteNonQuery() -ne 0).
— Гіксабель

Здається, він повертає кількість порушених рядків. docs.microsoft.com/en-us/dotnet/api/…
— NicolasW

27

Ця функція поверне результати запиту у вигляді масиву об'єктів shellhell, щоб ви могли легко використовувати їх у фільтрах та колонках доступу:

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
}

Чому це краще для заповнення DataTable(див . Відповідь Адама )?
— alroc

2
Напевно, не існує великої різниці, але SqlDataReaders зазвичай віддають перевагу, оскільки вони споживають менше ресурсів. Це, мабуть, не стосується тут, але приємно повернути реальні об'єкти замість даних, які можна використовувати в foreach та де клаузи, не турбуючись про джерело даних.
— mcobrien

1
приклад використання було б добре.
— Ерік Шнайдер

Іноді зірок не вистачає
— Фред Б

13

Якщо ви хочете зробити це на своїй локальній машині, а не в контексті SQL-сервера, то я б використав наступне. Це те, що ми використовуємо в моїй компанії.

$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

він покаже кількість з'єднання в sql, що використовується командою powershell
— arnav


0

Щоб уникнути ін'єкції SQL з параметрами varchar, які ви могли використовувати


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.