How to query SQL Server using PowerShell - sql

I have this code that I got from a website and it's connected to my SQL Server using window authentication but I'm not sure how can I choose a database and query some table?.
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-Null
$s = new-object ('Microsoft.SqlServer.Management.Smo.Server') "server instance"
$s.ConnectionContext.LoginSecure=$true
$s.Databases | select name, size, status
If I run this code, it show me a list of databases but I want to choose a database called "LitHold" and query some table from that database inside.

For SMO like you have in your question, you can run queries that return data using ExecuteWithResults() like so:
$s = New-Object Microsoft.SqlServer.Management.Smo.Server "server instance"
$db = $s.Databases.Item("master")
$query = "SELECT * FROM [master].[sys].[databases] ORDER BY [name];"
$result = $db.ExecuteWithResults($query)
# Show output
$result.Tables[0]

Related

How to scroll a resultset from an ODBC datasource using cursors in PowerShell?

How do I use a cursor to scroll a resultset from an ODBC datasource in PowerShell ?
Problem:
The SQL statement takes too long to execute (due to returning millions of rows). I only want to return the top 5 rows but this database does not support the top, limit or rownum select statement clauses).
Current code (that does not use cursors):
$datasourceName = "big_database"
$sqlQuery = "SELECT * as 'millions_of_rows' FROM big_table"
$odbcConnection = new-object Data.Odbc.OdbcConnection
$odbcConnection.ConnectionString = "dsn=$datasourceName"
$odbcConnection.open()
$resultSet = (new-object Data.Odbc.OdbcCommand($sqlQuery, $odbcConnection)).ExecuteReader()
$table = new-object "System.Data.DataTable"
$table.Load($resultSet)
#/* Display results */
$table

keyword 'like' in my SQL statement in Poweshell is getting treated like an '=' sign

The like statement in my SQL query in powershell isn't producing the intended results. My 'like' statement is getting treated like an '=' sign.
for example
I have a table with the following values:
FieldNames
1. George Bush;George Foreman;Mary jones;
2. George Foreman;
3. George Foreman; Michael Smith;
4. Mary Jones;George Foreman
Variable:
$Expression = "George Foreman"
Three options I tried:
1.
Select FieldNames from table where FieldNames like '%$Expression%'
2.
Select FieldNames from table where FieldNames like '%$($Expression)%'
3.
Select FieldNames from table where FieldNames like '%George Foreman%'
I receive the same results for all three options (only row 2 returns). I would expect all the rows to return.
I can run this same query in SSMS and all rows return.
Has anyone ran across this problem or have any suggestions on how I can modify my select query to get all the rows using 'like'?
Formatted Powershell expression:
#Variables:
$Expression = "George Foreman"
$UserName = "UserName"
$password = "Password"
$Database = "Database"
$Server = "Server"
$Query="Select FieldNames from table where FieldNames like '%$Expression%' "
$ConnectionString = "Server=$Server ;User ID=$UserName; password=$password;
Integrated Security=True; database=$Database;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connection
$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = $Query
$result = $command.ExecuteReader()
$connection.Close()

invoke-expression for SQLCMD -i "test.sql" and put results to a variable

I have a huge sql query where I want to run on a remote server from another server via powershell, however I am having trouble trying get the results per column per row of since test.sql produces a table with multiple table and result. I know I can query it using the
$ConnectionToServer = New-Object System.Data.SQLClient.SQLConnection
$CommandCMSQry = New-Object System.Data.SQLClient.SQLCommand
Where $CommandCMSQry contains the whole query in a string format. However, I am trying lessen the rows of the script thus I wanted to put the SQL query outside of the PS script.
$QryPath = "D:\CNA\DatabaseIntegrityCheck.sql"
invoke-expression "SQLCMD -E -S $InstanceNm -d 'master' -i $QryPath -b" | Tee-Object -Variable ResultCreateSP | Select-Object name,database_id
$ResultCreateSP
Example result:
main result
a b
1 foo1
2 foo2
and if I access the columns something with like this
write-host "a = " + $ResultCreateSP.name + "b = " + $ResultCreateSP.database_id
a = 1 b = foo1

Powershell Get-QADUser results to SQL table

