Powershell way to send email with query result in SQL server - sql

Currenly, I am working to setup a powershell job in SQL server to send database mail for some results in a table format. Here is my script:
$SMTPProperties = #{
To = "abc#abc.com.hk","test#test.com"
Cc = "xyz#xyz.com"
From = "test#abc.com.hk"
Subject = "SQL Report Status"
SMTPServer = "192.168.xx.xx"
}
$server = "192.168.xx.xx"
$database = "DBName"
$username = "abc"
$password = "abc124"
$query = "select top 10* from testing"
function ExecuteSqlQuery ($Server, $Database, $query) {
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$Server';database='$Database';User ID='$username'; Password='$password';trusted_connection=true;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandText = $query
$Reader = $Command.ExecuteReader()
$Datatable = New-Object System.Data.DataTable
$Datatable.Load($Reader)
$Connection.Close()
return $Datatable
}
$resultsDataTable = New-Object System.Data.DataTable
$resultsDataTable = ExecuteSqlQuery $Server $Database $query
Send-MailMessage #SMTPProperties -Body $query -BodyAsHTML | Format-Table
A few questions comes:
1. In #SMTPProperties, how can I send to multiple recipients? Solved
2. The script works but in content of the received email, it simply returns
text of the query (select top 10* from testing). It is not the
query result.
3. Is my script correct to output a HTML table in the email
content? If not , how can I change it?
4. How can I run above without provide UID and Password in above script.
Thank you.

