Skip to content

Commit

Permalink
Changes to resolve Issue 5443 (#5521)
Browse files Browse the repository at this point in the history
* Changes to resolve Issue 5443

* Changes to resolve Issue 5443 - fix formatting
  • Loading branch information
sqllensman authored and potatoqualitee committed May 14, 2019
1 parent 1a713ee commit 041830b
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 52 deletions.
149 changes: 105 additions & 44 deletions functions/Export-DbaCredential.ps1
Expand Up @@ -29,9 +29,6 @@ function Export-DbaCredential {
.PARAMETER ExcludePassword
Exports the SQL credential without any sensitive information.
.PARAMETER InputObject
Allow credentials to be piped in from Get-DbaCredential
.PARAMETER Append
Append to Path
Expand All @@ -56,7 +53,6 @@ function Export-DbaCredential {
#>
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipeline)]
[Alias("ServerInstance", "SqlServer")]
[DbaInstanceParameter[]]$SqlInstance,
[string[]]$Identity,
Expand All @@ -65,59 +61,121 @@ function Export-DbaCredential {
[string]$Path,
[switch]$ExcludePassword,
[switch]$Append,
[Parameter(ValueFromPipeline)]
[Microsoft.SqlServer.Management.Smo.Credential[]]$InputObject,
[switch]$EnableException
)
begin {
$serverArray = @()
$credentialArray = @{}
$credentialCollection = New-Object System.Collections.ArrayList
}
process {
foreach ($instance in $SqlInstance) {
try {
$server = Connect-SqlInstance -SqlInstance $instance -SqlCredential $sqlcredential -MinimumVersion 9
$InputObject += $server.Credentials
} catch {
Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue
}
if (-not $InputObject -and -not $SqlInstance) {
Stop-Function -Message "You must pipe in a Credential or specify a SqlInstance"
return
}

if ($Identity) {
$InputObject = $InputObject | Where-Object Identity -in $Identity
}
if (Test-Bound -ParameterName SqlInstance) {
foreach ($instance in $SqlInstance) {
try {
$server = Connect-SqlInstance -SqlInstance $instance -SqlCredential $sqlcredential -MinimumVersion 9

if (!(Test-SqlSa -SqlInstance $instance -SqlCredential $sqlcredential)) {
Stop-Function -Message "Not a sysadmin on $instance. Quitting." -Target $instance -Continue
$serverCreds = $server.Credentials
if (Test-Bound -ParameterName Identity) {
$serverCreds = $serverCreds | Where-Object Identity -in $Identity
}

$InputObject += $serverCreds
} catch {
Stop-Function -Message "Error occurred while establishing connection to $instance" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue
}
}
}

Write-Message -Level Verbose -Message "Getting NetBios name for $instance."
$sourceNetBios = Resolve-NetBiosName $server
foreach ($input in $InputObject) {
$server = $input.Parent
$instance = $server.Name

Write-Message -Level Verbose -Message "Checking if Remote Registry is enabled on $instance."
try {
Invoke-Command2 -Raw -Credential $Credential -ComputerName $sourceNetBios -ScriptBlock { Get-ItemProperty -Path "HKLM:\SOFTWARE\" } -ErrorAction Stop
} catch {
Stop-Function -Message "Can't connect to registry on $instance." -Target $sourceNetBios -ErrorRecord $_
return
if ($serverArray -notcontains $instance) {
try {
if ($ExcludePassword) {
$serverCreds = $server.Credentials
$creds = New-Object System.Collections.ArrayList

foreach ($cred in $server.Credentials) {
$credObject = [PSCustomObject]@{
Name = '[' + $cred.name + ']'
Identity = $cred.Id.ToString()
Password = ''
}
$creds.Add($credObject) | Out-Null
}
$creds | Add-Member -MemberType NoteProperty -Name 'SqlInstance' -Value $instance
$creds | Add-Member -MemberType NoteProperty -Name 'ExcludePassword' -Value $ExcludePassword
$credentialCollection.Add($credObject) | Out-Null
} else {
if (!(Test-SqlSa -SqlInstance $server)) {
Stop-Function -Message "Not a sysadmin on $instance. Quitting." -Target $instance -Continue
}

Write-Message -Level Verbose -Message "Getting NetBios name for $instance."
$sourceNetBios = Resolve-NetBiosName $server

Write-Message -Level Verbose -Message "Checking if Remote Registry is enabled on $instance."
try {
Invoke-Command2 -Raw -Credential $Credential -ComputerName $sourceNetBios -ScriptBlock { Get-ItemProperty -Path "HKLM:\SOFTWARE\" } -ErrorAction Stop
} catch {
Stop-Function -Message "Can't connect to registry on $instance." -Target $sourceNetBios -ErrorRecord $_
return
}

$creds = Get-DecryptedObject -SqlInstance $server -Type Credential
Write-Message -Level Verbose -Message "Adding Members"
$creds | Add-Member -MemberType NoteProperty -Name 'SqlInstance' -Value $instance
$creds | Add-Member -MemberType NoteProperty -Name 'ExcludePassword' -Value $ExcludePassword
$credentialCollection.Add($creds) | Out-Null
}
} catch {
Stop-Function -Continue -Message "Failure" -ErrorRecord $_
}

$serverArray += $instance

$key = $input.Parent.Name + '::[' + $input.Name + ']'
$credentialArray.add( $key, $true )
} else {
$key = $input.Parent.Name + '::[' + $input.Name + ']'
$credentialArray.add( $key, $true )
}
}
}

end {
$sql = @()
foreach ($cred in $credentialCollection) {
Write-Message -Level Verbose -Message "Credentials in object = $($cred.Count)"
if (-not (Test-Bound -ParameterName Path)) {
$timenow = (Get-Date -uformat "%m%d%Y%H%M%S")
$time = (Get-Date -Format yyyMMddHHmmss)
$mydocs = [Environment]::GetFolderPath('MyDocuments')
$path = "$mydocs\$($server.name.replace('\', '$'))-$timenow-credential.sql"
}
$serverName = $($cred[0].SqlInstance.replace('\', '$'))

$sql = @()
$path = Join-DbaPath -Path $mydocs "$serverName-$time-credential.sql"
}

if ($ExcludePassword) {
Stop-Function -Message "So sorry, there's no other way around it for now. The password has to be exported in plain text."
return
} else {
try {
$creds = Get-DecryptedObject -SqlInstance $server -Type Credential
} catch {
Stop-Function -Continue -Message "Failure" -ErrorRecord $_
}
foreach ($currentCred in $creds) {
foreach ($currentCred in $creds) {
$key = $currentCred.SqlInstance + '::' + $currentCred.Name
if ( $credentialArray.ContainsKey($key) ) {
$name = $currentCred.Name.Replace("'", "''")
$identity = $currentCred.Identity.Replace("'", "''")
$password = $currentCred.Password.Replace("'", "''")
$sql += "CREATE CREDENTIAL $name WITH IDENTITY = N'$identity', SECRET = N'$password'"
if ($currentCred.ExcludePassword) {
$sql += "CREATE CREDENTIAL $name WITH IDENTITY = N'$identity', SECRET = N'<EnterStrongPasswordHere>'"
} else {
$password = $currentCred.Password.Replace("'", "''")
$sql += "CREATE CREDENTIAL $name WITH IDENTITY = N'$identity', SECRET = N'$password'"
}

Write-Message -Level Verbose -Message "Created Script for $name"
}
}

Expand All @@ -127,14 +185,17 @@ function Export-DbaCredential {
} else {
Set-Content -Path $path -Value $sql
}
Get-ChildItem -Path $path
} catch {
Stop-Function -Message "Can't write to $path" -ErrorRecord $_ -Continue
}


Write-Message -Level Verbose -Message "Attempting to migrate $credentialName"
Get-ChildItem -Path $path
Write-Message -Level Verbose -Message "Credentials exported to $path"
}
}






}
17 changes: 9 additions & 8 deletions internal/functions/Get-DecryptedObject.ps1
Expand Up @@ -80,16 +80,16 @@ function Get-DecryptedObject {
}

<#
Query link server password information from the Db.
Remove header from pwdhash, extract IV (as iv) and ciphertext (as pass)
Ignore links with blank credentials (integrated auth ?)
#>
Query link server password information from the Db.
Remove header from pwdhash, extract IV (as iv) and ciphertext (as pass)
Ignore links with blank credentials (integrated auth ?)
#>

Write-Message -Level Verbose -Message "Query link server password information from the Db."

try {
if (-not $server.IsClustered) {
$connString = "Server=ADMIN:$sourceNetBios\$instance;Trusted_Connection=True"
$connString = "Server=ADMIN:$sourceNetBios\$instance;Trusted_Connection=True;Pooling=false"
} else {
$dacEnabled = $server.Configuration.RemoteDacConnectionsEnabled.ConfigValue

Expand All @@ -101,7 +101,7 @@ function Get-DecryptedObject {
}
}

$connString = "Server=ADMIN:$sourceName;Trusted_Connection=True"
$connString = "Server=ADMIN:$sourceName;Trusted_Connection=True;Pooling=false;"
}
} catch {
Stop-Function -Message "Failure enabling DAC on $sourcename" -Target $source -ErrorRecord $_
Expand All @@ -127,11 +127,11 @@ function Get-DecryptedObject {
}

Write-Message -Level Debug -Message $sql
Write-Message -Level Verbose -Message "Get entropy from the registry"

try {
$results = Invoke-Command2 -ErrorAction Stop -Raw -Credential $Credential -ComputerName $sourceNetBios -ArgumentList $connString, $sql {
$connString = $args[0]; $sql = $args[1]
$connString = $args[0]
$sql = $args[1]
$conn = New-Object System.Data.SqlClient.SQLConnection($connString)
$cmd = New-Object System.Data.SqlClient.SqlCommand($sql, $conn)
$dt = New-Object System.Data.DataTable
Expand All @@ -152,6 +152,7 @@ function Get-DecryptedObject {
return
}


if ($server.IsClustered -and $dacEnabled -eq $false) {
If ($Pscmdlet.ShouldProcess($server.Name, "Disabling DAC on clustered instance.")) {
try {
Expand Down

0 comments on commit 041830b

Please sign in to comment.