Start-AIEventAnalyzer.ps1

<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 4ff39349-66db-44eb-a12f-eb4249b0f24b
 
.AUTHOR Voytas
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS Events,AZURE,OpenAI
 
.LICENSEURI
 
.PROJECTURI https://github.com/voytas75/AzureOpenAI-PowerShell/tree/master/AIEventAnalyzer
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES PSAOAI
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
 Analyze Windows event logs using AZURE OpenAI
 
 #>

 using namespace System.Diagnostics
 
 Param()

function LogData {
  <#
.SYNOPSIS
This function logs the data into a specified file in a specified folder.
 
.DESCRIPTION
The LogData function takes a log folder, filename, data, and type as parameters.
It logs these parameters to a file in the specified folder. Each logged line includes the date, time, and type.
 
.PARAMETER LogFolder
This parameter accepts the folder where the log file will be stored.
 
.PARAMETER FileName
This parameter accepts the name of the file where the data will be logged.
 
.PARAMETER Data
This parameter accepts the data that needs to be logged.
 
.PARAMETER Type
This parameter accepts the type of the data that needs to be logged. The type can be "user", "system", or "other".
 
.EXAMPLE
LogData -LogFolder "C:\Logs" -FileName "log.txt" -Data "Some data to log" -Type "user"
#>

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

    [Parameter(Mandatory = $true)]
    [string]$FileName,

    [Parameter(Mandatory = $true)]
    [string]$Data,

    [Parameter(Mandatory = $true)]
    [ValidateSet("user", "system", "other")]
    [string]$Type
  )

  # Create the log folder if it doesn't exist
  if (!(Test-Path $LogFolder)) {
    New-Item -ItemType Directory -Force -Path $LogFolder
  }

  # Log the data, date, time, and type to the specified file in the specified folder
  $logFilePath = Join-Path -Path $LogFolder -ChildPath $FileName
  $logEntry = "{0}; {1}; {2}; {3}; {4}; {5}" -f (Get-Date), $Type, $Data, $null, $null, $null
  Add-Content -Path $logFilePath -Value $logEntry
}

