1
\$\begingroup\$

Remote-Computer-File-Transfer

I have created a PowerShell script, , for remote computers file transfer, for computers that only support New-PSDrive cmdlet, and I would like someone to take look at my code and give me guidelines on what I am doing the wrong way and what I am doing right.

The Script

Description

This script transfers files to remote computers. In Files-Paths.txt file user can write full paths to files for transfer, and in Remote-Computers.txt user can write list of remote computers to which files are transferred, ether by hostname or IP address. Script generates detailed log file and report that is sent via email to system administrators.

#Clears the contents of the DNS client cache
Clear-DnsClientCache

#Loading script configuration
$Settings = Get-Content "$PSScriptRoot\Settings.cfg" | ConvertFrom-StringData
$PSScriptRoot

#Defining network drive thru which files will be to transferred
$NetworkDrive = "T"

[System.Object[]]$FileList = Get-Content -Path $Settings.FileList
[System.Object[]]$ComputerList = Get-Content -Path $Settings.ComputerList

$SuccessfulTransfers = 0
$FailedTransfers = 0

Import-Module "$PSScriptRoot\Modules\Write-Log.psm1"
Import-Module "$PSScriptRoot\Modules\Start-FileTransfer.psm1"
Import-Module "$PSScriptRoot\Modules\Send-EmailReport.psm1"

Write-Log -Message $Settings.LogTitle -NoTimestamp
Write-Log -Message $Settings.LogSeparator -NoTimestamp

#Get credential from user input
Write-Log -Message "Enter username and password"
$Credential = Get-Credential
Write-Log -Message ("User " + $Credential.UserName + " has entered credentials")

foreach($File in $FileList) {
    if (Test-Path -Path $File) {
        Write-Log -Message "Successfully checked $File file - ready for transfer"
    }
    else {
        $Message = "Failed to access $File file - it does not exist.`nScript stopped - MISSING FILE ERROR"
        Write-Log -Message $Message
        Write-Log -Message $Settings.LogSeparator -NoTimestamp
        Send-EmailReport -Settings $Settings -FinalMessage $Message
        Exit
    }
}
Write-Log -Message "Successfully accessed all files - ready for transfer"

#Start file transfer
foreach ($Computer in $ComputerList) {
    if (Test-Connection -TargetName $Computer -Quiet -Count 1) {
        Write-Log -Message "Successfully connected to $Computer remote computer"
        $Partition = $Settings.Partition
        $NetworkPath = "\\$Computer\$Partition$"
        if (New-PSDrive -Name $NetworkDrive -Persist -PSProvider "FileSystem" -Root $NetworkPath -Credential $Credential) {
            Write-Log -Message "Successfully mapped network drive to $Partition partition on the $Computer remote computer"
            Start-FileTransfer -FileList $FileList -Destination ($NetworkDrive + ":\" + $Settings.TransferFolder) | `
            ForEach-Object {
                $SuccessfulTransfers += $_.Successful
                $FailedTransfers += $_.Failed
            }
            Remove-PSDrive -Name $NetworkDrive
        }
        else {
            Write-Log -Message "Failed to map network drive to C partition on the $Computer remote computer"
            $FailedTransfers += $FileList.Length
            Write-Log -Message "Canceld file transfer to $Computer remote computer"
        }
    }
    else {
        Write-Log -Message "Failed to connected to $Computer remote computer"
        $FailedTransfers += $FileList.Length
        Write-Log -Message "Canceld file transfer to $Computer remote computer"
    }
}

if($SuccessfulTransfers -gt 0) {
    Write-Log -Message "Successfully transferred $SuccessfulTransfers files"
}

if ($FailedTransfers -gt 0) {
    Write-Log -Message "Failed to transfer $FailedTransfers files"
}

if(($SuccessfulTransfers -gt 0 ) -and ($FailedTransfers -eq 0)) {
    $Message = "Successfully transferred all files"
}
elseif (($SuccessfulTransfers -gt 0 ) -and ($FailedTransfers -gt 0)) {
    $Message = "Successfully transferred some files with some failed"
}
elseif (($SuccessfulTransfers -eq 0 ) -and ($FailedTransfers -gt 0)) {
    $Message = "Failed to transfer any file"
}
Write-Log -Message $Message
Write-Log -Message $Settings.LogSeparator -NoTimestamp

#Sends email with detailed report and deletes temporary report log file
Send-EmailReport -Settings $Settings -FinalMessage $Message

Write-Log function

Description

Creates a log entry with timestamp and message passed thru a parameter Message, and saves the log entry to log file, to report log file, and writes the same entry to console. In Settings.cfg file paths to report log and permanent log file are contained, and option to turn on or off whether a console output, report log and permanent log should be written. If Settings.cfg file is absent it loads the default values. Depending on the NoTimestamp parameter, log entry can be written with or without a timestamp. Format of the timestamp is yyyy.MM.dd. HH:mm:ss:fff, and this function adds " - " after timestamp and before the main message.

function Write-Log {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
                   Position = 0,
                   ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true,
                   HelpMessage = "A string message to be written as a log entry")]
        [string]
        $Message,

        [Parameter(Mandatory = $false,
                   Position = 1,
                   ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true,
                   HelpMessage = "A switch parameter if present timestamp is disabled in log entry")]
        [switch]
        $NoTimestamp = $false
    )

    begin {
        if (Test-Path -Path ".\Settings.cfg") {
            $Settings = Get-Content ".\Settings.cfg" | ConvertFrom-StringData

            $LogFile         = $Settings.LogFile
            $ReportFile      = $Settings.ReportFile
            $WriteTranscript = $Settings.WriteTranscript -eq "true"
            $WriteLog        = $Settings.WriteLog -eq "true"
            $SendReport      = $Settings.SendReport -eq "true"
        }
        else {
            $LogFile         = ".\Log.log"
            $ReportFile      = ".\Report.log"
            $WriteTranscript = $true
            $WriteLog        = $true
            $SendReport      = $false
        }
        if (-not (Test-Path -Path $LogFile)) {
            New-Item -Path $LogFile -ItemType File
        }
        if ((-not (Test-Path -Path $ReportFile)) -and $SendReport) {
            New-Item -Path $ReportFile -ItemType File
        }
    }

    process {
        if (-not($NoTimestamp)) {
            $Timestamp = Get-Date -Format "yyyy.MM.dd. HH:mm:ss:fff"
            $LogEntry = "$Timestamp - $Message"
        }
        else {
            $LogEntry = $Message
        }

        if ($WriteTranscript) {
            Write-Verbose $LogEntry -Verbose
        }
        if ($WriteLog) {
            Add-content -Path $LogFile -Value $LogEntry
        }
        if ($SendReport) {
            Add-content -Path $ReportFile -Value $LogEntry
        }
    }
}

