Invoking SQL query within excel in powershell script - sql

I am trying to invoke SQL query within EXCEL worksheet in a powershell script, so the query will print to EXCEL worksheet
$username = $credentials.UserName
$password = $credentials.GetNetworkCredential().Password
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=10.10.10.10;Initial Catalog=database;User Id=$username;Password=$password;"
$excel = New-Object -Com Excel.Application
$excel.Visible = $True
$wb = $Excel.Workbooks.Add()
$currentWorksheet=1
if ($currentWorksheet -lt 4){
$ws = $wb.Worksheets.Item($currentWorksheet)
}
else
{
$ws = $wb.Worksheets.Add()
}
$currentWorksheet += 1
$qt = $ws.QueryTables.Add($conn.ConnectionString, $ws.Range("A1"), $SQL)
When I run the script I get error
Exception calling "Add" with "3" argument(s): "Exception from HRESULT: 0x800A03EC"
I thought I am entering the correct number of parameters and values in $ws.QueryTables.Add(
How to fix this?

I had to create DSN, as demonstrated here
http://blog.mclaughlinsoftware.com/2012/09/12/sql-server-odbc-osn/
Then I created variable at beginning of script
$DSN = 'SQL Server ODBC' (same as the example)
Now, value of $qt is changed,
$qt = $ws.QueryTables.Add("ODBC;DSN=$DSN", $ws.Range("A1"), $SQL)

Related

Insert Query is working sometimes in powershell

I'm inserting some data in SQL db with help of powershell, but sometimes it works sometimes not.
My Code:
$name= "TestTable"
$Database= "Testdb"
$date=Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$ComputerNameValue=$env:computername
$InsertQuery="INSERT INTO [$($Database)].[dbo].[$($name)]
([Date],[HostName])
VALUES('$date','$ComputerNameValue')
"
After SQL connection my code
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.Connection = $conn
$SqlCmd.CommandText = $InsertQuery
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
#Creating Dataset
$Datatable = New-Object "System.Data.Datatable"
$result = $SqlCmd.ExecuteNonQuery()
$conn.Close()
But in db sometimes its not working as shown in image.
Any help will be thankfull.

Why is this powershell code only returning one result when I have multiple results?

I am running a query through powershell. I know I have multiple results from running the query through ssms. Why does the variable only have one result in powershell?
I have used many methods to do this query and I finally got it working but can't get all the results of the query.
[string] $Server= "mochqdb01";
[string] $Database = "MoCApp.Models.Item+ItemDBContext";
[string] $SQLQuery= $("Select smEmail from Items where DateRequested >= dateadd(day,datediff(day,1,GETDATE()),0)");
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$Server;Database=$Database;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SQLQuery
$SqlCmd.Connection = $SqlConnection
$dbname = $SqlCmd.ExecuteScalar()
$SqlConnection.Close()
Write-output "Database is " $dbname
Output:
Database is
Franziew#marketyyo.com
Should have multiple results. Should I save into an array?
I actually want to save the results into this format.
Send-ToEmail -email "js#marketyyo.com","mb#marketyyo.com";Is this possible?
ExecuteScalar() returns the first column of the first row of the first result set. You need ExecuteReader(). EG
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$Server;Database=$Database;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SQLQuery
$SqlCmd.Connection = $SqlConnection
$rdr = $SqlCmd.ExecuteReader()
while ($rdr.Read())
{
$smMail = $rdr[0]
write-output "email is $smMail"
}
$rdr.Close()
$SqlConnection.Close()

How substitute variable in PowerShell SQL query

I need to use a variable in my SQL query. This is my script:
function SQLQueryWriteToFile([string]$SQLquery, [string]$extractFile, [string]$facility)
{
#create sql connection to connect to the sql DB
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = "Server=blah;Database=blah_Test;User ID=blah;Password=blah"
$sqlConnection.Open()
#Create a SqlCommand object to define the query
$sqlCmd = New-Object System.Data.SqlClient.SqlCommand
$sqlCmd.CommandText = $SQLquery
$sqlCmd.Connection = $sqlConnection
#create a SqlAdapter that actually does the work and manages everything
$sqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$sqlAdapter.SelectCommand = $sqlCmd
$sqlAdapter.SelectCommand.CommandTimeout=300 #set timeout for query execution to 5 minutes (60x5=300)
#create an empty dataSet for the query to fill with its results
$dataSet = New-Object System.Data.DataSet
#execute the query and fill the dataSet (then disconnect)
$sqlAdapter.Fill($dataSet)
$sqlConnection.Close()
#dump the data to csv
$DataSet.Tables[0] | Export-Csv $extractFile #this may not be comma delimited...need to check
}
#start here
$SQLquery_Privilege = #"
SELECT *
FROM "blah_Test".dbo.usr_Person_by_Privileges
WHERE
Status in ('Active')
and Facility = '$[facility]'
and Last not like ('%test%')
and Last not like ('%Test%')
--ORDER BY Last
"#
$extractFiles = #("C:\temp\Privileges_H_Bak.csv","C:\temp\Privileges_E_Bak.csv","C:\temp\Privileges_S_Bak.csv")
$facCode = #("H","E","S")
#Loop through list of files and queries for ProfileLong
for($i=0; $i -lt ($facCode.Length); $i++) {
SQLQueryWriteToFile $SQLquery_Privilege $extractFiles[$i] $facCode[$i]
}
I used the debugger and the query passed into the function does have the $facility variable show in it without substitution. How do I get it to do the variable substitution? Also, $facility passed into the function has a value.
There are 0 results showing in each extract files. When I just had each H,E,S individually in the query, and ran the script, it returns a good amount of rows.
I tried looking at substitute variable powershell sql but I can tell my query is still returning 0 rows even though I think I'm doing what they do.
Use query parameters instead of string substitution (this also protects against SQL injection vectors):
$SQLquery_Privilege = #"
SELECT *
FROM "blah_Test".dbo.usr_Person_by_Privileges
WHERE
Status in ('Active')
and Facility = #facility
and Last not like ('%test%')
and Last not like ('%Test%')
--ORDER BY Last
"#
# inside SQLQueryWriteToFile
$sqlCmd = New-Object System.Data.SqlClient.SqlCommand
$sqlCmd.CommandText = $SQLquery_Privilege
$sqlCmd.Parameters.Add('#facility',$facility)

PowerShell 2.0 Run one SQL File (having multi SP and Functions)

I have a .sql file which has multiple stored procedures and functions script in it.
I don't want to use Invoke commands because my server doesn't support them.
Currently I am using below code which works fine if my .sql file has only one stored procedure or function.
$scriptDetail = Get-Content $sqlScriptLocation | Out-String
$scriptDetail = $scriptDetail -creplace 'GO',''
$scriptDetail = $scriptDetail -replace 'SET ANSI_NULLS ON',''
$scriptDetail = $scriptDetail -replace 'SET QUOTED_IDENTIFIER ON',''
$ConnectionString = “Server=$dataSource;uid=$user; pwd=$cred;Database=$database;”
$sqlCon = New-Object -TypeName System.Data.SqlClient.SqlConnection -ArgumentList $ConnectionString
$sqlCon.Open()
$sqlCmd = New-Object -TypeName System.Data.SqlClient.SqlCommand
$sqlCmd.Connection = $sqlCon
$sqlCmd.CommandText = $scriptDetail
$sqlCmd.ExecuteNonQuery()
$sqlCon.Close()
I am replacing GO and other two commands in above code because they casused errors like
System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near 'GO'
System.Data.SqlClient.SqlException (0x80131904): 'CREATE FUNCTION' must be the first statement in a query batch
Must declare the scalar variable "#variableName"
I have came up with solution after Some digging, read the complete file and put it in an array and then run the ForEach loop, it will get each line in ForEach loop put a condition if its not equal to "GO" add it into another array else array(in which you are adding each line) execute it
Code is below
$SQLConnection = New-Object System.Data.SqlClient.SqlConnection
$SQLConnection.ConnectionString = "Server=" + $YourServerName + ";Database=" + $YourDatabaseName + ";User ID= " + $YourUserName + ";Password=" + $YourDbPassword + ";"
$DirectoryPath = "C:\FolderName"
$Dep_SqlFiles = get-childitem -Recurse $DirectoryPath -Include "*.sql"
$Dep_Info_DataEntry = #(Get-Content $Dep_SqlFiles.FullName) #Get all info of each file and put it in array
foreach($SQLString in $Dep_Info_DataEntry)
{
if($SQLString -ne "go")
{
#Preparation of SQL packet
$SQLToDeploy += $SQLString + "`n"
}
Else
{
try{
$SQLCommand = New-Object System.Data.SqlClient.SqlCommand($SQLToDeploy, $SQLConnection)
$SQLCommand.ExecuteNonQuery()
#use this if you want to log the output
#$SQLCommand.ExecuteScalar() | Out-File YourLogFile -Append
}
Catch
{
}
$SQLToDeploy = ""
}
}

Export SQL output to excel sheet

I would like to output sql output to an excel file, and a sheet that I give a name to, i.e. not "Sheet1". How do I even begin code this?
Below is current code that reads sql output
$sql_output = #()
while ($rdr.read()){
$sql_output += [PSCustomObject][Ordered]#{
Col1=$rdr.GetValue(0)
Col2=$rdr.GetValue(1)
Col3=$rdr.GetValue(2)
Col4=$rdr.GetValue(3)
Col5=$rdr.GetValue(4)
}
$count=$count + 1
}
Then exports to csv
$sql_output | Export-CSV "D:\Script\Network_Threat_Protection.csv" -NoTypeInfo -Append
I would eventually like this powershell script to read multiple sql queries and output it to different sheets within excel, but let me get the jist of exporting to excel first ....
Export-CSV does not generate an Excel file. It generates a comma delimited text file that usually is set to open with Excel. Being a CSV file there is no knowledge of multiple sheets or dataset properties like sheetnames, for that you will need to use the Excel comobject (and all of its nuances).
Here is a basic example of writing a real Excel file:
$a = New-Object -com Excel.Application
$a.Visible = $True
$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)
$c.Cells.Item(1,1) = "A value in cell A1."
$b.SaveAs("C:\Scripts\Test.xls")
$a.Quit()
What you are trying to do is not new. There are a lot of scripts on the internet for this task. Microsoft's Script Center is a good place to find powershell scripts. Here is one that seems to do what you want.
you can use CPPLUS library for exporting tables to excel sheets..
private DataTable GetData(string tableName)
{
using (SqlConnection sqlCon = new SqlConnection(connectionString))
{
SqlCommand sqlCommand = new SqlCommand("SELECT * FROM " + tableName, sqlCon);
sqlCon.Open();
var reader = sqlCommand.ExecuteReader();
DataTable dt = new DataTable();
dt.Load(reader);
return dt;
}
}
private void SaveExcel(DataTable dataTable, string newFile)
{
using (ExcelPackage pck = new ExcelPackage())
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add(newFile);
ws.Cells["A1"].LoadFromDataTable(dataTable, true);
pck.SaveAs( new System.IO.FileInfo("d:\\Export\\" + newFile + ".xlsx"));
}
}
Download Source