I'm querying Active Directory with a string which loops through each domain controller in our system and returns a set of results. The script works great with export-csv but because we wish to retain all data in the custom info field (it contains carriage-returns) I'd like to export this directly into an SQL table.
The error reported by Powershell reads:
Exception calling "ExecuteNonQuery" with "0" argument(s): "Insert Error: Column name or >number of supplied values does not match table definition."
Which is a pretty verbose response, I've created and named the columns of each table to exactly match the output of the get-object.
Here's the output from the pipe:
SamAccountName : testuser
DisplayName : Test User (COMPANY)
info : Test Entry 1234567890
Test for output.
Entering
Multiple lines.
whenCreated : 09/11/2004 09:08:42
whenChanged : 19/07/2012 09:25:21
AccountExpires :
pwdLastSet : 13/06/2012 07:43:43
LastLogonTimestamp : 18/07/2012 15:38:35
userAccountControl : 512
Name : Test User
LastLogon :
DC : DCNAME1
And here's the code:
##--AD data output to SQL script, you need the Quest plugin!
$SamAccountName = Read-Host "Enter the username to query for last logon"
##--Query domain for all domain controllers and funnel into a forEach loop
Get-QADComputer -ComputerRole DomainController | Foreach-Object{
$dc = $_.Name
##--Query each domain controller for the user object and retrieve the LastLogon timestamp
$user = Get-QADUser -Service $dc -SamAccountName $SamAccountName -IncludedProperties info,pwdLastSet,AccountExpires,userAccountControl | Select-Object SamAccountName,displayName,info,whenCreated,whenChanged,accountExpires,pwdLastSet,lastLogonTimestamp,userAccountControl,name,LastLogon,#{n='DC';e={$dc}} |
out-host
##--Open database connection
$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source=SQLSERVER; Initial Catalog=ADomain; Integrated Security=SSPI")
$conn.Open()
##--AAGH! How to grab the results of the Select-Object above?
$cmd = $conn.CreateCommand()
$cmd.CommandText ="INSERT extract VALUES ('$user')"
$cmd.ExecuteNonQuery()
##--Don't forget to close it!
$conn.Close()
Now I'm messing something up which is probably plainly obvious, any help much appreciated.
Assume the following test object:
$exampleObject = New-Object PSObject -Property #{SamAccountName="TestSAN";DisplayName="TestDN"}
$user = $exampleObject | Select-Object SamAccountName, DisplayName
##--AAGH! How to grab the results of the Select-Object above?
$commandText = "INSERT extract VALUES ('$($user.SamAccountName)','$($user.DisplayName)'"
I would also move the sql connect and close to outside of a loop and place it in a try/finally block, so it is only done once instead of for each DC entry and the Close is still called when there is an Exception during the execution of the try block. See here for reference on using a try/catch/finally block with Powershell.
here I'm using SqlServerCmdletSnapin and it's Invoke-sqlcmd. This script is using MSSQL database EMPLOYEE and table EMPLOYEE_DOMAIN. Hope it helps. Works fine for me..
Add-PSSnapin Quest.ActiveRoles.ADManagement
Add-PSSnapin SqlServerCmdletSnapin100
Add-PSSnapin SqlServerProviderSnapin100
$db_server = "10.3.18.55"
$db = "EMPLOYEE"
$table = "EMPLOYEE_DOMAIN"
$username = "import"
$pwd = "Okinawa84561"
# First, clear existing table
$sql_query_del = "DELETE FROM $table"
Invoke-Sqlcmd -ServerInstance $db_server -Database $db -Username $username -Password $pwd -Query $sql_query_del
# Get users with employeeID only and write their accountname and employeeID to DB
Get-QADUser -IncludeAllProperties | ? {$_.employeeID} | select sAMAccountName, employeeID | foreach {
$an = $_.sAMAccountName
$eid = $_.employeeID
Write-Host " sAMAccountName : $an employeeID : $eid"
$sql_query = "INSERT INTO $table (employeeID, domainName) VALUES ('$eid', '$an')"
Invoke-Sqlcmd -ServerInstance $db_server -Database $db -Username $username -Password $pwd -Query $sql_query
}

Read multiple tables from dataset in Powershell

I am using a function that collects data from a SQL server:
function Invoke-SQLCommand {
param(
[string] $dataSource = "myserver",
[string] $dbName = "mydatabase",
[string] $sqlCommand = $(throw "Please specify a query.")
)
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = `
"Server=$dataSource;Database=$dbName;Integrated Security=True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $sqlCommand
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
$DataSet.Tables[0]
}
It works great but returns only one table. I am passing several Select statements, so the dataset contains multiple tables.
I replaced
$DataSet.Tables[0]
with
for ($i=0;$i -lt $DataSet.tables.count;$i++){
$Dataset.Tables[$i]
}
but the console only shows the content of the first table and blank lines for each records of what should be the second table. The only way to see the result is to change the code to
$Dataset.Tables[$i] | out-string
but I do not want strings, I want to have table objects to work with.
When I assign what is returned by the Invoke-SQLCommand to a variable, I can see that I have an array of datarow objects but only from the first table. What happened to the second table?
Any help would be greatly appreciated.
Thanks
I tried your function (that returns $DataSet.Tables) and it worked pretty well for me. This command returned rows from both tables:
$t = Invoke-sqlcommand '.\sql2005' 'AdventureWorksDW' `
"SELECT * FROM DimOrganization; SELECT * FROM DimSalesReason"
$t[0] #returns rows from first table
$t[1] #returns rows from second table
Anyway, what I would recommend:
First I would discard output from Fill:
$SqlAdapter.Fill($DataSet) > $null
It is returned as well, but that's not probably desired.
As in your case Invoke-SqlCommand doesn't work, I would try to return 1 dim array like this:
function Invoke-SQLCommand {
...
,$DataSet.Tables
}
Consider that PowerShell treats DataTable specially and when trying to format it, it unravels Rows collection (credits to x0n). That's why just executing $t from my example displays all the rows returned from the command.
Thank you for your answer.
Well, I can't explain why it works for you and not for me.
If I run the exact same command as you (except for the data source, mysqlserver\sqlexpress in my case), $t[0] only returns the first row of the first table and $t[1] the second row.
What seems to be happening in my case is that the rows from all tables are merged so I end up with one big set of datarows, not the individual tables expected.
I ended replacing:
for ($i=0;$i -lt $DataSet.tables.count;$i++){
$Dataset.Tables[$i]
}
with just
$Dataset
I can then reference the individual tables from my script by using $t.Tables[0] and $t.Tables[1].
Thanks again