I have a PHP page which uses the shell_exec command:
$psscriptpath = "C:\inetpub\htdocs\school_panel\scripts\change.ps1";
shell_exec("powershell.exe -executionpolicy remotesigned -File " . $psscriptpath . " -username \"" . $username . "\" -password \"" . $password . "\"");
However, when i submit the page aka have the code above executed, my page just times out ( never finishes loading until the time out timer is reached and i get this error):
http://puu.sh/aXEdY/22cc87310c.png
Now i have done some research and it appears that i need to somehow set some sort of executing script permissions/rights in IIS/PHP? mabey change some php.ini config? I really am not sure.
I have already tried adding permissions for powershell for IUSER and etc. I have even set the execution policy on powershell to remotesigned. It appears i have the FastCGI and CGI module installed on IIS.
I have also tried running the script via CMD using php and it WORKS, just not in the browser.
Regards
Your solution is as simple as this:
shell_exec("powershell.exe -executionpolicy remotesigned -File {$psscriptpath} -username {$username} -password {$password} < NUL");
You do not need to surround parameters in double quotes, and in order to prevent powershell from hanging, you need to pass < NUL at the end of the line.
The < NUL will force the output from PowerShell back to PHP.
Related
I am currently having some weird behavior from shell_exec that I cant quite figure out.
This is my code:
$cmd = ('sshpass -p PASSWORD scp -o StrictHostKeyChecking=no ../../UpdateFiles/' . $FILENAME . ' root#' . $IP . '://media/sdcard');
$output = shell_exec($cmd);
if (empty($output)){
$cmd = ('sshpass -p PASSWORD ssh -o StrictHostKeyChecking=no root#' . $IP . ' /sbin/start_sw_upgrade_process sdcard /media/sdcard ' . $FILENAME);
$output = shell_exec($cmd);
if (empty($output)){ $output = "No return from update command"; }
}
printf("%s",$output);
So, the first command works as intended, returning nothing only when successful. This can be easily verified, by the file now being in the sd card.
Once the file has been transferred to the other device, the next command should execute.
This command should start a tool that should start using the file. As I am just using a dummy file it should return and error.
When I execute this code however, an empty string is returned, as it just prints "No return from update command"
However, if i go and execute the command manually at the same directory as the php file (filling in the variables manually ofc), there is an error being returned.
Whether the command is being executed but just not returning anything, or if the command doesn't execute at all, I am not too sure.
But I also use similar commands elsewhere such as:
$cmd = ('sshpass -p PASSWORD ssh -o StrictHostKeyChecking=no root#' . $IP . ' df | grep sdcard');
$output = shell_exec($cmd);
In which case it works as expected. So I dont quite understand why it doesn't in this case.
Is this some stupid obvious mistake?
I have recently changed it so instead of printing "no return from update command" it prints the command that was just executed.
When i copy that command and execute it the exact same situation, I get an output.
Why does it only work manually?
Ok, so it took a while but i figured out what was the actual issue.
So shell_exec() and exec() only read from sdtout, they do not read from sdterr.
While a normal shell console will convert the errors to standard output, the functions in php, will not.
As such the output of the functions was in fact empty, as the only output was errors.
to fix this I appended the argument "1>&2" at the end of the command.
This redirects the error output to the standard output. And now when the function is called I get an output instead of an empty string.
I'm using exec() for execute mysql-dump but it's generating an empty file on apache, but when i use the "php artisan serve" the file is generated correctly, the output file has the same user and group in apache and in the artisan serve.
Using: Ubuntu 14.04 and Xamp 5.6.12
$dir = substr(__DIR__, 0, 24).'database/backups/';
$newBackup = Backup::create();
$command = 'mysqldump -uroot lions > '.$dir.$newBackup->getDateTimeString().'.sql';
exec($command);
Ok, I was facing the same problem with Laravel 5.6 and running windows though. Before anything, you should make sure to include the password argument (either as --password or -p), even if its empty.
$cmd =
"mysqldump -h " . env('DB_HOST') .
" -u " . env('DB_USERNAME') .
" -p\"" . env('DB_PASSWORD') . "\"" .
" --databases " . env('DB_DATABASE');
The main issue is that even though several sources note that exec waits until the process is complete there is no way to know for sure, leaving that aside, since processes could be owned by different users it'd probably be better if you created a temporary file and then flashed the contents of the output array into it rather than hoping for mysqldump to do it for you.
$output = [];
$name = "your_random_file_name.sql";
exec($cmd, $output);
$tmppath = tempnam(sys_get_temp_dir(), $name);
$handle = fopen($tmppath, "w");
fwrite($handle, implode($output, "\n"));
Finally, write the main file to your desired location, in my case I upload it directly to an Amazon S3 bucket, and close the temporary file.
Storage::disk('myS3bucket')
->putFileAs("backups", new File($tmppath), $name);
fclose($handle);
I know it seems redundant but, as I mentioned above, there is no way to know for sure.
Indeed, in a development environment, it is customary not to set a password for the database. And that's why your command does not work.
But in a production environment, you are obliged to set a password for the database.
Try in your production environment (ie with a password!), And you will see that the script works.
I don't have a solution for this problem but I do know it should be possible to do this. If I enter the following command in my terminal the mysqldump works:
mysqldump "--user=root" "--password=" dbname > ~/Desktop/export.sql
But when I use this command in my scheduler as below, I gett an empty file.
$schedule->exec("mysqldump \"--user=".env('DB_USERNAME')."\" \"--password=".env('DB_PASSWORD')."\" ".env('DB_DATABASE')." > export.sql")->everyMinute();
Maybe there is someone who knows why this doesn't work? I'm guessing it's a permission issue, but I leak experience in this.
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.
Thanks for taking your time to read about my problem, so lets get straight into it.
My ultimate (end) goal is to be able to have a web base PHP app which lets users modify active directory for users inside a network.
I have found out commands that need to be ran via Powershell to change user passwords inside an active directory.
Now here is my current setup:
There is one main server where IIS is installed and the web application sits at.
There will be several computers connected to the network which navigate to the website and execute these commands
I have tried adding the code:
$query = shell_exec('Import-Module ActiveDirectory');
$query = shell_exec('$newpwd = ConvertTo-SecureString -String "'.$safe_password.'" -AsPlainText –Force');
$query = shell_exec('Set-ADAccountPassword "'.$safe_username.'" -NewPassword $newpwd –Reset');
Now here are my questions:
1) Once a computer runs that page and has those commands executed, are the commands going to be executed in the main server? where powershell is installed and permissions are granted. If not, my whole app wont work, are there any other solutions?
2) those commands are all powershell commands not cmd.exe commands. So does shell_exec() even run those commands in powershell, or just in cmd.exe. If it only runs in cmd then this wont work, how can i make it run via powershell?
I would appreciate if you could answer and help me out here, thanks alot.
Setup the Parameters in your PowerShell like this:
Param([string]$username, [string]$password)
Then call your script like this:
shell_exec("powershell.exe " . $psscriptpath . " -username \"" . $username . "\" -password \"" . $password . "\"");
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.