CSV File Validator Tool

<#
.SYNOPSIS
CSV File Validator Tool

.DESCRIPTION
This script provides a tool to validate CSV files, check for structural issues,
analyze data types, and provide detailed information about the CSV content.

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

.EXAMPLE
.\CSVValidator.ps1
#>

function Show-Menu {
    Clear-Host
    Write-Host "=== CSV File Validator Tool ===" -ForegroundColor Cyan
    Write-Host "1. Validate CSV File"
    Write-Host "2. Analyze CSV Structure"
    Write-Host "3. Check for Data Inconsistencies"
    Write-Host "4. Generate CSV Summary"
    Write-Host "5. Compare Two CSV Files"
    Write-Host "6. Exit"
}

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

    try {
        $csv = Import-Csv $filePath
        $rowCount = $csv.Count
        $columnCount = ($csv | Get-Member -MemberType NoteProperty).Count

        Write-Host "CSV is valid." -ForegroundColor Green
        Write-Host "Number of rows: $rowCount"
        Write-Host "Number of columns: $columnCount"

        $headers = ($csv | Get-Member -MemberType NoteProperty).Name
        Write-Host "Headers: $($headers -join ', ')"

        $size = (Get-Item $filePath).Length
        Write-Host "File Size: $size bytes"
    }
    catch {
        Write-Host "Invalid CSV. Error details:" -ForegroundColor Red
        Write-Host $_.Exception.Message
    }
}

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

    try {
        $csv = Import-Csv $filePath
        $headers = ($csv | Get-Member -MemberType NoteProperty).Name

        Write-Host "CSV Structure Analysis:" -ForegroundColor Yellow
        foreach ($header in $headers) {
            $values = $csv.$header | Where-Object { $_ -ne "" }
            $dataType = Guess-DataType $values
            $uniqueValues = ($values | Select-Object -Unique).Count
            $nullCount = ($csv.$header | Where-Object { $_ -eq "" }).Count

            Write-Host "`nColumn: $header"
            Write-Host "  Data Type: $dataType"
            Write-Host "  Unique Values: $uniqueValues"
            Write-Host "  Null/Empty Values: $nullCount"
            Write-Host "  Sample Values: $($values | Select-Object -First 5 -Unique)"
        }
    }
    catch {
        Write-Host "Error analyzing CSV structure: $_" -ForegroundColor Red
    }
}