Start-FileTransfer

Description

Transfers files from the list to destination folder. Log errors and actions while files are transferred.

function Start-FileTransfer {
    [CmdletBinding(SupportsShouldProcess = $true)]
    [OutputType([PSCustomObject])]
    param (

        [Parameter(Mandatory = $true,
                   Position = 0,
                   ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true,
                   HelpMessage = "List od file full names fot transfer")]
        [System.Object[]]
        $FileList,

        [Parameter(Mandatory = $true,
                   Position = 1,
                   ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true,
                   HelpMessage = "Full path to file transfer folder")]
        [string]
        $Destination
    )

    process {
        $SuccessfulTransfers = 0
        $FailedTransfers = 0

        foreach($File in $FileList) {
            #File name extraction from file full path
            $FileName = Split-Path $File -leaf

            try {
                Copy-Item -Path $File -Destination $Destination -Force
            }
            catch {
                Write-Log -Message ("Failed to transfer $FileName file to $Destination folder `n" + $_.Exception)
                $FailedTransfers ++
                continue
            }

            $TransferDestination = Join-Path -Path $Destination -ChildPath $FileName

            if(Test-Path -Path $TransferDestination) {
                Write-Log -Message "Successfully transferred $FileName file to $Destination folder"
                $SuccessfulTransfers ++
            }
        }
        New-Object -TypeName psobject -Property @{
            Successful = $SuccessfulTransfers
            Failed = $FailedTransfers
        }
    }
}

Send-EmailReport

Description

This function sends a report log file, Report.log, as an attachment to defined email address. settings are defined.

function Send-EmailReport {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
                   Position = 0,
                   ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true,
                   HelpMessage = "Email settings")]
        [System.Object[]]
        $Settings,

        [Parameter(Mandatory = $false,
                   Position = 1,
                   ValueFromPipeline = $true,
                   ValueFromPipelineByPropertyName = $true,
                   HelpMessage = "Additional variable information to be sent in the mail body")]
        [string]
        $FinalMessage
    )

    process {
        if ($Settings.SendReport -eq 'true') {
            $Body = $Settings.Body + "`n" + $FinalMessage
            Send-MailMessage -SmtpServer $Settings.SmtpServer `
                             -Port $Settings.Port `
                             -To $Settings.To `
                             -From $Settings.From `
                             -Subject $Settings.Subject `
                             -Body $Body `
                             -Attachments $Settings.ReportFile
            Remove-Item -Path $Settings.ReportFile
        }
    }
}

Setting file

LogTitle = ***********************************************  Remote Computer File Transfer PowerShell Script Log  ************************************************
LogSeparator = ******************************************************************************************************************************************************

WriteTranscript = true
WriteLog = true
SendReport = true

LogFile = .\\Log.log
ReportFile = .\\Report.log
FileList = .\\File-Paths.txt
ComputerList = .\\Computer-List.txt
Partition = C
TransferFolder = Target\Folder

SmtpServer = smtp.mail.com
Port = 25
To = system.administrators@company.com
From = powershell@company.com
Subject = Remote Computer File Transfer Report
Body = This is an automated message sent from PowerShell script. Remote Computer File Transfer PowerShell Script has finished executing.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.