$($args[2]) is not printing argument passed - powershell

I have a batch file (runPowerShell.bat) with the following line:
Powershell.exe -ExecutionPolicy ByPass -File %psFile% %2 %3 %4 %5
%1 is psFile in which the powershell file is passed in
%2 is another argument i intend to pass later
%3 is the arg i wanna print for now
The powershell file (scriptWrapper.ps1) contains this:
param($App_input)
$Script = "$($args[2])" #%2 for process or sync
write-host $Script
There is another PowerShell file called
Process.ps1
that i wish to pass as %3 argument, meaning $args[2]
if i say write-host "$args[2]" it prints like this:
Process.ps1[2]
so it kinda works but i dont want the positional parameter with it, so I followed this thread for guidance, and the solution ($($args[2])) makes sense, but I am unsure why its not working for me
accessing the $args array in powershell
it prints nothing:

I figured out why...
so apparently, args does not bode well with param().
I had param($App_input) that takes %1 for an app input first before the Process.ps1 input for %2. and since param() has to be defined at the top of the script, it seems to have an unfriendly effect with args.
WHen i commented out param(), $($args[1]) printed out fine
however, instead of args, i should have just easily added $Script in param
param($App_input, $Script)
much better now

Related

Is there a dynamic variable for passed arguments in powershell?

In batch, passed arguments can be used with %1, and onward counting.
Lets say I have the following "batch.bat" script:
# echo off
echo %1
pause>nul
If i call this from cmd like: call batch.bat hello it would output "hello" in the console.
Is there any variable in ps which does the same thing?
EDIT
I've found the folliwing, but it seems kind of unnatural.
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
Is there something more elegant perhaps?
PowerShell has an automatic variable $args that stores all arguments passed to a script (unless parameters were defined for the script). The individual arguments can be accessed by index ($args[0] for the first argument, $args[1] for the second, etc.).
However, in general it's advisable to define parameters to control what arguments a script should accept, e.g.
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[string]$First,
[Parameter(Mandatory=$false)]
[integer]$Second = 42
)
There are numerous advantages to this, including (but not limited to):
arguments are parsed automatically and the values are stored in the respective variables
scripts automatically prompt for mandatory parameters
scripts throw an error if incorrect arguments are passed
you can define default values for optional parameters
you can have your script or function accept pipeline input
you can validate parameter values
you can use comment-based help for documenting the parameters and their usage

How do I pass second parameter from CMD (%2) into a PowerShell variable

I have a file called test.bat.
It contains a call to a PowerShell script (Process.ps1) as follows:
Powershell.exe -File %1
where %1 is the name of the PowerShell file I would pass on the command line.
So essentially, it looks like this on the command line:
e:> test.bat Process.ps1
Right now the script runs as it should. However, I need to pass a second argument (%2) in the batch file (test.bat) so it would look like this:
Powershell.exe -File %1 %2
%1 is Process.ps1
%2 will be some cube name (i.e. CUBE1)
So on CMD it would look like this eventually:
e:> test.bat Process.ps1 CUBE1
Now, how can I pass that second argument (CUBE1) into a variable ($CUBE) declared in the PowerShell script (Process.ps1)?
I researched around the forums, but I can't find an example like my own case.
This may be something very simple I'm missing out on, but I am new to PowerShell/batch scripting so I can't quite put my finger on the answer.
There are two ways. The first is the use of the Parameter declarations:
Param(
[Parameter(mandatory)]
[String]
$first,
[Parameter(mandatory)]
[String]
$second
)
Write-Output "First argument: " $first
Write-Output "First argument: " $second
The second is the built-in $args variable:
Write-Output "First argument: " $args[0]
Write-Output "Second argument: " $args[1]

Calling a powershell function using a .bat file

