executing a Powershell script from php - php

I'm trying to execute a powershell script from PHP, but it does not seem to work.
The script 'newEvent.ps1' creates an event on the Exchange server.
$psPath = "powershell.exe";
$psDIR = "C:\\wamp\\www\\ant\\assets\\ps\\";
$psScript = "newEvent.ps1";
$runScript = $psDIR. $psScript;
$runCMD = $psPath." ".$runScript." 2>&1";
echo "\$psPath $psPath <br>";
echo "\$psDIR $psDIR <br>";
echo "\$psScript $psScript <br>";
echo "\$runScript $runScript <br>";
echo "\$runCMD $runCMD <br>";
exec( $runCMD,$out,$ret);
echo "<pre>";
print_r($out);
print_r($ret);
echo "</pre>";
It outputs:
$psPath powershell.exe
$psDIR C:\wamp\www\ant\assets\ps\
$psScript newEvent.ps1
$runScript C:\wamp\www\ant\assets\ps\newEvent.ps1
$runCMD powershell.exe C:\wamp\www\ant\assets\ps\newEvent.ps1 2>&1
Array
(
[0] => File C:\wamp\www\ant\assets\ps\newEvent.ps1 cannot be loaded because the execut
[1] => ion of scripts is disabled on this system. Please see "get-help about_signing"
[2] => for more details.
[3] => At line:1 char:39
[4] => + C:\wamp\www\ant\assets\ps\newEvent.ps1 <<<<
[5] => + CategoryInfo : NotSpecified: (:) [], PSSecurityException
[6] => + FullyQualifiedErrorId : RuntimeException
[7] =>
)
If I run powershell.exe C:\wamp\www\ant\assets\ps\newEvent.ps1 on the command-line, it works fine.
This is the first time im attempting something like this. I ran Set-ExecutionPolicy RemoteSigned -Scope LocalMachine but it still gives me the same error.
In fact I ran Set-ExecutionPolicy unristricted, but it's still the same.

It looks like your command is surrounded by single-quotes. I think if you remove them, your command should run.
shell_exec returns the output from the command you run. To further diagnose, store the output in a variable, then print it out:
$output = shell_exec($runCMD);
echo '<pre>' . $output . '</pre>';
Make sure you enable running scripts. That capability is turned off by default. You have to enable the execution of scripts on each machine you want to run PowerShell scripts. Run about help_signing for more information.
Microsoft recommends running Set-ExecutionPolicy RemoteSigned -Scope LocalMachine. This allows all user accounts on a machine to run local scripts without issue, but requires confirmation to run scripts downloaded from the internet. This needs to be run in an administrative prompt. If you are running a 64-bit operating system, you'll need to do this from both a 64-bit and 32-bit shell.

To execute a script file from PHP you should follow this example:
You should start out with a simple PowerShell script. Create a text file with the name "test.ps1".
Now type the following script in this file:
Get-Process
Place the code below in a PHP file named "test.php". Remember to update the file path in the following example "C:/PATH/TO/test.ps1" with the absolute path to your own script file.
echo "<pre>";
echo Shell_Exec('powershell -InputFormat none -ExecutionPolicy ByPass -NoProfile -Command "& { . \"C:/PATH/TO/test.ps1\"; }"');
echo "</pre>";
The above code will output a list of all your running processes.
Note that I was running my script in a Windows PC and I was getting error messages because of the file path. So, I replaced all backslashes from the file path with forward slashes.
The following parameters are worthy of note:
-InputFormat none - Thanks to a bug in PowerShell, the script will never finish running or exit. This parameter provides a workaround this bug.
-ExecutionPolicy ByPass - Without this parameter, the code will throw a low privilege error message.
-NoProfile - With this parameter, your script will run faster and more predictably.
-Command - By loading your script file through the "-Command" parameter, instead of the "-File" parameter, you will have greater flexibility.
If, for example, you needed to call a function inside your script and send parameters to that function, you would need to use the "-Command" parameter.
Here is an example of how to call a function "my-function" inside your PowerShell script file and pass the parameters "-myParameter" and "-myOtherParameter" to that function with the values "10" and "15" respectivelly:
echo "<pre>";
echo Shell_Exec('powershell -InputFormat none -ExecutionPolicy ByPass -NoProfile -Command "& { . \"C:/PATH/TO/test.ps1\"; my-function -myParameter 10 -myOtherParameter 15 }"');
echo "</pre>";

Found this on another website and thought I would pass it along:
I was debugging a program that uses Windows API (Creating a Child
Process with Redirected Input and Output) to capture stdout of
Microsoft’s Windows PowerShell.
Script passed to PowerShell (-File switch) didn’t execute and
PowerShell just hanged until killed by Task Manager.
It turns out that you need to use undocumented parameter “-InputFormat
none”:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -InputFormat none -File file.ps1
This did the trick for me.

Use "-executionPolicy Unrestricted" along with the command "powershell.exe". Therefore the command will be :
powershell.exe -executionPolicy Unrestricted
Then it will surely work.

Related

How to make a non-blocking php exec call?

