rmbolger / Posh-ACME

PowerShell module and ACME client to create certificates from Let's Encrypt (or other ACME CA)
https://poshac.me/docs/latest/
MIT License
756 stars 186 forks source link

Submit-ChallengeValidation - Parameter set cannot be resolved #399

Closed StuHare closed 2 years ago

StuHare commented 2 years ago

Hi

Has anyone come across an issue where the Submit-ChallengeValidation function fails with the following error?

Submit-ChallengeValidation: /home/vsts/.local/share/powershell/Modules/Posh-ACME/4.10.0/Public/New-PACertificate.ps1:238
Line |
 238 |          Submit-ChallengeValidation
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Parameter set cannot be resolved using the specified named
     | parameters. One or more parameters issued cannot be used
     | together or an insufficient number of parameters were provided.

##[error]PowerShell exited with code '1'.

This is running via Azure DevOps using an Ubuntu host VM, so access to the PoshACME agents and scripts are limited at this time.

This function is only using the PAOrder Parameter, the output of which looks fine.

What I cant tell is what parameter/s its referring to.

Continuing to investigate but any suggestions welcome.

image

rmbolger commented 2 years ago

Hey @StuHare. Thanks for reaching out. This sounds similar to an issue that existed a while back related to parameter binding conflicts in a plugin. Based on your log, it looks like you're using a custom plugin called CscDns. Can you share the parameter block from the Add-Txt function in that custom plugin and an example of the PluginArgs hashtable that would be sent with the New-PACertificate command?

StuHare commented 2 years ago

Hi @rmbolger, I thought exactly the same myself, so i added some write-debug output for all the passed parameter variables in the plugin, to check their contents, but it doesnt even get that far.

I had the Plugin working fine standalone outside of DevOps and PoshAcme, which led me to question whether the parameters were being passed correctly. From what i can see from the other debug output, it seems to suggest they are, but not 100%.

In terms of args I only really need ZoneName ApiKey and ApiToken for the plugin, but i have tried a few different combinations (with and without the others) receiving the same result.

Plugin Arguments

$paPluginArgs = @{
    AZSubscriptionId = $azureContext.Subscription.Id;
    AZAccessToken    = $azureAccessToken;
    CscApiKey        = $CscApiKey;
    CscApiToken      = $CscApiToken;
    CscZoneName      = $CscZoneName
}
Write-debug "** Requesting new certificate using CSC DNS Plugin **"
New-PACertificate -Domain $CertificateNamesArr -DnsPlugin CscDns -PluginArgs $paPluginArgs

Parameter Block

function Add-DnsTxt {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,Position=0)]
        [string]$RecordName,
        [Parameter(Mandatory,Position=1)]
        [string]$TxtValue,
        [Parameter(ParameterSetName='CscApiKey',Mandatory)]
        [string]$CscApiKey,
        [Parameter(ParameterSetName='CscApiToken',Mandatory)]
        [string]$CscApiToken,
    [Parameter(ParameterSetName='CscZoneName')]
        [string]$CscZoneName,
    [Parameter(ParameterSetName='AZAccessToken')]
        [string]$AZAccessToken,
    [Parameter(ParameterSetName='AZSubscriptionId')]
        [string]$AZSubscriptionId,
        <#
        Add plugin specific parameters here. Make sure their names are
        unique across all existing plugins. But make sure common ones
        across this plugin are the same.
        #>
        [Parameter(ValueFromRemainingArguments)]
        $ExtraParams
    )

Once I have tested this I will need to make the token parameters secure strings.

The PluginArgs look ok.

image

The parameters seem to get set without error.

DEBUG: Attempting to load plugin CscDns
DEBUG: Adding new value for CscZoneName
DEBUG: Adding new value for CscApiKey
DEBUG: Adding new value for AZSubscriptionId
DEBUG: Adding new value for AZAccessToken
DEBUG: Adding new value for CscApiToken
rmbolger commented 2 years ago

I think I see the problem. Each of the parameters in that param block has a unique ParameterSetName value which is telling PowerShell that they basically can't be used together in the same call. So it can't decide which parameter set to bind when you send all of them at once.

