PowerShell und SQL

Zugegenen, ich sehe mit größeren Datenmodellen und Datenbanken immer etwas auf Kriegsfuß. Vielleicht habe ich damals in der uni einfach den Faden zwischen der zweiten und dritten Normalisierung verloren. Aber Fakt ist, dass in der heutigen Welt nichts mehr ohne Datenbanken und Strukturen geht. Sei es nur eine flache CSV-Datei als Tabelle, eine Access-Datenbank oder eine SQL-basierte Plattform. Exchange nutzt zwar keine SQL-Datenbank aber Lync sehr wohl. Und sehr viele Daten stehen nun mal in SQL-Datenbanken oder kann man dort importieren und dann besser auswerten. Allerdings liefert PowerShell und DataTable nicht immer eine hohe Performance. Für den Import oder Export großer Datenmengen verweise ich auf PowerShell, SQL und BCP.

SQL Server Verwaltung

Ehe ich auf die Zugriffe in den SQL-Datenbanken per PowerShell eingehe, wollte ich Sie auf die Möglichkeiten verweisen, auch den SQL-Server selbst per PowerShell zu verwalten, d.h. Parameter des Servers anzeigen und ändern, Datenbanken anlegen und löschen, Berechtigungen setzen etc. All das, wozu sie in ansonsten das SQL-Management Studio verwenden oder das Setup der Applikation ihnen die Arbeit abnimmt.

Oft übernimmt diese Arbeit natürlich der Datenbank-Server-Administrator. Für die Entwicklung und Tests sollten Sie aber schon Zugriff über die Verwaltungswerkzeuge haben, damit Sie über andere Tools sehen können, welche Daten in den Tabellen sind, welche Werte ihr PowerShell-Skript liest und ändert und welche Fehler eventuell in den Logs erscheinen. Manchmal kann es ja auch erforderlich sein, die Tabellen zu verwerfen und neu aufzubauen (DROP and RECREATE).

System.Data.SqlClient.SqlDataAdapter

Ich nutze in der Folgen die .NET-Klasse System.Data.SqlClient.SqlDataAdapter um auf einen SQL-Server zuzugreifen. Das sollte die schnellste und dank "Managed Code" auch bessere Wahl sein als die früher oft genutzte ODBC-Schnittstelle. Dazu ist es natüröich erforderlich, dass Sie zumindest den SQL-Client auf dem System installiert haben, auf dem ihr PowerShell-Script ausgeführt wird. Sie können diese Komponenten von der SQL-Installationquelle bekommen oder natürlich auch als einzelner Download:

SQL2012SP1 http://www.microsoft.com/en-us/download/details.aspx?id=35580
SQL2008SP2 http://www.microsoft.com/en-us/download/details.aspx?id=30440

Die folgende Codesequenz ist stark verkürzt und erstellt keine Hilfsklasse für die SQL-Connection und SQL-Commands, sondern nutzt direkt den SQLDataAdapter. für einfache einmalige Anfragen sollte das aber akzeptabel sein.

Sie müssen natürlich schon ihren SQL-Server, ihre Instanz, Datenbank und Tabelle im Code eingeben, damit er in ihrer Umgebung funktioniert.

Hier erst mal ein erster Lese-Versuch.

write-host "Reading from SQL"
[string]$SQLConnection = "Server=Server\instanzname,port;Database=datenbank;Integrated Security=True"
[string]$SQLQuery = "Select * from tabellenname"
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter ($SQLQuery,$SQLConnection)
$DataSet = New-Object System.Data.DataSet
$result = $SqlAdapter.Fill($DataSet)
if ($result -ne 1) {
	write-error "Keine SQL-Daten erhalten"
	exit
}
write-host "  erhaltene tabellen: $result"
$count = 0
$DataSet.Tables[0] | %{
	$count = $count +1 
	write-host "  SQLTable ($count):" $_
}

Ein weiteres Beispiel mit einem etwas anderen Code, der aber zum gleichen Ergebnis führt.

$con = New-Object System.Data.SqlClient.SqlConnection
$con.ConnectionString = "Persist Security Info=False;Server=sql01.uclabor.de\MSSQL;database=Database1;Integrated Security=true"#;User Id=Domain\User;Password=geheim"
$con.Open()
$sql = "SELECT [mail] FROM [Database1].[dbo].[tablename]"
$cmd = New-Object System.Data.SqlClient.SqlCommand($sql,$con)
$rdr = $cmd.ExecuteReader()
while($rdr.Read())
{
     write-host ("Entry" + $rdr["mail"].ToString())
}
Write-Host "End"
$rdr.Close();

Zum "Abgucken" habe ich mir oft folgenden Code-Ausschnitt zu Hilfe genommen.

function Get-SQLData {
# Quelle: http://blogs.technet.com/b/lukeb/archive/2010/01/12/PowerShell-and-ews-how-to-update-contacts.aspx
   param ($strSQLServer="(local)\SQLEXPRESS",$strDB="ContactDB",$strQuery="Select * from dbo.Contacts")
 
   $strConnection = "Data Source=$strSqlServer; Initial Catalog=$($strDB); Integrated Security=SSPI" 
   $objConnection = New-Object System.Data.SqlClient.SqlConnection($strConnection) 
   $objCommand = New-Object System.Data.SqlClient.sqlCommand($strQuery,$objConnection)
 
   $objConnection.open()
 
   $objDataSet = new-object System.Data.DataSet("ContactData")
   $objdataAdapter = new-object System.Data.SqlClient.SqlDataAdapter($strQuery,$objConnection)
 
   [void]$objDataAdapter.Fill($objDataSet,"ContactData")
 
   $objConnection.close()
 
   $colNames=$objDataSet.tables["ContactData"].columns | foreach-object {$_.columnName}
 
   $objDataSet.tables["ContactData"].rows | foreach {
      $objRow = $_
      $objPS = New-Object psobject 
      $colNames | 
         foreach-object {
          $colName = $_ 
        if ($objRow[$colName].GetType().Name -eq "DBNull") {
            #  Change NULLS to Empty Strings
              $objPS = $objPS | add-member -passthru NoteProperty $colName ""
        }else {
              $objPS = $objPS | add-member -passthru NoteProperty $colName $objRow[$colName]
         }
        }
      $objPS
   }
}

SQL Schreiben/Importieren

Lesen Sie dazu bitte die Seite PowerShell, SQL und BCP

Stored Procedure

Manchmal reicht es nicht Daten in SQL zu schreiben. Diverse größere Aktionen wird man besser auf dem Server als "Stored Procedure" laufen lassen. Dieser Code auf dem Server kann wie folgt durch ein PowerShell-Script angestoßen werden:

$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Persist Security Info=False;Server=$($SQLServer);database=$($databasename);Integrated Security=true";
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "sp_proceurename"
$SqlCmd.Connection = $SqlConnection
$sqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure
$sqlCmd.CommandTimeout = 1200
$result = $sqlCmd.ExecuteNonQuery()
if ($result -ne 0) {
   $errorfound = $true
}
$SqlConnection.Close()

Sie müssen natürlich die richtigen Werte für den SQL-Server und die Datenbank eintragen und den Namen der Stored Procedure anpassen. Das Skript geht weiter davon aus, dass der aktuelle Anwender auch die Rechte im SQL-Server hat.

Andere SQL-Backends

Es muss ja nicht immer Microsoft SQL-Server sein. Die Welt hat durchaus mehr zu bieten, sei es mySQL, Oracle, SQLite und andere. Auf all diese anderen SQL-Systeme bin ich jetzt nicht weiter eingegangen. Hier aber ein paar weiterführende Links

Weitere Links