If you use Pleasant Password Server, you may have a need to request passwords from a command line or automated process. If you do, the script below should be very helpful.
It took me most of the evening to figure out how to request passwords using PowerShell and the RESTful API built into Pleasant Password Server (aka Keepass Server).
The vendor’s documentation is unfortunately very lacking. Seriously, would it kill you to include some examples? At any rate, the script below uses the Invoke-WebRequest cmdlet to access the RestfulAPI.
The key thing to note here is that the only way it seems to retrieve passwords is via their GUID. Importantly, this is not the UUID that is displayed in the desktop client.
The only way I’ve found to identify the GUID is to access the desired password using the webclient and then press F12 in your browser to activate the debugging tools.
From there if you select the “Network” tab, you should see the GUID appended to the end of the URL for your password server site.
# Connect to Pleasant Password Server (Keepass Server) using RESTful API to retreive password for specific entry # Keepass; REST; API; Token; Oauth2; Credential; Pleasant Password Server Function Get-KeepassPassword([string]$CredentialID) { $KeepassURL = "https://pleasantpasswordserver.company.com:10001" $Cred = Get-Credential -Message "Enter your credentials to access Keepass Server" $tokenParams = @{ grant_type='password'; username=$Cred.UserName; password=$Cred.GetNetworkCredential().password;} # Request a security token for the specified user that will be used to authenticate when requesting a password $JSON = Invoke-WebRequest -Uri "$KeepassURL/OAuth2/Token" -Method POST -Body $tokenParams -ContentType "application/x-www-form-urlencoded" # The RESTful API returns a JSON object. Convert that to a PowerShell object and extract just the access_token $Token = (ConvertFrom-Json $JSON.Content).access_token $headers = @{ "Accept" = "application/json" "Authorization" = "$Token"} # Request the password for a specific CredentialID # To obtain the CredentialID for a password, you must do the following: # 1) Connect to the Password web portal and select the password you wish to retreive # 2) Press F12 in your browser to open the debugging tools. Select the Network tab and review the GUID for the password you are looking at # 3) Provide that GUID as the CredentialID [string]$Password = Invoke-WebRequest -Uri "$KeepassURL/api/v3/rest/credential/$CredentialID/password" -Headers $headers -Method Get # The password is returned with quotes on either end # We need to remove the first and last characters (ie the quotes) so it can be used as a password $Password = $Password.Substring(1,$Password.Length-2) # Return the password for the specified CredentialID $Password } Get-KeepassPassword -CredentialID 9115ddfc-fg53-4718-85d1-63fc9c1a3067
9 comments
Skip to comment form
Hi so using the above works but what I actually want to do is build the ability to search for a password, Insert passwords. Now I know this is possible but seems like using the above methods with some modifications don’t work.
I get a message a lot “Message”:”No HTTP resource was found that matches the request URI
I am new to this invoke-webrequest so any chance you could add some guidance?
I know the URI for search is: $KeepassURL/api/v3/rest/search but cant seem to submit my search details.
Thanks in advance.
Are you using any version of Pleasant Keepass Server 6.x? The RESTful APIs prior to version 7 simply did not support search in any way, shape or form. That’s why even from the official mobile app you couldn’t search for passwords. Version 7 however has introduced search so you’ll need to be running that.
Beyond this, I’m afraid I haven’t yet sat down to try and figure it out. If you haven’t seen it already, the official documentation should give you some direction:
https://info.pleasantsolutions.com/Documentation/Pleasant_Password_Server/J._Programmatic_Access/J._Password_Server_REST_API_Documentation
If you do figure it out, please let me know as I’d love to see the search working!
Robbie,
I have this working now for searching after upgrading to version 7:
$KeepassURL = “https://serveraddress”
$Cred = Get-Credential -Message “Enter your credentials to access Keepass Server”
$tokenParams = @{
grant_type=’password’;
username=$Cred.UserName;
password=$Cred.GetNetworkCredential().password;}
# Request a security token for the specified user that will be used to authenticate when requesting a password
$JSON = Invoke-WebRequest -Uri “$KeepassURL/OAuth2/Token” -Method POST -Body $tokenParams -ContentType “application/x-www-form-urlencoded”
# The RESTful API returns a JSON object. Convert that to a PowerShell object and extract just the access_token
$Token = (ConvertFrom-Json $JSON.Content).access_token
$headers = @{
“Accept” = “application/json”
“Authorization” = “$Token”
}
$body = @{
“search” = “XXXXXXXXXXX XXXXXXX”
}
Invoke-RestMethod -method post -Uri “$KeepassURL/api/v4/rest/search” -body (ConvertTo-Json $body) -Headers $headers -ContentType ‘application/json’
I am now working on playing with the results. The main thing I have found about the above is the search, you should write it as you would in the search bar in the web interface. This will allow you to find what you are looking for better as the search results are convoluted and can be a pain to manipulate. Make your searches as direct as possibly.
Have fun and let me know what you think.
Hey,
I tried running a quick search with the code you provided and it worked great! The only thing now is the password is returned in the same request which when you think about it does make a lot of sense.
So the next step is to figure out how to request the password. I just looked at my original post and it looks like I did manage to figure that out for v6. (Funny, I barely have any memory of writing this now. That’s why blogs are so handy!).
I also noticed that the pscustomobject returned also has a groups parent. So at least with out our Keepass is structured, we can do a broad search for a keyword and then filter the returned results based upon the group and only show the contents of a specific group. Handy stuff. Thanks for sharing! If you come up with more, please post here!
Yea I noticed the password is not returned with this too. But it does make sense. Please note I have not neatened the script yet but this is where I have got to so far. The search variable used needs to be specific enough to return one item as I have not put any thing in place yet to deal with multiple values returned.
Also once it returns the details it just prints them to the screen as again I have not taken this any further yet. When I actually use this in a script I will update with improvements. But for now this should get anyone doing they will just need to manipulate the script a little. I used a VB input box for convenience probably should be a .net one if this is actually going to be used.
$KeepassURL = “https://URL TO KEEPASS”
[System.Reflection.Assembly]::LoadWithPartialName(‘Microsoft.VisualBasic’) | Out-Null
Function ConnectToKeePass
{
$Cred = Get-Credential -Message “Enter your credentials to access Keepass Server”
$tokenParams = @{
grant_type=’password’;
username=$Cred.UserName;
password=$Cred.GetNetworkCredential().password;
}
$JSON = Invoke-WebRequest -Uri “$KeepassURL/OAuth2/Token” -Method POST -Body $tokenParams -ContentType “application/x-www-form-urlencoded”
$Token = (ConvertFrom-Json $JSON.Content).access_token
$headers = @{
“Accept” = “application/json”
“Authorization” = “$Token”
}
Return $headers
}
Function Get-KeepassPassword($headers,[string]$CredentialID)
{
$Password = Invoke-RestMethod -Uri “$KeepassURL/api/v4/rest/credential/$CredentialID/password” -Headers $headers -Method Get -ContentType ‘application/json’
Return $Password
}
Function SearchKeePass($Headers,$bodyinput)
{
$body = @{
“search” = $bodyinput
}
$Result = New-Object System.Object
$Search = Invoke-RestMethod -method post -Uri “$KeepassURL/api/v4/rest/search” -body (ConvertTo-Json $body) -Headers $headers -ContentType ‘application/json’
$password = Get-KeepassPassword $Headers $Search.Credentials.id
$Result | Add-Member -MemberType NoteProperty -Name “Username” -Value $Search.Credentials.username
$Result| Add-Member -MemberType NoteProperty -Name “password” -Value $Password
Return $result
}
#Script Entry point
$searchstring = [Microsoft.VisualBasic.Interaction]::InputBox(“Enter the search term here”, “Keepass Search Variable”, “”)
$Searchaccount = SearchKeePass (ConnectToKeePass) $searchstring
write-host ($Searchaccount|Out-String)
I am going to look at building out the search function more so that you search for a group and it returns usernames and passwords in that group. Then you can search for a specific password in that group. But that would be specific to my needs. Ill post when I get round to it but might be a while.
Let me know your thoughts on above.
Very cool stuff!
Using your search code, I took a stab at having it return the passwords. It’s a quick and dirty approach but it seems to work. The code below returns two columns, the name of the entry and the password. It will do this for every returned result that was searched for. Thus if you search for “dhcp” and 4 results are returned, you will see 4 results and the password for each.
If I might make a minor suggestion on your code. I know you mentioned you hadn’t cleaned up yet so it’s probably just a typo but I notice that you called one of your functions “SearchKeepass” as opposed to “Search-Keepass”. The PowerShell authors were pretty adamant that cmdlets/functions should be in the “Verb[Dash]Noun” format. It’s a bit of a pet peeve of mine. 🙂
Thanks for continued sharing! This is awesome!
$KeepassURL = “https://passwords.dynms.com:10001”
$Cred = Get-Credential -Message “Enter your credentials to access Keepass Server” -UserName enterusername
$tokenParams = @{
grant_type=’password’;
username=$Cred.UserName;
password=$Cred.GetNetworkCredential().password;}
$JSON = Invoke-WebRequest -Uri “$KeepassURL/OAuth2/Token” -Method POST -Body $tokenParams -ContentType “application/x-www-form-urlencoded”
$Token = (ConvertFrom-Json $JSON.Content).access_token
$headers = @{
“Accept” = “application/json”
“Authorization” = “$Token”
}
$body = @{
“search” = “prtg”
}
$Results = Invoke-RestMethod -method post -Uri “$KeepassURL/api/v4/rest/search” -body (ConvertTo-Json $body) -Headers $headers -ContentType ‘application/json’
ForEach($Result in $Results.credentials)
{
$CredentialID = $Result.id
New-Object pscustomobject -Property @{‘Name’=$Result.name;’Password’ = (Invoke-WebRequest -Uri “$KeepassURL/api/v4/rest/credential/$CredentialID/password” -Headers $headers -Method Get)}
}
Good info. I’m trying to figure out how to do this in PowerShell 3 which has a bug where you can’t set the Accept header for Invoke-RestMethod. I think you end up having to use a .NET WebRequest object to actually call one of the REST API calls. Doubt the admins would let us move to PowerShell 4.
HI,
This is wonderful script and worked really as expected. I need to develop the script further and after searching the “username and password” of the server in PPS, I generated a random password using the following script :
function Generate-Password {
$alphabets= “abcdefghijklmnopqstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#%^*”
$char = for ($i = 0; $i -lt $alphabets.length; $i++) { $alphabets[$i] }
for ($i = 1; $i -le 16; $i++)
{
Write-host -nonewline $(get-random $char)
if ($i -eq 16) { write-host `n }
}
}
$pass = Generate-Password
Now,
I want to update the old password of the “searched” server with this newly generated password ( $pass) .
I tried using the following script for the same :
Function UpdatePassword
{
$body1 = @{
‘id’ = “953E46C8981B444282977C7D0C1A714C”
‘oldpassword’= $password
‘newpassword’=$pass
}
$update= Invoke-RestMethod -Uri “$KeepassURL/$Search.Credentials.username” -Headers $headers -Method Put -Body $body1 -ContentType “application/x-www-form-urlencoded”
}
But this extension to the script does not seem to update the password. Any ideas how should I proceed with it.