I was trying to query the SCCM database and sort the results with Powershell to get a full report on all the connections to a collection. To do this i needed to inject a SELECT query and retrieve an object from the database which proved to be a bit difficult. Below is how i resolved it.
To connect to a SQL you need a client, in powershell and .NET we have the System.Data.SQLClient namespace
$connection = New-Object System.Data.SqlClient.SqlConnection
Then i needed a connection string to open the database.
$connection.ConnectionString = "$ConnectionString" $connection.Open()
Now we need to inject the command we want. Fairly simple, we create a SQLCommand and connect it to the already established connection.
$Command = New-Object System.Data.SQLClient.SQLCommand $Command.Connection = $Connection
Then we insert our command
$Command.CommandText = $SQLQuery
What we do after is execute the command and create a counter of the columns in the result.
$Reader = $Command.ExecuteReader() $Counter = $Reader.FieldCount
Now we create the DataTable and use the counter to populate the columns. We name them after each column in the query.
$DataTable = New-Object system.Data.DataTable
for($i = 0; $i -lt $counter; $i++){
$Column = New-Object system.Data.DataColumn $Reader.GetName($i),([string])
$DataTable.Columns.Add($Column)
}
While the Reader is active it processes a loop for the length of counter and ejects the results into new rows in the DataTable.
To get the correct formatting, we place everything into a string and format accordingly. Name and value.
We then use the Invoke-Expression cmdlet to execute the formatted string and add values to the rows
while ($Reader.Read()) {
$Data = @()
for ($i = 0; $i -lt $Counter; $i++) {
$Data += [String]$Reader.GetValue($i)
}
$DataTable.Rows.Add($Data)
}
Last but not least, we close the reader and the connection to the database and output the finished table
$Reader.Close() $Connection.Close() Return $DataTable
And we’re done!
The finished function will now look like this:
Function Get-SQLQuery{
Param(
[Parameter(Mandatory=$true)]
[String]$SQLQuery,
[Parameter(Mandatory=$true)]
[String]$ConnectionString
)
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = "$ConnectionString"
$connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandText = $SQLQuery
$Reader = $Command.ExecuteReader()
$Counter = $Reader.FieldCount
$DataTable = New-Object system.Data.DataTable
for($i = 0; $i -lt $counter; $i++){
$Column = New-Object system.Data.DataColumn $Reader.GetName($i),([string])
$DataTable.Columns.Add($Column)
}
while ($Reader.Read()) {
$Data = @()
for ($i = 0; $i -lt $Counter; $i++) {
$Data += [String]$Reader.GetValue($i)
}
$DataTable.Rows.Add($Data)
}
$Reader.Close()
$Connection.Close()
Return $DataTable
}
First set your connectionstring and Select query then invoke the command like this:
Get-SQLQuery -ConnectionString $connectionstring -SQLQuery $SelectQuery
Examples of connectionstrings can be found at Connectionstrings.com
The usual string is the trusted which uses your credentials
If you are using the function a lot, concider adding it to your Powershell profile. For more information check out my previous post on WGET and profiles