I would like to know how to call a powershell function using a .Bat file.
I have this simple function:
(Script.ps1)
function testfunction
{
Write-Log "Calling from Bat file"
}
and I would like to call the function testfunction within the .Bat File.
powershell .\Script.ps1 ...
I noticed that there is a switch -ExecutionPolicy ByPass which allows the batch file to run using Powershell. This works here, taken from the answer by vonPryz.
#echo off
:: Create a test script file
echo function test { write-host "Called from %~f0" } > s.ps1
powershell -ExecutionPolicy ByPass -command ". "%cd%\s.ps1"; test;"
del s.ps1
pause
Start Powershell with -command switch, include the script and call the function. You need to dot source the script before its function can be called.
:: Create a test script file
C:\temp>echo function test { write-host "Called from .bat" } > c:\temp\s.ps1
C:\temp>powershell -command ". c:\temp\s.ps1; test;"
:: Output
Called from .bat
Also, take a look at some samples.
I know this is very old but I was recently trying to do this same thing and it took me a long time to find out what to do. The answer is amazingly simple
In BatchFile (RunMe)
powershell -command ". Script.ps1; Set-SomeFunction %1 %2 %3 %4 %5"
Then you can call the batch like
RunMe -SomeParm val -SomeParm2 val -SomeSwitch -SomeBool $true
also, to run as admin
powershell -command "Start-Process -verb runas powershell" "'-noexit -command ". Script.ps1; Set-SomeFunction %1 %2 %3 %4 %5 %6 %7 %8 %9'"
I usually do it like that:
powershell {Set-ExecutionPolicy unrestricted}
powershell.exe -executionpolicy ByPass ./script/powerhsell-script.ps1 %par1% %par2%
powershell {Set-ExecutionPolicy Restricted}
Hope you need that :)
I've done it using
powershell.exe -ExecutionPolicy Bypass -file ".\Write_date.ps1"
Seems similar to what others have written but I'm not sure what vonPryz meant by needing the dot source the script before calling the script. The above worked on a Win7 with executionpolicy set to restricted.

Pass parameter from a batch file to a PowerShell script

In my batch file, I call the PowerShell script like this:
powershell.exe "& "G:\Karan\PowerShell_Scripts\START_DEV.ps1"
Now, I want to pass a string parameter to START_DEV.ps1. Let's say the parameter is w=Dev.
How can I do this?
Let's say you would like to pass the string Dev as a parameter, from your batch file:
powershell -command "G:\Karan\PowerShell_Scripts\START_DEV.ps1 Dev"
put inside your powershell script head:
$w = $args[0] # $w would be set to "Dev"
This if you want to use the built-in variable $args. Otherwise:
powershell -command "G:\Karan\PowerShell_Scripts\START_DEV.ps1 -Environment \"Dev\""
and inside your powershell script head:
param([string]$Environment)
This if you want a named parameter.
You might also be interested in returning the error level:
powershell -command "G:\Karan\PowerShell_Scripts\START_DEV.ps1 Dev; exit $LASTEXITCODE"
The error level will be available inside the batch file as %errorlevel%.
Assuming your script is something like the below snippet and named testargs.ps1
param ([string]$w)
Write-Output $w
You can call this at the commandline as:
PowerShell.Exe -File C:\scripts\testargs.ps1 "Test String"
This will print "Test String" (w/o quotes) at the console. "Test String" becomes the value of $w in the script.
When a script is loaded, any parameters that are passed are automatically loaded into a special variables $args. You can reference that in your script without first declaring it.
As an example, create a file called test.ps1 and simply have the variable $args on a line by itself. Invoking the script like this, generates the following output:
PowerShell.exe -File test.ps1 a b c "Easy as one, two, three"
a
b
c
Easy as one, two, three
As a general recommendation, when invoking a script by calling PowerShell directly I would suggest using the -File option rather than implicitly invoking it with the & - it can make the command line a bit cleaner, particularly if you need to deal with nested quotes.
Add the parameter declaration at the top of ps1 file
test.ps1
param(
# Our preferred encoding
[parameter(Mandatory=$false)]
[ValidateSet("UTF8","Unicode","UTF7","ASCII","UTF32","BigEndianUnicode")]
[string]$Encoding = "UTF8"
)
write ("Encoding : {0}" -f $Encoding)
Result
C:\temp> .\test.ps1 -Encoding ASCII
Encoding : ASCII
The answer from #Emiliano is excellent. You can also pass named parameters like so:
powershell.exe -Command 'G:\Karan\PowerShell_Scripts\START_DEV.ps1' -NamedParam1 "SomeDataA" -NamedParam2 "SomeData2"
Note the parameters are outside the command call, and you'll use:
[parameter(Mandatory=$false)]
[string]$NamedParam1,
[parameter(Mandatory=$false)]
[string]$NamedParam2

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>
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.
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
OK, so first this is breaking a basic security feature in PowerShell. With that understanding, here is how you can do it:
Open an Windows Explorer window
Menu Tools -> Folder Options -> tab File Types
Find the PS1 file type and click the advanced button
Click the New button
For Action put: Open
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.
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.
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
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
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.