Paths.psm1
######################################################################################### # # Copyright (c) Microsoft Corporation. All rights reserved. # # Licensed under the MIT license. # # PSSwagger Module # ######################################################################################### Microsoft.PowerShell.Core\Set-StrictMode -Version Latest Import-Module (Join-Path -Path $PSScriptRoot -ChildPath Utilities.psm1) -DisableNameChecking Import-Module (Join-Path -Path $PSScriptRoot -ChildPath SwaggerUtils.psm1) -DisableNameChecking . "$PSScriptRoot\PSSwagger.Constants.ps1" -Force Microsoft.PowerShell.Utility\Import-LocalizedData LocalizedData -filename PSSwagger.Resources.psd1 function Get-SwaggerSpecPathInfo { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [PSObject] $JsonPathItemObject, [Parameter(Mandatory=$true)] [PSCustomObject] $PathFunctionDetails, [Parameter(Mandatory = $true)] [hashTable] $swaggerDict, [Parameter(Mandatory = $true)] [hashtable] $SwaggerMetaDict, [Parameter(Mandatory = $true)] [hashtable] $DefinitionFunctionsDetails, [Parameter(Mandatory=$true)] [hashtable] $ParameterGroupCache, [Parameter(Mandatory=$false)] [PSCustomObject] $PSMetaJsonObject ) Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState $UseAzureCsharpGenerator = $SwaggerMetaDict['UseAzureCsharpGenerator'] $EndpointRelativePath = $JsonPathItemObject.Name $PSMetaPathJsonObject = $null if($PSMetaJsonObject) { if(Get-Member -InputObject $PSMetaJsonObject.paths -Name $EndpointRelativePath) { $PSMetaPathJsonObject = $PSMetaJsonObject.paths.$EndpointRelativePath } elseif(Get-Member -InputObject $PSMetaJsonObject.'x-ms-paths' -Name $EndpointRelativePath) { $PSMetaPathJsonObject = $PSMetaJsonObject.'x-ms-paths'.$EndpointRelativePath } } # First get path level common parameters, if any, which will be common to all operations in this swagger path. $PathCommonParameters = @{} if(Get-Member -InputObject $JsonPathItemObject.value -Name 'Parameters') { $PSMetaParametersJsonObject = $null if($PSMetaPathJsonObject -and (Get-Member -InputObject $PSMetaPathJsonObject -Name 'parameters')) { $PSMetaParametersJsonObject = $PSMetaPathJsonObject.'parameters' } $GetPathParamInfo_params = @{ JsonPathItemObject = $JsonPathItemObject.Value SwaggerDict = $swaggerDict DefinitionFunctionsDetails = $DefinitionFunctionsDetails ParameterGroupCache = $ParameterGroupCache ParametersTable = $PathCommonParameters PSMetaParametersJsonObject = $PSMetaParametersJsonObject } Get-PathParamInfo @GetPathParamInfo_params } $JsonPathItemObject.value.PSObject.Properties | ForEach-Object { $longRunningOperation = $false $operationType = $_.Name if (((Get-Member -InputObject $_.Value -Name 'x-ms-long-running-operation') -and $_.Value.'x-ms-long-running-operation')) { $longRunningOperation = $true } $x_ms_pageableObject = $null if (((Get-Member -InputObject $_.Value -Name 'x-ms-pageable') -and $_.Value.'x-ms-pageable')) { $x_ms_pageableObject = @{} if (((Get-Member -InputObject $_.Value.'x-ms-pageable' -Name 'operationName') -and $_.Value.'x-ms-pageable'.'operationName')) { $x_ms_pageableObject['operationName'] = $_.Value.'x-ms-pageable'.'operationName' } if (((Get-Member -InputObject $_.Value.'x-ms-pageable' -Name 'itemName') -and $_.Value.'x-ms-pageable'.'itemName')) { $x_ms_pageableObject['itemName'] = $_.Value.'x-ms-pageable'.'itemName' } if ((Get-Member -InputObject $_.Value.'x-ms-pageable' -Name 'nextLinkName')) { if ($_.Value.'x-ms-pageable'.'nextLinkName') { $x_ms_pageableObject['nextLinkName'] = $_.Value.'x-ms-pageable'.'nextLinkName' } else { $x_ms_pageableObject = $null } } } if(Get-Member -InputObject $_.Value -Name 'security') { $operationSecurityObject = $_.Value.'security' } elseif ($swaggerDict.ContainsKey('Security')) { $operationSecurityObject = $swaggerDict['Security'] } else { $operationSecurityObject = $null } $cmdletInfoOverrides = @() $PSMetaOperationJsonObject = $null if($PSMetaPathJsonObject -and (Get-Member -InputObject $PSMetaPathJsonObject -Name $operationType)) { $PSMetaOperationJsonObject = $PSMetaPathJsonObject.$operationType } if($PSMetaOperationJsonObject -and (Get-Member -InputObject $PSMetaOperationJsonObject -Name 'x-ps-cmdlet-infos')) { $PSMetaOperationJsonObject.'x-ps-cmdlet-infos' | ForEach-Object { $cmdletInfoOverrides += @{ Name = $_.name } } } elseif ((Get-Member -InputObject $_.Value -Name 'x-ps-cmdlet-infos') -and $_.Value.'x-ps-cmdlet-infos') { foreach ($cmdletMetadata in $_.Value.'x-ps-cmdlet-infos') { $cmdletInfoOverride = @{} if ((Get-Member -InputObject $cmdletMetadata -Name 'name') -and $cmdletMetadata.name) { $cmdletInfoOverride['name'] = $cmdletMetadata.name } $cmdletInfoOverrides += $cmdletInfoOverride } } if(Get-Member -InputObject $_.Value -Name 'OperationId') { $operationId = $_.Value.operationId Write-Verbose -Message ($LocalizedData.GettingSwaggerSpecPathInfo -f $operationId) $FunctionDescription = "" if((Get-Member -InputObject $_.value -Name 'description') -and $_.value.description) { $FunctionDescription = $_.value.description } $ParametersTable = @{} # Add Path common parameters to the operation's parameters list. $PathCommonParameters.GetEnumerator() | ForEach-Object { # Cloning the common parameters object so that some values can be updated. $PathCommonParamDetails = $_.Value.Clone() if($PathCommonParamDetails.ContainsKey('OriginalParameterName') -and $PathCommonParamDetails.OriginalParameterName) { $PathCommonParamDetails['OriginalParameterName'] = '' } $ParametersTable[$_.Key] = $PathCommonParamDetails } $PSMetaParametersJsonObject = $null if($PSMetaOperationJsonObject -and (Get-Member -InputObject $PSMetaOperationJsonObject -Name 'parameters')) { $PSMetaParametersJsonObject = $PSMetaOperationJsonObject.'parameters' } $GetPathParamInfo_params2 = @{ JsonPathItemObject = $_.value SwaggerDict = $swaggerDict DefinitionFunctionsDetails = $DefinitionFunctionsDetails ParameterGroupCache = $ParameterGroupCache ParametersTable = $ParametersTable PSMetaParametersJsonObject = $PSMetaParametersJsonObject } Get-PathParamInfo @GetPathParamInfo_params2 $responses = "" if((Get-Member -InputObject $_.value -Name 'responses') -and $_.value.responses) { $responses = $_.value.responses } if($cmdletInfoOverrides) { $commandNames = $cmdletInfoOverrides } else { $commandNames = Get-PathCommandName -OperationId $operationId } $ParameterSetDetail = @{ Description = $FunctionDescription ParameterDetails = $ParametersTable Responses = $responses OperationId = $operationId OperationType = $operationType EndpointRelativePath = $EndpointRelativePath PathCommonParameters = $PathCommonParameters Priority = 100 # Default 'x-ms-pageable' = $x_ms_pageableObject } if ((Get-Member -InputObject $_.Value -Name 'x-ms-odata') -and $_.Value.'x-ms-odata') { # Currently only the existence of this property is really important, but might as well save the value $ParameterSetDetail.'x-ms-odata' = $_.Value.'x-ms-odata' } # There's probably a better way to do this... $opIdValues = $operationId -split "_",2 if(-not $opIdValues -or ($opIdValues.Count -ne 2)) { $approximateVerb = $operationId } else { $approximateVerb = $opIdValues[1] if ((-not $UseAzureCsharpGenerator) -and (Test-OperationNameInDefinitionList -Name $opIdValues[0] -SwaggerDict $swaggerDict)) { $ParameterSetDetail['UseOperationsSuffix'] = $true } } if ($approximateVerb.StartsWith("List")) { $ParameterSetDetail.Priority = 0 } $commandNames | ForEach-Object { $FunctionDetails = @{} if ($PathFunctionDetails.ContainsKey($_.name)) { $FunctionDetails = $PathFunctionDetails[$_.name] } else { $FunctionDetails['CommandName'] = $_.name $FunctionDetails['x-ms-long-running-operation'] = $longRunningOperation } if ($operationSecurityObject) { $FunctionDetails['Security'] = $operationSecurityObject } $ParameterSetDetails = @() if ($FunctionDetails.ContainsKey('ParameterSetDetails')) { $ParameterSetDetails = $FunctionDetails['ParameterSetDetails'] } $ParameterSetDetails += $ParameterSetDetail $FunctionDetails['ParameterSetDetails'] = $ParameterSetDetails $PathFunctionDetails[$_.name] = $FunctionDetails } } elseif(-not ((Get-Member -InputObject $_ -Name 'Name') -and ($_.Name -eq 'Parameters'))) { $Message = $LocalizedData.UnsupportedSwaggerProperties -f ('JsonPathItemObject', $($_.Value | Out-String)) Write-Warning -Message $Message } } } function New-SwaggerSpecPathCommand { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [hashtable] $PathFunctionDetails, [Parameter(Mandatory = $true)] [hashtable] $SwaggerMetaDict, [Parameter(Mandatory = $true)] [hashtable] $SwaggerDict, [Parameter(Mandatory=$true)] [hashtable] $DefinitionFunctionsDetails ) Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState $FunctionsToExport = @() Preprocess-PagingOperations -PathFunctionDetails $PathFunctionDetails $PathFunctionDetails.GetEnumerator() | ForEach-Object { $FunctionsToExport += New-SwaggerPath -FunctionDetails $_.Value ` -SwaggerMetaDict $SwaggerMetaDict ` -SwaggerDict $SwaggerDict ` -PathFunctionDetails $PathFunctionDetails ` -DefinitionFunctionsDetails $DefinitionFunctionsDetails } return $FunctionsToExport } <# Mark any operations as paging operations if they're the target of any operation's x-ms-pageable.operationName property. These operations will not generate -Page and -Paging, even though they're marked as pageable. These are single page operations and should never be unrolled (in the case of -not -Paging) or accept IPage parameters (in the case of -Page) #> function Preprocess-PagingOperations { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [hashtable] $PathFunctionDetails ) $PathFunctionDetails.GetEnumerator() | ForEach-Object { $_.Value.ParameterSetDetails | ForEach-Object { $parameterSetDetail = $_ if ($parameterSetDetail.ContainsKey('x-ms-pageable') -and $parameterSetDetail.'x-ms-pageable') { if ($parameterSetDetail.'x-ms-pageable'.ContainsKey('operationName')) { $matchingPath = $PathFunctionDetails.GetEnumerator() | Where-Object { $_.Value.ParameterSetDetails | Where-Object { $_.OperationId -eq $parameterSetDetail.'x-ms-pageable'.'operationName'} } | Select-Object -First 1 $matchingPath.Value['IsNextPageOperation'] = $true } } } } } function Add-UniqueParameter { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [hashtable] $ParameterDetails, [Parameter(Mandatory=$true)] [hashtable] $CandidateParameterDetails, [Parameter(Mandatory=$true)] [string] $OperationId, [Parameter(Mandatory=$true)] [hashtable] $ParametersToAdd, [Parameter(Mandatory=$true)] [hashtable] $ParameterHitCount ) Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState $parameterName = $CandidateParameterDetails.Name if($parameterDetails.IsParameter) { if (-not $parameterHitCount.ContainsKey($parameterName)) { $parameterHitCount[$parameterName] = 0 } $parameterHitCount[$parameterName]++ if (-not ($parametersToAdd.ContainsKey($parameterName))) { $parametersToAdd[$parameterName] = @{ # We can grab details like Type, Name, ValidateSet from any of the parameter definitions Details = $CandidateParameterDetails ParameterSetInfo = @{$OperationId = @{ Name = $OperationId Mandatory = $CandidateParameterDetails.Mandatory }} } } else { $parametersToAdd[$parameterName].ParameterSetInfo[$OperationId] = @{ Name = $OperationId Mandatory = $CandidateParameterDetails.Mandatory } } } } function New-SwaggerPath { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [hashtable] $FunctionDetails, [Parameter(Mandatory = $true)] [hashtable] $SwaggerMetaDict, [Parameter(Mandatory = $true)] [hashtable] $SwaggerDict, [Parameter(Mandatory = $true)] [hashtable] $PathFunctionDetails, [Parameter(Mandatory=$true)] [hashtable] $DefinitionFunctionsDetails ) Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState $commandName = $FunctionDetails.CommandName $parameterSetDetails = $FunctionDetails['ParameterSetDetails'] $isLongRunningOperation = $FunctionDetails.ContainsKey('x-ms-long-running-operation') -and $FunctionDetails.'x-ms-long-running-operation' $isNextPageOperation = $FunctionDetails.ContainsKey('IsNextPageOperation') -and $FunctionDetails.'IsNextPageOperation' $info = $SwaggerDict['Info'] $namespace = $info['NameSpace'] $models = $info['Models'] $modulePostfix = $info['infoName'] $clientName = '$' + $modulePostfix $UseAzureCsharpGenerator = $SwaggerMetaDict['UseAzureCsharpGenerator'] $description = '' $paramBlock = '' $paramHelp = '' $parametersToAdd = @{} $flattenedParametersOnPSCmdlet = @{} $parameterHitCount = @{} $globalParameterBlock = '' $x_ms_pageableObject = $null foreach ($parameterSetDetail in $parameterSetDetails) { if ($parameterSetDetail.ContainsKey('x-ms-pageable') -and $parameterSetDetail.'x-ms-pageable' -and (-not $isNextPageOperation)) { if ($x_ms_pageableObject -and $x_ms_pageableObject.ContainsKey('ReturnType') -and ($x_ms_pageableObject.ReturnType -ne 'NONE') -and ($x_ms_pageableObject.ReturnType -ne $parameterSetDetail.ReturnType)) { Write-Warning -Message ($LocalizedData.MultiplePageReturnTypes -f ($commandName)) $x_ms_pageableObject.ReturnType = 'NONE' } elseif (-not $x_ms_pageableObject) { $x_ms_pageableObject = $parameterSetDetail.'x-ms-pageable' $x_ms_pageableObject['ReturnType'] = $parameterSetDetail.ReturnType if ($x_ms_pageableObject.Containskey('operationName')) { # Search for the cmdlet with a parameter set with the given operationName $pagingFunctionDetails = $PathFunctionDetails.GetEnumerator() | Where-Object { $_.Value.ParameterSetDetails | Where-Object { $_.OperationId -eq $x_ms_pageableObject.operationName }} | Select-Object -First 1 if (-not $pagingFunctionDetails) { throw ($LocalizedData.FailedToFindPagingOperation -f ($($x_ms_pageableObject.OperationName), $commandName)) } $pagingParameterSet = $pagingFunctionDetails.Value.ParameterSetDetails | Where-Object { $_.OperationId -eq $x_ms_pageableObject.operationName } $unmatchedParameters = @() # This list of parameters works for when -Page is called... $cmdletArgsPageParameterSet = '' # ...and this list of parameters works for when unrolling paged results (when -Paging is not used) $cmdletArgsNoPaging = '' foreach ($pagingParameterEntry in $pagingParameterSet.ParameterDetails.GetEnumerator()) { $pagingParameter = $pagingParameterEntry.Value # Ignore parameters that are readonly or have a constant value if ($pagingParameter.ContainsKey('ReadOnlyGlobalParameter') -and $pagingParameter.ReadOnlyGlobalParameter) { continue } if ($pagingParameter.ContainsKey('ConstantValue') -and $pagingParameter.ConstantValue) { continue } $matchingCurrentParameter = $parameterSetDetail.ParameterDetails.GetEnumerator() | Where-Object { $_.Value.Name -eq $pagingParameter.Name } | Select-Object -First 1 if ($matchingCurrentParameter) { $cmdletArgsPageParameterSet += "-$($pagingParameter.Name) `$$($pagingParameter.Name) " $cmdletArgsNoPaging += "-$($pagingParameter.Name) `$$($pagingParameter.Name) " } else { $unmatchedParameters += $pagingParameter $cmdletArgsPageParameterSet += "-$($pagingParameter.Name) `$Page.NextPageLink " $cmdletArgsNoPaging += "-$($pagingParameter.Name) `$result.NextPageLink " } } if ($unmatchedParameters.Count -ne 1) { throw ($LocalizedData.InvalidPagingOperationSchema -f ($commandName, $pagingFunctionDetails.Value.CommandName)) } $x_ms_pageableObject['Cmdlet'] = $pagingFunctionDetails.Value.CommandName $x_ms_pageableObject['CmdletArgsPage'] = $cmdletArgsPageParameterSet.Trim() $x_ms_pageableObject['CmdletArgsPaging'] = $cmdletArgsNoPaging.Trim() } else { $x_ms_pageableObject['Operations'] = $parameterSetDetail.Operations $x_ms_pageableObject['MethodName'] = "$($parameterSetDetail.MethodName.Substring(0, $parameterSetDetail.MethodName.IndexOf('WithHttpMessagesAsync')))NextWithHttpMessagesAsync" } } } $parameterSetDetail.ParameterDetails.GetEnumerator() | ForEach-Object { $parameterDetails = $_.Value $parameterRequiresAdding = $true if ($parameterDetails.ContainsKey('x_ms_parameter_location') -and ('client' -eq $parameterDetails.'x_ms_parameter_location')) { # Check if a global has been added already if ($parametersToAdd.ContainsKey("$($parameterDetails.Name)Global")) { $parameterRequiresAdding = $false } elseif ($parameterDetails.ContainsKey('ReadOnlyGlobalParameter') -and $parameterDetails.ReadOnlyGlobalParameter) { $parameterRequiresAdding = $false } else { $globalParameterName = $parameterDetails.Name $globalParameterValue = "```$$($parameterDetails.Name)" if ($parameterDetails.ContainsKey('ConstantValue') -and $parameterDetails.ConstantValue) { # A parameter with a constant value doesn't need to be in the parameter block $parameterRequiresAdding = $false $globalParameterValue = $parameterDetails.ConstantValue } $globalParameterBlock += [Environment]::NewLine + $executionContext.InvokeCommand.ExpandString($GlobalParameterBlockStr) } } if ($parameterRequiresAdding) { $AddUniqueParameter_params = @{ ParameterDetails = $parameterDetails OperationId = $parameterSetDetail.OperationId ParametersToAdd = $parametersToAdd ParameterHitCount = $parameterHitCount } if ($parameterDetails.ContainsKey('x_ms_parameter_grouping_group')) { foreach ($parameterDetailEntry in $parameterDetails.'x_ms_parameter_grouping_group'.GetEnumerator()) { $AddUniqueParameter_params['CandidateParameterDetails'] = $parameterDetailEntry.Value Add-UniqueParameter @AddUniqueParameter_params } } elseif($parameterDetails.ContainsKey('FlattenOnPSCmdlet') -and $parameterDetails.FlattenOnPSCmdlet) { $DefinitionName = ($parameterDetails.Type -split '[.]')[-1] if($DefinitionFunctionsDetails.ContainsKey($DefinitionName)) { $DefinitionDetails = $DefinitionFunctionsDetails[$DefinitionName] $flattenedParametersOnPSCmdlet[$parameterDetails.Name] = $DefinitionDetails $DefinitionDetails.ParametersTable.GetEnumerator() | ForEach-Object { $AddUniqueParameter_params['CandidateParameterDetails'] = $_.value Add-UniqueParameter @AddUniqueParameter_params } } else{ Throw ($LocalizedData.InvalidPSMetaFlattenParameter -f ($parameterDetails.Name,$parameterDetails.Type)) } } else { $AddUniqueParameter_params['CandidateParameterDetails'] = $parameterDetails Add-UniqueParameter @AddUniqueParameter_params } } else { # This magic string is here to distinguish local vs global parameters with the same name, e.g. in the Azure Resources API $parametersToAdd["$($parameterDetails.Name)Global"] = $null } } } $topParameterToAdd = $null $skipParameterToAdd = $null $pagingBlock = '' $pagingOperationName = '' $pagingOperations = '' $Cmdlet = '' $CmdletParameter = '' $CmdletArgs = '' $pageType = 'Array' $resultBlockStr = $resultBlockNoPaging if ($x_ms_pageableObject) { if ($x_ms_pageableObject.ReturnType -ne 'NONE') { $pageType = $x_ms_pageableObject.ReturnType } if ($x_ms_pageableObject.ContainsKey('Operations')) { $pagingOperations = $x_ms_pageableObject.Operations $pagingOperationName = $x_ms_pageableObject.MethodName } else { $Cmdlet = $x_ms_pageableObject.Cmdlet $CmdletArgs = $x_ms_pageableObject.CmdletArgsPaging } $topParameterToAdd = @{ Details = @{ Name = 'Top' Type = 'int' Mandatory = '$false' Description = 'Return the top N items as specified by the parameter value. Applies after the -Skip parameter.' IsParameter = $true ValidateSet = $null ExtendedData = @{ Type = 'int' HasDefaultValue = $true DefaultValue = -1 } } ParameterSetInfo = @{} } $skipParameterToAdd = @{ Details = @{ Name = 'Skip' Type = 'int' Mandatory = '$false' Description = 'Skip the first N items as specified by the parameter value.' IsParameter = $true ValidateSet = $null ExtendedData = @{ Type = 'int' HasDefaultValue = $true DefaultValue = -1 } } ParameterSetInfo = @{} } } # Process security section $azSubscriptionIdBlock = "" $authFunctionCall = "" $overrideBaseUriBlock = "" $httpClientHandlerCall = "" $securityParametersToAdd = @() $PowerShellCodeGen = $SwaggerMetaDict['PowerShellCodeGen'] if (($PowerShellCodeGen['ServiceType'] -eq 'azure') -or ($PowerShellCodeGen['ServiceType'] -eq 'azure_stack')) { $azSubscriptionIdBlock = "`$subscriptionId = Get-AzSubscriptionId" } if ($PowerShellCodeGen['CustomAuthCommand']) { $authFunctionCall = $PowerShellCodeGen['CustomAuthCommand'] } if ($PowerShellCodeGen['HostOverrideCommand']) { $hostOverrideCommand = $PowerShellCodeGen['HostOverrideCommand'] $overrideBaseUriBlock = $executionContext.InvokeCommand.ExpandString($HostOverrideBlock) } # If the auth function hasn't been set by metadata, try to discover it from the security and securityDefinition objects in the spec if (-not $authFunctionCall) { if ($FunctionDetails.ContainsKey('Security')) { # For now, just take the first security object if ($FunctionDetails.Security.Count -gt 1) { Write-Warning ($LocalizedData.MultipleSecurityTypesNotSupported -f $commandName) } $firstSecurityObject = Get-Member -InputObject $FunctionDetails.Security[0] -MemberType NoteProperty # If there's no security object, we don't care about the security definition object if ($firstSecurityObject) { # If there is one, we need to know the definition if (-not $swaggerDict.ContainsKey("SecurityDefinitions")) { throw $LocalizedData.SecurityDefinitionsObjectMissing } $securityDefinitions = $swaggerDict.SecurityDefinitions $securityDefinition = $securityDefinitions.$($firstSecurityObject.Name) if (-not $securityDefinition) { throw ($LocalizedData.SpecificSecurityDefinitionMissing -f ($firstSecurityObject.Name)) } if (-not (Get-Member -InputObject $securityDefinition -Name 'type')) { throw ($LocalizedData.SecurityDefinitionMissingProperty -f ($firstSecurityObject.Name, 'type')) } $type = $securityDefinition.type if ($type -eq 'basic') { # For Basic Authentication, allow the user to pass in a PSCredential object. $credentialParameter = @{ Details = @{ Name = 'Credential' Type = 'PSCredential' Mandatory = '$true' Description = 'User credentials.' IsParameter = $true ValidateSet = $null ExtendedData = @{ Type = 'PSCredential' HasDefaultValue = $false } } ParameterSetInfo = @{} } $securityParametersToAdd += @{ Parameter = $credentialParameter IsConflictingWithOperationParameter = $false } # If the service is specified to not issue authentication challenges, we can't rely on HttpClientHandler if ($PowerShellCodeGen['NoAuthChallenge'] -and ($PowerShellCodeGen['NoAuthChallenge'] -eq $true)) { $authFunctionCall = 'Get-AutoRestCredential -Credential $Credential' } else { # Use an empty service client credentials object because we're using HttpClientHandler instead $authFunctionCall = 'Get-AutoRestCredential' $httpClientHandlerCall = '$httpClientHandler = New-HttpClientHandler -Credential $Credential' } } elseif ($type -eq 'apiKey') { if (-not (Get-Member -InputObject $securityDefinition -Name 'name')) { throw ($LocalizedData.SecurityDefinitionMissingProperty -f ($firstSecurityObject.Name, 'name')) } if (-not (Get-Member -InputObject $securityDefinition -Name 'in')) { throw ($LocalizedData.SecurityDefinitionMissingProperty -f ($firstSecurityObject.Name, 'in')) } $name = $securityDefinition.name $in = $securityDefinition.in # For API key authentication, the user should supply the API key, but the in location and the name are generated from the spec # In addition, we'd be unable to authenticate without the API key, so make it mandatory $credentialParameter = @{ Details = @{ Name = 'APIKey' Type = 'string' Mandatory = '$true' Description = 'API key given by service owner.' IsParameter = $true ValidateSet = $null ExtendedData = @{ Type = 'string' HasDefaultValue = $false } } ParameterSetInfo = @{} } $securityParametersToAdd += @{ Parameter = $credentialParameter IsConflictingWithOperationParameter = $false } $authFunctionCall = "Get-AutoRestCredential -APIKey `$APIKey -Location '$in' -Name '$name'" } else { Write-Warning -Message ($LocalizedData.UnsupportedAuthenticationType -f ($type)) } } } } if (-not $authFunctionCall) { # At this point, there was no supported security object or overridden auth function, so assume no auth $authFunctionCall = 'Get-AutoRestCredential' } $clientArgumentList = $clientArgumentListNoHandler if ($httpClientHandlerCall) { $clientArgumentList = $clientArgumentListHttpClientHandler } $nonUniqueParameterSets = @() foreach ($parameterSetDetail in $parameterSetDetails) { # Add parameter sets to paging parameter sets if ($topParameterToAdd -and $parameterSetDetail.ContainsKey('x-ms-pageable') -and $parameterSetDetail.'x-ms-pageable' -and (-not $isNextPageOperation)) { $topParameterToAdd.ParameterSetInfo[$parameterSetDetail.OperationId] = @{ Name = $parameterSetDetail.OperationId Mandatory = '$false' } } if ($skipParameterToAdd -and $parameterSetDetail.ContainsKey('x-ms-pageable') -and $parameterSetDetail.'x-ms-pageable' -and (-not $isNextPageOperation)) { $skipParameterToAdd.ParameterSetInfo[$parameterSetDetail.OperationId] = @{ Name = $parameterSetDetail.OperationId Mandatory = '$false' } } # Test for uniqueness of parameters $parameterSetDetail.ParameterDetails.GetEnumerator() | ForEach-Object { $parameterDetails = $_.Value # Check if the paging parameters are conflicting # Note that this has to be moved elsewhere to be more generic, but this is temporarily located here to solve this scenario for paging at least if ($topParameterToAdd -and $parameterDetails.Name -eq 'Top') { $topParameterToAdd = $null # If the parameter is not OData, full paging support isn't possible. if (-not $parameterDetails.ExtendedData.ContainsKey('IsODataParameter') -or -not $parameterDetails.ExtendedData.IsODataParameter) { Write-Warning -Message ($LocalizedData.ParameterConflictAndResult -f ('Top', $commandName, $parameterSetDetail.OperationId, $LocalizedData.PagingNotFullySupported)) } } if ($skipParameterToAdd -and $parameterDetails.Name -eq 'Skip') { $skipParameterToAdd = $null # If the parameter is not OData, full paging support isn't possible. if (-not $parameterDetails.ExtendedData.ContainsKey('IsODataParameter') -or -not $parameterDetails.ExtendedData.IsODataParameter) { Write-Warning -Message ($LocalizedData.ParameterConflictAndResult -f ('Skip', $commandName, $parameterSetDetail.OperationId, $LocalizedData.PagingNotFullySupported)) } } foreach ($additionalParameter in $securityParametersToAdd) { if ($parameterDetails.Name -eq $additionalParameter.Parameter.Details.Name) { $additionalParameter.IsConflictingWithOperationParameter = $true Write-Warning -Message ($LocalizedData.ParameterConflictAndResult -f ($additionalParameter.Parameter.Details.Name, $commandName, $parameterSetDetail.OperationId, $LocalizedData.CredentialParameterNotSupported)) } } if ($parameterHitCount[$parameterDetails.Name] -eq 1) { # continue here brings us back to the top of the $parameterSetDetail.ParameterDetails.GetEnumerator() | ForEach-Object loop continue } } # At this point none of the parameters in this set are unique $nonUniqueParameterSets += $parameterSetDetail } if ($topParameterToAdd) { $parametersToAdd[$topParameterToAdd.Details.Name] = $topParameterToAdd } if ($skipParameterToAdd) { $parametersToAdd[$skipParameterToAdd.Details.Name] = $skipParameterToAdd } foreach ($additionalParameter in $securityParametersToAdd) { if (-not $additionalParameter.IsConflictingWithOperationParameter) { $parametersToAdd[$additionalParameter.Parameter.Details.Name] = $additionalParameter.Parameter } } if ($topParameterToAdd -and $skipParameterToAdd) { $resultBlockStr = $executionContext.InvokeCommand.ExpandString($resultBlockWithSkipAndTop) } elseif ($topParameterToAdd -and -not $skipParameterToAdd) { $resultBlockStr = $executionContext.InvokeCommand.ExpandString($resultBlockWithTop) } elseif (-not $topParameterToAdd -and $skipParameterToAdd) { $resultBlockStr = $executionContext.InvokeCommand.ExpandString($resultBlockWithSkip) } $getTaskResult = $executionContext.InvokeCommand.ExpandString($getTaskResultBlock) if ($pagingOperations) { if ($topParameterToAdd) { $pagingBlock = $executionContext.InvokeCommand.ExpandString($PagingBlockStrFunctionCallWithTop) } else { $pagingBlock = $executionContext.InvokeCommand.ExpandString($PagingBlockStrFunctionCall) } } elseif ($Cmdlet) { if ($topParameterToAdd) { $pagingBlock = $executionContext.InvokeCommand.ExpandString($PagingBlockStrCmdletCallWithTop) } else { $pagingBlock = $executionContext.InvokeCommand.ExpandString($PagingBlockStrCmdletCall) } } # For description, we're currently using the default parameter set's description, since concatenating multiple descriptions doesn't ever really work out well. if ($nonUniqueParameterSets.Length -gt 1) { # Pick the highest priority set among $nonUniqueParameterSets, but really it doesn't matter, cause... # Print warning that this generated cmdlet has ambiguous parameter sets $defaultParameterSet = $nonUniqueParameterSets | Sort-Object -Property Priority | Select-Object -First 1 $DefaultParameterSetName = $defaultParameterSet.OperationId $description = $defaultParameterSet.Description Write-Warning -Message ($LocalizedData.CmdletHasAmbiguousParameterSets -f ($commandName)) } elseif ($nonUniqueParameterSets.Length -eq 1) { # If there's only one non-unique, we can prevent errors by making this the default $DefaultParameterSetName = $nonUniqueParameterSets[0].OperationId $description = $nonUniqueParameterSets[0].Description } else { # Pick the highest priority set among all sets $defaultParameterSet = $parameterSetDetails | Sort-Object @{e = {$_.Priority -as [int] }} | Select-Object -First 1 $DefaultParameterSetName = $defaultParameterSet.OperationId $description = $defaultParameterSet.Description } $oDataExpression = "" $oDataExpressionBlock = "" # Variable used to replace in function body $parameterGroupsExpressionBlock = "" # Variable used to store all group expressions, concatenate, then store in $parameterGroupsExpressionBlock $parameterGroupsExpressions = @{} $parametersToAdd.GetEnumerator() | ForEach-Object { $parameterToAdd = $_.Value if ($parameterToAdd) { $parameterName = $parameterToAdd.Details.Name $AllParameterSetsString = '' foreach ($parameterSetInfoEntry in $parameterToAdd.ParameterSetInfo.GetEnumerator()) { $parameterSetInfo = $parameterSetInfoEntry.Value $isParamMandatory = $parameterSetInfo.Mandatory $ParameterSetPropertyString = ", ParameterSetName = '$($parameterSetInfo.Name)'" if ($AllParameterSetsString) { # Two tabs $AllParameterSetsString += [Environment]::NewLine + " " + $executionContext.InvokeCommand.ExpandString($parameterAttributeString) } else { $AllParameterSetsString = $executionContext.InvokeCommand.ExpandString($parameterAttributeString) } } if (-not $AllParameterSetsString) { $isParamMandatory = $parameterToAdd.Details.Mandatory $ParameterSetPropertyString = "" $AllParameterSetsString = $executionContext.InvokeCommand.ExpandString($parameterAttributeString) } $paramName = "`$$parameterName" $ValidateSetDefinition = $null if ($parameterToAdd.Details.ValidateSet) { $ValidateSetString = $parameterToAdd.Details.ValidateSet $ValidateSetDefinition = $executionContext.InvokeCommand.ExpandString($ValidateSetDefinitionString) } $parameterDefaultValueOption = "" $paramType = "$([Environment]::NewLine) " if ($parameterToAdd.Details.ContainsKey('ExtendedData')) { if ($parameterToAdd.Details.ExtendedData.ContainsKey('IsODataParameter') -and $parameterToAdd.Details.ExtendedData.IsODataParameter) { $paramType = "[$($parameterToAdd.Details.Type)]$paramType" $oDataExpression += " if (`$$parameterName) { `$oDataQuery += `"&```$$parameterName=`$$parameterName`" }" + [Environment]::NewLine } else { # Assuming you can't group ODataQuery parameters if ($parameterToAdd.Details.ContainsKey('x_ms_parameter_grouping') -and $parameterToAdd.Details.'x_ms_parameter_grouping') { $parameterGroupPropertyName = $parameterToAdd.Details.Name $groupName = $parameterToAdd.Details.'x_ms_parameter_grouping' $fullGroupName = $parameterToAdd.Details.ExtendedData.GroupType if ($parameterGroupsExpressions.ContainsKey($groupName)) { $parameterGroupsExpression = $parameterGroupsExpressions[$groupName] } else { $parameterGroupsExpression = $executionContext.InvokeCommand.ExpandString($parameterGroupCreateExpression) } $parameterGroupsExpression += [Environment]::NewLine + $executionContext.InvokeCommand.ExpandString($parameterGroupPropertyExpression) $parameterGroupsExpressions[$groupName] = $parameterGroupsExpression } if ($parameterToAdd.Details.ExtendedData.Type) { $paramType = "[$($parameterToAdd.Details.ExtendedData.Type)]$paramType" if ($parameterToAdd.Details.ExtendedData.HasDefaultValue) { if ($parameterToAdd.Details.ExtendedData.DefaultValue) { if ([NullString]::Value -eq $parameterToAdd.Details.ExtendedData.DefaultValue) { $parameterDefaultValue = "[NullString]::Value" } elseif ("System.String" -eq $parameterToAdd.Details.ExtendedData.Type) { $parameterDefaultValue = "`"$($parameterToAdd.Details.ExtendedData.DefaultValue)`"" } else { $parameterDefaultValue = "$($parameterToAdd.Details.ExtendedData.DefaultValue)" } } else { $parameterDefaultValue = "`$null" } $parameterDefaultValueOption = $executionContext.InvokeCommand.ExpandString($parameterDefaultValueString) } } } $paramBlock += $executionContext.InvokeCommand.ExpandString($parameterDefString) $pDescription = $parameterToAdd.Details.Description $paramHelp += $executionContext.InvokeCommand.ExpandString($helpParamStr) } elseif($parameterToAdd.Details.Containskey('Type')) { $paramType = "[$($parameterToAdd.Details.Type)]$paramType" $paramblock += $executionContext.InvokeCommand.ExpandString($parameterDefString) $pDescription = $parameterToAdd.Details.Description $paramHelp += $executionContext.InvokeCommand.ExpandString($helpParamStr) } else { Write-Warning ($LocalizedData.ParameterMissingFromAutoRestCode -f ($parameterName, $commandName)) } } } foreach ($parameterGroupsExpressionEntry in $parameterGroupsExpressions.GetEnumerator()) { $parameterGroupsExpressionBlock += $parameterGroupsExpressionEntry.Value + [Environment]::NewLine } if ($oDataExpression) { $oDataExpression = $oDataExpression.Trim() $oDataExpressionBlock = $executionContext.InvokeCommand.ExpandString($oDataExpressionBlockStr) } $paramBlock = $paramBlock.TrimEnd().TrimEnd(",") $commandHelp = $executionContext.InvokeCommand.ExpandString($helpDescStr) if ($isLongRunningOperation) { if ($paramBlock) { $ParamBlockReplaceStr = $paramBlock + ",`r`n" + $AsJobParameterString } else { $ParamBlockReplaceStr = $AsJobParameterString } $PathFunctionBody = $executionContext.InvokeCommand.ExpandString($PathFunctionBodyAsJob) } else { $ParamBlockReplaceStr = $paramBlock $PathFunctionBody = $executionContext.InvokeCommand.ExpandString($PathFunctionBodySynch) } $functionBodyParams = @{ ParameterSetDetails = $parameterSetDetails ODataExpressionBlock = $oDataExpressionBlock ParameterGroupsExpressionBlock = $parameterGroupsExpressionBlock GlobalParameterBlock = $GlobalParameterBlock SwaggerDict = $SwaggerDict SwaggerMetaDict = $SwaggerMetaDict SecurityBlock = $executionContext.InvokeCommand.ExpandString($securityBlockStr) OverrideBaseUriBlock = $overrideBaseUriBlock ClientArgumentList = $clientArgumentList FlattenedParametersOnPSCmdlet = $flattenedParametersOnPSCmdlet } $pathGenerationPhaseResult = Get-PathFunctionBody @functionBodyParams $bodyObject = $pathGenerationPhaseResult.BodyObject $body = $bodyObject.Body $outputTypeBlock = $bodyObject.OutputTypeBlock if ($UseAzureCsharpGenerator) { $dependencyInitFunction = "Initialize-PSSwaggerDependencies -Azure" } else { $dependencyInitFunction = "Initialize-PSSwaggerDependencies" } $CommandString = $executionContext.InvokeCommand.ExpandString($advFnSignatureForPath) $GeneratedCommandsPath = Join-Path -Path (Join-Path -Path $SwaggerMetaDict['outputDirectory'] -ChildPath $GeneratedCommandsName) ` -ChildPath 'SwaggerPathCommands' if(-not (Test-Path -Path $GeneratedCommandsPath -PathType Container)) { $null = New-Item -Path $GeneratedCommandsPath -ItemType Directory } $CommandFilePath = Join-Path -Path $GeneratedCommandsPath -ChildPath "$commandName.ps1" Out-File -InputObject $CommandString -FilePath $CommandFilePath -Encoding ascii -Force -Confirm:$false -WhatIf:$false Write-Verbose -Message ($LocalizedData.GeneratedPathCommand -f $commandName) return $commandName } function Set-ExtendedCodeMetadata { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string] $MainClientTypeName, [Parameter(Mandatory=$true)] [string] $CliXmlTmpPath ) $resultRecord = @{ VerboseMessages = @() ErrorMessages = @() WarningMessages = @() } $resultRecord.VerboseMessages += $LocalizedData.ExtractingMetadata $PathFunctionDetails = Import-CliXml -Path $CliXmlTmpPath $errorOccurred = $false $PathFunctionDetails.GetEnumerator() | ForEach-Object { $FunctionDetails = $_.Value $ParameterSetDetails = $FunctionDetails['ParameterSetDetails'] foreach ($parameterSetDetail in $ParameterSetDetails) { if ($errorOccurred) { return } $operationId = $parameterSetDetail.OperationId $methodName = '' $operations = '' $operationsWithSuffix = '' $opIdValues = $operationId -split '_',2 if(-not $opIdValues -or ($opIdValues.count -ne 2)) { $methodName = $operationId + 'WithHttpMessagesAsync' } else { $operationName = $opIdValues[0] $operationType = $opIdValues[1] $operations = ".$operationName" if ($parameterSetDetail['UseOperationsSuffix'] -and $parameterSetDetail['UseOperationsSuffix']) { $operationsWithSuffix = $operations + 'Operations' } $methodName = $operationType + 'WithHttpMessagesAsync' } $parameterSetDetail['MethodName'] = $methodName $parameterSetDetail['Operations'] = $operations # For some reason, moving this out of this loop causes issues $clientType = $MainClientTypeName -as [Type] if (-not $clientType) { $resultRecord.ErrorMessages += $LocalizedData.ExpectedServiceClientTypeNotFound -f ($MainClientTypeName) Export-CliXml -InputObject $resultRecord -Path $CliXmlTmpPath $errorOccurred = $true return } # Process global parameters $paramObject = $parameterSetDetail.ParameterDetails $clientType.GetProperties() | ForEach-Object { $propertyName = $_.Name $matchingParamDetail = $paramObject.GetEnumerator() | Where-Object { $_.Value.Name -eq $propertyName } | Select-Object -First 1 -ErrorAction Ignore if ($matchingParamDetail) { $setSingleParameterMetadataParms = @{ CommandName = $FunctionDetails['CommandName'] Name = $matchingParamDetail.Value.Name HasDefaultValue = $false IsGrouped = $false Type = $_.PropertyType MatchingParamDetail = $matchingParamDetail.Value ResultRecord = $resultRecord } if (-not (Set-SingleParameterMetadata @setSingleParameterMetadataParms)) { Export-CliXml -InputObject $ResultRecord -Path $CliXmlTmpPath $errorOccurred = $true return } } } if ($operationsWithSuffix) { $operationName = $operationsWithSuffix.Substring(1) $propertyObject = $clientType.GetProperties() | Where-Object { $_.Name -eq $operationName } | Select-Object -First 1 -ErrorAction Ignore if (-not $propertyObject) { # The Operations suffix logic isn't rock solid, so this is safety check. $operationName = $operations.Substring(1) $propertyObject = $clientType.GetProperties() | Where-Object { $_.Name -eq $operationName } | Select-Object -First 1 -ErrorAction Ignore if (-not $propertyObject) { $resultRecord.ErrorMessages += $LocalizedData.ExpectedOperationsClientTypeNotFound -f ($operationName, $clientType) Export-CliXml -InputObject $resultRecord -Path $CliXmlTmpPath $errorOccurred = $true return } } else { $parameterSetDetail['Operations'] = $operationsWithSuffix } $clientType = $propertyObject.PropertyType } elseif ($operations) { $operationName = $operations.Substring(1) $propertyObject = $clientType.GetProperties() | Where-Object { $_.Name -eq $operationName } | Select-Object -First 1 -ErrorAction Ignore if (-not $propertyObject) { $resultRecord.ErrorMessages += $LocalizedData.ExpectedOperationsClientTypeNotFound -f ($operationName, $clientType) Export-CliXml -InputObject $resultRecord -Path $CliXmlTmpPath $errorOccurred = $true return } $clientType = $propertyObject.PropertyType } $methodInfo = $clientType.GetMethods() | Where-Object { $_.Name -eq $MethodName } | Select-Object -First 1 if (-not $methodInfo) { $resultRecord.ErrorMessages += $LocalizedData.ExpectedMethodOnTypeNotFound -f ($MethodName, $clientType) Export-CliXml -InputObject $resultRecord -Path $CliXmlTmpPath $errorOccurred = $true return } # Process output type $returnType = $methodInfo.ReturnType if ($returnType.Name -eq 'Task`1') { $returnType = $returnType.GenericTypeArguments[0] } if ($returnType.Name -eq 'AzureOperationResponse`1') { $returnType = $returnType.GenericTypeArguments[0] } $returnTypeString = Convert-GenericTypeToString -Type $returnType $parameterSetDetail['ReturnType'] = $returnTypeString $ParamList = @() $oDataQueryFound = $false $methodInfo.GetParameters() | Sort-Object -Property Position | ForEach-Object { $hasDefaultValue = $_.HasDefaultValue # All Types should be converted to their string names, otherwise the CLI XML gets too large $type = $_.ParameterType.ToString() $metadata = @{ Name = Get-PascalCasedString -Name $_.Name HasDefaultValue = $hasDefaultValue Type = $type } $matchingParamDetail = $paramObject.GetEnumerator() | Where-Object { $_.Value.Name -eq $metadata.Name } | Select-Object -First 1 -ErrorAction Ignore if ($matchingParamDetail) { # Not all parameters in the code is present in the Swagger spec (autogenerated parameters like CustomHeaders or ODataQuery parameters) $matchingParamDetail = $matchingParamDetail[0].Value if ($matchingParamDetail.ContainsKey('x_ms_parameter_grouping_group')) { # Look through this parameter group's parameters and extract the individual metadata $paramToAdd = "`$$($matchingParamDetail.Name)" $parameterGroupType = $_.ParameterType $parameterGroupType.GetProperties() | ForEach-Object { $parameterGroupProperty = $_ $matchingGroupedParameterDetailEntry = $matchingParamDetail.'x_ms_parameter_grouping_group'.GetEnumerator() | Where-Object { $_.Value.Name -eq $parameterGroupProperty.Name } | Select-Object -First 1 -ErrorAction Ignore if ($matchingGroupedParameterDetailEntry) { $setSingleParameterMetadataParms = @{ CommandName = $FunctionDetails['CommandName'] Name = $matchingParamDetail.Name HasDefaultValue = $false IsGrouped = $true Type = $_.PropertyType MatchingParamDetail = $matchingGroupedParameterDetailEntry.Value ResultRecord = $resultRecord } if (-not (Set-SingleParameterMetadata @setSingleParameterMetadataParms)) { Export-CliXml -InputObject $ResultRecord -Path $CliXmlTmpPath $errorOccurred = $true return } $matchingGroupedParameterDetailEntry.Value.ExtendedData.GroupType = $parameterGroupType.ToString() } } } else { # Single parameter $setSingleParameterMetadataParms = @{ CommandName = $FunctionDetails['CommandName'] Name = $_.Name HasDefaultValue = $hasDefaultValue IsGrouped = $false Type = $_.ParameterType MatchingParamDetail = $matchingParamDetail ResultRecord = $resultRecord } if ($hasDefaultValue) { $setSingleParameterMetadataParms['DefaultValue'] = $_.DefaultValue } if (-not (Set-SingleParameterMetadata @setSingleParameterMetadataParms)) { Export-CliXml -InputObject $ResultRecord -Path $CliXmlTmpPath $errorOccurred = $true return } $paramToAdd = $matchingParamDetail.ExtendedData.ParamToAdd } $ParamList += $paramToAdd } else { if ($metadata.Type.StartsWith("Microsoft.Rest.Azure.OData.ODataQuery``1")) { if ($oDataQueryFound) { $resultRecord.ErrorMessages += ($LocalizedData.MultipleODataQueriesOneFunction -f ($operationId)) Export-CliXml -InputObject $resultRecord -Path $CliXmlTmpPath return } else { # Escape backticks $oDataQueryType = $metadata.Type.Replace("``", "````") $ParamList += "`$(if (`$oDataQuery) { New-Object -TypeName `"$oDataQueryType`" -ArgumentList `$oDataQuery } else { `$null })" $oDataQueryFound = $true } } } } if ($parameterSetDetail.ContainsKey('x-ms-odata') -and $parameterSetDetail.'x-ms-odata') { $paramObject.GetEnumerator() | ForEach-Object { $paramDetail = $_.Value if (-not $paramDetail.ContainsKey('ExtendedData')) { $metadata = @{ IsODataParameter = $true } $paramDetail.ExtendedData = $metadata } } } $parameterSetDetail['ExpandedParamList'] = $ParamList -Join ", " } if ($errorOccurred) { return } } $resultRecord.Result = $PathFunctionDetails Export-CliXml -InputObject $resultRecord -Path $CliXmlTmpPath } function Convert-GenericTypeToString { param( [Parameter(Mandatory=$true)] [Type]$Type ) if (-not $Type.IsGenericType) { return $Type.FullName } $genericTypeStr = '' foreach ($genericTypeArg in $Type.GenericTypeArguments) { $genericTypeStr += "$(Convert-GenericTypeToString -Type $genericTypeArg)," } $genericTypeStr = $genericTypeStr.Substring(0, $genericTypeStr.Length - 1) return "$($Type.FullName.Substring(0, $Type.FullName.IndexOf('`')))[$genericTypeStr]" } function Set-SingleParameterMetadata { param( [Parameter(Mandatory=$true)] [string] $CommandName, [Parameter(Mandatory=$true)] [string] $Name, [Parameter(Mandatory=$true)] [bool] $HasDefaultValue, [Parameter(Mandatory=$true)] [bool] $IsGrouped, [Parameter(Mandatory=$true)] [System.Type] $Type, [Parameter(Mandatory=$true)] [hashtable] $MatchingParamDetail, [Parameter(Mandatory=$true)] [hashtable] $ResultRecord, [Parameter(Mandatory=$false)] [object] $DefaultValue ) $name = Get-PascalCasedString -Name $_.Name $metadata = @{ Name = $name HasDefaultValue = $HasDefaultValue Type = $Type.ToString() ParamToAdd = "`$$name" } if ($HasDefaultValue) { # Setting this default value actually matter, but we might as well if ("System.String" -eq $metadata.Type) { if ($DefaultValue -eq $null) { $metadata.HasDefaultValue = $false # This is the part that works around PS automatic string coercion $metadata.ParamToAdd = "`$(if (`$PSBoundParameters.ContainsKey('$($metadata.Name)')) { $($metadata.ParamToAdd) } else { [NullString]::Value })" } } elseif ("System.Nullable``1[System.Boolean]" -eq $metadata.Type) { if($DefaultValue -ne $null) { $DefaultValue = "`$$DefaultValue" } $metadata.Type = "switch" } else { $DefaultValue = $_.DefaultValue if (-not ($_.ParameterType.IsValueType) -and $DefaultValue) { $ResultRecord.ErrorMessages += $LocalizedData.ReferenceTypeDefaultValueNotSupported -f ($metadata.Name, $metadata.Type, $CommandName) return $false } } $metadata['DefaultValue'] = $DefaultValue } else { if ('$false' -eq $matchingParamDetail.Mandatory -and (-not $IsGrouped)) { # This happens in the case of optional path parameters, even if the path parameter is at the end $ResultRecord.WarningMessages += ($LocalizedData.OptionalParameterNowRequired -f ($metadata.Name, $CommandName)) } } $MatchingParamDetail['ExtendedData'] = $metadata return $true } function Get-TemporaryCliXmlFilePath { param( [Parameter(Mandatory=$true)] [string] $FullModuleName ) $random = [Guid]::NewGuid().Guid $filePath = Join-Path -Path (Get-XDGDirectory -DirectoryType Cache) -ChildPath "$FullModuleName.$random.xml" return $filePath } # SIG # Begin signature block # MIIasAYJKoZIhvcNAQcCoIIaoTCCGp0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUglSfETl+53rANJitrSvOuUaq # JiWgghWDMIIEwzCCA6ugAwIBAgITMwAAALfuAa/68MeouwAAAAAAtzANBgkqhkiG # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTYwOTA3MTc1ODQ1 # WhcNMTgwOTA3MTc1ODQ1WjCBszELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjENMAsGA1UECxMETU9QUjEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNO # OkJCRUMtMzBDQS0yREJFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT # ZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuCMjQSw3ep1m # SndFRK0xgVRgm9wSl3i2llRtDdxzAWN9gQtYAE3hJP0/pV/7HHkshYPfMIRf7Pm/ # dxSsAN+7ATnNUk+wpe46rfe0FDNxoE6CYaiMSNjKcMXH55bGXNnwrrcsMaZrVXzS # IQcmAhUQw1jdLntbdTyCAwJ2UqF/XmVtWV/U466G8JP8VGLddeaucY0YKhgYwMnt # Sp9ElCkVDcUP01L9pgn9JmKUfD3yFt2p1iZ9VKCrlla10JQwe7aNW7xjzXxvcvlV # IXeA4QSabo4dq8HUh7JoYMqh3ufr2yNgTs/rSxG6D5ITcI0PZkH4PYjO2GbGIcOF # RVOf5RxVrwIDAQABo4IBCTCCAQUwHQYDVR0OBBYEFJZnqouaH5kw+n1zGHTDXjCT # 5OMAMB8GA1UdIwQYMBaAFCM0+NlSRnAK7UD7dvuzK7DDNbMPMFQGA1UdHwRNMEsw # SaBHoEWGQ2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz # L01pY3Jvc29mdFRpbWVTdGFtcFBDQS5jcmwwWAYIKwYBBQUHAQEETDBKMEgGCCsG # AQUFBzAChjxodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv # c29mdFRpbWVTdGFtcFBDQS5jcnQwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZI # hvcNAQEFBQADggEBAG7J+Fdd7DgxG6awnA8opmQfW5DHnNDC/JPLof1sA8Nqczym # cnWIHmlWhqA7TUy4q02lKenO+R/vbmHna1BrC/KkczAyhOzkI2WFU3PeYubv8EjK # fYPmrNvS8fCsHJXj3N6fuFwXkHmCVBjTchK93auG09ckBYx5Mt4zW0TUbbw4/QAZ # X64rbut6Aw/C1bpxqBb8vvMssBB9Hw2m8ApFTApaEVOE/sKemVlq0VIo0fCXqRST # Lb6/QOav3S8S+N34RBNx/aKKOFzBDy6Ni45QvtRfBoNX3f4/mm4TFdNs+SeLQA+0 # oBs7UgdoxGSpX6vsWaH8dtlBw3NZK7SFi9bBMI4wggTtMIID1aADAgECAhMzAAAB # QJap7nBW/swHAAEAAAFAMA0GCSqGSIb3DQEBBQUAMHkxCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xIzAhBgNVBAMTGk1pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBMB4XDTE2MDgxODIwMTcxN1oXDTE3MTEwMjIwMTcxN1owgYMxCzAJ # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDTALBgNVBAsTBE1PUFIx # HjAcBgNVBAMTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjCCASIwDQYJKoZIhvcNAQEB # BQADggEPADCCAQoCggEBANtLi+kDal/IG10KBTnk1Q6S0MThi+ikDQUZWMA81ynd # ibdobkuffryavVSGOanxODUW5h2s+65r3Akw77ge32z4SppVl0jII4mzWSc0vZUx # R5wPzkA1Mjf+6fNPpBqks3m8gJs/JJjE0W/Vf+dDjeTc8tLmrmbtBDohlKZX3APb # LMYb/ys5qF2/Vf7dSd9UBZSrM9+kfTGmTb1WzxYxaD+Eaxxt8+7VMIruZRuetwgc # KX6TvfJ9QnY4ItR7fPS4uXGew5T0goY1gqZ0vQIz+lSGhaMlvqqJXuI5XyZBmBre # ueZGhXi7UTICR+zk+R+9BFF15hKbduuFlxQiCqET92ECAwEAAaOCAWEwggFdMBMG # A1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBSc5ehtgleuNyTe6l6pxF+QHc7Z # ezBSBgNVHREESzBJpEcwRTENMAsGA1UECxMETU9QUjE0MDIGA1UEBRMrMjI5ODAz # K2Y3ODViMWMwLTVkOWYtNDMxNi04ZDZhLTc0YWU2NDJkZGUxYzAfBgNVHSMEGDAW # gBTLEejK0rQWWAHJNy4zFha5TJoKHzBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8v # Y3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNDb2RTaWdQQ0Ff # MDgtMzEtMjAxMC5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRw # Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY0NvZFNpZ1BDQV8wOC0z # MS0yMDEwLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAa+RW49cTHSBA+W3p3k7bXR7G # bCaj9+UJgAz/V+G01Nn5XEjhBn/CpFS4lnr1jcmDEwxxv/j8uy7MFXPzAGtOJar0 # xApylFKfd00pkygIMRbZ3250q8ToThWxmQVEThpJSSysee6/hU+EbkfvvtjSi0lp # DimD9aW9oxshraKlPpAgnPWfEj16WXVk79qjhYQyEgICamR3AaY5mLPuoihJbKwk # Mig+qItmLPsC2IMvI5KR91dl/6TV6VEIlPbW/cDVwCBF/UNJT3nuZBl/YE7ixMpT # Th/7WpENW80kg3xz6MlCdxJfMSbJsM5TimFU98KNcpnxxbYdfqqQhAQ6l3mtYDCC # BbwwggOkoAMCAQICCmEzJhoAAAAAADEwDQYJKoZIhvcNAQEFBQAwXzETMBEGCgmS # JomT8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UE # AxMkTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDgz # MTIyMTkzMloXDTIwMDgzMTIyMjkzMloweTELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQ # Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCycllcGTBkvx2aYCAg # Qpl2U2w+G9ZvzMvx6mv+lxYQ4N86dIMaty+gMuz/3sJCTiPVcgDbNVcKicquIEn0 # 8GisTUuNpb15S3GbRwfa/SXfnXWIz6pzRH/XgdvzvfI2pMlcRdyvrT3gKGiXGqel # cnNW8ReU5P01lHKg1nZfHndFg4U4FtBzWwW6Z1KNpbJpL9oZC/6SdCnidi9U3RQw # WfjSjWL9y8lfRjFQuScT5EAwz3IpECgixzdOPaAyPZDNoTgGhVxOVoIoKgUyt0vX # T2Pn0i1i8UU956wIAPZGoZ7RW4wmU+h6qkryRs83PDietHdcpReejcsRj1Y8wawJ # XwPTAgMBAAGjggFeMIIBWjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLEejK # 0rQWWAHJNy4zFha5TJoKHzALBgNVHQ8EBAMCAYYwEgYJKwYBBAGCNxUBBAUCAwEA # ATAjBgkrBgEEAYI3FQIEFgQU/dExTtMmipXhmGA7qDFvpjy82C0wGQYJKwYBBAGC # NxQCBAweCgBTAHUAYgBDAEEwHwYDVR0jBBgwFoAUDqyCYEBWJ5flJRP8KuEKU5VZ # 5KQwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br # aS9jcmwvcHJvZHVjdHMvbWljcm9zb2Z0cm9vdGNlcnQuY3JsMFQGCCsGAQUFBwEB # BEgwRjBEBggrBgEFBQcwAoY4aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9j # ZXJ0cy9NaWNyb3NvZnRSb290Q2VydC5jcnQwDQYJKoZIhvcNAQEFBQADggIBAFk5 # Pn8mRq/rb0CxMrVq6w4vbqhJ9+tfde1MOy3XQ60L/svpLTGjI8x8UJiAIV2sPS9M # uqKoVpzjcLu4tPh5tUly9z7qQX/K4QwXaculnCAt+gtQxFbNLeNK0rxw56gNogOl # VuC4iktX8pVCnPHz7+7jhh80PLhWmvBTI4UqpIIck+KUBx3y4k74jKHK6BOlkU7I # G9KPcpUqcW2bGvgc8FPWZ8wi/1wdzaKMvSeyeWNWRKJRzfnpo1hW3ZsCRUQvX/Ta # rtSCMm78pJUT5Otp56miLL7IKxAOZY6Z2/Wi+hImCWU4lPF6H0q70eFW6NB4lhhc # yTUWX92THUmOLb6tNEQc7hAVGgBd3TVbIc6YxwnuhQ6MT20OE049fClInHLR82zK # wexwo1eSV32UjaAbSANa98+jZwp0pTbtLS8XyOZyNxL0b7E8Z4L5UrKNMxZlHg6K # 3RDeZPRvzkbU0xfpecQEtNP7LN8fip6sCvsTJ0Ct5PnhqX9GuwdgR2VgQE6wQuxO # 7bN2edgKNAltHIAxH+IOVN3lofvlRxCtZJj/UBYufL8FIXrilUEnacOTj5XJjdib # Ia4NXJzwoq6GaIMMai27dmsAHZat8hZ79haDJLmIz2qoRzEvmtzjcT3XAH5iR9HO # iMm4GPoOco3Boz2vAkBq/2mbluIQqBC0N1AI1sM9MIIGBzCCA++gAwIBAgIKYRZo # NAAAAAAAHDANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZImiZPyLGQBGRYDY29tMRkw # FwYKCZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQDEyRNaWNyb3NvZnQgUm9v # dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcwNDAzMTI1MzA5WhcNMjEwNDAz # MTMwMzA5WjB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwggEiMA0GCSqGSIb3DQEB # AQUAA4IBDwAwggEKAoIBAQCfoWyx39tIkip8ay4Z4b3i48WZUSNQrc7dGE4kD+7R # p9FMrXQwIBHrB9VUlRVJlBtCkq6YXDAm2gBr6Hu97IkHD/cOBJjwicwfyzMkh53y # 9GccLPx754gd6udOo6HBI1PKjfpFzwnQXq/QsEIEovmmbJNn1yjcRlOwhtDlKEYu # J6yGT1VSDOQDLPtqkJAwbofzWTCd+n7Wl7PoIZd++NIT8wi3U21StEWQn0gASkdm # EScpZqiX5NMGgUqi+YSnEUcUCYKfhO1VeP4Bmh1QCIUAEDBG7bfeI0a7xC1Un68e # eEExd8yb3zuDk6FhArUdDbH895uyAc4iS1T/+QXDwiALAgMBAAGjggGrMIIBpzAP # BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQjNPjZUkZwCu1A+3b7syuwwzWzDzAL # BgNVHQ8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwgZgGA1UdIwSBkDCBjYAUDqyC # YEBWJ5flJRP8KuEKU5VZ5KShY6RhMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAX # BgoJkiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290 # IENlcnRpZmljYXRlIEF1dGhvcml0eYIQea0WoUqgpa1Mc1j0BxMuZTBQBgNVHR8E # STBHMEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9k # dWN0cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEESDBGMEQGCCsG # AQUFBzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jv # c29mdFJvb3RDZXJ0LmNydDATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0B # AQUFAAOCAgEAEJeKw1wDRDbd6bStd9vOeVFNAbEudHFbbQwTq86+e4+4LtQSooxt # YrhXAstOIBNQmd16QOJXu69YmhzhHQGGrLt48ovQ7DsB7uK+jwoFyI1I4vBTFd1P # q5Lk541q1YDB5pTyBi+FA+mRKiQicPv2/OR4mS4N9wficLwYTp2OawpylbihOZxn # LcVRDupiXD8WmIsgP+IHGjL5zDFKdjE9K3ILyOpwPf+FChPfwgphjvDXuBfrTot/ # xTUrXqO/67x9C0J71FNyIe4wyrt4ZVxbARcKFA7S2hSY9Ty5ZlizLS/n+YWGzFFW # 6J1wlGysOUzU9nm/qhh6YinvopspNAZ3GmLJPR5tH4LwC8csu89Ds+X57H2146So # dDW4TsVxIxImdgs8UoxxWkZDFLyzs7BNZ8ifQv+AeSGAnhUwZuhCEl4ayJ4iIdBD # 6Svpu/RIzCzU2DKATCYqSCRfWupW76bemZ3KOm+9gSd0BhHudiG/m4LBJ1S2sWo9 # iaF2YbRuoROmv6pH8BJv/YoybLL+31HIjCPJZr2dHYcSZAI9La9Zj7jkIeW1sMpj # tHhUBdRBLlCslLCleKuzoJZ1GtmShxN1Ii8yqAhuoFuMJb+g74TKIdbrHk/Jmu5J # 4PcBZW+JC33Iacjmbuqnl84xKf8OxVtc2E0bodj6L54/LlUWa8kTo/0xggSXMIIE # kwIBATCBkDB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSMw # IQYDVQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQQITMwAAAUCWqe5wVv7M # BwABAAABQDAJBgUrDgMCGgUAoIGwMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEE # MBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBQZ # ik8/I/8DKLiv4FgFSr0Rz75LizBQBgorBgEEAYI3AgEMMUIwQKAWgBQAUABvAHcA # ZQByAFMAaABlAGwAbKEmgCRodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUG93ZXJT # aGVsbCAwDQYJKoZIhvcNAQEBBQAEggEAN/KEw65Hl3OYvH1s04yHYh97PrrHyVMb # 07bO1GzV/aFSO7Vqp+olcJCPSAocUdr2LOkYJ61E7SaZ48TEyS0FZrRgex+Pad89 # rosB8E2DKyc5SE9HQlCDVANjFPZloY4KWWs7gART2PcRb1n0SBt6omFpDNUdi346 # TeFMxdQj/BQd1KDDRaPqrpqHXLHuCB5v6X9IEUjk40hikEXWYi2FGg52nP0c85NS # Ng/td603+rHJxylakngUi2ARcKIK5X/FsqMpGgqbsPOAeYoGw7mGgL7RApi6MHbB # jwi1+YA2QvChnHTOy0w4mcoXdpbtWmdC9QueMSkg3Wh6ZKxkJq4xZqGCAigwggIk # BgkqhkiG9w0BCQYxggIVMIICEQIBATCBjjB3MQswCQYDVQQGEwJVUzETMBEGA1UE # CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z # b2Z0IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQ # Q0ECEzMAAAC37gGv+vDHqLsAAAAAALcwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJ # AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE3MDgwODE3MzUyNFowIwYJ # KoZIhvcNAQkEMRYEFOVS5yI2UfRYxi4gUvuCd7odA4SeMA0GCSqGSIb3DQEBBQUA # BIIBABR45sOu3J8hpL8xqKbtD6U1/MI0kn7LrIDPnAvm3MKgkh0qMAMoFE1Nz4yV # TpCIEzml9VQ4jOx9OyjMESgD1nIvKZ5+SrKTl2aviay+kjcHFI8pbRZallSUWeUH # lfU/5zuPOLmM+bt/gP7/WnRPPIw185ySoXIN4SJN6Es3AZgCQc2Iwj6qquC25wMZ # oBenRL23BIrrnOCo686qumdGmKawG/q4uS4D8VsR2ixbyNVJJArgvH1rr+sN9bby # kORX2PfVSHVhd9KRw9YenUQ9eHp8WlCkKD46nohleF7oPNbaP2GoRJHtU3pCjvJD # dR35x6Sdb4+0RmdHDS3H6bzWqqQ= # SIG # End signature block |