1

I've got a function in my script that wraps up the send-mailmessage cmdlet and does a bit of logic before sending out each email.

My question is how do I create the argument list to feed into send-mailmessage so that Cc, Bcc, and Attachments are optional.

What I'd done before is just a few if statements. But adding -Cc to the mix, that will be 9 if statements instead of the current 4. I figure I'm over-thinking this and there's got to be a simpler way.

Stripped down Function:

Function Send-Email ($To, $Cc, $Bcc, $Subject, $From, $Body, $Attachments)
{
    #Some more code goes here that sometimes modifies the incoming parameters
    $EmailServer = my.mail.server
    Try
    {
        #Need to add ability for $Cc to be optional
        if ($Attachments -and $Bcc) {send-mailmessage -to $To -Cc $Cc -Bcc $Bcc -subject $Subject -From $From -body $Body -smtpserver $EmailServer -attachments $Attachments -ErrorAction "Stop"}
        if ($Attachments -and -not $Bcc) {send-mailmessage -to $To -Cc $Cc -subject $Subject -From $From -body $Body -smtpserver $EmailServer -attachments $Attachments -ErrorAction "Stop"}
        if ($Bcc -and -not $Attachments) {send-mailmessage -to $To -Cc $Cc -Bcc $Bcc -subject $Subject -From $From -body $Body -smtpserver $EmailServer -ErrorAction "Stop"}
        if (-not $Attachments -and -not $Bcc) {send-mailmessage -to $To -Cc $Cc -subject $Subject -From $From -body $Body -smtpserver $EmailServer -ErrorAction "Stop"}
    }
    Catch [system.exception]
    {
        "Failed to send email to $($To) due to: $_"  #Logging removed for SO example code
    }
    Finally
    {}
}

I've tried generating the arguments as one long string or also as an array of strings, then using invoke-expression. I've tried the same, but using the '&' sign to execute the cmdlet.

I just get prompted for the parameters by the shell when I try that.

PS E:\script> invoke-expression 'send-mailmessage $a'

cmdlet Send-MailMessage at command pipeline position 1
Supply values for the following parameters:
From: 


PS E:\script> & send-mailmessage $a

cmdlet Send-MailMessage at command pipeline position 1
Supply values for the following parameters:
From: 

I've tried setting $Cc as $Null, or $False, or a null string "", but send-mailmessage complains of invalid parameters.

I feel like I'm missing something simple here, but in my mind, the function should look something like this invalid example:

Function Send-Email ($To, $Cc, $Bcc, $Subject, $From, $Body, $Attachments)
{
    #Some more code goes here that sometimes modifies the incoming parameters
    $EmailServer = my.mail.server
    if ($Cc) {$CcArg = "-Cc $Cc"}
    if ($Bcc) {$BccArg = "-Bcc $Bcc"}
    if ($Attachments) {$AttachArg = "-Attachments $Attachments"}
    Try
    {
        send-mailmessage -to $To ($CcArg) ($BccArg) -subject $Subject -From $From -body $Body -smtpserver $EmailServer $AttachArg -ErrorAction "Stop"
    }
    Catch [system.exception]
    {
        "Failed to send email to $($To) due to: $_"  #Logging removed for SO example code
    }
    Finally
    {}
}

Thanks for any thoughts or suggestions.

M Jeremy Carter
  • 433
  • 4
  • 9

2 Answers2

2

Ah hah! Found this post: Inline expansion of powershell variable as cmdlet parameter?

So function will look something like (Not fully tested, but the principle works):

Function Send-Email ($To, $Cc, $Bcc, $Subject, $From, $Body, $Attachments)
{
    #Some more code goes here that sometimes modifies the incoming parameters
    $EmailServer = my.mail.server
    $MoreArgs = @{}
    if ($Cc) {$MoreArgs.Add("Cc",$Cc)}
    if ($Bcc) {$MoreArgs.Add("Bcc",$Bcc)}
    if ($Attachments) {$MoreArgs.Add("Attachments",$Attachments)}
    Try
    {
        send-mailmessage -to $To -subject $Subject -From $From -body $Body -smtpserver $EmailServer -ErrorAction "Stop" @MoreArgs
    }
    Catch [system.exception]
    {
        "Failed to send email to $($To) due to: $_"  #Logging removed for SO example code
    }
    Finally
    {}
}
Community
  • 1
  • 1
M Jeremy Carter
  • 433
  • 4
  • 9
  • 2
    This feature (presenting a hashtable to a cmdlet to be interpreted as a list of parameters) is called "splatting" and is indeed the best answer to your problem. – Mike Shepard Oct 28 '13 at 17:04
2

Another option that eliminates all the Ifs.

$EmailParams = @{
 To          = $To
 Cc          = $Cc
 From        = $From
 Subject     = $Subject
 Body        = $body
 SMTPServer  = $MailServer
 Attachments = $Attachments
 ErrorAction = 'Stop'
 }

 $EmailParams.keys |
  Where {$EmailParams.$_ -eq $null } |
  foreach { $EmailParams.remove($_) }

 Try { Send-MailMessage @EmailParams }
 Catch { "Failed to send email to $($To) due to: $_"  }
 Finally {}
mjolinor
  • 66,130
  • 7
  • 114
  • 135