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

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
}

Related

Powershell connect to several INSTANCES of SQL Server

I need to create a script that do:
Get services where name are like MSSQL$* (in order to get all SQL Server instances services)
If the service are running, goes to check name
If the name of the service is like MSSQL$MICROSOFT##WID, throw a System.Exception
If not, try to connect to every instances running on the server, if one of them are inaccessible, throw a System.Exception
My current script:
$ErrorActionPreference = "Stop"
try {
$running = Get-Service | where {($_.Status -eq "Running") -and $_.Name -like "MSSQL*"}
$services = (Get-Service -Name 'MSSQL*')
$running.Status | Foreach-object {
if ($running.status -contains 'Running'){
if ($_.Name -ne 'MSSQL$MICROSOFT##WID'){
$instances = (get-itemproperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server').InstalledInstances
foreach ($instance in $instances){
$server = "localhost"
$database = "master"
$sql = "select name from sys.databases"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$server;Database=$database;Integrated Security=SSPI"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $sql
$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]
$return = ($DataSet.Tables[0])
if ($return -ne $null){return 1} else {[System.Exception]}
}}
} else {[System.Exception]}
}}catch{[System.Exception]}
finally{$ErrorActionPreference = "Stop"}
Check status of services with MSSQL*
If status of services is running, check name of service, if the name of service is equal to MSSQL$MICROSOFT##WID throw a System.Exception, if not, list all instances and then, foreach instance in instances, try to connect
If the connection is successful, return 1, if not, throw System.Exception
My questions are: with this script, doesn't matter how many instances have already installed in the server, only check the default... how can I make try the connection for every instance that is running?
I need to check the connection to each instance running on the server, if there is someone stopped, or inaccessible must throw a System.Exception.
And too, is not possible use dbatools, and invokesql...
Somebody knows how to make the connection to every instances running on the server, if one of them are inaccessible, throw a System.Exception?
------------------- UPDATED ------------------------
this string succesfully connect with an example of instance
$SqlConnection.ConnectionString = "Server='localhost\NEWINSTANCE';Database=master;Integrated Security=SSPI"
I just try to send the server trough variable, but give me error...
if ($_.Name -ne 'MSSQL$MICROSOFT##WID'){
$SQLinstancesold = dir "SQLSERVER:\SQL\(local)"
$SQLinstances = $SQLinstancesold | Format-table -HideTableHeaders
foreach ($SQLinstance in $SQLInstances) {
$server = 'localhost\'+$SQLinstance;
$database = "master"
$sql = "select name from sys.databases"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server='localhost\NEWINSTANCE';Database=master;Integrated Security=SSPI"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $sql
$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]
$return = ($DataSet.Tables[0])
if ($return -ne $null){return 1} else {echo "else of return 1"}
}}
I dont know how can I pass the variable to connectionstring in order to do the connection for each instance
--------------------------- UPDATED 2 -----------------------
I just modified the script:
Import-Module SQLPS -DisableNameChecking
$ErrorActionPreference = "Stop"
try {
$running = Get-Service | where {($_.Status -eq "Running") -and $_.Name -like "MSSQL*"}
$services = (Get-Service -Name 'MSSQL*')
$running.Status | Foreach-object {
if ($running.status -contains 'Running'){
if ($_.Name -ne 'MSSQL$MICROSOFT##WID'){
$SQLinstancesold = dir "SQLSERVER:\SQL\(local)"
$SQLinstances = $SQLinstancesold | Format-table -HideTableHeaders
$server = 'localhost\'+$SQLinstance;
foreach ($SQLinstance in $SQLInstances) {
$server = 'localhost\'+$SQLinstance;
$return = Invoke-Sqlcmd -ServerInstance $server -Database master -Query "select name from sys.databases"
if ($return -ne $null){return 1} else {echo "else of return 1"}
}}
} else {echo "here"}
}
}
catch{echo "hello?"}
finally{$ErrorActionPreference = "Stop"}
This way, list all instances, and for each instance declare variable server and try to invoke-sqlcmd
But, when I try to invoke $server on $return variable, give me an error, if I write for example the name of my instance NEWINSTANCE, return 1, that is correct
How can I put variable $server in order to get all instances on invokesqlcmd?

