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 } $FunctionSynopsis = '' if((Get-Member -InputObject $_.value -Name 'Summary') -and $_.value.Summary) { $FunctionSynopsis = $_.value.Summary } $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 } # Priority of a parameterset will be used to determine the default parameterset of a cmdlet. $Priority = 0 $ParametersCount = Get-HashtableKeyCount -Hashtable $ParametersTable if($ParametersCount) { # Priority for parameter sets with mandatory parameters starts at 100 $Priority = 100 $ParametersTable.GetEnumerator() | ForEach-Object { if($_.Value.ContainsKey('Mandatory') -and $_.Value.Mandatory -eq '$true') { $Priority++ } } # If there are no mandatory parameters, use the parameter count as the priority. if($Priority -eq 100) { $Priority = $ParametersCount } } $ParameterSetDetail = @{ Description = $FunctionDescription Synopsis = $FunctionSynopsis ParameterDetails = $ParametersTable Responses = $responses OperationId = $operationId OperationType = $operationType EndpointRelativePath = $EndpointRelativePath PathCommonParameters = $PathCommonParameters Priority = $Priority '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 } } $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, [Parameter(Mandatory=$false)] [AllowEmptyString()] [string] $PSHeaderComment ) 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 ` -PSHeaderComment $PSHeaderComment } 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, [Parameter(Mandatory=$false)] [AllowEmptyString()] [string] $PSHeaderComment ) 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'] $clientName = '$' + $info['ClientTypeName'] $UseAzureCsharpGenerator = $SwaggerMetaDict['UseAzureCsharpGenerator'] $description = '' $synopsis = '' $paramBlock = '' $paramHelp = '' $parametersToAdd = @{} $flattenedParametersOnPSCmdlet = @{} $parameterHitCount = @{} $globalParameters = @() $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($parameterSetDetail.ContainsKey('PSCmdletOutputItemType')) { $x_ms_pageableObject['PSCmdletOutputItemType'] = $parameterSetDetail.PSCmdletOutputItemType } 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 } $globalParameters += $globalParameterName } } 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 = '' $NextLinkName = 'NextLink' $pagingOperations = '' $Cmdlet = '' $CmdletParameter = '' $CmdletArgs = '' $pageType = 'Array' $PSCmdletOutputItemType = '' $resultBlockStr = $resultBlockNoPaging if ($x_ms_pageableObject) { if ($x_ms_pageableObject.ReturnType -ne 'NONE') { $pageType = $x_ms_pageableObject.ReturnType if($x_ms_pageableObject.ContainsKey('PSCmdletOutputItemType')) { $PSCmdletOutputItemType = $x_ms_pageableObject.PSCmdletOutputItemType } } 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 } if ($x_ms_pageableObject.ContainsKey('NextLinkName') -and $x_ms_pageableObject.NextLinkName) { $NextLinkName = $x_ms_pageableObject.NextLinkName } $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 $AuthenticationCommand = "" $AuthenticationCommandArgumentName = '' $hostOverrideCommand = '' $AddHttpClientHandler = $false $securityParametersToAdd = @() $PowerShellCodeGen = $SwaggerMetaDict['PowerShellCodeGen'] # CustomAuthCommand and HostOverrideCommand are not required for Arm Services if (($PowerShellCodeGen['ServiceType'] -ne 'azure') -and ($PowerShellCodeGen['ServiceType'] -eq 'azure_stack')) { if ($PowerShellCodeGen['CustomAuthCommand']) { $AuthenticationCommand = $PowerShellCodeGen['CustomAuthCommand'] } if ($PowerShellCodeGen['HostOverrideCommand']) { $hostOverrideCommand = $PowerShellCodeGen['HostOverrideCommand'] } } # 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 $AuthenticationCommand -and -not $UseAzureCsharpGenerator) { 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)) { $AuthenticationCommand = 'param([pscredential]$Credential) Get-AutoRestCredential -Credential $Credential' $AuthenticationCommandArgumentName = 'Credential' } else { # Use an empty service client credentials object because we're using HttpClientHandler instead $AuthenticationCommand = 'Get-AutoRestCredential' $AddHttpClientHandler = $true } } 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 } $AuthenticationCommand = "param([string]`$APIKey) Get-AutoRestCredential -APIKey `$APIKey -Location '$in' -Name '$name'" $AuthenticationCommandArgumentName = 'APIKey' } else { Write-Warning -Message ($LocalizedData.UnsupportedAuthenticationType -f ($type)) } } } } if (-not $AuthenticationCommand -and -not $UseAzureCsharpGenerator) { # At this point, there was no supported security object or overridden auth function, so assume no auth $AuthenticationCommand = 'Get-AutoRestCredential' } $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 {$_.Priority} | Select-Object -First 1 $DefaultParameterSetName = $defaultParameterSet.OperationId $description = $defaultParameterSet.Description $synopsis = $defaultParameterSet.Synopsis 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 $synopsis = $nonUniqueParameterSets[0].Synopsis } 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 $synopsis = $defaultParameterSet.Synopsis } $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 SwaggerDict = $SwaggerDict SwaggerMetaDict = $SwaggerMetaDict FlattenedParametersOnPSCmdlet = $flattenedParametersOnPSCmdlet } if($AuthenticationCommand) { $functionBodyParams['AuthenticationCommand'] = $AuthenticationCommand $functionBodyParams['AuthenticationCommandArgumentName'] = $AuthenticationCommandArgumentName } if($AddHttpClientHandler) { $functionBodyParams['AddHttpClientHandler'] = $AddHttpClientHandler } if($hostOverrideCommand) { $functionBodyParams['hostOverrideCommand'] = $hostOverrideCommand } if($globalParameters) { $functionBodyParams['GlobalParameters'] = $globalParameters } $pathGenerationPhaseResult = Get-PathFunctionBody @functionBodyParams $bodyObject = $pathGenerationPhaseResult.BodyObject $body = $bodyObject.Body if($PSCmdletOutputItemType){ $fullPathDataType = $PSCmdletOutputItemType $outputTypeBlock = $executionContext.InvokeCommand.ExpandString($outputTypeStr) } else { $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 @($PSHeaderComment, $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 $methodNames = @() $operations = '' $operationsWithSuffix = '' $opIdValues = $operationId -split '_',2 if(-not $opIdValues -or ($opIdValues.count -ne 2)) { $methodNames += $operationId + 'WithHttpMessagesAsync' $methodNames += $operationId + 'Method' + 'WithHttpMessagesAsync' } else { $operationName = $opIdValues[0] $operationType = $opIdValues[1] $operations = ".$operationName" if ($parameterSetDetail['UseOperationsSuffix'] -and $parameterSetDetail['UseOperationsSuffix']) { $operationsWithSuffix = $operations + 'Operations' } $methodNames += $operationType + 'WithHttpMessagesAsync' # When OperationType value conflicts with a definition name, AutoREST generates method name by adding Method to the OperationType. $methodNames += $operationType + 'Method' + 'WithHttpMessagesAsync' } $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 {$MethodNames -contains $_.Name} | Select-Object -First 1 if (-not $methodInfo) { $resultRecord.ErrorMessages += $LocalizedData.ExpectedMethodOnTypeNotFound -f (($MethodNames -join ', or '), $clientType) Export-CliXml -InputObject $resultRecord -Path $CliXmlTmpPath $errorOccurred = $true return } $parameterSetDetail['MethodName'] = $methodInfo.Name # 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] } # Note: ReturnType and PSCmdletOutputItemType are currently used for Swagger operations which supports x-ms-pageable. if (($returnType.Name -eq 'IPage`1') -and $returnType.GenericTypeArguments) { $PSCmdletOutputItemTypeString = Convert-GenericTypeToString -Type $returnType.GenericTypeArguments[0] $parameterSetDetail['PSCmdletOutputItemType'] = $PSCmdletOutputItemTypeString.Trim('[]') } $parameterSetDetail['ReturnType'] = Convert-GenericTypeToString -Type $returnType $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] $FullClientTypeName ) $random = [Guid]::NewGuid().Guid $filePath = Join-Path -Path (Get-XDGDirectory -DirectoryType Cache) -ChildPath "$FullClientTypeName.$random.xml" return $filePath } # SIG # Begin signature block # MIIarQYJKoZIhvcNAQcCoIIanjCCGpoCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU5/h5hXHsrJVILE1EFjztnO2a # sMOgghWAMIIEwjCCA6qgAwIBAgITMwAAALwLLhp7irHHkQAAAAAAvDANBgkqhkiG # 9w0BAQUFADB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G # A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEw # HwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwHhcNMTYwOTA3MTc1ODQ3 # WhcNMTgwOTA3MTc1ODQ3WjCBsjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw # b3JhdGlvbjEMMAoGA1UECxMDQU9DMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046 # MTJCNC0yRDVGLTg3RDQxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNl # cnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrW5IBRZQaAQPT # HTCSXDRgGi/lbqVTqt3Mp5XqqbEkIZowQp8M/Gyv+1TmRpbFaQIQ4oQ7AqZRsvd+ # PMGtZjo6vUBRyeLKpnHq1a9XYeiGkoGaJu/98Ued3Z+sFD45bhzi6tLzY6kq98KI # YqK7XsI76kqVU3oIyiETzzoANwuXUNSnm9lAN3l/G8xgDm/3qBWMSjkBvg2GeZ57 # 3WqYP6fImkO9U0bRtuIr6mybzvXUUO+rg6hhdrEnLGI4QQ7frEWReYeyMlgjC7VR # aJy2gomkh+sEmxxivphgOuJrtPgUhdIlyTkUTtyudNUd/6gTE4zt9TsmFf5wGCsx # pbZqKFW3AgMBAAGjggEJMIIBBTAdBgNVHQ4EFgQUyHJk5pJfz0FWFyn1nlRJFHyq # /vcwHwYDVR0jBBgwFoAUIzT42VJGcArtQPt2+7MrsMM1sw8wVAYDVR0fBE0wSzBJ # oEegRYZDaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv # TWljcm9zb2Z0VGltZVN0YW1wUENBLmNybDBYBggrBgEFBQcBAQRMMEowSAYIKwYB # BQUHMAKGPGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljcm9z # b2Z0VGltZVN0YW1wUENBLmNydDATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG # 9w0BAQUFAAOCAQEAPiS9UtetZjCdEkaanFlC+NU/Ti+PUD6O+P6yCASPI6+qK20t # B16FXJg7rXRee3c/E2wcyWuxeL/0oLkj4LunxQoDDhoOjM9w9SnrWjki/kbkEdbg # i1Pl4ebDSu+6Six3fdRrLowgkQwXxkCoUWwyFS9dL5BbC5lSzHlOiXiWVlc94vr3 # 9sMaoqsxl6A6Ud9YvbohYuiKJsdpSrLW97wXO66h+Cx289JckOmomW1Zum3ppfgp # +5lJJBxySomU08S8G5QOOrvjO4KsQ55eHHVWJXhnGL+zhghaSf5TIQuDdohDOnNb # +FImqnwn3++hmpbkAVWdFUNDNlJemia/hMH9vzCCBOswggPToAMCAQICEzMAAAF4 # JVq1zSPGX5UAAQAAAXgwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWljcm9zb2Z0IENvZGUgU2ln # bmluZyBQQ0EwHhcNMTcwODExMjAxMTE1WhcNMTgwODExMjAxMTE1WjCBgjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEMMAoGA1UECxMDQU9DMR4w # HAYDVQQDExVNaWNyb3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQCZbh1TVaudsrIbXUPPB9c8S+E+dKSbskHKYlG6SGTH8jhT # hpuvGiAO87F2b9GHVN+DvszaMkGy/xQgHaGEJLfpnb3kpakic7E0bjDHdG4KnHRb # no/wfUkGLfS79o+cw//RY8Ck6yE+0czDBcxp0Gbw5JyGP+KFqvzRR/3Tv3nt/5x0 # 5ZnEOHYP+eDVikDvn/DH+oxxtiCfX3tkvtm/yX4eOb47YdmYKQjCgz2+Nil/lupY # vU0QFIjvke3jshqQINDng/vO9ys2qA0ex/q5hlLKQTST99dGoM86Ge6F723ReToq # KnGLN8kiCG7uNapOAIQrpCHZq96CVumiaA5ZvxU9AgMBAAGjggFgMIIBXDATBgNV # HSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUjuhtD3FD7tk/RKloJFX05cpgLjcw # UQYDVR0RBEowSKRGMEQxDDAKBgNVBAsTA0FPQzE0MDIGA1UEBRMrMjI5ODAzKzFh # YmY5ZTVmLWNlZDAtNDJlNi1hNjVkLWQ5MzUwOTU5ZmUwZTAfBgNVHSMEGDAWgBTL # EejK0rQWWAHJNy4zFha5TJoKHzBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3Js # Lm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNDb2RTaWdQQ0FfMDgt # MzEtMjAxMC5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY0NvZFNpZ1BDQV8wOC0zMS0y # MDEwLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAYnG/oHG/xgZYR8NAMHZ/vE9GM0e4 # 7YdhuTea2uY7pSGwM707wp8Wan0Fa6evK1PWfcd/XNOh2BpEv5o8RmKDoEsG0ECP # 13Jug7cklfKreBVHQ+Djg43VVFLZpuo7aOAVK6wjlcnpPUtn+SfH9K0aM2FjDKVJ # FW6XFKXBat5R+Zp6uOxWTxpSeMTeDC5zF6IY6ogR1uzU+9EQoRlAvkwX6po+exEL # nMLr4++P+fqOxIU+PODIoB8ijClAqwwKvLlMPa3qlrNHt+LweTMu7lvGC/RA18wU # zzXAeomuZ03blUw+bkOiVgWOk4S0RN7EnW7zjJV8gd/+G2dbToUi1cB/fTCCBbww # ggOkoAMCAQICCmEzJhoAAAAAADEwDQYJKoZIhvcNAQEFBQAwXzETMBEGCgmSJomT # 8ixkARkWA2NvbTEZMBcGCgmSJomT8ixkARkWCW1pY3Jvc29mdDEtMCsGA1UEAxMk # TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDgzMTIy # MTkzMloXDTIwMDgzMTIyMjkzMloweTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEjMCEGA1UEAxMaTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0Ew # ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCycllcGTBkvx2aYCAgQpl2 # U2w+G9ZvzMvx6mv+lxYQ4N86dIMaty+gMuz/3sJCTiPVcgDbNVcKicquIEn08Gis # TUuNpb15S3GbRwfa/SXfnXWIz6pzRH/XgdvzvfI2pMlcRdyvrT3gKGiXGqelcnNW # 8ReU5P01lHKg1nZfHndFg4U4FtBzWwW6Z1KNpbJpL9oZC/6SdCnidi9U3RQwWfjS # jWL9y8lfRjFQuScT5EAwz3IpECgixzdOPaAyPZDNoTgGhVxOVoIoKgUyt0vXT2Pn # 0i1i8UU956wIAPZGoZ7RW4wmU+h6qkryRs83PDietHdcpReejcsRj1Y8wawJXwPT # AgMBAAGjggFeMIIBWjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLEejK0rQW # WAHJNy4zFha5TJoKHzALBgNVHQ8EBAMCAYYwEgYJKwYBBAGCNxUBBAUCAwEAATAj # BgkrBgEEAYI3FQIEFgQU/dExTtMmipXhmGA7qDFvpjy82C0wGQYJKwYBBAGCNxQC # BAweCgBTAHUAYgBDAEEwHwYDVR0jBBgwFoAUDqyCYEBWJ5flJRP8KuEKU5VZ5KQw # UAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9j # cmwvcHJvZHVjdHMvbWljcm9zb2Z0cm9vdGNlcnQuY3JsMFQGCCsGAQUFBwEBBEgw # RjBEBggrBgEFBQcwAoY4aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0 # cy9NaWNyb3NvZnRSb290Q2VydC5jcnQwDQYJKoZIhvcNAQEFBQADggIBAFk5Pn8m # Rq/rb0CxMrVq6w4vbqhJ9+tfde1MOy3XQ60L/svpLTGjI8x8UJiAIV2sPS9MuqKo # VpzjcLu4tPh5tUly9z7qQX/K4QwXaculnCAt+gtQxFbNLeNK0rxw56gNogOlVuC4 # iktX8pVCnPHz7+7jhh80PLhWmvBTI4UqpIIck+KUBx3y4k74jKHK6BOlkU7IG9KP # cpUqcW2bGvgc8FPWZ8wi/1wdzaKMvSeyeWNWRKJRzfnpo1hW3ZsCRUQvX/TartSC # Mm78pJUT5Otp56miLL7IKxAOZY6Z2/Wi+hImCWU4lPF6H0q70eFW6NB4lhhcyTUW # X92THUmOLb6tNEQc7hAVGgBd3TVbIc6YxwnuhQ6MT20OE049fClInHLR82zKwexw # o1eSV32UjaAbSANa98+jZwp0pTbtLS8XyOZyNxL0b7E8Z4L5UrKNMxZlHg6K3RDe # ZPRvzkbU0xfpecQEtNP7LN8fip6sCvsTJ0Ct5PnhqX9GuwdgR2VgQE6wQuxO7bN2 # edgKNAltHIAxH+IOVN3lofvlRxCtZJj/UBYufL8FIXrilUEnacOTj5XJjdibIa4N # XJzwoq6GaIMMai27dmsAHZat8hZ79haDJLmIz2qoRzEvmtzjcT3XAH5iR9HOiMm4 # GPoOco3Boz2vAkBq/2mbluIQqBC0N1AI1sM9MIIGBzCCA++gAwIBAgIKYRZoNAAA # AAAAHDANBgkqhkiG9w0BAQUFADBfMRMwEQYKCZImiZPyLGQBGRYDY29tMRkwFwYK # CZImiZPyLGQBGRYJbWljcm9zb2Z0MS0wKwYDVQQDEyRNaWNyb3NvZnQgUm9vdCBD # ZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcwNDAzMTI1MzA5WhcNMjEwNDAzMTMw # MzA5WjB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEwHwYD # VQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQCfoWyx39tIkip8ay4Z4b3i48WZUSNQrc7dGE4kD+7Rp9FM # rXQwIBHrB9VUlRVJlBtCkq6YXDAm2gBr6Hu97IkHD/cOBJjwicwfyzMkh53y9Gcc # LPx754gd6udOo6HBI1PKjfpFzwnQXq/QsEIEovmmbJNn1yjcRlOwhtDlKEYuJ6yG # T1VSDOQDLPtqkJAwbofzWTCd+n7Wl7PoIZd++NIT8wi3U21StEWQn0gASkdmEScp # ZqiX5NMGgUqi+YSnEUcUCYKfhO1VeP4Bmh1QCIUAEDBG7bfeI0a7xC1Un68eeEEx # d8yb3zuDk6FhArUdDbH895uyAc4iS1T/+QXDwiALAgMBAAGjggGrMIIBpzAPBgNV # HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQjNPjZUkZwCu1A+3b7syuwwzWzDzALBgNV # HQ8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwgZgGA1UdIwSBkDCBjYAUDqyCYEBW # J5flJRP8KuEKU5VZ5KShY6RhMF8xEzARBgoJkiaJk/IsZAEZFgNjb20xGTAXBgoJ # kiaJk/IsZAEZFgltaWNyb3NvZnQxLTArBgNVBAMTJE1pY3Jvc29mdCBSb290IENl # cnRpZmljYXRlIEF1dGhvcml0eYIQea0WoUqgpa1Mc1j0BxMuZTBQBgNVHR8ESTBH # MEWgQ6BBhj9odHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0 # cy9taWNyb3NvZnRyb290Y2VydC5jcmwwVAYIKwYBBQUHAQEESDBGMEQGCCsGAQUF # BzAChjhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY3Jvc29m # dFJvb3RDZXJ0LmNydDATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQUF # AAOCAgEAEJeKw1wDRDbd6bStd9vOeVFNAbEudHFbbQwTq86+e4+4LtQSooxtYrhX # AstOIBNQmd16QOJXu69YmhzhHQGGrLt48ovQ7DsB7uK+jwoFyI1I4vBTFd1Pq5Lk # 541q1YDB5pTyBi+FA+mRKiQicPv2/OR4mS4N9wficLwYTp2OawpylbihOZxnLcVR # DupiXD8WmIsgP+IHGjL5zDFKdjE9K3ILyOpwPf+FChPfwgphjvDXuBfrTot/xTUr # XqO/67x9C0J71FNyIe4wyrt4ZVxbARcKFA7S2hSY9Ty5ZlizLS/n+YWGzFFW6J1w # lGysOUzU9nm/qhh6YinvopspNAZ3GmLJPR5tH4LwC8csu89Ds+X57H2146SodDW4 # TsVxIxImdgs8UoxxWkZDFLyzs7BNZ8ifQv+AeSGAnhUwZuhCEl4ayJ4iIdBD6Svp # u/RIzCzU2DKATCYqSCRfWupW76bemZ3KOm+9gSd0BhHudiG/m4LBJ1S2sWo9iaF2 # YbRuoROmv6pH8BJv/YoybLL+31HIjCPJZr2dHYcSZAI9La9Zj7jkIeW1sMpjtHhU # BdRBLlCslLCleKuzoJZ1GtmShxN1Ii8yqAhuoFuMJb+g74TKIdbrHk/Jmu5J4PcB # ZW+JC33Iacjmbuqnl84xKf8OxVtc2E0bodj6L54/LlUWa8kTo/0xggSXMIIEkwIB # ATCBkDB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSMwIQYD # VQQDExpNaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQQITMwAAAXglWrXNI8ZflQAB # AAABeDAJBgUrDgMCGgUAoIGwMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwG # CisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRgaR35 # xaCjydVQp9Xyacht8pvtYzBQBgorBgEEAYI3AgEMMUIwQKAWgBQAUABvAHcAZQBy # AFMAaABlAGwAbKEmgCRodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUG93ZXJTaGVs # bCAwDQYJKoZIhvcNAQEBBQAEggEAbtltf0aVQX69gw1vgVkNtIU0UR7qhxE8Mk0T # 7JZopXy63g46asVsiqXd5Z2hYePR0HKHw3rEuNCGuJa/29u4e8s3qngar+Wn69o3 # qMffkE5LJNlXUButKUCC8weVKWO0Iptqj8z57iOHOvc0ADDPuscFMoBgrS2VJG+e # XLBScqrBWyIONu00H5PL2mNBM0TXDHV8KFALBd7gsz9EOzPMf39VJuurAkyutBg1 # pTUKfRlhRiovyHdBvpxTGN6q5hI+b3pOk2okLH3pqwvL28hacDumw67k/gx5EfLE # Uo1RlNQk2hVHpbSSQ5UcYs10TGWhGPcKB2Z/X69GrLNFDtskNaGCAigwggIkBgkq # hkiG9w0BCQYxggIVMIICEQIBATCBjjB3MQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EC # EzMAAAC8Cy4ae4qxx5EAAAAAALwwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzEL # BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE3MTAxMDIwNDc0OFowIwYJKoZI # hvcNAQkEMRYEFPpp56JXeeiFxftf47lVeOgZxJ4IMA0GCSqGSIb3DQEBBQUABIIB # AGcMrq6HDk/U9P3oHyx/eackYG0vhwkMKpd/oW/BG8irl9thHcaJPVWM9+Rbb7kI # pXEH5kgMSOTlUdSeWpSaVSl6q5CLIUMgmwoMQI6HTvyG78J2kmiN7SSn26ZVPlYL # NZD3dYnUG9GZogHnAaDs1mZFQyi8BSl+hJ6tdYjplxBV91eYkCLF5KprKPGn9DAa # ajOOlanFvFRhINXqckp9z5IK5dLLvA92jUvYRyZ04YC+VDNYKuJ1llYT0SH3JJQv # R8W90oaNonw5yn5jLAKhQrmAL5bUwA0cV9/1uWyrj7O3PLHelZuhaZ/bsfycttwn # PJjeSsalOIVdYWpzkj7XcVQ= # SIG # End signature block |