SQL DB export using powershell - sql

I am attempting to export BLOB data for images stored in a remote SQL server and save them to an export folder in .jpg on the local machine. Any assistance in troubleshooting the first error or helping me modify the working connection to pull the blob data and convert it to .jpgs on the local machine would be much appreciated.
I found the following code
$Server = "?????"
$Database = "??????"
$Dest = "c:\Export\"
$bufferSize = 8192
$sqlCommand = " SELECT ID?????1
FROM dbo.W?????e; "
$authentication = "Integrated Security=SSPI;"
$connectionString = "Provider=sqloledb; " +
"Data Source=$dataSource; " +
"Initial Catalog=$database; " +
"$authentication; "
$connection = New-Object System.Data.OleDb.OleDbConnection $connectionString
$command = New-Object System.Data.OleDb.OleDbCommand $sqlCommand,$connection
$connection.Open()
$reader = $command.ExecuteReader()
$out = [array]::CreateInstance('Byte', $bufferSize)
While ($reader.Read())
{
$fileStream = New-Object System.IO.FileStream ($Dest + $reader.GetString(0)), Create, Write
$binaryWriter = New-Object System.IO.BinaryWriter $fileStream
$start = 0
$received = $reader.GetBytes(1, $start, $out, 0, $bufferSize - 1)
While ($received -gt 0)
{
$binaryWriter.Write($out, 0, $received)
$binaryWriter.Flush()
$start += $received
$received = $reader.GetBytes(1, $start, $out, 0, $bufferSize - 1)
}
$binaryWriter.Close()
$fileStream.Close()
}
$fileStream.Dispose()
$reader.Close()
$command.Dispose()
$connection.Close()
I am getting errors when running the code.
I can connect to the database using this code, but I dont understand the streamprocess enough to mesh the code to do what I want
$Server = "?????"; # SQL Server Instance.
$Database = "?????";
$Dest = "c:\Export\"; # Path to export to.
$bufferSize = 8192; # Stream buffer size in bytes.
$connString = "data source=?????,1433;Initial catalog=?????;Integrated Security=TRUE;"
$QueryText = "SELECT ID?????1
FROM dbo.W??????e;"
$SqlConnection = new-object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = $connString
$SqlCommand = $SqlConnection.CreateCommand()
$SqlCommand.CommandText = $QueryText
$DataAdapter = new-object System.Data.SqlClient.SqlDataAdapter $SqlCommand
$dataset = new-object System.Data.Dataset
$DataAdapter.Fill($dataset)
$dataset.Tables[0]
Write-Output ("Finished");
This is what I am trying to accomplish, but I am getting errors casting the bytes to string
HERE

I bet your command timeout is too short. By default, it is 30 seconds. Blobs are usually very large, and I wouldn't be surprised if it is taking longer than 30 seconds to read them all from the database. Try setting the timeout to something really, really large:
$command.CommandTimeout = [Int32]::MaxValue

I got the same error.
Reading the original code a little closer the SQL Server name is for an instance. If you are executing this on the local server you can use "." as the server name.
$Server = ".";

Related

Check if the sql command gets timeout through powershell

I wrote a script whose purpose is to take all the files under a particular folder and in a loop to perform on the files SQL procedures in parallel (3 files at the same time).
I've seen some timeouts in the database but Powershell does not give me an error message about that. Is there a way to get errors about these timeouts?
I tried to deal with the problem by increasing the timeout value and yet the problem is not solved so I'll have to at least have a test on the subject or an error message.
I added the increased timeout to the script in the connection string and with: $Command.CommandTimeout =
param($fileName)
Import-Module sqlps -DisableNameChecking
$sqlserver = "SQLSERVERNAME"
$Connection = New-Object System.Data.SQLClient.SQLConnection
$Connection.ConnectionString = "server=SQLSERVERNAME;integrated security = True;connection Timeout=60;"
$Connection.Open()
$Command = $Connection.CreateCommand()
$Command.CommandTimeout = 60
#Start procedure
$Command.CommandText = "EXEC [DBNAME].[dbo].[usp_procname] #FileName"
$Command.Parameters.AddWithValue("#FileName", $fileName)
$Command.Connection = $Connection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $Command
$DataTable = New-Object System.Data.DataTable
$SqlAdapter.Fill($DataTable)
$Connection.Close()
I would really appreciate your help.

SQL Server query via PowerShell not returning expected results

