MSSQl 'GO' handling in Powershell connection String - sql-server

I have a sql query which is patched with a Go to check the orphan objects in mssql.
use DBName
go
sp_change_users_login 'report'
Now, I am automating the above in Powershell for all the user databases and trying to get the orphan users.
Here is the code:
if($port)
{
$connectionString ="server=$servername,$port;Integrated Security=true;" #uid=$DBUserName; pwd=$dbpwd;Database=$DB;
}
else
{
$connectionString ="server=$servername;Integrated Security=true;"
}
$connection = New-Object System.Data.SqlClient.SqlConnection -ea Stop
$connection.ConnectionString=$connectionString
$connection.Open()
$db_query = #"
Select name from sys.sysdatabases where dbid > 4 and name not in ('ReportServer')
"#
$command = $connection.CreateCommand()
$command.CommandText = $db_query
$result = $command.ExecuteReader()
$object= New-Object System.Data.DataTable
$object.Load($result)
[System.Array]$DBs = $object.name
if($DBs -is [System.Array])
{
foreach($DB in $DBs)
{
## PROBLEM IS HERE ###
$orphan_users_query = #"
use $DB
GO
sp_change_users_login 'report'
"#
$command = $connection.CreateCommand()
$command.CommandText = $orphan_users_query
$result = $command.ExecuteReader()
$object= New-Object System.Data.DataTable
$object.Load($result)
$object | Out-File C:\temp\outfile_property.txt -Append -Force
}
}
Problem is PS cannot identify the go separator because it is specific to MSSQL/SSMS. So, how can I still iterate and run the query in all user databases without creating multiple connections specific to each DB?

Calling ChangeDatabase on the connection is an alternate means of switching databases.
You can then just execute sp_change_users_login as is. No need for GO.

Related

Format Powershell SQL query to print all items in columns

I am using this style of sql connection and want to output the data into a table format but am only getting back the number of items. Having issues installing invoke-sql on old server not sure what the deal is... If any suggestions that would be great, for users that are stuck invoking sql like this :)
$user = "user"
$pwd = "password"
$SQLDBNAME = "database"
$SQLServer = ".\SQLEXPRESS"
$TagTable = "TagTable"
$sqlQuery = "SELECT TOP (10) [TagName] FROM [FactoryTalk_Datalog].[dbo].[TagTable]"
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection
$sqlConnection.ConnectionString = "Server=$SQLServer;Database=$SQLDBName;uid=$user;pwd=$pwd"
#Create and configure a command object
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $sqlConnection
#Create and configure a DataAdpater/DataSet pair of objects
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
#Fill Dataset with Data and close the connection to the database
$SqlAdapter.Fill($Dataset)
Write-Host $DataSet
#$DataSet | Export-Csv -Path "C:\Users\admin\Documents\sqlApplication" -NoTypeInformation -Force
$sqlConnection.Close()
This worked for me :) using .Tables wrote it out perfect.
#Fill Dataset with Data and close the connection to the database
$SqlAdapter.Fill($Dataset)
$DataSet.Tables | Format-Table
write-host $DataSet
#$DataSet | Export-Csv -Path "C:\Users\admin\Documents\sqlApplication" -NoTypeInformation -Force
$sqlConnection.Close()

ADO.NET query not showing in XEvents

I sent a query to SQL Server using an ADO.Net SqlAdapter from PowerShell. The query returns the correct result.
When I run an XEvent session with the sqlserver.sql_statement_starting event, the query from ADO.NET does not show up. Queries I sent from SSMS are shown immediately.
Is this a bug, or why do I not see the ADO.NET queries?
The code I am using is
$serverName = 'localhost'
$databaseName = 'Contoso Retail DW'
$schemaName = 'dbo'
$tableName = 'FactSalesFMCG'
$connString = Get-ConnectionString -IntegratedSecurity -Server $serverName -Database $databaseName
$sqlConn = [System.Data.SqlClient.SqlConnection]::new($connString)
$sqlConn.Open()
$columnMetadataAdapter = Get-ColumnMetadataAdapter -Conn $sqlConn -SchemaName $schemaName -TableName $tableName
$table = [System.Data.DataTable]::new()
$columnMetadataAdapter.Fill($table)
$sqlConn.Close()
Get-ConnectionString and Get-ColumnMetadataAdapter are PowerShell functions that assist in creating the needed ADO.NET objects. The table gets filled with the column metadata I wanted, but the SELECT statement is not shown in XEvents.
Can't repro.
CREATE EVENT SESSION [trc] ON SERVER
ADD EVENT sqlserver.rpc_completed,
ADD EVENT sqlserver.sp_statement_completed,
ADD EVENT sqlserver.sql_batch_completed,
ADD EVENT sqlserver.sql_statement_completed
GO
Start the session and watch live events in SSMS.
Then
PS C:\Users\dbrowne> $da = new-object system.data.sqlclient.sqldataadapter
PS C:\Users\dbrowne> $con = new-object system.data.sqlclient.sqlconnection "server=.;database=tempdb;integrated security=true"
PS C:\Users\dbrowne> $con.open()
PS C:\Users\dbrowne> $cmd = $con.createcommand()
PS C:\Users\dbrowne> $cmd.commandtext = "select * from sys.objects"
PS C:\Users\dbrowne> $da.selectcommand = $cmd
PS C:\Users\dbrowne> $dt = new-object system.data.datatable
PS C:\Users\dbrowne> $da.fill($dt)
106
and see both the sql_statement_completed and the sql_batch_completed (note with different code you might get an rpc_completed instead of a sql_batch_completed).
If you bind parameters into the SqlCommand it will be sent as an RPC call instead of a batch call, and the events will be a bit different rpc/sp instead of batch/sql.
rpc_completed/sp_statement_completed
instead of
sql_batch_completed/sql_statement_completed