Convert SQL varbinary content into .pkg file using PowerShell

I use SQL Server and I have a SQL table called [dbo].[TemplatePackageContent] which has only two fields:
[TemplatePackageContentId] [uniqueidentifier] NOT NULL,
[Content] [varbinary](max) NULL
I'd like to create PowerShell script which reads whole content from this table and for each row, it will generate a file, in a given directory with format {TemplatePackageContentId}.pkg based on the Content field.
So far I've managed how to read the whole content of the table:
param(
[string] $dataSource = "(localdb)\mssqlLocalDb",
[string] $database = "Hda_tenancy1",
[string] $sqlCommand = $("SELECT * FROM TemplatePackageContent")
)
$connectionString = "Data Source=$dataSource; " +
"Integrated Security=SSPI; " +
"Initial Catalog=$database"
$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
$command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$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
Now I would like to make a mentioned conversion of received result, presumably looping thru each row.
I found this article which solves a similar problem in c# and I was thinking about using some of the logic from there and try to convert it into a PowerShell script.
What is the most optimal way to convert all the "Content" fields into files with .pkg format and what library should I use or what approach?
Any ideas?
Cheers
I ended up with this solution:
param(
[string] $dataSource = "(localdb)\mssqlLocalDb",
[string] $database = "Hda_tenancy1",
[string] $templatePath = "C:\dev\hubadvance\Seeding\Templates\"
)
$sqlCommand = $("SELECT * FROM TemplatePackageContent");
$connection = new-object System.Data.SqlClient.SQLConnection("Data Source=$dataSource;Integrated Security=SSPI;Initial Catalog=$database");
$cmd = new-object System.Data.SqlClient.SqlCommand($sqlCommand, $connection);
$connection.Open();
$reader = $cmd.ExecuteReader();
$results = #();
while ($reader.Read())
{
$row = #{}
for ($i = 0; $i -lt $reader.FieldCount; $i++)
{
$row[$reader.GetName($i)] = $reader.GetValue($i);
}
$results += new-object psobject -property $row;
}
$connection.Close();
foreach ($row in $results)
{
Write-Host $row.TemplatePackageContentId;
$path = $templatePath + $row.TemplatePackageContentId + ".pkg";
[System.IO.File]::AppendAllText($path, $row.Content);
}

Powershell way to send email with query result in SQL server

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.

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.

How to retrieve OUTPUT statement when calling stored proc through Powershell

I am running the following script in powershell, however I don't seem to be able to retrieve any PRINT statements or error messages? How do I capture all outputs within the powershell session please?
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$sql_server;Database=$sql_db;user ID=$sql_usr;password=$sql_pwd"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.Connection = $SqlConnection
$SqlCmd.CommandText = "$storedProc"
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure
$SqlCmd.Parameters.Add("#COBDate", "$dateVariable")
$handler = [System.Data.SqlClient.SqlInfoMessageEventHandler] {param($sender, $event) Write-Host $event.Message };
$SqlConnection.add_InfoMessage($handler);
$SqlConnection.FireInfoMessageEventOnUserErrors = $true;
$SqlConnection.Open()
$SqlCmd.ExecuteNonQuery()
$SqlCmd.Parameters.value
$SqlConnection.Close()
The way I've implemented Eventhandler is as follows:
#Method 1 use hidden method
$Sqlconnection.FireInfoMessageEventOnUserErrors=$true
#...
$handler = [System.Data.SqlClient.SqlInfoMessageEventHandler] {Write-Host "$($_)"}
$Sqlconnection.add_InfoMessage($handler)
#OR Method 2 use Register-ObjecEvent
Register-ObjectEvent -InputObject $SqlConnection-EventName InfoMessage -Action { Write-Host " $($Event.SourceEventArgs)" } -SupportEvent
#...
$SqlConnection.Open()