Skip to content

Commit

Permalink
more azure support (#5172)
Browse files Browse the repository at this point in the history
* removed unnecessary params and added azure support

* added feature parity to connect-dbainstance
  • Loading branch information
potatoqualitee authored Mar 10, 2019
1 parent aafe10d commit f5499f8
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 50 deletions.
45 changes: 34 additions & 11 deletions functions/Connect-DbaInstance.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ function Connect-DbaInstance {
.PARAMETER SqlConnectionOnly
Instead of returning a rich SMO server object, this command will only return a SqlConnection object when setting this switch.
.PARAMETER AzureUnsupported
Throw if Azure is detected but not supported
.PARAMETER MinimumVersion
Throw if the target SQL Server instance version does not meet version requirements
.PARAMETER DisableException
By default in most of our commands, when something goes wrong we try to catch it, interpret it and give you a friendly warning message.
Expand Down Expand Up @@ -184,6 +190,7 @@ function Connect-DbaInstance {
[string]$AccessToken,
[ValidateSet('ReadOnly', 'ReadWrite')]
[string]$ApplicationIntent,
[switch]$AzureUnsupported,
[string]$BatchSeparator,
[string]$ClientName = "dbatools PowerShell module - dbatools.io - custom connection",
[int]$ConnectTimeout = ([Sqlcollaborative.Dbatools.Connection.ConnectionHost]::SqlConnectionTimeout),
Expand All @@ -192,6 +199,7 @@ function Connect-DbaInstance {
[int]$LockTimeout,
[int]$MaxPoolSize,
[int]$MinPoolSize,
[int]$MinimumVersion,
[switch]$MultipleActiveResultSets,
[switch]$MultiSubnetFailover,
[ValidateSet('TcpIp', 'NamedPipes', 'Multiprotocol', 'AppleTalk', 'BanyanVines', 'Via', 'SharedMemory', 'NWLinkIpxSpx')]
Expand Down Expand Up @@ -231,6 +239,17 @@ function Connect-DbaInstance {
}
}
}

if ($MinimumVersion -and $server.VersionMajor) {
if ($server.versionMajor -lt $MinimumVersion) {
throw "SQL Server version $MinimumVersion required - $server not supported."
}
}

if ($AzureUnsupported -and $server.DatabaseEngineType -eq "SqlAzureDatabase") {
throw "Azure SQL Database not supported"
}

#'PrimaryFilePath' seems the culprit for slow SMO on databases
$Fields2000_Db = 'Collation', 'CompatibilityLevel', 'CreateDate', 'ID', 'IsAccessible', 'IsFullTextEnabled', 'IsSystemObject', 'IsUpdateable', 'LastBackupDate', 'LastDifferentialBackupDate', 'LastLogBackupDate', 'Name', 'Owner', 'ReadOnly', 'RecoveryModel', 'ReplicationOptions', 'Status', 'Version'
$Fields200x_Db = $Fields2000_Db + @('BrokerEnabled', 'DatabaseSnapshotBaseName', 'IsMirroringEnabled', 'Trustworthy')
Expand All @@ -243,24 +262,25 @@ function Connect-DbaInstance {
process {
foreach ($instance in $SqlInstance) {
if ($instance.ComputerName -match "database\.windows\.net" -and -not $instance.InputObject.ConnectionContext.IsOpen) {
$isAzure = $true
if (-not (Test-Bound -ParameterName ConnectTimeout)) {
$ConnectTimeout = 30
if (-not $Database) {
Stop-Function -Message "You must specify -Database when connecting to a SQL Azure databse" -Continue
}
$isAzure = $true
$boundparams = $PSBoundParameters
[object[]]$connstringcmd = (Get-Command New-DbaConnectionString).Parameters.Keys
[object[]]$connectcmd = (Get-Command Connect-DbaInstance).Parameters.Keys

if ($SqlCredential) {
$azureconnstring = "Server=tcp:$($instance.ComputerName),$($instance.Port);Initial Catalog=$Database;Persist Security Info=False;User ID=$($SqlCredential.UserName);Password=$($($SqlCredential.GetNetworkCredential()).Password);MultipleActiveResultSets=$MultipleActiveResultSets;Encrypt=True;TrustServerCertificate=$TrustServerCertificate;Connection Timeout=$ConnectTimeout;"

if ($SqlCredential.UserName -like "*\*" -or $SqlCredential.UserName -like "*@*") {
$azureconnstring = $azureconnstring + 'Authentication="Active Directory Password"'
foreach ($key in $connectcmd) {
if ($key -notin $connstringcmd -and $key -ne "SqlCredential") {
$null = $boundparams.Remove($key)
}
} else {
$azureconnstring = "Server=tcp:$($instance.ComputerName),$($instance.Port);Initial Catalog=$Database;Persist Security Info=False;User ID=$($SqlCredential.UserName);MultipleActiveResultSets=$MultipleActiveResultSets;Encrypt=True;TrustServerCertificate=$TrustServerCertificate;Connection Timeout=$ConnectTimeout;"
$azureconnstring = $azureconnstring + 'Authentication="Active Directory Integrated"'
}
$azureconnstring = New-DbaConnectionString @boundparams

try {
$sqlconn = New-Object System.Data.SqlClient.SqlConnection $azureconnstring
$serverconn = New-Object Microsoft.SqlServer.Management.Common.ServerConnection $sqlconn
$null = $serverconn.Connect()
$server = New-Object Microsoft.SqlServer.Management.Smo.Server $serverconn
} catch {
Stop-Function -Message "Failure" -ErrorRecord $_ -Continue
Expand Down Expand Up @@ -490,6 +510,9 @@ function Connect-DbaInstance {
Add-Member -InputObject $server -NotePropertyName ComputerName -NotePropertyValue $parsedcomputername -Force
}
}
if ($isAzure -and $server.ServerType -ne 'SqlAzureDatabase') {
throw "Azure connection failed. The username or password may be incorrect."
}
$server
}
}
Expand Down
10 changes: 7 additions & 3 deletions functions/Get-DbaDatabase.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ function Get-DbaDatabase {
[DbaInstanceParameter[]]$SqlInstance,
[PSCredential]$SqlCredential,
[Alias("Databases")]
[object[]]$Database,
[object[]]$ExcludeDatabase,
[string[]]$Database,
[string[]]$ExcludeDatabase,
[Alias("SystemDbOnly", "NoUserDb", "ExcludeAllUserDb")]
[switch]$ExcludeUser,
[Alias("UserDbOnly", "NoSystemDb", "ExcludeAllSystemDb")]
Expand Down Expand Up @@ -276,7 +276,11 @@ function Get-DbaDatabase {

$inputObject = @()
foreach ($dt in $backed_info) {
$inputObject += $server.Databases | Where-Object Name -ceq $dt.name
if ($server.DatabaseEngineType -eq "SqlAzureDatabase") {
$inputObject += $server.Databases[$dt.name]
} else {
$inputObject += $server.Databases | Where-Object Name -ceq $dt.name
}
}
$inputobject = $inputObject |
Where-Object {
Expand Down
57 changes: 48 additions & 9 deletions functions/New-DbaConnectionString.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ function New-DbaConnectionString {
.PARAMETER ClientName
By default, this command sets the client to "dbatools PowerShell module - dbatools.io - custom connection" if you're doing anything that requires profiling, you can look for this client name. Using -ClientName allows you to set your own custom client.
.PARAMETER Database
Database name
.PARAMETER ConnectTimeout
The length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error.
Expand Down Expand Up @@ -173,6 +176,7 @@ function New-DbaConnectionString {
[string]$BatchSeparator,
[string]$ClientName = "custom connection",
[int]$ConnectTimeout,
[string]$Database,
[switch]$EncryptConnection,
[string]$FailoverPartner,
[switch]$IsActiveDirectoryUniversalAuth,
Expand All @@ -197,6 +201,24 @@ function New-DbaConnectionString {
process {
foreach ($instance in $sqlinstance) {
if ($Pscmdlet.ShouldProcess($instance, "Making a new Connection String")) {
if ($instance.ComputerName -match "database\.windows\.net" -and -not $instance.InputObject.ConnectionContext.IsOpen) {
if (-not $Database) {
Stop-Function -Message "You must specify -Database when connecting to a SQL Azure databse" -Continue
}
$isAzure = $true

if (-not (Test-Bound -ParameterName ConnectTimeout)) {
$ConnectTimeout = 30
}

if (-not (Test-Bound -ParameterName ClientName)) {
$ClientName = "dbatools PowerShell module - dbatools.io"

}
$EncryptConnection = $true
$instance = [DbaInstanceParameter]"tcp:$($instance.ComputerName),$($instance.Port)"
}

if ($instance.GetType() -eq [Microsoft.SqlServer.Management.Smo.Server]) {
return $instance.ConnectionContext.ConnectionString
} else {
Expand Down Expand Up @@ -230,14 +252,6 @@ function New-DbaConnectionString {
if ($TrustServerCertificate) { $server.ConnectionContext.TrustServerCertificate = $true }
if ($WorkstationId) { $server.ConnectionContext.WorkstationId = $WorkstationId }

$connstring = $server.ConnectionContext.ConnectionString
if ($MultiSubnetFailover) { $connstring = "$connstring;MultiSubnetFailover=True" }
if ($FailoverPartner) { $connstring = "$connstring;Failover Partner=$FailoverPartner" }
if ($ApplicationIntent) { $connstring = "$connstring;ApplicationIntent=$ApplicationIntent;" }

if ($connstring -ne $server.ConnectionContext.ConnectionString) {
$server.ConnectionContext.ConnectionString = $connstring
}
if ($null -ne $Credential.username) {
$username = ($Credential.username).TrimStart("\")

Expand All @@ -258,7 +272,32 @@ function New-DbaConnectionString {
}
}

($server.ConnectionContext.ConnectionString).Replace($guid, $SqlInstance)
$connstring = $server.ConnectionContext.ConnectionString
if ($MultiSubnetFailover) { $connstring = "$connstring;MultiSubnetFailover=True" }
if ($FailoverPartner) { $connstring = "$connstring;Failover Partner=$FailoverPartner" }
if ($ApplicationIntent) { $connstring = "$connstring;ApplicationIntent=$ApplicationIntent;" }

if ($isAzure) {
if ($Credential) {
if ($Credential.UserName -like "*\*" -or $Credential.UserName -like "*@*") {
$connstring = "$connstring;Authentication=`"Active Directory Password`""
} else {
$username = ($Credential.username).TrimStart("\")
$server.ConnectionContext.LoginSecure = $false
$server.ConnectionContext.set_Login($username)
$server.ConnectionContext.set_SecurePassword($Credential.Password)
}
} else {
$connstring = $connstring.Replace("Integrated Security=True;", "")
$connstring = "$connstring;Authentication=`"Active Directory Integrated`""
}
}

if ($connstring -ne $server.ConnectionContext.ConnectionString) {
$server.ConnectionContext.ConnectionString = $connstring
}

($server.ConnectionContext.ConnectionString).Replace($guid, $instance)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion functions/Remove-DbaDatabaseSafely.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ function Remove-DbaDatabaseSafely {
return
}

$sourceserver = Connect-SqlInstance -SqlInstance $SqlInstance -SqlCredential $sqlCredential -ParameterConnection
$sourceserver = Connect-SqlInstance -SqlInstance $SqlInstance -SqlCredential $sqlCredential

if (-not $destination) {
$destination = $sqlinstance
Expand Down
5 changes: 0 additions & 5 deletions functions/Write-DbaDataTable.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,6 @@ function Write-DbaDataTable {
.PARAMETER BulkCopyTimeOut
Value in seconds for the BulkCopy operations timeout. The default is 30 seconds.
.PARAMETER RegularUser
Deprecated - now all connections are regular user (don't require admin)
.PARAMETER WhatIf
If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run.
Expand Down Expand Up @@ -190,7 +187,6 @@ function Write-DbaDataTable {
[switch]$Truncate,
[ValidateNotNull()]
[int]$bulkCopyTimeOut = 5000,
[switch]$RegularUser,
[Alias('Silent')]
[switch]$EnableException,
[switch]$UseDynamicStringLength
Expand Down Expand Up @@ -672,6 +668,5 @@ function Write-DbaDataTable {
$bulkCopy.Close()
$bulkCopy.Dispose()
}
Test-DbaDeprecation -DeprecatedOn 1.0.0 -Parameter RegularUser
}
}
51 changes: 34 additions & 17 deletions internal/functions/Connect-SqlInstance.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ function Connect-SqlInstance {
.PARAMETER AzureUnsupported
Throw if Azure is detected but not supported
.PARAMETER RegularUser
The connection doesn't require SA privileges.
By default, the assumption is that SA is no longer required.
.PARAMETER MinimumVersion
The minimum version that the calling command will support
Expand All @@ -65,8 +61,6 @@ function Connect-SqlInstance {
[Parameter(Mandatory)]
[object]$SqlInstance,
[object]$SqlCredential,
[switch]$ParameterConnection,
[switch]$RegularUser = $true,
[int]$StatementTimeout,
[int]$MinimumVersion,
[switch]$AzureUnsupported,
Expand Down Expand Up @@ -110,6 +104,31 @@ function Connect-SqlInstance {
}
#endregion Ensure Credential integrity

if ($instance.ComputerName -match "database\.windows\.net" -and -not $instance.InputObject.ConnectionContext.IsOpen) {
$isAzure = $true
if (-not (Test-Bound -ParameterName ConnectTimeout)) {
$ConnectTimeout = 30
}

if ($SqlCredential) {
$azureconnstring = "Server=tcp:$($instance.ComputerName),$($instance.Port);Initial Catalog=$Database;Persist Security Info=False;User ID=$($SqlCredential.UserName);Password=$($($SqlCredential.GetNetworkCredential()).Password);MultipleActiveResultSets=$MultipleActiveResultSets;Encrypt=True;TrustServerCertificate=$TrustServerCertificate;Connection Timeout=$ConnectTimeout;"
$azureconnstring = $azureconnstring + 'Application Name = "dbatools PowerShell module - dbatools.io"'
}
if ($SqlCredential.UserName -like "*\*" -or $SqlCredential.UserName -like "*@*") {
$azureconnstring = $azureconnstring + 'Authentication="Active Directory Password";Application Name = "dbatools PowerShell module - dbatools.io"'
} else {
$azureconnstring = "Server=tcp:$($instance.ComputerName),$($instance.Port);Initial Catalog=$Database;Persist Security Info=False;MultipleActiveResultSets=$MultipleActiveResultSets;Encrypt=True;TrustServerCertificate=$TrustServerCertificate;Connection Timeout=$ConnectTimeout;"
$azureconnstring = $azureconnstring + 'Authentication="Active Directory Integrated"; Application Name = "dbatools PowerShell module - dbatools.io"'
}
try {
$sqlconn = New-Object System.Data.SqlClient.SqlConnection $azureconnstring
$serverconn = New-Object Microsoft.SqlServer.Management.Common.ServerConnection $sqlconn
$server = New-Object Microsoft.SqlServer.Management.Smo.Server $serverconn
} catch {
Stop-Function -Message "Failure" -ErrorRecord $_ -Continue
}
}

#region Safely convert input into instance parameters
<#
This is a bit ugly, but:
Expand All @@ -133,7 +152,7 @@ function Connect-SqlInstance {
#endregion Safely convert input into instance parameters

#region Input Object was a server object
if ($ConvertedSqlInstance.InputObject.GetType() -eq [Microsoft.SqlServer.Management.Smo.Server]) {
if ($ConvertedSqlInstance.InputObject.GetType() -eq [Microsoft.SqlServer.Management.Smo.Server] -or ($isAzure -and $instance.InputObject.ConnectionContext.IsOpen)) {
$server = $ConvertedSqlInstance.InputObject
$authtypeSMO = $SqlCredential.UserName -like '*\*'
if ($server.ConnectionContext.IsOpen -eq $false) {
Expand Down Expand Up @@ -190,18 +209,21 @@ function Connect-SqlInstance {
#endregion Input Object was a server object

#region Input Object was anything else
if (-not $isAzure) {
$server = New-Object Microsoft.SqlServer.Management.Smo.Server $ConvertedSqlInstance.FullSmoName
$server.ConnectionContext.ApplicationName = "dbatools PowerShell module - dbatools.io"
}

$server = New-Object Microsoft.SqlServer.Management.Smo.Server $ConvertedSqlInstance.FullSmoName
$server.ConnectionContext.ApplicationName = "dbatools PowerShell module - dbatools.io"
if ($ConvertedSqlInstance.IsConnectionString) { $server.ConnectionContext.ConnectionString = $ConvertedSqlInstance.InputObject }

try {
if (Test-Bound -ParameterName 'StatementTimeout') {
$server.ConnectionContext.StatementTimeout = $StatementTimeout
}
$server.ConnectionContext.ConnectTimeout = [Sqlcollaborative.Dbatools.Connection.ConnectionHost]::SqlConnectionTimeout

if ($null -ne $SqlCredential.UserName) {
if (-not $isAzure) {
$server.ConnectionContext.ConnectTimeout = [Sqlcollaborative.Dbatools.Connection.ConnectionHost]::SqlConnectionTimeout
}
if ($null -ne $SqlCredential.UserName -and -not $isAzure) {
$username = ($SqlCredential.UserName).TrimStart("\")

# support both ad\username and username@ad
Expand Down Expand Up @@ -282,11 +304,6 @@ function Connect-SqlInstance {
throw "Azure SQL Database not supported"
}

if (-not $RegularUser) {
if ($server.ConnectionContext.FixedServerRoles -notmatch "SysAdmin") {
throw "Not a sysadmin on $ConvertedSqlInstance. Quitting."
}
}
#'PrimaryFilePath' seems the culprit for slow SMO on databases
$Fields2000_Db = 'Collation', 'CompatibilityLevel', 'CreateDate', 'ID', 'IsAccessible', 'IsFullTextEnabled', 'IsSystemObject', 'IsUpdateable', 'LastBackupDate', 'LastDifferentialBackupDate', 'LastLogBackupDate', 'Name', 'Owner', 'ReadOnly', 'RecoveryModel', 'ReplicationOptions', 'Status', 'Version'
$Fields200x_Db = $Fields2000_Db + @('BrokerEnabled', 'DatabaseSnapshotBaseName', 'IsMirroringEnabled', 'Trustworthy')
Expand Down
Loading

0 comments on commit f5499f8

Please sign in to comment.