How to pass csv file as query param in api call using powershell - database

I have developed two simple PS scripts that work fine separately. Script1 connects to a DB, run a sql query and save the output (only one column that is a list of the project names) as csv file. Script2 connects to an endpoint using API calls and prints the details of a projects. I use script1's output as script2's input manually. I have tried a couple of different ways to automate this process but I haven't been able to get it to work. Does anyone know how can I pass the csv file as query param in api call?
Here is what I have so far:
This is Script1:
#SQL Connection variables
$Server = "my server"
$DBName = "db name"
$credential = Import-CliXml -Path "C:\Test\MyCredential.xml"
$User = $Credential.UserName
$PW = $credential.GetNetworkCredential().Password
$Connection = New-Object System.Data.SqlClient.SqlConnection
$Connection.ConnectionString = "Server = $Server; Database = $DBName; User ID = $User; Password = $PW;"
$Connection.Open()
#$Connection.State
$SqlQuery = "select from table example"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.Connection = $Connection
$SqlCmd.CommandText = $SqlQuery
$CxSqlCmd.CommandTimeout = 0
#Creating sql adapter
$SqlAdapter = New-Object System.Data.sqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
#Creating Dataset
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$DataSet.Tables[0] | export-csv -Path $OuputFile -NoTypeInformation
The output for script 1 is 11223344, So I use this project name as my input or query param in my second script.
And this is Script2:
$credential = Import-CliXml -Path "C:\Test\MyCredential2.xml"
$credential = Import-CliXml -Path "C:\Test\MyCredential2.xml"
$APIKEY = $credential.GetNetworkCredential().Password
$token = "APIKEY " + "$APIKEY"
$Params = #{
uri = 'https:myendpoint/search?name=11223344'
Headers = #{'Authorization' = "API KEY $token"}
Method ='GET'
ContentType = 'application/json'
}
$Response = Invoke-RestMethod #Params
I really appreciate it if someone can help me with this.

Related

Livestream data from SQL to Power BI online service using PowerShell or other options

I have an assignment to setup a live Power BI online service tile using live data streaming from SQL table. The data in the table updates every few seconds. Here is what I got so far using PowerShell.
But it appears to be not refreshing the data set every few seconds. What am I missing?
DO
{
$SqlServer = 'ServerName';
$SqlDatabase = 'DBName';
$sleepDuration = 3
$SqlConnectionString = 'Data Source={0};Initial Catalog={1};Integrated Security=SSPI' -f $SqlServer, $SqlDatabase;
$SqlQuery = "SELECT * FROM MyTable;";
$SqlCommand = New-Object -TypeName System.Data.SqlClient.SqlCommand;
$SqlCommand.CommandText = $SqlQuery;
$SqlConnection = New-Object -TypeName System.Data.SqlClient.SqlConnection -ArgumentList $SqlConnectionString;
$SqlCommand.Connection = $SqlConnection;
$SqlConnection.Open();
$SqlDataReader = $SqlCommand.ExecuteReader();
##you would find your own endpoint in the Power BI service
$endpoint = "......My PowerBI Service Push URL.........."
#Fetch data and write out to files
while ($SqlDataReader.Read()) {
$payload =
#{
"Col1" =$SqlDataReader['Col1']
"Col2" =$SqlDataReader['Col2']
}
Invoke-RestMethod -Method Post -Uri "$endpoint" -Body (ConvertTo-Json #($payload))
# Sleep for a second
Start-Sleep $sleepDuration
}
$SqlConnection.Close();
$SqlConnection.Dispose();
} While (1 -eq 1)

Powershell SQL Select statements using csv variables

