Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

I need to process an SVN working copy in a PS script, but I have trouble passing arguments to functions. Here's what I have:

function foo($arg1, $arg2)
{
  echo $arg1
  echo $arg2.FullName
}

echo "0: $($args[0])"
echo "1: $($args[1])"
$items = get-childitem $args[1] 
$items | foreach-object -process {foo $args[0] $_}

I want to pass $arg[0] as $arg1 to foo, and $arg[1] as $arg2. However, it doesn't work, for some reason $arg1 is always empty:

PS C:\Users\sbi> .\test.ps1 blah .\Dropbox
0: blah
1: .\Dropbox
C:\Users\sbi\Dropbox\Photos
C:\Users\sbi\Dropbox\Public
C:\Users\sbi\Dropbox\sbi
PS C:\Users\sbi>

Note: The "blah"parameter isn't passed as $arg1.

I am absolutely sure this is something hilariously simple (I only just started with doing PS and still feel very clumsy), but I have banged my head against this for more than an hour now, and I can't find anything.

share|improve this question

3 Answers 3

up vote 1 down vote accepted

The $arg[] array appears to lose scope inside the ForEach-Object.

function foo($arg1, $arg2)
{
  echo $arg1
  echo $arg2.FullName
}

echo "0: $($args[0])"
echo "1: $($args[1])"
$zero = $args[0]
$one = $args[1]
$items = get-childitem $args[1] 
$items | foreach-object {
    echo "inner 0: $($zero)"
    echo "inner 1: $($one)"
}
share|improve this answer
    
I could accept any of the three answers I got so far, but I'll pick this one, because this shows what I ended up doing. –  sbi Jul 7 '12 at 13:20

The reason that $args[0] is not returning anything in the foreach-object is that $args is an automatic variable that takes unnamed, unmatched parameters to a command and the foreach-object is a new command. There aren't any unmatched parameters for the process block, so $args[0] is null.

One thing that can help is that your scripts can have parameters, just like functions.

param ($SomeText, $SomePath)
function foo($arg1, $arg2)
{
  echo $arg1
  echo $arg2.FullName
}

echo "0: $SomeText"
echo "1: $SomePath"
$items = get-childitem $SomePath
$items | foreach-object -process {foo $SomeText $_}

As you start to want more functionality from your parameters, you might want to check out a blog post I wrote on the progression of parameters from $args to the current advanced parameters we can use now.

share|improve this answer
    
Blah. Reasons like this are why I avoid built-ins like Foreach-Object in favor of using the good ol' raw foreach looping construct. –  Trevor Sullivan Jul 6 '12 at 19:32
    
Ah, Ok. This I understand now. Damn, that seems quite counterintuitive, though! –  sbi Jul 6 '12 at 19:38

Try something like this:

# Use an advanced function
function foo
{
  [CmdletBinding()]
  param (
      [string] $arg1
    , [string] $arg2
  )

  Write-Host -Object $arg1;
  Write-Host -Object $arg2;
}

# Create array of "args" to emulate passing them in from command line.
$args = @('blah', 'c:\test');

echo "0: $($args[0])"
echo "1: $($args[1])"

# Force items to be returned as an array, in case there's only 1 item returned
$items = @(Get-ChildItem -Path $args[1]);
Write-Host -Object "There are $($items.Count) in `$items";

# Iterate over items found in directory
foreach ($item in $items) {
    foo -Arg1 $args[0] -Arg2 $item.FullName
}
share|improve this answer
    
That "force items to be returned as an array" is something I should indeed add. Thanks for the hint! –  sbi Jul 6 '12 at 19:39
    
Yeah, gotta be careful if you only get a single item back -- by casting it explicitly as an array, you get consistent results, so you can iterate over it using foreach. –  Trevor Sullivan Jul 6 '12 at 19:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.