Discover powerful PowerShell programs and scripts to automate tasks, manage systems, and enhance productivity. Learn to create, customize, and implement efficient PowerShell solutions for Windows administration, network management, and more. Explore expert tips, best practices, and real-world examples to master PowerShell programming and streamline your IT operations.

RDS User Disconnected Monitor and Action Script

<#
.SYNOPSIS
RDS User Disconnected Monitor and Action Script

.DESCRIPTION
This script monitors Remote Desktop Services for disconnected user sessions
and performs specified actions when a user disconnects.

.PARAMETER Action
The action to perform when a user disconnects. Options are 'Log', 'Logoff', or 'Both'.

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

.EXAMPLE
.\RDSDisconnectMonitor.ps1 -Action "Log" -LogFile "C:\Logs\RDSDisconnects.log"

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

param (
    [Parameter(Mandatory=$true)]
    [ValidateSet("Log", "Logoff", "Both")]
    [string]$Action,

    [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 get disconnected sessions
function Get-DisconnectedSessions {
    $sessions = quser | Where-Object { $_ -match 'Disc' }
    $disconnectedUsers = @()
    foreach ($session in $sessions) {
        $sessionInfo = $session -split '\s+'
        $disconnectedUsers += [PSCustomObject]@{
            Username = $sessionInfo[1]
            SessionID = $sessionInfo[2]
        }
    }
    return $disconnectedUsers
}

# Function to perform action on disconnected session
function Perform-Action {
    param (
        [string]$Username,
        [string]$SessionID
    )

    switch ($Action) {
        "Log" {
            Write-Log "User disconnected: $Username (Session ID: $SessionID)"
        }
        "Logoff" {
            logoff $SessionID
            Write-Log "User logged off: $Username (Session ID: $SessionID)"
        }
        "Both" {
            Write-Log "User disconnected: $Username (Session ID: $SessionID)"
            logoff $SessionID
            Write-Log "User logged off: $Username (Session ID: $SessionID)"
        }
    }
}

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

Write-Log "Starting RDS disconnect monitoring..."

# Main monitoring loop
try {
    $previousSessions = @()
    while ($true) {
        $currentSessions = Get-DisconnectedSessions
        
        # Check for new disconnections
        foreach ($session in $currentSessions) {
            if ($session.Username -notin $previousSessions.Username) {
                Perform-Action -Username $session.Username -SessionID $session.SessionID
            }
        }

        $previousSessions = $currentSessions
        Start-Sleep -Seconds 30  # Check every 30 seconds
    }
}
catch {
    Write-Log "An error occurred: $_"
}
finally {
    Write-Log "RDS disconnect monitoring stopped."
}

To use this script:

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

.\RDSDisconnectMonitor.ps1 -Action "Log" -LogFile "C:\Logs\RDSDisconnects.log"

You can replace “Log” with “Logoff” to automatically log off disconnected users, or “Both” to log and then log off.

Key features of this script:

  1. Monitoring: Continuously checks for disconnected RDS sessions.
  2. Flexible Actions: Can log disconnections, automatically log off disconnected users, or both.
  3. Logging: Records all actions and events to a specified log file.
  4. Customizable: Easy to modify for additional actions or different checking intervals.

Notes:

  • This script needs to be run with administrator privileges on the RDS server.
  • The script will continue running until manually stopped (e.g., by pressing Ctrl+C).
  • For production use, consider running this script as a Windows Service or scheduled task.
  • The script checks for disconnections every 30 seconds by default. You can adjust this interval by changing the Start-Sleep -Seconds 30 line.
  • Be cautious when using the “Logoff” action, as it will forcibly close user sessions, which might result in data loss if users have unsaved work.

This script provides a foundation for monitoring and managing disconnected RDS sessions. You can further customize it based on your specific requirements, such as sending notifications, integrating with other systems, or implementing more complex decision logic for when to log off users.

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.

Creating Best Practices for PowerShell Functions

Functions are a fundamental building block in PowerShell, allowing you to encapsulate reusable code and make your scripts more modular and maintainable. However, to ensure your functions are well-designed and follow best practices, there are several guidelines you should consider. In this post, we’ll explore some of the best practices for creating PowerShell functions.

1. Use Meaningful Function Names

The name of your function should be descriptive and convey the purpose of the function. Avoid using generic names like “DoSomething” or “ProcessData”. Instead, use names that clearly indicate what the function does, such as “Get-UserInfo” or “Convert-StringToInt”.

2. Provide Detailed Function Documentation

Every function should have a well-written help comment block that includes a description of the function, its parameters, return values, and any relevant examples. This documentation will not only help other users understand how to use your function, but it will also serve as a reference for you when you need to revisit the function in the future.

3. Use Consistent Parameter Naming

When defining the parameters for your function, use consistent naming conventions. This will make your functions more intuitive and easier to use. For example, if you have a function that takes a file path as input, use a parameter name like “FilePath” rather than “Path” or “FileName”.

4. Validate Input Parameters

Always validate the input parameters to your function to ensure that they are of the expected type and within the expected range of values. This will help prevent errors and unexpected behavior in your functions.

5. Use Appropriate Data Types

Choose the appropriate data types for your function’s parameters and return values. This will help ensure that your function behaves as expected and interoperates well with other PowerShell cmdlets and functions.

6. Provide Meaningful Error Handling

When your function encounters an error, provide meaningful error messages that explain what went wrong and how the user can resolve the issue. Use the throw statement to raise exceptions and provide detailed error information.

7. Implement Robust Error Handling

Use try-catch blocks to handle exceptions that may occur within your function. This will help ensure that your function gracefully handles errors and doesn’t crash unexpectedly.

8. Use Appropriate Cmdlet Verbs

When naming your functions, use the appropriate cmdlet verbs as defined by the PowerShell team. This will help ensure that your functions follow the PowerShell naming conventions and are more easily recognized by other PowerShell users.

9. Provide Examples and Samples

Include examples and sample usage in your function’s help documentation to help users understand how to use your function effectively.

10. Test Your Functions Thoroughly

Before releasing your functions, test them thoroughly to ensure they work as expected and handle edge cases appropriately.

By following these best practices, you can create PowerShell functions that are well-designed, maintainable, and easy to use. This will not only benefit you as the function author, but also the users who will be consuming your functions.

Sample script:

<#
.SYNOPSIS
    Retrieves user information from Active Directory.
.DESCRIPTION
    This function retrieves user information from Active Directory, including the user's name, email address, and department.
.PARAMETER UserPrincipalName
    The user's principal name (e.g., "user@powershellblog.com").
.EXAMPLE
    Get-UserInfo -UserPrincipalName "user@powershellblog.com"
    Retrieves the user information for the user with the principal name "user@powershellblog.com".
.NOTES
    This function requires the ActiveDirectory module to be installed and the user running the script to have the necessary permissions to query Active Directory.
#>
function Get-UserInfo {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, HelpMessage="Enter the user's principal name.")]
        [ValidateNotNullOrEmpty()]
        [string]$UserPrincipalName
    )

    try {
        # Retrieve the user object from Active Directory
        $user = Get-ADUser -Filter "UserPrincipalName -eq '$UserPrincipalName'" -Properties EmailAddress, Department

        # Create a custom object to hold the user information
        $userInfo = [PSCustomObject]@{
            Name = $user.Name
            EmailAddress = $user.EmailAddress
            Department = $user.Department
        }

        # Return the user information
        return $userInfo
    }
    catch {
        # Handle any errors that occur
        throw "Error retrieving user information: $($_.Exception.Message)"
    }
}

# Example usage
$userInfo = Get-UserInfo -UserPrincipalName "user@powershellblog.com"
Write-Host "Name: $($userInfo.Name)"
Write-Host "Email Address: $($userInfo.EmailAddress)"
Write-Host "Department: $($userInfo.Department)"

