Category: macOS

  • Smart Finder Tabs Launcher for macOS AppleScript

    This AppleScript streamlines your Finder workspace by checking for an existing Finder window and reusing it to open specified folders as individual tabs, thereby avoiding duplicate windows or tabs. Customize the folders by editing the definitions at the top of the script.

    The folder paths are defined near the beginning of the script. For example, you can customize the following lines to change which folders open:

    set docsFolder to (path to documents folder)
    set desktopFolder to (path to desktop folder)
    set downloadsFolder to (path to downloads folder)


    Simply modify these variables to point to your desired folder paths.

    Click to view script…
    -- Title: Finder Tabs Organizer
    -- Description:
    -- This AppleScript opens designated folders as tabs in Finder
    -- Customize the folders to open by modifying the folder definitions below.
    
    -- Handler to open a new tab for a given folder
    on openNewTabWithFolder(theFolder)
        tell application "System Events"
            keystroke "t" using {command down} -- simulate Command+T to open a new tab
        end tell
        delay 0.5
        tell application "Finder"
            set target of front Finder window to theFolder
        end tell
    end openNewTabWithFolder
    
    -- Define the folders to open
    set docsFolder to (path to documents folder)
    set desktopFolder to (path to desktop folder)
    set downloadsFolder to (path to downloads folder)
    
    tell application "Finder"
        activate
        if (count of Finder windows) > 0 then
            -- Use the existing Finder window and set its target to Documents
            set target of front Finder window to docsFolder
        else
            -- No window exists, so open a new window for Documents
            open docsFolder
        end if
    end tell
    
    delay 0.5
    
    -- Open additional tabs for the other folders.
    openNewTabWithFolder(desktopFolder)
    openNewTabWithFolder(downloadsFolder)

  • macOS User Login and Uptime Report Bash Script

    This script provides system administrators with a clear overview of the system’s current uptime and detailed last login information for human user accounts (UID ≥ 500). It displays key details such as the terminal, login date, login time, and session status for each account.

    Click to view script…
    #!/bin/bash
    # Title: Detailed macOS User Last Login Checker with System Uptime
    # Description:
    # This script lists human user accounts (UID ≥ 500) on macOS and displays detailed information about their last login session.
    # It also shows the current system uptime at the top.
    #
    # The output includes:
    #   - System Uptime: How long the machine has been running since the last boot.
    #   - Username     : The account name.
    #   - Terminal     : The terminal device used during login.
    #   - Login Date   : The date of the login (Day Month Date).
    #   - Login Time   : The time when the login occurred.
    #   - Login Status : Indicates if the session is still active or has ended.
    #
    # Note: "Never logged in" is shown if no login record exists.
    #
    # Retrieve and display system uptime
    systemUptime=$(uptime)
    echo "System Uptime: $systemUptime"
    echo ""
    
    # Print header for the login details
    echo "Username | Terminal | Login Date       | Login Time | Login Status"
    echo "---------------------------------------------------------------------"
    
    # List users with their UniqueIDs and process each one.
    dscl . -list /Users UniqueID | while read username uid; do
        if [ "$uid" -ge 500 ]; then
            # Retrieve the most recent login record for the user
            loginInfo=$(last -1 "$username" | head -n 1)
            
            # Check if there is a valid login record
            if echo "$loginInfo" | grep -q "wtmp begins"; then
                echo "$username |    -     |       -        |     -    | Never logged in"
            else
                # Parse the login record:
                #   Field 1: Username (redundant here)
                #   Field 2: Terminal (e.g., ttys000)
                #   Fields 3-5: Login Date (e.g., "Mon Feb 17")
                #   Field 6: Login Time (e.g., "05:44")
                #   Fields 7+: Login Status (e.g., "still logged in" or the session end time)
                terminal=$(echo "$loginInfo" | awk '{print $2}')
                login_date=$(echo "$loginInfo" | awk '{print $3, $4, $5}')
                login_time=$(echo "$loginInfo" | awk '{print $6}')
                login_status=$(echo "$loginInfo" | cut -d' ' -f7-)
                
                # Output the parsed details in a table-like format
                printf "%-8s | %-8s | %-16s | %-10s | %s\n" "$username" "$terminal" "$login_date" "$login_time" "$login_status"
            fi
        fi
    done
    
    # Legend:
    #   System Uptime - How long the system has been running since the last boot.
    #   Username      - The account name.
    #   Terminal      - The terminal device used during login.
    #   Login Date    - The date of the login (Day Month Date).
    #   Login Time    - The time of the login.
    #   Login Status  - The current status of the login session.
  • Enhanced macOS User Account Details Bash Script

    This Bash script retrieves and displays detailed information for all human user accounts (UID ≥ 500) on macOS, including the username, UID, admin privileges, full name, home directory, and default shell. It provides a clear and organized summary that is useful for system administrators to review and manage user configurations.

    Click to view script…
    #!/bin/bash
    # This script lists user accounts (UID >= 500) and shows additional details:
    # Username, UID, Admin Privileges (true/false), Full Name, Home Directory, and Shell
    
    # Print header for clarity
    echo "Username : UID : Has Admin Privileges : Full Name : Home Directory : Shell"
    
    # List all users with their UniqueID and process each line
    dscl . -list /Users UniqueID | while read username uid; do
        # Only process accounts with UID >= 500 (typically non-system, human user accounts)
        if [ "$uid" -ge 500 ]; then
            # Check if the user belongs to the 'admin' group
            if id -Gn "$username" 2>/dev/null | grep -qw "admin"; then
                adminFlag="true"
            else
                adminFlag="false"
            fi
    
            # Get the user's full name (if set). The command outputs a line like "RealName: John Doe"
            fullName=$(dscl . -read /Users/"$username" RealName 2>/dev/null | sed 's/RealName: //')
            
            # Get the user's home directory
            homeDir=$(dscl . -read /Users/"$username" NFSHomeDirectory 2>/dev/null | sed 's/NFSHomeDirectory: //')
            
            # Get the user's default shell
            shell=$(dscl . -read /Users/"$username" UserShell 2>/dev/null | sed 's/UserShell: //')
            
            # Output the collected information in a clear, colon-separated format
            echo "$username : $uid : $adminFlag : $fullName : $homeDir : $shell"
        fi
    done
  • Scheduled URL Launcher AppleScript

    This AppleScript prompts the user to input multiple URLs and offers a choice to open them immediately or after a countdown timer. For immediate launches, it confirms the URLs before opening, while for countdown mode it notifies the user that the countdown has started and then provides a final confirmation after the URLs have been opened.

    Click to view script…
    -- Create a large default text field by including multiple line breaks
    set multiLineDefault to return & return & return & return
    
    -- Prompt the user for a list of URLs (one URL per line)
    set urlInput to text returned of (display dialog "Enter list of URLs (one per line):" default answer multiLineDefault)
    
    -- Split the input into a list of lines
    set urlList to paragraphs of urlInput
    
    -- Ask the user if they want to open the URLs now or after a countdown
    set schedulingOption to button returned of (display dialog "Choose when to open the URLs:" buttons {"Now", "Countdown"} default button "Now")
    
    if schedulingOption is "Now" then
    	-- Build a confirmation message listing the URLs to be opened immediately
    	set confirmDialogText to "The following URLs will be opened now:" & return & return
    	repeat with aURL in urlList
    		set trimmedURL to trimWhitespace(aURL)
    		if trimmedURL is not "" then
    			-- Prepend protocol if missing
    			if (trimmedURL does not start with "http://") and (trimmedURL does not start with "https://") then
    				set trimmedURL to "https://" & trimmedURL
    			end if
    			set confirmDialogText to confirmDialogText & trimmedURL & return
    		end if
    	end repeat
    	
    	-- Show confirmation dialog before launching
    	set confirmResponse to button returned of (display dialog confirmDialogText buttons {"Cancel", "Open Now"} default button "Open Now")
    	if confirmResponse is "Cancel" then return
    	
    	-- Open URLs immediately
    	repeat with aURL in urlList
    		set trimmedURL to trimWhitespace(aURL)
    		if trimmedURL is not "" then
    			if (trimmedURL does not start with "http://") and (trimmedURL does not start with "https://") then
    				set trimmedURL to "https://" & trimmedURL
    			end if
    			open location trimmedURL
    		end if
    	end repeat
    	
    else if schedulingOption is "Countdown" then
    	-- Prompt for countdown seconds
    	set countdownInput to text returned of (display dialog "Enter countdown time in seconds:" default answer "10")
    	try
    		set countdownSeconds to countdownInput as integer
    	on error
    		display dialog "Invalid number. Exiting." buttons {"OK"} default button "OK"
    		return
    	end try
    	
    	-- Notify the user that the countdown is starting
    	display dialog "Countdown started for " & countdownSeconds & " seconds. The URLs will open automatically afterwards." buttons {"OK"} default button "OK"
    	
    	-- Delay for the specified number of seconds
    	delay countdownSeconds
    	
    	-- Open URLs after the delay
    	repeat with aURL in urlList
    		set trimmedURL to trimWhitespace(aURL)
    		if trimmedURL is not "" then
    			if (trimmedURL does not start with "http://") and (trimmedURL does not start with "https://") then
    				set trimmedURL to "https://" & trimmedURL
    			end if
    			open location trimmedURL
    		end if
    	end repeat
    	
    	-- Build a final confirmation message listing the URLs that were opened
    	set finalConfirmDialogText to "The following URLs have been opened:" & return & return
    	repeat with aURL in urlList
    		set trimmedURL to trimWhitespace(aURL)
    		if trimmedURL is not "" then
    			if (trimmedURL does not start with "http://") and (trimmedURL does not start with "https://") then
    				set trimmedURL to "https://" & trimmedURL
    			end if
    			set finalConfirmDialogText to finalConfirmDialogText & trimmedURL & return
    		end if
    	end repeat
    	
    	-- Show the final confirmation dialog
    	display dialog finalConfirmDialogText buttons {"OK"} default button "OK"
    end if
    
    --------------------------------------------------------------------------------
    -- Helper Handler: trimWhitespace
    -- Removes leading and trailing whitespace from a string
    --------------------------------------------------------------------------------
    on trimWhitespace(theText)
    	set AppleScript's text item delimiters to {" ", tab, return, linefeed}
    	set textItems to text items of theText
    	set AppleScript's text item delimiters to space
    	set trimmed to textItems as text
    	set AppleScript's text item delimiters to ""
    	return trimmed
    end trimWhitespace
  • Interactive Image Converter Swift Script

    This Swift script guides users through selecting an input image from common directories using numbered lists and then converting it to a desired format (PNG, JPEG, or TIFF) while also letting them choose an output directory and filename. It simplifies the image conversion process on macOS by providing an interactive, user-friendly interface.

    Click to view script…
    #!/usr/bin/env swift
    import Foundation
    import AppKit
    
    // MARK: - Helper Functions
    
    /// Prompts the user for input with a message.
    func prompt(_ message: String) -> String {
        print(message, terminator: " ")
        return readLine() ?? ""
    }
    
    /// Presents a numbered list of directory options to the user and returns the selected directory URL.
    func selectDirectory(options: [(name: String, url: URL)], promptMessage: String) -> URL {
        for (index, option) in options.enumerated() {
            print("\(index + 1): \(option.name) -> \(option.url.path)")
        }
        let choiceStr = prompt(promptMessage)
        if let choiceNum = Int(choiceStr), choiceNum > 0, choiceNum <= options.count {
            let selected = options[choiceNum - 1]
            if selected.name.hasPrefix("Other") {
                let customPath = prompt("Enter custom directory path:")
                return URL(fileURLWithPath: customPath, isDirectory: true)
            } else {
                return selected.url
            }
        } else {
            let manualPath = prompt("Invalid selection. Enter directory path manually:")
            return URL(fileURLWithPath: manualPath, isDirectory: true)
        }
    }
    
    /// Presents a numbered list of files for the user to choose from.
    func selectFile(from files: [URL], in directory: URL) -> URL {
        for (index, file) in files.enumerated() {
            print("\(index + 1): \(file.lastPathComponent)")
        }
        let choiceStr = prompt("Enter the number of your choice:")
        if let choiceNum = Int(choiceStr), choiceNum > 0, choiceNum <= files.count {
            return files[choiceNum - 1]
        } else {
            let manualFile = prompt("Invalid selection. Enter the file name (in \(directory.path)):")
            return directory.appendingPathComponent(manualFile)
        }
    }
    
    /// Converts a file size (in bytes) to a human-readable string.
    func humanReadableSize(_ size: UInt64) -> String {
        let formatter = ByteCountFormatter()
        formatter.countStyle = .file
        formatter.allowedUnits = [.useKB, .useMB, .useGB, .useTB]
        return formatter.string(fromByteCount: Int64(size))
    }
    
    // MARK: - Candidate Directories Setup
    
    let fileManager = FileManager.default
    var candidateDirs: [(name: String, url: URL)] = []
    
    if let desktop = fileManager.urls(for: .desktopDirectory, in: .userDomainMask).first {
        candidateDirs.append(("Desktop", desktop))
    }
    if let documents = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
        candidateDirs.append(("Documents", documents))
    }
    if let downloads = fileManager.urls(for: .downloadsDirectory, in: .userDomainMask).first {
        candidateDirs.append(("Downloads", downloads))
    }
    candidateDirs.append(("Other (enter path manually)", URL(fileURLWithPath: fileManager.currentDirectoryPath)))
    
    // MARK: - Input Directory and File Selection
    
    print("Select the input directory:")
    let inputDirectory = selectDirectory(options: candidateDirs, promptMessage: "Enter the number of your choice:")
    
    // Verify the input directory exists.
    var isDir: ObjCBool = false
    guard fileManager.fileExists(atPath: inputDirectory.path, isDirectory: &isDir), isDir.boolValue else {
        print("Directory \(inputDirectory.path) does not exist or is not a directory.")
        exit(1)
    }
    
    // Define supported image extensions.
    let validImageExtensions: Set<String> = ["png", "jpg", "jpeg", "tiff", "gif"]
    
    // Get and filter files in the chosen directory.
    guard let filesInDirectory = try? fileManager.contentsOfDirectory(at: inputDirectory,
                                                                       includingPropertiesForKeys: nil,
                                                                       options: [.skipsHiddenFiles]) else {
        print("Unable to read contents of directory \(inputDirectory.path)")
        exit(1)
    }
    let imageFiles = filesInDirectory.filter { validImageExtensions.contains($0.pathExtension.lowercased()) }
    
    if imageFiles.isEmpty {
        print("No image files found in \(inputDirectory.path)")
        exit(1)
    }
    
    print("\nSelect the image file to convert:")
    let inputFileURL = selectFile(from: imageFiles, in: inputDirectory)
    
    // Optionally, display file size.
    if let attrs = try? fileManager.attributesOfItem(atPath: inputFileURL.path),
       let fileSize = attrs[.size] as? UInt64 {
        print("Selected file: \(inputFileURL.lastPathComponent) (\(humanReadableSize(fileSize)))")
    }
    
    // MARK: - Output Format Selection
    
    print("\nSelect the desired output image format:")
    print("1: PNG")
    print("2: JPEG")
    print("3: TIFF")
    let formatChoiceStr = prompt("Enter the number of your choice:")
    var outputFileType: NSBitmapImageRep.FileType
    var outputExtension: String
    
    switch formatChoiceStr {
    case "1":
        outputFileType = .png
        outputExtension = "png"
    case "2":
        outputFileType = .jpeg
        outputExtension = "jpg"
    case "3":
        outputFileType = .tiff
        outputExtension = "tiff"
    default:
        print("Invalid selection.")
        exit(1)
    }
    
    // MARK: - Output Directory and File Name Selection
    
    print("\nSelect the output directory:")
    let outputDirectory = selectDirectory(options: candidateDirs, promptMessage: "Enter the number of your choice:")
    
    isDir = false
    guard fileManager.fileExists(atPath: outputDirectory.path, isDirectory: &isDir), isDir.boolValue else {
        print("Output directory \(outputDirectory.path) does not exist or is not a directory.")
        exit(1)
    }
    
    let defaultOutputName = inputFileURL.deletingPathExtension().lastPathComponent + "_converted." + outputExtension
    let outputFileName = prompt("Enter output file name (default: \(defaultOutputName)):")
    let finalOutputFileName = outputFileName.isEmpty ? defaultOutputName : outputFileName
    let outputFileURL = outputDirectory.appendingPathComponent(finalOutputFileName)
    
    // MARK: - Image Conversion
    
    print("\nConverting image...")
    
    guard let inputImage = NSImage(contentsOf: inputFileURL) else {
        print("Failed to load image from \(inputFileURL.path)")
        exit(1)
    }
    guard let tiffData = inputImage.tiffRepresentation else {
        print("Failed to get TIFF representation of the image.")
        exit(1)
    }
    guard let bitmapRep = NSBitmapImageRep(data: tiffData) else {
        print("Failed to create bitmap representation.")
        exit(1)
    }
    guard let outputImageData = bitmapRep.representation(using: outputFileType, properties: [:]) else {
        print("Failed to convert image to selected format.")
        exit(1)
    }
    
    do {
        try outputImageData.write(to: outputFileURL)
        print("Image successfully converted and saved to \(outputFileURL.path)")
    } catch {
        print("Error saving converted image: \(error)")
        exit(1)
    }
  • macOS File Finder Swift Script

    This Swift script allows users to search for files of a specific type in a chosen directory on macOS. It interactively prompts for a directory (from common options or a custom path) and a file extension, then recursively locates matching files and displays their names along with human-readable file sizes.

    Click to view script…
    #!/usr/bin/env swift
    
    import Foundation
    
    // MARK: - Helper: Format File Size in Human-Readable Format
    func humanReadableSize(_ size: UInt64) -> String {
        let formatter = ByteCountFormatter()
        formatter.countStyle = .file
        // Allow units from bytes up to TB
        formatter.allowedUnits = [.useKB, .useMB, .useGB, .useTB]
        return formatter.string(fromByteCount: Int64(size))
    }
    
    // MARK: - Helper: Prompt for User Input
    func prompt(_ message: String) -> String {
        print(message, terminator: " ")
        return readLine() ?? ""
    }
    
    // MARK: - Prepare Candidate Directories
    let fileManager = FileManager.default
    var candidateDirectories: [String: URL] = [:]
    
    if let desktopURL = fileManager.urls(for: .desktopDirectory, in: .userDomainMask).first {
        candidateDirectories["Desktop"] = desktopURL
    }
    if let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
        candidateDirectories["Documents"] = documentsURL
    }
    if let downloadsURL = fileManager.urls(for: .downloadsDirectory, in: .userDomainMask).first {
        candidateDirectories["Downloads"] = downloadsURL
    }
    // Provide an option for a custom directory.
    candidateDirectories["Other"] = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
    
    // MARK: - Display Directory Options
    print("Select a directory to search in:")
    let directoryKeys = Array(candidateDirectories.keys).sorted() // sorted for consistent ordering
    for (index, key) in directoryKeys.enumerated() {
        if key == "Other" {
            print("\(index + 1): Enter a custom directory path")
        } else if let url = candidateDirectories[key] {
            print("\(index + 1): \(key) -> \(url.path)")
        }
    }
    
    guard let dirChoiceStr = readLine(), let choiceNum = Int(dirChoiceStr),
          choiceNum > 0, choiceNum <= directoryKeys.count else {
        print("Invalid directory choice. Exiting.")
        exit(1)
    }
    
    let chosenKey = directoryKeys[choiceNum - 1]
    var searchDirectory: URL
    
    if chosenKey == "Other" {
        let customPath = prompt("Enter full directory path:")
        searchDirectory = URL(fileURLWithPath: customPath, isDirectory: true)
    } else {
        searchDirectory = candidateDirectories[chosenKey]!
    }
    
    // Verify the directory exists
    var isDir: ObjCBool = false
    guard fileManager.fileExists(atPath: searchDirectory.path, isDirectory: &isDir), isDir.boolValue else {
        print("The selected path does not exist or is not a directory. Exiting.")
        exit(1)
    }
    
    // MARK: - Get File Extension to Search For
    let fileExtensionInput = prompt("Enter file extension to search for (e.g., txt, pdf, jpg):")
    let fileExtension = fileExtensionInput.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
    
    if fileExtension.isEmpty {
        print("No file extension provided. Exiting.")
        exit(1)
    }
    
    // Validate file extension (alphanumeric only)
    let regex = try! NSRegularExpression(pattern: "^[a-zA-Z0-9]+$")
    let range = NSRange(location: 0, length: fileExtension.utf16.count)
    if regex.firstMatch(in: fileExtension, options: [], range: range) == nil {
        print("Invalid file extension provided. Exiting.")
        exit(1)
    }
    
    // MARK: - Search for Files
    print("\nSearching for .\(fileExtension) files in \(searchDirectory.path)...")
    
    guard let enumerator = fileManager.enumerator(at: searchDirectory,
                                                    includingPropertiesForKeys: [.fileSizeKey],
                                                    options: [.skipsHiddenFiles],
                                                    errorHandler: { (url, error) -> Bool in
                                                        print("Error accessing \(url.path): \(error.localizedDescription)")
                                                        return true
                                                    }) else {
        print("Failed to create directory enumerator. Exiting.")
        exit(1)
    }
    
    var foundFiles: [(url: URL, size: UInt64)] = []
    
    while let fileURL = enumerator.nextObject() as? URL {
        if fileURL.pathExtension.lowercased() == fileExtension {
            do {
                let resourceValues = try fileURL.resourceValues(forKeys: [.fileSizeKey])
                if let fileSize = resourceValues.fileSize {
                    foundFiles.append((fileURL, UInt64(fileSize)))
                }
            } catch {
                print("Error getting size for \(fileURL.path): \(error.localizedDescription)")
            }
        }
    }
    
    // MARK: - Display Results
    if foundFiles.isEmpty {
        print("No files with .\(fileExtension) extension were found in \(searchDirectory.path).")
    } else {
        print("\nFound \(foundFiles.count) file(s):")
        for (file, size) in foundFiles {
            print("\(file.lastPathComponent) - \(humanReadableSize(size))")
        }
    }
  • macOS App Version Finder Bash Script

    This interactive script scans your /Applications and ~/Applications directories to list installed apps, allowing you to select one and view its version. It supports multiple searches and includes a built-in quit option for easy use.

    Click to view script…
    #!/bin/bash
    # Interactive App Version Finder for macOS with multi-search capability
    
    # Define directories to search for applications.
    APP_DIRS=("/Applications" "$HOME/Applications")
    
    # Initialize an array to store found apps.
    apps=()
    
    # Search for .app directories (non-recursive) in defined directories.
    for dir in "${APP_DIRS[@]}"; do
      if [ -d "$dir" ]; then
        while IFS= read -r -d $'\0' app; do
          apps+=("$app")
        done < <(find "$dir" -maxdepth 1 -type d -name "*.app" -print0)
      fi
    done
    
    # Check if any apps were found.
    if [ ${#apps[@]} -eq 0 ]; then
      echo "No applications found in ${APP_DIRS[*]}."
      exit 1
    fi
    
    # Main interactive loop.
    while true; do
      echo ""
      echo "Available Applications:"
      for i in "${!apps[@]}"; do
        echo "[$i] $(basename "${apps[$i]}")"
      done
      echo "[q] Quit"
      
      read -p "Enter the number of the app to check its version (or 'q' to quit): " input
    
      # Check for the quit option.
      if [[ "$input" =~ ^[Qq]$ ]]; then
        echo "Exiting."
        exit 0
      fi
    
      # Validate input is a number and within range.
      if ! [[ "$input" =~ ^[0-9]+$ ]] || [ "$input" -ge "${#apps[@]}" ]; then
        echo "Invalid selection. Please try again."
        continue
      fi
    
      APP_PATH="${apps[$input]}"
      APP_NAME=$(basename "$APP_PATH" .app)
    
      # Retrieve the version information from the app's Info.plist.
      VERSION=$(defaults read "$APP_PATH/Contents/Info" CFBundleShortVersionString 2>/dev/null)
    
      if [ -z "$VERSION" ]; then
        echo "Version information not found for $APP_NAME."
      else
        echo "$APP_NAME version: $VERSION"
      fi
    
      echo ""
      # Ask if the user wants to perform another search.
      read -p "Do you want to search for another app? (y/n): " answer
      if [[ ! "$answer" =~ ^[Yy]$ ]]; then
        echo "Exiting."
        exit 0
      fi
    done
  • 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