Discover essential logging techniques and best practices for effective software development and system management. Learn about log management tools, log analysis, error tracking, and performance monitoring. Explore various logging frameworks, centralized logging solutions, and strategies for debugging and troubleshooting applications. Enhance your ability to maintain, secure, and optimize systems through comprehensive logging approaches.

Tag Archive for: Logging

RDS Login and Logout Logging Script

<#
.SYNOPSIS
RDS Login and Logout Logging Script

.DESCRIPTION
This script automatically logs user login and logout events for Remote Desktop Services.
It runs continuously as a background job, monitoring the Windows Event Log for relevant events.

.NOTES
File Name      : RDSLoginLogoutLogger.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V3 or later, admin rights on the RDS server
Version        : 1.0
Date           : [Current Date]

.EXAMPLE
Start-Job -FilePath .\RDSLoginLogoutLogger.ps1
#>

# Configuration
$logFilePath = "C:\Logs\RDSLoginLogout.log"
$lastRunFile = "C:\Logs\RDSLoginLogoutLastRun.txt"

# Ensure log directory exists
$logDir = Split-Path $logFilePath -Parent
if (-not (Test-Path $logDir)) {
    New-Item -ItemType Directory -Path $logDir | Out-Null
}

# Function to write log entries
function Write-Log {
    param (
        [string]$Message
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp - $Message"
    Add-Content -Path $logFilePath -Value $logEntry
}

# Function to get the last run time
function Get-LastRunTime {
    if (Test-Path $lastRunFile) {
        return Get-Content $lastRunFile
    }
    return (Get-Date).AddDays(-1).ToString("o")  # Default to 1 day ago if no last run time
}

# Function to save the last run time
function Save-LastRunTime {
    param (
        [DateTime]$LastRunTime
    )
    $LastRunTime.ToString("o") | Set-Content $lastRunFile
}

# Main logging loop
try {
    Write-Log "RDS Login/Logout logging started."

    while ($true) {
        $lastRunTime = Get-LastRunTime
        $currentTime = Get-Date

        # Query for login events
        $loginEvents = Get-WinEvent -FilterHashtable @{
            LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'
            ID = 21  # Event ID for session logon
            StartTime = $lastRunTime
        } -ErrorAction SilentlyContinue

        # Query for logout events
        $logoutEvents = Get-WinEvent -FilterHashtable @{
            LogName = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational'
            ID = 23  # Event ID for session logoff
            StartTime = $lastRunTime
        } -ErrorAction SilentlyContinue

        # Process login events
        foreach ($event in $loginEvents) {
            $username = $event.Properties[0].Value
            $sessionId = $event.Properties[1].Value
            Write-Log "User logged in: $username (Session ID: $sessionId)"
        }

        # Process logout events
        foreach ($event in $logoutEvents) {
            $username = $event.Properties[0].Value
            $sessionId = $event.Properties[1].Value
            Write-Log "User logged out: $username (Session ID: $sessionId)"
        }

        # Save the current time as the last run time
        Save-LastRunTime $currentTime

        # Wait for a minute before the next check
        Start-Sleep -Seconds 60
    }
}
catch {
    Write-Log "An error occurred: $_"
}
finally {
    Write-Log "RDS Login/Logout logging stopped."
}

To use this script:

  1. Save the script as RDSLoginLogoutLogger.ps1 in a suitable location on your RDS server.
  2. Modify the $logFilePath and $lastRunFile variables at the beginning of the script if you want to change the default log locations.
  3. To run the script as a background job, open PowerShell as an administrator and use the following command:
    Start-Job -FilePath C:\Path\To\RDSLoginLogoutLogger.ps1
    Replace C:\Path\To\ with the actual path where you saved the script.
  4. To check the status of the job: Get-Job
  5. To stop the job when needed: Stop-Job -Id <JobId>
  6. Replace <JobId> with the ID of the job from the Get-Job command.

Key features of this script:

  1. Continuous Monitoring: Runs as a background job, continuously checking for new login and logout events.
  2. Efficient Event Querying: Uses the last run time to query only for new events since the last check.
  3. Separate Log File: Logs events to a dedicated file for easy review and analysis.
  4. Error Handling: Includes basic error handling to log any issues that occur during execution.
  5. Low Resource Usage: Checks for new events every minute, balancing timeliness with system resource usage.

Notes:

  • This script needs to be run with administrator privileges on the RDS server.
  • The script creates a log file and a last run time file. Ensure the specified paths are accessible and writable.
  • For long-term use, consider implementing a log rotation mechanism to manage log file sizes.
  • You may need to adjust the event IDs (21 for login, 23 for logout) if your RDS environment uses different event IDs for these actions.
  • Always test the script in a non-production environment before deploying it to production servers.

This script provides a robust solution for automatically logging RDS login and logout events, which can be valuable for security auditing, user activity tracking, and compliance purposes.

Automated Folder Access Logging Script

<#
.SYNOPSIS
Automated Folder Access Logging Script

.DESCRIPTION
This script monitors a specified folder and its subfolders for file system events
and logs these events to a file. It uses the FileSystemWatcher class to monitor
the folder in real-time.

.PARAMETER FolderPath
The path of the folder to monitor.

.PARAMETER LogFile
The path of the log file where events will be recorded.

.EXAMPLE
.\FolderAccessLogger.ps1 -FolderPath "C:\ImportantFolder" -LogFile "C:\Logs\FolderAccess.log"

.NOTES
File Name      : FolderAccessLogger.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V3 or later
Version        : 1.0
Date           : [Current Date]
#>

param (
    [Parameter(Mandatory=$true)]
    [string]$FolderPath,

    [Parameter(Mandatory=$true)]
    [string]$LogFile
)

# Function to write log entries
function Write-Log {
    param (
        [string]$Message
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp - $Message"
    Add-Content -Path $LogFile -Value $logEntry
    Write-Host $logEntry
}

# Function to handle file system events
function Handle-FileSystemEvent {
    param (
        [System.IO.FileSystemEventArgs]$e
    )

    $eventType = $e.ChangeType
    $fullPath = $e.FullPath
    $message = "Event: $eventType, Path: $fullPath"
    Write-Log $message
}

# Create the log file if it doesn't exist
if (-not (Test-Path $LogFile)) {
    New-Item -Path $LogFile -ItemType File -Force
}

# Create a new FileSystemWatcher
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $FolderPath
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true

# Define the events to watch for
$changeTypes = [System.IO.WatcherChangeTypes]::Created -bor `
               [System.IO.WatcherChangeTypes]::Deleted -bor `
               [System.IO.WatcherChangeTypes]::Changed -bor `
               [System.IO.WatcherChangeTypes]::Renamed

# Set up event handlers
$onChanged = Register-ObjectEvent $watcher "Changed" -Action {
    Handle-FileSystemEvent -e $Event.SourceEventArgs
}
$onCreated = Register-ObjectEvent $watcher "Created" -Action {
    Handle-FileSystemEvent -e $Event.SourceEventArgs
}
$onDeleted = Register-ObjectEvent $watcher "Deleted" -Action {
    Handle-FileSystemEvent -e $Event.SourceEventArgs
}
$onRenamed = Register-ObjectEvent $watcher "Renamed" -Action {
    $oldPath = $Event.SourceEventArgs.OldFullPath
    $newPath = $Event.SourceEventArgs.FullPath
    $message = "Event: Renamed, Old Path: $oldPath, New Path: $newPath"
    Write-Log $message
}

Write-Log "Starting folder access monitoring for: $FolderPath"

try {
    # Keep the script running
    while ($true) {
        Start-Sleep -Seconds 1
    }
}
finally {
    # Clean up event handlers when the script is stopped
    Unregister-Event -SourceIdentifier $onChanged.Name
    Unregister-Event -SourceIdentifier $onCreated.Name
    Unregister-Event -SourceIdentifier $onDeleted.Name
    Unregister-Event -SourceIdentifier $onRenamed.Name
    $watcher.Dispose()
    Write-Log "Folder access monitoring stopped."
}

To use this script:

  1. Save it as FolderAccessLogger.ps1.
  2. Open PowerShell as an administrator.
  3. Navigate to the directory containing the script.
  4. Run the script with the required parameters:

.\FolderAccessLogger.ps1 -FolderPath "C:\PathToMonitor" -LogFile "C:\Logs\FolderAccess.log"

Replace "C:\PathToMonitor" with the path of the folder you want to monitor, and "C:\Logs\FolderAccess.log" with the desired path for your log file.

Key features of this script:

  1. Real-time monitoring: Uses FileSystemWatcher to detect changes as they happen.
  2. Comprehensive logging: Logs creation, deletion, modification, and renaming of files and folders.
  3. Subfolder inclusion: Monitors the specified folder and all its subfolders.
  4. Timestamped logs: Each log entry includes a timestamp for easy tracking.
  5. Continuous operation: The script runs indefinitely until manually stopped.
  6. Clean shutdown: Properly disposes of resources when the script is stopped.

Notes:

  • This script needs to be run with appropriate permissions to access the folder being monitored and to write to the log file.
  • The script will continue running until you manually stop it (e.g., by pressing Ctrl+C).
  • For long-term use, consider running this script as a Windows Service or scheduled task.
  • Be aware that monitoring a very active folder or a folder with many subfolders can generate a large number of events and potentially impact system performance.

This script provides a solid foundation for monitoring folder access and can be further customized based on specific needs, such as filtering certain types of files or events, or integrating with other notification systems.

Comprehensive Logging Tool

<#
.SYNOPSIS
Comprehensive Logging Tool

.DESCRIPTION
This script provides functionality for creating, managing, and analyzing log files
in various formats. It includes features for creating logs, appending to existing logs,
searching logs, and performing basic log analysis.

.NOTES
File Name      : LoggingTool.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V5.1 or later
Version        : 1.0
Date           : [Current Date]

.EXAMPLE
.\LoggingTool.ps1
#>

# Global variables
$global:logPath = "$env:USERPROFILE\Desktop\Logs"
$global:currentLogFile = ""

<#
.SYNOPSIS
Displays the main menu of the tool.
#>
function Show-Menu {
    Clear-Host
    Write-Host "=== Comprehensive Logging Tool ===" -ForegroundColor Cyan
    Write-Host "Current Log File: $global:currentLogFile"
    Write-Host "1. Create New Log File"
    Write-Host "2. Append to Existing Log"
    Write-Host "3. View Log Content"
    Write-Host "4. Search Log"
    Write-Host "5. Analyze Log (Basic Statistics)"
    Write-Host "6. Export Log to CSV"
    Write-Host "7. Rotate Log File"
    Write-Host "8. Delete Log File"
    Write-Host "9. Exit"
}

<#
.SYNOPSIS
Creates a new log file.
#>
function Create-NewLogFile {
    $logName = Read-Host "Enter the name for the new log file (without extension)"
    $logFormat = Read-Host "Enter log format (txt/json/xml)"
    
    $fileName = "$logName.$(Get-Date -Format 'yyyyMMdd').$logFormat"
    $global:currentLogFile = Join-Path $global:logPath $fileName

    if (!(Test-Path $global:logPath)) {
        New-Item -ItemType Directory -Path $global:logPath | Out-Null
    }

    switch ($logFormat) {
        "txt" { "" | Out-File -FilePath $global:currentLogFile }
        "json" { "[]" | Out-File -FilePath $global:currentLogFile }
        "xml" { '<?xml version="1.0" encoding="UTF-8"?><log></log>' | Out-File -FilePath $global:currentLogFile }
        default { Write-Host "Invalid format. Creating a txt file." -ForegroundColor Yellow; "" | Out-File -FilePath $global:currentLogFile }
    }

    Write-Host "Log file created: $global:currentLogFile" -ForegroundColor Green
}

<#
.SYNOPSIS
Appends an entry to the current log file.
#>
function Append-ToLog {
    if ([string]::IsNullOrEmpty($global:currentLogFile)) {
        Write-Host "No log file selected. Please create or select a log file first." -ForegroundColor Red
        return
    }

    $logEntry = Read-Host "Enter the log entry"
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

    $fileExtension = [System.IO.Path]::GetExtension($global:currentLogFile)
    switch ($fileExtension) {
        ".txt" { 
            "$timestamp - $logEntry" | Out-File -FilePath $global:currentLogFile -Append 
        }
        ".json" { 
            $jsonContent = Get-Content -Raw -Path $global:currentLogFile | ConvertFrom-Json
            $newEntry = @{
                "timestamp" = $timestamp
                "message" = $logEntry
            }
            $jsonContent += $newEntry
            $jsonContent | ConvertTo-Json | Set-Content -Path $global:currentLogFile
        }
        ".xml" { 
            [xml]$xmlContent = Get-Content -Path $global:currentLogFile
            $newEntry = $xmlContent.CreateElement("entry")
            $newEntry.SetAttribute("timestamp", $timestamp)
            $newEntry.InnerText = $logEntry
            $xmlContent.log.AppendChild($newEntry) | Out-Null
            $xmlContent.Save($global:currentLogFile)
        }
    }

    Write-Host "Log entry added successfully." -ForegroundColor Green
}

<#
.SYNOPSIS
Views the content of the current log file.
#>
function View-LogContent {
    if ([string]::IsNullOrEmpty($global:currentLogFile)) {
        Write-Host "No log file selected. Please create or select a log file first." -ForegroundColor Red
        return
    }

    Get-Content -Path $global:currentLogFile | Out-Host
    Read-Host "Press Enter to continue..."
}

<#
.SYNOPSIS
Searches the current log file for a specific term.
#>
function Search-Log {
    if ([string]::IsNullOrEmpty($global:currentLogFile)) {
        Write-Host "No log file selected. Please create or select a log file first." -ForegroundColor Red
        return
    }

    $searchTerm = Read-Host "Enter the search term"
    $results = Get-Content -Path $global:currentLogFile | Select-String -Pattern $searchTerm

    if ($results) {
        Write-Host "Search Results:" -ForegroundColor Yellow
        $results | ForEach-Object { Write-Host $_ }
    } else {
        Write-Host "No matches found." -ForegroundColor Yellow
    }

    Read-Host "Press Enter to continue..."
}

<#
.SYNOPSIS
Performs basic analysis on the current log file.
#>
function Analyze-Log {
    if ([string]::IsNullOrEmpty($global:currentLogFile)) {
        Write-Host "No log file selected. Please create or select a log file first." -ForegroundColor Red
        return
    }

    $content = Get-Content -Path $global:currentLogFile
    $totalEntries = $content.Count
    $uniqueEntries = ($content | Select-Object -Unique).Count
    $firstEntry = $content | Select-Object -First 1
    $lastEntry = $content | Select-Object -Last 1

    Write-Host "Log Analysis:" -ForegroundColor Yellow
    Write-Host "Total Entries: $totalEntries"
    Write-Host "Unique Entries: $uniqueEntries"
    Write-Host "First Entry: $firstEntry"
    Write-Host "Last Entry: $lastEntry"

    Read-Host "Press Enter to continue..."
}

<#
.SYNOPSIS
Exports the current log file to CSV format.
#>
function Export-LogToCSV {
    if ([string]::IsNullOrEmpty($global:currentLogFile)) {
        Write-Host "No log file selected. Please create or select a log file first." -ForegroundColor Red
        return
    }

    $csvPath = [System.IO.Path]::ChangeExtension($global:currentLogFile, "csv")
    $content = Get-Content -Path $global:currentLogFile

    $csvData = $content | ForEach-Object {
        if ($_ -match "^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) - (.*)$") {
            [PSCustomObject]@{
                Timestamp = $matches[1]
                Message = $matches[2]
            }
        }
    }

    $csvData | Export-Csv -Path $csvPath -NoTypeInformation
    Write-Host "Log exported to CSV: $csvPath" -ForegroundColor Green
}

<#
.SYNOPSIS
Rotates the current log file.
#>
function Rotate-LogFile {
    if ([string]::IsNullOrEmpty($global:currentLogFile)) {
        Write-Host "No log file selected. Please create or select a log file first." -ForegroundColor Red
        return
    }

    $directory = [System.IO.Path]::GetDirectoryName($global:currentLogFile)
    $fileName = [System.IO.Path]::GetFileNameWithoutExtension($global:currentLogFile)
    $extension = [System.IO.Path]::GetExtension($global:currentLogFile)

    $newFileName = "{0}_{1}{2}" -f $fileName, (Get-Date -Format "yyyyMMddHHmmss"), $extension
    $newFilePath = Join-Path $directory $newFileName

    Move-Item -Path $global:currentLogFile -Destination $newFilePath
    Write-Host "Log file rotated. New file: $newFilePath" -ForegroundColor Green

    # Create a new empty log file
    "" | Out-File -FilePath $global:currentLogFile
    Write-Host "New empty log file created: $global:currentLogFile" -ForegroundColor Green
}

<#
.SYNOPSIS
Deletes the current log file.
#>
function Delete-LogFile {
    if ([string]::IsNullOrEmpty($global:currentLogFile)) {
        Write-Host "No log file selected. Please create or select a log file first." -ForegroundColor Red
        return
    }

    $confirmation = Read-Host "Are you sure you want to delete the current log file? (Y/N)"
    if ($confirmation -eq "Y") {
        Remove-Item -Path $global:currentLogFile -Force
        Write-Host "Log file deleted: $global:currentLogFile" -ForegroundColor Green
        $global:currentLogFile = ""
    } else {
        Write-Host "Deletion cancelled." -ForegroundColor Yellow
    }
}

# Main program loop
do {
    Show-Menu
    $choice = Read-Host "`nEnter your choice (1-9)"

    switch ($choice) {
        "1" { Create-NewLogFile }
        "2" { Append-ToLog }
        "3" { View-LogContent }
        "4" { Search-Log }
        "5" { Analyze-Log }
        "6" { Export-LogToCSV }
        "7" { Rotate-LogFile }
        "8" { Delete-LogFile }
        "9" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

    if ($choice -ne "9") {
        Read-Host "`nPress Enter to continue..."
    }
} while ($choice -ne "9")

This Comprehensive Logging Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to manage and analyze log files:
    • Creating new log files in various formats (txt, json, xml)
    • Appending entries to existing logs
    • Viewing log content
    • Searching logs for specific terms
    • Performing basic log analysis
    • Exporting logs to CSV format
    • Rotating log files
    • Deleting log files
  3. Support for different log formats (txt, json, xml)
  4. Error handling and user confirmations for critical operations

Key features:

  • Flexible log creation in multiple formats
  • Easy log entry addition with automatic timestamps
  • Search functionality for quick information retrieval
  • Basic log analysis for insights
  • Log rotation for managing file sizes
  • CSV export for further analysis in spreadsheet applications
  • Safe log file deletion with user confirmation

This tool is particularly useful for:

  • Developers needing to implement logging in their applications
  • System administrators managing log files
  • IT professionals troubleshooting issues using logs
  • Anyone needing to create, manage, or analyze log files

To use this script effectively:

  1. Run PowerShell with appropriate permissions to create and modify files in the specified log directory
  2. Ensure you have write access to the desktop or modify the $global:logPath variable to a suitable location
  3. Be cautious when deleting log files, as this operation is irreversible

This script provides a comprehensive set of features for log management and analysis, making it easier to maintain, search, and gain insights from log files in various formats.