How to Load Function in new Powershell.exe Console - powershell

I have a function (function1) which requires sta mode. I'd like tocall this function from a non sta mode poshconsole. This works when i have function1 in my Profile
$command = "function1 'MyArguments'"
powershell -sta -command $command
But how can i do this when i have the function1 not in the profile and i call
powershell -sta -noprofile -command $command
Can i execute multiple commands with a powershell.exe call? Or can i handover a customprofilepath?

You can separate multiple commands with a semicolon (;) for example, dot source your script containing your function, then call the function:
powershell -sta -noprofile -command ". c:\functions.ps1 ; function1 'MyArguments'"

There are some ways how to deal with STA:
Single Threaded Apartment in PowerShell V1
Asynchronicity in PowerShell
Thread.ApartmentState and PowerShell Execution Thread
In case you will call powershell.exe (because it is obviously easier), you can first load your script with the function and then execute function1 'My arguments'
powershell -sta -noprofile -command '<pathToYourScript>.ps1; function1 args'
I tried to use -file parameter and -command argument together, but that doesn't work.

If you are running the PowerShell Community Extensions you can use Invoke-Apartment e.g.:
PS> Invoke-Apartment -Apartment STA `
-Expr {[Threading.Thread]::CurrentThread.ApartmentState}
STA

Related

Cannot access $Profile.CurrentUserAllHosts using pwsh.exe?

I want to read the automatic variable $profile.CurrentUserAllHosts, using a Deno script.
I already know how to execute pwsh.exe from Deno.
But would like to know how to invoke pwsh.exe to get the $profile.CurrentUserAllHosts value.
For example, I expect that two commands below yields the same results rather than different results:
PS> $profile.CurrentUserAllHosts
C:\Users\Flavio\Documents\PowerShell\profile.ps1
PS> pwsh.exe -noprofile -Command "{$profile.CurrentUserAllHosts}"
C:\Users\Flavio\Documents\PowerShell\Microsoft.PowerShell_profile.ps1.CurrentUserAllHosts
Note: I'm using Powershell 7.2.5, on Windows 10 and I can guarantee that pwsh.exe is the same version for all instances.
There's two things to keep in mind here:
You're running the command in PowerShell itself, so $profile is actually expanded in your parent-session due to the double-quotes in your -Command argument.
You're passing a string with a scriptblock as the -Command argument. It's not actually executed - you're just getting the result of {$profile.CurrentUserAllHosts}.ToString() which is the content of the scriptblock.
Suggestions:
Add a call operator to invoke the scriptblock in the string, ex -Command '& { $profile.CurrentUserAllHosts }'. If invoking pwsh from PowerShell you can also use pwsh.exe -noprofile -Command { $profile.CurrentUserAllHosts }.
Or provide the command as a simple string, ex. -Command '$profile.CurrentUserAllHosts'
In both alternatives, remember single quotes OR escaping the dollar-sign with backtick.

How can I redirect the error stream when calling powershell.exe using -File parameter

I'm executing a powershell script during an OS deployment task sequence using SCCM. Due to idiosyncrasies with this ecosystem I have to call the script with syntax like this (to the best of my experimentation):
powershell.exe -executionpolicy bypass -file "w:\scripts\script.ps1" -param1 "%param1%" -param2 "%param2%"
This works fine, but I wanted to capture the output of this and any error messages it throws. Normally I would do something like:
powershell.exe -executionpolicy bypass -file "w:\scripts\script.ps1" -param1 "%param1%" -param2 "%param2%" > "%logfile" 2>&1
However, per the documentation, the -file parameter must be the last parameter, and the above triggers an error since it's trying to interpret the ">" as a parameter.
Obviously I can't use:
powershell.exe -executionpolicy bypass -file "w:\scripts\script.ps1" -param1 "%param1%" -param2 "%param2%" | out-file "%logfile"
because this is a commandline engine, so even if the pipe wasn't interpreted as a parameter, out-file would be interpreted as an executable, not a cmdlet. And even if that worked, out-file doesn't capture the error stream.
Is my only option to output the script's internal logging to a file/transcript, within the script? I feel like there should be a way to do this all from the executable call. The parsing behavior of the -file parameter makes sense, but is obnoxiously limiting.
Thanks,
== Matt
As noted in my comment to the question, this was apparently due to an idiosyncrasy with SCCM's task sequence engine, which somehow causes cmd /c powershell.exe to be interpreted differently than powershell.exe.
Adding the cmd /c solved the issue of > being interpreted as a -file parameter input, rather than as a stream redirection operator.
In fact, I rediscovered that I do use syntax like:
powershell.exe -executionpolicy bypass -file "w:\scripts\script.ps1" -param1 "%param1%" -param2 "%param2%" > "%logfile" 2>&1
successfully outside of the task sequence engine, in other powershell scripts and batch scripts, so it's not a powershell nor commandline interpreter issue.

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.

Executing powershell.exe from powershell script (run in ISE but not in script)

I'm new to these awesome Power shell world. I have a problem with script and really apreciate your help.
I have a script "cmd4.ps1" that needs to run another script "Transfer.ps1" that needs to receive 3 strings params and it needs to be run as other process thead different to "cmd4.ps1".
cmd4.ps1:
$Script="-File """+$LocalDir+"\Remote\Transfer.ps1"" http://"+$ServerIP+"/Upload/"+$FileName+" "+$ServerIP+" "+$LocalIP
Start-Process powershell.exe -ArgumentList $Script
After ejecution, the $Script cointain a value similar to
-File "c:\temp re\Remote\Transfer.ps1" http://10.1.1.1/Upload/file.txt 10.1.1.1 10.1.1.10
containing the syntax to use -File parameter to run a script of Powershell.exe, and three parameters that Transfer.ps1 needs ("http://10.1.1.1/Upload/file.txt", 10.1.1.1, 10.1.1.10).
When I write these instructions in PowerShell ISE I can see every values are right and PowerShell.exe is executed with right values, everything work fine!, but if I put these instructions inside "cmd4.ps1" script it doesn't work, I mean something is not right with parameters because I can see it start powershell but it never ends.
-ArgumentList is expecting an array of string arguments instead of a single string. Try this instead:
$ScriptArgs = #(
'-File'
"$LocalDir\Remote\Transfer.ps1"
"http://$ServerIP/Upload/$FileName $ServerIP $LocalIP"
)
Start-Process powershell.exe -ArgumentList $ScriptArgs
Note that you can simplify the string construction of the args as shown above.
Why don't you put this in cmd4.ps1?
& "c:\temp re\Remote\Transfer.ps1" "http://10.1.1.1/Upload/file.txt" "10.1.1.1" "10.1.1.10"

Calling powershell function with parameter from .cmd or .bat file

I have written a powershell script which is a complete function taking parameters (e.g. function name (param) { } ) and below this is a call to the function, with the parameter.
I want to be able to call this function in its .ps1 file, passing in the parameter. How would I be able to package a call to the function via a .bat or .cmd file? I am using Powershell v2.0.
You should use so called "dot-sourcing" of the script and the command with more than one statement: dot-sourcing of the script + call of the function with parameters.
The test script Test-Function.ps1:
function Test-Me($param1, $param2)
{
"1:$param1, 2:$param2"
}
The calling .bat file:
powershell ". .\Test-Function.ps1; Test-Me -Param1 'Hello world' -Param2 12345"
powershell ". .\Test-Function.ps1; Test-Me -Param1 \"Hello world\" -Param2 12345"
Notes: this is not a requirement but I would recommend enclosing the entire command text with double quotation marks escaping, if needed, inner quotation marks using CMD escape rules.
I believe all you have to do is name the parameters in the call to the script like the following:
powershell.exe Path\ScripName -Param1 Value1 -Param2 Value2
Param1 and Param2 are actual parameter names in the function signature.
Enjoy!
To call a PowerShell function from cmd or batch with arguments you need to use the -Commmand Parameter or its alias -C.
Romans answer will work with PowerShell 5.1 for example but will fail for PowerShell 7.1.
Quote from an issue I left on GitHub on why the same command didn't work is:
So as to support Unix shebang lines, pwsh's CLI now defaults to the -File parameter (which expects only a script-file path), whereas powershell.exe default to -Command / -c.
To make your commands work with pwsh, you must use -Command / -C explicitly.
So if you have a PowerShell file test.ps1 with:
function Get-Test() {
[cmdletbinding()]
Param (
[Parameter(Mandatory = $true, HelpMessage = 'The test string.')]
[String]$stringTest
)
Write-Host $stringTest
return
}
And the batch file will then be:
rem Both commands are now working in both v5.1 and v7.1.
rem v7.1
"...pathto\pwsh.exe" -NoExit -Command ". '"...pathto\test.ps1"'; Get-Test ""help me"""
rem v5.1
powershell.exe -NoExit -Command ". '"...pathto\test.ps1"'; Get-Test ""help me"""
The quotes around ...pathto\test.ps1 are a must if your .ps1 contains spaces.
The same goes for ...pathto\pwsh.exe
Here's the Github issue I posted in full:
https://github.com/PowerShell/PowerShell/issues/15281