Examples/PowerShellCommandFinder.ps1

#requires -Version 7.0

<#
.SYNOPSIS
    Finds a likely local PowerShell command for a plain-English task.
 
.DESCRIPTION
    Searches installed cmdlet and function names and help text, then asks OpenAI Decisions
    to choose the best match from a short candidate list. Displays local help
    examples for review. The suggested command is never executed.
 
.PARAMETER Task
    Describe what you want PowerShell to do.
 
.PARAMETER CandidateCount
    Maximum number of locally matched commands OpenAI Decisions can choose from.
 
.EXAMPLE
    .\PowerShellCommandFinder.ps1 -Task 'Find files larger than 100 MB'
 
.EXAMPLE
    .\PowerShellCommandFinder.ps1 -Task 'Show processes using the most memory' -CandidateCount 18
 
.EXAMPLE
    .\PowerShellCommandFinder.ps1 -Task 'Search text inside every PowerShell script'
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory)]
    [string] $Task,

    [ValidateRange(3, 25)]
    [int] $CandidateCount = 12
)

# Set OPENAI_API_KEY before running this example.
# This script searches local command metadata. It asks OpenAI Decisions to choose a likely
# command, then displays help for review; it never runs the suggested command.

Import-Module (Join-Path $PSScriptRoot '..' 'PSAIOpenAIDecisions.psd1') -Force

$stopWords = @('the', 'and', 'for', 'with', 'from', 'that', 'this', 'into', 'using', 'use', 'find', 'get', 'show', 'list', 'all', 'how', 'can', 'want', 'need', 'please', 'powershell')
$terms = @(
    [regex]::Matches($Task.ToLowerInvariant(), '[a-z0-9]{3,}') |
        ForEach-Object Value |
        Where-Object { $_ -notmatch '^\d+$' } |
        Where-Object { $_ -notin $stopWords } |
        Sort-Object -Unique
)

if ($terms.Count -eq 0) {
    throw 'Describe what you want to do with a few specific words.'
}

$readOnlyVerbs = @('Compare', 'Find', 'Get', 'Group', 'Measure', 'Search', 'Select', 'Sort', 'Where')
$candidates = foreach ($command in Get-Command -CommandType Cmdlet -ListImported -ErrorAction SilentlyContinue |
    Where-Object { $_.Verb -in $readOnlyVerbs }) {
    # Filter on local command metadata first. Looking up help for every installed
    # command is slow and can make Get-Help probe unavailable filesystem drives.
    $metadata = "$($command.Name) $($command.Definition)".ToLowerInvariant()
    $metadataMatches = @($terms | Where-Object {
            $term = $_
            $metadata -match "(?<![a-z0-9])$([regex]::Escape($term.TrimEnd('s')))[a-z0-9]*"
        })
    if ($metadataMatches.Count -eq 0) { continue }

    $help = Get-Help -Name $command.Name -ErrorAction Ignore
    $synopsis = [string] $help.Synopsis
    if ([string]::IsNullOrWhiteSpace($synopsis)) {
        $synopsis = [string] $command.Definition
        if ($synopsis.Length -gt 240) { $synopsis = $synopsis.Substring(0, 240) }
    }

    $searchText = "$($command.Name) $synopsis $($command.Definition)".ToLowerInvariant()
    $matchCount = @($terms | Where-Object {
            $term = $_
            $searchText -match "(?<![a-z0-9])$([regex]::Escape($term.TrimEnd('s')))[a-z0-9]*"
        }).Count
    if ($matchCount -gt 0) {
        [pscustomobject]@{
            Name        = $command.Name
            CommandType = [string] $command.CommandType
            Module      = [string] $command.Source
            Synopsis    = $synopsis
            MatchCount  = $matchCount
        }
    }
}

$candidates = @($candidates | Sort-Object -Property @{ Expression = 'MatchCount'; Descending = $true }, Name | Select-Object -First $CandidateCount)
if ($candidates.Count -eq 0) {
    throw 'No local commands matched those terms. Try describing the task with words that may appear in command names or help, or import the relevant module first.'
}

$criteria = [ordered]@{}
foreach ($candidate in $candidates) {
    $criteria[$candidate.Name] = "[$($candidate.CommandType); module: $($candidate.Module)] $($candidate.Synopsis)"
}

$question = New-OpenAIDecisionQuestion `
    -Name command `
    -Type Choice `
    -Instructions "Choose the single PowerShell command that is the best fit for this task: $Task. Choose only from the supplied candidates. Prefer a command that directly accomplishes the task; do not infer that the command should be run." `
    -Criteria $criteria

$decision = Invoke-OpenAIDecision -State ([pscustomobject]@{
        Task       = $Task
        Candidates = @($candidates | Select-Object Name, CommandType, Module, Synopsis)
    }) -Question $question

$answer = $decision.answers.command
$selected = $candidates | Where-Object Name -eq $decision.command | Select-Object -First 1

Write-Host "Task: $Task" -ForegroundColor Cyan
if ($null -eq $selected) {
    Write-Warning 'OpenAI Decisions did not return a command from the supplied candidate list.'
    $decision
    return
}

[pscustomobject]@{
    Command    = $selected.Name
    Confidence = [math]::Round([double] $answer.confidence, 2)
    Module     = $selected.Module
    Synopsis   = $selected.Synopsis
}

Write-Host "`nLocal help for $($selected.Name) (review before using):" -ForegroundColor Cyan
Get-Help -Name $selected.Name -Examples | Select-Object -ExpandProperty Examples