Changing the extension of an attachment with the content filter
-
When compressing an attachment with the content filter, the file name can be changed, but the extension is fixed to ZIP. I would like an option to change the extension. Also, when compressing an attachment, I would like to insert a message such as "Example: Attachment compressed" into the message body.
In some industries in Japan, it is customary to change the extension of compressed files from "ZIP to ZI_" before sending and receiving them.
-
Arron Staff
The only way to have the files be renamed to ZI_ will be by using a custom script and having the content filter execute it.
Below is a script that should be very close to what you need. Please be careful, I have done very limited testing with this script. I would reccomend that you test it thoroughly before using it in your production environment. The script creates its own log file called MDaemon-$DATE$-Compress-Attachments.log in the MDaemon\Logs directory.
In order to use the script you will first need to download and install 7-Zip on your MDaemon server. Then create a content filter rule like the following:
[Rule030]
RuleName=Compress Files in ZI_
Enable=Yes
ThisRuleCondition=All
ProcessQueue=BOTH
Condition01=body|has attachment|AND|
Action01=run a program|"-1,0,0","C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file c:\Temp\CompressAttachmentsRenameZIP.ps1 $MESSAGEFILENAME$"You'll want to adjust the conditions on the content filter rule to meet your needs. If you want to add a warning about attachments being compressed you can adjust this rule to do it using the "Add a warning to the top of the message" action.
param( [string]$MSGFileName ) ################################################################################################################################ ################################################################################################################################ ## Put attachments in compressed file using ZI_ extension v 1.0.0 ## ## August 15, 2024 ## ## Copyright MDaemon Technologies 2024 ## ## ## ## 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 places them in a zip file that is then ## ## attached to the email. ## ## ## ## 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) } function AddFiletoArchive ($FileName, $Archive) { Log "Adding $FileName to $Archive using the following arguments:" $Args = "a `"$Archive`" `"$FileName`"" Log $Args $EXE1 = Start-Process $7Zip -ArgumentList $Args -Wait Log $EXE1.ExitCode } Function GET-RandomString($Length, $SourceData) { For ($loop=1; $loop –le $Length; $loop++) { $TempPassword+=($SourceData | GET-RANDOM) } return $TempPassword } $MDINIPath = GetRegistryValue "HKLM:\SOFTWARE\Alt-N Technologies\MDaemon" "IniPath" $TempPath = Get-PrivateProfileString $MDINIPath "Directories" "Temp" $RAWPath = Get-PrivateProfileString $MDINIPath "Directories" "Raw" $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" $alphabet=$NULL;For ($a=65;$a –le 90;$a++) {$alphabet+=,[char][byte]$a } #$MSGFileName = "C:\MDaemon\Queues\Bad\pd35000003755.msg" $OutputFile = $MSGFileName #"C:\MDaemon\Queues\Bad\pd35000003756.msg" $7Zip = "$env:ProgramFiles\7-Zip\7z.exe" if(!(Test-Path $7zip)) { $7Zip = "$env:ProgramW6432\7-Zip\7z.exe" Log "$7Zip does not exist. Trying $7Zip." if(!(Test-Path $7Zip)) { Log "$7zip does not exist." Log "Error: Could not find 7z.exe. The script will now exist." exit } } Log "The path to the 7-Zip EXE is $7Zip." Log "The MDaemon INI path is: $MDINIPath" Log "The Temp path is: $TempPath" Log "The Raw Files path is: $RAWPath" Log "The Log path is: $LogPath" Log "Cleaning up empty directories from $TempPath" Get-ChildItem $TempPath -recurse | Where-Object {$_.PSIsContainer -eq $True -and $_.GetFiles().Count -eq 0} | Remove-Item -Force -ErrorAction SilentlyContinue 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." $From = $MSG.Fields.Item("urn:schemas:mailheader:From").Value $To = $MSG.Fields.Item("urn:schemas:mailheader:x-mdaemon-deliver-to").Value $MSGSubject = $MSG.Subject $ArchiveFileName = $Attachments.Item(1).FileName Log "The name of the attachment is $ArchiveFileName." $ArchiveFileName = [io.path]::ChangeExtension($ArchiveFileName, "zip") Log "Setting the Archive file name to $ArchiveFileName." $RandFolder = GET-RandomString "10" $alphabet $AttachPath = Join-Path $TempPath $RandFolder if(!(Test-Path $AttachPath)) { Log "Creating a folder named $RandFolder in the Temp path." $null = New-Item $AttachPath -ItemType directory } Log "The attachment path is: $AttachPath" $ArchivePath = Join-Path $AttachPath $ArchiveFileName Log "The archive file name is: $ArchivePath" Log "Creating an Archive file" Foreach($Attachment in $Attachments) { $Count = 1 $AttachmentFileName = $($Attachment.FileName) Log "Found an attachment named $AttachmentFileName" $FileAttachPath = Join-Path $AttachPath $AttachmentFileName $AttachmentFileNameWOExtension = [System.IO.Path]::GetFileNameWithoutExtension($AttachmentFileName) $AttachmentFileNameExtension = [System.IO.Path]::GetExtension($AttachmentFileName) While((Test-Path $FileAttachPath) -or ($AttachmentFileName -eq $ArchiveFileName)) { $AttachmentFileName = $AttachmentFileNameWOExtension + "(" + $Count + ")" + $AttachmentFileNameExtension $FileAttachPath = Join-Path $AttachPath $AttachmentFileName $Count++ } Log "Saving to $FileAttachPath." $Attachment.SavetoFile($FileAttachPath) AddFiletoArchive $FileAttachPath $ArchivePath } if(Test-Path $ArchivePath) { Log "Removing all attachments from $MSGFileName" $Attachments.DeleteAll() $NewName = $ArchivePath.replace(".zip",".zi_") Log "Renaming to $NewName" Rename-Item -Path $ArchivePath –NewName $NewName Log "Adding $NewName attachment to $MSGFileName" $MSG.AddAttachment($NewName) Save-EmlFile $MSG $OutputFile } else { Log "Error: The compressed file could not be found at $ArchivePath. The script will now exit without making any changes." } Log "Removing all files and folders from $AttachPath" Remove-Item "$AttachPath\*" -Recurse -Force -ErrorAction SilentlyContinue if(Test-Path $AttachPath) { Log "Removing $AttachPath from disk." Remove-Item $AttachPath -Force -Recurse -ErrorAction SilentlyContinue } } 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 "----------"