Execute SQL command with powershell and specifying the domain account - sql-server

I am putting together some powershell scripts to execute SQL commands against SQL Server and need to specify the windows account to use in the connectionstring. I have tried the following which does not work.
$SQLServer = ".\sqlexpress"
$SQLDBName = "dbname"
$uid ="domain\user
$pwd = "password"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = false; User ID = $uid; Password = $pwd;"
$SqlCmd.Connection = $SqlConnection
$SqlConnection.Open();
.... Execute query...
I get the following error.
Exception calling "Open" with "0" argument(s): "Login failed for user
'Domain\user'.
I was lead to understand that if you specify false on integrated security then is would take the username and password and connect using the corresponding windows account.
For me this is failing to connect. Am I missing something here ?
Many thanks
Darren

Another way to tackle this would be to use the SQL PowerShell Module (SQLPS) which can be obtained by installing "Management Tools" from the SQL Management Studio Installer. By default, when using Invoke-Sqlcmd it will connect as the windows account that initiated the PowerShell instance. If you wish to run as another windows account other than the one you are signed in with, you would shift + right click PowerShell and choose option to "run as different user".
Once Module has been installed, you can import module by executing:
Import-Module SQLPS
Next you would execute your query like the following:
Invoke-Sqlcmd -ServerInstance "ServerName\Instance" -Database "DatabaseName" -Query "Some Query Here"
While entirely optional, I would recommend adding -Verbose as this will show you output just as you would see in Sql Management Studio.
Hope this helps.

Related

how to execute sql script using azure devops pipeline

I have SQL script which I want to execute using azure DevOps pipeline
I found multiple tasks for SQL but can not find any required task where I can pass sql server , database name and login details. Is there any task available for this ?
If there is not any task available and only way to execute is powershell script any sample available script for this ?
You can use PowerShell to execute sql scripts. Example:
Invoke-Sqlcmd -InputFile "$(scriptfilepath)" -ServerInstance $(sqlserver) -Database $(dbname) -Username "$(username)" -Password "$(pwd)" -QueryTimeout 36000 -Verbose
Add custom variables (scriptfilepath, sqlserver, ...) and set values to them.
PowerShell task
Define variables
Invoke-Sqlcmd
You can use Invoke-Sql command like this
$SQLServer = "TestServerOne"
$db3 = "TestDB3"
$qcd = "PRINT 'This is output'"
Invoke-Sqlcmd -ServerInstance $SQLServer -Database $db3 -Query $qcd -Username "User" -Password "Password" -Verbose
Make sure SqlServer module is installed. It works also with Powershell Core
You can also try to use Run SQL Server Scripts Task extension
If you want to do this in Azure Release Pipeline (classic), you can use the '
Azure SQL Database deployment
' block which uses Invoke-Sqlcmd under the hood.
With that, you can configure it to execute an SQL script on a given database under one or your subscriptions or service connections.

Unable to Process Partition in Power BI Premium Model Using SQL Server Agent Powershell CmdExec Step

