PowerShell or SQL Server truncating data - sql-server

I wrote a script that hits a web page, assigns the HTML to a variable, writes the variable value to the screen (just for my debugging purposes), then submits the data to a SQL stored procedure. The stored procedure variable is varchar(max). The database field is varchar(max). But for some reason, the HTML is truncated everytime. The output to the screen is not, so the problem appears to be with my stored procedure call.
$sqlConnection = new-object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = 'server=localhost;integrated security=TRUE;database=datawarehouse'
$sqlConnection.Open()
$sqlCommand = new-object System.Data.SqlClient.SqlCommand
$sqlCommand.CommandType = [System.Data.CommandType]'StoredProcedure'
$sqlCommand.CommandTimeout = 120
$sqlCommand.Connection = $sqlConnection
$sqlCommand.CommandText = "insert_html"
$sqlCommand.Parameters.Add("#source", [System.Data.SqlDbType]"VarChar")
$sqlCommand.Parameters["#source"].Value = 'HTML'
$sqlCommand.Parameters.Add("#dataelement", [System.Data.SqlDbType]"VarChar")
$sqlCommand.Parameters["#dataelement"].Value = 'List'
$sqlCommand.Parameters.Add("#data", [System.Data.SqlDbType]"VarChar", -1)
$sqlCommand.Parameters["#data"].Value = $html
$result = $sqlCommand.ExecuteNonQuery()
$sqlConnection.Close()

Related

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

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.

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

Calling SQL Server stored procedure from powershell

I'm trying to call a SQL Server stored procedure from PowerShell but I always get errors on parameters.
Stored procedure has 8 parameters, all with default values
#simchain nvarchar
#idSimulation int
#idCompany varchar
#modelName nvarchar
#simDate datetime
#mySim int
#statusFloor int
#statusCap int
From Management Studio I can call this procedure even without any parameter, so just executing EXEC [dbo].[E_simulations] works.
From PowerShell I create a connection and a command but I always get an error on missing parameters, for example
Procedure or function 'E_simulations' expects parameter '#simchain', which was not supplied.
Here is my test code (just to test proper execution)
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection;
$SqlConnection.ConnectionString = $ConnectionString;
$SqlCommand = $SqlConnection.CreateCommand();
$SqlCommand.CommandText = "EXEC [dbo].[E_simulations]";
$SqlConnection.Open();
$returnedValue = $SqlCommand.ExecuteNonQuery();
Am I missing something?
I have made quick test. I hope this will help
Made test proc:
CREATE PROC doTest (
#param1 INT = 1,
#param2 VARCHAR(10) = 'xxx'
)
AS
BEGIN
PRINT 'THIS ONE'
SELECT 1 As Data
END
Find PowerShell code, which executes proc:
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=localhost;Database=ForTests;Integrated Security=True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "doTest"
$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]
Execute result gave this
Data
----
1
I done everything same what you wrote and I have result without assigning params

Powershell SQL server update query

