PowerShell SQL query issue - sql

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.

Related

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()
}

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)

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

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++
}

SQL Query with Powershell - Return Values not maching

So I have some code I wrote to take the input form a text file and run some sql checks against another database I populated:
$volOutput = gc C:\Users\<user>\Desktop\mutant.txt
foreach ($m in $volOutput) {
$check = $m.split()[-1] | select -Unique
foreach ($c in $check) {
#$c - this lists all of them so the foreach is working...
# Build the connection and search the db for $c names.
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=(localdb)\mutex; Database=MutexObjects"
$conn.Open()
$db = $conn.CreateCommand()
$db.CommandText = "select Names from Objects WHERE Names='$c'"
$db.ExecuteScalar()
$conn.Close()
} # Foreach Check
} # First foreach
The return values I get are:
PS C:\> B:\Programming\powershell\parse_vol.ps1
ZonesCounterMutex
ZoneAttributeCacheCounterMutex
ZonesCacheCounterMutex
ZoneAttributeCacheCounterMutex
ZonesLockedCacheCounterMutex
ZonesCounterMutex
ZoneAttributeCacheCounterMutex
ZonesCacheCounterMutex
ZoneAttributeCacheCounterMutex
ZonesLockedCacheCounterMutex
Which is correct, but it's also missing a lot more. If I take individual samples and run queries from within SQL management studio for example, I get:
I populated the word "test" in each list as a....test.
Select Names From Objects WHERE Names='test'
Names
test
But I don't see test on the output from the above code. There are about 5 or 6 more than it's missing that I have validated manually by querying the db w/in SQL management studio.
Any help is much appreciated.
Compare the file content against the full list of Names from the database:
$filecontent = Get-Content "C:\Users\<user>\Desktop\mutant.txt" `
| % { $_.split()[-1] } `
| select -Unique
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=(localdb)\mutex; Database=MutexObjects"
$conn.Open()
$dbwrite = $conn.CreateCommand()
$dbwrite.CommandText = "SELECT Names FROM Objects"
$reader = $dbwrite.ExecuteReader([System.Data.CommandBehavior]::CloseConnection)
$dbcontent = while ( $reader.Read() ) { $reader[0] }
$conn.Close()
Compare-Object $filecontent $dbcontent
Does Compare-Object show differences?