Powershell script to set dead lock priority

I am trying to Set DeadLock Priority for my Transaction in my Power shell script but the Deadlock Priority is not maintained across the transaction.
Its running for the first Transaction and dropping for the rest of transaction.
Import-Module SqlServer -Version 21.0.17199
# Connect to your database. $Connection = New-Object System.Data.SQLClient.SQLConnection $Connection.ConnectionString = "" $Command = New-Object System.Data.SQLClient.SQLCommand $Connection.Open() $Command.Connection = $Connection #$connection.Connect() #$Command.CommandText = "SET DEADLOCK_PRIORITY 7;"; $server = New-Object Microsoft.SqlServer.Management.Smo.Server($connection) $database = $server.Databases[$databaseName] [String] $sql = "SET DEADLOCK_PRIORITY 7;"; $result = $database.ExecuteWithResults($sql); $Connection.Close()

Get-ClusterGroup and foreach using imported SQL table

I am looking at getting information from a number of servers i.e. clustername, nodename, and state.
I can get the correct ouput when I hardcode the names into a foreach loop like this:
$clusters = "Cluster1", "Cluster2"
foreach ($cluster in $clusters) {
Get-ClusterGroup -Cluster $cluster
}
but when I run this version that pulls the information from a SQL table its coming up with the below error.
$clusters = $SQLServer = "DatawarehouseServer" #use Server\Instance for named SQL instances!
$SQLDBName = "Datawarehouse"
$SqlQuery = "SELECT clusters FROM dbo.clusters"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$SQLServer;Database=$SQLDBName;Integrated Security=True"
$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)
$SqlConnection.Close()
clear
$DataSet.Tables[0]
foreach ($cluster in $clusters) {
Get-ClusterGroup -Cluster $cluster
}
WARNING: If you are running Windows PowerShell remotely, note that some failover
clustering cmdlets do not work remotely. When possible, run the cmdlet locally
and specify a remote computer as the target. To run the cmdlet remotely, try
using the Credential Security Service Provider (CredSSP). All additional errors
or warnings from this cmdlet might be caused by running it remotely.
Get-ClusterGroup : The cluster service is not running. Make sure that the
service is running on all nodes in the cluster. There are no more endpoints
available from the endpoint mapper
At line:26 char:2
+ {Get-ClusterGroup -Cluster $cluster}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ConnectionError: (:) [Get-ClusterGroup], ClusterCmdletException
+ FullyQualifiedErrorId : ClusterEndpointNotRegistered,Microsoft.FailoverClusters.PowerShell.GetClusterGroupCommand.
I have now been trying this I seem to be getting step closer or a step back depedant on how you look at it. It pulls the correct information out now but for only one cluster:
Thanks to the comments I have managed to get a step further or a step backwards with this:
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=Datawarehouseserver;Database=Datawarehouse;Integrated Security=True"
$SqlConnection.Open()
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = "SELECT clusters FROM dbo.clusters"
$SqlCmd.Connection = $SqlConnection
$clustername = $SqlCmd.ExecuteScalar()
$SqlConnection.Close()
#Write-Output "Cluster is " $dbname
clear
foreach ($cluster in $clustername) {
Get-ClusterGroup -Cluster $cluster
}
You need to iterate over the cluster names returned by your SQL query, but your variable $cluster is never assigned that list of names. Use this instead:
foreach ($cluster in $DataSet.Tables[0].clusters) {
...
}

Pass a query and access SQL Server Database in Powershell

I have a database named 'SQLDatabase'. It has many folders like 'System _Database', 'R_Database','ReportServer' etc.
I need to access 'R_Database'.
Now 'R_Database' has many folders like 'Storage', 'Security', 'Usage', 'Tables'.
I need to access 'Tables'.
Again, 'Tables' have many tables in it.
I need to access a particular table named 'DB_Batch', and update it.
How should I?
This is the code I did for connecting to the SQL Server, and then the Table. But it fails.
$dataSource = ".\MSSQL"
$user = "userID"
$pwd = "password01"
$database = "SQLDatabase"
$connectionString = "Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=False;"
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
#$connection.ConnectionString = "Server=$dataSource;Database=$database;Integrated Security=True;"
$connection.Open()
query = <query>..????
Now I suppose I need to pass a query. How should I?
I need to access the table first and then update it.
I even wrote the following code to end the above code, but not able to test as I am stuck.
$command = $connection.CreateCommand()
$command.CommandText = $query
$result = $command.ExecuteReader()
$result
I request, please help me with this. I have been trying this for days. I am using Powershell v2.0
In order to insert/update a table, use a SqlCommand and its ExecuteNonQuery().
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.connection = $connection
$cmd.commandtext = "INSERT INTO myTable (myColumn) values ({0})" -f $myValue
$cmd.ExecuteNonQuery()

Resources