I have a PowerShell script that is querying my local SQL Server database. I know it can connect and talk to the database because if I change my connection information to be wrong, my try/catch block throws the expected error. I have a table called MaintMode with 2 columns in it: SiteName and Status.
When I run a SELECT SiteName, Status FROM dbo.MaintMode in SQL Server Management Studio, I get:
SiteName Status
MySite off
which is great. However, when I have my PowerShell script run that exact same query, it just returns 1 to the console. How can I get my PowerShell script to return the same output that I would see in SQL Server Management Studio?
My PowerShell code is as follows:
# Set up connection to the SQL Server
$SQLServer = "localhost\SQLEXPRESS"
$SQLDBName = "MaintSiteDB"
$uid = "removed"
$pwd = "removed"
#Specify the query to run
$SqlQuery = "SELECT SiteName, Status FROM dbo.MaintMode;"
#Build connection to the SQL Server
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database =
$SQLDBName; Integrated Security = false; User ID = $uid; Password = $pwd;"
#Connect to the SQL Server and run the query
Try
{
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$QueryResult = $SqlAdapter.Fill($DataSet)
}
catch
{
Write-Output "Failed to connect to $SQLServer. Please check your
connection parameters and try again."
Break
}

Powershell - SQL Server - connectionstring in loop for multiple Instances

Thisis part of a bigger script which finds DatabaseFiles on a SQL Server machine (multiple instances).
Following should just return all files for 3 instances.
The server is called V3000801 and there is one default instance + 2 named instances on there. It's ok with me if either default or named doesn't work I'll work around this alone (most likely create a flag and do default with another connection string).
$SqlCmd.ExecuteNonQuery() just returns -1 which does not make any sense for me.
Thanks for the help
for($i=0;$i -lt $instances.Length;$i++){
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection;
$Server= "V3000801\"+$instances[$i];
$SqlConnection.ConnectionString = "Server = $server ; Database = master; Integrated Security = sspi;trusted_connection=true";
$sqlQuery="SELECT physical_name FROM sys.master_files;";
Write-Host $SqlConnection.ConnectionString;
$SqlConnection.Open();
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand;
$SqlCmd.CommandText = $sqlQuery;
$SqlCmd.Connection = $SqlConnection;
$SqlCmd.ExecuteNonQuery();
$SqlConnection.Close();
}
the link posted by #jody contains some good information
try:
$dr= $SqlCmd.ExecuteReader()
while ($dr.Read())
{
$dr.GetValue(0)
}
$sqlconnection.Close()
Use the ExecuteReader function for selects. ExecuteNonQuery is used for operations that do not return any results such as inserts, updates and deletes.
Here is an example in .NET but it should be similar in PowerShell.
EDIT:
This code should work. I tried it out on my own environment (with a different server name).
for($i=0;$i -lt $instances.Length;$i++){
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection;
$Server= "V3000801\"+$instances[$i];
$SqlConnection.ConnectionString = "Server = $server ; Database = master; Integrated Security = sspi;trusted_connection=true";
$sqlQuery="SELECT physical_name FROM sys.master_files;";
Write-Host $SqlConnection.ConnectionString;
$SqlConnection.Open();
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand;
$SqlCmd.CommandText = $sqlQuery;
$SqlCmd.Connection = $SqlConnection;
$reader = $SqlCmd.ExecuteReader();
while ($reader.Read())
{
"pfad=" $reader["physical_name"];
};
$SqlConnection.Close();
}

sqlbulkcopycolumnmapping import csv to table issue

I am at a loss. I am trying to import columns from a csv into an existing data table. I believe the best way to do this is through column mapping using sqlbulkcopy but i just cant wrap my head around this. Im using the script below with the out-datatable function to do column mapping and even though it appears to insert the data, when i run a query i cannot find it. What am i doing wrong?
import-module .\functions.psm1
# Database variables
$sqlserver = "Db-test-dev\sql2008"
$database = "Employees"
#$table = "dbo.tblPersonal"
$csvfile = "C:\temp\cidb_test.csv"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.connectionstring = "Data Source=$sqlserver;Integrated Security=true;Initial Catalog=$database;"
$CSVDataTable = Import-Csv ‘$csvfile’ | Out-DataTable
$sqlBulkCopy = New-Object (“Data.SqlClient.SqlBulkCopy”) -ArgumentList $SqlConnection
$sqlBulkCopy.DestinationTableName = “dbo.tblpersonal”
$ColumnMap1 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping(1, 1)
$ColumnMap2 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping(2, 2)
#$ColumnMap3 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping(2, 3)
$sqlBulkCopy.ColumnMappings.Add($ColumnMap1)
$sqlBulkCopy.ColumnMappings.Add($ColumnMap2)
#$sqlBulkCopy.ColumnMappings.Add($ColumnMap3)
$SqlConnection.Open()
$sqlBulkCopy.WriteToServer($CSVDataTable)
$SqlConnection.Close()
Added column mapping using bulkcopy
$ColumnMap1 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('SSN','SSN')
$ColumnMap2 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('LastName', 'LastName')
$ColumnMap3 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('MiddleName','MiddleName')
$ColumnMap4 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('FirstName','FirstName')
$ColumnMap5 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('PreferredName','PreferredName')
$ColumnMap6 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('WorkPhone','WorkPhone')
$ColumnMap7 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('Email','Email')
$ColumnMap8 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('EmpType','EmpType')
$ColumnMap9 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('HireDate', 'HireDate')
$ColumnMap10 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('ACID','ACID')
$ColumnMap11 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('OPID','OPID')
$ColumnMap12 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('Floor','Floor')
$ColumnMap13 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('Department','Department')
$ColumnMap14 = New-Object System.Data.SqlClient.SqlBulkCopyColumnMapping('Division','Division')
$BulkCopy.ColumnMappings.Add($ColumnMap1)
$BulkCopy.ColumnMappings.Add($ColumnMap2)
$BulkCopy.ColumnMappings.Add($ColumnMap3)
$BulkCopy.ColumnMappings.Add($ColumnMap4)
$BulkCopy.ColumnMappings.Add($ColumnMap5)
$BulkCopy.ColumnMappings.Add($ColumnMap6)
$BulkCopy.ColumnMappings.Add($ColumnMap7)
$BulkCopy.ColumnMappings.Add($ColumnMap8)
$BulkCopy.ColumnMappings.Add($ColumnMap9)
$BulkCopy.ColumnMappings.Add($ColumnMap10)
$BulkCopy.ColumnMappings.Add($ColumnMap11)
$BulkCopy.ColumnMappings.Add($ColumnMap12)
$BulkCopy.ColumnMappings.Add($ColumnMap13)
$BulkCopy.ColumnMappings.Add($ColumnMap14)

