modules/ArgumentCompleter.psm1

Set-StrictMode -Version "Latest"

function complete_argument_VMName {
    param ( $command_name, $parameter_name, $word_to_complete, $command_AST, $fake_bound_parameters )

    $quote = ""
    if ($word_to_complete.StartsWith("'")) {
        $quote = "'"
    }
    elseif ($word_to_complete.StartsWith('"')) {
        $quote = '"'
    }

    if (($quote.Length -gt 0) -and $word_to_complete.EndsWith("$quote")) {
        $word_to_complete = $word_to_complete.Substring(1, $word_to_complete.Length - 2)
    }

    Hyper-V\Get-VM |
        Where-Object -Property Name -like "$word_to_complete*" |
        Select-Object -ExpandProperty "Name" |
        ForEach-Object { '"' + $_ + '"' }
}


function Register-VMNameArgumentCompleter {
    $cmdlets_args = @{ }

    # All commands (cmdlets and function) with paramater or paramater alias "VMName"
    $candidate_commands = Get-Command -All -ParameterName "VMName" -CommandType "Function", "Cmdlet"

    $candidate_commands | ForEach-Object -Process {
        $parameters = $_.Parameters

        # This sometimes happens. Don't know why
        if ($null -eq $parameters) {
            return
        }

        $command_name = $_.Name

        # Paramater named "VMName"
        if ($parameters.Keys -contains "VMName") {
            $cmdlets_args.Add($command_name, "VMName")
        }

        # Paramater with an alias "VMName"
        $parameter_aliased_to_VMName = $parameters.GetEnumerator() |
            Where-Object -FilterScript { $_.Value.Aliases -contains "VMName" }

        if ($null -ne $parameter_aliased_to_VMName) {
            $parameter_name = $parameter_aliased_to_VMName.Key
            $cmdlets_args.Add($command_name, $parameter_name)
        }
    }

    $cmdlets_args.GetEnumerator() | ForEach-Object {
        $argument_completer = @{ "CommandName"   = $_.Key;
                                 "ParameterName" = $_.Value;
                                 "ScriptBlock"   = { complete_argument_VMName @Args };
                                }
        Register-ArgumentCompleter @argument_completer
    }
}