Connect to SQL Server Database from PowerShell - sql-server

I have looked around online for a while now and found many similar problems but for some reason I can't seem to get this working.
I am just trying to connect to a SQL server database and output the query results to a file - See PowerShell script below. What I am uncertain about is how to integrate the User ID and Password into the connection string.
$SQLServer = "aaaa.database.windows.net"
$SQLDBName = "Database"
$uid ="john"
$pwd = "pwd123"
$SqlQuery = "SELECT * from table;"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True; User ID = $uid; Password = $pwd;"
$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)
$DataSet.Tables[0] | out-file "C:\Scripts\xxxx.csv"
The following error message is received:
Exception calling "Fill" with "1" argument(s): "Windows logins are not supported in this version of SQL Server."

Integrated Security and User ID \ Password authentication are mutually exclusive. To connect to SQL Server as the user running the code, remove User ID and Password from your connection string:
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True;"
To connect with specific credentials, remove Integrated Security:
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; User ID = $uid; Password = $pwd;"

Change Integrated security to false in the connection string.
You can check/verify this by opening up the SQL management studio with the username/password you have and see if you can connect/open the database from there. NOTE! Could be a firewall issue as well.

# database Intraction
$SQLServer = "YourServerName" #use Server\Instance for named SQL instances!
$SQLDBName = "YourDBName"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName;
User ID= YourUserID; Password= YourPassword"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = 'StoredProcName'
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$SqlConnection.Close()
#End :database Intraction
clear

The answer are as below for Window authentication
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=$SQLServer;Database=$SQLDBName;Integrated Security=True;"

Assuming you can use integrated security, you can remove the user id and pass:
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True;"

To connect to SQL Server as an active directory user just start the PowerShell as an active directory user and connect to SQL Server with TrustedSecurity=true

I did remove integrated security ... my goal is to log onto a sql server using a connection string WITH active directory username / password. When I do that it always fails. Does not matter the format ... sam company\user ... upn whatever#company.com ... basic username.

I think that may work only if the specific user in question is explicitly set up to log in with a password on the SQL server database i.e. without inheriting credentials from integrated Windows / single-sign-on

Related

Connecting to an SQL server using a different domain account

I am currently trying to connect to an SQL server using a different domain/username that has permissions for querying the server. Here is the powershell just to test whether or not the connection works,
$connectionString = "Server=<my_server>;Database=<db>;User ID=<domain>\<testuser>;Password=<password>;Trusted_Connection=False;Encrypt=True;TrustServerCertificate=True;";
$connection = New-Object System.Data.SqlClient.SqlConnection($connectionString);
$connection.Open();
$connection.Close();
I end up getting this error.
Exception calling "Open" with "0" argument(s): "Login failed for user '<testuser>'.
I am certain that the username and password is correct. As that's what's in the Client Settings.
But I am wondering if there's additional arguments needed to add to the connection string?
This task needed to be automated, but the solution was to connect to the server using -Credentials to login to the desired user.
$computerName = 'SQLServer'
$adminUsername = 'username'
$adminPassword = ConvertTo-SecureString 'password' -AsPlainText -Force
$adminCreds = New-Object PSCredential $adminUsername, $adminPassword
Invoke-Command -ScriptBlock {
$SQLServer = "sqlserver"
$SQLDBName = "database"
$uid ="account"
$pwd = "password"
$SqlQuery = "SELECT TOP (12) [attribute1]
FROM [table].[dbo].[AAG00200];"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True; User ID = $uid; Password = $pwd;"
$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)
} -ComputerName $computerName -Credential $adminCreds

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) {
...
}

How to query SQL Server using PowerShell?

I found some code online but so far I can't get it to connect to my SQL Server database. I have followed this website to the letter: https://blogs.msdn.microsoft.com/walzenbach/2010/04/14/how-to-enable-remote-connections-in-sql-server-2008/
I have allowed remote connections, added port 1433 to my firewall etc. I then run this code from PowerShell ISE:
$dataSource = “\\SCCM12-01\MSSQLSERVER”
$user = “MyID\OurDomain.org”
$pwd = “MyPassword”
$database = “CM1”
$connectionString = “Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=False;”
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
when I run this 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: SQL Network Interfaces, error: 25 - Connection
string is not valid)"
If you have simple query to do I recommend Select-SQLView powershell module. It allows to quickly select rows from table or view. It stores your database and server name so you do not have to provide this values every time.
As usual You can push results to table or to GridView.
If more complex queries are needed use SQLCommands module.
Not sure why you are getting this error. You can refer to this link https://github.com/Tervis-Tumbler/InvokeSQL
You can try this one-
function Invoke-SQL {
param(
[string] $dataSource = ".\SQLEXPRESS",
[string] $database = "MasterData",
[string] $sqlCommand = $(throw "Please specify a query.")
)
$connectionString = "Data Source=$dataSource; " +
"Integrated Security=SSPI; " +
"Initial Catalog=$database"
$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
$command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
$connection.Open()
$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataSet) | Out-Null
$connection.Close()
$dataSet.Tables
}
The error message actually explains what's wrong:
"SQL Network Interfaces, error: 25 - Connection string is not valid".
There is something amiss on the connection string. What exactly is hard to say as you have masked most of the details. Maybe the smart quotes wreck things? Maybe you got a quote character in the password? Anyway, it looks like you have invalid parameter for the user id:
$connectionString = “Server=$dataSource;uid=$user; pwd=$pwd;Database=$database;Integrated Security=False;”
Try User Id instead of uid like so,
Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;
You properly just need to change 'Integrated Security' to 'true' when not using a db login
**Integrated Security=True**

