generate-portal-ux.ps1

# ----------------------------------------------------------------------------------
# Code generated by Microsoft (R) AutoRest Code Generator (autorest: 3.10.2, generator: @autorest/powershell@4.0.708)
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
#
# This Script will create a folder dedicated to Azure-specific content and includes metadata files essential for enhancing the user experience (UX) within the Azure portal.
# These files are utilized by the Azure portal to effectively present the usage of cmdlets related to specific resources on portal pages.
# ----------------------------------------------------------------------------------
param([switch]$NotIsolated)
$ErrorActionPreference = 'Stop'

$pwsh = [System.Diagnostics.Process]::GetCurrentProcess().Path
if(-not $NotIsolated) {
  Write-Host -ForegroundColor Green 'Creating isolated process...'
  & "$pwsh" -NonInteractive -NoLogo -NoProfile -File $MyInvocation.MyCommand.Path @PSBoundParameters -NotIsolated
  return
}

$moduleName = 'CommvaultPowerShell'
$rootModuleName = ''
if ($rootModuleName -eq "")
{
    $rootModuleName = $moduleName
}
$modulePsd1 = Get-Item -Path (Join-Path $PSScriptRoot "./$moduleName.psd1")
$modulePath = $modulePsd1.FullName

# Load DLL to use build-time cmdlets
Import-Module -Name $modulePath
Import-Module -Name (Join-Path $PSScriptRoot "./bin/$moduleName.private.dll")
$instance = [Commvault.Powershell.Module]::Instance
# Module info is shared per profile
$moduleInfo = Get-Module -Name $moduleName
$parameterSetsInfo = Get-Module -Name "$moduleName.private"

function Test-FunctionSupported()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [string]
        $FunctionName
    )

    If (-not $FunctionName.Contains("_")) {
        return $false
    }

    $cmdletName, $parameterSetName = $FunctionName.Split("_")
    If ($parameterSetName.Contains("List") -or $parameterSetName.Contains("ViaIdentity")  -or $parameterSetName.Contains("ViaJson")) {
        return $false
    }
    If ($cmdletName.StartsWith("New") -or $cmdletName.StartsWith("Set") -or $cmdletName.StartsWith("Update")) {
        return $false
    }

    $parameterSetInfo = $parameterSetsInfo.ExportedCmdlets[$FunctionName]
    foreach ($parameterInfo in $parameterSetInfo.Parameters.Values)
    {
        $category = (Get-ParameterAttribute -ParameterInfo $parameterInfo -AttributeName "CategoryAttribute").Categories
        $invalideCategory = @('Query', 'Body')
        if ($invalideCategory -contains $category)
        {
            return $false
        }
    }

    $customFiles = Get-ChildItem -Path custom -Filter "$cmdletName.*"
    if ($customFiles.Length -ne 0)
    {
        Write-Host -ForegroundColor Yellow "There are come custom files for $cmdletName, skip generate UX data for it."
        return $false
    }

    return $true
}

function Get-MappedCmdletFromFunctionName()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [string]
        $FunctionName
    )
    
    $cmdletName, $parameterSetName = $FunctionName.Split("_")

    return $cmdletName
}

function Get-ParameterAttribute()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [System.Management.Automation.ParameterMetadata]
        $ParameterInfo,
        [Parameter()]
        [String]
        $AttributeName
    )
    return $ParameterInfo.Attributes | Where-Object { $_.TypeId.Name -eq $AttributeName }
}

function Get-CmdletAttribute()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [System.Management.Automation.CommandInfo]
        $CmdletInfo,
        [Parameter()]
        [String]
        $AttributeName
    )

    return $CmdletInfo.ImplementingType.GetTypeInfo().GetCustomAttributes([System.object], $true) | Where-Object { $_.TypeId.Name -eq $AttributeName }
}

function Get-CmdletDescription()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [String]
        $CmdletName
    )
    $helpInfo = Get-Help $CmdletName -Full
    
    $description = $helpInfo.Description.Text
    if ($null -eq $description)
    {
        return ""
    }
    return $description
}

