top of page
Search

PowerShell Logging and Not Start-Transcript

Writer's picture: TenakaTenaka

Introduction

While PowerShell's Start-Transcript command is a common choice for logging script output, it has its shortcomings. It records console output (write-host) without providing structured log levels, detailed formatting, or robust error tracking.


Logging in PowerShell scripts is often overlooked, I know I often overlook it for 'just a quick script', yet it plays a crucial role in confirming output and in this example the movement of family photos, there is nothing more important on my computer system than the decades of pictures and videos and can't afford for any to be deleted or lost. So logging is vitally important


The script to organise files by Year and then by Month can be downloaded from (here).


Reminder Before You Begin

Before running this script on important files, make sure to test it first! While it works on during my testing and implementation, it's always best to double-check before making big changes.


Overview

This PowerShell script is designed to automate file organization within a specified directory. It performs two main functions:

  • Detecting and moving duplicate files based on SHA256 hashes to a duplicates folder.

  • Sorting remaining files into subdirectories organized by year and month based on their last modified date.


Additionally, the script implements detailed logging to track its execution, errors, and actions taken during the process.


Key Components of the Script


1. Parameters and Initialization

The script accepts two parameters:

  • $Data2SortPath: The main directory containing files to be organized.

  • $duplicatesPath: A subdirectory where duplicate files will be moved.


A log file is also created at the start with a timestamped filename:

$LogFile = "$($Data2SortPath)\OrganizeFilesLog_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"

This ensures that each script run generates a new log file, preventing overwriting of previous logs.


2. Logging Functionality

The script includes a custom logging function, Write-MoveLog, to standardize log messages:

function Write-MoveLog {
    param (
        [string]$Message,
        [string]$LogLevel = "INFO"
    )
    $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    "$Timestamp [$LogLevel] $Message" | Out-File -FilePath $LogFile -Append
}

This function:

  • Formats logs with a timestamp.

  • Assigns severity levels (INFO, ERROR, WARNING).

  • Writes logs to the designated log file.


3. Directory Validation and Setup

Before processing files, the script checks whether the specified directory exists:

if (-not (Test-Path -Path $Data2SortPath)) {
    Write-MoveLog "Error: The specified path '$Data2SortPath' does not exist." "ERROR"
    throw "The specified path does not exist."
}

If the directory does not exist, an error is logged, and execution is halted.

Similarly, it ensures the duplicates folder exists or creates it:

if (-not (Test-Path -Path $duplicatesPath)) {
    New-Item -Path $duplicatesPath -ItemType Directory -Force | Out-Null
    Write-MoveLog "Created duplicates folder at '$duplicatesPath'." "INFO"
}

4. Retrieving Files for Processing

The script gathers all files within the directory, excluding .log and .zip files:

$gtFiles = Get-ChildItem -Path $Data2SortPath -Recurse -File |
    Where { $_.DirectoryName -notmatch "duplicates" -or $_.extension -notmatch ".log" -and $_.extension -notmatch ".zip" }

This ensures only relevant files are processed.


5. Detecting and Handling Duplicates

Each file’s SHA256 hash is computed to detect duplicates:

$gtFileHash = (Get-FileHash -Algorithm SHA256 -Path $file.FullName).Hash

If a duplicate is found, it is moved to the duplicates folder with a unique name to avoid overwriting:

$duplicateName = Join-Path -Path $duplicatesPath -ChildPath $file.Name
$counter = 1
while (Test-Path -Path $duplicateName) {
    $duplicateName = Join-Path $duplicatesPath -ChildPath ("{0}_{1}{2}" -f $file.BaseName, $counter, $file.Extension)
    $counter++
}
Move-Item -Path $file.FullName -Destination $duplicateName
Write-MoveLog "Duplicate detected: '$($file.FullName)' moved to '$duplicateName'." "INFO"

6. Organizing Files by Date

For non-duplicate files, the script determines their last modified date and organizes them into Year/Month folders:

$year = $file.LastWriteTime.Year
$monthName = (Get-Culture).DateTimeFormat.GetMonthName($file.LastWriteTime.Month)
$yearPath = Join-Path -Path $Data2SortPath -ChildPath $year
$monthPath = Join-Path -Path $yearPath -ChildPath $monthName

If these directories do not exist, they are created:

if (-not (Test-Path -Path $yearPath)) {
    New-Item -ItemType Directory -Path $yearPath -Force | Out-Null
    Write-MoveLog "Created year folder at '$yearPath'." "INFO"
}
if (-not (Test-Path -Path $monthPath)) {
    New-Item -ItemType Directory -Path $monthPath -Force | Out-Null
    Write-MoveLog "Created month folder at '$monthPath'." "INFO"
}

Files are then moved to their respective folders:

$destination = Join-Path -Path $monthPath -ChildPath $file.Name
Move-Item -Path $file.FullName -Destination $destination -Verbose
Write-MoveLog "File '$($file.FullName)' moved to '$destination'." "INFO"

If a naming conflict occurs, the file is renamed and moved:

if (Test-Path -Path "$destination\$file.Name") {
    $duplicateName = Join-Path $duplicatesPath -ChildPath ("{0}_{1}{2}" -f $file.BaseName, $counter, $file.Extension)
    $counter++
    Move-Item -Path $file.FullName -Destination $duplicateName
    Write-MoveLog "File '$($file.FullName)' moved to '$duplicateName'." "WARNING"
}

7. Error Handling and Final Logging

Errors are caught and logged throughout the script:

catch {
    Write-MoveLog "Failed to move file '$file.FullName': $_" "ERROR"
    continue
}

Finally, a message indicates the script's completion:

Write-MoveLog "File organization complete. See details in the log file at '$LogFile'." "INFO"
Write-Host "Processing complete. Logs are saved to '$LogFile'."

Conclusion

This PowerShell script makes sorting your files a breeze! It finds duplicates, organizes everything by date, and keeps a detailed log so you always know what’s happening. The built-in logging helps with troubleshooting, making it easy to track any issues.


Of course any issues please provide feedback via the form on the home page. Thanks and as always your time is appreciated.

3 views0 comments

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
bottom of page