2023-05-24

PowerShell | How to cross-reference parameters between 2 argument completers?

My PowerShell module has 2 argument completers. The 2 parameters with argument completers are related to each other in a way that by calculating the value of one of them, we can get the value of the other one.

I want to use this relation to make sure when both of those parameters are being used, they only suggest unique values.

Remove-WDACConfig -UnsignedOrSupplemental -PolicyIDs a244370e-44c9-4c06-b551-f6016e563076,d3645984-47a0-4c8e-be75-1c06840e13e6,38734d8a-4bc4-4dd3-b23f-57f536814426,e63679a6-ae84-4d27-b842-258217562941 -PolicyNames 'Microsoft Windows Driver Policy - Enforced','Supplemental Policy 1 - 05-16-2023','Supplemental Policy 2 - 05-16-2023','Allow Microsoft Plus Block Rules - 05-16-2023'

As you can see in the command above, there are 4 policies deployed. I selected 4 of them by their IDs and then selected the same 4 with their names. Running that command throws an error for the next 4 since PowerShell can't find them anymore when they are already removed by IDs.

I want to change the argument completers so that when I specify say 2 of them by name, the ID of those 2 shouldn't appear when argument completing the IDs.

The values are Code Integrity policy IDs and names. This is related to a previous question.

I did try to modify it but couldn't get it to work exactly the way I want.

[ArgumentCompleter({
        param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
        $candidates = [PolicyIDz]::new().GetValidValues() | ForEach-Object { if ($_ -notin $fakeBoundParameters) { $_ } }
        $existing = $commandAst.FindAll({ 
                $args[0] -is [System.Management.Automation.Language.StringConstantExpressionAst]
            }, 
            $false
        ).Value
        #$existing = $existing | ForEach-Object { if ($_ -notin $fakeBoundParameters) { $_ } }
        Compare-Object -PassThru $candidates $existing | Where-Object SideIndicator -eq '<='
    })]
[ValidateScript({
        if ($_ -notin [PolicyIDz]::new().GetValidValues()) { throw "Invalid policy ID: $_" }
        $true
    })]
[Parameter(Mandatory = $false, ParameterSetName = "Unsigned Or Supplemental")]
[System.String[]]$PolicyIDs,


[ArgumentCompleter({
        param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
        $candidates = [PolicyNamez]::new().GetValidValues() | ForEach-Object { $CurrentActiveLoop = $_; if ((((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_.FriendlyName -eq $CurrentActiveLoop }).PolicyID) -notin $fakeBoundParameters) { $_ } }
        $existing = $commandAst.FindAll({ 
                $args[0] -is [System.Management.Automation.Language.StringConstantExpressionAst]
            }, 
            $false
        ).Value  
        # $existing = $existing | ForEach-Object { $CurrentActiveLoop = $_; if ((((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_.FriendlyName -eq $CurrentActiveLoop }).PolicyID) -notin $fakeBoundParameters) { $_ } }
          (Compare-Object -PassThru $candidates $existing | Where-Object SideIndicator -eq '<=').
        ForEach({ if ($_ -match ' ') { "'{0}'" -f $_ } else { $_ } })
    })]
[ValidateScript({
        if ($_ -notin [PolicyNamez]::new().GetValidValues()) { throw "Invalid policy name: $_" }
        $true
    })]
[Parameter(Mandatory = $false, ParameterSetName = "Unsigned Or Supplemental")]
[System.String[]]$PolicyNames,

My goal was to cross-refence all of the values stored in the $fakeBoundParameters by policy ID. I'm not sure what I'm missing.

They use class based ValidateSets too

# argument tab auto-completion and ValidateSet for Policy names 
        Class PolicyNamez : System.Management.Automation.IValidateSetValuesGenerator {
            [System.String[]] GetValidValues() {
                $PolicyNamez = ((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_.IsOnDisk -eq "True" } | Where-Object { $_.IsSystemPolicy -ne "True" }).Friendlyname | Select-Object -Unique
   
                return [System.String[]]$PolicyNamez
            }
        }

        # argument tab auto-completion and ValidateSet for Policy IDs     
        Class PolicyIDz : System.Management.Automation.IValidateSetValuesGenerator {
            [System.String[]] GetValidValues() {
                $PolicyIDz = ((CiTool -lp -json | ConvertFrom-Json).Policies | Where-Object { $_.IsOnDisk -eq "True" } | Where-Object { $_.IsSystemPolicy -ne "True" }).policyID
   
                return [System.String[]]$PolicyIDz
            }
        }    
    }



No comments:

Post a Comment