Add SQL Server Instances to Central Management Server Groups with Powershell

I am trying to create a script to automatically iterate through a text file of all our SQL Server instances and add each on if it doesn't already exist to the CMS. I want to try doing this through SMO instead of hardcoding sql strings in. Below is what I have so far but it doesn't seem to be working. Any help would be appreciated. Thanks.
Eventually I will add more If statements in to distribute the instances to certain groups but for now I'm just trying to get it to populate everything.
$CMSInstance = "cmsinstancename"
$ServersPath = "C:\Scripts\InPutFiles\servers.txt"
#Load SMO assemplies
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Management.RegisteredServers') | out-null
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Management.Common') | out-null
$connectionString = "Data Source=$CMSINstance;Initial Catalog=master;Integrated Security=SSPI;"
$sqlConnection = new-object System.Data.SqlClient.SqlConnection($connectionString)
$conn = new-object Microsoft.SqlServer.Management.Common.ServerConnection($sqlConnection)
$CMSStore = new-object Microsoft.SqlServer.Management.RegisteredServers.RegisteredServersStore($conn)
$CMSDBStore = $CMSStore.ServerGroups["DatabaseEngineServerGroup"]
$Servers = Get-Content $ServersPath;
foreach($Server in $Servers)
{
#Put this in loop to deal with duplicates in list itself
$AlreadyRegisteredServers = #()
$CMSDBStore.GetDescendantRegisteredServers()
$RegServerName = $Server.Name
$RegServerInstance = $Server.Instance
if($AlreadyRegisteredServers -notcontains $RegServerName)
{
Write-Host "Adding Server $RegServerName"
$NewServer = New-Object Microsoft.SqlServer.Management.RegisteredServers.RegisteredServer($CMSDBStore, "$RegServerName")
$NewServer.SecureConnectionString = "server=$RegServerInstance;integrated security=true"
$NewServer.ConnectionString = "server=$RegServerInstance;integrated security=true"
$NewServer.ServerName = "$RegServerInstance"
$NewServer.Create()
}
else
{
Write-Host "Server $RegServerName already exists - cannot add."
}
}
I cut your script down to just the basics and it works for me. I did have to change the connection command to work in my environment but other than that and registering a default instance of SQL Server there were no errors. Once I did a refresh of the CMS server the newly registered server was visible and accessible.
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Management.RegisteredServers') | Out-Null
$CMSInstance = 'CMS_ServerName'
$connectionString = "Data Source=$CMSInstance;Initial Catalog=master;Integrated Security=SSPI;"
$sqlConnection = new-object System.Data.SqlClient.SqlConnection($connectionString)
$conn = New-Object System.Data.SqlClient.SqlConnection("Server=$CMSInstance;Database=master;Integrated Security=True")
$CMSStore = new-object Microsoft.SqlServer.Management.RegisteredServers.RegisteredServersStore($conn)
$CMSDBStore = $CMSStore.ServerGroups["DatabaseEngineServerGroup"]
$RegServerName = 'ServerToRegister'
$RegServerInstance = $RegServerName
$NewServer = New-Object Microsoft.SqlServer.Management.RegisteredServers.RegisteredServer($CMSDBStore, "$RegServerName")
$NewServer.SecureConnectionString = "server=$RegServerInstance;integrated security=true"
$NewServer.ConnectionString = "server=$RegServerInstance;integrated security=true"
$NewServer.ServerName = "$RegServerInstance"
$NewServer.Create()