function Guess-DataType($values) {
    $sampleSize = [Math]::Min($values.Count, 100)
    $sample = $values | Select-Object -First $sampleSize

    $isNumeric = $sample | ForEach-Object { $_ -as [double] } | Where-Object { $_ -ne $null }
    $isDate = $sample | ForEach-Object { $_ -as [datetime] } | Where-Object { $_ -ne $null }

    if ($isNumeric.Count -eq $sampleSize) { return "Numeric" }
    elseif ($isDate.Count -eq $sampleSize) { return "Date" }
    else { return "String" }
}

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

    try {
        $csv = Import-Csv $filePath
        $headers = ($csv | Get-Member -MemberType NoteProperty).Name

        Write-Host "Checking for Data Inconsistencies:" -ForegroundColor Yellow
        foreach ($header in $headers) {
            $values = $csv.$header
            $dataType = Guess-DataType $values

            $inconsistencies = @()
            switch ($dataType) {
                "Numeric" {
                    $inconsistencies = $values | Where-Object { $_ -ne "" -and ($_ -as [double]) -eq $null }
                }
                "Date" {
                    $inconsistencies = $values | Where-Object { $_ -ne "" -and ($_ -as [datetime]) -eq $null }
                }
            }

            if ($inconsistencies.Count -gt 0) {
                Write-Host "`nInconsistencies found in column '$header' (Expected $dataType):"
                Write-Host ($inconsistencies | Select-Object -First 5) -ForegroundColor Red
                if ($inconsistencies.Count -gt 5) {
                    Write-Host "... and $($inconsistencies.Count - 5) more."
                }
            }
        }
    }
    catch {
        Write-Host "Error checking data inconsistencies: $_" -ForegroundColor Red
    }
}

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

    try {
        $csv = Import-Csv $filePath
        $rowCount = $csv.Count
        $headers = ($csv | Get-Member -MemberType NoteProperty).Name

        Write-Host "CSV Summary:" -ForegroundColor Yellow
        Write-Host "File: $filePath"
        Write-Host "Total Rows: $rowCount"
        Write-Host "Total Columns: $($headers.Count)"
        Write-Host "`nColumn Summary:"

        foreach ($header in $headers) {
            $values = $csv.$header
            $nonEmptyValues = $values | Where-Object { $_ -ne "" }
            $uniqueValues = ($nonEmptyValues | Select-Object -Unique).Count
            $nullCount = ($values | Where-Object { $_ -eq "" }).Count
            $dataType = Guess-DataType $nonEmptyValues

            Write-Host "`n$header:"
            Write-Host "  Data Type: $dataType"
            Write-Host "  Unique Values: $uniqueValues"
            Write-Host "  Null/Empty Count: $nullCount"
            Write-Host "  Fill Rate: $([math]::Round(($rowCount - $nullCount) / $rowCount * 100, 2))%"

            if ($dataType -eq "Numeric") {
                $numericValues = $nonEmptyValues | ForEach-Object { $_ -as [double] }
                $min = ($numericValues | Measure-Object -Minimum).Minimum
                $max = ($numericValues | Measure-Object -Maximum).Maximum
                $avg = ($numericValues | Measure-Object -Average).Average
                Write-Host "  Min: $min"
                Write-Host "  Max: $max"
                Write-Host "  Average: $([math]::Round($avg, 2))"
            }
        }
    }
    catch {
        Write-Host "Error generating CSV summary: $_" -ForegroundColor Red
    }
}

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

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

    try {
        $csv1 = Import-Csv $filePath1
        $csv2 = Import-Csv $filePath2

        $headers1 = ($csv1 | Get-Member -MemberType NoteProperty).Name
        $headers2 = ($csv2 | Get-Member -MemberType NoteProperty).Name

        Write-Host "Comparing CSV Files:" -ForegroundColor Yellow
        Write-Host "File 1: $filePath1"
        Write-Host "File 2: $filePath2"

        Write-Host "`nColumn Comparison:"
        $commonHeaders = $headers1 | Where-Object { $headers2 -contains $_ }
        $uniqueHeaders1 = $headers1 | Where-Object { $headers2 -notcontains $_ }
        $uniqueHeaders2 = $headers2 | Where-Object { $headers1 -notcontains $_ }

        Write-Host "Common Columns: $($commonHeaders -join ', ')"
        Write-Host "Columns only in File 1: $($uniqueHeaders1 -join ', ')"
        Write-Host "Columns only in File 2: $($uniqueHeaders2 -join ', ')"

        Write-Host "`nRow Count Comparison:"
        Write-Host "File 1 Row Count: $($csv1.Count)"
        Write-Host "File 2 Row Count: $($csv2.Count)"

        Write-Host "`nData Comparison for Common Columns:"
        foreach ($header in $commonHeaders) {
            $diff = Compare-Object $csv1.$header $csv2.$header
            if ($diff) {
                Write-Host "Differences found in column '$header':"
                Write-Host "  Values only in File 1: $($diff | Where-Object { $_.SideIndicator -eq '<=' } | Select-Object -ExpandProperty InputObject)"
                Write-Host "  Values only in File 2: $($diff | Where-Object { $_.SideIndicator -eq '=>' } | Select-Object -ExpandProperty InputObject)"
            }
            else {
                Write-Host "No differences found in column '$header'"
            }
        }
    }
    catch {
        Write-Host "Error comparing CSV files: $_" -ForegroundColor Red
    }
}

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

    switch ($choice) {
        "1" { Validate-CSVFile }
        "2" { Analyze-CSVStructure }
        "3" { Check-DataInconsistencies }
        "4" { Generate-CSVSummary }
        "5" { Compare-CSVFiles }
        "6" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

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

This CSV File Validator Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to perform various CSV-related tasks:
    • Validate CSV files and provide basic statistics
    • Analyze and display the structure of CSV files
    • Check for data inconsistencies
    • Generate a comprehensive summary of the CSV content
    • Compare two CSV files

Key features:

  1. CSV Validation:
    • Checks if the CSV is valid and can be parsed
    • Provides row count, column count, headers, and file size
  2. CSV Structure Analysis:
    • Analyzes each column for data type, unique values, and null/empty values
    • Provides sample values for each column
  3. Data Inconsistency Check:
    • Identifies values that don’t match the expected data type for each column
  4. CSV Summary Generation:
    • Provides a comprehensive summary of the CSV, including data types, unique values, fill rates, and basic statistics for numeric columns
  5. CSV Comparison:
    • Compares two CSV files for structural differences and data discrepancies

This tool is particularly useful for:

  • Data analysts validating CSV datasets
  • QA engineers checking CSV file integrity
  • Developers working with CSV data imports/exports
  • Anyone needing to quickly analyze or compare CSV 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 CSV file(s) when prompted
  4. Review the output for validation results, structure analysis, inconsistencies, summaries, or file comparisons

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

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.

XML File Validator Tool

<#
.SYNOPSIS
XML File Validator Tool

.DESCRIPTION
This script provides a tool to validate XML files, check for syntax errors,
analyze the structure, and perform various XML-related tasks.

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

.EXAMPLE
.\XMLValidator.ps1
#>

Add-Type -AssemblyName System.Xml.Linq

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

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

    try {
        [xml]$xml = Get-Content $filePath
        Write-Host "XML is valid." -ForegroundColor Green

        $size = (Get-Item $filePath).Length
        $elementCount = $xml.SelectNodes("//*").Count
        $attributeCount = $xml.SelectNodes("//@*").Count

        Write-Host "File Size: $size bytes"
        Write-Host "Number of Elements: $elementCount"
        Write-Host "Number of Attributes: $attributeCount"
    }
    catch [System.Xml.XmlException] {
        Write-Host "Invalid XML. Error details:" -ForegroundColor Red
        Write-Host $_.Exception.Message
    }
}

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

    try {
        [xml]$xml = Get-Content $filePath
        $structure = Get-XMLStructure $xml.DocumentElement
        Write-Host "XML Structure:" -ForegroundColor Yellow
        $structure | ForEach-Object { Write-Host $_ }
    }
    catch {
        Write-Host "Error analyzing XML structure: $_" -ForegroundColor Red
    }
}

