How to save result from SQL query in Powershell string variable? - sql

I using invoke-sqlcmd to query a database on MSSMS. This works no problem.
I have a loop that runs the query X amount of times and the query returns a keycode eg. TGHDWS4.
I need this keycode as a string in powershell. I then want to add the string to an array.
The only thing i've tried is using invoke-sqlcmd. I have seen other examples on the net that use connection creation and connection close methods but i dont want to have to do that if possible.
The below code is where i'm at. How do I add the keycode (returned from the query) to an array as a string?
#Enter your confirmation numbers here;
$confArray = #(
'0000000090519838',
'0000000090059392'
)
$resultArray = #()
#Function that runs for each element in the above array
function getKeycode ($confNumber) {
$QueryFmt= "
select distinct top 100
aa.deliveryKeycode as 'Keycode'
from appointment a with (nolock)
left join appointmentattribute aa with (nolock) on aa.appointmentid = a.appointmentid
where
a.confirmationnumber in (
'"+ $confNumber + "'
)
"
$result = Invoke-Sqlcmd -ServerInstance myserver -Database mydatabase -Query $QueryFmt
$resultArray.Add($result)
}
#the for loop
foreach($con in $confArray){
getKeycode -confNumber $con
$count ++;
}

I guess by just returning your array from within your function:
# ...
$result = Invoke-Sqlcmd -ServerInstance myserver -Database mydatabase -Query $QueryFmt
$resultArray.Add($result)
return $resultArray
}

Writing to an array in the parent scope from your function is a bit of an anti-pattern, I'd strongly advise against it.
Just return Invoke-SqlCmd ... directly:
function Get-Keycode ([int]$confNumber) {
$QueryFmt= "
select distinct top 100
aa.deliveryKeycode as 'Keycode'
from appointment a with (nolock)
left join appointmentattribute aa with (nolock) on aa.appointmentid = a.appointmentid
where
a.confirmationnumber in (
'"+ $confNumber + "'
)"
return Invoke-Sqlcmd -ServerInstance myserver -Database mydatabase -Query $QueryFmt
}
# Assign the output of the foreach loop to `$KeyCodes`
$KeyCodes = foreach($con in $confArray){
Get-Keycode -confNumber $con
$count++
}

Related

PowerShell SQL query issue

I'm reading a CSV column and checking it using my SQL Server Table1 column and then updated table2 column like this but I'm not sure why it's working.
I'm getting 99 for all the rows even though my CSV column is not all empty and the value is exactly matched in table1. Any help or suggestion would be really appreciated.
$CSVImport = Import-CSV $CSVFileName
ForEach ($CSVLine in $CSVImport) {
$CSVEvent = $CSVLine.Event
$CSVName = $CSVLine.Name
if($CSVEvent -eq ''){
$EventID = '99'
}else{
$EventID = "SELECT Convert(int,Event_Id) From Table1 WHERE Event_name = '$CSVEvent'"
Invoke-Sqlcmd -Query $EventID
}
$query = "INSERT INTO Table2(Event_Id, Name) VALUES($EventID, '$CSVName');"
Invoke-Sqlcmd -Query $query
}
}
Invoke-Sqlcmd -Query $EventID
This outputs the result of your query instead of capturing it in a variable. In the absence of assigning the output to a variable, redirecting it, or sending it through the pipeline, it prints to the display.
I assume the intent is to store the result of the Invoke-Sqlcmd in variable $EventID, as an integer:
$EventID = Invoke-Sqlcmd -Query $EventID | ForEach-Object { $_[0] }
However, note that if the query returns multiple rows, $EventID will be an array of integers.

Oracle SQL query returns some data when it should be empty-PowerShell