I need to echo text to a named pipe (FIFO) in Linux. Even though I'm running in background with '&' and redirecting all output to a /dev/null, the shell_exec call always blocks.
There are tons of answers to pretty much exactly this question all over the internet, and they all basically point to the following php manual section:
If a program is started with this function, in order for it to continue running in the background, the output of the program must be redirected to a file or another output stream. Failing to do so will cause PHP to hang until the execution of the program ends.
And sure enough, when I try the non-blocking approach (of backgrounding and redirecting to /dev/null) with other commands like sleep, php successfully executes without hanging. But for the case of echo-ing to the FIFO, php hangs even though running the same command with bash produces no visible output and immediately returns to the shell.
In bash, I can run:
bash$ { echo yay > fifo & } &> /dev/null
bash$ cat fifo
yay
[1]+ Done echo yay > fifo
but when running the following php file with php echo.php:
<?php
shell_exec("{ echo yay > fifo & } &> /dev/null");
?>
it hangs, unless I first open fifo for reading.
So my question is, why is this blocking, but sleep isn't? In addition, I want to know what is happening behind the scenes: when I put the '&' in the php call, even though the shell_exec call blocks, the echo call clearly doesn't block whatever bash session php invoked it on, because when I CTRL+C out of php, I can read 'yay' from the FIFO (if I don't background the echo command, after CTRL+C the FIFO contains no text). This suggests that perhaps php is waiting on the pid of the echo command before going to the next instruction. Is this true?
I've been trying something similar and in the end came up with this solution:
/**
* This runs a shell command on the server under the current PHP user, that is in CLI mode it is the user you are logged in with.
* If a command is run in the background the method will return the location of the tempfile that captures the output. In that case you will have to manually remove the temporary file.
*/
static public function command($cmd, $show_output = true, $escape_command = false, $run_in_background = false)
{
if ($escape_command)
$cmd = escapeshellcmd($cmd);
$f = trim(`mktemp`);
passthru($cmd . ($show_output ? " | tee $f" : " > $f") . ($run_in_background ? ' &' : ''));
return $run_in_background ? $f : trim(`cat $f ; rm -rf $f`);
}
The trick is to write the output to a temporary file and return that when the command has finished (blocking behavior) or just return the file path (non-blocking behavior). Also, I'm using passthru rather than shell_exec because interactive sessions are not possible with the latter because of the blocking behavior.

Plink fails to run when executed from PHP in wamp, but works when executed manually

I need to access a Linux machine from Windows 7 via PHP.
For that I created simple bat (MyScript.bat) script containing plink.
c:\wamp\www\abc\plink.exe user1#192.168.70.128 -pw l1c -C "df -h">11.txt
When I am executing the bat script, it's working fine, i.e. the output is written in file 11.txt
But when I am accessing it from PHP, the 11.txt is created without data
echo exec('MyScript.bat');
Moreover, in browser, the script commands are displayed as text. I even tried to use print_r for the display.
"c:\wamp\www\abc\plink.exe user1#192.168.70.128 -pw l1c -C "df -h">11.txt
Do not launch external tool for SSH.
PHP has native support for SSH.
Or use phpseclib:
require __DIR__ . '/vendor/autoload.php';
use phpseclib\Net\SSH2;
$ssh = new SSH2($hostname);
if ($ssh->login($username, $password))
{
echo $ssh->exec("df -h");
}
See:
https://phpseclib.com/docs/connect
https://phpseclib.com/docs/auth
Anyway, if you want to use Plink, redirect also the standard error output to debug your problem:
plink.exe .. dir > 11.txt 2>&1
See How to redirect Windows cmd stdout and stderr to a single file?.
You are for sure missing the -hostkey switch to explicitly specify a fingerprint of the trusted hostkey.

Command works in SSH terminal, but not in PHP script

I'm having a weird problem. I have installed ffmpeg on my server. When I run "ffmpeg" from SSH (PuTTY) it confirms the install:
Then I placed the following code in a PHP file, inside a website on the same server:
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$output = exec('ffmpeg -h');
echo "<pre>$output</pre>";
?>
However when I run the PHP script, the page is blank, there is no output. I can confirm that exec is working fine, because when I run php -v | grep cli both in PHP and in terminal, they both output the same thing.
I am using Plesk (web host edition) to manage the site, and have given it access to the server over SSH (/bin/sh)
What am I missing here?
You want to use the full path to ffmeg as it's likely not in the webserver user's path environment variable.
Also, the return of exec() is the last line of output, which may be a blank line, you never know. So use the second parameter to capture all output in an array:
exec('/path/to/ffmpeg -h', $output);
echo implode('<br>', $output);
Or you can try system() or passthru() to output directly:
echo "<pre>" . system('/path/to/ffmpeg -h') . "</pre>";
I would recommend trying
$command = escapeshellcmd('/root/bin/ffmpeg -h');
$output = shell_exec($command);
echo "<pre>$output</pre>";
EDIT - ADDITION
However, the issue in this case is that files in /root are not available to the web server user for security reasons. The ffmpeg executable should go into /usr/local/bin or another directory where it is available to the web server user.

PHP | Passing parameters into Powershell script

I am trying to create a PHP application which runs powershell scripts.
I have a file called "change.ps1" which is a powershell script, here is the content of that file:
Param([string]$username, [string]$password)
Import-Module ActiveDirectory
$newpwd = ConvertTo-SecureString -String "$password" -AsPlainText –Force
Set-ADAccountPassword $username -NewPassword $newpwd –Reset
Now i have a PHP page which uses the shell_exec() function to run this script and pass TWO parameters to it, which you can see above is used in the ps1 file ( $username, $password):
$psscriptpath = "c:\inetpub\htdocsscripts\change.ps1";
shell_exec("powershell.exe -executionpolicy remotesigned -File" . $psscriptpath . " -username \"" . $username . "\" -password \"" . $password . "\"");
At the moment this does not work (the page never finishes loading aka times out). So the question is, am i doing this correctly? where have i gone wrong. The theory behind this is relatively simple, use PHP to pass variables through as parameters into a powershell script.
Thanks for taking a look, and let me know if you have questions.
UPDATE:
I tried running the script directly via the cmd to see if the problem was in the script its self. Here is the error i was shown:
http://puu.sh/aXuH3/b8db154625.png
SECOND UPDATE:
I have fixed the error on the CMD, it was an encoding issue. However when i try to run the php page, i still get the time out issue:
http://puu.sh/aXEdY/22cc87310c.png
ok, seems you are missing something.
you need to point to the absolute path of the script. If you saw my message on wizpert, i did a cd command to the directory of the script to ensure the correct environment:
c:\>cd c:\my\directory\with\powershells
then you can execute your powershell with all the variables on it. Also try to do it via cmd to see if it produces any messages. If you see there is a timeout, it means that the process or is hanging or the web user does not have enough rights to execute shells.
If so, modify your php.ini or whatever let it know that the www-data user (in apache, not sure on IIS) has rights to execute commands.\
also it could be that you are executing that parameter wrongfully:
Param([string]$username, [string]$password)
Import-Module ActiveDirectory
$newpwd = ConvertTo-SecureString -String $password -AsPlainText –Force
Set-ADAccountPassword $username -NewPassword $newpwd –Reset
Make $password without quotes on the powerscript.
This is a solution for Windows 2012R2 server - Apache 2.4 - PHP 7.4
The trick is to switch the codepage in the command environment. Below shows that UTF is well revieved inside the ps1 file, since the content of the test.txt holds the correct data.
The problem arise, when the output from PowerShell goes back to the server encoded in codepage 850.
A change to codepage 65001 (UTF8) is the solution.
This is test.ps1
param([String]$p1)
$loc = $env:LOCALAPPDATA
"a${p1}b" | Out-File -FilePath "${loc}\test.txt" -Encoding utf8
chcp
chcp 65001
write-host "a${p1}b"
chcp 850
This is output from CDM.EXE
C:\PowerShell>powershell -file test.ps1 -p1 ÆØŁódźÅ€
Active code page: 850
Active code page: 65001
aÆØŁódźÅ€b
Active code page: 850
This is PHP
echo "<pre>";
$psscriptpath = "C:/powershell/test.ps1 -p1 ÆØŁódźÅ€";
echo $psscriptpath . '<br>';
echo 'From PowerShell:<br>';
$psData = shell_exec("powershell.exe -executionpolicy remotesigned -File " . $psscriptpath);
echo $psData . '<br>';
echo 'From readfile: ';
readfile(getenv('LOCALAPPDATA') . "\\test.txt");
echo "</pre>";
This is from my browser:
C:/powershell/test.ps1 -p1 ÆØŁódźÅ€
From PowerShell:
Active code page: 850
Active code page: 65001
aÆØŁódźÅ€b
Active code page: 850
From readfile: aÆØŁódźÅ€b
A final comment: Always switch back to you localized codepage after the data has been generated from some application.
I have experienced stange things to hanppend in the CMD window when it is in 65001 mode
This trick also works when using the PostgreSQl psql.exe to output data. I assume the same goes for Mysql and others.

Executing Perl through PHP returns Exit Status 2

I am attempting to execute a Perl script through PHP via the following command:
$last_line = exec('/usr/bin/perl /path/to/perl/script.pl ' . escapeshellarg($argument),$output,$status);
The script does not perform its function, and the exit status is always 2 (improper use of shell builtins). Both Perl and the script can be read and executed by any user. Running the script on a command line works just fine. Any thoughts?
I use this code to run file.pl located in same folder as php file
$output = passthru("perl relative_path/file.pl ".$_POST["var1"]." ".$_POST["var2"]);
I use a perl script as a database interface from PHP with the following code:
exec ( $cmdToPass . " 2>&1" , $output , $returnVar);
Where:
$cmdToPass is the command I'm executing (the perl script) with stderr redirected to stdout.
$output holds the command's output
$returnVar holds the exit code
You should then be able to print $output to determine why the script. You may also wish to check the PHP error log (usually the same as the web server's error log) to see if anything is captured there.
See the PHP manual on exec if you need more info on the exec function.

Categories