Try removing the ParameterSetName='blah' from each one so there's only a single, default parameter set. Make sure you make the changes in the param block for Remove-DnsTxt (and Save-DnsTxt if it has any). Here's what the resulting param block should probably look like:

    param(
        [Parameter(Mandatory,Position=0)]
        [string]$RecordName,
        [Parameter(Mandatory,Position=1)]
        [string]$TxtValue,
        [Parameter(Mandatory)]
        [string]$CscApiKey,
        [Parameter(Mandatory)]
        [string]$CscApiToken,
        [string]$CscZoneName,
        [string]$AZAccessToken,
        [string]$AZSubscriptionId,
        [Parameter(ValueFromRemainingArguments)]
        $ExtraParams
    )
StuHare commented 2 years ago

Thanks @rmbolger that was definitely part of the problem and a misunderstanding on my part on how the Parameter sets worked.

The Find Zone function also had similar issues and was resolved by setting the positions - errors with parameter null values were firing.

if (-not ($zoneID = Find-CSCZone $RecordName $CscZoneName $CscApiKey $CscApiToken)) {
        throw "Unable to find hosted zone for $CscZoneName"
    }

function Find-CSCZone {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,Position=0)]
        [string]$RecordName,
        [Parameter(Mandatory,Position=1)]
        [string]$CscZoneName,
        [Parameter(Mandatory,Position=2)]
        [string]$CscApiKey,
        [Parameter(Mandatory,Position=3)]
        [string]$CscApiToken,
        <#
        Add plugin specific parameters here. Make sure their names are
        unique across all existing plugins. But make sure common ones
        across this plugin are the same.
        #>
        [Parameter(ValueFromRemainingArguments)]
        $ExtraParams
    )
# Null Message parameter
Submit-ChallengeValidation: /home/vsts/.local/share/powershell/Modules/Posh-ACME/4.10.0/Public/New-PACertificate.ps1:238
Line |
 238 |          Submit-ChallengeValidation
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot bind argument to parameter 'Message' because it is null.

Next issue: Currently troubleshooting the Remove-DnsTxt function (it has identical parameters defined to Add-DnsTxt & works successfully) which is failing to find the CscApiKey CscApiToken parameters. Write-debug output shows they are set.

# Failure

DEBUG: *** Remove-DnsTxt Function *** 
Remove-DnsTxt: /home/vsts/.local/share/powershell/Modules/Posh-ACME/4.10.0/Public/Unpublish-Challenge.ps1:48
Line |
  48 |          Remove-DnsTxt -RecordName $recordName -TxtValue $txtValue @Pl …
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot process command because of one or more missing
     | mandatory parameters: CscApiKey CscApiToken.

##[error]PowerShell exited with code '1'.

# Call to remove dns record

Remove-DnsTxt -RecordName $recordName -TxtValue $txtValue @PluginArgs

#Param block for Add-DnsTxt and Remove-DnsTxt - works for add fails to remove.

param(
        [Parameter(Mandatory,Position=0)]
        [string]$RecordName,
        [Parameter(Mandatory,Position=1)]
        [string]$TxtValue,
        [Parameter(Mandatory)]
        [string]$CscApiKey,
        [string]$CscApiToken,
        [string]$CscZoneName,
        <#
        Add plugin specific parameters here. Make sure their names are
        unique across all existing plugins. But make sure common ones
        across this plugin are the same.
        #>
        [Parameter(ValueFromRemainingArguments)]
        $ExtraParams
    )
rmbolger commented 2 years ago

Based on the error, PowerShell still thinks both CscApiKey and CscApiToken are mandatory. But the updated param block you posted makes it look like only CscApiKey is mandatory....which doesn't really make sense. Is there a dependent helper function that still has CscApiToken as mandatory?

Also, you had originally said both params were supposed to be mandatory, right? So is the updated param block wrong?

StuHare commented 2 years ago

Another layer 8 problem I think :) - although the params were defined they were not being passed to the Find-CSCZone function. Just running a retest now to confirm.

Good point on the mandatory parameters i'll update those too.

StuHare commented 2 years ago

Pipeline and its scripts now successfully run via DevOps. Certificate has not been imported into the key vault but thats for tomorrow. :)

Many thanks for the help @rmbolger much appreciated.

Once i have cleaned up the script, would you like me to send over the DNS plugin for CSC Global API for review?

rmbolger commented 2 years ago

Happy to help! Glad you got it sorted. And sure, I'd love to take a look at the CSC script. I actually have a client using CSC that I could even probably test it against.