# Test whether the parameter is from swagger http path
function Test-ParameterFromSwagger()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [System.Management.Automation.ParameterMetadata]
        $ParameterInfo
    )
    $category = (Get-ParameterAttribute -ParameterInfo $ParameterInfo -AttributeName "CategoryAttribute").Categories
    $doNotExport = Get-ParameterAttribute -ParameterInfo $ParameterInfo -AttributeName "DoNotExportAttribute"
    if ($null -ne $doNotExport)
    {
        return $false
    }
    
    $valideCategory = @('Path')
    if ($valideCategory -contains $category)
    {
        return $true
    }
    return $false
}

function New-ExampleForParameterSet()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [System.Management.Automation.CommandInfo]
        $ParameterSetInfo
    )
    $parameters = $ParameterSetInfo.Parameters.Values | Where-Object { Test-ParameterFromSwagger $_ }
    $result = @()
    foreach ($parameter in $parameters)
    {
        $category = (Get-ParameterAttribute -parameterInfo $parameter -AttributeName "CategoryAttribute").Categories
        $sourceName = (Get-ParameterAttribute -parameterInfo $parameter -AttributeName "InfoAttribute").SerializedName
        $name = $parameter.Name
        $result += [ordered]@{
            name = "-$Name"
            value = "[$category.$sourceName]"
        }
    }

    return $result
}

function New-ParameterArrayInParameterSet()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [System.Management.Automation.CommandInfo]
        $ParameterSetInfo
    )
    $parameters = $ParameterSetInfo.Parameters.Values | Where-Object { Test-ParameterFromSwagger $_ }
    $result = @()
    foreach ($parameter in $parameters)
    {
        $isMandatory = (Get-ParameterAttribute -parameterInfo $parameter -AttributeName "ParameterAttribute").Mandatory
        $parameterName = $parameter.Name
        $parameterType = $parameter.ParameterType.ToString().Split('.')[1]
        if ($parameter.SwitchParameter)
        {
            $parameterSignature = "-$parameterName"
        }
        else
        {
            $parameterSignature = "-$parameterName <$parameterType>"
        }
        if ($parameterName -eq "SubscriptionId")
        {
            $isMandatory = $false
        }
        if (-not $isMandatory)
        {
            $parameterSignature = "[$parameterSignature]"
        }
        $result += $parameterSignature
    }

    return $result
}

function New-MetadataForParameterSet()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [System.Management.Automation.CommandInfo]
        $ParameterSetInfo
    )
    $httpAttribute = Get-CmdletAttribute -CmdletInfo $ParameterSetInfo -AttributeName "HttpPathAttribute"
    $httpPath = $httpAttribute.Path
    $apiVersion = $httpAttribute.ApiVersion
    $provider = [System.Text.RegularExpressions.Regex]::New("/providers/([\w+\.]+)/").Match($httpPath).Groups[1].Value
    $resourcePath = "/" + $httpPath.Split("$provider/")[1]
    $resourceType = [System.Text.RegularExpressions.Regex]::New("/([\w]+)/\{\w+\}").Matches($resourcePath) | ForEach-Object {$_.groups[1].Value} | Join-String -Separator "/"
    $cmdletName = Get-MappedCmdletFromFunctionName $ParameterSetInfo.Name
    $description = (Get-CmdletAttribute -CmdletInfo $ParameterSetInfo -AttributeName "DescriptionAttribute").Description
    [object[]]$example = New-ExampleForParameterSet $ParameterSetInfo
    [string[]]$signature = New-ParameterArrayInParameterSet $ParameterSetInfo

    return @{
        Path = $httpPath
        Provider = $provider
        ResourceType = $resourceType
        ApiVersion = $apiVersion
        CmdletName = $cmdletName
        Description = $description
        Example = $example
        Signature = @{
            parameters = $signature
        }
    }
}