I am writing a script in PowerShell Core 7.2. I get a list of files from a folder that I check against Oracle db. I need the data of Description, and NC_Name column if the file is in db.
The issue is that even when the file is not in db it still returns the data but of some other file.
For example: I have a list of files, File#1, File#2,File#3. If File#2 is not in the db it still returns the data of File#1.
I have tried counting the number of rows and putting it as a condition. As in
$rowNum = $connection.count
The issue with this is that $rowNum is never zero because it returns data for some other file; because the variable $fileName is never empty.
I also tried checking for the file name in the query itself but it gave a lot of errors. The query was
$query="DECLARE record_exists INTEGER; BEGIN SELECT COUNT(*) INTO record_exists FROM NC_PROGRAMS WHERE NC_PROGRAMS.NC_NAME = '$fileName' AND ROWNUM = 1; IF record_exists = 1 THEN Select DESCRIPTION, NC_NAME"
The code is:
#Get all files
$result = $start.EnumerateDirectories() | ForEach-Object -Parallel {
$_.GetFiles('*.EIA', $using:enum)
}
$result | Format-Table -AutoSize
foreach($item in $result){
$fileName = $item.BaseName
#Oracle connection
Add-Type -Path C:\lib\netstandard2.1\Oracle.ManagedDataAccess.dll
$query = "Select DESCRIPTION, NC_NAME From NC_PROGRAMS WHERE
NC_PROGRAMS.NC_NAME = '$fileName' "
$connectionString = "connectionString"
$connection = New-Object Oracle.ManagedDataAccess.Client.OracleConnection($connectionString)
$connection.Open()
$command = $connection.CreateCommand()
$command.CommandText = $query
$reader = $command.ExecuteReader()
$rowNum = $connection.count
Write-host "Number of rows-"$rowNum
while($reader.Read()) {
$description=$reader.GetString(0)
$fastemsFileName = $reader.GetString(1)
}
$connection.Close()
}

How to use IN clause with SQLParameters?

My function works perfectly if I provide one instance of ComputerName value. My question is how to modify SQL query so it could accept an array? I don't believe creating a loop to query a database several times is a proper way. For example, I think this SQL query with IN clause is a proper way:
SELECT * FROM Customers WHERE Country IN ('Germany', 'France', 'UK');
In other words, I'd like to be able to call this function providing multiple ComputerName values. Like this:
PS C:\>Get-Query_Database_Query1('comp01','comp02')
The code I need help with. Please use SQLParameters to build SQL query:
function Get-Query_Database_Query1
{
[OutputType([System.Data.DataTable])]
param
(
[Parameter(Mandatory = $false,
Position = 1)]
[string]$PCname
)
#Database Query
$QueryString = "select * from [Table1] where [ComputerName]=#PCname"
#Database Connection String
$ConnectionString = 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Open\Database4.mdb;Password=;User ID=Admin'
$command = New-Object System.Data.OleDb.OleDbCommand ($QueryString, $ConnectionString)
$Command.Parameters.Add("#PCname", [System.Data.OleDb.OleDbType]::VarChar, 50).Value = $PCname;
$adapter = New-Object System.Data.OleDb.OleDbDataAdapter ($command)
#Load the Dataset
$dataset = New-Object System.Data.DataSet
[void]$adapter.Fill($dataset)
#Return the Dataset
return #( ,$dataset.Tables[0])
}
You need to do a little bit of string manipulation, also when working with SQL queries is a lot easier to use Here Strings.
If you are going to pass multiple computers to your functions, the parameter $PCname has to be able to accept an array of strings, hence changing [string] to [string[]].
Check out this code and see if it works for you:
function Get-Query_Database_Query1
{
[OutputType([System.Data.DataTable])]
param
(
[Parameter(Mandatory = $false,
Position = 1)]
[string[]]$PCname
)
#Database Query
$QueryString = #"
SELECT *
FROM [Table1]
WHERE [ComputerName] IN ('{0}')
"# -f ($PCname -join "','")
$QueryString
}
Get-Query_Database_Query1 -PCname 'computer1','computer2','computer3','computer4'
Here is how the query should look like:
PS /home/> Get-Query_Database_Query1 -PCname 'computer1','computer2','computer3','computer4'
SELECT *
FROM [Table1]
WHERE [ComputerName] IN ('computer1','computer2','computer3','computer4')

Importing CSV columns into SQL table without Sqlcmd

