PowerShell'den bir SQL Server sorgusu nasıl çalıştırılır?


161

Yerel makinemde Powershell kullanarak SQL Server'da rasgele bir sorgu yürütmenin bir yolu var mı?

Yanıtlar:


166

Bunu sadece .net ve PowerShell (ek SQL araçları yüklü değil) ile yapmanız gereken diğerleri için burada kullandığım işlev:

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

}

Bunu çok uzun zamandır kullanıyorum, kimin hangi kısımları yazdığını bilmiyorum ama bu başkalarının örneklerinden damıtıldı, ancak açık olması ve ekstra bağımlılıklar veya özellikler olmadan neyin gerekli olduğu basitleştirildi.

Bu işlemi, GitHub'da bir komut dosyası modülüne dönüştürdüğüm kadar sık ​​sık kullanıyorum ve paylaşıyorum, böylece şimdi modül dizininize gidip çalıştırabilirsiniz git clone https://github.com/ChrisMagnuson/InvokeSQLve bu noktadan sonra ileri çağırmak-sql kullanmaya başladığınızda otomatik olarak yüklenecektir (varsayarak) powershell v3 veya daha yenisini kullanmanız).


imha burada ya da powershell'de önemli değil mi?
Maslow

2
@Maslow Kesin olarak söyleyemedim, bunun nesneleri atmadan iyi çalıştığını biliyorum, ancak kapanmadan haftalarca defalarca çağıracak tek bir powershell.exe işleminiz varsa sonunda bir sorun olabilir, ancak bunu test etmek zorunda kalacak.
Chris Magnuson

1
Bunun, kullanıcı girişine dayanan bir kaynaktan sorgu verilerinin okunmasına bağlı olmaları durumunda sizi sql enjeksiyon saldırılarına karşı savunmasız olabilecek komut dosyaları yazmaya zorladığını unutmayın.
Joel Coehoorn

4
@AllTradesJack Google Sql Enjeksiyonu. Invoke-Sql komutunun, komut metninden ayrı parametreleri dahil etme yolu yoktur. Bu, sorguları oluşturmak için dize birleştirmeyi kullandığınızı garanti eder ve bu büyük bir hayır-hayırdır.
Joel Coehoorn

1
Benim için iyi çalışıyor. Herkes, bir nesneyi atmak, sadece $connection.dispose()vb eklemek için . Ama herhangi bir fark
yaratıp yaratmadığını

101

Invoke-SqlcmdCmdlet'i kullanabilirsiniz

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

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


22
Birisi sql sunucusu bağlamında iseniz, bu harika olabilir, ama iş istasyonunuzu kullanıyorsanız çok fazla söz
etmelidir

10
SQL Server istemci araçlarının (SSMS) yüklü olduğu her yerde çalıştırabilirsiniz. SQL Server çalıştırıyor olsun ya da olmasın, herhangi bir iş istasyonundan iyi çalışır.
alroc

3
Import-Module "sqlps" -DisableNameChecking
Cmdlet'in

1
Hala SQL 2008 R2 kullanıyorsanız, modül etrafında bir çözüm kullanmanız gerekir: sev17.com/2010/07/10/making-a-sqlps-module
Vincent De Smet

2
Invoke-SqlCmd, tuhaf uç durumlar ve tutarsız davranışların sonsuz bir kabusudur. Neden bazen sütun çıkarıyor, bazen de çıkmıyor? Hata mesajlarım nerede? Neden bir bilgisayarda ya da başka bir bilgisayarda değil? Nasıl kurarım? Her sorunun cevabı bir öncekinden daha kötüdür.
Pxtl

28

İşte bu blogda bulduğum bir örnek .

$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();

Muhtemelen söylediği yerde farklı bir TSQL ifadesi kullanabilirsiniz dbcc freeproccache.


1
Benim için çalıştı bu çözüm, ancak, ExecuteNonQuery()başarı üzerine ben kullanımının olduğu koşulunu sıfır döndürdü: if ($cmd.ExecuteNonQuery() -ne 0).
Gixabel

Etkilenen satır sayısını döndürüyor gibi görünüyor. docs.microsoft.com/tr-tr/dotnet/api/…
NicolasW

27

Bu işlev, bir sorgunun sonuçlarını powershell nesneleri dizisi olarak döndürür; böylece bunları filtrelerde ve erişim sütunlarında kolayca kullanabilirsiniz:

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
}

Bu neden bir doldurma yerine tercih edilir DataTable( bkz.Adam'ın cevabı )?
alroc

2
Muhtemelen büyük bir fark yoktur, ancak SqlDataReaders genellikle daha az kaynak tükettiklerinden tercih edilir. Burada alakalı olması muhtemel değildir, ancak verilerin kaynağı hakkında endişelenmeden, foreach ve nerede cümlelerde kullanabileceğiniz bir datatable yerine gerçek nesneleri geri almak güzeldir.
mcobrien

1
örnek bir kullanım iyi olurdu.
Eric Schneider

Bazen yeterli yıldız yoktur
Fred B

13

SQL sunucusu bağlamında yerine yerel makinenizde yapmak istiyorsanız , aşağıdakileri kullanırdım. Şirketimde kullandığımız şey bu.

$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

Sadece $ ServerName , $ DatabaseName ve $ Query değişkenlerini doldurun ve gitmekte fayda var.

Başlangıçta bunu nasıl öğrendiğimizden emin değilim, ama burada çok benzer bir şey var .


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

powershell komutu tarafından kullanılan
sql'deki


0

Varchar parametreleri ile SQL enjeksiyonu önlemek için kullanabilirsiniz


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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.