In the code below, I'm trying to query a DB with multiple select statements using variables brought in from a csv and load a data-table using a reader.
The code runs without error but does not retrieve any data.
$csv = Import-Csv $filepath
$database = "DBNAME"
$connectionString = "Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=True;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
$sqlCommand = $connection.CreateCommand()
$Datatable = New-Object System.Data.DataTable
ForEach ($row in $csv){
$query = "Select Emailaddress,Column2 from Users Where [Emailaddress] = '$row.Email'"
$sqlCommand.CommandText = $query
$DataReader = $sqlCommand.ExecuteReader()
$DataTable.Load($DataReader)
}
$DataTable | export-csv "c:\Output\Seereader.csv" -NoTypeInformation
$connection.Close()
This:
$query = "Select Emailaddress,Column2 from Users Where [Emailaddress] = '$row.Email'"
Should probably be this:
$query = "Select Emailaddress,Column2 from Users Where [Emailaddress] = '$($row.Email)'"
Whilst the previous answer works, it is vulnerable to SQL injection.
Obligatory xkcd
If you're not sure what "SQL Injection" is; it's only a very worthy Google away...
i.e. you really need to go and find out!
The correct way...
Parameterise your queries!
# Your query; with a #param
$Query = "SELECT Emailaddress, Column2 FROM [Users] WHERE [Emailaddress] = #emailAddress";
# Set up your basic command
$command = $connection.CreateCommand()
$command.CommandText = $Query
# Fill in the parameters!
$command.Parameters.AddWithValue("#emailAddress", $row.Email)
# Run boy, run!
$results = $command.ExecuteReader()
# Resultification (that's definitely not a made up word)
$table = New-Object System.Data.DataTable
$table.Load($results)
Safe and sound :-)

How to delete a row from a table in SQL Server using PowerShell script?

$uncServer = "\\10.243.174.102\e$"
$uncFullPath = "$uncServer\New folder\Demo.txt"
$username = "XYZ"
$password = "xyz"
net use $uncServer $password /USER:$username
$SQLServer = "AP-PUN-SRSTEP29\MSSQLSERVER12" #use Server\Instance for named SQL instances!
$SQLDBName = "SystemDB"
$SqlQuery = "Delete * from V_Solution WHERE Notes ='9.4.4'";
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True"
#$SqlConnection.open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
I have SQL Server 2012 installed on a remote server and I want to delete a row from a particular table in a specific database, from a local machine using a PowerShell script. Is is possible to do that?
One method is using ADO.NET objects as you would in any .NET application. The PowerShell example below doesn't require SQL tools to be installed.
To execute the query using Windows authentication, specify Integrated Security=SSPI in the connection string:
$connectionString = "Data Source=YourServer;Initial Catalog=YourDatabase;Integrated Security=SSPI";
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString);
$command = New-Object System.Data.SqlClient.SqlCommand("DELETE FROM dbo.YourTable WHERE YourTableID = 1", $connection);
$connection.Open();
$rowsDeleted = $command.ExecuteNonQuery();
Write-Host "$rowsDeleted rows deleted";
$connection.Close();
To execute the query using SQL authentication, specify User ID=YourSqlLogin;Password=YourSqlLoginPassword in the connection string.
$connectionString = "Data Source=YourServer;Initial Catalog=YourDatabase;User ID=YourSqlLogin;Password=YourSqlLoginPassword";
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString);
$command = New-Object System.Data.SqlClient.SqlCommand("DELETE FROM dbo.YourTable WHERE YourTableID = 1", $connection);
$connection.Open();
$rowsDeleted = $command.ExecuteNonQuery();
Write-Host "$rowsDeleted rows deleted";
$connection.Close();
In either case, DELETE permissions on the table are required.
I'm not sure of the purpose of the NET USE command in the script you added to your question, unless that is to authenticate to the server in a workgroup environment. Personally, I would just use SQL authentication and remove the NET USE ugliness.
EDIT:
In the case of multiple SELECT statements in the same batch, each will return a separate recordset. This will require invoking NextRecordset if you are using a DataReader, which will return false when no more recordsets are available:
$reader = $command.ExecuteReader();
do {
While($reader.Read()) {
#process row here;
}
} while($reader.NextResult());
Alternatively, you could use a DataAdapter to fill a 'DataSet'. The DataSet will contain a separate DataTable for each resultset:
$da = New-Object System.Data.SqlClient.SqlDataAdapter($command);
$ds = New-Object System.Data.DataSet;
$null = $da.Fill($ds);
foreach($dt in $ds.Tables) {
$dt | Out-GridView;
}
You could also tweak your SQL query to concatenate the results into a single resultset using UNION ALL if the number of columns and data types are identical. Here's an example snippet:
$sqlQuery = #("
SELECT *
FROM DB926.dbo.Version_Solution
WHERE Notes ='9.2.7'
UNION ALL
SELECT *
FROM DB_926.dbo.Version_Solution
WHERE Notes ='9.2.7'";
);
$command = New-Object System.Data.SqlClient.SqlCommand($sqlQuery, $connection);
Change your code like this :
$uncServer = "\\10.243.174.102\e$"
$uncFullPath = "$uncServer\New folder\Demo.txt"
$username = "XYZ"
$password = "xyz"
net use $uncServer $password /USER:$username
$SQLServer = "AP-PUN-SRSTEP29\MSSQLSERVER12" #use Server\Instance for named SQL instances!
$SQLDBName = "SystemDB"
$SqlQuery = "Delete from V_Solution WHERE Notes ='9.4.4'";
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True"
$SqlConnection.open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlCmd.ExecuteNonQuery
$SqlConnection.Close()

