chkdsk
Goto Top

Export Outlook Mails als .msg

Guten Morgen Zusammen,

ich habe ein Problem mit einem Powershell Skript.
Aktuell sichert das Skript alle Mails im Ordner Posteingang nach Eingabe eines bestimmten Zeitraums in einen Ordner als .msg Datei. Das funktioniert auch. Allerdings werden die Unterordner im Posteingang scheinbar ignoriert. Auch wenn ich mit der Rekursiv Funktion suche, werden diese ignoriert. Hat jemand einen Tipp? Oder geht es gänzlich einfacher?

# Function: Validate-Properties
function Validate-Properties {
    param (
        [psobject]$InputObject,
        [string[]]$RequiredProperties
    )

    $MissingProps = @()

    foreach ($Prop in $RequiredProperties) {
        if (-not $InputObject.PSObject.Properties[$Prop]) {
            $MissingProps += $Prop
        }
    }

    return $MissingProps
}

# Function: Create-FileName
function Create-FileName {
    param (
        [psobject]$InputObject,
        [string]$FileNameFormat
    )

    $FileName = $FileNameFormat

    $FileName = $FileName -replace '%SenderName%', $InputObject.SenderName  
    $FileName = $FileName -replace '%Subject%', $InputObject.Subject -replace '[<>:"/\\|?*]', '' # Remove invalid characters  
    $FileName = $FileName -replace '%ReceivedTime%', $InputObject.ReceivedTime.ToString('yyyyMMdd_HHmmss')  

    return $FileName
}

# Function: Get-ValidFileName
function Get-ValidFileName {
    param (
        [string]$FileName
    )

    # Replace invalid characters for Windows file names
    $InvalidChars = [System.IO.Path]::GetInvalidFileNameChars()
    foreach ($char in $InvalidChars) {
        $FileName = $FileName -replace [regex]::Escape($char), ''  
    }

    return $FileName
}

# Function: Add-Numbering
function Add-Numbering {
    param (
        [string]$FileName,
        [string]$FileExtension
    )

    $Counter = 1
    $BaseFileName = $FileName
    while (Test-Path "$FileName.$FileExtension") {  
        $FileName = "$BaseFileName ($Counter)"  
        $Counter++
    }

    return "$FileName.$FileExtension"  
}

