Private/sql.ps1
# todo: assuming subscription + database / connection string info is coming from env vars or the permission itself. # contd: Imperial code is doing direct calls to KV as part of the database access token retrieval, best to avoid this to keep all the functions clean of other dependencies # contd: missing env vars I can see: DatabaseName, Subscription. function Set-RKSQLPermission { [CmdletBinding()] param([PSCustomObject[]]$Permission) Write-Host "Attempting Set-RKSQLPermission: Type: '$($Permission.principalType)', Name: '$($Permission.principalName)', Role: '$($Permission.databaseRole)', Scope: '$($Permission.scope)'" $scopeProperties = Format-RKAzureScopeAsHashTable -Scope $Permission.scope $databaseAccessToken = Get-RKAzDatabaseAccessToken if ($null -eq $databaseAccessToken){ throw "Error obtaining access token - check your Powershell Az Context." } $databaseProperties = [DatabaseProperties]@{ ServerName = "$($scopeProperties['servers']).database.windows.net" DatabaseName = $scopeProperties['databases'] DatabaseAccessToken = $databaseAccessToken } New-RKDatabaseRole -RoleName $Permission.databaseRole -DatabaseProperties $databaseProperties switch ($Permission.principalType.toUpper()) { 'AAD' { New-RKContainedDatabaseUser -PrincipalName $Permission.principalName -DatabaseProperties $databaseProperties -Refresh } 'SQL' { New-RKSQLDatabaseUser -PrincipalName $Permission.principalName -DatabaseProperties $databaseProperties -Refresh } Default { Write-Error "Principal type $($Permission.principalType) is invalid for this permission."; } } Set-RKDatabaseRoleMember -PrincipalName $Permission.principalName -RoleName $Permission.databaseRole -DatabaseProperties $databaseProperties } function New-RKDatabaseRole { param( [string]$RoleName, [DatabaseProperties]$DatabaseProperties ) $SQL = "SELECT 1 [Exists] FROM sys.database_principals WHERE [name] = '$RoleName' AND type = 'R'" $Result = Invoke-RKSQL -SQL $SQL -DatabaseProperties $DatabaseProperties if ($Result.exists -ne 1) { $SQL = "CREATE ROLE [$RoleName]" Invoke-RKSQL -SQL $SQL -DatabaseProperties $DatabaseProperties } } function New-RKSQLDatabaseUser { param( [string]$PrincipalName, [DatabaseProperties]$DatabaseProperties, [switch]$Refresh ) # todo } function Invoke-RKSQL { param([string]$SQL, [DatabaseProperties]$DatabaseProperties) if (!(Get-Module sqlServer -ListAvailable)) { Install-Module sqlServer -Scope CurrentUser -Force } Import-Module sqlServer Write-Host "Executing SQL Server: '$($DatabaseProperties.ServerName)' Database: '$($databaseProperties.DatabaseName)', SQL: $($SQL)" return (Invoke-Sqlcmd -Query $SQL -ServerInstance $DatabaseProperties.ServerName -Database $DatabaseProperties.DatabaseName -AccessToken $databaseProperties.DatabaseAccessToken) } function New-RKContainedDatabaseUser { param( [string]$PrincipalName, [DatabaseProperties]$DatabaseProperties, [switch]$Refresh ) $SQL = "SELECT 1 [Exists] FROM sys.database_principals WHERE [name] = '$PrincipalName' AND type IN ('E', 'X')" $Result = Invoke-RKSQL -SQL $SQL -DatabaseProperties $DatabaseProperties if (($Result.exists -eq 1) -and ($Refresh.IsPresent)) { $SQL = "DROP USER [$PrincipalName]; CREATE USER [$PrincipalName] FROM EXTERNAL PROVIDER" Invoke-RKSQL -SQL $SQL -DatabaseProperties $DatabaseProperties } elseif ($Result.exists -ne 1) { $SQL = "CREATE USER [$PrincipalName] FROM EXTERNAL PROVIDER" Invoke-RKSQL -SQL $SQL -DatabaseProperties $DatabaseProperties } } function Set-RKDatabaseRoleMember { param( [string]$RoleName, [string]$PrincipalName, [DatabaseProperties]$DatabaseProperties ) Write-Host "Attempting Set-RKDatabaseRoleMember: Role: '$($RoleName)', Principal: '$($PrincipalName)'" $SQL = "EXEC sp_addrolemember '$($RoleName)', '$($PrincipalName)'" Invoke-RKSQL -SQL $SQL -DatabaseProperties $DatabaseProperties } function Get-RKAzDatabaseAccessToken { param() return (Get-RKAzAccessToken -Resource 'https://database.windows.net/') } class DatabaseProperties { [ValidateNotNullOrEmpty()][string]$ServerName [ValidateNotNullOrEmpty()][string]$DatabaseName [ValidateNotNullOrEmpty()][string]$DatabaseAccessToken } |