Is there something I am fundamentally missing from

2020-07-30 01:53发布

问题:

I've written a PowerShell module that we use in our Azure Pipeline that will bind an SSL Certificate to a custom hostname. I am able to get the module working locally, including the inline script that I use in the pipeline to initialize the module. When I run the script locally, I do not get any errors. When I use the same script in the pipeline I receive the following error:

2019-07-16T23:00:40.3007294Z ##[error]Parameter set cannot be resolved using the specified named parameters.

I'm not using parameter sets, so I'm not sure why it is complaining. What is the reason I am able to execute my code locally and not in the release pipeline? Is the parameter set error really a complaint about something else?

Again, I've tested this locally. All of my parameters are required, so I'm not specifying a ParameterSet, though, I did set one up just in case, and I got the same error.

This is the script I use in the release pipeline using an Azure Powershell Task after I successfully import my module. I know my variable declarations are correct because I have tested them and they output fine (both locally and in the pipeline):

The error happens when the task hits this line in the script: Enable-SslStateOnWebapp -WebappName $webappName -customWebappHostname $webAppCustomHostname -existingKeyvaultName $existingVaultName -existingKeyvaultCertName $certName

$myVars = '$(armDeploymentOutput)' | ConvertFrom-Json
Write-Host "The following variables are available: $($myVars)" -Verbose
$existingVaultName = $myVars.existingKeyVaultName.value
$webappName=$myVars.webappName.value
$webAppCustomHostname=$myVars.webAppCustomHostname.value
$certName=$myVars.existingKeyVaultCertificateName.value

if ($webappName -and $webAppCustomHostname -and $existingVaultName -and $certName) {
    Write-Host "Attempting to enable SSL Binding for $($webappName) on the hostname $($webAppCustomHostname) using cert $($certName) from the existing keyvault of $($existingVaultName)." -Verbose
    Enable-SslStateOnWebapp -WebappName $webappName -customWebappHostname $webAppCustomHostname -existingKeyvaultName $existingVaultName -existingKeyvaultCertName $certName
}
else {
    Write-Host "Insufficient parameters have been provided to complete SSL Binding. To enable SSL binding, please provide a custom hostname, an existing keyvault where your certificate is stored, and the name of your certificate. Please visit the readme for more information." -Verbose
}

This is the PowerShell module that is initialized:

function Enable-SslStateOnWebapp {
    param (
        [Parameter(
            Mandatory = $true,
            HelpMessage = 'A webapp name is required.')]
        [ValidateNotNullOrEmpty()]
        [string] $WebappName,

        [PARAMETER(
            Mandatory = $true,            
            HelpMessage = 'The FQDN of the custom hostname you want to bind.')]
        [ValidateNotNullOrEmpty()]
        [string] $customWebappHostname,

        [Parameter(
            Mandatory = $true,
            HelpMessage = 'A name for an existing Keyvault is required.')]
        [ValidateNotNullOrEmpty()]
        [string] $existingKeyvaultName,

        [PARAMETER(
            Mandatory = $true,            
            HelpMessage = 'A name of the pfx certificate stored in the pre-existing keyvault')]
        [ValidateNotNullOrEmpty()]
        [string] $existingKeyVaultCertName
    )
    #getting webapp resources
    $webapp = Get-AzureRmResource -Name $webappName
    #obtaining resource group resources through the use of resource group name tied to webapp
    $rg = Get-AzureRmResource -ResourceGroupName $webapp.ResourceGroupName 

...

}

