0

I have an application, running in .Net Framework 4.7.2 that I need to connect to a postgresql database. The connection works when the database exists, but if it doesn't, I want to create the database. In order to do that from the application, I planned on using ProcessStartInfo and sending the command:

string strDbCreationCmd = $"createdb -U postgres {dbName}";

I was easily able to create the database using solely the command line, which additionally prompts me for the password for the superuser, which I type into the command line:

enter image description here

I have additionally gotten a working ProcessStartInfo reader that I have used in previous applications for doing something similar (such as starting a docker container, which I unfortunately cannot use for instantiating the database for this specific case). I have modified it slightly to perform some directory navigation and then run the command. This works fine, up until the point where the password prompt appears. First off, it shows up in the launched command prompt, which I was not expecting: enter image description here

Then, when I try to write the password ("test" is the fill-in here) nothing happens and I time out on the next read. If I type "test" into the command line, it will register and continue, but obviously, I cannot rely on someone entering the superuser password into the command line.

How would I send input to the command line for the Password?

Here is my code for running the command line:

static Tuple<string, string> RunCmdLine(string cmd, string navCmd1 = "", string navCmd2 = ""){
var startInfo = new ProcessStartInfo()
{
    WindowStyle = ProcessWindowStyle.Normal,
    WorkingDirectory = @"C:\",
    FileName = "cmd.exe",
    UseShellExecute = false,
    RedirectStandardInput = true,
    RedirectStandardOutput = true,
    RedirectStandardError = true
};
var response = new StringBuilder();
var error = new StringBuilder();

Process process = new Process() { StartInfo = startInfo };

AutoResetEvent errorWaitHandle = new AutoResetEvent(false);
    
process.ErrorDataReceived += (sender, args) =>
{
    if (args.Data == null)
    {
        errorWaitHandle.Set();
    }
    else
    {
        error.AppendLine(args.Data);
    }
};

process.Start();

/* clear out the boot up text:
    Microsoft Windows [Version 10.0.19045.4170]
    (c) Microsoft Corporation. All rights reserved.
    empty line
*/
process.StandardOutput.ReadLine();
process.StandardOutput.ReadLine();
process.StandardOutput.ReadLine();

// if navigation to a directory is needed
if (!string.IsNullOrEmpty(navCmd1))
{
    process.StandardInput.WriteLine(navCmd1);
    process.StandardOutput.ReadLine(); // cd\
    process.StandardOutput.ReadLine(); // space
}
if (!string.IsNullOrEmpty(navCmd2))
{
    process.StandardInput.WriteLine(navCmd2);
    process.StandardOutput.ReadLine(); // cd "Program Files\PostgreSQL\15\bin"
    process.StandardOutput.ReadLine(); // space
}

// now write the actual command
process.StandardInput.WriteLine(cmd);
response.AppendLine(process.StandardOutput.ReadLine());

errorWaitHandle.WaitOne(1000);
process.StandardInput.WriteLine("test");

// read the input
response.AppendLine(process.StandardOutput.ReadLine());
// get the output we actually want
response.AppendLine(process.StandardOutput.ReadLine());
// get any errors that arrived
process.BeginErrorReadLine();

// give a second for errors to read if any (freezes if none otherwise)
errorWaitHandle.WaitOne(1000);
    
// close the process
process.Close();

return new Tuple<string, string>(response.ToString(), error.ToString());}
6
  • stackoverflow.com/questions/13351078/… Commented Jun 3, 2024 at 17:01
  • 2
    This is an X/Y problem. Instead of asking "how do I pipe in the password when the executable asks me for it", ask "how do I run createdb non-interactively?" The documentation has some advice on that. Commented Jun 3, 2024 at 17:04
  • @gunr2171 Thanks for pointing me that direction. It looks like the .pgpass file is a good option. I will try that out and see how it works. Commented Jun 3, 2024 at 17:53
  • This post shows how to send responses to prompts when using System.Diagnostics.Process. Commented Jun 5, 2024 at 3:06
  • However, a quick search for c# postgres create database results in the following: stackoverflow.com/questions/17838913/… Commented Jun 5, 2024 at 3:08

1 Answer 1

0

Thanks to the comment from gunr2171, I looked into pgpass (The password file): enter link description here

Creating this file with the expected password avoids the hang-up that results from being prompted for the password. The file is placed in AppData\Roaming\postgresql and is titled pgpass.conf. The format and an example of its use is:

#hostname:port:database:username:password
localhost:5432:*:*:test

where * allows for any database and any username. Fill in your own password in place of "test".

Finally, I changed the command to run to ignore prompting for the password, so that it relies on this pgpass.conf file as follows:

string strDbCreationCmd = $"createdb -U postgres -w {dbName}";
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.