Here’s how this script follows the best practices we discussed:

  1. Meaningful Function Name: The function is named Get-UserInfo, which clearly indicates its purpose.
  2. Detailed Function Documentation: The function includes a comprehensive help comment block that provides a synopsis, description, parameter information, an example, and notes.
  3. Consistent Parameter Naming: The function takes a single parameter, UserPrincipalName, which is a clear and consistent name for the user’s principal name.
  4. Input Parameter Validation: The function uses the [Parameter(Mandatory=$true)] attribute to ensure that the UserPrincipalName parameter is provided, and the [ValidateNotNullOrEmpty()] attribute to ensure that the parameter is not null or empty.
  5. Appropriate Data Types: The function uses the [string] data type for the UserPrincipalName parameter, which is the expected data type for a user’s principal name.
  6. Meaningful Error Handling: The function uses a try-catch block to handle any errors that may occur during the execution of the function, and it throws a custom error message with detailed information about the error.
  7. Appropriate Cmdlet Verb: The function uses the Get- verb, which is the appropriate cmdlet verb for a function that retrieves information.
  8. Examples and Samples: The function includes an example usage in the help comment block, which demonstrates how to use the function.
  9. Thorough Testing: While not shown in the script, it’s important to thoroughly test the function to ensure it works as expected and handles edge cases appropriately.

By following these best practices, the Get-UserInfo function is well-designed, maintainable, and easy to use.

CSV Generator Tool

<#
.SYNOPSIS
CSV Generator Tool

.DESCRIPTION
This script provides an interactive tool to create CSV structures, add columns and rows,
and export the resulting CSV to a file.

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

.EXAMPLE
.\CSVGenerator.ps1
#>

# Global variables
$script:csvData = @()
$script:columns = @()
$script:csvFilePath = "$env:USERPROFILE\Desktop\Generated_CSV_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"

function Show-Menu {
    Clear-Host
    Write-Host "=== CSV Generator Tool ===" -ForegroundColor Cyan
    Write-Host "1. Define Columns"
    Write-Host "2. Add Row"
    Write-Host "3. View Current CSV Structure"
    Write-Host "4. Import Data from JSON"
    Write-Host "5. Generate Sample Data"
    Write-Host "6. Export CSV to File"
    Write-Host "7. Exit"
}

function Define-Columns {
    $script:columns = @()
    do {
        $columnName = Read-Host "Enter column name (or press Enter to finish)"
        if ($columnName -ne "") {
            $script:columns += $columnName
        }
    } while ($columnName -ne "")

    Write-Host "Columns defined: $($script:columns -join ', ')" -ForegroundColor Green
}

function Add-Row {
    if ($script:columns.Count -eq 0) {
        Write-Host "Please define columns first." -ForegroundColor Yellow
        return
    }

    $row = @{}
    foreach ($column in $script:columns) {
        $value = Read-Host "Enter value for '$column'"
        $row[$column] = $value
    }

    $script:csvData += [PSCustomObject]$row
    Write-Host "Row added successfully." -ForegroundColor Green
}

function View-CurrentCSV {
    if ($script:csvData.Count -eq 0) {
        Write-Host "No data available. Please add some rows first." -ForegroundColor Yellow
        return
    }

    $script:csvData | Format-Table -AutoSize
}

function Import-FromJSON {
    $jsonPath = Read-Host "Enter the path to the JSON file"
    if (-not (Test-Path $jsonPath)) {
        Write-Host "File not found." -ForegroundColor Red
        return
    }

    try {
        $jsonData = Get-Content $jsonPath -Raw | ConvertFrom-Json
        
        if ($jsonData -is [Array]) {
            $script:columns = $jsonData[0].PSObject.Properties.Name
            $script:csvData = $jsonData
        }
        else {
            $script:columns = $jsonData.PSObject.Properties.Name
            $script:csvData = @($jsonData)
        }

        Write-Host "Data imported successfully from JSON." -ForegroundColor Green
        Write-Host "Columns: $($script:columns -join ', ')" -ForegroundColor Green
        Write-Host "Number of rows: $($script:csvData.Count)" -ForegroundColor Green
    }
    catch {
        Write-Host "Error importing JSON: $_" -ForegroundColor Red
    }
}

function Generate-SampleData {
    if ($script:columns.Count -eq 0) {
        Write-Host "Please define columns first." -ForegroundColor Yellow
        return
    }

    $rowCount = Read-Host "Enter the number of sample rows to generate"
    if (-not [int]::TryParse($rowCount, [ref]$null)) {
        Write-Host "Invalid number. Please enter a valid integer." -ForegroundColor Red
        return
    }

    $script:csvData = @()

    for ($i = 1; $i -le [int]$rowCount; $i++) {
        $row = @{}
        foreach ($column in $script:columns) {
            $row[$column] = Get-SampleValue $column $i
        }
        $script:csvData += [PSCustomObject]$row
    }

    Write-Host "$rowCount sample rows generated successfully." -ForegroundColor Green
}

function Get-SampleValue($columnName, $rowNumber) {
    switch -Regex ($columnName.ToLower()) {
        "id|number" { return $rowNumber }
        "name" { return "Name$rowNumber" }
        "date" { return (Get-Date).AddDays($rowNumber).ToString("yyyy-MM-dd") }
        "email" { return "user$rowNumber@example.com" }
        "phone" { return "555-0$rowNumber" }
        "address" { return "$rowNumber Main St" }
        "city" { return "City$rowNumber" }
        "country" { return "Country$rowNumber" }
        "amount|price" { return [math]::Round((Get-Random -Minimum 10 -Maximum 1000), 2) }
        default { return "Value$rowNumber" }
    }
}

