Scenario
You have a SQL Server Agent job which needs to regularly access a remote file share in an untrusted domain. This requires you to provide the remote username and password while accessing the remote share. In addition, you do not wish to store the password of the remote share account in clear text.
Solution
- First, transform the clear text password into an encrypted string and store that string inside a SQL table. Note convertto/from-securestring uses DPAPI so it uses the machine dependent key if a key is not specified. You should encrypt and decrypt the password on the same machine or designate a specific key (beyond the scope of this article):
- https://blogs.msdn.microsoft.com/timid/2014/07/21/storing-securestrings-machine-independently/
- https://blogs.msdn.microsoft.com/sergey_babkins_blog/2015/11/06/certificates-part-3-encryption-and-decryption-by-hand-and-securestring/
- https://msdn.microsoft.com/en-us/library/ms995355.aspx
- https://powershell.org/2014/02/01/revisited-powershell-and-encryption/
- The SQL Agent PowerShell job step can now query the encrypted password string from SQL, create a PSCredential object using this password and then use this credential object to authenticate to the remote UNC share.
- Reference:
Sample PowerShell Script
#————————————————————————-
#————————————————————————-
#————————————————————————-
#Part 1: Save the encrypted password to a SQL Server table. This needs to run ONCE. You should run this from the PowerShell command prompt (or PowerShell ISE) on the SQL server itself (or designate a specific key during encryption and use the same key for decryption).
#Convert the clear text password to a securestring object
$secPwd=‘ENTER CLEAR TEXT PASSWORD HERE’ | ConvertTo-SecureString -AsPlainText -Force
#Convert from a securestring object to an encrypted password string
$secPwdStr= $secpwd | convertfrom-securestring
#Insert the encrypted string into a SQL Server table
$qry=”create table testPwdTable (testPwdColumn varchar(max));insert into testPwdTable values (`’$secPwdStr`’)”
invoke-sqlcmd -ServerInstance . -Database testPwdConfigDB -Query $qry
#————————————————————————-
#————————————————————————-
#————————————————————————-
#Part 2: Authenticate to the UNC share using previously stored encrypted password. Run this within the SQL Agent PowerShell subsystem job step. If the password string was encrypted on a different machine you will need to specify a specific key during decryption.
$UserName=‘ENTER_REMOTE_DOMAIN_HEREENTER_REMOTE_USERNAME_HERE’
#Query the SQL Server table to get the saved encrypted password string
#Note ExpandProperty is used to get the raw string testPwdColumn value (instead of a sql column object)
$qry=”select top 1 testPwdColumn from testPwdTable”
$secPwdStr= invoke-sqlcmd -ServerInstance . -Database testPwdConfigDB -Query $qry | select -ExpandProperty testPwdColumn
#Convert the encrypted password string to a SecureString object
$secpwd= $secPwdStr | ConvertTo-SecureString
#Create a PowerShell credential object with this username + password(securestring object)
$cr = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $UserName , $secpwd
#Create a mapped drive to the remote share, pass the credential object to the New-PSDrive commandlet
if (-not (test-path “y:”))
{
write-output (“Creating mapped drive y:”)
New-PSDrive -Name y -PSProvider FileSystem -Root ‘\ENTER_IP_ADDRESS_HERESQLBACKUPFOLDER’ -Credential $cr -Description “Log Shipping source share”
}
$r=test-path “y:”
write-output (“Path status is ” + $r)
#Expect a value of true to be returned when looking at the job history
Fany Carolina Vargas | SQL Dedicated Premier Field Engineer | Microsoft Services