How to pass command-line arguments to a PowerShell ps1 file

For years, I have used the cmd/DOS/Windows shell and passed command-line arguments to batch files. For example, I have a file, zuzu.bat and in it, I access %1, %2, etc. Now, I want to do the same when I call a PowerShell script when I am in a Cmd.exe shell. I have a script, xuxu.ps1 (and I've added PS1 to my PATHEXT variable and associated PS1 files with PowerShell). But no matter what I do, I seem unable to get anything from the $args variable. It always has length 0.

If I am in a PowerShell shell, instead of cmd.exe, it works (of course). But I'm not yet comfortable enough to live in the PowerShell environment full time. I don't want to type powershell.exe -command xuxu.ps1 p1 p2 p3 p4. I want to type xuxu p1 p2 p3 p4.

Is this possible, and if so, how?

The sample I cannot get to work is trivial, foo.ps1:

Write-Host "Num Args:" $args.Length;
foreach ($arg in $args) {
    Write-Host "Arg: $arg";
}

The results are always like this:

C:\temp> foo
Num Args: 0
C:\temp> foo a b c d
Num Args: 0
c:\temp>

Upvotes: 120

Views: 394015

Answers (8)

V.B
V.B

Reputation: 1211

You could declare your parameters in the file, like param:

[string]$param1
[string]$param2

And then call the PowerShell file like so .\temp.ps1 param1 param2....param10, etc.

(For more information, see here, e.g.: https://www.red-gate.com/simple-talk/sysadmin/powershell/how-to-use-parameters-in-powershell/#heading-1)

Upvotes: 15

Youssef
Youssef

Reputation: 181

I wanted to automate the "Unblocking" of files downloaded from the internet in Windows, so I got my .ps1 file working, but when I wanted to make it as a "right-click" menu option, it never worked despite trying all possible combinations (passing params to cmd alone, then to powershell alone and to ps1, using single/double quotes, etc) !

After struggling for some hours, I was able to make it work by using both cmd and powershell in the same command like this :

cmd.exe /c start powershell "C:\folder\script.ps1 -folder '%1'"

where folder is a parameter referring to the right-clicked folder, and here is the ps1 file if someone is interested :

param (
    [string]$folder = "$env:userprofile\Downloads"
    #defaults to the current user Downloads folder
)
# Remove Recurse if you don't want to unblock inner folders
get-childitem "$folder" -Recurse | unblock-file

You can then make a .reg file to add this as a right-click option to unblock all files at once :

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\UnblockDL]
@="Unblock DL Files"

[HKEY_CLASSES_ROOT\Directory\shell\UnblockDL\command]
@="cmd.exe /c start powershell \"C:\\folder\\script.ps1 -folder '%1'\""

Remember to adjust "C:\folder\script.ps1" to your own ps1 file, and make sure its name/path don't contain any spaces (don't ask me why !).

Upvotes: 0

Atiq Rahman
Atiq Rahman

Reputation: 678

You may not get "xuxu p1 p2 p3 p4" as it seems. But when you are in PowerShell and you set

PS > Set-ExecutionPolicy Unrestricted -Scope CurrentUser

You can run those scripts like this:

./xuxu p1 p2 p3 p4

or

.\xuxu p1 p2 p3 p4

or

./xuxu.ps1 p1 p2 p3 p4

I hope that makes you a bit more comfortable with PowerShell.

Upvotes: 1

ta32
ta32

Reputation: 148

if you want to invoke ps1 scripts from cmd and pass arguments without invoking the script like

powershell.exe script.ps1 -c test
script -c test ( wont work )

you can do the following

setx PATHEXT "%PATHEXT%;.PS1;" /m
assoc .ps1=Microsoft.PowerShellScript.1
ftype Microsoft.PowerShellScript.1=powershell.exe "%1" %*

This is assuming powershell.exe is in your path

https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/ftype

Upvotes: 1

Arj
Arj

Reputation: 2046

This article helps. In particular, this section:

-File

Runs the specified script in the local scope ("dot-sourced"), so that the functions and variables that the script creates are available in the current session. Enter the script file path and any parameters. File must be the last parameter in the command, because all characters typed after the File parameter name are interpreted as the script file path followed by the script parameters.

i.e.

powershell.exe -File "C:\myfile.ps1" arg1 arg2 arg3

means run the file myfile.ps1 and arg1 arg2 & arg3 are the parameters for the PowerShell script.

Upvotes: 51

Randall Borck
Randall Borck

Reputation: 854

After digging through the PowerShell documentation, I discovered some useful information about this issue. You can't use the $args if you used the param(...) at the beginning of your file; instead you will need to use $PSBoundParameters. I copy/pasted your code into a PowerShell script, and it worked as you'd expect in PowerShell version 2 (I am not sure what version you were on when you ran into this issue).

If you are using $PSBoundParameters (and this ONLY works if you are using param(...) at the beginning of your script), then it is not an array, it is a hash table, so you will need to reference it using the key / value pair.

param($p1, $p2, $p3, $p4)
$Script:args=""
write-host "Num Args: " $PSBoundParameters.Keys.Count
foreach ($key in $PSBoundParameters.keys) {
    $Script:args+= "`$$key=" + $PSBoundParameters["$key"] + "  "
}
write-host $Script:args

And when called with...

PS> ./foo.ps1 a b c d

The result is...

Num Args:  4
$p1=a  $p2=b  $p3=c  $p4=d

Upvotes: 31

guillermooo
guillermooo

Reputation: 8115

Maybe you can wrap the PowerShell invocation in a .bat file like so:

rem ps.bat
@echo off
powershell.exe -command "%*"

If you then placed this file under a folder in your PATH, you could call PowerShell scripts like this:

ps foo 1 2 3

Quoting can get a little messy, though:

ps write-host """hello from cmd!""" -foregroundcolor green

Upvotes: 6

EBGreen
EBGreen

Reputation: 37710

OK, so first this is breaking a basic security feature in PowerShell. With that understanding, here is how you can do it:

  1. Open an Windows Explorer window
  2. Menu Tools -> Folder Options -> tab File Types
  3. Find the PS1 file type and click the advanced button
  4. Click the New button
  5. For Action put: Open
  6. For the Application put: "C:\WINNT\system32\WindowsPowerShell\v1.0\powershell.exe" "-file" "%1" %*

You may want to put a -NoProfile argument in there too depending on what your profile does.

Upvotes: 19

Related Questions