Search code examples
powershelluriids

PS function to populate IDs to URI


I have the following string

$list = @("123","456","789")
$template = "https://mysite.test/api/v1/policy/{id}/version/{id}/example"

I am working on a function to meet the following requirements :

  • replaces each {id} in the order provided by an array ($list)
  • If the array list contains exactly one more item than the count of {id} append the last id at the end of the $string (in this example, array contains 3 items, string will be appended by /789)
  • accepts an array of $ids but fails if array list does not match list of {id} or list of array +1 (for the above append scenario)

The issue is that every {id} is replaced by the first item from my list, as shown below

if ($template.Contains('{id}')) {
    foreach ($id in $list ) {
        $template = $template -replace '{id}', $id 
    }
}

$string
https://mysite.test/api/v1/policy/123/version/123/example

Expected values

  • array with 2 values

      https://mysite.test/api/v1/policy/123/version/456/example
    
  • array with 3 values

      https://mysite.test/api/v1/policy/123/version/456/example/789
    

Solution

  • The easiest option is to use format string instead of {id} for interpolating the values:

    $template = 'https://mysite.test/api/v1/policy/{0}/version/{1}/example{2}'
    $list = @('123', '456', '789')
    
    if ($list.Count -lt 3) {
        $list += $null
    }
    else {
        $list[2] = '/' + $list[2] # prepend `/` to the last item
    }
    
    $template -f $list
    

    If you must use {id} then, perhaps using regex replacement with a match evaluator or replacement with a scriptblock work for this use case. Basically, in the evaluator you can increment an index for each pattern match and get the next replacement value in $list.

    It would look something like this for PowerShell 5.1:

    $template = 'https://mysite.test/api/v1/policy/{id}/version/{id}/example'
    $list = @('123', '456', '789')
    $idx = @(0)
    
    [regex]::Replace($template, '{id}|$', {
        # if there is a "next value" in the list
        if ($next = $list[$idx[0]++]) {
            # if matching EOL
            if (-not $args[0].Value) {
                return '/' + $next
            }
            # else
            $next
        }
    })
    

    And like this for PowerShell 7+:

    $template = 'https://mysite.test/api/v1/policy/{id}/version/{id}/example'
    $list = @('123', '456', '789')
    $idx = @(0)
    
    $template -replace '{id}|$', {
        # if there is a "next value" in the list
        if ($next = $list[$idx[0]++]) {
            # if matching EOL
            if (-not $_.Value) {
                return '/' + $next
            }
            # else
            $next
        }
    }