function Invoke-AIEventAnalyzer {
  <#
.SYNOPSIS
This function uses Azure OpenAI to interpret the input using a language model and the user's query.
 
.DESCRIPTION
The Invoke-AICopilot function takes an input object and a natural language query as parameters.
It converts the input object to a string and calls the Invoke-AzureOpenAIChatCompletion function to interpret the input using a language model and the user's query.
 
.PARAMETER InputObject
This parameter accepts the input object that needs to be interpreted.
 
.PARAMETER NaturalLanguageQuery
This parameter accepts the natural language query to interpret the input object.
 
.EXAMPLE
Invoke-AICopilot -InputObject $InputObject -NaturalLanguageQuery "Show only processes using more than 500MB of memory"
#>

  [CmdletBinding()]
  param (
    [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
    [object]$InputObject,

    [Parameter(Mandatory = $true, Position = 0)]
    [string]$NaturalLanguageQuery,

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

  begin {

    # This block runs once before any input is processed
    # Initialize an array to store the input objects
    $inputObjects = @()
  }

  process {
    # This block runs once for each item of input
    # Add the current input object to the array
    $inputObjects += $InputObject
  }

  end {
    # This block runs once after all input has been processed
    # Convert the array of input objects into a single string
    $inputString = $inputObjects | Out-String

    # Call the Invoke-AzureOpenAIChatCompletion function to interpret the input using a language model and the user's query
    $response = Invoke-PSAOAIChatCompletion -SystemPrompt $NaturalLanguageQuery -usermessage $inputString -OneTimeUserPrompt -Mode Precise -simpleresponse -LogFile $LogFile

    # Return the response from the Azure OpenAI Chat Completion function
    return $response 
  }
}

# This function is used to clear the LLMDataJSON
function Clear-LLMDataJSON {
  <#
.SYNOPSIS
This function clears the LLMDataJSON.
 
.DESCRIPTION
The Clear-LLMDataJSON function takes a string of data as input, finds the first instance of '[' and the last instance of ']', and returns the substring between these two characters. This effectively removes any characters before the first '[' and after the last ']'.
 
.PARAMETER data
A string of data that needs to be cleared.
 
.EXAMPLE
$data = "{extra characters}[actual data]{extra characters}"
Clear-LLMDataJSON -data $data
#>

  param (
    # The data parameter is mandatory and should be a string
    [Parameter(Mandatory = $true)]
    [string]$data
  )
  # Find the first occurrence of '[' and remove everything before it
  $data = $data.Substring($data.IndexOf('['))
  # Find the last occurrence of ']' and remove everything after it
  $data = $data.Substring(0, $data.LastIndexOf(']') + 1)
  # Return the cleaned data
  return $data
}

function Get-EventSeverity {
  # Define the parameters for the function
  param (
    # The Severity parameter is mandatory and should be an integer or a string
    [Parameter(Mandatory = $true)]
    [ValidateScript({
        if (($_ -is [int] -and 1..5 -contains $_) -or ($_ -is [string] -and $_ -in "Critical", "Error", "Warning", "Information", "Verbose")) {
          $true
        }
        else {
          throw "Invalid input. Please enter an integer between 1 and 5 or a valid severity name."
        }
      })]
    $Severity
  )

  # Define the hash table for severity levels and their corresponding names
  $EventLevels = @{
    1 = "Critical"
    2 = "Error"
    3 = "Warning"
    4 = "Information"
    5 = "Verbose"
  }

  # Define the reverse hash table for severity names and their corresponding levels
  $EventLevelsReverse = $EventLevels.GetEnumerator() | Group-Object -Property Value -AsHashTable -AsString

  # Check if the input is an integer or a string and return the corresponding value
  if ($Severity -is [int]) {
    return $EventLevels[$Severity]
  }
  else {
    return ($EventLevelsReverse[$Severity]).Name
  }
}

function Get-EventLogInfo {
  <#
.SYNOPSIS
   This function retrieves the count of events from a specified Windows Event Log based on the severity level.
 
.DESCRIPTION
   The Get-EventLogInfo function creates an object of the specified Windows Event Log and filters the entries based on the provided severity level.
   It then returns the count of the filtered events.
 
.PARAMETER logName
   The name of the Windows Event Log from which the events are to be retrieved.
 
.PARAMETER severityLevel
   The severity level of the events to be retrieved. The valid values are "Critical", "Error", "Warning", "Information", "Verbose", "SuccessAudit", "FailureAudit".
 
.EXAMPLE
   Get-EventLogInfo -logName "System" -severityLevel "Information"
   This command retrieves the count of "Information" level events from the "System" Windows Event Log.
#>

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

    [Parameter(Mandatory = $true)]
    [ValidateSet("Critical", "Error", "Warning", "Information", "Verbose", "SuccessAudit", "FailureAudit")]
    [string]$severityLevel
  )

  # Create an object of the specified Windows Event Log
  $eventLog = new-object System.Diagnostics.EventLog($logName)

  # Filter the entries of the Event Log based on the provided severity level
  $filteredEvents = $eventLog.Entries | Where-Object { $_.EntryType -eq $([System.Diagnostics.EventLogEntryType]::$severityLevel) }
  
  # Return the count of the filtered events
  return $filteredEvents.Count
}

function Get-LogFileDetails {
  param (
    [Parameter(Mandatory = $true)]
    [string]$LogFolder,
    [Parameter(Mandatory = $true)]
    [string]$logFileName,
    [Parameter(Mandatory = $true)]
    [string]$LogEventDataFileName
    
  )
  $logFile = Join-Path -Path $LogFolder -ChildPath $logFileName
  if (Test-Path -Path $logFile) {
    $logFileDetails = Get-Item -Path $logFile
    Write-Host "Log File Details:"
    Write-Host "-----------------"
    Write-Host "Full Path: $($logFileDetails.FullName)"
    Write-Host "Size: $($logFileDetails.Length) bytes"
    Write-Host "Last Modified: $($logFileDetails.LastWriteTime)"
  }
  else {
    Write-Host "Log file does not exist."
  }
  Write-Host ""
  if (Test-Path -Path $LogEventDataFileName) {
    $logFileEventDetails = Get-Item -Path $LogEventDataFileName
    Write-Host "Log File Event Details:"
    Write-Host "-----------------"
    Write-Host "Full Path: $($logFileEventDetails.FullName)"
    Write-Host "Size: $($logFileEventDetails.Length) bytes"
    Write-Host "Last Modified: $($logFileEventDetails.LastWriteTime)"
  }
  else {
    Write-Host "Log file does not exist."
  }


}

function Format-ContinuousText {
  # Define the parameters for the function
  param (
    # The text parameter is mandatory and should be a string
    [Parameter(Mandatory = $true)]
    [string]$text
  )

  # This function is designed to transform any text into a continuous string by replacing newline characters with a space.
  # It accepts a string as input and returns a string where all newline characters (`r`n) and (`n`) are replaced with a space (" ").

  # The `-replace` operator is used to replace all newline characters with a space.
  # The result is returned as the output of the function.

  $text = $text -replace "`r`n", " " # Replace carriage return and newline characters
  return $text -replace "`n", " " # Replace newline characters
}

function Update-PromptData {
  <#
.SYNOPSIS
This function updates a given prompt with additional instructions for both experienced and less experienced professionals.
 
.DESCRIPTION
The Update-PromptData function takes an input prompt and appends additional instructions to it. These instructions are tailored for both experienced and less experienced professionals. The function returns the updated prompt.
 
.PARAMETER inputPrompt
The input prompt that needs to be updated. This parameter is mandatory.
 
.EXAMPLE
$promptAnalyze = Update-PromptData -inputPrompt $promptAnalyze
This example updates the $promptAnalyze variable.
 
.EXAMPLE
$promptTroubleshoot = Update-PromptData -inputPrompt $promptTroubleshoot
This example updates the $promptTroubleshoot variable.
#>

  param (
    [Parameter(Mandatory = $true)]
    [string]$inputPrompt
  )

  # Text for experienced professionals
  $experiencedProfessionalsText = "Ensure that the response is comprehensive and detailed, providing in-depth insights."
  
  # Text for less experienced professionals
  $lessExperiencedProfessionalsText = "Make sure the analysis is easy to understand, with clear explanations and step-by-step instructions."

  # Combine the input prompt with the additional instructions
  $updatedPrompt = $inputPrompt + " " + $experiencedProfessionalsText

  # Return the updated prompt
  return $updatedPrompt
}

function Get-SummarizeSession {
  param (
    [Parameter(Mandatory = $true)]
    [string]$LogFolder,
    [Parameter(Mandatory = $true)]
    [string]$logFileName
  )

  Write-Host "Wait for summary..." -ForegroundColor Magenta
  Write-Host "it isn't logged" -ForegroundColor DarkGray
  Write-Host ""

  # Read the log file
  $logData = Get-Content -Path (Join-Path -Path $LogFolder -ChildPath $logFileName)

  # Initialize counters
  $userActionsCount = 0
  $systemResponsesCount = 0

  # Count the occurrences of ";user" and ";system" in the log file
  $userActionsCount = ($logData -match "; user;").Count
  $systemResponsesCount = ($logData -match "; system;").Count
  

  # Print the summary
  Write-Host "Session Summary:"
  Write-Host "Total User Actions: $userActionsCount"
  Write-Host "Total System Responses: $systemResponsesCount"
  Write-Host ""

  Write-Host "Wait for more..." -ForegroundColor Magenta
  Write-Host ""

  # Summarize the session log data using AI
  $summary = $logData | Invoke-AIEventAnalyzer -NaturalLanguageQuery "Summarize the log data in a single paragraph to show the user what was done. Use a cheerful style. Finally, add something nice for the user."
  Write-Host ""
  # Print the summary
  Write-Host "AI Summary:" -ForegroundColor Green
  Write-Host $summary -ForegroundColor White
}

function Start-AIEventAnalyzer {
  [CmdletBinding()]
  param (
    [Parameter()]
    [string]$LogFolder
  )

  if ([string]::IsNullOrEmpty($LogFolder)) {
    $LogFolder = Join-Path -Path ([Environment]::GetFolderPath("MyDocuments")) -ChildPath "AIEventAnalyzer"
    if (-not (Test-Path -Path $LogFolder)) {
      New-Item -ItemType Directory -Path $LogFolder | Out-Null
    }
  }
  Write-Host "[Info] The logs will be saved in the following folder: $LogFolder" -ForegroundColor DarkGray
  Write-Host ""
        
  # Define the prompts for the AI model
  $promptAnalyze = @'
###Instruction###
 
Your role as a prompt maker is to develop a series of prompts designed to guide the incident analysis process, focusing on identifying root causes, understanding their impact, and proposing practical solutions or further investigative steps. It is critical in analyzing Windows event data to uncover patterns, anomalies, and insights that shed light on system performance, stability, and security. Responses must strictly follow the JSON format, ensuring clarity and consistency in the analysis process.
 
Example of a JSON response with two records:
[
  {
    "promptNumber": 1,
    "prompt": "Analyze the root cause of the W32time service stopping and assess if it is a regular behavior or an indication of an underlying issue.",
    "action": "Aznalyze",
    "analysisActions": [
      "Check if the service is configured to stop at scheduled times.",
      "Review system logs for any related errors or warnings.",
      "Verify if there was a system shutdown or restart."
    ]
  },
  {
    "promptNumber": 2,
    "prompt": "Analyze the pattern of package installations and removals, and determine if there are any inconsistencies or issues with the update process.",
    "action": "Aznalyze",
    "analysisActions": [
      "Ensure that Adobe Acrobat is running the latest version.",
      "Review Adobe Acrobat's security settings and permissions.",
      "Check for any related security advisories from Adobe."
    ]
  }
]
'@


  $promptTroubleshoot = @'
###Instruction###
 
Your job as a prompt creator is to develop a set of prompts based on the Windows event database to diagnose the root causes of problems that affect the performance, reliability or security of the system, propose targeted solutions and verify their effectiveness. These prompts MUST guide user through a systematic troubleshooting process, providing comprehensive analysis and resolution of identified issues. Responses must strictly follow the JSON format.
 
Example of a JSON response with two records:
[
  {
    "promptNumber": 1,
    "prompt": "Investigate the reason behind the change in the startup type of the Background Intelligent Transfer Service (BITS) and whether it aligns with system policies or user actions.",
    "action": "Troubleshoot",
    "analysisActions": [
      "Review recent administrative actions or group policies that might have changed the BITS configuration.",
      "Check if any software installations or updates require BITS to change its startup type.",
      "Ensure that the change does not affect any critical system updates or operations."
    ]
  },
  {
    "promptNumber": 2,
    "prompt": "Analyze the implications of system session moves indicated by 'Kernel-Power' events and determine if they are expected transitions based on user interactions or system policies.",
    "action": "Troubleshoot",
    "analysisActions": [
      "Correlate the session moves with user login, unlock, or input events to confirm if they are user-initiated.",
      "Check for any power settings or scripts that might automate session state changes",
      "Ensure that these session changes do not indicate any instability or security concerns."
    ]
  }
]
'@


  $promptDocumentation = @'
###Instruction###
 
As a prompt creator, it's your responsibility to create prompts that help users gather relevant information from Windows events to include in your documentation. These prompts should focus on capturing key details such as event types, event IDs, timestamps, event messages, and any associated activities. Make sure your documentation provides a clear and concise overview of the events and their significance. Responses must strictly follow JSON to maintain consistency and facilitate easy referencing.
 
Example of a JSON response with two records:
[
    {
        "promptNumber": 1,
        "prompt": "A program has crashed. Identify the program name and any error code displayed (if applicable).",
        "action": "Documentation",
        "analysisActions": [
            "Identify if the crashing program is essential for system operation.",
            "Search for known issues or solutions related to the program name and error code (if available).",
            "Review application logs for additional details about the crash.",
            "Consider monitoring program performance to identify potential causes (e.g., resource exhaustion).",
            "If the program is critical, investigate potential workarounds or mitigation strategies."
        ]
    },
    {
        "promptNumber": 2,
        "prompt": "Are there any additional details or logs associated with the event?",
        "action": "Documentation",
        "analysisActions": [
            "Additional logs may provide more context about the event."
        ]
    }
]
'@


  $promptCorrelate = @'
###Instruction###
 
As a prompt creator, you're tasked with generating a series of prompts focused on identifying correlations between Windows events, determining their importance, and gaining actionable insights to gain deeper insights into system behavior and performance, and improve system management and troubleshooting processes. Responses must strictly follow the JSON format, which facilitates structured analysis and interpretation of correlated data.
 
Example of a JSON response with two records:
[
    {
        "promptNumber": 1,
        "prompt": "Identify events occurring immediately before or after a specific event type (e.g., system errors). Analyze the timestamps and event messages to determine potential cause-and-effect relationships.",
        "action": "Correlate",
        "analysisActions": [
            "Consider the logical sequence of events to identify potential dependencies.",
            "Focus on frequently occurring patterns of pre- and post-crash events to pinpoint potential root causes.",
            "Prioritize investigation based on the severity of the correlated event (e.g., high-impact errors)."
        ]
    },
    {
        "promptNumber": 2,
        "prompt": "Analyze trends in specific event types (e.g., security warnings) over time. Look for spikes or recurring patterns that might indicate ongoing issues or potential security threats.",
        "action": "Correlate",
        "analysisActions": [
            "Correlate event trends with system activities or configuration changes.",
            "Evaluate the potential impact of identified trends on system stability and security.",
            "Prioritize troubleshooting efforts based on the severity and frequency of the trending event type."
        ]
    }
]
'@


  $promptPredict = @'
###Instruction###
 
Your goal as a prompt maker is to create prompts to select appropriate predictive analytics techniques, train predictive models, and interpret predictive insights to predict the behavior of the system. These prompts should allow users to use predictive analytics to optimize system performance and mitigate potential risks. Responses must strictly follow the JSON format.
 
Example of a JSON response with two records:
[
  {
    "promptNumber": 1,
    "prompt": "Identify historical event patterns that might be indicative of future occurrences (e.g., cyclical resource usage spikes). Select appropriate predictive modeling techniques (e.g., time series forecasting) based on the identified patterns and desired outcome.",
    "action": "Predict",
    "analysisActions": [
      "Consider the volume and frequency of historical events for choosing suitable modeling techniques.",
      "Evaluate the desired prediction timeframe (short-term vs. long-term) when selecting a model.",
      "Prioritize techniques that align with system performance metrics you aim to predict (e.g., resource utilization, application response times)."
    ]
  },
  {
    "promptNumber": 2,
    "prompt": "Train and validate a predictive model using historical event data. Analyze the model's performance metrics (e.g., accuracy, precision) to assess its reliability for forecasting future events. Interpret the model's predictions in the context of system behavior and resource allocation.",
    "action": "Predict",
    "analysisActions": [
      "Fine-tune model parameters for optimal predictive performance.",
      "Monitor the model's predictions over time and retrain it if significant deviations occur.",
      "Use the model's insights to proactively allocate resources and mitigate potential performance bottlenecks.",
      "Evaluate the cost-benefit of implementing the predictive model based on its accuracy and impact on system management."
    ]
  }
]
'@


  $promptOptimize = @'
###Instruction###
 
As a prompt engineer, your job is to generate prompts based on insights from analyzing Windows event data to identify optimization opportunities, implement optimization strategies, and measure the impact of optimization efforts on system performance. These prompts should guide users through a systematic optimization process, ensuring continuous improvement and performance gains. Responses must strictly follow the JSON format.
 
Example of a JSON response with two records:
[
  {
    "promptNumber": 1,
    "prompt": "Analyze event data to identify bottlenecks or recurring issues that are impacting system performance or resource utilization (e.g., frequent disk I/O delays, high memory usage by specific applications).",
    "action": "Optimize",
    "analysisActions": [
      "Prioritize optimization efforts based on the severity and impact of identified bottlenecks.",
      "Consider potential solutions based on the nature of the issue (e.g., hardware upgrades, software configuration changes).",
      "Evaluate the cost-effectiveness of potential solutions before implementing them."
    ]
  },
  {
    "promptNumber": 2,
    "prompt": "Implement and monitor the effectiveness of chosen optimization strategies. Analyze system performance metrics (e.g., CPU utilization, application response times) before and after optimization to measure the impact.",
    "action": "Optimize",
    "analysisActions": [
      "Correlate changes in event data with performance improvements after optimization.",
      "Continuously monitor system performance to identify new optimization opportunities.",
      "Refine or adjust optimization strategies based on ongoing analysis and performance metrics."
    ]
  }
]
'@


  $promptAudit = @'
###Instruction###
 
Your tasks as a prompt engineer are to develop prompts to define audit criteria, suggest how audit reviews are conducted, and document audit findings. These prompts should facilitate end-to-end auditing processes, ensuring that the user can effectively assess system compliance, audit Windows event logs to ensure compliance with general best practices for regulatory requirements, organizational policies, and system security. and identify areas for improvement. Responses must strictly follow the JSON format.
 
Example of a JSON response with two records:
[
  {
    "promptNumber": 1,
    "prompt": "Define specific audit criteria based on relevant regulations, organizational policies, and security best practices. Identify specific event types, user activities, or access attempts that require scrutiny during the audit.",
    "action": "Audit",
    "analysisActions": [
      "Consider the sensitivity of data and systems to determine appropriate audit criteria.",
      "Prioritize audit criteria based on the potential security risks and regulatory compliance requirements.",
      "Reference industry standards or security frameworks to ensure comprehensive audit coverage."
    ]
  },
  {
    "promptNumber": 2,
    "prompt": "Conduct a thorough review of Windows event logs based on the defined criteria. Analyze identified events for potential security violations, policy breaches, or unauthorized access attempts. Document all audit findings, including timestamps, event details, and any remediation actions taken.",
    "action": "Audit",
    "analysisActions": [
      "Correlate events with user activity logs for additional context.",
      "Evaluate the potential impact of identified security events on system integrity and data confidentiality.",
      "Recommend appropriate corrective actions based on the audit findings (e.g., user account suspension, policy adjustments).",
      "Maintain clear and concise audit reports for future reference and regulatory compliance purposes."
    ]
  }
]
'@


  $promptAutomate = @'
###Instruction###
 
As a prompt engineer, your goal is to create prompts based on analysis of Windows event data, aimed at identifying automation opportunities, designing automated workflows, and implementing automation solutions. These prompts should enable the user to automate routine tasks, reduce manual effort, and improve overall operational efficiency. Responses must strictly follow the JSON format.
 
Example of a JSON response with two records:
[
  {
    "promptNumber": 1,
    "prompt": "Identify repetitive tasks or manual interventions triggered by specific Windows events (e.g., restarting a service after a crash, applying security updates). Analyze the frequency and impact of these tasks to determine their suitability for automation.",
    "action": "Automate",
    "analysisActions": [
      "Prioritize automation efforts based on the time saved and potential for human error reduction.",
      "Consider the complexity of the task and the availability of suitable automation tools.",
      "Evaluate the potential impact of automation failures and develop mitigation strategies."
    ]
  },
  {
    "promptNumber": 2,
    "prompt": "Design an automated workflow that replicates the identified manual task using scripting languages or automation tools. Integrate event triggers and appropriate actions based on the analyzed event data. Test and refine the automation solution to ensure its reliability and effectiveness.",
    "action": "Automate",
    "analysisActions": [
      "Document the automation workflow clearly for future reference and maintenance.",
      "Schedule regular testing and monitoring of automated tasks to ensure ongoing functionality.",
      "Establish procedures for handling errors or unexpected events within the automated workflow.",
      "Continuously evaluate the effectiveness of automation and identify opportunities for further optimization."
    ]
  }
]
'@


  $promptEducate = @'
###Instruction###
 
As a prompt engineer, it's your job to develop prompts to create learning materials, conduct training sessions, or facilitate knowledge-sharing activities based on the results of Windows Event Analysis. These prompts should ensure that users can effectively communicate key concepts, best practices, and actionable insights to increase the understanding and proficiency of IT staff. Responses must strictly follow the JSON format.
 
Example of a JSON response with two records:
[
  {
    "promptNumber": 1,
    "prompt": "Identify key themes or recurring issues revealed by your event data analysis. Consider common challenges faced by IT staff and areas where knowledge gaps might exist.",
    "action": "Educate",
    "analysisActions": [
      "Prioritize educational topics based on their potential impact on IT staff efficiency and system security.",
      "Tailor content to the specific needs and technical expertise of your audience.",
      "Incorporate real-world examples from your event analysis to illustrate key points and best practices."
    ]
  },
  {
    "promptNumber": 2,
    "prompt": "Choose an appropriate educational format (e.g., training manuals, interactive workshops, knowledge-sharing sessions) that aligns with the identified content and target audience. Develop clear and concise learning objectives for your chosen format.",
    "action": "Educate",
    "analysisActions": [
      "Incorporate interactive elements or hands-on activities to enhance engagement and knowledge retention.",
      "Encourage discussions and knowledge sharing to foster collaboration among IT staff.",
      "Provide opportunities for feedback and evaluation to ensure the effectiveness of your educational materials."
    ]
  }
]
'@


  $promptSummarize = @'
###Instruction###
 
As a prompt engineer, it's your job to develop prompts that help users summarize the most critical aspects of Windows events, including notable patterns, significant anomalies, identified root causes, and recommended actions. You need to extract key insights and insights from your Windows event data in concise summaries for easy referencing and analysis. These prompts should enable users to effectively communicate the essence of the data analysis process and its implications in a clear and concise manner. Responses must strictly follow JSON to maintain consistency and facilitate easy referencing.
 
Example of a JSON response with two records:
[
  {
    "promptNumber": 1,
    "prompt": "Did you encounter any high-severity events (e.g., errors, warnings)? If so, briefly describe them and note the timestamps for potential reference.",
    "action": "Summarize",
    "analysisActions": [
        "Classify the high-severity events by event type (e.g., security errors, application crashes).",
        "Evaluate the potential impact of each high-severity event on system stability, security, or functionality.",
        "Correlate high-severity events with other relevant events to identify potential root causes or contributing factors.",
        "Prioritize investigation and remediation efforts based on the severity and potential impact of the events.",
        "Consider referring to knowledge bases or vendor documentation for troubleshooting guidance specific to the identified high-severity events."
    ]
  },
  {
    "promptNumber": 2,
    "prompt": "Considering your findings, what specific actions are recommended to address identified problems or improve system health?",
    "action": "Summarize",
    "analysisActions": [
        "Prioritize recommendations based on their potential impact on mitigating risks or enhancing system performance.",
        "Align recommendations with the identified root causes of problems to ensure they address the underlying issues.",
        "Consider the feasibility and potential resource requirements for implementing each recommendation.",
        "Formulate clear and actionable steps for each recommendation, including specific configuration changes, security updates, or troubleshooting procedures.",
        "Estimate the expected timeframe for implementing the recommendations and their potential impact on system downtime (if applicable).",
        "Develop a plan for monitoring the effectiveness of implemented recommendations and identify the need for further adjustments."
    ]
  }
]
'@


  # Define the list of actions
  $actions = @("Analyze", "Troubleshoot", "Correlate", "Predict", "Optimize", "Audit", "Automate", "Educate", "Documentation", "Summarize")
  # Define the list of prompts corresponding to each action
  $prompts = @($promptAnalyze, $promptTroubleshoot, $promptCorrelate, $promptPredict, $promptOptimize, $promptAudit, $promptAutomate, $promptEducate, $promptDocumentation, $promptSummarize)
    
  do {
    # Display the list of actions to the user
    Write-Host "Please choose an action for Windows events:" -ForegroundColor DarkCyan
    for ($i = 0; $i -lt $actions.Length; $i++) {
      Write-Host "$($i+1). $($actions[$i])" -ForegroundColor Cyan
    }
    Write-Host ""

    # Ask the user to choose an action
    Write-Host "Enter the number of your chosen action (default: 1 - Analyze)" -ForegroundColor DarkCyan -NoNewline
    $chosenActionIndex = Read-Host " "
    if ([string]::IsNullOrEmpty($chosenActionIndex)) {
      $chosenActionIndex = 1
      break
    }
    # Validate the user's input
  } while ($chosenActionIndex -notmatch '^\d+$' -or [int]$chosenActionIndex -lt 1 -or [int]$chosenActionIndex -gt $actions.Length)
  
  Write-Verbose $chosenActionIndex

  # Get the chosen action and corresponding prompt
  $chosenAction = $actions[$chosenActionIndex - 1]
  Write-Verbose $chosenAction 
  $prompt_one = $prompts[$chosenActionIndex - 1]
  Write-Verbose $prompt_one

  # Display the chosen action to the user
  Write-Host "Your selected action is: $chosenAction" -ForegroundColor Green
  Write-Host ""  
  # Clean the system prompt by removing non-ASCII characters
  $prompt_one = [System.Text.RegularExpressions.Regex]::Replace($prompt_one, "[^\x00-\x7F]", " ")        

  # Get a list of all Windows event logs, sort them by record count in descending order, and select the top 25 logs
  $logs = Get-WinEvent -ListLog * -ErrorAction SilentlyContinue | Sort-Object RecordCount -Descending | Select-Object LogName, RecordCount

  $minEventCountDefault = 2100
  Write-Host "Please enter the minimum number of events a log should have to be shown in the list." -ForegroundColor DarkCyan
  Write-Host "Enter the minimum event count (default: $minEventCountDefault)" -ForegroundColor DarkCyan -NoNewline
  $minEventCount = Read-Host " "
  if ([string]::IsNullOrEmpty($minEventCount) -or $minEventCount -lt 0) {
    $minEventCount = $minEventCountDefault
  }
  Write-Host "You have chosen to display logs with at least $minEventCount events." -ForegroundColor Green
  Write-Host ""


  $logs = $logs | Where-Object { $_.RecordCount -ge $minEventCount }

  # Display the name and record count of each log
  #$logs | ForEach-Object {Write-Host "$($_.LogName) - $($_.RecordCount) records"}
  try {
    $LogsFiltered = $logs.where{ $_.RecordCount -gt $minEventCount }
    foreach ($log in $LogsFiltered) {
      Write-Host "$($log.LogName) - " -ForegroundColor Cyan -NoNewline
      Write-Host "$($log.RecordCount) records" -ForegroundColor DarkCyan
    }
  }
  catch [System.Management.Automation.HaltCommandException] {
    # Handle termination here (e.g., write message)
    Write-Host "Command stopped by user (Quit)" -ForegroundColor DarkMagenta
    
  }
  Write-Host ""

  $LogNameDefault = $logs[0].LogName
  # Prompt the user to enter the log name for analysis
  Write-Host "Please enter the LogName from the list above to analyze events (default: $LogNameDefault)" -ForegroundColor DarkCyan -NoNewline
  $chosenLogName = Read-Host " "

  # Check if the chosen log name is empty or null. If it is, set it to the first log name in the logs list
  if ([string]::IsNullOrEmpty($chosenLogName)) {
    $chosenLogName = $LogNameDefault
  }
  Write-Host "You have chosen the log: $chosenLogName" -ForegroundColor Green
  Write-Host ""

  # Get the record count for the chosen log name
  $logRecordCount = ($logs | Where-Object { $_.logname -eq "$chosenLogName" }).Recordcount
  # Display the record count for the chosen log name
  Write-Host "The log '$chosenLogName' has $logRecordCount events of all severity levels."
  Write-Host ""

  # Loop until a valid severity level is entered
  do {
    Write-Host "Counting the number of events for each severity level, this may take some time..." -ForegroundColor DarkCyan
    $severityLevels = @("Critical", "Error", "Warning", "Information", "Verbose")
    foreach ($level in $severityLevels) {
      $count = Get-EventLogInfo -logName $chosenLogName -severityLevel $level
      Write-Host "The log '$chosenLogName' has $count events of '$level' severity level." -ForegroundColor DarkCyan
    }
    Write-Host ""
    # Ask the user to enter the severity level
    Write-Host "Please enter the severity level of the events you want to analyze. Options are: Critical, Error, Warning, Information, Verbose, or All." -ForegroundColor DarkCyan
    Write-Host "Enter the severity level (default: All)" -ForegroundColor DarkCyan -NoNewline
    $chosenSeverityLevel = Read-Host " "
    # If the entered severity level is valid, get the events for that severity level
    if ($chosenSeverityLevel -in @("Critical", "Error", "Warning", "Information", "Verbose")) {
      $filterXPath = "*[System[(Level=$(Get-EventSeverity -Severity $chosenSeverityLevel))]]"
      $data_to_analyze = Get-WinEvent -LogName $chosenLogName -FilterXPath $filterXPath -ErrorAction SilentlyContinue | Select-Object Message, Level, ProviderName, ProviderId, LogName, TimeCreated 
      $logRecordServerityCount = $data_to_analyze.Count
      Write-Host "You have chosen the severity level: $chosenSeverityLevel ($(Get-EventSeverity -Severity $chosenSeverityLevel))" -ForegroundColor Green
      Write-Host ""
    }
    # If the entered severity level is empty or null, set it to "All" and get all events
    elseif ([string]::IsNullOrEmpty($chosenSeverityLevel)) {
      $chosenSeverityLevel = "All"
      $logRecordServerityCount = $logRecordCount
      Write-Host "You have chosen the severity level: $chosenSeverityLevel" -ForegroundColor Green
      Write-Host ""
    }
    # If the entered severity level is invalid, set it to "All" and get all events
    else {
      $chosenSeverityLevel = "All"
      $logRecordServerityCount = $logRecordCount
      Write-Host "You have chosen the severity level: $chosenSeverityLevel" -ForegroundColor Green
      Write-Host ""
    }
  } until ([int]$logRecordServerityCount -gt 0)

  $logRecordServerityCountDefault = 50
  if ($logRecordServerityCount -lt $logRecordServerityCountDefault) {
    $logRecordServerityCountDefault = $logRecordServerityCount
  }
  # Ask the user to enter the number of most recent events they want to analyze
  Write-Host "Please enter the number of most recent '$chosenLogName' for '$chosenSeverityLevel' serverity events you want to analyze (1-$logRecordServerityCount) (default: $logRecordServerityCountDefault)" -ForegroundColor DarkCyan -NoNewline
  $chosenLogNameNewest = Read-Host " "

  # If the entered number is empty or null, set it to 10
  if ([string]::IsNullOrEmpty($chosenLogNameNewest)) {
    $chosenLogNameNewest = $logRecordServerityCountDefault
  }
  Write-Host "You have chosen $chosenLogNameNewest most recent events." -ForegroundColor Green
  Write-Host ""

  # If the chosen severity level is not valid, get the most recent events up to the entered number
  if ($chosenSeverityLevel -notin @("Critical", "Error", "Warning", "Information", "Verbose")) {
    $data_to_analyze = Get-WinEvent -LogName $chosenLogName -MaxEvents $chosenLogNameNewest | Select-Object Message, Level, ProviderName, ProviderId, LogName, TimeCreated 
  }
  else {
    $data_to_analyze = $data_to_analyze | Select-Object -First $chosenLogNameNewest
  }
  $logRecordServerityCount = $data_to_analyze.Count

  # Display the chosen log name, severity level, and event count
  Write-Host "Action: $chosenAction" -ForegroundColor Yellow
  Write-Host "LogName: $chosenLogName" -ForegroundColor Magenta
  Write-Host "Level: $chosenSeverityLevel" -ForegroundColor Blue
  Write-Host "Event count: $logRecordServerityCount (all: $logRecordCount)"  -ForegroundColor Yellow 
  Write-Host ""

  $currentDateTime = Get-Date -Format "yyyyMMdd-HHmmss"
  $chosenLogName = $chosenLogName -replace '[\\/:*?"<>|]', '_'
  $logFileName = "$chosenAction-$chosenLogName-$chosenSeverityLevel-$currentDateTime.txt"
  $data_to_file = [ordered]@{
    "Action"     = $chosenAction
    "LogName"    = $chosenLogName
    "Level"      = $chosenSeverityLevel
    "EventCount" = $logRecordServerityCount
    "All Events" = $logRecordCount
    "Prompt"     = (Format-ContinuousText -text $prompt_one)
  }
  foreach ($key in $data_to_file.Keys) {
    LogData -LogFolder $LogFolder -FileName $logFileName -Data "$key : $($data_to_file[$key])" -Type "user"
  }

  $logFileNameEventData = "$chosenAction-$chosenLogName-$chosenSeverityLevel-EventData-$currentDateTime.txt"
  $logFileNameEventData = Join-Path $LogFolder $logFileNameEventData
  LogData -LogFolder $LogFolder -FileName $logFileName -Data "Log file with events data: $logFileNameEventData" -Type "other"

  Write-Verbose "Log with event data: $logFileNameEventData"

  Write-Host "Generating prompts for '$chosenAction' action..." -ForegroundColor Green

  # Invoke the AI model with the prompt and the data to analyze
  $json_data = $data_to_analyze | Invoke-AIEventAnalyzer -NaturalLanguageQuery $prompt_one -LogFile $logFileNameEventData -Verbose:$false

  write-Verbose $json_data
  
  if ([string]::IsNullOrEmpty($json_data)) {
    Write-Host "No data to analyze. Exiting script..." -ForegroundColor Red
    return
  }

  # Clean the returned JSON data
  $json_data = Clear-LLMDataJSON -data $json_data

  LogData -LogFolder $LogFolder -FileName $logFileName -Data ($json_data | ConvertTo-Json -Depth 100) -Type "system"

  # Convert the cleaned JSON data to a PowerShell object
  $object_prompt = ($json_data | ConvertFrom-Json ) 

  Write-Host ""
  # Loop until the user chooses to quit
  while ($true) {
    # Display the prompt number and prompt
    $SubPrompts = $object_prompt
    #LogData -LogFolder $LogFolder -FileName $logFileName -Data "All Sub-Prompts: $(Format-ContinuousText -text $($SubPrompts | Out-String))" -Type "system"
    #$SubPrompts | Format-List promptNumber, prompt | Out-Host -Paging
    foreach ($SubPrompt in $SubPrompts) {
      Write-Host "$($SubPrompt.promptNumber)} " -foregroundColor DarkGreen -NoNewline
      Write-Host "$($subPrompt.prompt)" -ForegroundColor Green
      Write-Host ""
    }
    Write-Host ""

    # Inform the user that they can quit the script at any time
    Write-Host "Enter 'Q' and ENTER to quit the script ( AI will do summarize of session )." -ForegroundColor DarkBlue
    Write-Host ""

    # Get the total number of prompts
    $prompt_count = $object_prompt.Count

    $choose_prompt_number = $null
    # Keep asking the user to choose a valid prompt number until they choose a number within the valid range
    do {
      if (-not [string]::IsNullOrEmpty($choose_prompt_number) -and [int]$choose_prompt_number -ge 1 -and [int]$choose_prompt_number -le $prompt_count) {
        Write-Host "Last chosen prompt number: $choose_prompt_number" -ForegroundColor DarkGreen
      }
      Write-Host "Choose the number of prompt to analyze events (1-$prompt_count)" -ForegroundColor Cyan -NoNewline
      $choose_prompt_number = Read-Host " "
      Write-Host ""

      # If the user chooses to quit, end the script
      if ($choose_prompt_number -eq 'q' -or $choose_prompt_number -eq 'Q') {
        # Display a message indicating that the script is quitting
        Write-Host "Quiting..."
        Write-Host ""

        # Log the quit action
        LogData -LogFolder $LogFolder -FileName $logFileName -Data "Quiting" -Type "user"

        # Get the details of the log file
        Get-LogFileDetails -LogFolder $LogFolder -logFileName $logFileName -LogEventDataFileName $logFileNameEventData
        Write-Host ""

        Get-SummarizeSession -LogFolder $LogFolder -logFileName $logFileName
        Write-Host ""
        # Break the loop to end the script
        # break
        return
      }
    } while ($choose_prompt_number -notmatch '^\d+$' -or [int]$choose_prompt_number -lt 1 -or [int]$choose_prompt_number -gt $prompt_count)
    
    # Construct the chosen prompt
    $choose_prompt = $($object_prompt[($choose_prompt_number - 1)].prompt)

    # Display the chosen prompt to the console
    Write-Host "Prompt: '$choose_prompt'" -ForegroundColor Green
    Write-Host ""
    # Log the chosen prompt
    LogData -LogFolder $LogFolder -FileName $logFileName -Data "Chosen Sub-Prompt: $(Format-ContinuousText -text $choose_prompt)" -Type "user"

    # Update the chosen prompt using the Update-PromptData function
    $choose_prompt = Update-PromptData -inputPrompt $choose_prompt
    # Display the updated prompt to the console
    Write-Host "Enriched Prompt: '$choose_prompt'" -ForegroundColor DarkGreen
    Write-Host ""
    # Log the updated prompt
    LogData -LogFolder $LogFolder -FileName $logFileName -Data "Chosen Sub-Prompt (updated): $(Format-ContinuousText -text $choose_prompt)" -Type "user"
    
    Write-Host "Generating response for the chosen prompt..." -ForegroundColor Cyan
    # Invoke the AI model with the chosen prompt and the data to analyze
    $dataSubpromptResponse = ($data_to_analyze | Invoke-AIEventAnalyzer -NaturalLanguageQuery $choose_prompt -LogFile $logFileNameEventData -Verbose:$false)
    LogData -LogFolder $LogFolder -FileName $logFileName -Data "Sub-Prompt response: $(Format-ContinuousText -text $dataSubpromptResponse)" -Type "system"
    Write-Host ""
    
    # Output the response data with paging
    $dataSubpromptResponse | Out-Host -Paging

    # Ask the user to press any key to continue
    Write-Host "Press any key to continue ..." -ForegroundColor Cyan
    $null = [Console]::ReadKey($true)
    Write-Host ""
  }
}

function Show-Banner {
  Write-Host @'
 
  Welcome to the
                 _____ ______ _ _
           /\ |_ _| ____| | | /\ | |
          / \ | | | |____ _____ _ __ | |_ / \ _ __ __ _| |_ _ _______ _ __
         / /\ \ | | | __\ \ / / _ \ '_ \| __| / /\ \ | '_ \ / _` | | | | |_ / _ \ '__|
        / ____ \ _| |_| |___\ V / __/ | | | |_ / ____ \| | | | (_| | | |_| |/ / __/ |
       /_/ \_\_____|______\_/ \___|_| |_|\__/_/ \_\_| |_|\__,_|_|\__, /___\___|_|
                                                                        __/ |
                                                                       |___/
                                                                  powered by AZURE OpenAI
        
       voytas75; https://github.com/voytas75/AzureOpenAI-PowerShell
 
'@

  Write-Host @"
       This PowerShell script, Start-AIEventAnalyzer.ps1, is a tool designed to analyze Windows Event Logs using Azure's OpenAI.
       It allows users to select a specific log and severity level, and then uses AI to analyze the events. The script provides
       prompts to guide the user through the process, and the results are displayed in a user-friendly format. The tool is
       particularly useful for system administrators and IT professionals who need to analyze large amounts of log data quickly
       and efficiently.
        
"@
 -ForegroundColor Blue

  Write-Host @"
       "You never know what you're gonna get with an AI, just like a box of chocolates. You might get a whiz-bang algorithm that
       writes you a symphony in five minutes flat, or you might get a dud that can't tell a cat from a couch. But hey, that's
       the beauty of it all, you keep feedin' it data and see what kind of miraculous contraption it spits out next."
                     
                                                                   ~ Who said that? You never know with these AIs these days...
                                                                    ...maybe it was Skynet or maybe it was just your toaster :)
 
"@
 -ForegroundColor DarkYellow

  Write-Host @"
       To start type 'Start-AIEventAnalyzer'
 
 
"@
 -ForegroundColor White
}

Clear-Host
Show-Banner

$moduleName = "PSAOAI"
if (Get-Module -ListAvailable -Name $moduleName) {
    [void](Import-module -name PSAOAI)
} else {
    Write-Host "You need to install '$moduleName' module. USe: 'Install-Module PSAOAI'"
}