function Get-XMLStructure($element, $indent = "") {
    $output = @()
    $output += "$indent$($element.Name)"
    
    if ($element.Attributes.Count -gt 0) {
        $attributes = $element.Attributes | ForEach-Object { "$($_.Name)='$($_.Value)'" }
        $output += "$indent  Attributes: $($attributes -join ', ')"
    }
    
    foreach ($child in $element.ChildNodes) {
        if ($child.NodeType -eq [System.Xml.XmlNodeType]::Element) {
            $output += Get-XMLStructure $child "$indent  "
        }
        elseif ($child.NodeType -eq [System.Xml.XmlNodeType]::Text) {
            $output += "$indent  Text: $($child.Value.Trim())"
        }
    }
    
    return $output
}

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

    $searchTerm = Read-Host "Enter the search term (element or attribute name)"

    try {
        [xml]$xml = Get-Content $filePath
        $results = $xml.SelectNodes("//*[local-name()='$searchTerm'] | //@*[local-name()='$searchTerm']")
        
        if ($results.Count -eq 0) {
            Write-Host "No results found for: $searchTerm" -ForegroundColor Yellow
        }
        else {
            Write-Host "Search Results:" -ForegroundColor Green
            foreach ($result in $results) {
                Write-Host "XPath: $($result.XPath)"
                if ($result.NodeType -eq [System.Xml.XmlNodeType]::Element) {
                    Write-Host "Element Value: $($result.InnerXml)"
                }
                elseif ($result.NodeType -eq [System.Xml.XmlNodeType]::Attribute) {
                    Write-Host "Attribute Value: $($result.Value)"
                }
                Write-Host "---"
            }
        }
    }
    catch {
        Write-Host "Error searching XML: $_" -ForegroundColor Red
    }
}

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

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

    try {
        $xml1 = [System.Xml.Linq.XDocument]::Load($filePath1)
        $xml2 = [System.Xml.Linq.XDocument]::Load($filePath2)

        $differences = Compare-XmlDocs $xml1 $xml2

        if ($differences.Count -eq 0) {
            Write-Host "The XML files are identical." -ForegroundColor Green
        }
        else {
            Write-Host "Differences found:" -ForegroundColor Yellow
            foreach ($diff in $differences) {
                Write-Host "XPath: $($diff.XPath)"
                Write-Host "File 1 Value: $($diff.Value1)"
                Write-Host "File 2 Value: $($diff.Value2)"
                Write-Host "---"
            }
        }
    }
    catch {
        Write-Host "Error comparing XML files: $_" -ForegroundColor Red
    }
}

