How to add Managed Identity user to Azure SQL database with Powershell? - powershell

I'm trying to create a deploy script in powershell to create and configure the environment for a web application. The web app uses user-assigned Managed Identity to reach the SQL server.
I have to run the following command in the SQL server:
CREATE USER [<identity-name>] FROM EXTERNAL PROVIDER;
But this command errors when I use sql adminstrator login: "Only connections established with Active Directory accounts can create other Active Directory users."
I add an AD administrator with Set-AzSqlServerActiveDirectoryAdministrator
But how can use this AD login from powershell to run the SQL command?

It seems that Invoke-Sqlcmd (or at least the version of it that I have) doesn't support Azure AD authentication.
I've used a PowerShell script like this to create users (you may need to update sqlcmd):
$query = "CREATE USER [$identityName] FROM EXTERNAL PROVIDER;"
sqlcmd -S $serverHostName -d $databaseName -G -N -U $username -t 120 -b -Q $query
The -G flag there tells it to use Azure AD authentication, in this case it will use interactive authentication and require you to login.
If I recall, you can use the -U and -P flags to define the username and password as well for the Azure AD user, but that'll only work if the user doesn't have MFA enabled and isn't a federated user.

Apparently the Azure AD login only works with the -ConnectionString parameter. So the solution is:
# Create User Managed Identity
$mi = New-AzUserAssignedIdentity -ResourceGroupName $resourceGroupName -Name $managedIdentityName
# Enable AD login for SQL server
Set-AzSqlServerActiveDirectoryAdministrator -ServerName $sqlServerName -ResourceGroupName $resourceGroupName -DisplayName $AdAdminUser -ObjectId $AdAdminObjectId
# Add Managed identity login to SQL server
$connectString = "Server=tcp:$sqlServerName.database.windows.net,1433;Initial Catalog=$sqlDBName;Authentication=Active Directory Password;user=$AdAdminUser;pwd=$AdAdminPw"
$query = "CREATE USER [$managedIdentityName] FROM EXTERNAL PROVIDER;"
Invoke-Sqlcmd -ConnectionString $connectString -Query $query -OutputSqlErrors $true

Related

Run SQL query using powershell and AAD authentication with an SSO account

I am trying to run a set of queries from Cloud Shell using powershell that require and Azure AD user. I generally use invoke-sqlcmd using the server admin and password but the specific query I want to run require an AD user. I would like to run the query as myself. I have found that I can use the ConnectionString parameter to do this, but my problem is I do not have a password as I login to Azure via SSO. I basically want to mimic the process of going to my DB in Azure, going to query editor, using AAD authentication and running a query, but with powershell. Is there a way I can do this? Example of what I am trying to do below:
$serverName = 'server'
$dbName = 'database'
$query = 'CREATE USER [AAD_User] FROM EXTERNAL PROVIDER;'
Invoke-Sqlcmd -ServerInstance $ServerName -Database $dbName -Query $query
When I attempt this I get:
Invoke-Sqlcmd: Cannot authenticate using Kerberos. Ensure Kerberos has been initialized on the client with 'kinit' and a Service Principal Name has been registered for the SQL Server to allow Kerberos authentication.
I tried to reproduce the same in my environment and got the results like below:
As SSO is enabled and you do not have a password, you can try generating access token to perform the action.
I used the below script to add the user in Azure Database:
Connect-AzAccount
$connectionString = "Server=testrukserver.database.windows.net;Initial Catalog=testdb;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30"
$accessToken = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
$sqlConn = New-Object System.Data.SqlClient.SqlConnection
$sqlConn.ConnectionString = $connectionString
$sqlConn.AccessToken = $accessToken
$sqlConn.Open()
Invoke-Sqlcmd -ServerInstance testrukserver.database.windows.net -Database testdb -AccessToken $accessToken -query 'CREATE USER [test#xxx.onmicrosoft.com] FROM EXTERNAL PROVIDER'
$sqlConn.Close()
The user is added sccessfully in the Azure Database like below:
Reference:
Connecting to Azure SQL Database with AAD Authentication using Powershell by alex stuart

How to get tenant properties through PowerShell with SharePointPnP?

I have been given a task to setup a scheduled task which will run daily to pull down the list of allowed domains from SPO. This is not an issue if I use Connect-SPOService and Get-SPOTenant, like this:
Connect-SPOService –url https://xxxx-admin.sharepoint.com
Get-SPOTenant | select -ExpandProperty SharingAllowedDomainList > d:\allowedDomains.txt
The issue issue is that this has to be automated. There is also a requirement to use an ClientId and Secret in the script, rather than providing me with an account which bypasses MFA and has SP Admin rights.
Because of that, I've turned to SharePointPnP, which does allow you to connect with ClientId and Secret. I'm able to connect to connect with the following:
Connect-PnPOnline -url https://xxxx-admin.sharepoint.com -ClientId "xxxxx" -ClientSecret "xxxxx"
Where I'm struggling now is trying to how I can retrieve the SharingAllowedDomainList property through SharePointPnP, or if that is even possible?
#THTX,
Can you please have a try below pnp powershell cmdlet?
Get-PnPTenant
Get-PnPTenantSite
It has SharingAllowedDomainList property:
BR