Remote connection string to database fails for username, but can access via Studio Manager

Whilst my Windows AD account has datareader access to a SQL 2012 database (can access via SQL Studio Manager, perform queries etc), my login seems to fail when I try to perform the same query via a SQL connection through a Powershell script.
So I log into the Computer with my AD Account, same as specified in UID in the connection string, and Powershell is launched under the same account.
This is the SQL Query invoked within Powershell:
$ADComputer='Server1'
$sqlParameters = New-Object System.Data.SqlClient.SqlParameter('#ServerName', $ADComputer)
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server=<servername>;Database=<databasename>;Uid=<domain\user>;Pwd=<password>"
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText =
"SELECT TOP 1 MAX(CIA.EnforcementDeadline) AS EnforcementDeadline
FROM v_collection, v_FullCollectionMembership FCM
INNER JOIN v_Collection COL
ON FCM.CollectionID = COL.CollectionID
INNER JOIN v_CIAssignment CIA
WHERE FCM.CollectionID NOT IN ('SMS00001','SMSDM003')
AND FCM.Name='$ADComputer'"
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlConnection.Close()
$SqlAdapter.Fill($DataSet)
$DataSet.Tables[0]
$LastUpdateDate = $DataSet.Tables[0]
$LastUpdate = $LastUpdateDate | Select Column1 -Expandproperty Column1
Exception calling "Fill" with "1" argument(s): "Login failed for user '<domain\user>'."
It's as if the connection string doesn't notice what's specified.
However, if I remove the UID and PWD and add "Integrated Security" it then works:
$SqlConnection.ConnectionString = "Server=<servername>;Database=<databasename>;Integrated Security=SSPI"
I have also discovered that the line
$SqlAdapter.Fill($DataSet)
Is where the error occurs. Admittedly, I don't consider myself a guru in PS as I am learning, but it sounds as if this could be writing something somewhere that may cause write permission issues?
Hope someone can help or at least explain why it's failing.
thanks
You can't login to SQL Server using a domain account specified in the connection string.
You can either specify user name and password in the connection string using a SQL authentication user (if you enabled Mixed Mode Authentication on the server) or specify "Integrated Security=True" to use current process credentials.
https://msdn.microsoft.com/en-us/library/bb669066(v=vs.110).aspx

Create SQL Connection With Different Domain Credentials

I have the below code for creating a trusted connection to SQL Server and returning the results as a DataTable:
function Execute-SQLQuery {
param (
[Parameter(Mandatory = $true)]
[string]$DbInstance
,
[Parameter(Mandatory = $true)]
[string]$DbCatalog
,
[Parameter(Mandatory = $true)]
[string]$Query
,
[Parameter(Mandatory = $false)]
[int]$CommandTimeoutSeconds = 30 #this is the SQL default
,
[Parameter(Mandatory = $false)]
[System.Management.Automation.Credential()]
[System.Management.Automation.PSCredential]$Credential=[System.Management.Automation.PSCredential]::Empty
)
begin {
$connectionString = ("Server={0};Database={1};Integrated Security=True;" -f $DbInstance,$DbCatalog)
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = $connectionString
#$connection.Credential = $Credential #this is for SQL credentials only
$connection.Open()
}
process {
$command = $connection.CreateCommand()
$command.CommandTimeout = $CommandTimeoutSeconds
$command.CommandText = $query
$result = $command.ExecuteReader()
$table = new-object “System.Data.DataTable”
$table.Load($result)
Write-Output $table
}
end {
$connection.Close()
}
}
I'd like to enable it such that I can specify different domain credentials.
The Credential property on the connection object is for SQL credentials (System.Data.SqlClient.SqlCredential); which is not what I'm after; I want to impersonate a different domain user.
I could add code to run invoke-command using the credential, then call this function within that; however there's a bad smell to that solution / I'm certain something better should exist...
Update
Based on some code found here I amended my code as follows
if($Credential -and ($Credential -ne [System.Management.Automation.PSCredential]::Empty)) {
#remove integrated security to allow credential to be specified
$connectionString = ("Server={0};Database={1};" -f $DbInstance,$DbCatalog) #Integrated Security=True;
#make password read only to allow for conversion
$Credential.Password.MakeReadOnly();
#convert to SQL credential and assign to credential property
$connection.Credential = New-Object System.Data.SqlClient.SqlCredential($Credential.UserName, $Credential.Password);
}
However this didn't work / gave the error: Exception calling "Open" with "0" argument(s): "Login failed for user 'myDomain\myUsername'.
I assume this is what I'd originally thought; i.e. it's expecting an actual SQL user rather than just a user with access to the SQL DB.
NB: I have confirmed through SSMS that this user does have access to the database in question.
For now my workaround is to leave the credential parameter with its default value (leaving it in place such that it's easy to implement this functionality later if desired; even though having this parameter do nothing may be misleading) and am running my powershell ISE session as the relevant user account; not ideal, but sufficient for my immediate needs.

Resources