smtp.smime.lib.ps1

<#PSScriptInfo
 
    .VERSION 1.0.4
 
    .GUID b1f9432e-8253-441a-9fc1-d88cf2f17e8b
 
    .AUTHOR rob.kalmar
 
    .COMPANYNAME
 
    .COPYRIGHT Rob Kalmar
 
    .TAGS SMTP SMIME Email STARTTLS
 
    .LICENSEURI
 
    .PROJECTURI
 
    .ICONURI
 
    .EXTERNALMODULEDEPENDENCIES
 
    .REQUIREDSCRIPTS
 
    .EXTERNALSCRIPTDEPENDENCIES
 
    .RELEASENOTES
 
 
#>


<#
 
    .DESCRIPTION
    Send encrypted and/or signed messages through SMTP.
    If you like this script please consider donating:
    https://bunq.me/robkalmar/5.00/PowerShellSMIMEToolkit
    Thanks!
 
#>
 

# PowerShell S/MIME Toolkit v1.0
#
#
# Copyright 2020 Rob Kalmar
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# Functions to send signed and encrypted s/mime messages
#
# Tested platforms:
# Windows Server 2008 R2 (Needs this hotfix: http://support.microsoft.com/kb/2480994)
# Windows Server 2012
# Windows Server 2012 R2
# Windows Server 2016
# Windows Server 2019

Function Show-License
{
  [CmdletBinding()]
  param ()

  Add-Type -AssemblyName System.Drawing
  Add-Type -AssemblyName System.Windows.Forms

  $Form1 = New-Object -TypeName System.Windows.Forms.Form
  $Form1.Size = New-Object -TypeName System.Drawing.Size -ArgumentList (400,450)
  $Form1.Text = 'PowerShell S/MIME Toolkit v1.0 license'
  $Form1.StartPosition = 'CenterScreen'
  $Form1.FormBorderStyle = 'FixedDialog'
  $Form1.MaximizeBox = $false
  $Form1.MinimizeBox = $false

  $License = 'Copyright 2020 Rob Kalmar
 
    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  IN THE SOFTWARE.'


  $Label1 = New-Object -TypeName System.Windows.Forms.Label
  $Label1.Location = New-Object -TypeName System.Drawing.Size -ArgumentList (10,20) 
  $Label1.Size = New-Object -TypeName System.Drawing.Size -ArgumentList (380,280) 
  $Label1.Text = $License
  $null = $Form1.Controls.Add($Label1) 

  $Label2 = New-Object -TypeName System.Windows.Forms.Label
  $Label2.Location = New-Object -TypeName System.Drawing.Size -ArgumentList (10,320) 
  $Label2.Size = New-Object -TypeName System.Drawing.Size -ArgumentList (380,20) 
  $Label2.Text = 'If you like these PowerShell scripts please feel free to make a donation...'
  $null = $Form1.Controls.Add($Label2) 

  $LinkLabel1 = New-Object -TypeName System.Windows.Forms.LinkLabel 
  $LinkLabel1.Location = New-Object -TypeName System.Drawing.Size -ArgumentList (10,340) 
  $LinkLabel1.Size = New-Object -TypeName System.Drawing.Size -ArgumentList (150,20) 
  $LinkLabel1.LinkColor = 'BLUE' 
  $LinkLabel1.ActiveLinkColor = 'RED' 
  $LinkLabel1.Text = 'Make donation...' 
  $null = $Form1.Controls.Add($LinkLabel1) 
  
  $null = $LinkLabel1.Add_Click(
    {
      [Diagnostics.Process]::Start('https://bunq.me/robkalmar/5.00/PowerShellSMIMEToolkit')
    }
  ) 

  $Label3 = New-Object -TypeName System.Windows.Forms.Label
  $Label3.Location = New-Object -TypeName System.Drawing.Size -ArgumentList (10,360) 
  $Label3.Size = New-Object -TypeName System.Drawing.Size -ArgumentList (380,20) 
  $Label3.Text = 'Thank you!'
  $null = $Form1.Controls.Add($Label3) 

  $Button1 = New-Object -TypeName System.Windows.Forms.Button
  $Button1.Location = New-Object -TypeName System.Drawing.Size -ArgumentList (290,380) 
  $Button1.Size = New-Object -TypeName System.Drawing.Size -ArgumentList (80,20) 
  $Button1.Text = 'Close'
  $null = $Form1.Controls.Add($Button1)    

  $null = $Button1.Add_Click(
    {    
      $Form1.Close()
    }
  )

  $null = $Form1.ShowDialog()
  
  Return $null
}

Function Test-IsAscii
{
  <#
      .SYNOPSIS
      Tests if the input string only contains ASCII values.
      .DESCRIPTION
      Tests if the input string only contains ASCII values.
      Returns true if this is the case, otherwise it returns false.
      .PARAMETER $text
      A string to check.
      .EXAMPLE
      Test-IsAscii -text 'This string contains only ASCII'
  #>

  param
  (
    [parameter(Mandatory=$true)][string]$text
  )
  [byte[]]$utf8text = [Text.Encoding]::UTF8.GetBytes($text)
  [string]$asciitext = [Text.Encoding]::ASCII.GetString($utf8text)
  If ($text -eq $asciitext)
  {
    Return $True
  }
  Else
  {
    Return $False
  }
}

function New-MailserverSettings
{
  <#
      .SYNOPSIS
      Create a new PSObject which sets the properties of a mail server
      .DESCRIPTION
      This function creates a new PSObject and sets the properties of a mail server object.
      The function returns a PSObject.
      .EXAMPLE
      Call this function with a string representing the fully qualified domain name of the mail server
      New-MailserverSettings "mail.example.com"
      .PARAMETER $FQDN
      A string containing fully qualified domain name of the mail server
      .PARAMETER $Output
      An integer indicating whether to send to mail to the mail server and/or to disk.
      Output = 0 -> save to eml file
      Output = 1 -> send to smtp server
      Output = 2 -> save to eml file and send to smtp server
      .PARAMETER $Port
      A string containing the port of the mail server to connect to, default to "25"
      .PARAMETER $STARTTLS
      A boolean indicating whether to use STARTTLS or not when connecting to the mail server, defaults to $False
      .PARAMETER $Username
      A string containing the username used for authentication on the mail server, defaults to ""
      .PARAMETER $Password
      A secure string containing the password used for authentication on the mail server, defaults to 1
  #>

  param
  (
    [parameter(Mandatory=$true)][string]$FQDN,
    [ValidateSet(0,1,2)][int]$Output = 1,
    [string]$Port = '25',
    [string]$STARTTLS = $False,
    [string]$VerifyServerCertificate = $True,
    [string]$Username = '',
    [string]$Password = ''
  )

  $MailServer = new-object -TypeName PSObject
  $MailServer | Add-Member -Name FQDN -Value $FQDN -MemberType NoteProperty
  $MailServer | Add-Member -Name Output -Value $Output -MemberType NoteProperty
  $MailServer | Add-Member -Name Port -Value $Port -MemberType NoteProperty
  $MailServer | Add-Member -Name STARTTLS -Value $STARTTLS -MemberType NoteProperty
  $MailServer | Add-Member -Name VerifyServerCertificate -Value $VerifyServerCertificate -MemberType NoteProperty
  $MailServer | Add-Member -Name Username -Value $Username -MemberType NoteProperty
  $MailServer | Add-Member -Name Password -Value $Password -MemberType NoteProperty
  Return $MailServer
}