My expected result is that the build pipeline would execute the script without errors. Instead, I get passing results locally (which makes this obviously difficult to debug, and then in the pipeline I get the following debug logging:

2019-07-16T23:00:39.1496157Z ##[debug]Caught exception from task script.
2019-07-16T23:00:39.1536232Z ##[debug]Error record:
2019-07-16T23:00:39.1993172Z ##[debug]Enable-SslStateOnWebapp : Parameter set cannot be resolved using the specified named parameters.
2019-07-16T23:00:40.2927954Z ##[debug]At D:\agent3\_work\_temp\7be280f0-5905-4e05-99e0-972c90739a12.ps1:13 char:5
2019-07-16T23:00:40.2930113Z ##[debug]+     Enable-SslStateOnWebapp -WebappName $webappName -customWebappHost ...
2019-07-16T23:00:40.2940404Z ##[debug]+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-07-16T23:00:40.2940886Z ##[debug]    + CategoryInfo          : InvalidArgument: (:) [Enable-SslStateOnWebapp],     ParameterBindingException
2019-07-16T23:00:40.2941287Z ##[debug]    + FullyQualifiedErrorId : AmbiguousParameterSet,Enable-SslStateOnWebapp
2019-07-16T23:00:40.2941647Z ##[debug] 
2019-07-16T23:00:40.2941968Z ##[debug]Script stack trace:
2019-07-16T23:00:40.2942368Z ##[debug]at Enable-SslStateOnWebapp, D:\agent3\_work\r6\a\_infra-grs-referenceapp\drop\pwsh-modules\grs-arm\enable-ssl_state_on_webapp\enable-ssl_state_on_webapp.ps1: line 64

I checked if there are hidden unix characters, since I'm developing locally on a Mac, there are none:

Unix-hidden character check

回答1:

TLDR; This issue is caused by an incompatibility of the versions being used between your local development environment and the version being used by the AzureDevops build agent. Check the build agent versions and ensure they are the same as the version you developed in.

I was inspired by the answer in this post.

The error is thrown from line 64 in the script (which is the first executable line of the script):

2019-07-16T23:00:39.1496157Z ##[debug]Caught exception from task script.
2019-07-16T23:00:39.1536232Z ##[debug]Error record:
2019-07-16T23:00:39.1993172Z ##[debug]Enable-SslStateOnWebapp : Parameter set cannot be resolved using the specified named parameters.
2019-07-16T23:00:40.2927954Z ##[debug]At D:\agent3\_work\_temp\7be280f0-5905-4e05-99e0-972c90739a12.ps1:13 char:5
2019-07-16T23:00:40.2930113Z ##[debug]+     Enable-SslStateOnWebapp -WebappName $webappName -customWebappHost ...
2019-07-16T23:00:40.2940404Z ##[debug]+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-07-16T23:00:40.2940886Z ##[debug]    + CategoryInfo          : InvalidArgument: (:) [Enable-SslStateOnWebapp],     ParameterBindingException
2019-07-16T23:00:40.2941287Z ##[debug]    + FullyQualifiedErrorId : AmbiguousParameterSet,Enable-SslStateOnWebapp
2019-07-16T23:00:40.2941647Z ##[debug] 
2019-07-16T23:00:40.2941968Z ##[debug]Script stack trace:
2019-07-16T23:00:40.2942368Z ##[debug]at Enable-SslStateOnWebapp, D:\agent3\_work\r6\a\_infra-grs-referenceapp\drop\pwsh-modules\grs-arm\enable-ssl_state_on_webapp\enable-ssl_state_on_webapp.ps1: line 64

Given that it is the first executable line of the script, I assumed that the error was the result of the parameter binding on the function working incorrectly, especially because line 63 was not being written to the host.

Write-Host "Attempting to get webapp resource..." -Verbose

I have found that this is in fact not the case. I've observed that at times a Write-Host may not be called if the subsequent line fails.

Developing locally, I am using v6.13.1 of AzureRM. If I look at the function I am calling on line 64, this function is:

$webapp = Get-AzureRmResource -Name $webappName

Looking at the documentation (v6.13.1) for this cmdlet:

Get-AzureRmResource
   [[-Name] <String>]
   [-ResourceType <String>]
   [-ODataQuery <String>]
   [-ResourceGroupName <String>]
   [-TagName <String>]
   [-TagValue <String>]
   [-ExpandProperties]
   [-ApiVersion <String>]
   [-Pre]
   [-DefaultProfile <IAzureContextContainer>]
   [<CommonParameters>]

and documentation for the version on my build agent (~v4.6):

Get-AzureRmResource
   [-ResourceName <String>]
   [-ResourceType <String>]
   [-ExtensionResourceName <String>]
   [-ExtensionResourceType <String>]
   [-ExpandProperties]
   [-IsCollection]
   [-Top <Int32>]
   [-ODataQuery <String>]
   [-TenantLevel]
   [-ApiVersion <String>]
   [-Pre]
   [-DefaultProfile <IAzureContextContainer>]
   [<CommonParameters>]

we can see that the -Name and -ResourceName parameters are different. This causes the AmbiguousParameterSet error.

RESOLUTION: Our particular build agent is local and isn't updated as regularly as the Microsoft hosted agents.

I forced an update to our build agent's AzureRM version using a standard powershell task:

- task: PowerShell@2
 inputs:
 targetType: 'inline'
 script: 'Install-PackageProvider -Name NuGet -Force -Scope CurrentUser;
 Install-Module -Name AzureRM -RequiredVersion 6.13.1 -Force -Scope CurrentUser -AllowClobber;'

And then called Get-Module in the subsequent task with my script and specified the version 6.13.1 in the task's preferredAzurePowerShellVersion section (if the version you want is not available on the agent, this will result in an error of version not available, hence why you run the previous PowerShell task.:

- task: AzurePowerShell@3
 inputs:
 azureSubscription: '<subscription>'
 ScriptType: 'InlineScript'
 Inline: 'Get-Module AzureRm;
 Import-Module $(System.DefaultWorkingDirectory)\drop\pwsh-modules\grs-arm;
 $myVars = '$(armDeploymentOutput)' | ConvertFrom-Json
 Write-Host "The following variables are available: $($myVars)" -Verbose

 $existingVaultName = $myVars.existingKeyVaultName.value
 $webappName=$myVars.webappName.value
 $webAppCustomHostname=$myVars.webAppCustomHostname.value
 $certName=$myVars.existingKeyVaultCertificateName.value

 Write-Host "Setting an access policy for the SPN to $($existingVaultName)" -Verbose
 Set-AzureRmKeyVaultAccessPolicy -VaultName $existingVaultName -ServicePrincipalName <spnClientId> -PermissionsToCertificates get -PermissionsToSecrets get

 if ($webappName -and $webAppCustomHostname -and $existingVaultName -and $certName) 
 {Write-Host "Attempting to enable SSL Binding for $($webappName) on the hostname 
 $($webAppCustomHostname) using cert $($certName) from the existing keyvault of 
 $($existingVaultName)." -Verbose
 Enable-SslStateOnWebapp -WebappName $webappName -customWebappHostname 
 $webAppCustomHostname -existingKeyvaultName $existingVaultName - 
 existingKeyvaultCertName $certName -Verbose}
 else {Write-Host "Insufficient parameters have been provided to complete SSL 
 Binding. To enable SSL binding, please provide a custom hostname, an existing 
 keyvault where your certificate is stored, and the name of your certificate. 
 Please visit the readme for more information." -Verbose}

 Write-Host "Removing SPN access to $($existingVaultName)" -Verbose
 Remove-AzureRmKeyVaultAccessPolicy -VaultName $existingVaultName - 
 ServicePrincipalName <spnClientId>
 preferredAzurePowerShellVersion: '6.13.1'

This resolved my issue completely.