How do I have an array parameter that takes input from the args or the pipeline in Powershell?

Use the automatic variable $input.

If only pipeline input is expected then:

function my-function {
    $arg = @($input)
    $arg
}

But I often use this combined approach (a function that accepts input both as an argument or via pipeline):

function my-function {
    param([string[]]$arg)

    # if $arg is $null assume data are piped
    if ($null -eq $arg) {
        $arg = @($input)
    }

    $arg
}


# test
my-function 1,2,3,4
1,2,3,4 | my-function

Here's another example using Powershell 2.0+

This example is if the parameter is not required:

function my-function {
  [cmdletbinding()]
  Param(
    [Parameter(ValueFromPipeline=$True)]
    [string[]]$Names
  )

  End {
    # Verify pipe by Counting input
    $list = @($input)
    $Names = if($list.Count) { $list } 
      elseif(!$Names) { @(<InsertDefaultValueHere>) } 
      else { @($Names) }

    $Names -join ':'
  }
}

There's one case where it would error out without the 'elseif'. If no value was supplied for Names, then $Names variable will not exist and there'd be problems. See this link for explanation.

If it is required, then it doesn't have to be as complicated.

function my-function {
  [cmdletbinding()]
  Param(
    [Parameter(Mandatory=$true,ValueFromPipeline=$True)]
    [string[]]$Names
  )

  End {
    # Verify pipe by Counting input
    $list = @($input)
    if($list.Count) { $Names = $list } 

    $Names -join ':'
  }
}

It works, exactly as expected and I now I always reference that link when writing my Piped Functions.