# Function: Export-OutlookMessage
function Export-OutlookMessage {

    [CmdletBinding()]

    Param(
        [parameter(Mandatory=$true,ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [psobject[]]$Messages,
        [parameter(Mandatory=$true,ValueFromPipeline=$false)] [string]$OutputFolder,
        [parameter(Mandatory=$false,ValueFromPipeline=$false)] [string]$FileNameFormat='FROM= %SenderName% SUBJECT= %Subject%',  
        [parameter(Mandatory=$false,ValueFromPipeline=$false)] [ref]$SkippedMessages
    ) 

    BEGIN {
        Write-Verbose -Message 'Export-OutlookMessage starting...'  
        $olSaveAsTypes = "Microsoft.Office.Interop.Outlook.olSaveAsType" -as [type]  

        # Convert format message to real file name, replace %...% with message attribute
        $RegEx = '(\%)(.+?)(\%)'  
        
        $ReqProps = @('Subject','SaveAs','SenderName')  
        $ReqProps += ([regex]::Matches($FileNameFormat,$RegEx) ).Value -replace '%',''  

        # Initialize queue for skipped messages, if it is passed
        if ($SkippedMessages) {
            $SkippedMessages.Value = @()
        }
    }

    PROCESS {

        foreach ($Message in $Messages) {

            # Check input object
            $NotFoundProps = Validate-Properties -InputObject $Message -RequiredProperties $ReqProps # Validate-Properties is internal function
            if ($NotFoundProps) {      
                $ErrorMessage = 'Message '  
                if ($Message.Subject) {
                    $ErrorMessage += $Message.Subject
                } else {
                    $ErrorMessage += 'Unknown'  
                }
                $ErrorMessage += ' is not a proper object. Missing: ' + ($NotFoundProps -join ',')  
                if ($SkippedMessages) {
                    $SkippedMessages.Value += $Message # adding skipped messages to referenced variable if passed
                }
                Write-Error -Message $ErrorMessage
                Continue # next foreach
            }

            Write-Verbose -Message ('Processing '+($Message.Subject))  

            # Creating file name
            $FileName = Create-FileName -InputObject $Message -FileNameFormat $FileNameFormat   # Create-FileName is internal function
            
            # Fix file name
            $FileName = Get-ValidFileName -FileName  $FileName
            $FullFilePath = Add-Numbering -FileName (Join-Path -Path $OutputFolder -ChildPath $FileName) -FileExtension 'msg'  
            Write-Verbose -Message "Saving message to $FullFilePath"  

            # Save message to disk
            try {
                $Message.SaveAs($FullFilePath,$olSaveAsTypes::olMSGUnicode)
            } catch {
                if ($SkippedMessages) {
                    $SkippedMessages.Value += $Message # adding skipped messages to referenced variable if passed
                }
                Write-Error -Message ('Message save exception.'+$Error[0].Exception)  
            }
        }

    } 

    END {
        Write-Verbose -Message 'Export-OutlookMessage completed.'  
    }
}

Add-Type -AssemblyName System.Windows.Forms

# Function to prompt for date input
function Get-DateRange {
    $StartDateInput = Read-Host "Enter the start date (dd.MM.yyyy)"  
    $EndDateInput = Read-Host "Enter the end date (dd.MM.yyyy)"  

    try {
        # Parse the input dates using the specified format
        $StartDate = [datetime]::ParseExact($StartDateInput, "dd.MM.yyyy", $null)  
        $EndDate = [datetime]::ParseExact($EndDateInput, "dd.MM.yyyy", $null)  
        
        # Ensure the start date is before or equal to the end date
        if ($StartDate -gt $EndDate) {
            throw "Start date must be before or equal to end date."  
        }
    } catch {
        Write-Error "Invalid date format or range. Please use dd.MM.yyyy format."  
        exit 1
    }

    return @{ StartDate = $StartDate; EndDate = $EndDate }
}

# Function to prompt user for folder selection
function Get-OutputFolder {
    $FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
    $FolderBrowser.Description = "Select the folder where you want to save the exported emails"  

    # Show the dialog and get the result
    $DialogResult = $FolderBrowser.ShowDialog()
    
    if ($DialogResult -eq [System.Windows.Forms.DialogResult]::OK) {
        $SelectedPath = $FolderBrowser.SelectedPath
        if (-not (Test-Path -Path $SelectedPath)) {
            New-Item -ItemType Directory -Path $SelectedPath | Out-Null
            Write-Output "Created folder: $SelectedPath"  
        }
        return $SelectedPath
    } else {
        Write-Error "No folder was selected. Exiting script."  
        exit 1
    }
}

# Get date range from the user
$DateRange = Get-DateRange
$StartDate = $DateRange.StartDate
$EndDate = $DateRange.EndDate

# Get output folder from the user
$OutputFolder = Get-OutputFolder

# Initialize Outlook COM object
$Outlook = New-Object -ComObject Outlook.Application
$Namespace = $Outlook.GetNamespace("MAPI")  
$Inbox = $Namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
$InboxMessages = $Inbox.Items

# Initialize counters
$SuccessCount = 0
$FailureCount = 0

# Filter messages by date range
$FilteredMessages = @()
foreach ($Item in $InboxMessages) {
    if ($Item -is [Microsoft.Office.Interop.Outlook.MailItem] -and $Item.ReceivedTime -ge $StartDate -and $Item.ReceivedTime -le $EndDate) {
        $FilteredMessages += $Item
    }
}

# Display total count for debugging
$TotalItems = $FilteredMessages.Count
Write-Output "Total items to process: $TotalItems"  

# Loop through filtered messages
for ($i = 0; $i -lt $TotalItems; $i++) {
    $Item = $FilteredMessages[$i]
    
    try {
        # Create a valid filename for the email with sender name included
        $SenderName = $Item.SenderName -replace '[\\/:*?"<>|]', ''  # Remove invalid characters  
        $FileName = "{0:yyyyMMdd_HHmm} - {1} - {2}.msg" -f $Item.ReceivedTime, $SenderName, $Item.Subject  
        $FileName = $FileName -replace '[\\/:*?"<>|]', ''  # Remove invalid filename characters  
        
        # Define the full path for the file
        $FilePath = Join-Path -Path $OutputFolder -ChildPath $FileName
        
        # Save the mail item
        $Item.SaveAs($FilePath, 3)  # 3 corresponds to olMSGUnicode
        Write-Output "Saved: $FilePath"  
        $SuccessCount++
    }
    catch {
        Write-Warning "Failed to save an item. Subject: $($Item.Subject) - Error: $_"  
        $FailureCount++
    }

    # Display progress information
    $PercentComplete = [math]::Round((($i + 1) / $TotalItems) * 100, 2)
    Write-Output "Progress: $PercentComplete% Complete - Processing item $($i + 1) of $TotalItems"  
}

# Summary of the operation
Write-Output "Successfully saved $SuccessCount items."  
Write-Output "Failed to save $FailureCount items."  

Content-Key: 12360602016

Url: https://administrator.de/contentid/12360602016

Printed on: August 20, 2024 at 05:08 o'clock

Member: bacardi
bacardi Aug 19, 2024 updated at 13:00:54 (UTC)
Goto Top
Moin.
Auch wenn ich mit der Rekursiv Funktion suche, werden diese ignoriert.
Dann hast du die Funktion falsch aufgebaut.
Du musst dir eine rekursive Funktion in der Art und Weise bauen dann klappt das auch ...
function RecurseIntoFolders {
    param(
        $parentfolder
    )
    # alle Mails des Ordners durchlaufen und exportieren
    foreach($mail in $parentfolder.Items){
        # .....
        # $mail.SaveAs(.......)     
    }
    # alle Unterordner des Ordners mit der Funktion rekursiv durchlaufen
    foreach($folder in $parentfolder.Folders){
        RecurseIntoFolders -parentfolder $folder
    }
}

RecurseIntoFolders -parentfolder $inbox
Gruß