<#
.SYNOPSIS
Exports 'files', i.e., CyberArk Account passwords from a CyberArk Safe using PACLI.
.DESCRIPTION
Uses 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' -Resolve
function Invoke-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 -eq 0) {
$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-PACLI default @PACLIDefaults
Invoke-PACLI definefromfile vault=$VaultName parmfile=(Resolve-Path $VaultIniPath) |
Out-Null
Invoke-PACLI logon logonfile=(Resolve-Path $UserIniPath) | Out-Null
Invoke-PACLI opensafe | Out-Null
try {
# 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 safe
Invoke-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 object
Invoke-PACLI retrievefile file=$_ localfolder=$localFolder localfile=$localFile
if ($LastExitCode -ne 0) { 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 string
Invoke-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 list
if ($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-Null
Invoke-PACLI logoff vault=$VaultName user=$Username | Out-Null
Invoke-PACLI term | Out-Null