I’m currently importing a csv file and inserting some of the results into a table.
Unfortunately I’m using Sqlcmd, but the module isn’t installed on the relevant server and can’t be installed (out of my control).
Is there a way to manage the exact same as the below, outside of SqlCMD?
Example Code:
$server = 's'
$database = 'd'
$table = 't'
Import-CSV C:\Test\Test.csv | ForEach-Object {Invoke-Sqlcmd `
-Database $database -ServerInstance $server `
-Query "INSERT INTO $table VALUES ('$($_."Column One")',
'$($_."Column Two")',
NULL,
'$($_.""Column Three"")')"
}
You can try the ADO.Net objects:
# Hardcode the table name, unless you *REALLY* trust your users.
$SQL = "INSERT INTO TableName VALUES (#Column1, #Column2, NULL, #Column3)"
$conn = new-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=$server;Database=$database;Integrated Security=True;"
$cmd = new-Object System.Data.SqlClient.SqlCommand($SQL, $conn)
# Use actual types and lengths from the database here
$c1 = $cmd.Parameters.Add("#Column1", [System.Data.SqlDbType]::NVarChar, 20)
$c2 = $cmd.Parameters.Add("#Column2", [System.Data.SqlDbType]::NVarChar, 20)
$c3 = $cmd.Parameters.Add("#Column3", [System.Data.SqlDbType]::NVarChar, 20)
$conn.Open()
Import-CSV C:\Test\Test.csv | ForEach-Object {
$c1.Value = $_."Column One"
$c2.Value = $_."Column Two"
$c3.Value = $_."Column Three"
$cmd.ExecuteNonQuery()
}
$conn.Close()
This will also fix any issues with apostrophes in the data, which would have caused HUGE problems in the original.
You could try and use the bulk insert command, search for a simple SQL connection and query execution - the exact one that Joel Coehoorn posted, if you have bulk permissions and the server has access to the file itself. you could also add parameters to it and then call it however you see fit. Meaning you could foreach files in folder, call the bulk insert with your connection.
BULK INSERT TableName
FROM 'LinkToSourceFile.csv' WITH (
FIELDTERMINATOR = '\t',
ROWTERMINATOR = '\n',
FIRSTROW = 2
);

Powershell insert into MS Access with WHERE clause

Trying to insert values into MS Access DB based on values entered into a powershell form with a WHERE clause. I'm receiving a simple error but struggling to resolve ("Missing Semicolon (;) at end of SQL Statement")
Here is my base code;
$query = "INSERT INTO SignIns ([DateTimeOUT], [SignedOut]) VALUES ('$($info.F1)','$($info.F2)') FROM $Info WHERE SignIns.Surname = '$($Info.F3)'"
$cmd = $conn.CreateCommand()
$cmd.CommandText = $query
$result = $cmd.ExecuteNonQuery()
$conn.Close()
I've amended to add a semicolon in all places I thought could resolve, but no luck, still returns the same error (Missing Semi Colon at end of SQL statement);
$query = "INSERT INTO SignIns ([DateTimeOUT], [SignedOut]) VALUES ('$($info.F1)','$($info.F2)') FROM $Info WHERE SignIns.Surname = '$($Info.F3);';";
$cmd = $conn.CreateCommand()
$cmd.CommandText = $query;
$result = $cmd.ExecuteNonQuery();
$conn.Close()
(for reference, I've added a semi-colon at the end of my WHERE clause, at the end of the $Query variable and tried to append onto the end of $query when executing in the $cmd.commandtext variable, and also on the end of the $result variable.
I expect the statement to execute as normal and update with the given values. Testing within Access DB itself is difficult as I am unable to reference my PS form from within the DB. Any help greatly appreciated,
Thanks.
Update: Ameding query to UPDATE now lets me 'insert' values with WHERE statement following a simple logic.
$conn.Open()
$query = "UPDATE SignIns SET DateTimeOUT = '$($info.F1)' WHERE SignIns.Surname = '$($Info.F3)'";
$cmd = $conn.CreateCommand()
$cmd.CommandText = $query;
$result = $cmd.ExecuteNonQuery();
$query = "UPDATE SignIns SET SignedOut = '$($info.F2)' WHERE SignIns.Surname = '$($Info.F3)'";
$cmd = $conn.CreateCommand()
$cmd.CommandText = $query;
$result = $cmd.ExecuteNonQuery();
$conn.Close()
It is not a method I'm normally use to when inputting new values into a table, but same result so.. I don't think there's any implications. It probably takes the update as 'Update from NULL to VALUE' as opposed to INSERT FROM source to DESINTATION (where)