How do I account for CSV column titles and null rows when trying to import a CSV to SQL Server using PowerShell

I have a large CSV file with 5 columns, the first row being the title of the columns. I'm trying to pass the values to a datatable using powershell that I then pass to a table-value parameter to load the data into my SQL Server instance. My SQL Server table has already been created with the 5 columns, but I am running into issues.
cls
#CSV variables
$csvfile = "C:\Students\test.csv"
$csvdelimiter = ","
$firstRowColumns = $true
#creating the datatable
$dt = New-Object System.Data.Datatable
$reader = New-Object System.IO.StreamReader $csvfile
$columns = (Get-Content $csvfile -First 1).Split($csvdelimiter)
foreach ($column in $columns)
{
if ($firstRowColumns -eq $true)
{
[void]$dt.Columns.Add($column)
$reader.ReadLine()
} else { [void]$dt.Columns.Add() }
}
# Read in the data, line by line
while (($line = $reader.ReadLine()) -ne $null)
{
[void]$dt.Rows.Add($line.Split($csvdelimiter))
}
function ExecSproc
{
param ($Conn, $Sproc, $Parameters=#{})
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure
$SqlCmd.Connection = $Conn
$SqlCmd.CommandText = $Sproc
foreach($p in $Parameters.Keys){
[Void] $SqlCmd.Parameters.AddWithValue("#$p",$Parameters[$p])
}
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter($SqlCmd)
$DataSet = New-Object System.Data.DataSet
[Void] $SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
return $DataSet.Tables[0]
}
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "server='.';database='ActiveStudents';trusted_connection=true;"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
ExecSproc -Conn $SqlConnection -Sproc spInsertStudents -Parameters #{TVP = $dt}
These are the errors being thrown:
Exception calling "Add" with "1" argument(s): "Input array is longer than the number of columns in this table."
At C:\Scripts\ActiveStudentInsert.ps1:24 char:2
Exception calling "Fill" with "1" argument(s): "Conversion failed when converting the nvarchar value '' to data type int.
The data for table-valued parameter "#TVP" doesn't conform to the table type of the parameter. SQL Server error is: 245, state: 1
The statement has been terminated."
Chad Miller made a great script in the Script Gallery that outputs DataTables in a very similar way to the one you are looking to do.
If you used his functions, then it would look something like this:
$dt = Import-Csv $csvfile | Out-DataTable
If you have a really large amount of data, I would recommend you check out the SQL BCP command-line utility.

Pass a variable from Powershell to saved SQL Script

I have a Powershell Function that is being used to run multiple queries in SQL and export as CSVs. Each of these queries relies on a date variable. Is there a way to pass this date variable from Powershell into these SQL Scripts (not stored procedures) using my current setup? Any help is much appreciated!
Function Run-Query
{
param([string[]]$queries,[string[]]$sheetnames)
Begin
{
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $Database; User ID = $uid; Password = $pwd;"
Write-host "Connection to database successful."
}#End Begin
Process
{
# Loop through each query
For($i = 0; $i -lt $queries.count; $i++)
{
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
# Use the current index ($i) to get the query
$SqlCmd.CommandText = $queries[$i]
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
# Use the current index ($i) to get the sheetname for the CSV
$DataSet.Tables[0] #| Export-Csv -NoTypeInformation -Path "C:\Users\mbaron\Downloads\$($sheetnames[$i]).csv"
}
}#End Process
End
{
$SqlConnection.Close()
}
}#End function run-query.
You could add a marker in your queries where the data is being used, then do a replace with the relevant date, e.g.:
cls
$date = '1/1/2016'
$query = 'some $$marker$$ script'
$query = $query.replace('$$marker$$', $date )
$query

Resources