function Compare-XmlDocs($doc1, $doc2) {
    $differences = @()
    $elements1 = $doc1.Descendants()
    $elements2 = $doc2.Descendants()

    foreach ($element in $elements1) {
        $xpath = $element.XPathSelectElement($element.GetAbsoluteXPath())
        $otherElement = $doc2.XPathSelectElement($xpath.GetAbsoluteXPath())

        if ($null -eq $otherElement) {
            $differences += @{XPath = $xpath.GetAbsoluteXPath(); Value1 = $element.Value; Value2 = "Element not found"}
        }
        elseif ($element.Value -ne $otherElement.Value) {
            $differences += @{XPath = $xpath.GetAbsoluteXPath(); Value1 = $element.Value; Value2 = $otherElement.Value}
        }

        foreach ($attr in $element.Attributes()) {
            $otherAttr = $otherElement?.Attribute($attr.Name)
            if ($null -eq $otherAttr) {
                $differences += @{XPath = "$($xpath.GetAbsoluteXPath())/@$($attr.Name)"; Value1 = $attr.Value; Value2 = "Attribute not found"}
            }
            elseif ($attr.Value -ne $otherAttr.Value) {
                $differences += @{XPath = "$($xpath.GetAbsoluteXPath())/@$($attr.Name)"; Value1 = $attr.Value; Value2 = $otherAttr.Value}
            }
        }
    }

    foreach ($element in $elements2) {
        $xpath = $element.XPathSelectElement($element.GetAbsoluteXPath())
        $otherElement = $doc1.XPathSelectElement($xpath.GetAbsoluteXPath())

        if ($null -eq $otherElement) {
            $differences += @{XPath = $xpath.GetAbsoluteXPath(); Value1 = "Element not found"; Value2 = $element.Value}
        }

        foreach ($attr in $element.Attributes()) {
            $otherAttr = $otherElement?.Attribute($attr.Name)
            if ($null -eq $otherAttr) {
                $differences += @{XPath = "$($xpath.GetAbsoluteXPath())/@$($attr.Name)"; Value1 = "Attribute not found"; Value2 = $attr.Value}
            }
        }
    }

    return $differences
}

function Validate-XMLAgainstXSD {
    $xmlPath = Read-Host "Enter the path to the XML file"
    $xsdPath = Read-Host "Enter the path to the XSD schema file"

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

    try {
        $xmlReader = [System.Xml.XmlReader]::Create($xmlPath)
        $schemaReader = [System.Xml.XmlReader]::Create($xsdPath)
        $schema = [System.Xml.Schema.XmlSchema]::Read($schemaReader, $null)

        $settings = New-Object System.Xml.XmlReaderSettings
        $settings.ValidationType = [System.Xml.ValidationType]::Schema
        $settings.Schemas.Add($schema) | Out-Null

        $settings.ValidationEventHandler = {
            param($sender, $e)
            Write-Host "Validation Error: $($e.Message)" -ForegroundColor Red
        }

        $validatingReader = [System.Xml.XmlReader]::Create($xmlPath, $settings)
        while ($validatingReader.Read()) { }

        Write-Host "XML is valid according to the XSD schema." -ForegroundColor Green
    }
    catch {
        Write-Host "Error validating XML against XSD: $_" -ForegroundColor Red
    }
    finally {
        if ($null -ne $xmlReader) { $xmlReader.Close() }
        if ($null -ne $schemaReader) { $schemaReader.Close() }
        if ($null -ne $validatingReader) { $validatingReader.Close() }
    }
}

# Extension method to get absolute XPath
Add-Type @"
using System.Xml.Linq;
using System.Linq;

