40

I have a Powershell script that is going to be run through an automation tool against multiple servers.

It works fine on Windows machines, as the remote calls use the tool's service account without any need for prompting or exposing any credentials in code.

This script also runs against Linux machines via SSH using the SharpSSH package. SharpSSH does not automatically use the Powershell user's credentials but requires either a username and password, an RSA key file, or a PSCredential object.

I can't prompt for credentials using Get-Credential, because it's being run through the automation tool. I don't want to expose the username and password in code or have an RSA key sitting out there. I would like to construct a PSCredential object from the current Powershell user (the service account).

Trying [System.Net.CredentialCache]::DefaultNetworkCredentials shows a blank, and [System.Security.Principal.WindowsIdentity]::GetCurrent() doesn't provide the object or information I need.

Does anyone have a method for creating a PSCredential object from the current user? Or maybe a completely different alternative for this problem?

Many thanks!

1
  • I was lucky that in my case I didn't actually need a Credential object after looking closer. I thought I did to use with New-PSSession, but it turns out it used my currently logged in user just fine if I omitted -Credential. Commented Aug 8 at 15:00

4 Answers 4

21

The Windows API will not expose the information you need, which is why Powershell can't get to them. Its an intentional feature of the security subsystem. The only way for this to work is for the Linux machines to trust the calling machine, such as joining them to an Active Directory (or any kerberos setup really).

Aside from that, you'd need to store and pass this information somehow.

You could store the RSA key in the user's keystore and extract it at runtime (using the .NET Crypto/Keystore libs), so you aren't storing the key around with the code. That way the key itself would be protected by the OS and available only when the calling user was authenticated. You'd have one more thing to install, but may be the only way to achieve what you are aiming for.

Sign up to request clarification or add additional context in comments.

2 Comments

Ahh, that's unfortunate. After some discussions and research, we're going to go with the RSA key. It'll end up enabling more in the future anyway. Thanks, Taylor!
You say if the user is part of AD, you can get a credential object; is that correct? I am trying to do this (the title of the question), on Windows.
4

Since you can get the password in plaintext from a credential object, I doubt you can get this without prompting.

Comments

4

"Trying [System.Net.CredentialCache]::DefaultNetworkCredentials shows a blank, and [System.Security.Principal.WindowsIdentity]::GetCurrent() doesn't provide the object or information I need."

You already have your answer. I use this to pass the currently logged in user's credentials along in several scripts:

$Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials $Username = $Credentials.UserName $Password = $Credentials.Password 

If you try to dump them to any kind of readable output, those values are empty when you dump them (for obvious security reasons), however they do work where you need a PSCredential object.

4 Comments

Can you let us have an example of a cmdlet that will accept this PSCredential as I haven't found any. Have been trying to use this to pass to Send-MailMessage without success
This doesn't appear to work for me: > pss mytarget -Credential $Credentials Enter-PSSession: Cannot process argument transformation on parameter 'Credential'. userName
It doesn't work for me either
This does not work.
3

How about encrypting the password using the service account's encryption key?

A quick example:

Run PowerShell as the service account, run the following and save the output to a text file (or embed it in the scheduled task call):

$String = '<PASSWORD>' ConvertFrom-SecureString -SecureString (ConvertTo-SecureString -String $String -AsPlainText -Force) 

Use the following in your scheduled task in order to decrypt and utilize the password:

 $EncryptedString = '<ENCRYPTED PASSWORD FROM ABOVE>' [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((ConvertTo-SecureString -String $EncryptedString))) 

That should do the trick. You cannot reuse the encrypted password on a different computer, though, or if you for whatever reason destroy you local key store :)

2 Comments

The secureString method is reversible, so the password is not technically secure. Without the -force option you'll get: "ConvertTo-SecureString : The system cannot protect plain text input."
@cmcginty ConvertTo-SecureString is reversible only for the user on that machine who created it. Decrypting it requires being logged in as that user. So NTFS permissions will be sufficient to protect the text file you've saved it to.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.