I am trying to use Analysis Services Cmdlets to process partitions on a Power BI Premium Model. My PowerShell script works fine when run from ISE, the command line, and when scheduled using windows task scheduler; however, when I try to schedule the PowerShell script using a SQL Server 2019 Agent job using a step type of
Operating System (CmdExec)" the following error message is encountered.
Message Executed as user: MyDomain\MyUser. Invoke-ProcessPartition : The
connection string is not valid. At
C:\Users\MyUser\Desktop\PS1\SSAS\wtf.ps1:15 char:11 + $asResult =
Invoke-ProcessPartition -Credential $UserCredential -Server...+
CategoryInfo : NotSpecified: (:) [Invoke-ProcessPartition],
ConnectionException + FullyQualifiedErrorId :
Microsoft.AnalysisServices.ConnectionException,Microsoft.AnalysisServices.PowerShell.Cmd
lets.ProcessPartition.
I have followed the steps in this blog article to setup the job. The same windows user is used in all three run scenarios. The SQL server is my local development SQL server of which the windows user is SA on the SQL Server and Windows Admin. The same machine the SQL Instance is on is being used for successfully executing the other three ways of running the PS scripts, (ISE, Command Line, & Windows Task Scheduler)
If I run the following from the command line on the same machine as the SQL server, my local host, the PowerShell script runs successfully.
PowerShell -File "C\Users\MyUser\Desktop\PS1\SSAS\wtf.ps1"
Below is my PowerShell script modified to be as small as possible to demonstrate issue and of course sensitive information redacted. Thanks in advance for any help, I'm at a loss at how to proceed. I really need this to work from the SQL agent so I don't have to guess when steps that the processing depends on have completed.
$ErrorActionPreference=”Stop”
Import-Module "SqlServer"
$User = "MyUser#MyDomain.com"
$PWord = ConvertTo-SecureString -String "MyPassword" -AsPlainText -Force
$UserCredential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $User, $PWord
$server = "powerbi://api.powerbi.com/v1.0/myorg/MyWorkspace"
$db = "MyModel"
$asResult = Invoke-ProcessPartition -Credential $UserCredential -Server $server -PartitionName "DimDate" -TableName "DimDate" -Database $db -RefreshType "Full"
The step code in my job is:
powershell -File "C:\Users\MyUser\Desktop\PS1\SSAS\wtf.ps1"
UPDATE:
I have discovered that if I target an on-prem SSAS server, the exact same code, with the exception of the server variable, does work using the SQL Agent method, but of course switching to on-prem is not what I desire.
UPDATE 2:
When I right click on a job within SSMS, and click "Start PowerShell" this opens up a SQL Server PowerShell Window. If I try executing the script this way I get the below error message. The account being used does not have MFA enabled.
Unable to obtain authentication token using the credentials provided.
If your Active Directory tenant administrator has configured
Multi-Factor Authentication or if your account is a Microsoft Account,
please remove the user name and password from the connection string,
and then retry. You should then be prompted to enter your credentials.
If I don't pass a credential to the Invoke-ProcessPartition command using the SQL Server PowerShell window, I get prompted for credentials and the call works. Of course I can't use this as a workaround because I need it to run unattended.
I also tried opening PowerShell ISE as the account being used for authentication to the Workspace in the PS script and it also gives the same error as the SQL Server Agent Job does.
The connection string is not valid.
I have found a solution to the issue. The resolution was twofold.
First problem was that when PowerShell was being run from the SQL Server Agent, the Version of the SqlServer module was an older outdated version. I found this out by executing a ps1 file from the SQL Server Agent Job using the following code and looking in the job history results.
Get-Command -module sqlserver invoke*
I tried running
Install-Module sqlserver -AllowClobber -Scope AllUsers
as an admin but it did not update the SqlServer module the SQL agent was running. Instead I created a ps1 file that simply runs
Install-Module sqlserver -AllowClobber -Scope CurrentUser -Force
and called the script using a SQL Agent CMD task and this updated the SqlServer module version. After this I started getting a more useful error message:
Unable to obtain authentication token using the credentials provided.
If your Active Directory tenant administrator has configured
Multi-Factor Authentication or if your account is a Microsoft Account,
please remove the user name and password from the connection string,
and then retry. You should then be prompted to enter your
credentials
With this new error message, I decided to try an alternate way of supplying credentials by utilizing Azure Service Principals. This new method resulted in success from all PowerShell methods including SQL Server Agent Job. The steps implemented are outlined in this Power BI Documentation.
The final PS code looks like this.
$ErrorActionPreference=”Stop”
Import-Module "SqlServer"
$AppId = "AAD_App_Registration_Application_Client_Id"
$TenantId = "AAD_App_Registration_Directory_Tenant_Id"
$AppSecret = "AAD_App_Registration_CertificatesAndSecrets_ClientSecret"
$PWord = ConvertTo-SecureString -String $AppSecret -AsPlainText -Force
$Credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $AppId, $PWord
Invoke-ProcessPartition -Server "powerbi://api.powerbi.com/v1.0/myorg/MyModel" -PartitionName "DimDate" -TableName "DimDate" -Database "MyModel" -RefreshType "Full" -ServicePrincipal -ApplicationId $AppId -TenantId $TenantId -Credential $Credential