function Export-CSVToFile {
    if ($script:csvData.Count -eq 0) {
        Write-Host "No data to export. Please add some rows first." -ForegroundColor Yellow
        return
    }

    try {
        $script:csvData | Export-Csv -Path $script:csvFilePath -NoTypeInformation
        Write-Host "CSV exported successfully to: $script:csvFilePath" -ForegroundColor Green
    }
    catch {
        Write-Host "Error exporting CSV: $_" -ForegroundColor Red
    }
}

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

    switch ($choice) {
        "1" { Define-Columns }
        "2" { Add-Row }
        "3" { View-CurrentCSV }
        "4" { Import-FromJSON }
        "5" { Generate-SampleData }
        "6" { Export-CSVToFile }
        "7" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

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

This CSV Generator Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to interactively build CSV structures:
    • Define columns
    • Add rows manually
    • View the current CSV structure
    • Import data from JSON
    • Generate sample data
    • Export the CSV to a file

Key features:

  1. Column Definition:
    • Allows users to define custom column names
  2. Manual Data Entry:
    • Supports adding rows manually with guided input for each column
  3. Data Visualization:
    • Provides a view of the current CSV structure in a tabular format
  4. JSON Import:
    • Allows importing data from a JSON file to quickly populate the CSV
  5. Sample Data Generation:
    • Automatically generates sample data based on column names
    • Supports common data types like IDs, names, dates, emails, etc.
  6. CSV Export:
    • Exports the generated data to a CSV file

This tool is particularly useful for:

  • Developers needing to create test data in CSV format
  • Data analysts creating sample datasets
  • QA engineers generating CSV files for testing
  • Anyone needing to quickly create structured CSV data

To use this script effectively:

  1. Run the script in PowerShell
  2. Use the menu options to build your CSV structure:
    • Start by defining columns
    • Add rows manually, import from JSON, or generate sample data
    • View the current structure at any time
  3. When finished, export the CSV to a file

This script provides a user-friendly way to create CSV structures without having to manually write CSV syntax or use spreadsheet software. It’s especially helpful for creating test data or sample datasets quickly and easily.

JSON File Validator Tool

<#
.SYNOPSIS
JSON File Validator Tool

.DESCRIPTION
This script provides a tool to validate JSON files, check for syntax errors,
and provide detailed information about the JSON structure.

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

.EXAMPLE
.\JSONValidator.ps1
#>

function Show-Menu {
    Clear-Host
    Write-Host "=== JSON File Validator Tool ===" -ForegroundColor Cyan
    Write-Host "1. Validate JSON File"
    Write-Host "2. Analyze JSON Structure"
    Write-Host "3. Search JSON"
    Write-Host "4. Compare Two JSON Files"
    Write-Host "5. Exit"
}

function Validate-JSONFile {
    $filePath = Read-Host "Enter the path to the JSON file"
    if (-not (Test-Path $filePath)) {
        Write-Host "File not found." -ForegroundColor Red
        return
    }

    try {
        $content = Get-Content $filePath -Raw
        $json = ConvertFrom-Json $content -ErrorAction Stop
        Write-Host "JSON is valid." -ForegroundColor Green

        $size = (Get-Item $filePath).Length
        $objectCount = ($content | Select-String -Pattern "{" -AllMatches).Matches.Count
        $arrayCount = ($content | Select-String -Pattern "\[" -AllMatches).Matches.Count

        Write-Host "File Size: $size bytes"
        Write-Host "Number of Objects: $objectCount"
        Write-Host "Number of Arrays: $arrayCount"
    }
    catch {
        Write-Host "Invalid JSON. Error details:" -ForegroundColor Red
        Write-Host $_.Exception.Message
    }
}

function Analyze-JSONStructure {
    $filePath = Read-Host "Enter the path to the JSON file"
    if (-not (Test-Path $filePath)) {
        Write-Host "File not found." -ForegroundColor Red
        return
    }

    try {
        $json = Get-Content $filePath -Raw | ConvertFrom-Json
        $structure = Get-JSONStructure $json
        Write-Host "JSON Structure:" -ForegroundColor Yellow
        $structure | ForEach-Object { Write-Host $_ }
    }
    catch {
        Write-Host "Error analyzing JSON structure: $_" -ForegroundColor Red
    }
}

function Get-JSONStructure($obj, $path = "", $depth = 0) {
    $output = @()
    $indent = "  " * $depth

    if ($obj -is [System.Management.Automation.PSCustomObject]) {
        $output += "$indent$path {}"
        $obj.PSObject.Properties | ForEach-Object {
            $newPath = if ($path) { "$path.$($_.Name)" } else { $_.Name }
            $output += Get-JSONStructure $_.Value $newPath ($depth + 1)
        }
    }
    elseif ($obj -is [Array]) {
        $output += "$indent$path []"
        if ($obj.Count -gt 0) {
            $output += Get-JSONStructure $obj[0] "$path[0]" ($depth + 1)
        }
    }
    else {
        $type = if ($null -eq $obj) { "null" } else { $obj.GetType().Name }
        $output += "$indent$path : $type"
    }

    return $output
}

function Search-JSON {
    $filePath = Read-Host "Enter the path to the JSON file"
    if (-not (Test-Path $filePath)) {
        Write-Host "File not found." -ForegroundColor Red
        return
    }

    $searchKey = Read-Host "Enter the key to search for"

    try {
        $json = Get-Content $filePath -Raw | ConvertFrom-Json
        $results = Search-JSONRecursive $json $searchKey
        
        if ($results.Count -eq 0) {
            Write-Host "No results found for key: $searchKey" -ForegroundColor Yellow
        }
        else {
            Write-Host "Search Results:" -ForegroundColor Green
            $results | ForEach-Object {
                Write-Host "Path: $($_.Path)"
                Write-Host "Value: $($_.Value)"
                Write-Host "---"
            }
        }
    }
    catch {
        Write-Host "Error searching JSON: $_" -ForegroundColor Red
    }
}

function Search-JSONRecursive($obj, $searchKey, $currentPath = "") {
    $results = @()

    if ($obj -is [System.Management.Automation.PSCustomObject]) {
        $obj.PSObject.Properties | ForEach-Object {
            $newPath = if ($currentPath) { "$currentPath.$($_.Name)" } else { $_.Name }
            if ($_.Name -eq $searchKey) {
                $results += @{Path = $newPath; Value = $_.Value}
            }
            $results += Search-JSONRecursive $_.Value $searchKey $newPath
        }
    }
    elseif ($obj -is [Array]) {
        for ($i = 0; $i -lt $obj.Count; $i++) {
            $newPath = "${currentPath}[$i]"
            $results += Search-JSONRecursive $obj[$i] $searchKey $newPath
        }
    }

    return $results
}

function Compare-JSONFiles {
    $filePath1 = Read-Host "Enter the path to the first JSON file"
    $filePath2 = Read-Host "Enter the path to the second JSON file"

    if (-not (Test-Path $filePath1) -or -not (Test-Path $filePath2)) {
        Write-Host "One or both files not found." -ForegroundColor Red
        return
    }

    try {
        $json1 = Get-Content $filePath1 -Raw | ConvertFrom-Json
        $json2 = Get-Content $filePath2 -Raw | ConvertFrom-Json

        $differences = Compare-ObjectRecursive $json1 $json2

        if ($differences.Count -eq 0) {
            Write-Host "The JSON files are identical." -ForegroundColor Green
        }
        else {
            Write-Host "Differences found:" -ForegroundColor Yellow
            $differences | ForEach-Object {
                Write-Host "Path: $($_.Path)"
                Write-Host "File 1 Value: $($_.Value1)"
                Write-Host "File 2 Value: $($_.Value2)"
                Write-Host "---"
            }
        }
    }
    catch {
        Write-Host "Error comparing JSON files: $_" -ForegroundColor Red
    }
}

function Compare-ObjectRecursive($obj1, $obj2, $path = "") {
    $differences = @()

    if ($obj1 -is [System.Management.Automation.PSCustomObject] -and $obj2 -is [System.Management.Automation.PSCustomObject]) {
        $allProperties = $obj1.PSObject.Properties.Name + $obj2.PSObject.Properties.Name | Select-Object -Unique
        foreach ($prop in $allProperties) {
            $newPath = if ($path) { "$path.$prop" } else { $prop }
            if ($obj1.PSObject.Properties.Name -notcontains $prop) {
                $differences += @{Path = $newPath; Value1 = ""; Value2 = $obj2.$prop}
            }
            elseif ($obj2.PSObject.Properties.Name -notcontains $prop) {
                $differences += @{Path = $newPath; Value1 = $obj1.$prop; Value2 = ""}
            }
            else {
                $differences += Compare-ObjectRecursive $obj1.$prop $obj2.$prop $newPath
            }
        }
    }
    elseif ($obj1 -is [Array] -and $obj2 -is [Array]) {
        $maxLength = [Math]::Max($obj1.Length, $obj2.Length)
        for ($i = 0; $i -lt $maxLength; $i++) {
            $newPath = "${path}[$i]"
            if ($i -ge $obj1.Length) {
                $differences += @{Path = $newPath; Value1 = ""; Value2 = $obj2[$i]}
            }
            elseif ($i -ge $obj2.Length) {
                $differences += @{Path = $newPath; Value1 = $obj1[$i]; Value2 = ""}
            }
            else {
                $differences += Compare-ObjectRecursive $obj1[$i] $obj2[$i] $newPath
            }
        }
    }
    elseif ($obj1 -ne $obj2) {
        $differences += @{Path = $path; Value1 = $obj1; Value2 = $obj2}
    }

    return $differences
}

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

    switch ($choice) {
        "1" { Validate-JSONFile }
        "2" { Analyze-JSONStructure }
        "3" { Search-JSON }
        "4" { Compare-JSONFiles }
        "5" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

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

This JSON File Validator Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to perform various JSON-related tasks:
    • Validate JSON files and provide basic statistics
    • Analyze and display the structure of JSON files
    • Search for specific keys within JSON files
    • Compare two JSON files and highlight differences

Key features:

  1. JSON Validation:
    • Checks if the JSON is syntactically valid
    • Provides file size, number of objects, and number of arrays
  2. JSON Structure Analysis:
    • Displays a hierarchical view of the JSON structure
    • Shows types of values (object, array, string, number, etc.)
  3. JSON Search:
    • Allows searching for specific keys within the JSON
    • Displays the path and value of found keys
  4. JSON Comparison:
    • Compares two JSON files
    • Highlights differences, including added, removed, or modified values

This tool is particularly useful for:

  • Developers working with JSON data
  • QA engineers validating JSON outputs
  • Data analysts examining JSON structures
  • Anyone needing to quickly validate, analyze, or compare JSON files

To use this script effectively:

  1. Run the script in PowerShell
  2. Use the menu options to select the desired function
  3. Provide the path to the JSON file(s) when prompted
  4. Review the output for validation results, structure analysis, search results, or file comparisons

This script provides a comprehensive set of tools for working with JSON files, making it easier to validate, understand, and compare JSON data without having to manually parse the files or use multiple tools.

JSON Generator Tool

<#
.SYNOPSIS
JSON Generator Tool

.DESCRIPTION
This script provides an interactive tool to create JSON structures, add objects, arrays,
and key-value pairs, and export the resulting JSON to a file.

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

.EXAMPLE
.\JSONGenerator.ps1
#>

# Global variables
$script:jsonObject = @{}
$script:currentPath = @()
$script:jsonFilePath = "$env:USERPROFILE\Desktop\Generated_JSON_$(Get-Date -Format 'yyyyMMdd_HHmmss').json"

function Show-Menu {
    Clear-Host
    Write-Host "=== JSON Generator Tool ===" -ForegroundColor Cyan
    Write-Host "Current Path: $(if ($script:currentPath.Count -eq 0) { 'Root' } else { $script:currentPath -join '.' })"
    Write-Host "1. Add Key-Value Pair"
    Write-Host "2. Add Object"
    Write-Host "3. Add Array"
    Write-Host "4. Move to Parent"
    Write-Host "5. View Current JSON Structure"
    Write-Host "6. Export JSON to File"
    Write-Host "7. Exit"
}

function Add-KeyValuePair {
    $key = Read-Host "Enter the key"
    $value = Read-Host "Enter the value"

    # Try to convert the value to appropriate type
    if ($value -eq "true" -or $value -eq "false") {
        $value = [System.Convert]::ToBoolean($value)
    }
    elseif ($value -match "^\d+$") {
        $value = [int]$value
    }
    elseif ($value -match "^\d*\.\d+$") {
        $value = [double]$value
    }

    $current = Get-CurrentObject
    $current[$key] = $value
    Write-Host "Key-Value pair added." -ForegroundColor Green
}

function Add-Object {
    $key = Read-Host "Enter the key for the new object"
    $current = Get-CurrentObject
    $current[$key] = @{}
    $script:currentPath += $key
    Write-Host "Object added and set as current path." -ForegroundColor Green
}

function Add-Array {
    $key = Read-Host "Enter the key for the new array"
    $current = Get-CurrentObject
    $current[$key] = @()
    $script:currentPath += $key
    Write-Host "Array added and set as current path." -ForegroundColor Green

    do {
        $addItem = Read-Host "Do you want to add an item to the array? (Y/N)"
        if ($addItem -eq 'Y') {
            $item = Read-Host "Enter the item value"
            # Try to convert the value to appropriate type
            if ($item -eq "true" -or $item -eq "false") {
                $item = [System.Convert]::ToBoolean($item)
            }
            elseif ($item -match "^\d+$") {
                $item = [int]$item
            }
            elseif ($item -match "^\d*\.\d+$") {
                $item = [double]$item
            }
            $current[$key] += $item
            Write-Host "Item added to array." -ForegroundColor Green
        }
    } while ($addItem -eq 'Y')
}

function Move-ToParent {
    if ($script:currentPath.Count -eq 0) {
        Write-Host "Already at root level." -ForegroundColor Yellow
        return
    }
    $script:currentPath = $script:currentPath[0..($script:currentPath.Count - 2)]
    Write-Host "Moved to parent." -ForegroundColor Green
}

function Get-CurrentObject {
    $current = $script:jsonObject
    foreach ($key in $script:currentPath) {
        $current = $current[$key]
    }
    return $current
}

function View-CurrentJSON {
    $jsonString = $script:jsonObject | ConvertTo-Json -Depth 10
    Write-Host "Current JSON Structure:" -ForegroundColor Yellow
    Write-Host $jsonString
}

function Export-JSONToFile {
    try {
        $jsonString = $script:jsonObject | ConvertTo-Json -Depth 10
        $jsonString | Out-File -FilePath $script:jsonFilePath -Encoding UTF8
        Write-Host "JSON exported successfully to: $script:jsonFilePath" -ForegroundColor Green
    }
    catch {
        Write-Host "Error exporting JSON: $_" -ForegroundColor Red
    }
}

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

    switch ($choice) {
        "1" { Add-KeyValuePair }
        "2" { Add-Object }
        "3" { Add-Array }
        "4" { Move-ToParent }
        "5" { View-CurrentJSON }
        "6" { Export-JSONToFile }
        "7" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

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

This JSON Generator Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to interactively build JSON structures:
    • Add key-value pairs
    • Add nested objects
    • Add arrays and array items
    • Navigate the JSON structure (move to parent)
  3. Ability to view the current JSON structure at any time.
  4. Option to export the generated JSON to a file.

Key features:

  • Interactive JSON creation process
  • Support for nested objects and arrays
  • Automatic type conversion for values (boolean, integer, double, string)
  • Hierarchical navigation within the JSON structure
  • Real-time viewing of the current JSON structure
  • Export functionality to save the generated JSON

This tool is particularly useful for:

  • Developers who need to create JSON structures for testing or configuration purposes
  • Anyone learning about JSON structure and wanting to experiment with creating JSON documents
  • System administrators who need to generate JSON files for various applications
  • Quality Assurance professionals creating JSON test data

To use this script effectively:

  1. Run the script in PowerShell
  2. Use the menu options to build your JSON structure:
    • Add key-value pairs for simple data
    • Add objects for nested structures
    • Add arrays for lists of items
    • Use the “Move to Parent” option to navigate back up the JSON tree
  3. View the current JSON structure at any time to check your progress
  4. When finished, export the JSON to a file

This script provides a user-friendly way to create JSON structures without having to manually write JSON syntax. It’s especially helpful for those who are new to JSON or need to quickly generate JSON files without writing them by hand. The tool also handles proper nesting and type conversion, ensuring that the generated JSON is valid and properly formatted.

XML Generator Tool

<#
.SYNOPSIS
XML Generator Tool

.DESCRIPTION
This script provides an interactive tool to create XML structures, add elements and attributes,
and export the resulting XML to a file.

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

.EXAMPLE
.\XMLGenerator.ps1
#>

# Global variables
$script:xmlDoc = New-Object System.Xml.XmlDocument
$script:currentElement = $null
$script:xmlFilePath = "$env:USERPROFILE\Desktop\Generated_XML_$(Get-Date -Format 'yyyyMMdd_HHmmss').xml"

function Show-Menu {
    Clear-Host
    Write-Host "=== XML Generator Tool ===" -ForegroundColor Cyan
    Write-Host "1. Create Root Element"
    Write-Host "2. Add Child Element"
    Write-Host "3. Add Attribute to Current Element"
    Write-Host "4. Add Text to Current Element"
    Write-Host "5. Move to Parent Element"
    Write-Host "6. View Current XML Structure"
    Write-Host "7. Export XML to File"
    Write-Host "8. Exit"
}

function Create-RootElement {
    $rootName = Read-Host "Enter the name for the root element"
    $root = $script:xmlDoc.CreateElement($rootName)
    $script:xmlDoc.AppendChild($root) | Out-Null
    $script:currentElement = $root
    Write-Host "Root element '$rootName' created." -ForegroundColor Green
}

function Add-ChildElement {
    if ($null -eq $script:currentElement) {
        Write-Host "No current element selected. Please create a root element first." -ForegroundColor Yellow
        return
    }

    $childName = Read-Host "Enter the name for the child element"
    $child = $script:xmlDoc.CreateElement($childName)
    $script:currentElement.AppendChild($child) | Out-Null
    $script:currentElement = $child
    Write-Host "Child element '$childName' added to current element." -ForegroundColor Green
}

function Add-Attribute {
    if ($null -eq $script:currentElement) {
        Write-Host "No current element selected. Please create an element first." -ForegroundColor Yellow
        return
    }

    $attrName = Read-Host "Enter the name of the attribute"
    $attrValue = Read-Host "Enter the value of the attribute"
    $script:currentElement.SetAttribute($attrName, $attrValue)
    Write-Host "Attribute '$attrName' added to current element." -ForegroundColor Green
}

function Add-Text {
    if ($null -eq $script:currentElement) {
        Write-Host "No current element selected. Please create an element first." -ForegroundColor Yellow
        return
    }

    $text = Read-Host "Enter the text content for the current element"
    $script:currentElement.InnerText = $text
    Write-Host "Text added to current element." -ForegroundColor Green
}

function Move-ToParentElement {
    if ($null -eq $script:currentElement -or $script:currentElement -eq $script:xmlDoc.DocumentElement) {
        Write-Host "Already at the root level or no element selected." -ForegroundColor Yellow
        return
    }

    $script:currentElement = $script:currentElement.ParentNode
    Write-Host "Moved to parent element." -ForegroundColor Green
}

function View-CurrentXML {
    if ($null -eq $script:xmlDoc.DocumentElement) {
        Write-Host "XML structure is empty. Please create a root element first." -ForegroundColor Yellow
        return
    }

    $xmlString = $script:xmlDoc.OuterXml
    $xmlFormatted = Format-XML $xmlString
    Write-Host "Current XML Structure:" -ForegroundColor Yellow
    Write-Host $xmlFormatted
}

function Format-XML([string]$xmlString) {
    $stringWriter = New-Object System.IO.StringWriter
    $xmlWriter = New-Object System.Xml.XmlTextWriter($stringWriter)
    $xmlWriter.Formatting = [System.Xml.Formatting]::Indented
    $xmlDoc = New-Object System.Xml.XmlDocument
    $xmlDoc.LoadXml($xmlString)
    $xmlDoc.WriteContentTo($xmlWriter)
    $xmlWriter.Flush()
    $stringWriter.Flush()
    return $stringWriter.ToString()
}

function Export-XMLToFile {
    if ($null -eq $script:xmlDoc.DocumentElement) {
        Write-Host "XML structure is empty. Please create a root element first." -ForegroundColor Yellow
        return
    }

    try {
        $script:xmlDoc.Save($script:xmlFilePath)
        Write-Host "XML exported successfully to: $script:xmlFilePath" -ForegroundColor Green
    }
    catch {
        Write-Host "Error exporting XML: $_" -ForegroundColor Red
    }
}

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

    switch ($choice) {
        "1" { Create-RootElement }
        "2" { Add-ChildElement }
        "3" { Add-Attribute }
        "4" { Add-Text }
        "5" { Move-ToParentElement }
        "6" { View-CurrentXML }
        "7" { Export-XMLToFile }
        "8" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

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

This XML Generator Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to interactively build XML structures:
    • Create a root element
    • Add child elements
    • Add attributes to elements
    • Add text content to elements
    • Navigate the XML structure (move to parent element)
  3. Ability to view the current XML structure at any time.
  4. Option to export the generated XML to a file.

Key features:

  • Interactive XML creation process
  • Hierarchical element creation and navigation
  • Support for adding attributes and text content
  • Real-time viewing of the current XML structure
  • XML formatting for better readability
  • Export functionality to save the generated XML

This tool is particularly useful for:

  • Developers who need to create XML structures for testing or configuration purposes
  • Anyone learning about XML structure and wanting to experiment with creating XML documents
  • System administrators who need to generate XML files for various applications
  • Quality Assurance professionals creating XML test data

To use this script effectively:

  1. Run the script in PowerShell
  2. Use the menu options to build your XML structure:
    • Start by creating a root element
    • Add child elements, attributes, and text as needed
    • Use the “Move to Parent Element” option to navigate back up the XML tree
  3. View the current XML structure at any time to check your progress
  4. When finished, export the XML to a file

This script provides a user-friendly way to create XML structures without having to manually write XML syntax. It’s especially helpful for those who are new to XML or need to quickly generate XML files without writing them by hand.

SEO Checker Tool

<#
.SYNOPSIS
SEO Checker Tool

.DESCRIPTION
This script analyzes a webpage for various SEO elements and provides a report.

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

.EXAMPLE
.\SEOChecker.ps1
#>

# Import required modules
Add-Type -AssemblyName System.Web

# Global variables
$script:reportPath = "$env:USERPROFILE\Desktop\SEO_Analysis_Report_$(Get-Date -Format 'yyyyMMdd_HHmmss').html"

function Show-Menu {
    Clear-Host
    Write-Host "=== SEO Checker Tool ===" -ForegroundColor Cyan
    Write-Host "1. Analyze Website"
    Write-Host "2. View Last Report"
    Write-Host "3. Exit"
}

function Analyze-Website {
    $url = Read-Host "Enter the website URL to analyze (include http:// or https://)"
    
    if (-not ($url -match "^https?://")) {
        Write-Host "Invalid URL. Please include http:// or https://" -ForegroundColor Red
        return
    }

    Write-Host "`nAnalyzing $url..." -ForegroundColor Yellow

    try {
        $response = Invoke-WebRequest -Uri $url -UseBasicParsing
        $content = $response.Content
        $statusCode = $response.StatusCode

        $results = @{
            URL = $url
            StatusCode = $statusCode
            Title = Get-Title $content
            MetaDescription = Get-MetaDescription $content
            HeaderTags = Get-HeaderTags $content
            ImageAltTags = Get-ImageAltTags $content
            WordCount = Get-WordCount $content
            LoadTime = Measure-LoadTime $url
            MobileFriendly = Test-MobileFriendly $url
            SSL = Test-SSL $url
        }

        Generate-Report $results
    }
    catch {
        Write-Host "Error analyzing website: $_" -ForegroundColor Red
    }
}

function Get-Title($content) {
    if ($content -match "<title>(.*?)</title>") {
        return $matches[1]
    }
    return "No title found"
}

function Get-MetaDescription($content) {
    if ($content -match '<meta name="description" content="(.*?)"') {
        return $matches[1]
    }
    return "No meta description found"
}

function Get-HeaderTags($content) {
    $headers = @{}
    for ($i = 1; $i -le 6; $i++) {
        $count = ([regex]::Matches($content, "<h$i")).Count
        if ($count -gt 0) {
            $headers["H$i"] = $count
        }
    }
    return $headers
}

function Get-ImageAltTags($content) {
    $images = [regex]::Matches($content, '<img [^>]*alt="([^"]*)"')
    return @{
        TotalImages = $images.Count
        ImagesWithAlt = ($images | Where-Object { $_.Groups[1].Value -ne "" }).Count
    }
}

function Get-WordCount($content) {
    $text = $content -replace '<[^>]+>', '' -replace '&nbsp;', ' '
    $words = $text -split '\s+' | Where-Object { $_ -ne '' }
    return $words.Count
}

function Measure-LoadTime($url) {
    $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
    Invoke-WebRequest -Uri $url -UseBasicParsing | Out-Null
    $stopwatch.Stop()
    return [math]::Round($stopwatch.Elapsed.TotalSeconds, 2)
}

function Test-MobileFriendly($url) {
    # This is a basic check. For a more accurate test, you'd need to use Google's Mobile-Friendly Test API
    $userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1"
    $response = Invoke-WebRequest -Uri $url -UserAgent $userAgent -UseBasicParsing
    return $response.StatusCode -eq 200
}

function Test-SSL($url) {
    return $url.StartsWith("https://")
}

function Generate-Report($results) {
    $reportContent = @"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SEO Analysis Report</title>
    <style>
        body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; padding: 20px; }
        h1, h2 { color: #0078D4; }
        table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
        .good { color: green; }
        .warning { color: orange; }
        .bad { color: red; }
    </style>
</head>
<body>
    <h1>SEO Analysis Report</h1>
    <p>Generated on: $(Get-Date)</p>
    <p>URL: $($results.URL)</p>

    <h2>General Information</h2>
    <table>
        <tr><th>Status Code</th><td>$($results.StatusCode)</td></tr>
        <tr><th>Title</th><td>$($results.Title)</td></tr>
        <tr><th>Meta Description</th><td>$($results.MetaDescription)</td></tr>
        <tr><th>Word Count</th><td>$($results.WordCount)</td></tr>
        <tr><th>Load Time</th><td>$($results.LoadTime) seconds</td></tr>
        <tr><th>Mobile Friendly</th><td>$(if ($results.MobileFriendly) { "Yes" } else { "No" })</td></tr>
        <tr><th>SSL</th><td>$(if ($results.SSL) { "Yes" } else { "No" })</td></tr>
    </table>

    <h2>Header Tags</h2>
    <table>
        $(foreach ($header in $results.HeaderTags.GetEnumerator()) {
            "<tr><th>$($header.Key)</th><td>$($header.Value)</td></tr>"
        })
    </table>

    <h2>Images</h2>
    <table>
        <tr><th>Total Images</th><td>$($results.ImageAltTags.TotalImages)</td></tr>
        <tr><th>Images with Alt Text</th><td>$($results.ImageAltTags.ImagesWithAlt)</td></tr>
    </table>

    <h2>Recommendations</h2>
    <ul>
        $(if ($results.Title.Length -gt 60) { "<li class='warning'>Title is too long ($(($results.Title).Length) characters). Keep it under 60 characters.</li>" })
        $(if ($results.Title.Length -lt 30) { "<li class='warning'>Title is too short ($(($results.Title).Length) characters). Aim for 30-60 characters.</li>" })
        $(if ($results.MetaDescription.Length -gt 160) { "<li class='warning'>Meta description is too long ($(($results.MetaDescription).Length) characters). Keep it under 160 characters.</li>" })
        $(if ($results.MetaDescription.Length -lt 50) { "<li class='warning'>Meta description is too short ($(($results.MetaDescription).Length) characters). Aim for 50-160 characters.</li>" })
        $(if ($results.WordCount -lt 300) { "<li class='warning'>Content might be too short ($($results.WordCount) words). Aim for at least 300 words.</li>" })
        $(if ($results.LoadTime -gt 3) { "<li class='warning'>Page load time is slow ($($results.LoadTime) seconds). Aim for under 3 seconds.</li>" })
        $(if (-not $results.MobileFriendly) { "<li class='bad'>Page may not be mobile-friendly. Consider optimizing for mobile devices.</li>" })
        $(if (-not $results.SSL) { "<li class='bad'>Site is not using SSL. Consider switching to HTTPS for better security and SEO.</li>" })
        $(if ($results.ImageAltTags.ImagesWithAlt -lt $results.ImageAltTags.TotalImages) { "<li class='warning'>Not all images have alt text. Add alt text to improve accessibility and SEO.</li>" })
    </ul>
</body>
</html>
"@

    $reportContent | Out-File -FilePath $script:reportPath
    Write-Host "Report generated and saved to: $script:reportPath" -ForegroundColor Green
}

function View-LastReport {
    if (Test-Path $script:reportPath) {
        Start-Process $script:reportPath
    } else {
        Write-Host "No report found. Please analyze a website first." -ForegroundColor Yellow
    }
}

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

    switch ($choice) {
        "1" { Analyze-Website }
        "2" { View-LastReport }
        "3" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

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

This SEO Checker Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to analyze various SEO elements of a webpage:
    • Page title
    • Meta description
    • Header tags (H1 to H6)
    • Image alt tags
    • Word count
    • Page load time
    • Mobile-friendliness (basic check)
    • SSL implementation
  3. A report generation function that creates an HTML report with the analysis results and recommendations.
  4. Option to view the last generated report.

Key features:

  • Analyzes important on-page SEO elements
  • Provides a visual HTML report with color-coded recommendations
  • Checks for mobile-friendliness and SSL implementation
  • Measures page load time
  • Offers suggestions for improvement based on common SEO best practices

This tool is particularly useful for:

  • Website owners who want to perform a basic SEO check
  • Digital marketers analyzing website SEO elements
  • Web developers ensuring they’ve implemented basic SEO best practices
  • Anyone learning about SEO and wanting to analyze real websites

To use this script effectively:

  1. Run the script in PowerShell
  2. Choose to analyze a website by entering its URL
  3. Review the generated HTML report
  4. Use the recommendations to improve the website’s SEO

Please note that this is a basic SEO checker and doesn’t cover all aspects of SEO. For a comprehensive SEO analysis, you would need to consider many more factors and potentially use more advanced APIs and tools. However, this script provides a good starting point for basic on-page SEO analysis.

Certificate Request Toolkit

<#
.SYNOPSIS
Certificate Request Toolkit

.DESCRIPTION
This script provides a comprehensive set of tools for creating, managing, and analyzing
certificate requests (CSRs) and certificates. It includes features for generating CSRs,
analyzing existing CSRs and certificates, and performing related tasks.

.NOTES
File Name      : CertRequestToolkit.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V5.1 or later, OpenSSL (optional for some features)
Version        : 1.0
Date           : [Current Date]

.EXAMPLE
.\CertRequestToolkit.ps1
#>

# Check if OpenSSL is available
$openSSLAvailable = $null -ne (Get-Command openssl -ErrorAction SilentlyContinue)

function Show-Menu {
    Clear-Host
    Write-Host "=== Certificate Request Toolkit ===" -ForegroundColor Cyan
    Write-Host "1. Generate CSR"
    Write-Host "2. Analyze CSR"
    Write-Host "3. Analyze Certificate"
    Write-Host "4. Generate Self-Signed Certificate"
    Write-Host "5. Convert Certificate Format"
    Write-Host "6. Check Certificate Expiration"
    Write-Host "7. Verify Certificate Chain"
    Write-Host "8. Extract Public Key from Certificate"
    Write-Host "9. Exit"
}

function Generate-CSR {
    $subject = Read-Host "Enter the subject (e.g., CN=example.com,O=MyOrg,C=US)"
    $keySize = Read-Host "Enter key size (2048 or 4096, default is 2048)"
    if ([string]::IsNullOrWhiteSpace($keySize)) { $keySize = 2048 }

    $sanNames = @()
    do {
        $san = Read-Host "Enter Subject Alternative Name (or press Enter to finish)"
        if (-not [string]::IsNullOrWhiteSpace($san)) {
            $sanNames += $san
        }
    } while (-not [string]::IsNullOrWhiteSpace($san))

    $outputPath = Join-Path -Path $env:USERPROFILE -ChildPath "Desktop\certificate_request.csr"

    if ($openSSLAvailable) {
        $configPath = Join-Path -Path $env:TEMP -ChildPath "openssl_config.cnf"
        $config = @"
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[req_distinguished_name]
$subject

[v3_req]
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names

[alt_names]
"@
        for ($i = 0; $i -lt $sanNames.Count; $i++) {
            $config += "DNS.$($i+1) = $($sanNames[$i])`n"
        }

        $config | Out-File -FilePath $configPath -Encoding ASCII

        $keyPath = Join-Path -Path $env:USERPROFILE -ChildPath "Desktop\private_key.pem"
        
        & openssl req -new -newkey rsa:$keySize -nodes -keyout $keyPath -out $outputPath -config $configPath

        Remove-Item -Path $configPath

        Write-Host "CSR generated and saved to: $outputPath" -ForegroundColor Green
        Write-Host "Private key saved to: $keyPath" -ForegroundColor Green
    }
    else {
        Write-Host "OpenSSL is not available. Using .NET to generate CSR (limited functionality)." -ForegroundColor Yellow
        
        $rsa = [System.Security.Cryptography.RSA]::Create($keySize)
        $req = New-Object -TypeName System.Security.Cryptography.X509Certificates.CertificateRequest(
            $subject, $rsa, [System.Security.Cryptography.HashAlgorithmName]::SHA256, 
            [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)

        foreach ($san in $sanNames) {
            $req.CertificateExtensions.Add(
                [System.Security.Cryptography.X509Certificates.X509SubjectAlternativeNameExtension]::new(
                    $san, $false))
        }

        $csr = $req.CreateSigningRequest()
        [System.IO.File]::WriteAllBytes($outputPath, $csr)

        Write-Host "CSR generated and saved to: $outputPath" -ForegroundColor Green
        Write-Host "Note: Private key is not saved separately when using .NET method." -ForegroundColor Yellow
    }
}

function Analyze-CSR {
    $csrPath = Read-Host "Enter the path to the CSR file"
    if (-not (Test-Path $csrPath)) {
        Write-Host "CSR file not found." -ForegroundColor Red
        return
    }

    if ($openSSLAvailable) {
        Write-Host "`nCSR Analysis:" -ForegroundColor Yellow
        & openssl req -in $csrPath -noout -text
    }
    else {
        Write-Host "OpenSSL is not available. Limited analysis will be performed." -ForegroundColor Yellow
        $csrContent = Get-Content $csrPath -Raw
        $csrBytes = [System.Convert]::FromBase64String(($csrContent -replace "-----BEGIN CERTIFICATE REQUEST-----", "" -replace "-----END CERTIFICATE REQUEST-----", "").Trim())
        $csr = New-Object System.Security.Cryptography.X509Certificates.X509CertificateRequest(,$csrBytes)
        
        Write-Host "`nCSR Subject: $($csr.Subject)" -ForegroundColor Yellow
        Write-Host "Public Key Algorithm: $($csr.PublicKey.Oid.FriendlyName)" -ForegroundColor Yellow
        Write-Host "Public Key Size: $($csr.PublicKey.Key.KeySize) bits" -ForegroundColor Yellow
    }
}

function Analyze-Certificate {
    $certPath = Read-Host "Enter the path to the certificate file"
    if (-not (Test-Path $certPath)) {
        Write-Host "Certificate file not found." -ForegroundColor Red
        return
    }

    if ($openSSLAvailable) {
        Write-Host "`nCertificate Analysis:" -ForegroundColor Yellow
        & openssl x509 -in $certPath -noout -text
    }
    else {
        Write-Host "OpenSSL is not available. Limited analysis will be performed." -ForegroundColor Yellow
        $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath)
        
        Write-Host "`nCertificate Subject: $($cert.Subject)" -ForegroundColor Yellow
        Write-Host "Issuer: $($cert.Issuer)" -ForegroundColor Yellow
        Write-Host "Valid From: $($cert.NotBefore)" -ForegroundColor Yellow
        Write-Host "Valid To: $($cert.NotAfter)" -ForegroundColor Yellow
        Write-Host "Serial Number: $($cert.SerialNumber)" -ForegroundColor Yellow
        Write-Host "Thumbprint: $($cert.Thumbprint)" -ForegroundColor Yellow
    }
}

function Generate-SelfSignedCertificate {
    $subject = Read-Host "Enter the subject (e.g., CN=example.com)"
    $validityDays = Read-Host "Enter validity period in days (default is 365)"
    if ([string]::IsNullOrWhiteSpace($validityDays)) { $validityDays = 365 }

    $outputPath = Join-Path -Path $env:USERPROFILE -ChildPath "Desktop\self_signed_certificate.pfx"
    $password = Read-Host "Enter a password for the PFX file" -AsSecureString

    $cert = New-SelfSignedCertificate -Subject $subject -CertStoreLocation Cert:\CurrentUser\My `
        -KeyExportPolicy Exportable -KeySpec Signature -KeyLength 2048 -KeyAlgorithm RSA `
        -HashAlgorithm SHA256 -NotAfter (Get-Date).AddDays($validityDays)

    Export-PfxCertificate -Cert $cert -FilePath $outputPath -Password $password

    Remove-Item $cert.PSPath

    Write-Host "Self-signed certificate generated and saved to: $outputPath" -ForegroundColor Green
}

function Convert-CertificateFormat {
    if (-not $openSSLAvailable) {
        Write-Host "This feature requires OpenSSL, which is not available." -ForegroundColor Red
        return
    }

    $inputPath = Read-Host "Enter the path to the input certificate file"
    if (-not (Test-Path $inputPath)) {
        Write-Host "Input file not found." -ForegroundColor Red
        return
    }

    $outputFormat = Read-Host "Enter the desired output format (PEM, DER, P12)"
    $outputPath = Join-Path -Path $env:USERPROFILE -ChildPath "Desktop\converted_certificate.$($outputFormat.ToLower())"

    switch ($outputFormat.ToUpper()) {
        "PEM" { & openssl x509 -in $inputPath -outform PEM -out $outputPath }
        "DER" { & openssl x509 -in $inputPath -outform DER -out $outputPath }
        "P12" {
            $password = Read-Host "Enter a password for the P12 file" -AsSecureString
            $plainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
            & openssl pkcs12 -export -in $inputPath -out $outputPath -password pass:$plainPassword
        }
        default { Write-Host "Unsupported output format." -ForegroundColor Red; return }
    }

    Write-Host "Certificate converted and saved to: $outputPath" -ForegroundColor Green
}

function Check-CertificateExpiration {
    $certPath = Read-Host "Enter the path to the certificate file"
    if (-not (Test-Path $certPath)) {
        Write-Host "Certificate file not found." -ForegroundColor Red
        return
    }

    $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath)
    $daysUntilExpiration = ($cert.NotAfter - (Get-Date)).Days

    Write-Host "`nCertificate Expiration Information:" -ForegroundColor Yellow
    Write-Host "Subject: $($cert.Subject)"
    Write-Host "Expiration Date: $($cert.NotAfter)"
    Write-Host "Days Until Expiration: $daysUntilExpiration"

    if ($daysUntilExpiration -le 30) {
        Write-Host "Warning: Certificate will expire soon!" -ForegroundColor Red
    }
}

function Verify-CertificateChain {
    $certPath = Read-Host "Enter the path to the certificate file"
    if (-not (Test-Path $certPath)) {
        Write-Host "Certificate file not found." -ForegroundColor Red
        return
    }

    $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath)
    $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
    $chainBuilt = $chain.Build($cert)

    Write-Host "`nCertificate Chain Verification:" -ForegroundColor Yellow
    if ($chainBuilt) {
        Write-Host "Certificate chain is valid." -ForegroundColor Green
        Write-Host "`nCertificate Chain:"
        foreach ($element in $chain.ChainElements) {
            Write-Host "  Subject: $($element.Certificate.Subject)"
            Write-Host "  Issuer: $($element.Certificate.Issuer)"
            Write-Host "  Valid From: $($element.Certificate.NotBefore)"
            Write-Host "  Valid To: $($element.Certificate.NotAfter)"
            Write-Host ""
        }
    }
    else {
        Write-Host "Certificate chain is not valid." -ForegroundColor Red
        Write-Host "`nChain Status:"
        foreach ($status in $chain.ChainStatus) {
            Write-Host "  $($status.StatusInformation)"
        }
    }
}

function Extract-PublicKey {
    if (-not $openSSLAvailable) {
        Write-Host "This feature requires OpenSSL, which is not available." -ForegroundColor Red
        return
    }

    $certPath = Read-Host "Enter the path to the certificate file"
    if (-not (Test-Path $certPath)) {
        Write-Host "Certificate file not found." -ForegroundColor Red
        return
    }

    $outputPath = Join-Path -Path $env:USERPROFILE -ChildPath "Desktop\public_key.pem"
    & openssl x509 -in $certPath -pubkey -noout > $outputPath

    Write-Host "Public key extracted and saved to: $outputPath" -ForegroundColor Green
}

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

    switch ($choice) {
        "1" { Generate-CSR }
        "2" { Analyze-CSR }
        "3" { Analyze-Certificate }
        "4" { Generate-SelfSignedCertificate }
        "5" { Convert-CertificateFormat }
        "6" { Check-CertificateExpiration }
        "7" { Verify-CertificateChain }
        "8" { Extract-PublicKey }
        "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 Certificate Request Toolkit includes:

  1. A menu-driven interface for easy navigation.
  2. Functions for various certificate-related tasks:
    • Generating Certificate Signing Requests (CSRs)
    • Analyzing CSRs
    • Analyzing certificates
    • Generating self-signed certificates
    • Converting certificate formats
    • Checking certificate expiration
    • Verifying certificate chains
    • Extracting public keys from certificates
  3. Support for both OpenSSL (when available) and .NET methods for certain operations.
  4. Comprehensive error handling and user guidance.

Key features:

  • CSR generation with customizable subject, key size, and Subject Alternative Names (SANs)
  • Detailed analysis of CSRs and certificates
  • Self-signed certificate generation for testing purposes
  • Certificate format conversion (requires OpenSSL)
  • Certificate expiration checking
  • Certificate chain verification
  • Public key extraction from certificates (requires OpenSSL)
  • Fallback to .NET methods when OpenSSL is not available for some features

This tool is particularly useful for:

  • System administrators managing SSL/TLS certificates
  • Security professionals working with digital certificates
  • Developers needing to generate CSRs or analyze certificates
  • IT professionals troubleshooting certificate-related issues

To use this script effectively:

  1. Run the script in PowerShell
  2. Ensure OpenSSL is installed and available in the system PATH for full functionality
  3. Use the menu to navigate between different certificate-related tasks
  4. Follow the prompts to provide necessary information for each operation

This comprehensive toolkit provides a wide range of certificate management and analysis capabilities, making it a valuable resource for anyone working with digital certificates in a Windows environment.

Advanced Password Generator Tool

<#
.SYNOPSIS
Advanced Password Generator Tool

.DESCRIPTION
This script provides an advanced password generation tool with features including
customizable generation criteria, password strength evaluation, password history,
and additional utility functions.

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

.EXAMPLE
.\AdvancedPasswordGenerator.ps1
#>

# Import required modules
Add-Type -AssemblyName System.Web

# Global variables
$script:passwordHistory = @()
$script:maxHistorySize = 10
$script:passwordFilePath = Join-Path -Path $env:USERPROFILE -ChildPath "Documents\PasswordGeneratorHistory.txt"

function Show-Menu {
    Clear-Host
    Write-Host "=== Advanced Password Generator Tool ===" -ForegroundColor Cyan
    Write-Host "1. Generate Password"
    Write-Host "2. Set Password Options"
    Write-Host "3. View Current Settings"
    Write-Host "4. View Password History"
    Write-Host "5. Evaluate Password Strength"
    Write-Host "6. Generate Passphrase"
    Write-Host "7. Export Password History"
    Write-Host "8. Exit"
}

function Set-PasswordOptions {
    $script:passwordLength = Read-Host "Enter password length (default is 16)"
    if ([string]::IsNullOrWhiteSpace($script:passwordLength)) { $script:passwordLength = 16 }
    
    $script:includeUppercase = Read-Host "Include uppercase letters? (Y/N, default is Y)"
    $script:includeUppercase = ($script:includeUppercase -ne 'N')
    
    $script:includeLowercase = Read-Host "Include lowercase letters? (Y/N, default is Y)"
    $script:includeLowercase = ($script:includeLowercase -ne 'N')
    
    $script:includeNumbers = Read-Host "Include numbers? (Y/N, default is Y)"
    $script:includeNumbers = ($script:includeNumbers -ne 'N')
    
    $script:includeSpecialChars = Read-Host "Include special characters? (Y/N, default is Y)"
    $script:includeSpecialChars = ($script:includeSpecialChars -ne 'N')

    $script:excludeSimilarChars = Read-Host "Exclude similar characters (O, 0, I, l, 1)? (Y/N, default is N)"
    $script:excludeSimilarChars = ($script:excludeSimilarChars -eq 'Y')
    
    Write-Host "Password options updated." -ForegroundColor Green
}

function View-CurrentSettings {
    Write-Host "`nCurrent Password Generation Settings:" -ForegroundColor Yellow
    Write-Host "Password Length: $script:passwordLength"
    Write-Host "Include Uppercase: $($script:includeUppercase ? 'Yes' : 'No')"
    Write-Host "Include Lowercase: $($script:includeLowercase ? 'Yes' : 'No')"
    Write-Host "Include Numbers: $($script:includeNumbers ? 'Yes' : 'No')"
    Write-Host "Include Special Characters: $($script:includeSpecialChars ? 'Yes' : 'No')"
    Write-Host "Exclude Similar Characters: $($script:excludeSimilarChars ? 'Yes' : 'No')"
    Write-Host ""
}

function Generate-Password {
    $characterSet = @()
    if ($script:includeUppercase) { $characterSet += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.ToCharArray() }
    if ($script:includeLowercase) { $characterSet += 'abcdefghijklmnopqrstuvwxyz'.ToCharArray() }
    if ($script:includeNumbers) { $characterSet += '0123456789'.ToCharArray() }
    if ($script:includeSpecialChars) { $characterSet += '!@#$%^&*()_+-=[]{}|;:,.<>?'.ToCharArray() }

    if ($script:excludeSimilarChars) {
        $characterSet = $characterSet | Where-Object { $_ -notin 'O', '0', 'I', 'l', '1' }
    }

    if ($characterSet.Count -eq 0) {
        Write-Host "Error: No character set selected. Please update your settings." -ForegroundColor Red
        return
    }

    $password = -join (1..$script:passwordLength | ForEach-Object { Get-Random -InputObject $characterSet })
    
    Write-Host "`nGenerated Password:" -ForegroundColor Green
    Write-Host $password
    Write-Host ""

    $strength = Evaluate-PasswordStrength -Password $password
    Write-Host "Password Strength: $strength" -ForegroundColor Yellow

    Add-ToPasswordHistory -Password $password

    $saveToFile = Read-Host "Do you want to save this password to a file? (Y/N)"
    if ($saveToFile -eq 'Y') {
        $fileName = "GeneratedPassword_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt"
        $filePath = Join-Path -Path $env:USERPROFILE -ChildPath "Desktop\$fileName"
        $password | Out-File -FilePath $filePath
        Write-Host "Password saved to: $filePath" -ForegroundColor Green
    }
}

function Evaluate-PasswordStrength {
    param ([string]$Password)

    $score = 0

    if ($Password.Length -ge 12) { $score += 2 }
    elseif ($Password.Length -ge 8) { $score += 1 }

    if ($Password -cmatch "[A-Z]") { $score += 1 }
    if ($Password -cmatch "[a-z]") { $score += 1 }
    if ($Password -match "\d") { $score += 1 }
    if ($Password -match "[^a-zA-Z0-9]") { $score += 1 }

    switch ($score) {
        0 { return "Very Weak" }
        1 { return "Weak" }
        2 { return "Moderate" }
        3 { return "Strong" }
        4 { return "Very Strong" }
        default { return "Extremely Strong" }
    }
}

function Add-ToPasswordHistory {
    param ([string]$Password)

    $script:passwordHistory = @($Password) + $script:passwordHistory
    if ($script:passwordHistory.Count -gt $script:maxHistorySize) {
        $script:passwordHistory = $script:passwordHistory[0..($script:maxHistorySize - 1)]
    }
}

function View-PasswordHistory {
    if ($script:passwordHistory.Count -eq 0) {
        Write-Host "Password history is empty." -ForegroundColor Yellow
        return
    }

    Write-Host "`nPassword History (Most Recent First):" -ForegroundColor Yellow
    for ($i = 0; $i -lt $script:passwordHistory.Count; $i++) {
        Write-Host "$($i + 1). $($script:passwordHistory[$i])"
    }
    Write-Host ""
}

function Generate-Passphrase {
    $wordList = @("apple", "banana", "cherry", "date", "elderberry", "fig", "grape", "honeydew", "kiwi", "lemon", "mango", "nectarine", "orange", "papaya", "quince", "raspberry", "strawberry", "tangerine", "ugli", "vanilla", "watermelon", "xigua", "yuzu", "zucchini")
    $passphrase = -join ((1..4 | ForEach-Object { Get-Random -InputObject $wordList }) -join "-")
    
    Write-Host "`nGenerated Passphrase:" -ForegroundColor Green
    Write-Host $passphrase
    Write-Host ""

    Add-ToPasswordHistory -Password $passphrase
}

function Export-PasswordHistory {
    if ($script:passwordHistory.Count -eq 0) {
        Write-Host "Password history is empty. Nothing to export." -ForegroundColor Yellow
        return
    }

    $script:passwordHistory | Out-File -FilePath $script:passwordFilePath
    Write-Host "Password history exported to: $script:passwordFilePath" -ForegroundColor Green
}

# Initialize default settings
$script:passwordLength = 16
$script:includeUppercase = $true
$script:includeLowercase = $true
$script:includeNumbers = $true
$script:includeSpecialChars = $true
$script:excludeSimilarChars = $false

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

    switch ($choice) {
        "1" { Generate-Password }
        "2" { Set-PasswordOptions }
        "3" { View-CurrentSettings }
        "4" { View-PasswordHistory }
        "5" { 
            $pwToEvaluate = Read-Host "Enter a password to evaluate"
            $strength = Evaluate-PasswordStrength -Password $pwToEvaluate
            Write-Host "Password Strength: $strength" -ForegroundColor Yellow
        }
        "6" { Generate-Passphrase }
        "7" { Export-PasswordHistory }
        "8" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

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

This Advanced Password Generator Tool includes:

  1. A menu-driven interface with expanded options.
  2. Enhanced functions for password generation and management:
    • Customizable password generation with more options
    • Password strength evaluation
    • Password history tracking
    • Passphrase generation
    • Export functionality for password history
  3. Additional features:
    • Option to exclude similar characters (O, 0, I, l, 1) for improved readability
    • Passphrase generation using a predefined word list
    • Ability to evaluate the strength of any given password
    • Password history with a configurable size limit
    • Export functionality to save password history to a file

Key features:

  • More flexible and customizable password generation
  • Built-in password strength evaluation
  • Password history tracking for easy reference
  • Passphrase generation as an alternative to traditional passwords
  • Ability to export password history for backup or review
  • Enhanced user interface with more options and information

This tool is particularly useful for:

  • System administrators requiring advanced password management capabilities
  • Security professionals needing to generate and evaluate various types of passwords
  • Users who want a comprehensive tool for creating and managing strong passwords
  • IT professionals implementing or reviewing password policies

To use this script effectively:

  1. Run the script in PowerShell
  2. Use the expanded menu to access various features
  3. Customize password generation settings as needed
  4. Generate passwords or passphrases
  5. Use the password strength evaluation feature to check existing passwords
  6. Manage and export password history as required

This advanced script provides a more comprehensive approach to password generation and management, offering additional features for security-conscious users and professionals.