I'm trying to connect to a Microsoft SQL Database and update any record that the changed field is = to 'x'. I'm able to query the database but when I attempt to do an update I get this error:
Fill : Exception calling "Fill" with "1" argument(s): "Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding."
This is the script I'm using:
#Create SQL Connection
$con = new-object "System.data.sqlclient.SQLconnection"
#Set Connection String
$con.ConnectionString =(“Data Source=server;Initial Catalog=IDCards;Integrated Security=SSPI”)
$con.open()
$sqlcmd = new-object "System.data.sqlclient.sqlcommand"
$sqlcmd.connection = $con
$sqlcmd.CommandTimeout = 600000
#$sqlcmd.CommandText = “select * from tblPhotoID where changed = 'X'”
$sqlcmd.CommandText = “UPDATE dbo.tblPhotoID SET Changed = '1' WHERE Changed ='X'”
$adapter = New-Object system.data.sqlclient.sqldataadapter ($sqlcmd.CommandText, $con)
$set = New-Object system.data.dataset
$adapter.Fill($set)
There are about 4000 records that would updated currently. The script runs about 30 secs before timing out. I've tried increasing the command timeout and gotten the same results.
Your update statement is not going to return a recordset so there is nothing to fill the dataset. You instead want to try the following:
#Create SQL Connection
$con = new-object "System.data.sqlclient.SQLconnection"
#Set Connection String
$con.ConnectionString =(“Data Source=sb-inft-orange.ads.iu.edu;Initial Catalog=IDCards;Integrated Security=SSPI”)
$con.open()
$sqlcmd = new-object "System.data.sqlclient.sqlcommand"
$sqlcmd.connection = $con
$sqlcmd.CommandTimeout = 600000
$sqlcmd.CommandText = “UPDATE dbo.tblPhotoID SET Changed = '1' WHERE Changed ='X'”
$rowsAffected = $sqlcmd.ExecuteNonQuery()
In your code, you have used $adapter.Fill($set) FYI, It is used to add rows in the DataSet to match those in the data source.Instead you can use $adapter.Update($Set) I think this will solve your problem. Also you can use $sqlcmd.ExecuteNonQuery()
#Create SQL Connection
$con = new-object "System.data.sqlclient.SQLconnection"
#Set Connection String
$con.ConnectionString =(“Data Source=sb-inft-orange.ads.iu.edu;Initial
Catalog=IDCards;Integrated Security=SSPI”)
$con.open()
$sqlcmd = new-object "System.data.sqlclient.sqlcommand"
$sqlcmd.connection = $con
$sqlcmd.CommandTimeout = 600000
$sqlcmd.CommandText = “UPDATE dbo.tblPhotoID SET Changed = '1' WHERE Changed ='X'”
$sqlcmd.ExecuteNonQuery()
$cn = New-Object System.Data.SqlClient.SqlConnection ( "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog.......)
$q = "select ... from .. "
$da = New-Object System.Data.SqlClient.SqlDataAdapter($q, $cn)
$da.SelectCommand.CommandTimeout = 60

How do I call a SQL Server stored procedure from PowerShell?

I have a large CSV file and I want to execute a stored procedure for each line.
What is the best way to execute a stored procedure from PowerShell?
This answer was pulled from http://www.databasejournal.com/features/mssql/article.php/3683181
This same example can be used for any adhoc queries. Let us execute the stored procedure “sp_helpdb” as shown below.
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=HOME\SQLEXPRESS;Database=master;Integrated Security=True"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "sp_helpdb"
$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]
Here is a function that I use (slightly redacted). It allows input and output parameters. I only have uniqueidentifier and varchar types implemented, but any other types are easy to add. If you use parameterized stored procedures (or just parameterized sql...this code is easily adapted to that), this will make your life a lot easier.
To call the function, you need a connection to the SQL server (say $conn),
$res=exec-storedprocedure -storedProcName 'stp_myProc' -parameters #{Param1="Hello";Param2=50} -outparams #{ID="uniqueidentifier"} $conn
retrieve proc output from returned object
$res.data #dataset containing the datatables returned by selects
$res.outputparams.ID #output parameter ID (uniqueidentifier)
The function:
function exec-storedprocedure($storedProcName,
[hashtable] $parameters=#{},
[hashtable] $outparams=#{},
$conn,[switch]$help){
function put-outputparameters($cmd, $outparams){
foreach($outp in $outparams.Keys){
$cmd.Parameters.Add("#$outp", (get-paramtype $outparams[$outp])).Direction=[System.Data.ParameterDirection]::Output
}
}
function get-outputparameters($cmd,$outparams){
foreach($p in $cmd.Parameters){
if ($p.Direction -eq [System.Data.ParameterDirection]::Output){
$outparams[$p.ParameterName.Replace("#","")]=$p.Value
}
}
}
function get-paramtype($typename,[switch]$help){
switch ($typename){
'uniqueidentifier' {[System.Data.SqlDbType]::UniqueIdentifier}
'int' {[System.Data.SqlDbType]::Int}
'xml' {[System.Data.SqlDbType]::Xml}
'nvarchar' {[System.Data.SqlDbType]::NVarchar}
default {[System.Data.SqlDbType]::Varchar}
}
}
if ($help){
$msg = #"
Execute a sql statement. Parameters are allowed.
Input parameters should be a dictionary of parameter names and values.
Output parameters should be a dictionary of parameter names and types.
Return value will usually be a list of datarows.
Usage: exec-query sql [inputparameters] [outputparameters] [conn] [-help]
"#
Write-Host $msg
return
}
$close=($conn.State -eq [System.Data.ConnectionState]'Closed')
if ($close) {
$conn.Open()
}
$cmd=new-object system.Data.SqlClient.SqlCommand($sql,$conn)
$cmd.CommandType=[System.Data.CommandType]'StoredProcedure'
$cmd.CommandText=$storedProcName
foreach($p in $parameters.Keys){
$cmd.Parameters.AddWithValue("#$p",[string]$parameters[$p]).Direction=
[System.Data.ParameterDirection]::Input
}
put-outputparameters $cmd $outparams
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
[Void]$da.fill($ds)
if ($close) {
$conn.Close()
}
get-outputparameters $cmd $outparams
return #{data=$ds;outputparams=$outparams}
}
Here is a function I use to execute sql commands. You just have to change $sqlCommand.CommandText to the name of your sproc and $SqlCommand.CommandType to CommandType.StoredProcedure.
function execute-Sql{
param($server, $db, $sql )
$sqlConnection = new-object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = 'server=' + $server + ';integrated security=TRUE;database=' + $db
$sqlConnection.Open()
$sqlCommand = new-object System.Data.SqlClient.SqlCommand
$sqlCommand.CommandTimeout = 120
$sqlCommand.Connection = $sqlConnection
$sqlCommand.CommandText= $sql
$text = $sql.Substring(0, 50)
Write-Progress -Activity "Executing SQL" -Status "Executing SQL => $text..."
Write-Host "Executing SQL => $text..."
$result = $sqlCommand.ExecuteNonQuery()
$sqlConnection.Close()
}
Use sqlcmd instead of osql if it's a 2005 database
Consider calling osql.exe (the command line tool for SQL Server) passing as parameter a text file written for each line with the call to the stored procedure.
SQL Server provides some assemblies that could be of use with the name SMO that have seamless integration with PowerShell. Here is an article on that.
http://www.databasejournal.com/features/mssql/article.php/3696731
There are API methods to execute stored procedures that I think are worth being investigated. Here a startup example:
http://www.eggheadcafe.com/software/aspnet/29974894/smo-running-a-stored-pro.aspx
I include invoke-sqlcmd2.ps1 and write-datatable.ps1 from http://blogs.technet.com/b/heyscriptingguy/archive/2010/11/01/use-powershell-to-collect-server-data-and-write-to-sql.aspx. Calls to run SQL commands take the form: Invoke-sqlcmd2 -ServerInstance "<sql-server>" -Database <DB> -Query "truncate table <table>" An example of writing the contents of DataTable variables to a SQL table looks like: $logs = (get-item SQLSERVER:\sql\<server_path>).ReadErrorLog()
Write-DataTable -ServerInstance "<sql-server>" -Database "<DB>" -TableName "<table>" -Data $logs I find these useful when doing SQL Server database-related PowerShell scripts as the resulting scripts are clean and readable.
Adds CommandType and Parameters to #Santiago Cepas' answer:
function Execute-Stored-Procedure
{
param($server, $db, $spname)
$sqlConnection = new-object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = 'server=' + $server + ';integrated security=TRUE;database=' + $db
$sqlConnection.Open()
$sqlCommand = new-object System.Data.SqlClient.SqlCommand
$sqlCommand.CommandTimeout = 120
$sqlCommand.Connection = $sqlConnection
$sqlCommand.CommandType= [System.Data.CommandType]::StoredProcedure
# If you have paramters, add them like this:
# $sqlCommand.Parameters.AddWithValue("#paramName", "$param") | Out-Null
$sqlCommand.CommandText= $spname
$text = $spname.Substring(0, 50)
Write-Progress -Activity "Executing Stored Procedure" -Status "Executing SQL => $text..."
Write-Host "Executing Stored Procedure => $text..."
$result = $sqlCommand.ExecuteNonQuery()
$sqlConnection.Close()
}
# Call like this:
Execute-Stored-Procedure -server "enter-server-name-here" -db "enter-db-name-here" -spname "enter-sp-name-here"
I added timeout and show how to reader a scalar or get results using a reader
function exec-query( $storedProcName,$parameters=#{},$conn,$timeout=60){
$cmd=new-object system.Data.SqlClient.SqlCommand
$cmd.CommandType=[System.Data.CommandType]'StoredProcedure'
$cmd.Connection=$conn
$cmd.CommandText=$storedProcName
$cmd.CommandTimeout=$timeout
foreach($p in $parameters.Keys){
[Void] $cmd.Parameters.AddWithValue("#$p",$parameters[$p])
}
#$id=$cmd.ExecuteScalar()
$adapter=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
$dataset=New-Object system.Data.DataSet
$adapter.fill($dataset) | Out-Null
#$reader = $cmd.ExecuteReader()
#$results = #()
#while ($reader.Read())
#{
# write-host "reached" -ForegroundColor Green
#}
return $dataSet.Tables[0]
}

Resources