Tag: #Utility

  • Interactive macOS Countdown Timer Bash Script

    This Bash script creates a countdown timer that either accepts the duration in seconds as a command-line argument or prompts the user for input. It displays the remaining time in the Terminal and sends a native macOS notification when the countdown completes.

    Click to view script…
    #!/bin/bash
    # Simple Countdown Timer for macOS with Interactive Input
    
    # Check if a time (in seconds) was provided as an argument
    if [ $# -eq 0 ]; then
        # Prompt the user for input if no argument is given
        read -p "Enter number of seconds for the countdown: " TIME_LEFT
    else
        TIME_LEFT=$1
    fi
    
    # Validate that the input is a positive integer
    if ! [[ $TIME_LEFT =~ ^[0-9]+$ ]] ; then
        echo "Error: Please enter a positive integer for seconds." >&2
        exit 1
    fi
    
    # Countdown loop
    while [ $TIME_LEFT -gt 0 ]; do
        echo -ne "Time left: ${TIME_LEFT} second(s) \r"
        sleep 1
        ((TIME_LEFT--))
    done
    
    # Move to a new line after the countdown
    echo -e "\nTime's up!"
    
    # Display a macOS notification using osascript
    osascript -e 'display notification "Countdown Complete!" with title "Timer"'
  • Automated Screen Capture AppleScript Tool

    This AppleScript lets you capture screenshots either on demand or at scheduled intervals, automatically saving each capture in a designated folder with a unique, timestamped filename. Notifications alert you whenever a screenshot is taken, ensuring you always know when your screen has been captured.

    Warning: This script requires specific macOS permissions to function correctly. In particular, macOS Catalina and later require that you enable Screen Recording permissions for the app running the script (e.g., Script Editor or Terminal), and you may also need to grant Automation or Full Disk Access in Security & Privacy settings. Without these permissions, the screenshot functionality and notifications might not work as expected.

    Click to view script…
    -- Automated Screen Capture Script
    
    -- Ensure the "Screenshots" folder exists on the Desktop
    do shell script "mkdir -p ~/Desktop/Screenshots"
    
    -- Ask the user to choose a capture mode
    display dialog "Choose Screenshot Mode:" buttons {"On Demand", "Scheduled"} default button "On Demand"
    set modeChoice to button returned of result
    
    if modeChoice is "On Demand" then
        my takeScreenshot()
    else if modeChoice is "Scheduled" then
        display dialog "Enter interval between screenshots (in seconds):" default answer "60"
        set intervalSeconds to (text returned of result) as integer
        
        display dialog "Enter number of screenshots to capture:" default answer "10"
        set numberShots to (text returned of result) as integer
        
        repeat with i from 1 to numberShots
            my takeScreenshot()
            delay intervalSeconds
        end repeat
    end if
    
    -- Handler to take a screenshot and save it with a timestamped filename
    on takeScreenshot()
        -- Create a timestamp
        set timeStamp to do shell script "date +%Y%m%d-%H%M%S"
        set fileName to "Screenshot-" & timeStamp & ".png"
        set filePath to "~/Desktop/Screenshots/" & fileName
        -- Capture the screenshot silently (-x suppresses the shutter sound)
        do shell script "screencapture -x " & filePath
        display notification "Captured: " & fileName with title "Screen Capture"
    end takeScreenshot
  • Flexible Volume Controller AppleScript

    This AppleScript lets you adjust your Mac’s system volume either by selecting from a list of predefined levels (Mute, 0, 25, 50, 75, or 100) or by entering a custom value between 0 and 100, with a notification confirming the change.

    Click to view script…
    -- Volume Controller Script
    
    -- First, choose the control method.
    display dialog "Choose Volume Control Method:" buttons {"Predefined Levels", "Custom Level"} default button "Predefined Levels"
    set methodChoice to button returned of result
    
    if methodChoice is "Predefined Levels" then
        -- Use a list to display multiple predefined options.
        set volumeOptions to {"Mute", "0", "25", "50", "75", "100"}
        set volChoiceList to choose from list volumeOptions with prompt "Select Volume Setting:" default items {"50"}
        
        if volChoiceList is false then
            display notification "No selection made." with title "Volume Controller"
            return
        end if
        
        set volChoice to item 1 of volChoiceList
        if volChoice is "Mute" then
            set volume with output muted
            display notification "Volume muted" with title "Volume Controller"
        else
            set volValue to volChoice as integer
            set volume output volume volValue
            display notification "Volume set to " & volValue & "%" with title "Volume Controller"
        end if
        
    else if methodChoice is "Custom Level" then
        display dialog "Enter desired volume level (0-100):" default answer "50"
        set volInput to text returned of result
        set volLevel to volInput as integer
        
        if volLevel < 0 then
            set volLevel to 0
        else if volLevel > 100 then
            set volLevel to 100
        end if
        
        set volume output volume volLevel
        display notification "Volume set to " & volLevel & "%" with title "Volume Controller"
    end if
  • Light and Dark Mode Toggler AppleScript

    This AppleScript toggles your macOS display between dark and light modes, letting you quickly adapt your favorite setting.

    Click to view script…
    tell application "System Events"
        tell appearance preferences
            set dark mode to not dark mode
        end tell
    end tell

  • USB Device Logger PowerShell Script

    A PowerShell script that logs detailed information about all connected USB devices, including their names, PNP device IDs, and descriptions, along with a timestamp. This tool is ideal for tracking USB connections over time for auditing or troubleshooting purposes.

    Click to view script…
    <#
    .SYNOPSIS
        Logs all USB devices connected to the system.
    
    .DESCRIPTION
        This script uses CIM/WMI to query for USB devices (by filtering for PNPDeviceIDs that start with "USB")
        and logs their details (Name, PNPDeviceID, Description) along with a timestamp. The log is appended to a file,
        which by default is stored in the same directory as the script (USBDeviceLog.txt).
    
    .NOTES
        Run this script with the necessary permissions. 
        Adjust the log file path if needed.
    #>
    
    # Define the log file location (you can change this to an absolute path if desired)
    $logFilePath = Join-Path -Path $PSScriptRoot -ChildPath "USBDeviceLog.txt"
    
    # Get the current timestamp
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    
    # Create the log entry header
    $logEntry = "USB Device Log - $timestamp`r`n" + ("=" * 50) + "`r`n"
    
    # Query for USB devices by filtering Win32_PnPEntity for entries with a PNPDeviceID starting with "USB"
    try {
        $usbDevices = Get-CimInstance -ClassName Win32_PnPEntity | Where-Object { $_.PNPDeviceID -like "USB*" }
    }
    catch {
        Write-Error "Error querying USB devices: $_"
        exit
    }
    
    if ($usbDevices) {
        foreach ($device in $usbDevices) {
            $logEntry += "Name         : " + $device.Name + "`r`n"
            $logEntry += "PNPDeviceID  : " + $device.PNPDeviceID + "`r`n"
            $logEntry += "Description  : " + $device.Description + "`r`n"
            $logEntry += ("-" * 40) + "`r`n"
        }
    }
    else {
        $logEntry += "No USB devices found." + "`r`n"
    }
    
    $logEntry += "`r`n"
    
    # Append the log entry to the log file
    try {
        Add-Content -Path $logFilePath -Value $logEntry
        Write-Host "USB devices logged successfully to $logFilePath" -ForegroundColor Green
    }
    catch {
        Write-Error "Failed to write to log file: $_"
    }
  • Drive Space Information PowerShell Script

    This PowerShell script retrieves and displays space information for all local fixed drives, including total size, free space, used space, and the percentage of free space.

    Click to view script…
    # Get-DriveSpaceInfo.ps1
    # This script retrieves space information for each local drive (DriveType=3) on the computer.
    # It displays the drive letter, total size, free space, used space, and percentage of free space.
    
    # Retrieve local disk drives (DriveType=3 indicates local fixed disks)
    $drives = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"
    
    if (!$drives) {
        Write-Host "No local drives found."
        exit
    }
    
    foreach ($drive in $drives) {
        $driveLetter = $drive.DeviceID
        $totalSize = $drive.Size
        $freeSpace = $drive.FreeSpace
    
        # Calculate used space and percentage of free space (if total size is not zero)
        if ($totalSize -gt 0) {
            $usedSpace = $totalSize - $freeSpace
            $percentFree = [Math]::Round(($freeSpace / $totalSize) * 100, 2)
            $totalSizeGB = [Math]::Round($totalSize / 1GB, 2)
            $freeSpaceGB = [Math]::Round($freeSpace / 1GB, 2)
            $usedSpaceGB = [Math]::Round($usedSpace / 1GB, 2)
        }
        else {
            $usedSpace = 0
            $percentFree = 0
            $totalSizeGB = 0
            $freeSpaceGB = 0
            $usedSpaceGB = 0
        }
    
        Write-Host "Drive: $driveLetter" -ForegroundColor Cyan
        Write-Host "  Total Size: $totalSizeGB GB"
        Write-Host "  Free Space: $freeSpaceGB GB ($percentFree`%)"
        Write-Host "  Used Space: $usedSpaceGB GB"
        Write-Host "-------------------------------------"
    }
  • Largest Files Explorer with Interactive Details PowerShell Script

    This PowerShell script scans a specified directory for files, lists the largest files in a neat, truncated table, and lets you view full details for any selected file or all files, providing a comprehensive yet user-friendly overview of disk usage.

    Click to view script…
    <#
    .SYNOPSIS
        Lists the largest files in a directory with a truncated display and full detail lookup.
    
    .DESCRIPTION
        This script recursively scans a specified directory (or the current directory by default),
        sorts all files by size in descending order, and displays the top N largest files as specified by the user.
        It shows a truncated file name and full path for a neat table view.
        After displaying the table, the user can choose an index (or "all") to view full details of the file(s).
    
    .NOTES
        Run as Administrator if scanning protected directories.
    #>
    
    # Function to convert bytes to a human-readable format.
    function Convert-BytesToHumanReadable {
        param ([long]$bytes)
        if ($bytes -ge 1PB) {
            return "{0:N2} PB" -f ($bytes / 1PB)
        }
        elseif ($bytes -ge 1TB) {
            return "{0:N2} TB" -f ($bytes / 1TB)
        }
        elseif ($bytes -ge 1GB) {
            return "{0:N2} GB" -f ($bytes / 1GB)
        }
        elseif ($bytes -ge 1MB) {
            return "{0:N2} MB" -f ($bytes / 1MB)
        }
        elseif ($bytes -ge 1KB) {
            return "{0:N2} KB" -f ($bytes / 1KB)
        }
        else {
            return "$bytes B"
        }
    }
    
    # Function to truncate long strings.
    function Truncate-String {
        param (
            [Parameter(Mandatory = $true)]
            [string]$str,
            [int]$maxLength = 50
        )
        if ($str.Length -gt $maxLength) {
            return $str.Substring(0, $maxLength - 3) + "..."
        }
        else {
            return $str
        }
    }
    
    # Prompt the user for the directory to scan (default is current directory).
    $directory = Read-Host "Enter the directory to scan (or press Enter for current directory)"
    if ([string]::IsNullOrWhiteSpace($directory)) {
        $directory = (Get-Location).Path
    }
    
    if (-not (Test-Path $directory)) {
        Write-Error "Directory '$directory' does not exist."
        exit
    }
    
    # Prompt the user for the number of items to list.
    $numberOfItems = Read-Host "Enter the number of largest files to list"
    if (-not [int]::TryParse($numberOfItems, [ref]$null)) {
        Write-Error "Invalid number entered. Please enter a valid integer."
        exit
    }
    $numberOfItems = [int]$numberOfItems
    
    Write-Host "Scanning directory '$directory' for files..." -ForegroundColor Cyan
    
    # Recursively retrieve all files within the specified directory.
    try {
        $files = Get-ChildItem -Path $directory -File -Recurse -ErrorAction SilentlyContinue
    } catch {
        Write-Error "Error retrieving files: $_"
        exit
    }
    
    if (!$files) {
        Write-Host "No files found in '$directory'."
        exit
    }
    
    # Sort the files by size (Length) descending and take the top N items.
    $largestFiles = $files | Sort-Object Length -Descending | Select-Object -First $numberOfItems
    
    # Build a table with an index and truncated file name and path.
    $i = 1
    $result = foreach ($file in $largestFiles) {
        [PSCustomObject]@{
            Index         = $i
            "File Name"   = Truncate-String -str $file.Name -maxLength 30
            "Full Path"   = Truncate-String -str $file.FullName -maxLength 60
            "Size (Bytes)"= $file.Length
            "Size (Human)"= Convert-BytesToHumanReadable -bytes $file.Length
        }
        $i++
    }
    
    # Display the results in a formatted table.
    Write-Host "`nTop $numberOfItems largest files in '$directory':" -ForegroundColor Green
    $result | Format-Table -AutoSize
    
    # Allow the user to view full details if needed.
    $choice = Read-Host "`nEnter a file index to view full details, type 'all' to view details for all files, or press Enter to exit"
    if (-not [string]::IsNullOrWhiteSpace($choice)) {
        if ($choice -match '^(all)$') {
            Write-Host "`nFull details for all files:" -ForegroundColor Cyan
            $largestFiles | Format-List *
        }
        elseif ([int]::TryParse($choice, [ref]$null)) {
            $index = [int]$choice
            if ($index -ge 1 -and $index -le $largestFiles.Count) {
                Write-Host "`nFull details for file at index $($index):" -ForegroundColor Cyan
                $largestFiles[$index - 1] | Format-List *
            }
            else {
                Write-Host "Invalid index entered." -ForegroundColor Yellow
            }
        }
    }
  • DNS Ping Test Utility PowerShell Script

    This PowerShell script allows users to select from a list of popular DNS servers and perform customizable ping tests to verify network connectivity. It supports both continuous and fixed-count pings, configurable intervals, optional logging, and displays summary statistics for comprehensive network diagnostics.

    Click to view script…
    <#
    .SYNOPSIS
        DNS Ping Test Utility
    
    .DESCRIPTION
        This script allows the user to choose from a list of popular DNS servers (e.g., Google, Cloudflare, OpenDNS, etc.)
        and then performs either continuous or fixed-count ping tests to verify network connectivity.
        Users can configure the interval between pings and optionally log the results to a file for further analysis.
        
    .NOTES
        Press Ctrl+C to exit continuous ping mode.
    #>
    
    # Define a list of DNS providers.
    $dnsProviders = @(
        [PSCustomObject]@{Name="Google DNS";       IP="8.8.8.8"},
        [PSCustomObject]@{Name="Cloudflare DNS";   IP="1.1.1.1"},
        [PSCustomObject]@{Name="OpenDNS";          IP="208.67.222.222"},
        [PSCustomObject]@{Name="Quad9 DNS";        IP="9.9.9.9"},
        [PSCustomObject]@{Name="Level3 DNS";       IP="4.2.2.2"}
    )
    
    # Display the DNS server options.
    Write-Host "Select a DNS server to ping:" -ForegroundColor Cyan
    for ($i = 0; $i -lt $dnsProviders.Count; $i++) {
        Write-Host ("{0}. {1} ({2})" -f ($i + 1), $dnsProviders[$i].Name, $dnsProviders[$i].IP)
    }
    
    # Prompt the user to choose a DNS server.
    [int]$choice = Read-Host "Enter the number corresponding to your choice"
    if ($choice -lt 1 -or $choice -gt $dnsProviders.Count) {
        Write-Error "Invalid selection. Exiting."
        exit
    }
    
    $selectedDNS = $dnsProviders[$choice - 1]
    Write-Host "You selected: $($selectedDNS.Name) ($($selectedDNS.IP))" -ForegroundColor Green
    
    # Ask if the user wants a fixed number of pings or continuous ping.
    $pingCountInput = Read-Host "Enter number of pings (or press Enter for continuous ping)"
    if ($pingCountInput -match '^\d+$') {
        $pingCount = [int]$pingCountInput
        $isContinuous = $false
    } else {
        $isContinuous = $true
    }
    
    # Ask for the interval between pings in seconds.
    $intervalInput = Read-Host "Enter interval in seconds between pings (default is 1 second)"
    if ([string]::IsNullOrWhiteSpace($intervalInput)) {
        $interval = 1
    } else {
        $interval = [double]$intervalInput
    }
    
    # Ask if the user wants to log the results to a file.
    $logChoice = Read-Host "Do you want to log results to a file? (Y/N)"
    $logEnabled = $false
    if ($logChoice -match '^[Yy]') {
        $logEnabled = $true
        $logFile = Read-Host "Enter log file path (or press Enter for default 'DNSPingLog.txt')"
        if ([string]::IsNullOrWhiteSpace($logFile)) {
            $logFile = "DNSPingLog.txt"
        }
        Write-Host "Logging enabled. Results will be saved to $logFile" -ForegroundColor Green
    }
    
    # Initialize an array to store successful ping response times if a fixed ping count is specified.
    if (-not $isContinuous) {
        $results = @()
    }
    
    Write-Host "Starting ping test to $($selectedDNS.IP)..." -ForegroundColor Cyan
    
    # Function to log output if logging is enabled.
    function Log-Output {
        param (
            [string]$message
        )
        if ($logEnabled) {
            $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            Add-Content -Path $logFile -Value "[$timestamp] $message"
        }
    }
    
    # Run the ping test.
    if ($isContinuous) {
        Write-Host "Press Ctrl+C to stop continuous ping."
        while ($true) {
            try {
                $pingResult = Test-Connection -ComputerName $selectedDNS.IP -Count 1 -ErrorAction SilentlyContinue
                $timestamp = Get-Date -Format "HH:mm:ss"
                if ($pingResult) {
                    $replyTime = $pingResult.ResponseTime
                    $output = "[$timestamp] Ping $($i)/$($pingCount): Reply from $($selectedDNS.IP): time = $replyTime ms"
                } else {
                    $output = "[$timestamp] Ping $($i)/$($pingCount): Request timed out for $($selectedDNS.IP)."
                }
                Write-Host $output
                Log-Output -message $output
            }
            catch {
                Write-Host "An error occurred: $_"
                Log-Output -message "Error: $_"
            }
            Start-Sleep -Seconds $interval
        }
    } else {
        for ($i = 1; $i -le $pingCount; $i++) {
            try {
                $pingResult = Test-Connection -ComputerName $selectedDNS.IP -Count 1 -ErrorAction SilentlyContinue
                $timestamp = Get-Date -Format "HH:mm:ss"
                if ($pingResult) {
                    $replyTime = $pingResult.ResponseTime
                    $output = "[$timestamp] Ping $($i)/$($pingCount): Reply from $($selectedDNS.IP): time = $replyTime ms"
                    $results += $replyTime
                } else {
                    $output = "[$timestamp] Ping $($i)/$($pingCount): Request timed out for $($selectedDNS.IP)."
                }
                Write-Host $output
                Log-Output -message $output
            }
            catch {
                Write-Host "An error occurred: $_"
                Log-Output -message "Error: $_"
            }
            Start-Sleep -Seconds $interval
        }
        
        # Provide summary statistics for the fixed-count ping test.
        if ($results.Count -gt 0) {
            $avgTime = [Math]::Round(($results | Measure-Object -Average).Average, 2)
            Write-Host "`nPing test completed. Average response time: $avgTime ms" -ForegroundColor Green
            Log-Output -message "Ping test completed. Average response time: $avgTime ms"
        } else {
            Write-Host "`nPing test completed. No successful pings." -ForegroundColor Yellow
            Log-Output -message "Ping test completed. No successful pings."
        }
    }
  • User Account Audit with Net User Parsing PowerShell Script

    This PowerShell script audits local user accounts by listing each account’s enabled/disabled status and extracting detailed last logon information using the net user command. It outputs a neatly formatted table, providing system administrators with a clear snapshot of user account activity for easier monitoring and troubleshooting.

    Click to view script…
    <#
    .SYNOPSIS
        Audits local user accounts by listing their enabled/disabled status and last logon time.
    
    .DESCRIPTION
        This script retrieves local user accounts using Get-LocalUser and then obtains last logon information
        for each account by parsing the output of the "net user" command. It outputs a table showing each account's name,
        whether it is enabled, and its last logon time (or "Never" if the account has not logged on).
    
    .NOTES
        Run as Administrator if necessary.
    #>
    
    function Get-LastLogonNetUser {
        param (
            [Parameter(Mandatory = $true)]
            [string]$UserName
        )
    
        # Execute the "net user" command for the given user
        $netUserOutput = net user $UserName 2>&1
    
        # Look for a line that contains "Last logon"
        $lastLogonLine = $netUserOutput | Where-Object { $_ -match "Last logon" }
        if ($lastLogonLine) {
            # The expected format is something like:
            #   Last logon                   2/12/2021 3:45:30 PM
            # Remove the label text and trim spaces to isolate the date/time string.
            $logonValue = ($lastLogonLine -replace ".*Last logon\s+", "").Trim()
            if ($logonValue -match "Never") {
                return "Never"
            }
            else {
                # Attempt to parse the logon value as a DateTime.
                try {
                    $dt = [DateTime]::Parse($logonValue)
                    return $dt
                }
                catch {
                    return $logonValue
                }
            }
        }
        else {
            return "Unknown"
        }
    }
    
    # Retrieve local user accounts.
    try {
        $localUsers = Get-LocalUser
    } catch {
        Write-Error "Failed to retrieve local users. Ensure this is run on a supported version of Windows with appropriate permissions."
        exit
    }
    
    # Prepare an array to store the audit results.
    $result = @()
    
    foreach ($user in $localUsers) {
        $userName = $user.Name
        $lastLogon = Get-LastLogonNetUser -UserName $userName
    
        $result += [PSCustomObject]@{
            Name      = $userName
            Enabled   = $user.Enabled
            LastLogon = $lastLogon
        }
    }
    
    # Output the results in a formatted table.
    $result | Format-Table -AutoSize
  • Live Stock Price Tracker Python Script

    This Python script fetches live stock prices for a specified ticker using the yfinance library and logs the data with a timestamp into a CSV file for further analysis. It provides an easy way to monitor and record real-time market price movements.

    If you haven’t installed yfinance yet, you can easily add it by running the following command in your terminal:

    pip install yfinance
    Click to view script…
    #!/usr/bin/env python3
    import yfinance as yf
    import csv
    import os
    from datetime import datetime
    
    def fetch_stock_price(ticker_symbol):
        """
        Fetches the current stock price for the given ticker symbol using yfinance.
        It first tries to get the 'regularMarketPrice' from the ticker info.
        If that fails, it falls back to using the latest close price from recent historical data.
        """
        ticker = yf.Ticker(ticker_symbol)
        try:
            # Attempt to get the live price from the info dictionary
            info = ticker.info
            price = info.get("regularMarketPrice", None)
            if price is None:
                # Fallback: get the most recent closing price from historical data
                data = ticker.history(period="1d", interval="1m")
                price = data["Close"].iloc[-1]
        except Exception as e:
            print(f"Error fetching data for {ticker_symbol}: {e}")
            return None
        return price
    
    def store_stock_price(ticker_symbol, price, filename="stock_prices.csv"):
        """
        Stores the fetched stock price along with a timestamp and the ticker symbol into a CSV file.
        If the file does not exist, it creates one with appropriate headers.
        """
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        header = ["timestamp", "ticker", "price"]
        file_exists = os.path.isfile(filename)
        
        with open(filename, mode="a", newline="") as file:
            writer = csv.writer(file)
            if not file_exists:
                writer.writerow(header)
            writer.writerow([now, ticker_symbol, price])
        
        print(f"Stored price for {ticker_symbol} at {now} in {filename}.")
    
    def main():
        print("Stock Price Tracker")
        print("-------------------")
        print("Fetches live stock prices and stores them for analysis.\n")
        
        ticker_symbol = input("Enter the stock ticker (e.g., AAPL): ").strip().upper()
        if not ticker_symbol:
            print("No ticker entered. Exiting.")
            return
        
        price = fetch_stock_price(ticker_symbol)
        if price is not None:
            print(f"Current price of {ticker_symbol}: ${price:.2f}")
            store_stock_price(ticker_symbol, price)
        else:
            print("Failed to fetch stock price.")
    
    if __name__ == "__main__":
        main()