For more recipients you can use Cc field
I use this for sending mails for my Powershell scripts.
Send-MailMessage `
-Credential $anonCredentials `
-From FromMailAddress#Domain.com `
-To MainMailAddress#Domain.com `
-Cc "FirstRecipient#Domain.com","SecondRecipient#Domain.om","ThirdRecipient#Domain.com" `
-Subject "Enter your subject" -Body "This is an automated message from the server with some data" `
-SmtpServer 192.168.x.x `
-Attachments "C:\ThedataIwanttosend.rar"
If you try to export your report in an html file or something else and then mail it to those that must receive it? does this solution works for you? if you run your script you have any results?
You are setting $Query to a text and then you never update with something new.
your -body takes $query as text so it is right to get that text as a mail.
Send-MailMessage #SMTPProperties -Body $query -BodyAsHTML | Format-Table
Are you getting the right data from the Function you are using? if yes then you have to put those results in a variable and write that variable as a body.
now you have :
$query = "select top 10* from testing"
Send-MailMessage #SMTPProperties -Body $query -BodyAsHTML | Format-Table
so the mail you are getting gets the -body data from the $query variable that is the text you set on the $query variable.
If you want something else in that mail body you have to save it into the $query variable or create a new variable with the results and then add it to the -Body.
Hope it helps.

Related

Cyclic csv-Import to SQL file by file

I try to write a short script that cyclic imports csv-files to a SQL data table that are being dropped in an import folder ($sourceSQL). Each csv-file consists of one line of information (here three columns). To make sure that the file was successfully written to the data table, I check if the unique Id can be found in the table.
So far it works with the first file. However, the second file gets only moved to the destination folder without being written to the data table. I can't find the problem. Is it because of the $data variable?
$StartButton.Add_Click({
$script:ActiveLoop = $true
while ($script:ActiveLoop){
If (Test-Path $sourceSQL){
$data = $null
Do{
$data = import-csv $impcsv -Header A,B,C
foreach($i in $data)
{
$Id = $i.A
$State = $i.B
$Sequence = $i.C
$query = INSERT INTO $SQLTable (Id, State, Sequence)
VALUES ('$Id','$State','$Sequence')"
$impcsv = invoke-sqlcmd -Database $SQLDatabase -Query $query -serverinstance $SQLInstance -Username $SQLUsername -Password $SQLPassword}
$SqlQueryId = "SELECT TOP 1 Id from $SQLTable ORDER BY Id DESC"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLInstance; Database = $SQLDatabase; User ID = $SQLUsername; Password = $SQLPassword"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQueryId
$SqlCmd.Connection = $SqlConnection
$SqlConnection.Open()
$IdCheck= [string]$SqlCmd.ExecuteScalar()
$SqlConnection.Close()
} Until ($Id -eq $IdCheck)
Move-Item $sourceSQL -Destination $destinationSQL
}
[System.Windows.Forms.Application]::DoEvents()
}
})
$objForm.Controls.Add($StartButton)

Powershell to save sql return dataset into csv file

I have the following script to run a script and to return the dataset when I would like the result saved into the folder under csv formet:
$connectionString = "Data Source=$sqlserver; User ID = $username; Password = $pws;Initial Catalog=$database;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$query = “SELECT TOP 5 * FROM Test”
$command = $connection.CreateCommand()
$command.CommandText = $query
$result = $command.ExecuteReader()
$result |export-csv c:\temp\Test.csv -notypeinformation
$connection.Close()
It's generate the csv file, however the contains inside the csv file is the fields count of each row of the dataset instead of the dataset itself. Does anyone know what is going wrong with my script?
Try to change your $result variable from $command.ExecuteReader() to an invoke-sqlcmd
$result = invoke-sqlcmd -query $query -serverinstance $sqlserver -database $database

Powershell how to store and ID giving back from a post method

Okay i wrote the following code to post to an API. The API then returns back an ID that i need to store back into a database. How would i go in doing this i am so confused or is better to store it in memory? I feel that sending it back to sql will be much better. So to be clear again once i run the script i will get back a response back saying that it added what i wanted and it will give me back an ID basically tagging what was added. I need to grab that ID and send it back to a database simultaneously after it is added to the API
$DBServer = "xxxxx"
$DataBaseName = "xxxxxx"
$Connection = new-object system.data.sqlclient.sqlconnection #Set new object to connect to sql database
$Connection.ConnectionString ="server=$DBServer;database=$databasename;trusted_connection=True" # Connection string setting for local machine database with window authentication
Write-host "Connection Information:" -foregroundcolor yellow -backgroundcolor black
$Connection #List connection information to screen
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand #setting object to use sql commands
############ MAIN ####################################
$SqlQuery = #"
SELECT [DeviceId]
,[DeviceName]
FROM [xxx].[dbo].[xxx]
order by 2
"#
$Connection.open()
Write-host "Connection to the $DatabaseName DB was successful." -foregroundcolor green -backgroundcolor black
$SqlCmd.CommandText = $SqlQuery
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$SqlCmd.Connection = $Connection
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$Connection.Close()
###### Will Creds be required??
#Web Client connection
$WebClient = New-Object net.webclient
Add-Type -AssemblyName System.Web.Extensions
#Credentials
$userName ="xxxxxxx"
$password = "xxxxxxxx"
$pair = "$($userName):$($password)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$basicAuthValue = "Basic $encodedCreds"
$Headers = #{
Authorization = $basicAuthValue
}
#ConvertFromJson
$webclient.Credentials = new-object System.Net.NetworkCredential($username, $password)
foreach ($Row in $DataSet.Tables[0].Rows)
{
#Note sure of the URL at this point..
$URL = "https://xxxxxxxxx/xxxx/xx"
$Endpoint = "/devices.json/$($Row[0])/xxxxxxxxx"
$URLSvc = "$URL$Endpoint"
#write-host $URLSvc + " - " + $($Row[1])
########### TEST ####################
# Create JSON Hash
$JsonTemplate = ConvertTo-Json #{
"applicationName"= "xxx-$($Row[1])";
"applicationType"= "xxxxx";
"description1"= "xxxxx";
"description2"= "";
"passwordCompositionPolicyId"= "xxxxx"
}
## Write out for Display
#ConvertFromJson!!!!!!!!!!!!!!!!!!!!
Write-Host $JsonTemplate -foregroundcolor Red -backgroundcolor White
$xxx = Invoke-RestMethod -Method Post -Headers $Headers -Uri $URLSvc -Body $JsonTemplate -ContentType application/json
Write-Host $xxx
}

What is returned from a SQL query into a PowerShell variable?

Here is the function I have setup that works just fine to send queries to a SQL database from PowerShell and return the results (the results are what I don't quite understand)
function Invoke-SQL
{
param (
[string]$server,
[string]$database,
[string]$Query
)
$connectionString = "Data Source=$server; " +
"Integrated Security=SSPI; " +
"Initial Catalog=$database"
$connection = new-object
system.data.SqlClient.SQLConnection($connectionString)
$command = new-object system.data.sqlclient.sqlcommand($Query, $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
}
If I run a query such as the one below (it returns no results, meaning there were no records that existed that matched the condition) why does it return nothing when I just put in $results? Why is the result 'Table' when I do Write-Host $results ? See below
PS>$results = Invoke-SQL -server 'servername' -database 'DBname' -Query "SELECT * FROM [DBname].[dbo].[TableName] WHERE UserID = 'x' AND ComputerName = 'x'"
PS>$results
PS>Write-Host $results
Table
When no records are found I thought it would be equal to "" or $null but it is not upon testing
$null test
PS>If ($results -eq $null) {
>> write-host "Null"}else{
>> write-host "Not Null"
>> }
Not Null
"" test
PS>If ($results -eq "") {
>> write-host "Empty"}else{
>> write-host "Not Empty"
>> }
If someone could explain this to me, and what options I might have in order to check if a query returns no results, that would be great!
Read the comments on the question post for more details.
In order to see if records were returned or not, this will return the number of rows (records) returned. Credit to #Bill_Stewart.
($results | Measure-Object).Count
#Tomalak provided a helpful link.
#BaconBits had this helpful tip to get the type of an object
$results.GetType().FullName
# or
$results | Get-Member
Thank you all for your help.

Powershell array correlation to SQL table dataset from powershell

First off, I'm new to stack. I have referenced stack many times in the past, but recently I have been stuck on this issue for quite sometime. So here goes.
My goal:
I am attempting to correlate an array output from VMware that matches a custom value on each VM machine. ( an asset ID ) to a value ( ID Key ) on a microsoft SQL 2000 server.
As such, since this server is pre 2005 I am unable to use the invoke-sqlcmd powershell command. I have to utilize the full SQL connection string and command structure to return a value out of this database. This sql statement and script works fine on its own. Meaning that the sql portion of this script, functioning on its own will pull results out of the database with a manual tag number put in place of my variable "$etag". I'm fairly new to powershell, and sql use from powershell.
So here is my script with names of the protected taken out.
#========================================================================
# Created on: 12/4/2013 2:01 PM
# Created by: Shaun Belcher
# Filename:
#========================================================================
function get-inventory
{
Add-PSSnapin VMware.VimAutomation.Core
$date=get-date
$vcenterserver = #("srv-1","srv-2","srv-3")
Connect-VIServer -server $vcenterserver
$toAddr="user#domain.com"
$fromAddr="user#domain.com"
$smtpsrv="mail.domain.com"
#Variables
$mdesks=#()
$sqlServer = "serverdb"
$sqlDBNAME = "instance"
$sqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection
$DataSet = New-Object System.Data.DataSet
$sqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.connection = $sqlConnection
$sqlAdapter.SelectCommand = $sqlCmd
#db Connection
$sqlConnection.ConnectionString = "Server = $sqlServer; Database = $sqlDBname; Integrated Security=True;"
$SqlCmd.connection = $SqlConnection
$SqlCmd.commandtext = $sqlQuery
$sqlAdapter.SelectCommand = $sqlCmd
$sqlQuery += "SELECT INVHARDW_PropTag as proptag, invhardw_clientID as ClientID, invhardw_notes as Notes FROM INV_Hardware where invhardw_proptag = '$etag';"
$SqlCmd.commandtext = $sqlQuery
$sqlAdapter.SelectCommand = $sqlCmd
$sqlAdapter.Fill($DataSet)
$DataSet.Tables[0]
$sqlConnection.Close()
$mdesks = #($DataSet.Tables[0] | select propTag, ClientID, Notes)
$virtuals= #(Get-VM | select Name,vmhost,memoryMB,#{N="Datastore";E={[string]::Join(',',(Get-Datastore -Id $_.DatastoreIdList | Select -ExpandProperty Name))}})
$etags = #(Get-vm | Get-Annotation |select value,#{N="mDeskNote";E={[string]::Join(',',($mdesk | Where-Object {$mdesks.propTag = $_;}))}},#{N="mDeskClientID";E={[string]::Join(',',($mdesk | Where-Object {$mdesks.propTag = $_;}))}})
if($virtuals -ne $null){
$body = #("
<center><table border=1 width=50 % cellspacing=0 cellpadding=8 bgcolor=Black cols=3>
<tr bgcolor=White><td>Virtual Machine</td><td>Host Machine</td><td>Memory Allocated</td><td>DatastoreList</td><td>Asset Tag</td><td>App Note</td><td>App Client ID</td></tr>")
$i = 0
do {
#if($i % 2){$body += "<tr bgcolor=#D2CFCF><td>$($virtuals[$i].Name)</td></tr>";$i++}
#else {$body += "<tr bgcolor=#EFEFEF><td>$($virtuals[$i].Name)</td></tr>";$i++}
if($i % 2){$body += "<tr bgcolor=#D2CFCF><td>$($virtuals[$i].Name)</td><td>$($virtuals[$i].VMHost)</td><td>$($virtuals[$i].MemorymB)</td><td>$($virtuals[$i].datastore)</td><td>$($etags[$i].value)</td><td>$mdesks[$i].notes</td><td>$mdesks[$i].ClientID</td></tr>";$i++}
else {$body += "<tr bgcolor=#EFEFEF><td>$($virtuals[$i].Name)</td><td>$($virtuals[$i].VMHost)</td><td>$($virtuals[$i].memorymb)</td><td>$($virtuals[$i].datastore)</td><td>$($etags[$i].value)</td><td>$mdesks[$i].notes</td><td>$mdesks[$i].ClientID</td></tr>";$i++}
}
while ($virtuals[$i] -ne $null)
$body += "</table></center>"
# Send email.
if($attachmentPref){
$virtuals | Export-CSV "Inventory $($date.month)-$($date.day)-$($date.year).csv"
Send-MailMessage -To "$toAddr" -From "$fromAddr" -Subject "$vcenterserver Inventory = $countvms" -Body "$body" -Attachments "Inventory $($date.month)-$($date.day)-$($date.year).csv" -SmtpServer "$smtpsrv" -BodyAsHtml
Remove-Item "Inventory $($date.month)-$($date.day)-$($date.year).csv"
}
Else{
Send-MailMessage -To "$toAddr" -From "$fromAddr" -Subject "Inventory $vcenterserver = $countvms" -Body "$body" -SmtpServer "$smtpsrv" -BodyAsHtml
}
}
Disconnect-VIServer -Server $vcenterserver -Confirm:$false exit
get-inventory
This returns the information and sends it in an email with columns and rows of the information. Again, these are two working scripts that just do not return the result that is sought after.