Automatischer Export in csv Files
Hier finden Sie ein PowerShell Skript zum Export der Daten.
Generell empfehlen wir die eingebaute Backup-Lösung zu verwenden. Diese erzeugt eine Datei welche hochverschlüsselt ist (AES256). Dieses Backup kann auch an einem Einzelplatz / Notfallnotebook oder ähnlichem in den Pleasant Password Server eingespielt werden.
Tipp:
Über den KeePass Client können Sie in den Formaten csv, html, xml und kdbx exportieren. Gerade der Export im Format xml ist sehr mächtig, da er alle Felder exportiert.
Wenn Sie dennoch eine .csv File mit den Daten erzeugen wollen, finden Sie hier ein PowerShell-Beispiel, dass Sie sich entsprechend anpassen können.
Achtung:
Die Erstellung von Skripten und die Interaktion mit der API liegt in Ihrer Verantwortung. Das bereitgestellte Skript ist als Beispiel gedacht und sollte an Ihre individuellen Anforderungen angepasst werden. Bitte denken Sie daran, dass die Anpassung und Nutzung des Skripts auf eigenes Risiko erfolgt und wir leider keinen Support dafür anbieten können.
# Create a CSV file of all credential entries in
# Pleasant Keepass Server including:
# - passwords, foldername, folder path,
# - tags, totp secret,
# - file attachments, and
# - password breach potential indicator.
#
# Version:
# - 3.3.3
#
# Functionality:
# - Export Password Server entries
# - Download and save any attachment files separately
# - Anonymously check passwords and hashes against the popular haveibeenpwned.com database
#
# Usage:
# - enter your parameter values
# - to integrate with password breach checking, first install PwnedPassCheck (below)
# - running the script will prompt for username/password login
#
# Parameter Options:
# password server url,
# export path,
# export passwords,
# export all results,
# check for pwned password,
# rate-limit password retrievals
#
#
# Pwned Module Integration & Usage:
# - PwnedPassCheck (v2.0) - GitHub: PowerShell haveibeenpwned integration module, by rmbolger
# https://github.com/rmbolger/PwnedPassCheck
# - To use this module, first install by following the instructions or use this command:
# Install-Module -Name PwnedPassCheck -Scope CurrentUser
#
$PasswordServerURL = "https://mydomain:10001" # The URL for your Password Server
$ExportPath = 'c:\Temp\ExportedEntries.csv' # Where to write exported entry list
$AttachmentsPath = 'c:\Temp\Attachments' # Where to save attachments
$ExportPasswords = $true # Include passwords in export? (many hits to db)
$DelayTime = .05 # Rate-limit password retrievals (in secs)
$ExportAll = $true # (true) Export all credentials, or (false) just exports 1 sample record
$ExportAttachments = $true # Export attachments
$ExportCustomFields = $true # Export custom user fields
$ExportCustomAppFields = $true # Export custom application fields
$CheckPwned = $false # Check if password has been pwned?
$Results = @() # Our entries (final result)
$FolderLookup = @{} # Hash-table folder lookup
$ThisLevelCreds = @() # Entry list
# Prompt for admin credentials to access Password Server
$Cred = Get-Credential
# Create the OAuth2 token params
$tokenParams = @{
grant_type='password';
username=$Cred.UserName;
password=$Cred.GetNetworkCredential().password;
}
# Authenticate to Pleasant Password Server
try {
$JSON = Invoke-WebRequest -Uri "$PasswordServerURL/OAuth2/Token" -Method POST -Body $tokenParams -ContentType "application/x-www-form-urlencoded" -ErrorAction stop
$Token = (ConvertFrom-Json $JSON.Content).access_token
Write-Host "Logs: Authentication successful"
} catch {
Write-Error "Logs: Failed to authenticate: $_"
exit
}
# Prep JSON headers
$headers = @{
"Accept" = "application/json"
"Authorization" = "$Token"
}
# Ensure the attachments folder exists
if ($ExportAttachments -and -not (Test-Path -Path $AttachmentsPath)) {
New-Item -Path $AttachmentsPath -ItemType Directory
Write-Host "Logs: Created attachments folder at $AttachmentsPath"
}
# Function to get all attachments from an entry
function Get-Attachments {
param (
[string]$EntryId,
[string]$BaseUrl,
[string]$ApiKey
)
$url = "$BaseUrl/api/v5/rest/entries/$EntryId/attachments"
$headers = @{
"Authorization" = "Bearer $ApiKey"
}
try {
$response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
#Write-Host "Logs: Retrieved attachments for EntryId ${EntryId}"
return $response
} catch {
Write-Error "Logs: Failed to retrieve attachments for EntryId ${EntryId}: $_"
return $null
}
}
# Function to save an attachment to a file
function Save-AttachmentToFile {
param (
[string]$FileName,
[string]$FileData,
[string]$OutputPath
)
$bytes = [System.Convert]::FromBase64String($FileData)
$filePath = Join-Path -Path $OutputPath -ChildPath $FileName
try {
[System.IO.File]::WriteAllBytes($filePath, $bytes)
Write-Host "Logs: Saved attachment to $filePath"
} catch {
Write-Error "Logs: Failed to save attachment to ${filePath}: $_"
}
}
# Function to get all folders and credentials
function Get-AllFoldersAndCredentials {
param (
[string]$BaseUrl,
[hashtable]$Headers
)
try {
$KeepassData = Invoke-RestMethod -method get -Uri "$BaseUrl/api/v5/rest/folders" -Headers $Headers -ContentType 'application/json'
Write-Host "Logs: Retrieved folders and credentials"
return $KeepassData
} catch {
Write-Error "Logs: Failed to retrieve folders and credentials: $_"
exit
}
}
# Retrieve all folders and credentials
$KeepassData = Get-AllFoldersAndCredentials -BaseUrl $PasswordServerURL -Headers $headers
# Make the command a variable so we can execute the .property syntax to access the child properties using invoke-expression
$global:Command = '($KeepassData)'
# Function to get the full path of a folder
function Get-FolderPath {
param (
[string]$folderId,
[hashtable]$folderLookup
)
$folderPath = "\"
while ($folderId -ne "00000000-0000-0000-0000-000000000000") {
$folder = $folderLookup[$folderId]
$folderPath = $folder[0] + "\" + $folderPath
$folderId = $folderLookup[$folderId][1] # recurse on the parent group id
}
return $folderPath.TrimEnd("\")
}
$EntryCount = 0
$path = ""
# Will break once all of the levels have been processed
:outerLoop while(1 -eq 1)
{
# Retrieve the folders at the current level
$ThisLevelFolders = $null
$ThisLevelFolders = Invoke-Expression -Command $global:Command
ForEach($folder in $ThisLevelFolders | select name, id, parentid, notes)
{
$FolderLookup += @{ $folder.id = $folder.name, $folder.parentid, $folder.notes }
}
# Retrieve the entries in these folders
$global:Command = "$global:Command."+"children"
$ThisLevelCreds = $ThisLevelFolders.credentials
ForEach($row in $ThisLevelCreds)
{
if ($ExportPasswords)
{
$pwd = (Invoke-WebRequest -Uri "$PasswordServerURL/api/v5/rest/credential/$($row.id)/password" -Headers $headers -Method Get).Content.Trim([char]0x022)
}
else {$pwd = ""}
if ($CheckPwned)
{
$pwned = (Get-PwnedPassword $pwd).SeenCount
}
else {$pwned = ""}
# Get the folder name and full path
$groupName = $folderLookup[$row.GroupId][0]
$path = Get-FolderPath -folderId $row.GroupId -folderLookup $FolderLookup
# Retrieve attachments
$attachmentFileNames = @()
$attachmentFileData = @()
$attachmentFileSizes = @()
if ($ExportAttachments) {
if ($attachments) {
foreach ($attachment in $attachments) {
Write-Host "Logs: Attachment found for EntryId $($row.id), saving to file..."
Save-AttachmentToFile -FileName $attachment.FileName -FileData $attachment.FileData -OutputPath $AttachmentsPath
$attachmentFileNames += $attachment.FileName
$attachmentFileData += $attachment.FileData
$attachmentFileSizes += $attachment.FileSize
}
} else {
#Write-Host "Logs: No attachments found for EntryId $($row.id)"
}
}
# Retrieve custom fields if available
$customUserFields = if ($ExportCustomFields) { $row.CustomUserFields } else { @{} }
$customAppFields = if ($ExportCustomAppFields) { $row.CustomApplicationFields } else { @{} }
# Set the entry fields
$Results +=[pscustomobject]@{
Path = $path
GroupName = $groupName
GroupId = $row.GroupId
Id = $row.id
Name = $row.name
URL = $row.url
Username = $row.username
Tags = ($row.tags.name) -join " ; "
Created = $row.created
Modified = $row.modified
Expires = $row.expires
Notes = $row.notes
TOTPIssuer = $row.issuer
TOTPSecret = $row.secret
TOTPDigits = $row.digits
TOTPPeriod = $row.period
Password = $pwd
Pwned = $pwned
AttachmentFileNames = $attachmentFileNames -join ", "
AttachmentFileData = $attachmentFileData -join ", "
AttachmentFileSizes = $attachmentFileSizes -join ", "
CustomUserFields = $customUserFields
CustomApplicationFields = $customAppFields
}
$EntryCount += 1
# Count
if(-not $ExportAll)
{break outerLoop}
# Add a delay here. The parameter is in seconds.
Start-Sleep -Seconds $DelayTime
}
# If no more data is found in the current level, assume we've hit the end and exit. Otherwise append .children to dig another level deeper
if($ThisLevelFolders.count -eq 0)
{break}
}
If ($ExportAll -eq $true)
{
# Export to CSV file
$Results | Export-CSV $ExportPath -NoTypeInformation
}
Else
{
# Print sample output to screen
$Results | select * | select -first 1
}
Write-Output "Exported $EntryCount credentials"