Unable to connect Powershell to AzureSQL database

I am writing a Powershell script that should connect and query the database (that is hosted in Azure). I am able to connect without a problem to SSMS using my AzureAD ID. However, I am unable to do the same in Powershell. I am using this pattern for my connection string:
"Server=tcp:myserver.database.windows.net,1433;Authentication=Active Directory Password;Database=myDataBase;UID=myUser#myDomain;PWD=myPassword;"
Just to be clear, the connection string works perfectly fine and the DB admin told me that I have all the needed permissions. What is the possible cause for this? I tried both Invoke-SqlCMD and ADO.net. Please help!!
Here is a piece of code I ran as a test and it worked fine.
$server = "tcp:thesqlservername.database.windows.net,1433"
$database = "testdb"
$adminName = "testuser01#mytenantname.onmicrosoft.com"
$adminPassword = "TestPassword"
$connectionString = "Server=$server;Database=$database;User ID=$adminName;Password=$adminPassword;authentication=Active Directory Password;"
$connection = New-Object -TypeName System.Data.SqlClient.SqlConnection($connectionString)
$ds = new-object "System.Data.DataSet" "dsPersonData"
$q = #"
SELECT * FROM [SalesLT].[Customer]
"#
$da = new-object "System.Data.SqlClient.SqlDataAdapter" ($q, $connection)
$da.Fill($ds)
$dtPerson = $ds.Tables[0]
I created a demo azure sql db, set the test user as "active directory admin" on the sql server in azure, and installed smss (management studio) on my desktop to test.
what error are you getting?

Connecting to SQL Server 2012 (using Windows auth) via powershell Enter-PSSession

Hope you can assist me with an issue I am facing. This is a lengthy one to provide context. In short, my Windows auth access to a SQL Server 2008 R2 database fails as it appears to be trying to access the database as 'NT AUTHORITY\ANONYMOUS LOGON' and not the current user.
Here's my scenario: server farm with multiple servers running standalone SQL Server databases on which a number of PowerShell scripts need to be run, which connect to the databases and run some queries & based on the queries, make some updates to some database tables. We're failing at Windows auth login to the database (which works fine with SQL Server Mgmt Studio v10).
It looks something like this:
win7pc PS C:> Enter-PSSession -ComputerName winsvr2k8r2
[winsvr2k8r2]: PS c:\users\svs_acct1>
[winsvr2k8r2]: PS c:\users\svs_acct1> Set-Location C:
NB: there is a script directory that is part of the $env:PATH set in the profile
[winsvr2k8r2]: PS c:\users\svs_acct1> . .\users\svs_acct1\bin\Run-AdminTasks
Script output
Loading AD module ...
Setting Global Variables ...
I am user: domreff1\dbappuser
Initiating DB Connection using windows auth to: sTango # hgr23992\atr77504
with connect string ...
Data Source=hgr23992\atr77504;Initial Catalog=sTango;Integrated Security=SSPI
ERROR
Exception calling "Open" with "0" argument(s): "Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'."
At C:\users\svs_acct1\bin\Run-AdminTasks:21 char:20
+ $SqlConnection.open <<<< ();
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
The relevant DB connection elements in the script:
$SQLServer = "hgr23992\atr77504";
$SQLDBName = "sTango";
$SQLDBUser = [Security.Principal.WindowsIdentity]::GetCurrent().Name;
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Data Source=$SQLServer;Initial Catalog=$SQLDBName;Integrated Security=SSPI"
$SqlConnection.open();
I have trawled through various posts and tried connection string a number of different ways e.g.
Data Source=$SQLServer;Initial Catalog=$SQLDBName;Integrated Security=[Yes|True|SSPI]
with no joy.
Any ideas on what the issue may be and why the DB connection seems to be reflecting a different context/user to what I am running the script as?
The problem is kerberos auth and the missing delegation of the token.
You could enable CredSSP auth for powershell (on client & server side). Please do this only over SSL otherwise you're vulnerable for an MITM.
check
https://msdn.microsoft.com/en-us/library/ee309365(v=vs.85).aspx

