0

I'm trying to create a powershell script which will enter a password coming from the Credential Manager into the password input of a Python script. In this older post, I found some information on how to start a process with Powershell and then enter some text in the STDIN but for some reason, this method does not work for me. I execute the python script and it just keeps waiting for a password input in the Powershell command line window.

This is the code and it executes the Python script correctly which asks for a password, but nothing happens after that. I can enter the password manually and click enter, but that is not the purpose of course. Then I can just execute the python script by itself.

$executingScriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
. $executingScriptDirectory\CredMan.ps1

$launcherScript = Join-Path $executingScriptDirectory "launcher.py"
$credTarget = 'some-target-in-credential-manager'

Write-Host "Loading password from Windows credmgr entry '$credTarget' ..."

[object] $cred = Read-Creds $credTarget
if ($cred -eq $null)
{
    Write-Host ("No such credential found: {0}" -f $credTarget)
    Exit 2
}

# Found the credential; grab the password and boot up the launcher
[string] $password = $cred.CredentialBlob

Write-Host "Launching $launcherScript ..."
Write-Host "Password: '$password'"

$psi = New-Object System.Diagnostics.ProcessStartInfo;
$psi.Arguments = "$launcherScript "
$psi.FileName = "python.exe";
$psi.UseShellExecute = $false; # start the process from its own executable file
$psi.RedirectStandardInput = $true; # enable the process to read from stdin

$p = [System.Diagnostics.Process]::Start($psi);

Start-Sleep -s 2 # wait 2 seconds so that the process can be up and running
$p.StandardInput.WriteLine($password); 
$p.WaitForExit()

What could the problem be? The password is requested in the python script with this line and so uses the getpass module.

password = getpass.getpass("Enter your password: ")

Thank you for your help.

If you need any more information, just request it :).

Community
  • 1
  • 1
Digihash
  • 327
  • 1
  • 13
  • What is the output from the Write-Host call? Are you seeing the password you expect at that point? I'm surprised that you can just cast CredentialBlob as a string and that is the password. – Brian O''Byrne Apr 20 '16 at 16:42

2 Answers2

1

I suppose the Python process does not read the password from the STDIN stream but directly from the terminal the process is attached to. This terminal stream is not subject to any redirects you happen to install before starting the subprocess, so writing to the process's STDIN will not influence this. The fact that you can type your password directly using the keyboard into the Python process and that it accepts it proves me right, I'd say.

In your case you need to tweak the Python process to read the PW from somewhere else, e. g. by passing a special option (totally depending on your Python process of course) or by patching the Python source itself.

Maybe there also are Windows-specific ways to simulate keyboard presses, but that I would call a very ugly a hack and thus cannot recommend.

Alfe
  • 56,346
  • 20
  • 107
  • 159
  • Hi, I've changed the python script so now you can give a parameter with it for the password like this: script.py -p 'password' But how do I give this $password variable as a parameter for -p to the python script? – Digihash May 04 '16 at 11:23
  • I don't know the language you are using to call the Python script, but the place where you've got `$psi.Arguments = "$launcherScript "` and `$psi.FileName = "python.exe";` seems suspicious. Maybe it works with `$psi.Arguments = "$launcherScript -p $password"`? Or can you somehow pass an array of all arguments (e. g. `$psi.Arguments = [ "$launcherScript", "-p", "$password" ]`)? – Alfe May 06 '16 at 20:54
1

Alfe, thank you for showing me the right direction to solve this problem.

I've adjusted the python script so that it accepts parameters on the command line and the parameter for the password can be given after the -p option, so like this:

$ script.py -p "password"

To do this from the powershell script, I used this code to first get the credential out of the Windows Credential Manager and give it as a parameter to the python script.

I used an existing script to be able to get the credentials out of the credentials manager, namely the CredMan.ps1 script.

# Get the path of where this script is being invocated to reference to the script files in the same directory as this script.
$executingScriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
# Include external script to speak with Credential Manager
. $executingScriptDirectory\CredMan.ps1

$launcherScript = Join-Path $executingScriptDirectory "script.py"
$credentialTarget = "name-of-credential-in-manager"

[object] $cred = Read-Creds $credentialTarget
if ($cred -eq $null) {
    Write-Host ("No such credential found: {0}" -f $credentialTarget)
    Exit 2
}

# Found the credential; Grab the password and execute the script with the password
[string] $password = $cred.CredentialBlob

# Execute python script with password given as parameter
$exe = "python.exe"
&$exe $launcherScript -p $password

Thank you for your help and I hope you understand the given answer.

Digihash
  • 327
  • 1
  • 13
  • nice solution, but how do you release it this to end client? You have to execute CredMan.ps1 on client machine every time password changes. Is there a way to convert it to secure string and pass it along with software? – olekb Apr 14 '17 at 16:56
  • I'm not sure I understand your question but CredMan.ps1 is executed every time the python script is executing. This is because at any moment the user can change his password in the Windows Credential manager. So we never save the password and let this over to the credential manager which is designed to securely store passwords. – Digihash Apr 24 '17 at 05:42