How to safely update database using powershell syntax? - sql-server

I have a PowerShell script which runs safely up to the point of an update. I connect to the database and can read from it, however, I have trouble updating.
Here is a copy of the error message I receive:
"Exception calling "ExecuteNonQuery" with "0" argument(s): "There is already an open DataReader associated with this Command which must be closed first."
At C:\xxx\xxx\ToolsController.ps1:37 char:5
+ $InnerCommand.ExecuteNonQuery()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : InvalidOperationException"
FYI: I posted this before and this is an update to the previous question.
Any help at all would be greatly appreciated.
I have tried attaching the variable at the end of the string i.e '..+$varibale'
also tried #" "# and I have gotten the same result.
$Global:Server = "server"
$Global:Database = "db"
$Global:u = "un"
$Global:p = "pw"
[string]$Query = "SELECT * FROM [dbo].[jobs] WHERE [Run] = 0"
try{
$ConnectionString = "server=$Server;Integrated Security=true;database=$Database;user id=$u;password=$p"
$Connection = New-Object System.Data.SqlClient.SqlConnection
$Connection.ConnectionString = $ConnectionString
$Connection.Open()
}
catch{
"Failed to connect SQL Server"
}
$Command = $Connection.CreateCommand()
$InnerCommand = $Connection.CreateCommand()
$Command.CommandText = $Query
$jobs = $Command.ExecuteReader()
while ($jobs.Read()){
switch($jobs["Script"]){
15
{
$traverse = $jobs["Frequency"] - 1
While ($traverse -ge 0) {
c:\xx\xx\batch $jobs["Date"]
$traverse--
}
"Updating Database...."
$Query2 = "UPDATE [dbo].jobs SET [Run] = 1 WHERE [ID] = $jobs['ID']" <------Error here.
$InnerCommand.CommandText = $Query2
$InnerCommand.ExecuteNonQuery()
"Updating Completed!"
}
}
}
$Connection.Close()
$Connection.Dispose()
Write-Host "Connection Closed"

Add MultipleActiveResultSets=True to the connection string. This will allow interleaving of UPDATE statements while reading from the data reader.

Related

Powershell fails to connect to SQL Server

I am using SQL Server Management Studio version 15.0.18358.0 and I am trying to automate a Flat File SQL Server Imports With PowerShell. I am not an administrator (not sure if that matters). This is my first time attempting such a query as I am completely new to using PowerShell - I referenced the following link which is very useful:
https://www.mssqltips.com/sqlservertip/3208/automating-flat-file-sql-server-imports-with-powershell/.
I basically copy and pasted the code in the link and made edits to the following lines:
$connection.ConnectionString = "Data Source=" + $ENTSQL01LSNR + ";Database=" + $EMTCQIData + ";integrated security=true"
AutoImportCommaFlatFiles -location "Q:\Data Requests\ED TO BED TEST\" -file "ED_TO_BED_DAILY" -extension ".txt" -server "ENTSQL01LSNR" -database "EMTCQIData"
After making these edits, I get the following error:
Exception calling "Open" with "0" argument(s): "A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not
accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection
to SQL Server)"
At line:21 char:5
+ $connection.Open()
Full Code
Function AutoImportCommaFlatFiles($location, $file, $extension, $server, $database)
{
$full = $location + $file + $extension
$all = Get-Content $full
$columns = $all[0]
$columns = $columns.Replace(" ","")
$columns = $columns.Replace(",","] VARCHAR(100), [")
$table = "CREATE TABLE " + $file + "([" + $columns + "] VARCHAR(100))"
$connection = New-Object System.Data.SqlClient.SqlConnection
$buildTable = New-Object System.Data.SqlClient.SqlCommand
$insertData = New-Object System.Data.SqlClient.SqlCommand
$connection.ConnectionString = "Data Source=" + $ENTSQL01LSNR + ";Database=" + $EMTCQIData + ";integrated security=true"
$buildTable.CommandText = $table
$buildTable.Connection = $connection
## Added to function
$x = 0
$insertData.CommandText = "EXECUTE stp_CommaBulkInsert #1,#2"
$insertData.Parameters.Add("#1", $full)
$insertData.Parameters.Add("#2", $file)
$insertData.Connection = $connection
$connection.Open()
$buildTable.ExecuteNonQuery()
$connection.Close()
## Added to function
$x = 1
if ($x = 1)
{
$connection.Open()
$insertData.ExecuteNonQuery()
$connection.Close()
}
}
AutoImportCommaFlatFiles -location "Q:\Data Requests\ED TO BED TEST\" -file "ED_TO_BED_DAILY" -extension ".txt" -server "ENTSQL01LSNR" -database "EMTCQIData"

