param ( [Parameter(Mandatory)] [ValidateScript({ Test-Path $_ -PathType Leaf })] [string]$Path ) process { Add-Type -AssemblyName System.Management.Automation $script_path_raw = Get-Item $Path $script_name = $script_path_raw.Name $script_path = $script_path_raw | Select-Object -ExpandProperty FullName $tokens = $null $errors = $null $ast = [System.Management.Automation.Language.Parser]::ParseFile($script_path, [ref]$tokens, [ref]$errors) if ($errors.Count -gt 0) { throw "Parse errors found: $($errors | ForEach-Object { $_.Message })" } $paramBlock = $ast.ParamBlock if (-not $paramBlock) { throw "No param() block found at the script level." } $cmdletBindingAttr = $paramBlock.Attributes | Where-Object { $_.TypeName.Name -eq 'CmdletBinding' } $defaultParamSet = $cmdletBindingAttr.NamedArguments | Where-Object { $_.ArgumentName -eq 'DefaultParameterSetName' } | Select-Object -ExpandProperty Argument | Select-Object -ExpandProperty Value $parameters = @() foreach ($param in $paramBlock.Parameters) { $paramName = $param.Name.VariablePath.UserPath # Fix the type name $staticType = $param.StaticType if ($staticType.IsGenericType -and $staticType.Name -eq 'Nullable`1') { $innerType = $staticType.GenericTypeArguments[0].Name $paramType = "Nullable[$innerType]" } else { $paramType = $staticType.Name } $aliases = @() $validations = @() $parameterSets = @() $description = $null $helpMessage = $null foreach ($attr in $param.Attributes) { switch ($attr.TypeName.Name) { 'Parameter' { $mandatory = $false $parametersetname = 'Default' $position = $null $frompipeline = $null $frompipeline_by_property = $null $helpmessage = $null foreach ($arg in $attr.NamedArguments) { switch ($arg.ArgumentName) { 'Mandatory' { $mandatory = $arg.Argument.Extent.Text -eq '$true' } 'Position' { $position = $arg.Argument.Value } 'ParameterSetName' { $parametersetname = $arg.Argument.Value } 'ValueFromPipeline' { $frompipeline = $arg.Argument.Extent.Text -eq '$true' } 'ValueFromPipelineByPropertyName' { $frompipeline_by_property = $arg.Argument.Extent.Text -eq '$true' } 'HelpMessage' { $helpMessage = $arg.Argument.Value } } } $paramInfo = @{ name = $parametersetname mandatory = $mandatory } if($null -ne $position) { $paramInfo.position = $position } if($null -ne $frompipeline) { $paramInfo.valueFromPipeline = $frompipeline } if($null -ne $frompipeline_by_property) { $paramInfo.valueFromPipelineByPropertyName = $frompipeline_by_property } $parameterSets += [pscustomobject]$paramInfo break } 'Alias' { $aliases += $attr.PositionalArguments.Value break } { $_ -like 'Validate*' } { $val = @{ type = $attr.TypeName.Name } if ($attr.TypeName.Name -eq 'ValidateRange') { $val.min = $attr.PositionalArguments[0].Value $val.max = $attr.PositionalArguments[1].Value } elseif ($attr.TypeName.Name -eq 'ValidateSet') { $val.values = $attr.PositionalArguments.Value } elseif ($attr.TypeName.Name -eq 'ValidateScript') { $val.script = $attr.PositionalArguments.ScriptBlock.Extent.Text } $validations += [pscustomobject]$val break } } } if ($parameterSets.Count -eq 0) { $parameterSets += [pscustomobject]@{ name = "Default" mandatory = $false } } $parameters += [pscustomobject]@{ name = $paramName type = $paramType aliases = $aliases description = $description helpMessage = $helpMessage validations = $validations parameterSets = $parameterSets } } $result = [pscustomobject]@{ name = $script_name path = $script_path parameters = $parameters cmdletBinding = [pscustomobject]@{ defaultParameterSetName = $defaultParamSet ?? "Default" } } return $result }