Ivanova
Ivanova

Reputation: 55

Generate list of new and modified files on an FTP server using WinSCP .NET assembly

I've a PowerShell script that detects when a new file is uploaded on a FTP server. I want to include list of such files (it's possible that they have multiple files) to a mail. I already have the part of the script for add it to the mail and send it (I think I've done this in right way), but I only need the name of the file and not on the full path. FYI : I'm using the winscpnet.dll library.

Have you a idea how to do it?

This is the script :

param (
    # Use Generate Session URL function to obtain a value for -sessionUrl parameter.
    $sessionUrl = "xxxxxxx",
    $remotePath = "xxxxxxx"
)

### SENDING MAIL FONCTION IF NEW FILE ###
Function SendMail-New
{
    $EXPEDITEUR = "xxxxxxx"
    $DESTINATAIRE = "xxxxxxx","xxxxxxx"
    $SUJET = "xxxxxxx"
    $SERVEUR_SMTP = "sxxxxxxx" 
    $CORPS_MAIL = "xxxxxxx"
    #$PJ = ($added -Join "`n") # If attached file
    #$attachment = New-Object System.Net.Mail.Attachment($PJ) # For attached file
    $Mail_Message = New-Object System.Net.Mail.MailMessage # Creating mail object
    $Mail_Message.From = $EXPEDITEUR
    $Mail_Message.Subject = $SUJET
    $Mail_Message.Body = $CORPS_MAIL
    #$Mail_Message.Attachments.Add($PJ)
    $Mail_Adresses = $Mail_Message.To
    if ($DESTINATAIRE -is "System.Array") # If more than 1 adress
    {
        foreach ($Adr in $DESTINATAIRE) # Adding each mail adress
        {
            $Mail_Adress = New-Object System.Net.Mail.MailAddress $Adr
            $Mail_Adresses.Add($Mail_Adress)
        }
    }
    else
    {
        $Mail_Adress = New-Object System.Net.Mail.MailAddress $DESTINATAIRE
        $Mail_Adresses.Add($Mail_Adress)
    }
    $SMTPClient = New-Object Net.Mail.SmtpClient($SERVEUR_SMTP, xxxxxxx) # SMTP server and port
    $SMTPClient.EnableSsl = $false # If SSL his activated or not - import the certificate before ?
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("xxxxxxx", "xxxxxxx"); #ICI Login et password du compte mail
    $SMTPClient.Send($Mail_Message) # Mail sending
}

### SENDING MAIL FONCTION IF DELETED FILE ###
Function SendMail-Deleted
{
    $EXPEDITEUR = "xxxxxxx"
    $DESTINATAIRE = "xxxxxxx","xxxxxxx"
    $SUJET = "xxxxxxx"
    $SERVEUR_SMTP = "xxxxxxx" 
    $CORPS_MAIL = "xxxxxxx"
    #$PJ = 'c:\script\Rapport.txt' # If attached file
    #$attachment = New-Object System.Net.Mail.Attachment($PJ) # For attached file
    $Mail_Message = New-Object System.Net.Mail.MailMessage # Creating mail object
    $Mail_Message.From = $EXPEDITEUR
    $Mail_Message.Subject = $SUJET
    $Mail_Message.Body = $CORPS_MAIL
    #$Mail_Message.Attachments.Add($PJ)
    $Mail_Adresses = $Mail_Message.To
    if ($DESTINATAIRE -is "System.Array") # If more than 1 adress
    {
        foreach ($Adr in $DESTINATAIRE) # Adding each mail adress
        {
            $Mail_Adress = New-Object System.Net.Mail.MailAddress $Adr
            $Mail_Adresses.Add($Mail_Adress)
        }
    }
    else
    {
        $Mail_Adress = New-Object System.Net.Mail.MailAddress $DESTINATAIRE
        $Mail_Adresses.Add($Mail_Adress)
    }
    $SMTPClient = New-Object Net.Mail.SmtpClient($SERVEUR_SMTP, xxxxxxx) # SMTP server and port
    $SMTPClient.EnableSsl = $false # If SSL his activated or not - import the certificate before ?
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("xxxxxxx", "xxxxxxx"); #ICI Login et password du compte mail
    $SMTPClient.Send($Mail_Message) # Mail sending
}

### SENDING MAIL FONCTION FOR A SCRIPT ERROR ###
Function SendMail-Error
{
    $EXPEDITEUR = "xxxxxxx"
    $DESTINATAIRE = "xxxxxxx"
    $SUJET = "xxxxxxx"
    $SERVEUR_SMTP = "xxxxxxx" 
    $CORPS_MAIL = "Le script c'est fermé suite à une erreur: $($_.Exception.Message)"
    #$PJ = 'c:\script\Rapport.txt' # If attached file
    #$attachment = New-Object System.Net.Mail.Attachment($PJ) # For attached file
    $Mail_Message = New-Object System.Net.Mail.MailMessage # Creating mail object
    $Mail_Message.From = $EXPEDITEUR
    $Mail_Message.Subject = $SUJET
    $Mail_Message.Body = $CORPS_MAIL
    #$Mail_Message.Attachments.Add($PJ)
    $Mail_Adresses = $Mail_Message.To
    if ($DESTINATAIRE -is "System.Array") # If more than 1 adress
    {
        foreach ($Adr in $DESTINATAIRE) # Adding each mail adress
        {
            $Mail_Adress = New-Object System.Net.Mail.MailAddress $Adr
            $Mail_Adresses.Add($Mail_Adress)
        }
    }
    else
    {
        $Mail_Adress = New-Object System.Net.Mail.MailAddress $DESTINATAIRE
        $Mail_Adresses.Add($Mail_Adress)
    }
    $SMTPClient = New-Object Net.Mail.SmtpClient($SERVEUR_SMTP, xxxxxxx) # SMTP server and port
    $SMTPClient.EnableSsl = $false # If SSL his activated or not - import the certificate before ?
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("xxxxxxx", "xxxxxxx"); #ICI Login et password du compte mail
    $SMTPClient.Send($Mail_Message) # Mail sending
}

try
{
    # Load WinSCP .NET assembly
    Add-Type -Path "WinSCPnet.dll"
 
    # Setup session options
    $sessionOptions = New-Object WinSCP.SessionOptions
    $sessionOptions.ParseUrl($sessionUrl)
 
    $session = New-Object WinSCP.Session
 
    try
    {
        # Connect
        $session.Open($sessionOptions)
 
        $prevFiles = $Null;
 
        while ($True)
        {
            # Collect file list
            $files =
                $session.EnumerateRemoteFiles(
                    $remotePath, "*.*", [WinSCP.EnumerationOptions]::AllDirectories) |
                Select-Object -ExpandProperty FullName
 
            if ($prevFiles -eq $Null)
            {
                # In the first round, just print number of files found
                Write-Host "Found $($files.Count) files"
            }
            else
            {
                # Then look for differences against the previous list
                $changes = Compare-Object -DifferenceObject $files -ReferenceObject $prevfiles
 
                $added =
                    $changes |
                    Where-Object -FilterScript { $_.SideIndicator -eq "=>" } |
                    Select-Object -ExpandProperty InputObject
                if ($added)
                {
                    Write-Host "Added files:"
                    Write-Host ($added -Join "`n")
                    Write-Warning "xxxxxxx"
                    SendMail-New # Send notification by mail for NEW FILE
                    echo "Mail envoyé"
                }
 
                $removed =
                    $changes |
                    Where-Object -FilterScript { $_.SideIndicator -eq "<=" } |
                    Select-Object -ExpandProperty InputObject
                if ($removed)
                {
                    Write-Host "Removed files:"
                    Write-Host ($removed -Join "`n")
                    Write-Warning "Un rapport d'intervention a été supprimé"
                    SendMail-Deleted # Send notification by mail for DELETED FILE
                    echo "Mail envoyé"
                }
            }
 
            $prevFiles = $files
 
            Write-Host "Sleeping 10s..."
            Start-Sleep -Seconds 10
        }
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }
}
catch
{
    SendMail-Error
    Write-Host "Error: $($_.Exception.Message)"
    echo "Mail d'erreur envoyé"
    exit 1
}

Upvotes: 1

Views: 231

Answers (1)

Martin Prikryl
Martin Prikryl

Reputation: 202474

I assume you do not have any subfolders in your comparison. Otherwise your requirement would not make sense to me.

If that assumption is correct, just compare plain file names (Name) instead of full paths (FullName). And exclude subfolders ([WinSCP.EnumerationOptions]::None), to make it clear that the code does not support them anymore.

$files =
    $session.EnumerateRemoteFiles(
        $remotePath, "*.*", [WinSCP.EnumerationOptions]::None) |
    Select-Object -ExpandProperty Name

Upvotes: 1

Related Questions