Execute a .SQL file in Powershell without having SQL Server installed?

I need to provide a powershell script that runs a bunch of steps to install a custom solution. One of these steps is create a SQL Server database and execute a .sql file to generate the schema.
The thing is that I need a way of doing it in any machine, whether is has SQL server locally installed or not (it usually is on another network machine).
Also I need to avoid using 3rd party modules since I cannot force clients to install them.
Is there a way of doing this?
UPDATE: The server running the script will have .NET 4.5 installed since SharePoint 2013 will be installed.
Something like this:
#Variables
$sqlServer = "."
$sqlDBName = "master"
$sqlQuery = "CREATE DATABASE test"
# Create the connection string
$sqlConnectionString ="Server = $sqlServer; Database = $sqlDBName; Integrated Security = True"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = $sqlConnectionString
#Create the SQL Command object
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $SqlQuery
$SqlCmd.Connection = $SqlConnection
#Open SQL connection
$SqlCmd.Connection.Open()
#Execute the Query
$ReturnValue = $SqlCmd.ExecuteNonQuery()
--Edit
Technically GO is not a T-SQL command. It's the end-of-batch marker recognised by Microsoft SQL tools (Management Studio, isql, osql). So that is why when you execute the statement directly, it isn't recognized. The 'real' solution is to either eliminate the GO statements, or split up the statements into separate batch processes (either physically or string.split("GO"))
Or the alternate using SQL Management Object which theoretically can handle "Go" statements (SqlCommand() ExecuteNonQuery() truncates command text):
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
$SMOServer = New-Object ('Microsoft.SqlServer.Management.Smo.Server')
$SMOServer.ConnectionContext.ConnectionString = $sqlConnectionString
$SMOServer.ConnectionContext.ExecuteNonQuery($sqlQuery)
--Edit 2
Or, if you can't use SQL Management Object, and you have "GO" Statements, something quick and dirty is that you can split the string and use code like this:
#Variables
$sqlServer = "."
$sqlDBName = "master"
$sqlQuery = "CREATE DATABASE test; GO; CREATE DATABASE test2; GO;"
# Create the connection string
$sqlConnectionString ="Server = $sqlServer; Database = $sqlDBName; Integrated Security = True"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = $sqlConnectionString
$sqlQuery -split "GO;" | ForEach-Object{
if($_ -ne "")
{
#Create the SQL Command object
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $_
$SqlCmd.Connection = $SqlConnection
#Open SQL connection
$SqlCmd.Connection.Open()
#Execute the Query
$ReturnValue = $SqlCmd.ExecuteNonQuery()
#Close the connection
$SqlCmd.Connection.Close()
}
}
You can use the ordinary .NET classes SqlConnection and SqlCommand from PowerShell. To do that you don't need SQL Server, nor any specific PowerShell modules, installed. Just create the objects using the New-Object cmdlet.
Update:
Here's a sample of how you could do (no error handling added) to call execute SQL code without using SQL specific cmdlets:
$connectionString = "" #Set your connection string here
$connection = New-Object -TypeName System.Data.SqlClient.SqlConnection($connectionString)
$query = "" #Set your sql query here
$command = New-Object -TypeName System.Data.SqlClient.SqlCommand($query, $connection)
$connection.Open()
$command.ExecuteNonQuery() #Other methods are available if you want to get the return value of your query.
$connection.Close()
You are trying to do something that perhaps cannot be done, depends on your definition of "sql not installed". If the client does not have the sql client tools installed, you will not be able to talk directly to sql server at all.
If you need to install sql server on a remote computer, you will not in general be able to do so without admin permissions, and doing so remotely with admin permissions is still complicated as SQL server 2012 is not designed for a remote install -- though you could perform a remote install using the CMD processor via remote connection (if you have some way to do that as this is not built in to the standard windows installation.
If the sql client tools are installed on your local machine (where you are running powershell) and sql server is running on the remote machine -- and you have a database login with suitable permissions, you can instantiate SqlCommand objects to do everything you might need.

Resources