function Get-MimeType
{
  <#
      .SYNOPSIS
      Retrieves the Mime Type of a file extension from the Registry
      .DESCRIPTION
      This function retrieves the Mime Type of an file extension from the Windows Registry
      The function returns a string of the Mime Type.
      .EXAMPLE
      Call this function with a string representing the extension of a file
      Get-MimeType ".zip"
      .PARAMETER $Extension
      A string containing the extension of a file
  #>

  [CmdletBinding()]
  param
  (
    [string]$Extension = $null
  )

  $MimeType = 'application/octet-stream'

  $null = New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT

  Try
  {
    $Exists = Test-Path -Path "HKCR:$Extension" -ErrorAction Stop
    If ($Exists)
    {
      $Item = Get-ItemProperty -Path HKCR:$Extension -ErrorAction Stop
      $ItemContentType = $Item.'Content Type'
      If (($ItemContentType -eq $null) -or ($ItemContentType -eq ''))
      {
        $ItemContentType = 'application/octet-stream'
      }
      $MimeType = $ItemContentType
    }
  }
  Catch
  {
    $MimeType = 'application/octet-stream'
  }
  Return $MimeType
}


function New-UTF8EncodedFileName
{
  <#
      .SYNOPSIS
      Given a filename string the function encodes it into UTF8.
      .DESCRIPTION
      Given a filename string the function encodes it into UTF8 for use in
      the Content-Type or Content-Disposition name/filename paramters
      .PARAMETER $FileName
      The filename to encode into UTF8
      .EXAMPLE
      New-UTF8EncodedFileName -FileName 'example.txt'
      Encodes the filename example.txt to UTF8.
  #>

  param
  (
    [parameter(Mandatory=$true)][string]$FileName
  )
    
  [String]$Header = ' =?UTF-8?B?'
  [String]$Footer = '?='
  [String]$EncodedB64FileName = $null
  [int]$ChunkSize = 60 #needs to be multiple of 4, otherwise Outlook does not like it.
  [String]$B64FileName = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($FileName))
  [int]$SizeB64FileName = $B64FileName.Length

  $UTF8EncodedFileName = New-Object -TypeName System.Text.StringBuilder 

  [int]$Position = 0
  While ($Position -le ($SizeB64FileName - $ChunkSize))
  {
    $null = $UTF8EncodedFileName.AppendLine()
    $EncodedB64FileName = $Header + $B64FileName.Substring($Position,$ChunkSize) + $Footer
    $null = $UTF8EncodedFileName.Append("$EncodedB64FileName")
    $Position = $Position + $ChunkSize   
  }
  If (($SizeB64FileName-$Position) -gt 0)
  {
    $null = $UTF8EncodedFileName.AppendLine()
    $EncodedB64FileName = $Header + $B64FileName.Substring($Position,$SizeB64FileName-$Position) + $Footer
    $null = $UTF8EncodedFileName.Append("$EncodedB64FileName") 
  }
    
  Return $UTF8EncodedFileName
}