Can connect to SQL Server from SSMS from other computer but Can't connect to SQL Server in a network from powershell

i am trying to connect to a sql server from powershell and getting this error
Exception calling "Open" with "0" argument(s): "The target principal
name is incorrect. Cannot generate SSPI context." At
C:\Users\Musawwir\Downloads\remotely access db.ps1:10 char:1
+ $Connection.Open()
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: ( [], MethodInvocationException
+ FullyQualifiedErrorId : SqlException Exception calling "Fill" with "1" argument(s):
I can connect to SQL SERVER from other machines through SSMS but can not connect through powershell, also the script runs fine on local machine.
Here is the code i am using :
[string] $Server= "tcp:DESKTOP-J9UQ90E,1433"
[string] $Database = "Eshop"
[string] $SQLQuery= "[dbo].[usp_getCustomerAge]"
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$Server';database='$Database';Connection Timeout=300;Integrated Security=TRUE;UID=ali;PWD=1234"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandText = $SQLQuery
$Command.CommandTimeout=500
$adp = New-Object System.Data.SqlClient.SqlDataAdapter $Command
$data = New-Object System.Data.DataSet
$adp.Fill($data) | Out-Null
$data2 = ''
$emp = ''
foreach($Row in $data.Tables.Rows){
[string]$C_name = $Row[0]
$C_name
$data2= $data2+ "|"+$C_name
$C_name = $C_name+"|"
$C_name | out-file "d:\\test4.txt" -Append
}
$Connection.Close()
#$data2 | out-file "d:\\test4.txt"
The user ali wasn't having access to stored procedure .. changed user from ali to sa and integrated security to false solved the problem

Exception calling "ExecuteReader" with "0" argument(s): "Incorrect syntax near '='."

I am writing a powershell code with an SQL query to get information from one of our Databases and then put that information into a variable for further use.
My entire code works, and does exactly what i want it to do.
But somewhere in this snippet of the code two errors are produced that I can't figure out why happen if the script is actually doing what it's supposed to do.
$Server = "######"
$Database = "######"
$UserSqlQuery = "SELECT [UdstyrsId]
,[Model]
,[Serienr]
,[Udlevdato]
,[Repnr]
,[Notat]
FROM [IT-Support].[dbo].[Udstyrsoplysninger] where aflevdato is null and repnr = $repnr"
function ExecuteSqlQuery($Server, $Database, $UserSQLQuery)
{
$Datatable = New-Object System.Data.DataTable
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server='$Server';database='$Database';integrated security=true;"
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandText = $UserSQLQuery
$Reader = $Command.ExecuteReader();
$Datatable.Load($Reader);
$Connection.Close()
return $Datatable
}
$ResultsDataTable = New-Object System.Data.DataTable
$ResultsDataTable = ExecuteSqlQuery $Server $Database $UserSqlQuery
Error code:
Exception calling "ExecuteReader" with "0" argument(s): "Incorrect syntax near '='."
At C:\Users\adm-#######\Desktop\UserResignation.ps1:70 char:13
+ $Reader = $Command.ExecuteReader();
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SqlException
Exception calling "Load" with "1" argument(s): "Value cannot be null.
Parameter name: dataReader"
At C:\Users\adm-#######\Desktop\UserResignation.ps1:71 char:13
+ $Datatable.Load($Reader);
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentNullException
Line 70 and 71 is these lines in the script:
$Reader = $Command.ExecuteReader();
$Datatable.Load($Reader);
You forgot to declare $repnr for query's where condition and because of that you get syntax error where aflevdato is null and repnr = .
$repnr = 123
$UserSqlQuery = "SELECT [UdstyrsId]
,[Model]
,[Serienr]
,[Udlevdato]
,[Repnr]
,[Notat]
FROM [IT-Support].[dbo].[Udstyrsoplysninger] where aflevdato is null and repnr = $repnr"

How to call a stored procedure with a char parameter from Powershell

I have a Powershell script which I want to execute a SQL Server stored procedure. The stored procedure has a parameter named #backupType which of a CHAR(1) type. I'm calling it like this:
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=(local);Database=master;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "sp_myStoredProcedure"
$SqlCmd.Connection = $SqlConnection
$SqlCmd.Parameters.Add("#backupType", [System.Data.SqlDbType]"Char", 1)
$SqlCmd.Parameters["#backupType"].Value = "F"
$result = $SqlCmd.ExecuteNonQuery()
$SqlConnection.Close()
The error I get is:
Exception calling "ExecuteNonQuery" with "0" argument(s): "Procedure or function 'sp_myStoredProcedure' expects parameter '#backupType', which was not supplied." At line:14 char:1
$result = $SqlCmd.ExecuteNonQuery()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : SqlException
I can only assume I'm specifying the parameter wrong but a Google and search of SO has not surfaced anything helpful. Any ideas?
try with
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure
$SqlCmd.Parameters.Add("#backupType", [System.Data.SqlDbType]::Char, 1).Value="F"

SQL query for Bulk Update

I need to update a table using text file. Currently my code works fine if I perform Get-Content from txt file and then run the SQL update query, but only in case of small data. If the size of text is too long or it contains some special characters, it throws an error as following:
Exception calling "ExecuteReader" with "0" argument(s): "Incorrect syntax near
')</td><td style=\"border:1px solid #cccccc\">#fieldValueEmpty($issue.getCustom
FieldValue($componentTypeCf),'."
At C:\Users\d-mansings\Desktop\Scripted Field Configuration\Script\Prod_UpdateS
cript.ps1:78 char:37
+ $Reader = $Command.ExecuteReader <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Following is the code I'm using:
Function DatabaseQueries(){
#To connect to the SQL database
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "Server=$IPSource ; Database=$DBNameSource ; User ID=$UserIDSource ; Password=$LoginPwdSource;"
$Connection.Open()
#Query to get the ID of the stored script field from propertyentry
$Command1 = New-Object System.Data.SQLClient.SQLCommand
$Command1.Connection = $Connection
$Command1.CommandText = "SELECT [ID] FROM [dbo].[propertyentry] WHERE [PROPERTY_KEY]='com.onresolve.jira.groovy.groovyrunner:customfields' "
$Reader = $Command1.ExecuteReader()
while ($Reader.Read()) {
$ID = $Reader.GetValue($1)
}
#To get the updated script file
$ScriptDir = $ParentDir + '\Script.txt'
$ScriptData = Get-Content "$ScriptDir"
$Connection.Close()
#Query to update the Script in JIRA database
$Connection.Open()
$Command = New-Object System.Data.SQLClient.SQLCommand
$Command.Connection = $Connection
$Command.CommandText = #"
Update [dbo].[propertytext] set [propertyvalue] ='$ScriptData' Where ID=$ID
"#
$Reader = $Command.ExecuteReader()
$Connection.Close()
}
It is difficult to write a complete solution if file contents and database structure are not specified. You surely encountered some kind of SQL injection. SQL Query concatenation is considered harmful and you should avoid it. Use ADO.NET parameters to pass variables ($Command.Parameters.AddWithValue in your example). See the following example:
function Invoke-Sql(
$ConnectionString,
$Query,
$Parameters
) {
$conn = New-Object System.Data.SqlClient.SqlConnection -ArgumentList $ConnectionString
$cmd = New-Object System.Data.SqlClient.SqlCommand -ArgumentList $Query,$conn
$conn.Open()
foreach ($arg in $Parameters.GetEnumerator()){
$cmd.Parameters.AddWithValue($arg.Key, $arg.Value) | Out-Null;
}
$reader = $cmd.ExecuteReader()
if ($reader.Read()) {
[string[]]$columns = 0..($reader.FieldCount-1) |
% { if ($reader.GetName($_)) { $reader.GetName($_) } else { "(no name $_)" } }
do {
$obj = #{}
0..($reader.FieldCount-1) | % { $obj.Add($columns[$_], $reader[$_]) }
New-Object PSObject -Property $obj
} while ($reader.Read())
}
$reader.Dispose()
$cmd.Dispose()
$conn.Dispose()
}
Invoke-Sql `
-ConnectionString "Server=.\SQL2014;Database=Test1;Integrated Security=true" `
-Query 'SELECT Name, Id [ObjectId], Id + 3, #arg FROM IdNameTest' `
-Parameters #{arg = 'Some text'''}
Invoke-Sql `
-ConnectionString "Server=.\SQL2014;Database=Test1;Integrated Security=true" `
-Query 'UPDATE IdNameTest SET Name=#name WHERE Id=#id' `
-Parameters #{name = "'DROP DATABASE Death;! %&#!$"; id=1}
Thanks for the response, I have figured out a way to execute the query by just using a replace function, as it was getting confused between the single inverted commas
select REPLACE(Cast(propertyvalue AS varchar(Max)), '''', '''''') FROM [dbo].[propertytext] WHERE ID=$ID

Resources