Local System Account and Windows Credential Manager

So, I have a powershell script that uses the Windows Credential Manager to store credentials. When I use my account I can access these credentials, but it seems like when I try to use the local system account (trying not to use my account to run scripts) it doesnt pull from the credential manager. What gives?
if (Get-Module -ListAvailable -Name CredentialManager) {
Import-Module CredentialManager
}
else {
Install-Module CredentialManager
}
$service_fqdn = '<SERVER-FQDN>'
$creds = Get-StoredCredential -Target '<SERVICE ACCOUNT>'
$oauth_client_id = $creds.UserName
$oauth_client_secret = $creds.GetNetworkCredential().Password
I get a null error when I try to get the password for $oauth_client_secret
The issue is that all credentials are stored and accessible for only the current logged in user.
i.e. If you create the credential logged in as user1, you can't access them as user2, or even with the Local System Account.
This makes sense, and can't be worked around. You don't want random
logged in people/users to be able to access other people's
credentials.
The "workaround" is to create a new user/service account with minimal permissions that is dedicated to running the service/script. You then can create the new credential as that new user/service account:
New-StoredCredential -Target "Server1" -Username "SA-Username" -Password "Password123"
Then running the script as that user, you will have access to the credential.
Note: you cannot use the Local System Account to run the script as you can't explicitly specify the Local System Account as a valid user to create the new stored credential.
Edit:
As #MrBungle correctly mentions. The Local System Account has god like powers, and it is recommended not to use it if possible. Instead use the unprivileged Local Service Account whenever possible.

New-AzureRmWebAppBackup errors out on "master" db

I'm attempting to script an Azure Web App backup in PowerShell.
These commands:
$DatabaseBackupSetting = New-AzureRmWebAppDatabaseBackupSetting -Name $DatabaseName `
-ConnectionString $ConnectionStrings[0].ConnectionString -DatabaseType "SqlAzure"
New-AzureRmWebAppBackup -ResourceGroupName $ResourceGroupName -Name $Site -StorageAccountUrl $SasUrl `
-Databases $DatabaseBackupSetting -BackupName ($Site + "_backup_" + (Get-Date -Format FileDateTimeUniversal)).ToLower()
Should back up the site and the attached db.
Here is the connection string I'm passing in to New-AzureRmWebAppDatabaseBackupSetting:
Server=tcp:[MYSERVER].database.windows.net,1433;Initial Catalog=demo-dev;Persist Security Info=False;User ID=demoadmin;Password=[MY_PASSWORD];MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
When I run the New-AzureRmWebAppBackup command and check the status I see:
The server principal "demoadmin" is not able to access the database "master" under the current security context.
Cannot open database "master" requested by the login. The login failed.
Login failed for user 'demoadmin'.
I can't figure out how to tell the command to ignore the "master" db.
Any thoughts?

Credentials using Invoke-Sqlcmd against sql azure

I'm attempting to run a powershell build script against a sql azure database but receiving Login failed for user 'X'.
I'm fairly convinced the credentials are correct as they were taken straight from the live application config.
This is the command I'm using:
Invoke-Sqlcmd -InputFile "Build.sql" -ServerInstance $server -Database $database `
-WarningAction SilentlyContinue -OutputSqlErrors $false `
-Username $username -Password $password -EncryptConnection
I had this working with sqlcmd in a batch file so I'm wondering if it's got anything to do with the way the credentials are being sent, trusted_connection=false doesn't appear to be an option I can try.
It could be the password contains a few special characters that Azure/Invoke-sqlcmd does not handle (such as dollar, single or double quote, parentheses). I tried using the Azure interface and surrounding the password with single-quotes (we had a dollar-sign in the password), but that did not work. So, we simply removed the special character and now it is OK. see: Powershell Invoke-Sqlcmd Login Failed
and
https://mohitgoyal.co/2017/08/09/vsts-azure-sql-database-deployment-task-keeps-failing-with-error-login-failed-for-user/
When connecting to SQL Azure the login name must be of the form user#server. So if you created an user 'foo' and a server 'bar', the login must be foo#bar. See Managing Databases and Logins in Azure SQL Database:
Because some tools implement tabular data stream (TDS) differently, you may need to append the Azure SQL Database server name to the login in the connection string using the <login>#<server> notation. In these cases, separate the login and Azure SQL Database server name with the # symbol. For example, if your login was named login1 and the fully qualified name of your Azure SQL Database server is servername.database.windows.net, the username parameter of your connection string should be: login1#servername.
CREATE LOGIN also explains this:
In some methods of connecting to SQL Database, such as sqlcmd, you must append the SQL Database server name to the login name in the connection string by using the <login>#<server> notation. For example, if your login is login1 and the fully qualified name of the SQL Database server is servername.database.windows.net, the username parameter of the connection string should be login1#servername.