Understanding $args in PowerShell
-
I'm helping someone with this and thought that I would post something here as it is easier to format and reference.
$args is an array of the arguments that are passed into the script at the time that it is run. When running a script from the command line it is common to want to gather some information from the user who is running the script. Of course we could do this interactively by asking questions of the user after they run the script, but that can get very annoying very quickly if the end user uses the script with any frequency or if it needs to be a part of some other automation.
Rather we accept a set of arguments at the time that it is run. This is extremely common and anyone working at the command prompt will be doing this all of the time. You do this with built-in Windows commands all of the time. Here is an example:
copy file1 c:\dir\temp\
Copy here takes two arguments. The file that you want to copy and the location to which you want to copy it. There is no reason not to do this with your own scripts.
Each of the arguments that are passed into your script go into the $args array. Like any array, we can reference the first argument as $args[0], the second as $args[1], the third as $args[2] and so forth for as many as we receive.
I will provide a very simplistic example.
-
Here is a one line program. Save it as hello.ps1 and run it from a command prompt. Here is the program.
write-host "Hello" $args[0]
Here is how to run it...
.\hello.ps1 Scott
Output:
Hello Scott
-
<sigh> Oh, the poor poor puppies....
-
Ok, still finding this a bit difficult. I thought the $args was created automatically so is it necessary to include the $args[0] as in the example?
-
@chutestrate said:
Ok, still finding this a bit difficult. I thought the $args was created automatically so is it necessary to include the $args[0] as in the example?
$args is created when the user, not the programmer, passes arguments to the script. In my example the argument was my name, Scott, which I passed in the line when I ran the program.
To use the argument that I passed in, the program has to reference it. The only way to reference it in the script is to use $args[0] which is a reference to the first argument passed. If you don't use $args[0] the argument will be ignored as nothing in the script looks for it.
-
@scottalanmiller said:
To use the argument that I passed in, the program has to reference it. The only way to reference it in the script is to use $args[0] which is a reference to the first argument passed. If you don't use $args[0] the argument will be ignored as nothing in the script looks for it.
That's not accurate, actually. PowerShell very much will try to display it as best it can. So if you do:
.\test.ps1 Scott
And your script is
Write-Host "Hi " $Args
It'll work just fine. If you run it: .\test.ps1 Scott,Martin you'll get:
Hi Scott Martin
Notice no comma, PowerShell is just squashing the array together. Change the script to:
Write-Host "Hi " $Args[1] " and " $Args[0]"
And run it: .\test.ps1 Scott,Martin and you'll get:
Hi Martin and Scott
-
Let's try another program with arguments. This time we will make the program just a little bit longer:
foreach ($argument in $args) { write-host $argument }
Run it like this (assuming that you also save it as argtest.ps1)...
.\argtest.ps1 this is a test
And it prints out...
this is a test
-
Well, I"m just not going to get this easily. I'm getting singular concepts but it's not flowing together cohesively.
-
@Martin9700 ah yes, you can reference the array itself as a whole rather than the individual elements. Makes sense.
-
@chutestrate said:
Well, I"m just not going to get this easily. I'm getting singular concepts but it's not flowing together cohesively.
It's important to remember though, in PowerShell no one uses $Args. We use named Parameters, just so we can avoid the confusion of $Args. Also makes the script easier to read:
Param( [string]$First, [string]$Second ) Write "Hi $First and $Second"
-
@chutestrate said:
Well, I"m just not going to get this easily. I'm getting singular concepts but it's not flowing together cohesively.
Try actually running the script that I just made where it takes an unlimited number of arguments, stores them in the $args array and prints them out one at a time. Play with that for a minute actually running it with different arguments passed it. I think that it will help once you see it a few times.
-
@Martin9700 that makes learning it so much harder though. If a single array is confusing, doing that makes it even more abstract.
-
which script the args or param
-
@scottalanmiller said:
@Martin9700 that makes learning it so much harder though. If a single array is confusing, doing that makes it even more abstract.
Then using named parameters? I don't see how that's more confusing then some nameless value you HOPE is right. In this example you have two ways you could run the script:
.\test.ps1 Scott Martin
or
.\test.ps1 -First Scott -Second Martin
Notice in the second example the script is now resembling a proper cmdlet.
-
And once you get into named parameters, you can start using the parameter decorators:
Param ( [ValidateSet("Martin","Scott")] [string]$First, [ValidateSet("Martin","Chutestrate")] [string]$Second ) Write-Host "Hi $First and $Second!"
Try .\test.ps1 -First Rob -Second Scott
-
@chutestrate said:
which script the args or param
Using param to abstract args is going to make learning what an array is less simple.
-
@Martin9700 said:
@scottalanmiller said:
@Martin9700 that makes learning it so much harder though. If a single array is confusing, doing that makes it even more abstract.
Then using named parameters? I don't see how that's more confusing then some nameless value you HOPE is right. In this example you have two ways you could run the script:
.\test.ps1 Scott Martin
or
.\test.ps1 -First Scott -Second Martin
Notice in the second example the script is now resembling a proper cmdlet.
That's much more complex because you are using a more complex structure where you now have to have names. It is easier to use when you are dealing with arbitrary inputs, but that isn't the goal here. John is trying to understand what an argument is and what an array is.
-
@scottalanmiller said:
@chutestrate said:
which script the args or param
Using param to abstract args is going to make learning what an array is less simple.
OK, now I see where you're going with this. I suppose that's an argument, but in my view you should know what an array is and how to manipulate it before you start messing with $Args. Otherwise your picking a tough path to walk. Besides, learning best practices early instead of breaking bad habits later.
-
Sorry martin9700 I'm not even close to understanding what you are trying demonstrate.
-
Here is a slightly more complex example but it gives more illustrative output.
for ($i=0; $i -lt $args.length; $i++) { 'This is $args[' + $i + "], which is: " + $args[$i] }
Save and run with any number of arguments that you want.
> .\argsdemo.ps1 I can put in a lot of arguments and it works just fine for a demo. This is $args[0], which is: I This is $args[1], which is: can This is $args[2], which is: put This is $args[3], which is: in This is $args[4], which is: a This is $args[5], which is: lot This is $args[6], which is: of This is $args[7], which is: arguments This is $args[8], which is: and This is $args[9], which is: it This is $args[10], which is: works This is $args[11], which is: just This is $args[12], which is: fine This is $args[13], which is: for This is $args[14], which is: a This is $args[15], which is: demo.