1

I'm using the following command to send an automated email on Powershell.

powershell -Command {$to = "myemail@mail.com"; $from = "senderemail@mail.com"; $subject = "subject goes here"; $body = "message body goes here"; $smtpServer = "smtp.server.com"; $smtpClient = New-Object Net.Mail.SmtpClient($smtpServer, 587); $smtpClient.EnableSsl = $true; $smtpClient.Credentials = New-Object System.Net.NetworkCredential("senderemail@mail.com", "Dnd912n9d2n1dsda90"); $smtpClient.Send($from, $to, $subject, $body);}";

Here it works. So now I want to use this code on a private way (avoiding showing passwords and emails).

So I made a console app with C# to open Powershell and execute the command, but it's not working.

strCmdText = "{$to = \"myemail@mail.com\"; $from = \"senderemail@mail.com\"; $subject = \"subject goes here\"; $body = \"message body goes here\"; $smtpServer = \"smtp.server.com\"; $smtpClient = New-Object Net.Mail.SmtpClient($smtpServer, 587); $smtpClient.EnableSsl = $true; $smtpClient.Credentials = New-Object System.Net.NetworkCredential(\"senderemail@mail.com\", \"Dnd912n9d2n1dsda90\"); $smtpClient.Send($from, $to, $subject, $body);}";

using var ps = PowerShell.Create();

    var processStartInfo = new ProcessStartInfo();
    processStartInfo.FileName = "powershell.exe";
    processStartInfo.Arguments = " powershell-Command " + strCmdText;
    processStartInfo.UseShellExecute = false;
    processStartInfo.RedirectStandardOutput = true;

    using var process = new Process();
    process.StartInfo = processStartInfo;
    process.Start();

I'm not receiving any errors on visual studio. if I open .exe it closes inmediatly as if it would be working. But no email is sent or received.

I want to do it by this way because of the privacy the command would have avoiding passwords and emails being shown. Program has to activate when X conditions on computer happen, so it has to execute easy. Say that if I execute the command on CMD, i receive a different error, that's why I'm doing it on powershell.

genius
  • 45
  • 4

1 Answers1

0

The syntax of the first command you're showing (powershell -Command { ... }) works only from inside a PowerShell session, not when powershell.exe, the Windows PowerShell CLI, is called from another (non-PowerShell) process.

Therefore:

  • Do not enclose the value of $strCmdText in { ... }

    • When the PowerShell CLI is called from the outside, { ... } creates a script block containing ... instead of actually executing ...
  • \-escape all embedded " chars.

    • On its process command line, the PowerShell CLI requires those " characters that are part of the command to execute via -Command to be escaped, as \".
  • Remove the extraneous powershell token from processStartInfo.Arguments = " powershell-Command " + ..., i.e . use processStartInfo.Arguments = "-Command " + ...

    • Strictly speaking, you don't need -Command, as it is powershell.exe's default parameter; however, using it is a good habit to form, especially since pwsh, the PowerShell (Core) CLI, now defaults to -File instead.

To put it all together:

// Note the need to escape each embedded " as \\\":
// \ to escape it for the sake of C#,
// preceded by \\ in order to produce verbatim \" in the string value.
strCmdText = "$to = \\\"myemail@mail.com\\\"; $from = \\\"senderemail@mail.com\\\"; $subject = \\\"subject goes here\\\"; $body = \\\"message body goes here\\\"; $smtpServer = \\\"smtp.server.com\\\"; $smtpClient = New-Object Net.Mail.SmtpClient($smtpServer, 587); $smtpClient.EnableSsl = $true; $smtpClient.Credentials = New-Object System.Net.NetworkCredential(\\\"senderemail@mail.com\\\", \\\"Dnd912n9d2n1dsda90\\\"); $smtpClient.Send($from, $to, $subject, $body)";

using var ps = PowerShell.Create();

    var processStartInfo = new ProcessStartInfo();
    processStartInfo.FileName = "powershell.exe";
    processStartInfo.Arguments = "-Command " + strCmdText;
    processStartInfo.UseShellExecute = false;
    processStartInfo.RedirectStandardOutput = true;

    using var process = new Process();
    process.StartInfo = processStartInfo;
    process.Start();

Note:

  • As long as launching powershell.exe succeeds, you'll see no errors on the C# side, even if the powershell.exe call then fails.

  • To test for failure:

    • Once process.HasExited returns true, test process.ExitCode for 0 (success) or nonzero (failure).

      • Note that how powershell.exe -Command sets its exit code may not be obvious: it is the success status of whatever statement executes last that determines the exit code (0 in case of success, 1 otherwise); if a fatal (script-terminating) error occurs (potentially in an earlier statement), the exit code is 1 too - see this answer for details.
  • To examine error messages:

    • Examine the process' stderr output.
mklement0
  • 382,024
  • 64
  • 607
  • 775