Encrypting passwords for automation on Windows using Powershell, WinSCP and DPAPI

I have been using VBScript to generate and send data over SFTP from a Windows host to a remote server using WinSCP, obviously this requires the use of a set of credentials which have to be shown in plain text in your script file, not ideal.

Fortunately WinSCP has some pretty good documentation about the subject however I had to do some research to figure out how to use the Windows Data Protection API in a Powershell script hence the reason for this article.

Windows DPAPI allows you to encrypt passwords, only allowing the user account which has encrypted it to decrypt it. It is still an issue if the user account is compromised obviously, but at least no more plain text passwords.

How to encrypt a password using DPAPI in Powershell ?

Using the following command you will be prompted to type the password you wish to encrypt in a CMD windows on the Windows machine where you wish to use the said password.

powershell.exe -command "$SecurePassword = Read-Host -AsSecureString "Enter password" | convertfrom-securestring | out-file C:\securePassword.txt"

This will output the encrypted password in a text file in C:\.

How to use my encrypted password in Powershell ?

In order to use this, you will need a Powershell script depending on the operation you are trying to achieve.
These scripts are using WinSCP automation library which can be downloaded here : https://winscp.net/download/WinSCP-5.11.2-Automation.zip
The files contained in the zip need to be present at the root of the folder where the scripts below are.

Get files from SFTP

The following script will get the files listed in a text file getlist.txt located in the same folder as the script.

You can easily find the SSH Key fingerprint in the right format by connecting with the WinSCP GUI and checking the Server/Protocol Information in the Session menu dropdown.

getfile.ps1

param (
$localPath = "c:",
$remotePath = "./"
)

try
{
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"

# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "<FTP_HOST>"
UserName = "<FTP_USERNAME>"
SecurePassword = ConvertTo-SecureString "<YOUR_ENCRYPTED_PASSWORD>"
SshHostKeyFingerprint = "<REMOTE_SSH_KEY_FINGERPRINT>"
}

$session = New-Object WinSCP.Session

try
{
# Connect
$session.Open($sessionOptions)

$lines = Get-Content "getlist.txt"

foreach ($line in $lines)
{
Write-Host "Downloading $line ..."
$session.GetFiles(($remotePath + $line),($localPath + $line)).Check()
}
}

finally
{
# Disconnect, clean up
$session.Dispose()
}

exit 0
}
catch [Exception]
{
Write-Host "Error: $($_.Exception.Message)"
exit 1
}
Send files to SFTP

The following script will send the files listed in a text file sendlist.txt located in the same folder as the script.

sendfile.ps1

try
{
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"

# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "<FTP_HOST>"
UserName = "<FTP_USERNAME>"
SecurePassword = ConvertTo-SecureString "<YOUR_ENCRYPTED_PASSWORD>"
SshHostKeyFingerprint = "<REMOTE_SSH_KEY_FINGERPRINT>"
}

$session = New-Object WinSCP.Session

try
{
# Connect
$session.Open($sessionOptions)

$remotePath = "./"

$lines = Get-Content "sendlist.txt"

foreach ($line in $lines)
{
Write-Host "Uploading $line ..."
$session.PutFiles($line, $remotePath).Check()
}
}
finally
{
# Disconnect, clean up
$session.Dispose()
}

exit 0
}
catch [Exception]
{
Write-Host "Error: $($_.Exception.Message)"
exit 1
}

You can call these scripts from a VBscript which will generate the text files containing the filenames to upload or download, for instance. The bottom line is that you now don’t have the plain text password in your scripts anymore.

Leave a Reply

Your email address will not be published. Required fields are marked *