function New-HeaderMimePart
{
  <#
      .SYNOPSIS
      Creates a new header for a Mime part
      .DESCRIPTION
      This function creates a new header for Mime part of a message
      The function returns a string
      .EXAMPLE
      Call this function with a string representing the Mime Type and file name of the Mime part to which the header will be added
      New-HeaderMimePart "application/octet-stream" "filename.zip"
      .PARAMETER $MimeType
      A string containing the Mime Type of a file
      .PARAMETER $MimeType
      A string containing the file name of a file
  #>

  param
  (
    [parameter(Mandatory=$true)][string]$MimeType,
    [parameter(Mandatory=$true)][string]$FileName
  )

  $MimePartHeader = New-Object -TypeName System.Text.StringBuilder 
  
  If ((Test-IsAscii -text $FileName) -and ($FileName.Length -le 64))
  {
    $null = $MimePartHeader.AppendLine("Content-Type: $MimeType; charset=`"utf-8`";")
    $null = $MimePartHeader.AppendLine(" name=`"$FileName`"")
    $null = $MimePartHeader.AppendLine('Content-Transfer-Encoding: base64')
    $null = $MimePartHeader.AppendLine('Content-Disposition: attachment;')
    $null = $MimePartHeader.AppendLine(" filename=`"$FileName`"")
    $null = $MimePartHeader.AppendLine() 
  }
  Else
  {
    [String]$UTF8EncodedFileName = New-UTF8EncodedFileName -FileName $FileName

    $null = $MimePartHeader.Append("Content-Type: $MimeType; charset=`"utf-8`"; name=`"")
    $null = $MimePartHeader.Append("$UTF8EncodedFileName")
    $null = $MimePartHeader.AppendLine('"')

    $null = $MimePartHeader.AppendLine('Content-Transfer-Encoding: base64')
    
    $null = $MimePartHeader.Append('Content-Disposition: attachment; filename="')
    $null = $MimePartHeader.Append("$UTF8EncodedFileName")
    $null = $MimePartHeader.AppendLine('"')

    $null = $MimePartHeader.AppendLine()
  }
    
  Return $MimePartHeader
}


function New-MimePart
{
  <#
      .SYNOPSIS
      Creates a new Mime part for a Mime Message
      .DESCRIPTION
      This function creates a new Mime part for a Mime message
      The function returns a string
      .EXAMPLE
      Call this function with an object representing a file
      New-MimePart file
      .PARAMETER $File
      An object representing a file
  #>

  param
  (
    [parameter(Mandatory=$true)][IO.FileInfo]$File
  )

  $Extension = $null
  $Extension = [IO.Path]::GetExtension($File)
  $MimeType = Get-MimeType -Extension $Extension

  $FileName = [IO.Path]::GetFileName($File)
  $Header = New-HeaderMimePart -MimeType $MimeType -FileName $FileName

  $MimePart = New-Object -TypeName System.Text.StringBuilder
  $null = $MimePart.Append($Header)

  [Byte[]] $BinaryData = [IO.File]::ReadAllBytes($File)
  [string] $Base64Value = [Convert]::ToBase64String($BinaryData, [Base64FormattingOptions]::InsertLineBreaks)

  $null = $MimePart.Append($Base64Value)
  $null = $MimePart.AppendLine()

  Return $MimePart
}


function New-MimeMessage
{
  <#
      .SYNOPSIS
      Create a Mime Message
      .DESCRIPTION
      This function creates multipart/mixed a Mime message
      The function returns a string
      .EXAMPLE
      Call this function with a string representing the body of the Mime Message and an object representing a file
      New-MimeMessage "body text" file
      .PARAMETER $File
      An string representing the body text of the message
      .PARAMETER $File
      An object representing a file
  #>

  [CmdletBinding()]
  param
  (
    [string]$Body = $null,
    [IO.FileInfo[]]$FileList = $null
  )

  $MIMEMessage = New-Object -TypeName System.Text.StringBuilder 

  If ($FileList -eq $null)
  {
    $null = $MIMEMessage.AppendLine("Content-Type: text/plain; charset=`"utf-8`"")
    $null = $MIMEMessage.AppendLine('Content-Transfer-Encoding: base64')

    $null = $MIMEMessage.AppendLine()
    
    [Byte[]] $BodyBytes = [Text.Encoding]::UTF8.GetBytes($Body)
    [string] $BodyB64 = [Convert]::ToBase64String($BodyBytes, [Base64FormattingOptions]::InsertLineBreaks)
    
    $null = $MIMEMessage.Append($BodyB64)
    $null = $MIMEMessage.AppendLine()
  }
  Else
  {
    [String]$Boundary = 'boundary-' + [guid]::NewGuid()
        
    $null = $MIMEMessage.AppendLine('Content-Type: multipart/mixed;') 
    $null = $MIMEMessage.AppendLine(" boundary=$Boundary") 
    $null = $MIMEMessage.AppendLine()
    $null = $MIMEMessage.AppendLine('This is a multi-part message in MIME format.')
    $null = $MIMEMessage.AppendLine("--$Boundary")
    $null = $MIMEMessage.AppendLine("Content-Type: text/plain; charset=`"utf-8`"")
    $null = $MIMEMessage.AppendLine('Content-Transfer-Encoding: base64')
    $null = $MIMEMessage.AppendLine()
    
    [Byte[]] $BodyBytes = [Text.Encoding]::UTF8.GetBytes($Body)
    [string] $BodyB64 = [Convert]::ToBase64String($BodyBytes, [Base64FormattingOptions]::InsertLineBreaks)
    
    $null = $MIMEMessage.Append($BodyB64)
    $null = $MIMEMessage.AppendLine()
    $null = $MIMEMessage.Append("--$Boundary")
   
    $File = $null

    Foreach ($File in $FileList)
    {
      $null = $MIMEMessage.AppendLine()  
      $Part = New-MimePart -File $File

      $null = $MIMEMessage.Append($Part)
      $null = $MIMEMessage.Append("--$Boundary")
    }
        
    $null = $MIMEMessage.AppendLine('--')
  }

  Return $MIMEMessage
}


function New-EncryptedContent
{
  <#
      .SYNOPSIS
      Returns an encrypted byte array of a string using given certificate
      .DESCRIPTION
      This function encrypts a given string using the public key of a given certificate.
      The function returns an array of encrypted bytes.
      .EXAMPLE
      Call this function with a string to be encrypted and a certificate containing a public key
      New-EncryptedContent "Example string" certificate
      .PARAMETER $MIMEMessage
      A string containing the message to be encrypted
      .PARAMETER $Certificate
      A certificate which will be used to encrypt the Mime Message.
      .PARAMETER $EncryptionAlgorithm
      A string specifying the encryption algorithm to be used for encyption, defaults to "1.2.840.113549.3.7" (3DES)
      "1.2.840.113549.3.2" # RC2 Key length 40/64/128
      "1.3.14.3.2.7" #DES
      "1.2.840.113549.3.7" #3DES
      "2.16.840.1.101.3.4.1.2" #AES-128
      "2.16.840.1.101.3.4.1.22" #AES-192
      "2.16.840.1.101.3.4.1.42" #AES-256
      .PARAMETER $KeyLength
      An integer specifying the key length to be used in case of using RC2, defaults to 128
      Valid values are [40,64,128]
  #>

  param
  (
    [parameter(Mandatory=$true)][string]$MIMEMessage,
    [parameter(Mandatory=$true)][Security.Cryptography.X509Certificates.X509Certificate2]$Certificate,
    [string]$EncryptionAlgorithm = '1.2.840.113549.3.7',
    [ValidateSet(40,64,128)][int]$KeyLength = 128
  )

  Add-Type -AssemblyName System.Security
    
  [Byte[]] $BodyBytes = [Text.Encoding]::ASCII.GetBytes($MIMEMessage.ToString())
  $ContentInfo = New-Object -TypeName System.Security.Cryptography.Pkcs.ContentInfo -ArgumentList (,$BodyBytes) 
  
  $SubjectIdentifierType = 2
    
  $AlgorithmIdentifier = New-Object -TypeName System.Security.Cryptography.Pkcs.AlgorithmIdentifier -ArgumentList $EncryptionAlgorithm
  If ($EncryptionAlgorithm -eq '1.2.840.113549.3.2')
  {
    $AlgorithmIdentifier.KeyLength = $KeyLength
  }
  $EnvelopedCMS = New-Object -TypeName System.Security.Cryptography.Pkcs.EnvelopedCms -ArgumentList $SubjectIdentifierType , $ContentInfo , $AlgorithmIdentifier

  $CMSRecipient = New-Object -TypeName System.Security.Cryptography.Pkcs.CmsRecipient -ArgumentList $SubjectIdentifierType , $Certificate 

  $EnvelopedCMS.Encrypt($CMSRecipient) 
  [Byte[]] $EncryptedBytes = $EnvelopedCMS.Encode() 
  Return $EncryptedBytes
}


function New-SignedContent
{
  <#
      .SYNOPSIS
      Returns a signed byte array of a string using given certificate
      .DESCRIPTION
      This function signs a given string using the private key of a given certificate.
      The function returns an array of signed bytes.
      .EXAMPLE
      Call this function with a string to be signed and a certificate containing a private key
      New-SignedContent "Example string" certificate
      .PARAMETER $MIMEMessage
      A string containing the message to be signed
      .PARAMETER $Certificate
      A certificate which will be used to sign the Mime Message.
      .PARAMETER $EndCertOnly
      Set to $True to avoid issues with building up the certificate chain to the root certificate, defaults to $False
      .PARAMETER $Detached
      If set to $True the signatue will be detached so non smime capable clients can still read the message.
      .PARAMETER $Boundary
      Defines the boudary used in the multipart MIME message.
      .PARAMETER $DigestAlgorithm
      A string specifying which digest algorithm to use, defaults to "1.3.14.3.2.26" (SHA-1)
      "1.2.840.113549.2.5" #md5
      "1.3.14.3.2.26" #SHA-1
      "2.16.840.1.101.3.4.2.1" #SHA-256
      "2.16.840.1.101.3.4.2.2" #SHA-384
      "2.16.840.1.101.3.4.2.3" #SHA-512
      .PARAMETER $EnhancedProtection
      Turn ON or OFF enhanced protection. When ON the recipient and subject will be added as signed attributes to the signature.
      This enables you to check if they were changed in transit.
      Note: No mail client actually checks for this, so you need to program something yourself.
      .PARAMETER $Recipient
      The recipient the include as a signed attribute.
      .PARAMETER $Subject
      The subject to include as a signed attribute.
  #>

  param
  (
    [parameter(Mandatory=$true)][string]$MIMEMessage,
    [parameter(Mandatory=$true)][Security.Cryptography.X509Certificates.X509Certificate2]$Certificate,
    [bool]$EndCertOnly = $False,
    [bool]$Detached = $True,
    [string]$Boundary = 'boundary-1',
    [string]$DigestAlgorithm = '1.3.14.3.2.26',
    [bool]$EnhancedProtection = $True,
    [string]$Recipient = $null,
    [string]$Subject = $null        
  )
 
  Add-Type -AssemblyName System.Security
    
  [Byte[]] $BodyBytes = [Text.Encoding]::ASCII.GetBytes($MIMEMessage.ToString())
  $ContentInfo = New-Object -TypeName System.Security.Cryptography.Pkcs.ContentInfo -ArgumentList (,$BodyBytes) 
  $SignedCMS = New-Object -TypeName System.Security.Cryptography.Pkcs.SignedCms -ArgumentList $ContentInfo, $Detached

  $CMSSigner = New-Object -TypeName System.Security.Cryptography.Pkcs.CmsSigner -ArgumentList $Certificate 
  If ($EndCertOnly)
  {
    $CMSSigner.IncludeOption = [Security.Cryptography.X509Certificates.X509IncludeOption]::EndCertOnly
  }
  Else
  {
    $CMSSigner.IncludeOption = [Security.Cryptography.X509Certificates.X509IncludeOption]::WholeChain
  }
  $CMSSigner.DigestAlgorithm = $DigestAlgorithm

  $TimeStamp=Get-Date
  $Pkcs9SigningTime = New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9SigningTime -ArgumentList ($TimeStamp)
  $null = $CMSSigner.SignedAttributes.Add($Pkcs9SigningTime)

  If ($EnhancedProtection)
  {
    If ($Recipient)
    {
      $documentNameAttribute = New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9DocumentName -ArgumentList ("$Recipient")
      $null = $CMSSigner.SignedAttributes.Add($documentNameAttribute)
    }
    If ($Subject)
    {
      $documentDescriptionAttribute = New-Object -TypeName System.Security.Cryptography.Pkcs.Pkcs9DocumentDescription -ArgumentList ("$Subject")
      $null = $CMSSigner.SignedAttributes.Add($documentDescriptionAttribute)
    }
  }
    
  $SignedCMS.ComputeSignature($CMSSigner)
  [Byte[]] $SignedBytes = $SignedCMS.Encode()

  If ($Detached -eq $True)
  {
    $MultipartSigned = New-Object -TypeName System.Text.StringBuilder
        
    $null = $MultipartSigned.AppendLine("--$Boundary")
    $null = $MultipartSigned.AppendLine("$MIMEMessage")
    $null = $MultipartSigned.AppendLine("--$Boundary")
    $null = $MultipartSigned.AppendLine('Content-Type: application/pkcs7-signature; name="smime.p7s"')
    $null = $MultipartSigned.AppendLine('Content-Disposition: attachment; filename="smime.p7s"')
    $null = $MultipartSigned.AppendLine('Content-Transfer-Encoding: base64')
    $null = $MultipartSigned.AppendLine()

    [String]$Signature = [Convert]::ToBase64String($SignedBytes, [Base64FormattingOptions]::InsertLineBreaks)
    $null = $MultipartSigned.AppendLine("$Signature")

    $null = $MultipartSigned.AppendLine()
    $null = $MultipartSigned.AppendLine("--$Boundary--")
    
    [Byte[]] $SignedBytes = [Text.Encoding]::UTF8.GetBytes($MultipartSigned.ToString())
  }  

  Return $SignedBytes
}


function Send-SMIMEMail
{
  <#
      .SYNOPSIS
      Sends a SMIME message to a mail server
      .DESCRIPTION
      This function sends message to a mail server
      The function returns $True if the message is successfully sent otherwise $False
      .EXAMPLE
      Call this function with an object representing a mail server and an object of type System.Net.Mail.MailMessage
      Send-SMIMEMail mailserver message
      .PARAMETER $MailServer
      An object representing a mail server
      .PARAMETER $File
      An object representing an object of type System.Net.Mail.MailMessage
  #>

  param
  (
    [parameter(Mandatory=$true)][PSObject]$MailServer,
    [parameter(Mandatory=$true)][Net.Mail.MailMessage]$Message
  )

  $SendMail = $False
    
  $scriptPath = $(Split-Path -Path $script:MyInvocation.MyCommand.Path)

  $MailClient = New-Object -TypeName System.Net.Mail.SmtpClient -ArgumentList $MailServer.FQDN, $MailServer.Port
  $MailClient.Credentials = New-Object -TypeName System.Net.NetworkCredential -ArgumentList ($MailServer.Username, $MailServer.Password)

  $Delivery = $MailServer.Output
  switch ($Delivery)
  {
    1
    {
      $MailClient.DeliveryMethod = [Net.Mail.SmtpDeliveryMethod]::Network
      $MailClient.EnableSsl = [Convert]::ToBoolean($($MailServer.STARTTLS))
      
      If ([Convert]::ToBoolean($($MailServer.VerifyServerCertificate)))
      {
        [Net.ServicePointManager]::ServerCertificateValidationCallback = $null
      }
      Else
      {
        [Net.ServicePointManager]::ServerCertificateValidationCallback = { Return $True }
      }
      
      Try
      {
        $MailClient.Send($Message)
        $MailClient.Dispose()
        $SendMail = $True
      }
      Catch
      {
        $SendMail = $False
        $MailClient.Dispose()
      } 
    }

    2
    {
      $MailClient.DeliveryMethod = [Net.Mail.SmtpDeliveryMethod]::SpecifiedPickupDirectory
            
      $Exists = Test-Path -Path "$scriptPath\sent"
      if (!$Exists)
      {
        $null = New-Item -ItemType directory -Path "$scriptPath\sent"
      }
      $MailClient.PickupDirectoryLocation = "$scriptPath\sent"
      Try
      {
        $MailClient.Send($Message)
        $SendMail = $True
      }
      Catch
      {
        $SendMail = $False
      }
      $MailClient.DeliveryMethod = [Net.Mail.SmtpDeliveryMethod]::Network
      $MailClient.EnableSsl = [Convert]::ToBoolean($($MailServer.STARTTLS))
      
      If ([Convert]::ToBoolean($($MailServer.VerifyServerCertificate)))
      {
        [Net.ServicePointManager]::ServerCertificateValidationCallback = $null
      }
      Else
      {
        [Net.ServicePointManager]::ServerCertificateValidationCallback = { Return $True }
      }

      Try
      {
        $MailClient.Send($Message)
        $MailClient.Dispose()
        $SendMail = $True
      }
      Catch
      {
        $SendMail = $False
        $MailClient.Dispose()
      }
    }

    Default
    {
      $MailClient.DeliveryMethod = [Net.Mail.SmtpDeliveryMethod]::SpecifiedPickupDirectory
      $Exists = Test-Path -Path "$scriptPath\sent"
      if (!$Exists)
      {
        $null = New-Item -ItemType directory -Path "$scriptPath\sent"
      }
      $MailClient.PickupDirectoryLocation = "$scriptPath\sent"
      Try
      {
        $MailClient.Send($Message)
        $MailClient.Dispose()
        $SendMail = $True
      }
      Catch
      {
        $SendMail = $False
        $MailClient.Dispose()
      }
    }
  }
  Return $SendMail
}

function Get-Oid
{
  <#
      .SYNOPSIS
      Get the Oid of an Encryption or Digest algorithm.
      .DESCRIPTION
      This function return the Oid (as string) for a given encryption or digest algorithm (or $null when not known).
      .PARAMETER Algorithm
      A string of the name of the encryption or digest algorithm.
      .EXAMPLE
      Get-Oid -Algorithm 'aes128'
      This returns a string with the Oid of aes128 which is '2.16.840.1.101.3.4.1.2'
  #>


  param
  (
    [parameter(Mandatory=$true)][string]$Algorithm
  )
  
  Switch ($Algorithm)
  {
    # DigestAlgorithms
    'md5'     { $Oid = '1.2.840.113549.2.5' }
    'sha1'    { $Oid = '1.3.14.3.2.26' }
    'sha256'  { $Oid = '2.16.840.1.101.3.4.2.1' }
    'sha384'  { $Oid = '2.16.840.1.101.3.4.2.2' }
    'sha512'  { $Oid = '2.16.840.1.101.3.4.2.3' }
    
    # EncryptionAlgorithms
    'rc2'     { $Oid = '1.2.840.113549.3.2' }
    'des'     { $Oid = '1.3.14.3.2.7' }
    '3des'    { $Oid = '1.2.840.113549.3.7' }
    'aes128'  { $Oid = '2.16.840.1.101.3.4.1.2' }
    'aes192'  { $Oid = '2.16.840.1.101.3.4.1.22' }
    'aes256'  { $Oid = '2.16.840.1.101.3.4.1.42' }
    
    # Unknown
    Default   { $Oid = $null }
  }

  Return $Oid
}

Function New-MicAlg
{
  <#
      .SYNOPSIS
      Given a digest algorithm returns a string for use in the micalg parameter in the Content-Type.
      .DESCRIPTION
      Given a digest algorithm returns a string for use in the micalg parameter in the Content-Type.
      This uses the specs of smime 3.1 (https://tools.ietf.org/html/rfc3851#section-3.4.3.2)
      If you want to use smime 3.2 see RFC 5751
      .PARAMETER $DigestAlgorithm
      The Digest Algorithm used for signing messages.
      .EXAMPLE
      New-MicAlg -DigestAlgorithm '1.3.14.3.2.26'
      Returns sha1
  #>



  param
  (
    [parameter(Mandatory=$true)][string]$DigestAlgorithm       
  )
    
  switch ($DigestAlgorithm)
  {
    '1.2.840.113549.2.5'     { $MicAlg = 'md5'}
    '1.3.14.3.2.26'          { $MicAlg = 'sha1'}
    '2.16.840.1.101.3.4.2.1' { $MicAlg = 'sha256'}
    '2.16.840.1.101.3.4.2.2' { $MicAlg = 'sha384'}
    '2.16.840.1.101.3.4.2.3' { $MicAlg = 'sha512'}
    Default                  { $MicAlg = 'sha1'}
  }
    
  Return $MicAlg
}

function Send-EncryptedMail
{
  <#
      .SYNOPSIS
      Send an encrypted mail message through a mail server
      .DESCRIPTION
      This function sends an encrypted message through a mail server using a specified certificate.
      The function returns $True when successfull otherwise $False
      .EXAMPLE
      Call this function with a mail server object, a certificate of the recipient, a string containing the sender mail address, a string with the subject text, a string containing the body text,
      an attachment representing a file.
      Send-EncryptedMail mailserver certificate "example@example.com" "subject text" "body text" file
      .PARAMETER $MailServer
      An object representing a mail server
      .PARAMETER $RecipientCertificate
      A certificate which will be used to encrypt the body text and attachment.
      .PARAMETER $Sender
      A string representing an e-mail address
      .PARAMETER $Subject
      A string representing the subject of a mail message
      .PARAMETER $Body
      A string representing the body text of a mail message
      .PARAMETER $Attachment
      An object representing an array of files.
      .PARAMETER $EncryptionAlgorithm
      A string specifying the encryption algorithm to be used for encyption, defaults to "1.2.840.113549.3.7" (3DES)
      "1.2.840.113549.3.2" # RC2 Key length 40/64/128
      "1.3.14.3.2.7" #DES
      "1.2.840.113549.3.7" #3DES
      "2.16.840.1.101.3.4.1.2" #AES-128
      "2.16.840.1.101.3.4.1.22" #AES-192
      "2.16.840.1.101.3.4.1.42" #AES-256
      .PARAMETER $KeyLength
      An integer specifying the key length to be used in case of using RC2, defaults to 128
      Valid values are [40,64,128]
  #>

  param
  (
    [parameter(Mandatory=$true)][PSObject]$MailServer,
    [parameter(Mandatory=$true)][Security.Cryptography.X509Certificates.X509Certificate2]$RecipientCertificate,
    [parameter(Mandatory=$true)][string]$Sender,
    [string]$Subject = $null,
    [string]$Body = $null,
    [IO.FileInfo[]]$Attachments = $null,
    [string]$EncryptionAlgorithm = '3des',
    [ValidateSet(40,64,128)][int]$KeyLength = 128
  )

  $EncryptionAlgorithm = Get-Oid -Algorithm $EncryptionAlgorithm    
  
  $SendEncryptedMail = $False
    
  $MIMEMessage = New-MimeMessage -Body $Body -FileList $Attachments
  $EncryptedBytes = New-EncryptedContent -MIMEMessage $MIMEMessage -Certificate $RecipientCertificate -EncryptionAlgorithm $EncryptionAlgorithm -KeyLength $KeyLength
    
  $MemoryStream = New-Object -TypeName System.IO.MemoryStream -ArgumentList @(,$EncryptedBytes) 
    
  $ContentType = New-Object -TypeName System.Net.Mime.ContentType -ArgumentList 'application/pkcs7-mime; name="smime.p7m"; smime-type=enveloped-data'
    
  $AlternateView = New-Object -TypeName System.Net.Mail.AlternateView -ArgumentList ($MemoryStream, $ContentType) 

  $Recipient = $RecipientCertificate.GetNameInfo('EmailName', $False)

  $Message = New-Object -TypeName System.Net.Mail.MailMessage
  $Message.To.Add($Recipient) 
  $Message.From = $Sender
  $Message.SubjectEncoding = [Text.Encoding]::UTF8
  $Message.Subject = $Subject
  $Message.Headers.Add('Return-Path', "<$Sender>")
  $Message.Headers.Add('X-Secured-By','Powershell S/MIME Toolkit v1.0') 
  $Message.AlternateViews.Add($AlternateView)

  $SendEncryptedMail = Send-SMIMEMail -MailServer $MailServer -Message $Message
  Return $SendEncryptedMail
}


function Send-SignedMail
{
  <#
      .SYNOPSIS
      Send an encrypted mail message through a mail server
      .DESCRIPTION
      This function sends an encrypted message through a mail server using a specified certificate.
      The function returns $True when successfull otherwise $False
      .EXAMPLE
      Call this function with a mail server object, a certificate of the recipient, a string containing the sender mail address, a string with the subject text, a string containing the body text,
      an attachment representing a file.
      Send-EncryptedMail mailserver certificate "example@example.com" "subject text" "body text" file
      .PARAMETER $MailServer
      An object representing a mail server
      .PARAMETER $Recipient
      A string representing an e-mail address
      .PARAMETER $SenderCertificate
      A certificate which will be used to sign the body text and attachment.
      .PARAMETER $Subject
      A string representing the subject of a mail message
      .PARAMETER $Body
      A string representing the body text of a mail message
      .PARAMETER $Attachment
      An object representing an array of files.
      .PARAMETER $EndCertOnly
      Set to $True to avoid issues with building up the certificate chain to the root certificate, defaults to $False
      .PARAMETER $Detached
      If set to $True the signatue will be detached so non smime capable clients can still read the message.
      .PARAMETER $DigestAlgorithm
      A string specifying which digest algorithm to use, defaults to "1.3.14.3.2.26" (SHA-1)
      "1.2.840.113549.2.5" #md5
      "1.3.14.3.2.26" #SHA-1
      "2.16.840.1.101.3.4.2.1" #SHA-256
      "2.16.840.1.101.3.4.2.2" #SHA-384
      "2.16.840.1.101.3.4.2.3" #SHA-512
      .PARAMETER $EnhancedProtection
      Turn ON or OFF enhanced protection. When ON the recipient and subject will be added as signed attributes to the signature.
  #>

  param
  (
    [parameter(Mandatory=$true)][PSObject]$MailServer,
    [parameter(Mandatory=$true)][string]$Recipient,
    [parameter(Mandatory=$true)][Security.Cryptography.X509Certificates.X509Certificate2]$SenderCertificate,
    [string]$Subject = $null,
    [string]$Body = $null,
    [IO.FileInfo[]]$Attachments = $null,
    [bool]$EndCertOnly = $False,
    [bool]$Detached = $True,
    [string]$DigestAlgorithm = 'sha1',
    [bool]$EnhancedProtection = $True
  )

  $DigestAlgorithm = Get-Oid -Algorithm $DigestAlgorithm
  
  $SendSignedMail = $False
    
  [String]$Boundary = 'boundary-2-' + [guid]::NewGuid()
    
  $MIMEMessage = New-MimeMessage -Body $Body -FileList $Attachments
  $SignedBytes = New-SignedContent -MIMEMessage $MIMEMessage -Certificate $SenderCertificate -EndCertOnly $EndCertOnly -Detached $Detached -Boundary $Boundary -DigestAlgorithm $DigestAlgorithm -EnhancedProtection $EnhancedProtection -Recipient $Recipient -Subject $Subject

  $MemoryStream = New-Object -TypeName System.IO.MemoryStream -ArgumentList @(,$SignedBytes)
    
  If ($Detached -eq $True)
  {
    $MicAlg = New-MicAlg -DigestAlgorithm $DigestAlgorithm
    $ContentType = New-Object -TypeName System.Net.Mime.ContentType -ArgumentList "multipart/signed; boundary=`"$Boundary`"; protocol=`"application/pkcs7-signature`"; micalg=$MicAlg"
  }
  Else
  {
    $ContentType = New-Object -TypeName System.Net.Mime.ContentType -ArgumentList 'application/pkcs7-mime; smime-type=signed-data; name="smime.p7m"'
  }
    
  $AlternateView = New-Object -TypeName System.Net.Mail.AlternateView -ArgumentList ($MemoryStream, $ContentType) 
    
  If ($Detached -eq $True)
  {
    $AlternateView.TransferEncoding = '2'
  }
  Else
  {
    $AlternateView.TransferEncoding = '1'
  }
    
  $Sender = $SenderCertificate.GetNameInfo('EmailName', $False)

  $Message = New-Object -TypeName System.Net.Mail.MailMessage
  $Message.To.Add("<$Recipient>") 
  $Message.From = "<$Sender>"
  $Message.SubjectEncoding = [Text.Encoding]::UTF8
  $Message.Subject = $Subject
  $Message.Headers.Add('Return-Path', "<$Sender>")
  $Message.Headers.Add('X-Secured-By','Powershell S/MIME Toolkit v1.0') 
  $Message.AlternateViews.Add($AlternateView)

  $SendSignedMail = Send-SMIMEMail -MailServer $MailServer -Message $Message
  Return $SendSignedMail
}


function Send-SignedAndEncryptedMail
{
  <#
      .SYNOPSIS
      Send a signed and encrypted mail message through a mail server
      .DESCRIPTION
      This function sends an encrypted message through a mail server using a specified certificate.
      The function returns $True when successfull otherwise $False
      .EXAMPLE
      Call this function with a mail server object, a certificate of the recipient, a certificate of the sender, a string with the subject text, a string containing the body text,
      an attachment representing a file.
      Send-SignedAndEncryptedMail mailserver certificate certificate "subject text" "body text" file
      .PARAMETER $MailServer
      An object representing a mail server
      .PARAMETER $RecipientCertificate
      A certificate which will be used to encrypt the body text and attachment.
      .PARAMETER $SenderCertificate
      A certificate which will be used to sign the body text and attachment.
      .PARAMETER $Subject
      A string representing the subject of a mail message
      .PARAMETER $Body
      A string representing the body text of a mail message
      .PARAMETER $Attachment
      An object representing an array of files.
      .PARAMETER $EndCertOnly
      Set to $True to avoid issues with building up the certificate chain to the root certificate, defaults to $False
      .PARAMETER $Detached
      If set to $True the signatue will be detached so non smime capable clients can still read the message.
      .PARAMETER $DigestAlgorithm
      A string specifying which digest algorithm to use, defaults to "1.3.14.3.2.26" (SHA-1)
      "1.2.840.113549.2.5" #md5
      "1.3.14.3.2.26" #SHA-1
      "2.16.840.1.101.3.4.2.1" #SHA-256
      "2.16.840.1.101.3.4.2.2" #SHA-384
      "2.16.840.1.101.3.4.2.3" #SHA-512
      .PARAMETER $EncryptionAlgorithm
      A string specifying the encryption algorithm to be used for encyption, defaults to "1.2.840.113549.3.7" (3DES)
      "1.2.840.113549.3.2" # RC2 Key length 40/64/128
      "1.3.14.3.2.7" #DES
      "1.2.840.113549.3.7" #3DES
      "2.16.840.1.101.3.4.1.2" #AES-128
      "2.16.840.1.101.3.4.1.22" #AES-192
      "2.16.840.1.101.3.4.1.42" #AES-256
      .PARAMETER $KeyLength
      An integer specifying the key length to be used in case of using RC2 , defaults to 128
      Valid values are [40,64,128]
      .PARAMETER $EnhancedProtection
      Turn ON or OFF enhanced protection. When ON the recipient and subject will be added as signed attributes to the signature.
  #>

  param
  (
    [parameter(Mandatory=$true)][PSObject]$MailServer,
    [parameter(Mandatory=$true)][Security.Cryptography.X509Certificates.X509Certificate2]$RecipientCertificate,
    [parameter(Mandatory=$true)][Security.Cryptography.X509Certificates.X509Certificate2]$SenderCertificate,
    [string]$Subject = $null,
    [string]$Body = $null,
    [IO.FileInfo[]]$Attachments = $null,
    [bool]$EndCertOnly = $False,
    [bool]$Detached = $True,
    [string]$DigestAlgorithm = 'sha1',
    [string]$EncryptionAlgorithm = '3des',
    [ValidateSet(40,64,128)][int]$KeyLength = 128,
    [bool]$EnhancedProtection = $True
  )

  $DigestAlgorithm = Get-Oid -Algorithm $DigestAlgorithm
  $EncryptionAlgorithm = Get-Oid -Algorithm $EncryptionAlgorithm

  $SendSignedAndEncryptedMail = $False
    
  [String]$Boundary = 'boundary-2-' + [guid]::NewGuid()
    
  $Recipient = $RecipientCertificate.GetNameInfo('EmailName', $False)
    
  $MIMEMessage = New-MimeMessage -Body $Body -FileList $Attachments
  $SignedBytes = New-SignedContent -MIMEMessage $MIMEMessage -Certificate $SenderCertificate -EndCertOnly $EndCertOnly -Detached $Detached -Boundary $Boundary -DigestAlgorithm $DigestAlgorithm -EnhancedProtection $EnhancedProtection -Recipient $Recipient -Subject $Subject

  $SignedB64String = [Convert]::ToBase64String($SignedBytes, [Base64FormattingOptions]::InsertLineBreaks)

  $MIMESigned = New-Object -TypeName system.Text.StringBuilder 
    
  If ($Detached -eq $True)
  {          
    $null = $MIMESigned.AppendLine('Content-Type: multipart/signed;')
    $null = $MIMESigned.AppendLine(" boundary=`"$Boundary`";")
    $MicAlg = New-MicAlg -DigestAlgorithm $DigestAlgorithm
    $null = $MIMESigned.AppendLine(" protocol=`"application/pkcs7-signature`"; micalg=$MicAlg")
    $null = $MIMESigned.AppendLine('Content-Transfer-Encoding: 7bit')
    $null = $MIMESigned.AppendLine()
    $Body = [Text.Encoding]::ASCII.GetString($SignedBytes)
    $null = $MIMESigned.Append("$Body")
    $null = $MIMESigned.AppendLine()
      
  }
  Else
  {
    $null = $MIMESigned.AppendLine('Content-Type: application/pkcs7-mime; name="smime.p7m"; smime-type=signed-data')
    $null = $MIMESigned.AppendLine('Content-Transfer-Encoding: base64')
    $null = $MIMESigned.AppendLine('Content-Disposition: attachment; filename="smime.p7m"')
    $null = $MIMESigned.AppendLine()
    $null = $MIMESigned.Append($SignedB64String)
    $null = $MIMESigned.AppendLine()
  }

  $EncryptedBytes = New-EncryptedContent -MIMEMessage $MIMESigned -Certificate $RecipientCertificate -EncryptionAlgorithm $EncryptionAlgorithm -KeyLength $KeyLength
    
  $MemoryStream = New-Object -TypeName System.IO.MemoryStream -ArgumentList @(,$EncryptedBytes) 
    
  $ContentType = New-Object -TypeName System.Net.Mime.ContentType -ArgumentList 'application/pkcs7-mime; name="smime.p7m"; smime-type=enveloped-data'
    
  $AlternateView = New-Object -TypeName System.Net.Mail.AlternateView -ArgumentList ($MemoryStream, $ContentType)

  $Sender = $SenderCertificate.GetNameInfo('EmailName', $False)
   
  $Message = New-Object -TypeName System.Net.Mail.MailMessage
  $Message.To.Add($Recipient) 
  $Message.From = $Sender
  $Message.SubjectEncoding = [Text.Encoding]::UTF8
  $Message.Subject = $Subject
  $Message.Headers.Add('Return-Path', "<$Sender>")
  $Message.Headers.Add('Content-Disposition', 'attachment; filename="smime.p7m"')
  $Message.Headers.Add('X-Secured-By','Powershell S/MIME Toolkit v1.0') 
  $Message.AlternateViews.Add($AlternateView)

  $SendSignedAndEncryptedMail = Send-SMIMEMail -MailServer $MailServer -Message $Message
  Return $SendSignedAndEncryptedMail
}

# example

# show license
$null = Show-License

# enter your SMTP servername or IP address:
$FQDN = '<server>'
# enter the port to connect to (defaults: 25):
$Port = '25'
# use STARTTLS to switch to TLS/SSL connection:
$STARTTLS = $True
# should the server certificate be validated:
$VerifyServerCertificate = $True

# enter the username to authenticatie with:
$Username = '<username>'
# enter the password used to authenticate:
$Password = '<pasword>'

# use 0 for testing
# Output = 0 -> save to eml file
# Output = 1 -> send to smtp server
# Output = 2 -> save to eml file and send to smtp server
$Output = 0

# create a new MailServerSettings object:
$MailServerDetails = New-MailServerSettings -FQDN $FQDN -Output $Output -Port $Port -STARTTLS $STARTTLS -VerifyServerCertificate $VerifyServerCertificate -Username $Username -Password $Password 

# select the certificate used for the sender (used for signing messages):
# normally you would use:
# $CertSenderFile = "$(Split-Path -Path $script:MyInvocation.MyCommand.Path)\certificates\personone.pfx"
# $CertSenderPassword = 'password'
# $CertSender = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList ($CertSenderFile, $CertSenderPassword)
#
# in this example we use this:
$CertSenderBase64 = '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
  TFVFQk9YLmlwdjZ4cy5ubF9Sb290LVNlY3VyZS1DQSgxKS5jcnQwKQYIKwYBBQUHMAGGHWh0dHA6
  Ly9ibHVlYm94LmlwdjZ4cy5ubC9vY3NwMEUGA1UdEQQ+MDygJAYKKwYBBAGCNxQCA6AWDBRwZXJz
  b24ub25lQGlwdjZ4cy5ubIEUcGVyc29uLm9uZUBpcHY2eHMubmwwDQYJKoZIhvcNAQELBQADggIB
  AENF8WBDzyNY6ttp0JgFzriqVJNIvSM0qzrmH2hXlEni4wEJ5n0S7ct1KdtiHlREDbSyWzDQ7Js3
  IhtwJ4DVZ8lEKzeSaZ44V39Da/0Gaq2+SikdqE68+fDsl+gf50Wys62jhBktNDpOvQ9p6At7gGDj
  NvaXrWzkhvL61b3gNem25DABrHHVbvKtiHoX2EonYjtMGtq2R3evb3XN00KZ9qcSV9gwryGjyQcv
  rJe80YgN7MXi2OnBs4no8YJjqjNQc1lMWJC0XONM2k7oy+9vyJg/FJvBd2fTzQeQJCZte1NAlP3y
  i91JbNWrDXMqeKpYOZTQR+ifcjED+YlVRsTQwaLXC2SPNAIxpVK0ohq4PwYffYMl6zfs5iDI7eUZ
  8xRw/41UfR9Ex1wmHZc2kjz7taqKxzO5r2wvHbDsBychVdtqDoTFtLpvhi9//QRzCWxnOA+pLsz0
  94ZbVPbYIFjhlm8/7b0aqhBeK9RfWIt2RUF11QyikwgNlnEVxnkAbNbuZv5lLPbDUrSq28Odrj+/
  hscGQAcmOaenGPvvV1+3CVz/tygxr6GqA2NNdtn82y0IYusSUeo3Unmzqn9QZ/GRASR1XjGD011k
  5cqPRACZMzb4ew418Jy6sDhVWWJqGA+TeXw88pnrdKy0MPpzYE3MS63+GMSmJ1FbmVHyFSP/Aywt
  MYIBFjATBgkqhkiG9w0BCRUxBgQEAQAAADAyBgorBgEEAYI3EQNHMSQEIm8AdgBoAGIAbwB4AC4A
  aQBwAHYANgB4AHMALgBuAGwAAAAwgcoGCisGAQQBgjcRA1cxgbsEgbgAAAAAAAAAAAIAAAAAAAAA
  AgAAAGwAZABhAHAAOgAAAHsARQA0ADkANwA2ADQAQwAzAC0ANgAxADcAMQAtADQAOQAzADQALQBB
  ADkAMQA4AC0ANQA1ADMAMgA5AEYAQgA3ADAANAA4ADkAfQAAAEIATABVAEUAQgBPAFgALgBpAHAA
  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'

$CertSenderBytes = [Convert]::FromBase64String($CertSenderBase64)
$CertSenderPassword = 'password'
$CertSender = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList ($CertSenderBytes, $CertSenderPassword)

# get the From address from the certificate
$fromAddress = $CertSender.GetNameInfo('EmailName', $False)

# select the certificate used for the recipient (used for encrypting messages):
# normally you would use:
# $CertRecipientFile = "$(Split-Path -Path $script:MyInvocation.MyCommand.Path)\certificates\persontwo.cer"
# $CertRecipient = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $CertRecipientFile
#
# in this example we use this:
$CertRecipientBase64 = 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlHdVRDQ0JLR2dBd0lCQWdJS0pIcTM2QUFC
  QUFBQmRqQU5CZ2txaGtpRzl3MEJBUXNGQURCRk1SSXdFQVlLDQpDWkltaVpQeUxHUUJHUllDYm13
  eEZqQVVCZ29Ka2lhSmsvSXNaQUVaRmdacGNIWTJlSE14RnpBVkJnTlZCQU1UDQpEbEp2YjNRdFUy
  VmpkWEpsTFVOQk1CNFhEVEl3TURNeE9URXpOVEl6TmxvWERUTXdNRE14TnpFek5USXpObG93DQpn
  WW94RWpBUUJnb0praWFKay9Jc1pBRVpGZ0p1YkRFV01CUUdDZ21TSm9tVDhpeGtBUmtXQm1sd2Rq
  WjRjekVQDQpNQTBHQTFVRUN4TUdhWEIyTm5oek1SRXdEd1lEVlFRTEV3aGxlSFJsY201aGJERVRN
  QkVHQTFVRUF4TUtVR1Z5DQpjMjl1SUZSM2J6RWpNQ0VHQ1NxR1NJYjNEUUVKQVJZVWNHVnljMjl1
  TG5SM2IwQnBjSFkyZUhNdWJtd3dnZ0VpDQpNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dF
  S0FvSUJBUURQYVo5TGZ2VEhIUWVUUnpDa1BxNitqdkoyDQpnd2REQ1FwWm5JY05sRG5IeFhRblJS
  R296VE5sNVlNa01nMkJTNm11TjFZOU5la3FYSGVFUkNobEVyUkxCUWFWDQpjVE1jWllxVVRWM3FF
  MFY3UWVtNkkrM210MGozTXlNczJqTElSZy9NOTMrWW9jVTlNV1l4a0JRdmJuY0Y1L3BjDQplbUdw
  Qm0rS1VlVVNsNDlCbDFQTmhQSG50bm1WbDA0R0FMd2w5bWtHMU8ydC8wTURrcnZ2RG9yN3k4QXhB
  ano3DQpwenZ1T0UrSkZLTjJISS91SFJ3NmNxemZ1UjB3WFpUZ3Y1Y0FlSUwySU1xQWlkUHVxeWdS
  TE1tbVFsd2dUY1BqDQpZTXlNbHFJUnE0eExUQUJRYk9sMEZHci9Bb0xFbXVodVFhRFozV3lNM3Yr
  T2pqeVltTmQ4K3dzUlhYWHpBZ01CDQpBQUdqZ2dKak1JSUNYekErQmdrckJnRUVBWUkzRlFjRU1U
  QXZCaWNyQmdFRUFZSTNGUWlCcjVZY2hxM3VNb1NCDQptUldDajVrN2d2UDdQNEY0Z3V2T0M0SG5q
  QzBDQVdRQ0FRTXdLUVlEVlIwbEJDSXdJQVlJS3dZQkJRVUhBd0lHDQpDQ3NHQVFVRkJ3TUVCZ29y
  QmdFRUFZSTNDZ01FTUE0R0ExVWREd0VCL3dRRUF3SUZvREExQmdrckJnRUVBWUkzDQpGUW9FS0RB
  bU1Bb0dDQ3NHQVFVRkJ3TUNNQW9HQ0NzR0FRVUZCd01FTUF3R0Npc0dBUVFCZ2pjS0F3UXdSQVlK
  DQpLb1pJaHZjTkFRa1BCRGN3TlRBT0JnZ3Foa2lHOXcwREFnSUNBSUF3RGdZSUtvWklodmNOQXdR
  Q0FnQ0FNQWNHDQpCU3NPQXdJSE1Bb0dDQ3FHU0liM0RRTUhNQjBHQTFVZERnUVdCQlRJenZpYkVR
  dTRScVlVVE5qK0ozRFo4SEtkDQpiakFmQmdOVkhTTUVHREFXZ0JUaFk2V2MvbVVBZlJCWEcyYkZO
  K29kVG9rQTN6QkhCZ05WSFI4RVFEQStNRHlnDQpPcUE0aGpab2RIUndPaTh2WW14MVpXSnZlQzVw
  Y0hZMmVITXVibXd2UTJWeWRFVnVjbTlzYkM5U2IyOTBMVk5sDQpZM1Z5WlMxRFFTNWpjbXd3Z1pR
  R0NDc0dBUVVGQndFQkJJR0hNSUdFTUZjR0NDc0dBUVVGQnpBQ2hrdG9kSFJ3DQpPaTh2WW14MVpX
  SnZlQzVwY0hZMmVITXVibXd2UTJWeWRFVnVjbTlzYkM5Q1RGVkZRazlZTG1sd2RqWjRjeTV1DQpi
  RjlTYjI5MExWTmxZM1Z5WlMxRFFTZ3hLUzVqY25Rd0tRWUlLd1lCQlFVSE1BR0dIV2gwZEhBNkx5
  OWliSFZsDQpZbTk0TG1sd2RqWjRjeTV1YkM5dlkzTndNRVVHQTFVZEVRUStNRHlnSkFZS0t3WUJC
  QUdDTnhRQ0E2QVdEQlJ3DQpaWEp6YjI0dWRIZHZRR2x3ZGpaNGN5NXViSUVVY0dWeWMyOXVMblIz
  YjBCcGNIWTJlSE11Ym13d0RRWUpLb1pJDQpodmNOQVFFTEJRQURnZ0lCQURTRnRndHNqamdSRm5q
  SGJCam1GV3ErRE94a0dkZWt4bTJRdjhsRHJZbFRERWgxDQpBSEVoZ2Y0dkJNMTVhbUFPaGZIS3d6
  TlA4dURZSmU2ejg2dzE0ZHhub3AxMEVnaGVWODhnS1I4ZE9YQk9WTmpODQpJTDVQbHNjVUh6N3JS
  OWQ3UkJLZ2g1K0VpODRGUElReU1UUW9mMVIzUlJPV1l4anBvSWErbTRrWXFQNWs0K3JVDQpaeFFK
  NGE1QUhJSE5OWDU3cXltbkorbkZOSDZFMUxFbzh1am01bnQzUFB1STFzMm9PNTZVMk5tYllwV1pB
  YnNkDQpXOGJEaWxPcHhkK0RwNzJsTTliYndZSVQzSW9EdzVTcXFIcFBBZS90SENxNjh6OE8wUzZx
  cFBmVUo4eW1GU0NaDQpYYWhQZCtNc1JMMnJaUXYzQlA2QUd1eDFhL0tUcDZwano5cEE0VmlSMzZi
  YmJFbi8yWnNPeVdxS1hNbE9sWXlsDQo4dGJiaXh3RnpZOVFmRjI2Q2l0a3BxcURmUzB5Yk11UWJW
  NnZyTVY5blNFaGwvN3RWYmNXZkEyeTdtK0ZPTHc5DQo5eHRTVCtjb2FjVjQzek5WYWp6L2dMWGNR
  ZDk1eXhaTk5wTGVGYzEzMHJlcUxESXhLUm4vWFBxMmUwZWJpQW8vDQpyTFI3TnowbThqMitKbnVs
  V2RmajEyV1l4ZFl5azJTdGVMTVVaTDlSSWxJRzNxUTNndUNTeWI3bk1GQUhtV0pODQpEVDF5VTFB
  Y3JVVmtBRng2Z1c0eStMR1FlWkw0TjNhSFJoMWovQ1J0bEF2bUJvK01zMTRhSFEyRks1NGxpVWUw
  DQp4eFVSSmg2Ry9paDNldUR3dHN5SWo3M2oxYlJzM1FVV3dZTmdtekx1K21QeGdPa0FSZFZpODlB
  SzFtejgNCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0NCg==
'

$CertRecipientBytes = [Convert]::FromBase64String($CertRecipientBase64)
$CertRecipient = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList ($CertRecipientBytes, $null)

# get the To address from the certificate
$toAddress = $CertRecipient.GetNameInfo('EmailName', $False)

# security settings:
# should the signed message be detached (readable for non s/mime clients):
$Detached = $True
# encryption algorithm to be used:
# valid values are: 'rc2','des','3des','aes128','aes192','aes256'
$EncryptionAlgorithm = 'aes256'
# when using encryption algorith 'rc2' you can specify a key length:
# valid values are: 40, 64, 128
$KeyLength = 128
# signing algorithm to be used:
# valid values are: 'md5','sha1','sha256','sha384','sha512'
$DigestAlgorithm = 'sha256'
# should the whole certificate chain be verified for the signing certificate:
# set this to $True if you do not have the root certificate (and/or intermediate certificates) of the signing certificate installed.
$EndCertOnly = $True
# if you want to use enhanced protection for signing the message:
# this adds signed attributes to the signed part
# it adds the recipient address to Pkcs9DocumentName
# and adds the subject to Pkcs9DocumentDescription
# this has no effect on most mail reader programs
$EnhancedProtection = $True

# the text of the body:
$Bodytext = "This is the body of the mail message. ©`r`nBye...`r`n"

# attchments you want to include:
# you can use wildcard to select multiple attachment
# set to $null if you do not want to include attachments
# normally you can use:
# $Attachments = get-item -Path "$(Split-Path -Path $script:MyInvocation.MyCommand.Path)\attachments\*"
#
# in this example we do not include attachments
$Attachments = $null

# set the subject and send using encryption and signing:
$Subject = '© Signed and encrypted ©'
$Result = Send-SignedAndEncryptedMail -MailServer $mailserverdetails -RecipientCertificate $certrecipient -SenderCertificate $certsender -Subject $subject -Body $bodytext -EncryptionAlgorithm $EncryptionAlgorithm -KeyLength $KeyLength -DigestAlgorithm $DigestAlgorithm -EndCertOnly $EndCertOnly -Detached $Detached -Attachments $attachments -EnhancedProtection $EnhancedProtection
$Result

# set the subject and send using encryption only:
$Subject = '© Encrypted ©'
$Result = Send-EncryptedMail -MailServer $mailserverdetails -RecipientCertificate $certrecipient -Sender $fromAddress -Subject $subject -Body $bodytext -EncryptionAlgorithm $EncryptionAlgorithm -KeyLength $KeyLength -Attachments $attachments
$Result

# set the subject and send using signing only:
$Subject = '© Signed ©'
$Result = Send-SignedMail -MailServer $mailserverdetails -Recipient $toAddress -SenderCertificate $certsender -Subject $subject -Body $bodytext -DigestAlgorithm $DigestAlgorithm -EndCertOnly $EndCertOnly -Detached $Detached -Attachments $attachments -EnhancedProtection $EnhancedProtection
$Result