Skip to content
37 changes: 21 additions & 16 deletions Build/Build-Module.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
Invoke-ModuleBuild -ModuleName 'PSWriteHTML' {
param(
[ValidateSet('Manifest', 'Build', 'Publish')]
[string] $ConfigurationGateMode = 'Build',

[bool] $SignModule = ($ConfigurationGateMode -eq 'Publish'),

[string] $PowerShellGalleryApiKeyPath = 'C:\Support\Important\PowerShellGalleryAPI.txt',

[string] $GitHubApiKeyPath = 'C:\Support\Important\GitHubAPI.txt'
)

Import-Module PSPublishModule -Force -ErrorAction Stop

Build-Module -ModuleName 'PSWriteHTML' {
# Usual defaults as per standard module
$Manifest = [ordered] @{
ModuleVersion = '1.X.0'
Expand Down Expand Up @@ -27,6 +40,7 @@
'Microsoft.PowerShell.Utility'
# this is optional, and checked for existance in the source codes directly
'PSParseHTML'
'Mailozaurr'
) -IgnoreFunctionName 'Select-Unique', 'Compare-TwoArrays', 'IsNumeric', 'IsOfType', 'Format-HTML', 'Optimize-HTML' # those functions are internal within private function

$ConfigurationFormat = [ordered] @{
Expand Down Expand Up @@ -70,23 +84,13 @@
# when creating PSD1 use special style without comments and with only required parameters
New-ConfigurationFormat -ApplyTo 'DefaultPSD1', 'OnMergePSD1' -PSD1Style 'Minimal'
# configuration for documentation, at the same time it enables documentation processing
$documentationConfiguration = @{
Enable = $true
PathReadme = 'Docs\Readme.md'
Path = 'Docs'
}

if ((Get-Command New-ConfigurationDocumentation).Parameters.ContainsKey('SyncExternalHelpToProjectRoot')) {
$documentationConfiguration.SyncExternalHelpToProjectRoot = $true
}

New-ConfigurationDocumentation @documentationConfiguration
New-ConfigurationDocumentation -Enable -PathReadme 'Docs\Readme.md' -Path 'Docs' -SyncExternalHelpToProjectRoot

New-ConfigurationImportModule -ImportSelf

$newConfigurationBuildSplat = @{
Enable = $true
SignModule = $true
SignModule = $SignModule
MergeModuleOnBuild = $true
MergeFunctionsFromApprovedModules = $true
CertificateThumbprint = '483292C9E317AA13B07BB7A96AE9D1A5ED9E7703'
Expand All @@ -100,7 +104,8 @@
New-ConfigurationArtefact -Type Unpacked -Enable -Path "$PSScriptRoot\..\Artefacts\Unpacked" -AddRequiredModules
New-ConfigurationArtefact -Type Packed -Enable -Path "$PSScriptRoot\..\Artefacts\Packed" -ArtefactName '<ModuleName>.v<ModuleVersion>.zip'

# options for publishing to github/psgallery
#New-ConfigurationPublish -Type PowerShellGallery -FilePath 'C:\Support\Important\PowerShellGalleryAPI.txt' -Enabled:$true
#New-ConfigurationPublish -Type GitHub -FilePath 'C:\Support\Important\GitHubAPI.txt' -UserName 'EvotecIT' -Enabled:$true #-GenerateReleaseNotes
New-ConfigurationPublish -Type PowerShellGallery -FilePath $PowerShellGalleryApiKeyPath -Enabled:$false -UseAsDependencyVersionSource
New-ConfigurationPublish -Type GitHub -FilePath $GitHubApiKeyPath -UserName 'EvotecIT' -RepositoryName 'PSWriteHTML' -Enabled:$false -GenerateReleaseNotes
Comment thread
PrzemyslawKlys marked this conversation as resolved.

New-ConfigurationGate -Mode $ConfigurationGateMode
} -ExitCode
9 changes: 7 additions & 2 deletions PSWriteHTML.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ try {
Write-Color 'Running tests...' -Color Yellow
Write-Color

$result = Invoke-Pester -Script $PSScriptRoot\Tests -Verbose -PassThru
$InvokePesterCommand = Get-Command Invoke-Pester
if ($InvokePesterCommand.Parameters.ContainsKey('Path')) {
$result = Invoke-Pester -Path $PSScriptRoot\Tests -Output Detailed -PassThru
} else {
$result = Invoke-Pester -Script $PSScriptRoot\Tests -Verbose -PassThru
}

if ($result.FailedCount -gt 0) {
throw "$($result.FailedCount) tests failed."
}
}
195 changes: 195 additions & 0 deletions Private/Invoke-PSWriteHTMLMailozaurr.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
function Invoke-PSWriteHTMLMailozaurr {
<#
.SYNOPSIS
Maps the legacy PSWriteHTML email contract to Mailozaurr without requiring the module.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)][System.Collections.IDictionary] $EmailParameters,
[Parameter(Mandatory)][AllowEmptyString()][string] $Body,
[System.Collections.Generic.List[string]] $Attachment,
[System.Collections.IDictionary] $AdditionalParameters,
[switch] $WhatIf
)

$Command = Get-Command -Name 'Mailozaurr\Send-EmailMessage' -ErrorAction SilentlyContinue
if (-not $Command) {
$Candidate = Get-Command -Name 'Send-EmailMessage' -ErrorAction SilentlyContinue
if ($Candidate -and ($Candidate.ModuleName -eq 'Mailozaurr' -or $Candidate.Source -eq 'Mailozaurr')) {
$Command = $Candidate
}
}
Comment thread
PrzemyslawKlys marked this conversation as resolved.
if (-not $Command) {
throw "Email -UseMailozaurr requires the Mailozaurr module and its Send-EmailMessage command to be available."
}

$Parameters = [ordered] @{}
$CommonMappings = [ordered] @{
From = 'From'
To = 'To'
CC = 'Cc'
BCC = 'Bcc'
ReplyTo = 'ReplyTo'
Subject = 'Subject'
Priority = 'Priority'
}
foreach ($SourceName in $CommonMappings.Keys) {
$Value = $EmailParameters[$SourceName]
if ($null -ne $Value -and -not ($Value -is [string] -and [string]::IsNullOrWhiteSpace($Value))) {
$Parameters[$CommonMappings[$SourceName]] = $Value
}
}

$UseSmtpTransport = $true
$NonSmtpSelectors = @('Graph', 'MgGraphRequest', 'SendGrid', 'EmailProvider')
$SmtpAuthenticationParameters = @('Credential', 'Username', 'Password', 'UseDefaultCredentials', 'OAuth2', 'AsSecureString')
$SmtpOnlyParameters = @(
'Server', 'SmtpServer', 'Port', 'Encoding',
'DeliveryNotificationOption', 'DeliveryStatusNotificationType',
'Username', 'Password', 'AuthenticationMechanism', 'SecureSocketOptions', 'UseSsl',
'SkipCertificateRevocation', 'SkipCertificateValidation', 'SkipCertificateValidatation',
'Timeout', 'MimeMessagePath', 'LocalDomain', 'UseDefaultCredentials',
'SignOrEncrypt', 'CertificatePath', 'CertificatePassword',
'CertificatePasswordAsSecureString', 'CertificateThumbprint', 'Certificate',
'PublicKeyPath', 'PrivateKeyPath', 'PrivateKeyPassword',
'PrivateKeyPasswordAsSecureString', 'OAuth2', 'oAuth', 'AsSecureString'
)
$IsParameterEnabled = {
param($Value)

if ($Value -is [System.Management.Automation.SwitchParameter]) {
return $Value.IsPresent
}
if ($Value -is [bool]) {
return $Value
}
if ($Value -is [string]) {
return -not [string]::IsNullOrWhiteSpace($Value)
}
return $null -ne $Value
}
if ($AdditionalParameters) {
foreach ($Key in $AdditionalParameters.Keys) {
$SelectorName = [string] $Key
if ($NonSmtpSelectors -notcontains $SelectorName) {
continue
}
$SelectorValue = $AdditionalParameters[$Key]
if (& $IsParameterEnabled $SelectorValue) {
$UseSmtpTransport = $false
break
}
}
}

if ($UseSmtpTransport) {
$ExplicitSmtpAuthenticationParameter = $null
$AdditionalUseDefaultCredentialsSpecified = $false
$AdditionalAsSecureStringSpecified = $false
if ($AdditionalParameters) {
foreach ($Key in $AdditionalParameters.Keys) {
if ([string]::Equals([string] $Key, 'AsSecureString', [System.StringComparison]::OrdinalIgnoreCase)) {
$Value = $AdditionalParameters[$Key]
if ($Value -is [bool] -or $Value -is [System.Management.Automation.SwitchParameter]) {
$AdditionalAsSecureStringSpecified = $true
break
}
}
}
foreach ($AuthenticationParameter in @('Credential', 'Password', 'UseDefaultCredentials')) {
foreach ($Key in $AdditionalParameters.Keys) {
if ([string]::Equals([string] $Key, $AuthenticationParameter, [System.StringComparison]::OrdinalIgnoreCase)) {
if ($AuthenticationParameter -eq 'UseDefaultCredentials') {
$Value = $AdditionalParameters[$Key]
if ($Value -is [bool] -or $Value -is [System.Management.Automation.SwitchParameter]) {
$AdditionalUseDefaultCredentialsSpecified = $true
}
}
if (& $IsParameterEnabled $AdditionalParameters[$Key]) {
$ExplicitSmtpAuthenticationParameter = $AuthenticationParameter
break
}
}
}
if ($ExplicitSmtpAuthenticationParameter) {
break
}
}
}
$LegacyDefaultCredentialsEffective = ([bool] $EmailParameters.UseDefaultCredentials) -and
-not $AdditionalUseDefaultCredentialsSpecified -and
-not $ExplicitSmtpAuthenticationParameter
$SmtpPasswordReplacementParameter = if ($ExplicitSmtpAuthenticationParameter) {
$ExplicitSmtpAuthenticationParameter
} elseif ($LegacyDefaultCredentialsEffective) {
'UseDefaultCredentials'
} else {
$null
}
if ($EmailParameters.PasswordFromFile -and -not $SmtpPasswordReplacementParameter) {
throw "Email -UseMailozaurr does not map the legacy -PasswordFromFile behavior for SMTP. Pass Credential or provider authentication through -MailozaurrParameters."
}

$SmtpMappings = [ordered] @{
Server = 'Server'
Login = 'Username'
Password = 'Password'
Port = 'Port'
}
foreach ($SourceName in $SmtpMappings.Keys) {
if (($SourceName -eq 'Password' -and ($EmailParameters.PasswordFromFile -or $SmtpPasswordReplacementParameter)) -or
($SourceName -eq 'Login' -and $SmtpPasswordReplacementParameter -in @('Credential', 'UseDefaultCredentials'))) {
continue
}
$Value = $EmailParameters[$SourceName]
if ($null -ne $Value -and -not ($Value -is [string] -and [string]::IsNullOrWhiteSpace($Value))) {
$Parameters[$SmtpMappings[$SourceName]] = $Value
}
}
if ($LegacyDefaultCredentialsEffective) {
$Parameters['UseDefaultCredentials'] = $true
}
if ($EmailParameters.EnableSSL) {
$Parameters['UseSsl'] = $true
}
if ($EmailParameters.PasswordAsSecure -and
-not $AdditionalAsSecureStringSpecified -and
$SmtpPasswordReplacementParameter -notin @('Credential', 'Password', 'UseDefaultCredentials')) {
$Parameters['AsSecureString'] = $true
}
if ($EmailParameters.DeliveryNotifications -and $EmailParameters.DeliveryNotifications -ne 'None') {
$Parameters['DeliveryNotificationOption'] = @($EmailParameters.DeliveryNotifications)
}
}

$Parameters['HTML'] = $Body
if ($Attachment -and $Attachment.Count -gt 0) {
$Parameters['Attachment'] = $Attachment.ToArray()
}
if ($AdditionalParameters) {
foreach ($Key in $AdditionalParameters.Keys) {
if ($SmtpOnlyParameters -contains [string] $Key -and -not $UseSmtpTransport) {
continue
Comment thread
PrzemyslawKlys marked this conversation as resolved.
}
if ([string]::Equals([string] $Key, 'AsSecureString', [System.StringComparison]::OrdinalIgnoreCase)) {
$Value = $AdditionalParameters[$Key]
$IsBooleanSwitchValue = $Value -is [bool] -or $Value -is [System.Management.Automation.SwitchParameter]
if (-not $IsBooleanSwitchValue -or -not (& $IsParameterEnabled $Value)) {
continue
}
}
if ($NonSmtpSelectors -contains [string] $Key -and -not (& $IsParameterEnabled $AdditionalParameters[$Key])) {
continue
}
if ($SmtpAuthenticationParameters -contains [string] $Key -and -not (& $IsParameterEnabled $AdditionalParameters[$Key])) {
continue
}
$Parameters[$Key] = $AdditionalParameters[$Key]
}
Comment thread
PrzemyslawKlys marked this conversation as resolved.
}
if ($WhatIf) {
$Parameters['WhatIf'] = $true
}

& $Command @Parameters
}
14 changes: 13 additions & 1 deletion Public/Email.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ function Email {
.PARAMETER OutputHTML
Switch parameter to output the email content as HTML.

.PARAMETER UseMailozaurr
Sends through Mailozaurr's Send-EmailMessage command when requested. Mailozaurr is resolved at runtime and is not a required PSWriteHTML dependency.

.PARAMETER MailozaurrParameters
Optional provider, authentication, retry, and transport parameters passed to Send-EmailMessage. Explicit values override parameters mapped from Email.

.PARAMETER WhatIf
Switch parameter to show what would happen without actually sending the email.

Expand Down Expand Up @@ -105,6 +111,8 @@ function Email {
[alias('Supress')][bool] $Suppress = $true,
[switch] $Online,
[switch] $OutputHTML,
[switch] $UseMailozaurr,
[System.Collections.IDictionary] $MailozaurrParameters,
[switch] $WhatIf
)
$Script:EmailSchema = [ordered]@{}
Expand Down Expand Up @@ -218,7 +226,11 @@ function Email {
}

#$MailSentTo = "To: $($ServerParameters.To -join ', '); CC: $($ServerParameters.CC -join ', '); BCC: $($ServerParameters.BCC -join ', ')".Trim()
$EmailOutput = Send-Email -EmailParameters $ServerParameters -Body $Body -Attachment $Attachments -WhatIf:$WhatIf
if ($UseMailozaurr) {
$EmailOutput = Invoke-PSWriteHTMLMailozaurr -EmailParameters $ServerParameters -Body $Body -Attachment $Attachments -AdditionalParameters $MailozaurrParameters -WhatIf:$WhatIf
} else {
$EmailOutput = Send-Email -EmailParameters $ServerParameters -Body $Body -Attachment $Attachments -WhatIf:$WhatIf
}
if (-not $Suppress) {
$EmailOutput
}
Expand Down
Loading
Loading