Reputation: 909
Two situations. first is the previously discussed Start-Process
process that I need to use due to -wait.
Start-Process, Invoke-Command or?)
Start-Process -FilePath 'C:\Gyb\gyb.exe' -ArgumentList @("--email $UserEmail", "--action backup", "--local-folder $GYBfolder", "--service-account") -Wait
$filename = "C:\reports\" + $UserEmail.Split("@")[0] + "_Backup.csv"
Send-MailMessage @MailArguments -to $PEmail -cc -Body $Body -Subject $mailSubject
Upvotes: 3
Views: 708
Reputation: 21418
I will answer these in reverse order.
How do I know if the email sent?
Send-MailMessage
will throw an error if the mail server can't send the message. Beyond that, you're at the mercy of the network of servers ensuring email gets delivered to the appropriate mailbox.
If you really need to verify receipt, you could always request a delivery receipt, butSend-MailMessage
does not support this. You would need to use System.Web.Mail
namespace to prepare and send the mail instead, which you can set the DeliveryNotificationOptions.OnSuccess
option. However, heed the following warning from Microsoft:
The
Send-MailMessage
cmdlet is obsolete. This cmdlet does not guarantee secure connections to SMTP servers. While there is no immediate replacement available in PowerShell, we recommend you do not useSend-MailMessage
. For more information, see Platform Compatibility note DE0005.
The linked additional information explains that SmtpClient
is the component at fault, and other .NET libraries are recommended for sending emails instead.
A less reliable option would be to wait for a Non-Delivery Receipt in the inbox of the sending account to appear, but there is no guarantee how long it might take to receive one back. You could wait 5 mins before declaring success, but the NDR might not come back for 10.
How do I get the error from this since I command opens and runs?
If you mean you want to figure out why the Start-Process
bit failed, you have three options. IMO both Start-Process
solutions aren't perfect in this regard but will get the job done, but the third solution gives you the most control.
-NoNewWindow
cannot be used with-Verb RunAs
Start-Process -NoNewWindow ....
Start-Process -RedirectStandardOutput stdout.txt ....
$stdout = Get-Content stdout.txt
Process.Start
method with the ProcessStartInfo
class to launch the process. Most robust, but more complicated than using Start-Process
:# Create process start information. See documentation for property details
$pInfo = New-Object System.Diagnostics.ProcessStartInfo -Property @{
FileName = 'ping'
Arguments = 'google.com'
UseShellExecute = $false
RedirectStandardOutput = $true
CreateNoWindow = $true
}
# Start the process
$p = [System.Diagnostics.Process]::Start($pInfo)
# Wait until process finishes
while( !$p.HasExited ) {
Start-Sleep 10 # Number of seconds to sleep
}
# Get the standard output as a string
$output= $p.StandardOutput.ReadToEnd()
&
to prefix your command and execute your program. It's much easier to use than Start-Process
and unless you need to use one of the flags of Start-Process
(like -Wait
for GUI apps). The above section 3. can be simplified if we use &
instead:$output = & ping google.com
This works because the call operator does directly invoke the process, and the process output is able to be redirected. I have not tested this but I believe in this case STDERR can be redirected to the variable by redirecting your Error Stream to the Success Stream.
The caveat to using the &
call operator is that you are stuck with how it works; there is no customizing the behavior. Fortunately, it should work for the majority of use cases.
If you're a keen observer you will notice that Process.Start
returns the same Process
type that Start-Process -Passthru ....
returns. You may be asking yourself, "why can't we just use the convenient-to-use cmdlet to return the Process
object and simply consume its StandardOutput
property?
We need to ensure that $pInfo
sets a few critical properties which you can't set withStart-Process
:
UseShellExecute = $false
FileName
instead of invoking via a shell (e.g.cmd.exe /c FileName Arguments
)STDOUT
, STDERR
, or STDIN
streams for the child processRedirectStandardOutput = $true
STDOUT
to the Stream
read by the Process.StandardOutput
StreamReader
STDERR
and STDIN
as well, RedirectStandardError
and RedirectStandardInput
respectively. Process.StandardError
and Process.StandardInput
work similarly as well, noting that the latter is a StreamWriter
.Since Start-Process
doesn't let you provide a ProcessStartInfo
argument, nor does it provide parameters to control either behavior, file redirection is the only option. Otherwise, the returned process object with Start-Process -Passthru ....
is the same type. Trying to use the Process.StandardOutput
StreamReader
doesn't work in this case, because there is no redirected stream to read from.
Upvotes: 3