public static class XElementExtensions
{
    public static string GetAbsoluteXPath(this XElement element)
    {
        if (element == null)
            return string.Empty;

        var ancestors = element.AncestorsAndSelf().Reverse().ToList();
        return "/" + string.Join("/", ancestors.Select(e => e.Name.LocalName));
    }
}
"@

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

    switch ($choice) {
        "1" { Validate-XMLFile }
        "2" { Analyze-XMLStructure }
        "3" { Search-XML }
        "4" { Compare-XMLFiles }
        "5" { Validate-XMLAgainstXSD }
        "6" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

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

This XML File Validator Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to perform various XML-related tasks:
    • Validate XML files and provide basic statistics
    • Analyze and display the structure of XML files
    • Search for specific elements or attributes within XML files
    • Compare two XML files and highlight differences
    • Validate XML against an XSD schema

Key features:

  1. XML Validation:
    • Checks if the XML is syntactically valid
    • Provides file size, number of elements, and number of attributes
  2. XML Structure Analysis:
    • Displays a hierarchical view of the XML structure
    • Shows element names, attributes, and text content
  3. XML Search:
    • Allows searching for specific elements or attributes within the XML
    • Displays the XPath and value of found elements/attributes
  4. XML Comparison:
    • Compares two XML files
    • Highlights differences, including added, removed, or modified elements and attributes
  5. XSD Schema Validation:
    • Validates an XML file against an XSD schema
    • Reports any validation errors

This tool is particularly useful for:

  • Developers working with XML data
  • QA engineers validating XML outputs
  • Data analysts examining XML structures
  • Anyone needing to quickly validate, analyze, or compare XML 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 XML file(s) when prompted
  4. Review the output for validation results, structure analysis, search results, file comparisons, or schema validation

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

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.

Dr. Scripto and the Certificate Conundrum

It was a bustling Monday morning at the PowerShell Academy. The corridors were filled with the excited chatter of students discussing their weekend coding projects. Dr. Scripto, the renowned PowerShell wizard, was in his office, sipping his morning coffee from his favorite cmdlet-decorated mug, when his phone rang.

“Dr. Scripto speaking,” he answered cheerfully.

“Doctor, we need your help urgently!” It was the panicked voice of Sarah, the IT manager from Contoso Corp, a long-time partner of the Academy. “Our certificate infrastructure is in shambles. We have hundreds of expiring certificates, and our manual process can’t keep up. Can you help us automate this with PowerShell?”

Dr. Scripto’s eyes lit up with excitement. “Certificates, you say? And automation? Sarah, my dear, you’ve just made my Monday! I’ll be right over.”

Within the hour, Dr. Scripto arrived at Contoso Corp, his trusty laptop under one arm and a stack of PowerShell reference books under the other. Sarah greeted him at the reception, looking frazzled.

“It’s a mess, Doctor,” she said, leading him to the server room. “We have web servers, email servers, VPN endpoints, all needing new certificates. And don’t get me started on our internal PKI…”

Dr. Scripto stroked his PowerShell-blue beard thoughtfully. “Fear not, Sarah. PowerShell is more than up to this task. Let’s start by assessing the situation.”

He opened his laptop and began typing furiously:

# Get all certificates in the LocalMachine store
$certs = Get-ChildItem -Path Cert:\LocalMachine -Recurse

# Find soon-to-expire certificates
$expiringSoon = $certs | Where-Object { $_.NotAfter -lt (Get-Date).AddDays(30) }

# Display the results
$expiringSoon | Select-Object Subject, NotAfter, Thumbprint

“Great Scott!” Dr. Scripto exclaimed. “You weren’t exaggerating, Sarah. You have 237 certificates expiring within the next month!”

Sarah nodded grimly. “And that’s just on this server. We have dozens more.”

Dr. Scripto’s eyes gleamed with the thrill of a challenge. “Well then, we’d better get cracking. First, let’s create a function to generate new certificate requests.”

He began typing again:

function New-CertificateRequest {
    param (
        [string]$Subject,
        [string]$SANs,
        [string]$OutputPath
    )

    $sanList = $SANs -split ','

    $params = @{
        Subject = $Subject
        KeyAlgorithm = 'RSA'
        KeyLength = 2048
        HashAlgorithm = 'SHA256'
        KeyUsage = 'DigitalSignature', 'KeyEncipherment'
        TextExtension = @("2.5.29.17={text}DNS=$($sanList -join '&DNS=')")
    }

    $cert = New-SelfSignedCertificate @params

    $certPath = Join-Path -Path $OutputPath -ChildPath "$($Subject.Split('=')[1]).pfx"
    $cert | Export-PfxCertificate -FilePath $certPath -Password (ConvertTo-SecureString -String 'P@ssw0rd' -AsPlainText -Force)

    return $certPath
}

“Excellent!” Sarah exclaimed. “But what about our internal Certificate Authority?”

“Ah, yes,” Dr. Scripto nodded. “We’ll need to submit these requests to your CA. Let’s create another function for that.”

function Submit-CertificateRequest {
    param (
        [string]$CertReqPath,
        [string]$CAName,
        [string]$Template
    )

    $certReq = Get-Content -Path $CertReqPath -Raw
    $response = certreq -submit -config $CAName -attrib "CertificateTemplate:$Template" $certReq

    if ($response -match 'Certificate retrieved') {
        Write-Host "Certificate issued successfully!"
    } else {
        Write-Host "Failed to issue certificate. Error: $response"
    }
}

As the day wore on, Dr. Scripto and Sarah worked tirelessly, crafting scripts to inventory all servers, generate certificate requests, submit them to the CA, and install the new certificates. They created scheduled tasks to automate the process and set up monitoring to alert them of any issues.

As the sun began to set, Dr. Scripto ran a final check:

$newCerts = Get-ChildItem -Path Cert:\LocalMachine -Recurse | 
    Where-Object { $_.NotAfter -gt (Get-Date).AddDays(365) }

Write-Host "New certificates installed: $($newCerts.Count)"

The console displayed: “New certificates installed: 237”

Sarah let out a whoop of joy. “Dr. Scripto, you’ve done it! You’ve saved us months of manual work!”

Dr. Scripto smiled, adjusting his PowerShell-themed bowtie. “My dear Sarah, this is the power of PowerShell. It turns days of tedious work into mere hours of exciting scripting!”

As they walked out of the server room, Sarah asked, “Dr. Scripto, how can we ever thank you?”

Dr. Scripto’s eyes twinkled. “Well, I’ve always wanted to deliver a guest lecture on ‘The Art of Certificate Automation with PowerShell’. Perhaps you could put in a good word with your CEO?”

Sarah laughed. “Consider it done! I have a feeling our entire IT department will be signing up for that lecture.”

As Dr. Scripto drove back to the PowerShell Academy, he couldn’t help but smile. Another day, another PowerShell victory. He was already looking forward to sharing this adventure with his students.

“Remember,” he mused to himself, “in the world of IT, certificates may expire, but the power of PowerShell is eternal!”

And with that thought, Dr. Scripto began planning his next lecture, excited to inspire a new generation of PowerShell enthusiasts to tackle the challenges of modern IT infrastructure.

Unleashing the Power of PowerShell Automation: Streamline Your IT Operations

PowerShell automation has become an indispensable tool for IT professionals, system administrators, and developers alike. This powerful scripting language, developed by Microsoft, offers a robust platform for automating tasks, managing systems, and streamlining complex IT operations. In this article, we’ll explore the benefits of PowerShell automation and how it can revolutionize your workflow.

What is PowerShell Automation?

PowerShell automation refers to the process of creating scripts and modules that perform repetitive tasks, manage system configurations, and interact with various Windows components and services automatically. By leveraging PowerShell’s extensive cmdlet library and object-oriented approach, IT professionals can create efficient, reusable scripts that save time and reduce human error.

Key Benefits of PowerShell Automation:

  1. Time-saving: Automate repetitive tasks to free up valuable time for more critical projects.
  2. Consistency: Ensure that processes are executed consistently across multiple systems.
  3. Scalability: Easily manage large-scale environments with minimal effort.
  4. Error reduction: Minimize human errors by standardizing processes through scripts.
  5. Flexibility: Integrate with other tools and platforms for comprehensive automation solutions.

Getting Started with PowerShell Automation:

  1. Learn the basics: Familiarize yourself with PowerShell syntax, cmdlets, and scripting concepts.
  2. Identify automation opportunities: Look for repetitive tasks in your daily workflow that can be automated.
  3. Start small: Begin with simple scripts and gradually build more complex automation solutions.
  4. Leverage existing resources: Utilize PowerShell modules and community-contributed scripts to accelerate your learning and development process.
  5. Practice proper scripting techniques: Implement error handling, logging, and documentation in your scripts for better maintainability.

Real-world Applications:

  1. User account management: Automate the creation, modification, and deletion of user accounts across multiple systems.
  2. System maintenance: Schedule and execute regular maintenance tasks such as disk cleanup, software updates, and backups.
  3. Reporting: Generate customized reports on system performance, resource utilization, and security compliance.
  4. Cloud management: Automate the provisioning and management of cloud resources across platforms like Azure and AWS.
  5. Configuration management: Ensure consistent configurations across multiple servers and workstations.

Best Practices for PowerShell Automation:

  1. Use version control: Implement a version control system like Git to track changes and collaborate with team members.
  2. Implement security measures: Follow the principle of least privilege and use secure coding practices to protect sensitive information.
  3. Test thoroughly: Validate your scripts in a non-production environment before deploying them to live systems.
  4. Document your code: Provide clear comments and documentation to make your scripts easily understandable and maintainable.
  5. Stay updated: Keep your PowerShell knowledge current by following Microsoft’s documentation and community resources.

PowerShell automation is a game-changer for IT professionals looking to increase efficiency, reduce errors, and manage complex environments with ease. By mastering PowerShell scripting and automation techniques, you can transform your IT operations and focus on more strategic initiatives. Embrace the power of PowerShell automation today and unlock new levels of productivity in your organization.

PowerShell 7.2: A Powerful Update to Microsoft’s Cross-Platform Automation Tool

PowerShell 7.2, released in November 2021, represents a significant update to Microsoft’s popular command-line shell and scripting language. This version brings numerous improvements and new features, enhancing its capabilities for both Windows and cross-platform environments.

Key Features and Improvements:

  1. Enhanced Performance: PowerShell 7.2 boasts improved startup times and overall performance, making it more responsive and efficient for daily use.
  2. .NET 6 Integration: Built on .NET 6, this version leverages the latest improvements in the .NET framework, offering better stability and expanded capabilities.
  3. Enhanced Error Handling: The new version introduces more descriptive error messages and improved exception handling, making debugging easier for developers and administrators.
  4. PSReadLine Updates: PowerShell 7.2 includes updates to PSReadLine, offering improved command-line editing features such as predictive IntelliSense and better tab completion.
  5. New Cmdlets and Parameters: Several new cmdlets have been added, and existing ones have been enhanced with additional parameters, expanding PowerShell’s functionality.
  6. Improved Cross-Platform Support: This version continues to strengthen PowerShell’s cross-platform capabilities, making it even more versatile for use on Windows, macOS, and Linux.
  7. Security Enhancements: PowerShell 7.2 incorporates various security improvements, including better handling of sensitive data and enhanced execution policies.
  8. Compatibility Improvements: Efforts have been made to improve compatibility with existing PowerShell scripts and modules, easing the transition for users upgrading from earlier versions.
  9. Updated Help System: The help documentation has been expanded and improved, making it easier for users to find information and learn new features.
  10. Community-Driven Enhancements: Many improvements in PowerShell 7.2 come from community feedback and contributions, reflecting Microsoft’s commitment to open-source development.

PowerShell 7.2 is a Long-Term Servicing (LTS) release, meaning it will receive extended support and updates. This makes it an excellent choice for organizations looking for a stable, feature-rich automation and scripting platform.

For system administrators, developers, and IT professionals, PowerShell 7.2 offers a robust set of tools for managing systems, automating tasks, and developing complex scripts. Its cross-platform nature makes it particularly valuable in heterogeneous environments.

To get started with PowerShell 7.2, users can download it from the official Microsoft website or through the Microsoft Store on Windows. It can be installed alongside existing PowerShell versions, allowing for easy testing and gradual adoption.

In conclusion, PowerShell 7.2 represents a significant step forward in Microsoft’s commitment to providing a powerful, flexible, and cross-platform automation tool. Whether you’re managing Windows servers, developing scripts for cloud environments, or automating tasks on Linux systems, PowerShell 7.2 offers the tools and capabilities to streamline your work and boost productivity.

Dr. Scripto and the DNS Dilemma

It was a quiet Friday afternoon at the PowerShell Academy when suddenly, the tranquility was shattered by a frantic knock on Dr. Scripto’s office door.

“Come in!” Dr. Scripto called, looking up from his latest PowerShell module creation.

In burst Timmy, the academy’s junior network administrator, his face pale with panic. “Dr. Scripto! We have a major crisis! The academy’s DNS server is acting up, and nobody can access any websites or resources!”

Dr. Scripto’s eyes lit up with excitement. “A DNS emergency, you say? This sounds like a job for PowerShell!”

He grabbed his trusty laptop, adorned with PowerShell stickers, and followed Timmy to the server room. The place was in chaos, with blinking lights and the sound of frustrated users echoing through the halls.

“Let’s see what we’re dealing with,” Dr. Scripto said, cracking his knuckles and opening a PowerShell console.

First, he checked the DNS service status:

Get-Service -Name DNS | Select-Object Name, Status

“Hmm, the service is running. Let’s dig deeper,” Dr. Scripto muttered.

He then proceeded to check the DNS server’s configuration:

Get-DnsServerSetting -All | Format-List

“Aha!” Dr. Scripto exclaimed. “It seems our forwarders are misconfigured. Let’s fix that!”

He swiftly typed out a command to set the correct forwarders:

Set-DnsServerForwarder -IPAddress "8.8.8.8", "8.8.4.4"

“Now, let’s check our zone transfers,” Dr. Scripto said, his fingers flying across the keyboard:

Get-DnsServerZone | Where-Object {$_.ZoneType -eq "Primary"} | 
    Select-Object ZoneName, ZoneType, IsDsIntegrated, ReplicationScope

“Just as I suspected,” he murmured. “Our zone replication is off. Time to fix it!”

He quickly wrote a script to correct the zone replication:

$zones = Get-DnsServerZone | Where-Object {$_.ZoneType -eq "Primary" -and -not $_.IsDsIntegrated}
foreach ($zone in $zones) {
    Set-DnsServerPrimaryZone -Name $zone.ZoneName -ReplicationScope "Domain" -PassThru
}

As the script ran, the blinking lights on the server rack began to stabilize. Timmy watched in awe as Dr. Scripto worked his PowerShell magic.

“Now, for the final touch,” Dr. Scripto said with a flourish. “Let’s create a monitoring script to alert us if this happens again.”

He quickly wrote out a PowerShell script:

$scriptBlock = {
    $dnsService = Get-Service -Name DNS
    $forwarders = Get-DnsServerForwarder
    if ($dnsService.Status -ne 'Running' -or $forwarders.Count -eq 0) {
        Send-MailMessage -To "admin@powershellacademy.com" -From "monitor@powershellacademy.com" -Subject "DNS Alert!" -Body "Check DNS server immediately!"
    }
}

$trigger = New-JobTrigger -Once -At (Get-Date) -RepeatIndefinitely -RepetitionInterval (New-TimeSpan -Minutes 5)
Register-ScheduledJob -Name "DNSMonitor" -ScriptBlock $scriptBlock -Trigger $trigger

“There!” Dr. Scripto said triumphantly. “Now we’ll be alerted if anything goes wrong with our DNS server.”

Timmy’s eyes were wide with admiration. “Dr. Scripto, that was amazing! How did you know exactly what to do?”

Dr. Scripto chuckled, adjusting his PowerShell-themed bowtie. “My dear Timmy, in the world of IT, DNS is always the culprit until proven otherwise. And with PowerShell, we have the tools to prove it – and fix it – faster than you can say ‘cmdlet’!”

As they walked back to Dr. Scripto’s office, cheers erupted from around the academy as students and staff regained their internet access.

“Remember, Timmy,” Dr. Scripto said sagely, “in the face of any IT crisis, keep calm and PowerShell on!”

And with that, another DNS crisis was averted, thanks to the power of PowerShell and the wisdom of Dr. Scripto. As for Timmy, he headed straight to the library, determined to study more about DNS and PowerShell, inspired by the day’s adventure.