Here is a copy of the script I wrote. Its more complicated than it probably needs to be but I opted to extract the attachment and re-add it because I already had a script that was doing something similar.
The script is not deleting the original attachment, partially because I wasn't able to get it to work like I wanted, and partially because I thought it was a good means of testing it.
To use the script, you'll want to create a content filter rule with whatever conditions work for you, and that use the Run a process action. It should look something like the following:
RuleName=Rename Attachments
Enable=Yes
ThisRuleCondition=All
ProcessQueue=BOTH
Condition01=body|has attachment|AND|
Condition02=X-MDAEMON-DELIVER-TO|contains local account|AND|
Action01=run a program|"-1,0,0","C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file c:\Temp\RenameAttachments.ps1 $MESSAGEFILENAME$"
param(
[string]$MSGFileName = "C:\MDaemon\Queues\Bad\md5001000002293.msg"
)
################################################################################################################################
################################################################################################################################
## RemoveSpacesfromAttachmentNames ##
## September 10, 2023 ##
## Copyright MDaemon Technologies 2023 ##
## ##
## This script is designed to be ran by the content filter in MDaemon. It accepts the path to a message file as a parameter. ##
## The script extracts all attachments from the passed message and replaces all spaces in the filename with an underscore ##
## and then reattaches the file. ##
## ##
## MDaemon Technologies offers no warranty, provides no support, and is not responsible for any damages that may be arise ##
## from the use of this script. Use at your own risk. ##
## ##
################################################################################################################################
################################################################################################################################
clear
function Get-PrivateProfileString ($Path, $Category, $Key) {
#############################################################################
##
## Get-PrivateProfileString
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Retrieves an element from a standard .INI file
.EXAMPLE
Get-PrivateProfileString c:\windows\system32\tcpmon.ini `
"<Generic Network Card>" Name
Generic Network Card
#>
Set-StrictMode -Version Latest
## The signature of the Windows API that retrieves INI
## settings
$signature = @'
[DllImport("kernel32.dll")]
public static extern uint GetPrivateProfileString(
string lpAppName,
string lpKeyName,
string lpDefault,
StringBuilder lpReturnedString,
uint nSize,
string lpFileName);
'@
## Create a new type that lets us access the Windows API function
$type = Add-Type -MemberDefinition $signature `
-Name Win32Utils -Namespace GetPrivateProfileString `
-Using System.Text -PassThru
## The GetPrivateProfileString function needs a StringBuilder to hold
## its output. Create one, and then invoke the method
$builder = New-Object System.Text.StringBuilder 1024
$null = $type::GetPrivateProfileString($category,
$key, "", $builder, $builder.Capacity, $path)
## Return the output
$builder.ToString()
}
function GetRegistryValue($Key, $Name){
Log "Checking $Key"
if(Test-Path $Key)
{
$Value = (Get-ItemProperty $Key -Name $Name).$Name
if($Value -eq $null)
{
#This is included to clear the error that is set when the $Key exists but the $Name does not.
$Error.Clear()
}
}
if(!(Test-Path $Key) -or ($Value -eq $null) -or ($Value.Length -eq 0))
{
$Base = Split-Path (Split-Path $Key)
$Leaf2 = Split-Path $key -Leaf
$Leaf1 = Split-Path (Split-Path $key) -Leaf
$SysWownode = Join-Path (Join-Path (Join-Path $Base "Wow6432Node") $Leaf1) $Leaf2
if(Test-Path $SysWownode)
{
Log "The registry key value is empty or does not exist, checking $SysWownode."
$Value = (Get-ItemProperty $SysWowNode -Name $Name).$Name
if(($Value -eq $null) -or ($Value.Length -eq 0))
{
Log "We can't find the registry key values, the script will now stop."
exit
}
else
{
$Error.Clear()
return $Value
}
}
else
{
Log "We can't find the registry key values, the script will now stop."
exit
}
}
else
{
return $Value
}
}
function Log($string, $color){
if($string -ne $null)
{
if($global:LoggedScriptStarting -ne "Yes")
{
$global:LoggedScriptStarting = "Yes"
Log "Starting Script run at $MyDate.`r`n"
}
if ($color -eq $null)
{
$color = "White"
}
write-host $string -ForegroundColor $color
if ($LogFile -ne $null)
{
$string | out-file -Filepath $LogFile -append
}
}
}
function Load-EmlFile ($MSGFileName){
if($MSGFileName -eq "" -or (!(Test-Path $MSGFileName)))
{
Log "The File name, $MSGFileName, is empty or does not exist. This is a critical error. The script will now exit."
exit
}
$AdoDbStream = New-Object -ComObject ADODB.Stream
$AdoDbStream.Type = 1
$AdoDbStream.Open()
$AdoDbStream.LoadFromFile($MSGFileName)
$CdoMessage = New-Object -ComObject CDO.Message
$CdoMessage.DataSource.OpenObject($ADoDBStream,"_Stream")
$AdoDbStream.Close()
return $CdoMessage
}
function Save-EmlFile ($Message, $OutputFile) {
Log "Saving updated message to disk as $OutputFile"
$Message.GetStream().SaveToFile($OutputFile,2)
}
$MDINIPath = GetRegistryValue "HKLM:\SOFTWARE\Alt-N Technologies\MDaemon" "IniPath"
$TempPath = Get-PrivateProfileString $MDINIPath "Directories" "Temp"
$LogPath = Get-PrivateProfileString $MDINIPath "Directories" "LogFiles"
$CurrentDate = Get-Date
$LogFileDate = (Get-Date -Format yyyy-MM-dd)
$LogFile = join-path $LogPath "MDaemon-$LogFileDate-Compress-Attachments.log"
$OutputFile = $MSGFileName #"C:\MDaemon\Queues\Bad\pd35000003756.msg"
Log "The MDaemon INI path is: $MDINIPath"
Log "The Temp path is: $TempPath"
Log "The Log path is: $LogPath"
Log "Loading $MSGFileName"
$MSG = Load-EmlFile $MSGFileName
$MSGID = $MSG.Fields.Item("urn:schemas:mailheader:Message-ID").Value
Log "The message ID is $MSGID."
$Attachments = $MSG.Attachments
if($Attachments.Count -gt 0)
{
Log "There were $($Attachments.Count) attachments found."
$AttachPath = Join-Path $TempPath "RenameAttachments"
if(!(Test-Path $AttachPath))
{
Log "Creating $AttachPath."
New-Item $AttachPath -ItemType directory
}
Log "The attachment path is: $AttachPath"
Foreach($Attachment in $Attachments)
{
$AttachmentFileName = $($Attachment.FileName)
Log "Found an attachment named $AttachmentFileName"
if($AttachmentFileName.contains(" ")){
$FileAttachPath = Join-Path $AttachPath $AttachmentFileName
Log "Saving to $FileAttachPath."
$Attachment.SavetoFile($FileAttachPath)
$NewName = $AttachmentFileName.replace(" ","_")
Log "Renaming to $NewName"
Rename-Item -Path $FileAttachPath –NewName $NewName
$NewFileAttachPath = Join-Path $AttachPath $NewName
Log "Attaching $NewFileAttachPath to email."
$MSG.AddAttachment($NewFileAttachPath)
#Log "Removing $AttachmentFilename from $MSGFileName"
#$Attachment.Delete()
Remove-Item $NewFileAttachPath -Force -ErrorAction SilentlyContinue
}
}
Save-EmlFile $MSG $OutputFile
} else {
Log "No attachments were found in $MSGFileName with Message ID of $MSGID. Nothing is being done."
}
$CurrentDate = Get-Date
Log "`r`nEnding Script run at $CurrentDate."
Log "----------"