Public/Import-TraverseFlexCommand.ps1

function Import-TraverseFlexCommand {
<#
.SYNOPSIS
Connects to the FlexBVE Help API and automatically generates a powershell module to use with Traverse
.DESCRIPTION
This command automatically generates a Powershell Module with the Traverse FlexAPI commands.
These commands match the commands in the FlexAPI, with some additional validation and structure
Documentation for all commands can be found at the Traverse Developers Guide, but there is no inline help generated
#>

    [CmdletBinding()]
    param (
        #A prefix to append to the commands, similar to Powershell Module Prefix.
        [String]$Prefix = "TraverseFlex",
        #Don't generate shorthand aliases for commands
        [Switch]$NoCreateShortAliases,
        #Don't generate shortand aliases that match the BVE CLI aliases
        [Switch]$NoCreateBVECLIAliases,
        #Shorthand Alias Prefix to use. Defaults to "tf". For example, Get-TraverseFlexUser aliases to "gtfu"
        [String]$AliasPrefix = "tf"
    )

    $commands = Get-TraverseFlexCommand | where {$_.noun}

    #Exclude items that have bad formatting or otherwise require special formatting
    #TODO: Fix these functions

    $commands = $commands | where {
        "TestCreate",
        "TestUpdate",
        "TestSuppress",
        "ActionCreate",
        "ActionUpdate",
        "HotSpotUpdate" -notcontains ($PSItem.noun + $PSItem.verb)}

    $cmdlist = ""
    $aliases = @{}

    #Generate Function Code for the various commands
    foreach ($cmdItem in $commands) {
        $noun = $cmdItem.noun
        $PShellNoun = $noun
        $verb = $cmdItem.verb
        #Substitute Invalid Nouns for Powershell-Approved ones
        $PShellVerb = switch ($verb) {
            "List" {"Get"}
            "Create" {"New"}
            "Update" {"Set"}
            "Delete" {"Remove"}
            "Status" {"Get"; $PShellNoun = $PShellNoun + "Status"}
            "Members" {"Get"; $PShellNoun = $PShellNoun + "Members"}
            "Baseline" {"New"; $PShellNoun = $PShellNoun + "Baseline"}
            "Represent" {"Enter"}
            "Suppress" {"Disable"}
            "" {"Invoke"}
            default {$verb}
        }

        #Generate the Parameter Information
        $PShellParams = @()
        foreach ($param in $cmdItem.params) {
            #Sets up the attributes required
            $paramAttributes = "[Parameter("
            $paramAttributes += "Mandatory=`$$($param.mandatory),"
            $paramAttributes += "ParameterSetName='$($param.parameterset)'"
            $paramAttributes += ")]"
            $PShellParams += switch ($param.type) {
                "String" {$paramAttributes + "[String]`$$($param.name)`r`n"}
                "RegEx" {$paramAttributes + "[String]`$$($param.name)`r`n"}
                "Boolean" {$paramAttributes + "[Switch]`$$($param.name)`r`n"}
                default {$paramAttributes + "[String]`$$($param.name)`r`n"}
            }
        }

        #Add in the Comma Characters for all but the last command
        $PShellParamsFinal = ""
        #The skip last syntax is for PS4 and below compatability. PS5 would use -skiplast
        $PShellParams | select -skip 1 -last 99999999 | foreach {
            $PShellParamsFinal += $PSItem -replace '\r\n$',",`r`n"
        }
        $PShellParamsFinal += $PShellParams | select -last 1


        $command = @"
<#
.SYNOPSIS
This is an autogenerated function for the Traverse FlexAPI command $($cmdItem.command)
#>
function $PShellVerb-$PShellNoun {
    [CmdletBinding()]
    param (
        $PShellParamsFinal
    )
 
    #Filter Out Common PS Parameters so they don't screw up Invoke-TraverseCommand
    `$traverseCommandParameters = ([HashTable]`$PSCmdlet.MyInvocation.BoundParameters).clone()
    `$commonParameters = [System.Management.Automation.PSCmdlet]::CommonParameters +
        [System.Management.Automation.PSCmdlet]::OptionalCommonParameters
 
    `$keysToRemove = @()
    foreach (`$tCommandKey in `$PSCmdlet.MyInvocation.BoundParameters.keys) {
        if (`$commonParameters -contains `$tCommandKey) {
            `$keysToRemove += `$tCommandKey
        }
    }
    `$keysToRemove | foreach {
        `$traverseCommandParameters.Remove("`$PSItem") | out-null
    }
 
    #Build the Initial Command Parameters
    `$invokeTraverseCommandParams = @{
        Command = '$($cmdItem.command)'
        ArgumentList = `$traverseCommandParameters
    }
 
    #Passthrough Verbose if Present
    if (`$PSCmdlet.MyInvocation.BoundParameters['Verbose']) {
        `$invokeTraverseCommandParams.verbose = `$true
    }
 
    Invoke-TraverseCommand @invokeTraverseCommandParams
}
 
 
"@


        $cmdList += $command
        $aliases.Add($cmdItem.command.tolower(),"$PShellVerb-$Prefix$PShellNoun")
    }
    #Add the export command so that Aliases get added in addition to functions
    $cmdList += @"
export-modulemember -Function *
"@

    $flexModulePath =  $env:temp + "\$prefix-" + (New-GUID).toString() + "\$prefix.psm1"
    New-Item -type Directory (Split-Path -Parent $flexModulePath) | out-null
    remove-item  $flexModulePath -ErrorAction SilentlyContinue
    $cmdList > $flexModulePath
    if (get-module $prefix) {throw "Module $prefix is already loaded. Either remove the module or specify a different module prefix";exit}
    import-module $flexModulePath -prefix $prefix -global -NoClobber


    If (!$NoCreateAliases) {
        foreach ($cmdlet in (get-command -module $prefix | sort-Object Name)) {
            #Find a shortname alias that is available and not already used, up to 4 characters
            $aliasParams = @{
                Name = $null
                Value = $cmdlet.Name
            }

            $i = 1
            do {
                $candidateAliasName = ($cmdlet.verb.substring(0,1).toLower() +
                    $AliasPrefix.toLower() +
                    $cmdlet.noun.replace($prefix,'').substring(0,$i).toLower())
                if (get-alias $candidateAliasName -ErrorAction SilentlyContinue) {
                    $i++
                    continue
                } else {
                    $aliasParams.Name = $candidateAliasName
                }

            } until ($aliasParams.Name -or $i -ge 5)

            if ($aliasParams.Name) {
                Set-Alias @aliasParams -Scope Global
            } else {
                write-Warning "Couldn't find a sufficient alias shorthand for $($cmdlet.name)"
            }
        }
    }

    If (!$NoCreateBVECLIAliases) {
        #TODO: Fix for prefixes
        foreach ($aliasItem in $aliases.GetEnumerator()) {
            Set-Alias -Name $aliasItem.Name -Value $aliasItem.Value -Scope Global
        }
    }
}