function Merge-WithExistCmdletMetadata()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [System.Collections.Specialized.OrderedDictionary]
        $ExistedCmdletInfo,
        [Parameter()]
        [Hashtable]
        $ParameterSetMetadata
    )
    $ExistedCmdletInfo.help.parameterSets += $ParameterSetMetadata.Signature
    $ExistedCmdletInfo.examples += [ordered]@{
        description = $ParameterSetMetadata.Description
        parameters = $ParameterSetMetadata.Example
    }

    return $ExistedCmdletInfo
}

function New-MetadataForCmdlet()
{
    [CmdletBinding()]
    Param (
        [Parameter()]
        [Hashtable]
        $ParameterSetMetadata
    )
    $cmdletName = $ParameterSetMetadata.CmdletName
    $description = Get-CmdletDescription $cmdletName
    $result = [ordered]@{
        name = $cmdletName
        description = $description
        path = $ParameterSetMetadata.Path
        help = [ordered]@{
            learnMore = [ordered]@{
                url = "https://learn.microsoft.com/powershell/module/$rootModuleName/$cmdletName".ToLower()
            }
            parameterSets = @()
        }
        examples = @()
    }
    $result = Merge-WithExistCmdletMetadata -ExistedCmdletInfo $result -ParameterSetMetadata $ParameterSetMetadata
    return $result
}

$parameterSets = $parameterSetsInfo.ExportedCmdlets.Keys | Where-Object { Test-FunctionSupported($_) }
$resourceTypes = @{}
foreach ($parameterSetName in $parameterSets)
{
    $cmdletInfo = $parameterSetsInfo.ExportedCommands[$parameterSetName]
    $parameterSetMetadata = New-MetadataForParameterSet -ParameterSetInfo $cmdletInfo
    $cmdletName = $parameterSetMetadata.CmdletName
    if (-not ($moduleInfo.ExportedCommands.ContainsKey($cmdletName)))
    {
        continue
    }
    if ($resourceTypes.ContainsKey($parameterSetMetadata.ResourceType))
    {
        $ExistedCmdletInfo = $resourceTypes[$parameterSetMetadata.ResourceType].commands | Where-Object { $_.name -eq $cmdletName }
        if ($ExistedCmdletInfo)
        {
            $ExistedCmdletInfo = Merge-WithExistCmdletMetadata -ExistedCmdletInfo $ExistedCmdletInfo -ParameterSetMetadata $parameterSetMetadata
        }
        else
        {
            $cmdletInfo = New-MetadataForCmdlet -ParameterSetMetadata $parameterSetMetadata
            $resourceTypes[$parameterSetMetadata.ResourceType].commands += $cmdletInfo
        }
    }
    else
    {
        $cmdletInfo = New-MetadataForCmdlet -ParameterSetMetadata $parameterSetMetadata
        $resourceTypes[$parameterSetMetadata.ResourceType] = [ordered]@{
            resourceType = $parameterSetMetadata.ResourceType
            apiVersion = $parameterSetMetadata.ApiVersion
            learnMore = @{
                url = "https://learn.microsoft.com/powershell/module/$rootModuleName".ToLower()
            }
            commands = @($cmdletInfo)
            provider = $parameterSetMetadata.Provider
        }
    }
}

$UXFolder = 'UX'
if (Test-Path $UXFolder)
{
    Remove-Item -Path $UXFolder -Recurse
}
$null = New-Item -ItemType Directory -Path $UXFolder

foreach ($resourceType in $resourceTypes.Keys)
{
    $resourceTypeFileName = $resourceType -replace "/", "-"
    if ($resourceTypeFileName -eq "")
    {
        continue
    }
    $resourceTypeInfo = $resourceTypes[$resourceType]
    $provider = $resourceTypeInfo.provider
    $providerFolder = "$UXFolder/$provider"
    if (-not (Test-Path $providerFolder))
    {
        $null = New-Item -ItemType Directory -Path $providerFolder
    }
    $resourceTypeInfo.Remove("provider")
    $resourceTypeInfo | ConvertTo-Json -Depth 10 | Out-File "$providerFolder/$resourceTypeFileName.json"
}