Import Accounts from CyberArk Safes using Microsoft PowerShell and the CyberArk PACLI utility.
CyberArk includes a Command-Line Interface, PACLI, that communicates directly with the CyberArk Vault. It operates on "files" stored in "safes" in the vault. It can export CyberArk account data, which CyberArk clients like PrivateArk and Password Vault Web Access (PVWA) store as files in safes.
The instructions below use a PowerShell script that uses PACLI to export all the files matching a pattern. Using the default pattern "*," it exports all files from the Safe. It extracts the Username, Address, and password for each one; however, it can be configured to extract other fields if required. The script provides the exported files as objects, so ConvertTo-CSV is then used to transform them into a Comma-separated Value (CSV) format to import them into Keeper.
Prerequisites
Three external components are required to use the script below:
CyberArk PACLI
A Vault.ini configuration file
A User.ini credential file
CyberArk PACLI
The PACLI is available for download from the CyberArk Marketplace website. It is a zip file containing the PACLI.exe binary and some supporting files. The script will expect the path of the directory containing the binary.
Vault.ini
The vault.ini file contains parameters PACLI needs to locate and log on to the vault. For example:
The ADDRESS is the hostname or IP address of the CyberArk Vault server.
The PREAUTHSECUREDSESSION and TRUSTSSC settings are required when the log-on user is authenticated via LDAP (Active Directory) or RADIUS. Otherwise, they may be omitted.
User.ini
The User.ini file is in INI format. However, it is generated using theCreateCredFile.exe tool that CyberArk includes, along with some of its components. For example, generating a user.ini for Myuser in the CORP Active Directory domain:
The latest version of the PACLI zip contains the tool. Running it with the /? parameter will explain the other options that are useful in other authentication scenarios.
Export
Paste the following into a file ending with .ps1, e.g., Export-CyberArkSafeFiles.ps1
<#.SYNOPSISExports 'files', i.e., CyberArk Account passwords from a CyberArk Safe using PACLI..DESCRIPTIONUses CyberArk's PACLI command to export files from a CyberArk Safe.It retrieves files, their categories, and contents and exports an object for each.It uses filepattern=* to get all files in the safe by default.The default categories are 'Address' and 'UserName'.#>param (# The name of the 'Vault' in CyberArk, e.g., 'CAMainVault' [Parameter(Mandatory =$true)][string]$VaultName,# The name of the 'Safe' in CyberArk [Parameter(Mandatory =$true)][ValidateNotNullOrEmpty()][string]$SafeName,# The CyberArk log on user (must match credentials in the User.ini) [Parameter(Mandatory =$true)][ValidateNotNullOrEmpty()][string]$Username,# The path to the PACLI directory containing PACLI.exe [Parameter(Mandatory =$true)] [ValidateScript({ Test-Path-PathType Leaf (Join-Path$_'PACLI.exe') })] [string]$PACLIPath,# Arguments `findfiles` uses to generate the list of files to export [string[]]$FindFilesArguments ='filepattern=*',# The categories to export from the files [Parameter()][string[]]$Categories =@('Address','UserName'),# A CyberArk Vault.ini file [Parameter()][ValidateScript({ Test-Path$_-PathType Leaf })] [string]$VaultIniPath ='Vault.ini',# A CyberArk User.ini (or .cred) file as generated by CreateCredFile.exe [Parameter()][ValidateScript({ Test-Path$_-PathType Leaf })] [string]$UserIniPath ='User.ini',# The folder in the safe to export files from--most use 'Root' [string]$FolderName ='Root',# The session ID to use for the underlying PACLI commands [Parameter()][ValidateNotNullOrEmpty()][string]$SessionId,# ErrorAction for retrievefile errors [Parameter()][ValidateSet('Stop','Continue','SilentlyContinue')] [string]$PACLIErrorAction ='Continue')$PACLI =Join-Path $PACLIPath 'PACLI.exe'-ResolvefunctionInvoke-PACLI {param ( [Parameter(Mandatory =$True)][string]$Command, [Parameter(ValueFromRemainingArguments)][string[]]$Arguments ) $Executable =".\{0}"-f (Split-Path-Leaf $PACLI) $CommandLine ="$Executable $Command $($Arguments -join' ')"try {Push-Location$(Split-Path-Parent $PACLI) -StackName 'PACLI' $Output = (& $Executable $Command $Arguments 2>$null)if ($LastExitCode-eq0) { $Output }else {switch ($PACLIErrorAction) {'Continue' {Write-Error"'$CommandLine' exited with code $LastExitCode" }'Stop' { throw"'$CommandLine' exited with code $LastExitCode" } } } }finally {Pop-Location-StackName 'PACLI' }}Invoke-PACLI init$PACLIDefaults ="vault=$VaultName","user=$Username","safe=$SafeName","folder=$FolderName"if ($SessionId) { $PACLIDefaults +="sessionId=$SessionId"}Invoke-PACLIdefault @PACLIDefaultsInvoke-PACLI definefromfile vault=$VaultName parmfile=(Resolve-Path $VaultIniPath) |Out-NullInvoke-PACLI logon logonfile=(Resolve-Path $UserIniPath) |Out-NullInvoke-PACLI opensafe |Out-Nulltry {# Create a temporary file to store the file contents during processing $tempFile = [IO.Path]::GetTempFileName()# Split the tempFile path into the folder and the filename for 'retrievefile' $localFolder =Split-Path $tempFile $localFile =Split-Path-Leaf $tempFile# Get the list of files in the safeInvoke-PACLI findfiles $FindFilesArguments 'output(name)'|Where-Object { $_.Trim() -ne'' } |ForEach-Object { $file =@{ Name =$_ }# Retrieve the file and store the contents (the password) in the file objectInvoke-PACLI retrievefile file=$_ localfolder=$localFolder localfile=$localFileif ($LastExitCode-ne0) { return } $file.Password = (Get-Content $tempFile).TrimEnd([Char]0) # Can be null-padded# Get the list of categories for the file as a quoted CSV stringInvoke-PACLI listfilecategories file=$_'output(all,enclose)'|ForEach-Object {# Get the category name and value and strip the quotes $category = ($_-split','|ForEach-Object { $_.Trim('"') })[0..1]# Add the category to the file object if it is on the listif ($category[0] -in $Categories) { $file[$category[0]] = $category[1] } } [PSCustomObject]$file }}finally {Remove-Item-Path $tempFile -Force}Invoke-PACLI closesafe vault=$VaultName user=$Username safe=$SafeName |Out-NullInvoke-PACLI logoff vault=$VaultName user=$Username |Out-NullInvoke-PACLI term |Out-Null
Extract the PACLI.zip into the same directory or a sub-directory of the directory containing the script.
Open PowerShell and change to the directory containing the script.
Run the script and pipe the output into Export-CSV:
Note the use of use of tab characters instead of commas, the use of UTF-8 encoding, excluding a header and not quoting the data all help Keeper import the data properly.
Transformation
PowerShell can help transform the data beyond just formatting it as CSV. This more advanced example creates the "login" field by combining the Username and Address fields and uses it as the "title" field as well.