Powershell output to PHP variable using shell_exec - php

I have a powershell script which outputs a video file duration. Running this script gives me the expected result.
$Folder = 'C:\my\path\to\folder'
$File = 'sample1_1280_720.mp4'
$LengthColumn = 27
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace($Folder)
$objFile = $objFolder.ParseName($File)
$Length = $objFolder.GetDetailsOf($objFile, $LengthColumn)
Write-Output $Length
In a php file, I'm trying to save this output to a variable.
<?php
$var = shell_exec("powershell -File C:\my\path\to\psFile.ps1 2>&1");
echo "<pre>$var</pre>";
?>
The string output I get from shell_exec is the text you see when you start powershell from cmd. Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved. Any suggestions on how to extract the video duration?

Using your PS code
$Folder = 'C:\my\path\to\folder'
$File = 'sample1_1280_720.mp4'
$LengthColumn = 27
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace($Folder)
$objFile = $objFolder.ParseName($File)
$Length = $objFolder.GetDetailsOf($objFile, $LengthColumn)
$Length
I'm able to get the file length using PS -File and -Command. I added a few other flags you may want or need. You shouldn't need to use redirection 2>&1 to get your variable from PS to PHP. It is most likely the reason you are getting the logo.
function PowerShellCommand($Command)
{
$unsanitized = sprintf('powershell.exe -NonInteractive -NoProfile -ExecutionPolicy Bypass -Command "%s"', $Command);
return shell_exec($unsanitized);
}
function PowerShellFile($File)
{
$unsanitized = sprintf('powershell.exe -NonInteractive -NoProfile -ExecutionPolicy Bypass -File "%s"', $File);
return shell_exec($unsanitized);
}
// Can use relative paths
echo PowerShellCommand("./psFile.ps1");
// Be sure to escape Windows paths if needed
echo PowerShellFile("C:\\my\\path\\to\\folder\\psFile.ps1");
Returning $Length in all three ways work for me
$Length
return $Length
Write-Output $length

Related

Php exec Powershell script Azure AZ commands do not run, all the other functions do

My PHP script
exec('powershell.exe -ExecutionPolicy Unrestricted -NoProfile -InputFormat none -file "..\..\scripts\addcustomer.ps1"', $output);
AZ function in the script:
$file = “$PSScriptRoot\Azure\pass.txt”
$azureuser = “user#contoso.com”
$Password = Get-Content $file | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PsCredential($azureuser, $Password)
Login-AzAccount -Credential $credential
New-AzDnsRecordSet -Name "$name" -RecordType A -ZoneName "contoso.co" -ResourceGroupName "RG" -Ttl 3600 -DnsRecords (New-AzDnsRecordConfig -IPv4Address "$ipaddress")
The $output does not display any output of this function. I confirm that if I run the script manually, everything works.
Many thanks.
Use exec($your_command, $output, $error_code) and see what $error_code contains. It may just be because powershell.exe isn't in the PATH env variable in PHP.
Try to put the full path to your PowerShell executable, typically something like this:
<?php
// A default powershell path in case "where powershell" doesn't work.
define('POWERSHELL_EXE', 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe');
// Find the path to powershell with the "where" command.
$powershell_exe = exec('where powershell');
if ($powershell_exe === false) {
$powershell_exe = POWERSHELL_EXE;
}
// Also check that the path to your script can be found.
// If it doesn't then you can use realpath() to get the
// full path to your script.
$cmd = $powershell_exe .
' -ExecutionPolicy Unrestricted -NoProfile -InputFormat none' .
' -file "..\..\scripts\addcustomer.ps1"';
$last_line = exec($cmd, $full_output, $error_code);
// Then check if $last_line !== false and check $error_code to see
// what happened.
var_export([
'$cmd' => $cmd,
'$last_line' => $last_line,
'$full_output' => $full_output,
'$error_code' => $error_code,
]);
Another important point: Has the user running your PHP code enought rights to do what you are doing in your PS1 script?
You may need to run your PowerShell script with elevation privilege or another user. I never did that but perhaps this topic could help:
PHP command to execute powershell script as admin

Running Powershell completely headless

i want to send a "Ballon Notification" to a remote computer in my network. Every machine in the network runs on windows 10.
The event needs to be triggered from a website which is build with php.
I've accomplished this by using the following code:
php
$powershell_path = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
$script_path = "[..path to the ps1 script..]\\test.ps1";
$exec = $powershell_path." -executionPolicy Unrestricted ".$script_path." -computer_name ".$args['remote_computer'];
shell_exec($exec." 2>&1");
test.ps1
param(
[parameter(mandatory=$true)][string]$computer_name
)
function Send-Balloon {
Param(
[parameter(mandatory=$true)][string]$To,
[parameter(mandatory=$true)][string]$balloon_title,
[parameter(mandatory=$true)][string]$balloon_text,
[parameter(mandatory=$false)][int]$show_time,
[parameter(mandatory=$false)][string]$scripts_path,
[parameter(mandatory=$false)][string]$script_name
)
if(!$show_time) { $show_time = 15000 }
if(!$scripts_path) { $scripts_path = "C:\temp\" }
if(!$script_name) { $script_name = "task.ps1" }
$remote_computer = $To
if(!(Test-Connection -ComputerName $remote_computer -Count 1 -ErrorAction SilentlyContinue)) {
Write-Warning "$remote_computer could not be reached"
break
}
$str = #"
Add-Type -AssemblyName System.Windows.Forms
`$balloon = [System.Windows.Forms.NotifyIcon]::new()
`$path = (Get-Process -id `$pid).Path
`$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon(`$path)
`$balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Info
`$balloon.BalloonTipTitle = '$balloon_title'
`$balloon.BalloonTipText = '$balloon_text'
`$balloon.Visible = `$true
`$balloon.ShowBalloonTip(100000)
"#
$script = [scriptblock]::Create($str)
$script | Out-File $scripts_path\$script_name
$remote_path = "\\$remote_computer\c$\temp"
if(!(Test-Path $remote_path)) {
New-Item -ItemType Directory -Path $remote_path
}
Copy-Item -Path $scripts_path\$script_name -Destination $remote_path
$task_scriptblock = {
$schedule_script = 'C:\temp\task.ps1'
$seconds = 2
$a = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle hidden -Command $schedule_script"
$tr = New-ScheduledTaskTrigger -Once -At ((Get-Date) + (New-TimeSpan -Seconds $seconds))
$p = New-ScheduledTaskPrincipal -UserId (Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -expand UserName)
$tn = "!random_task_name_" + (-join ((65..90) + (97..122) | Get-Random -Count 10 | % {[char]$_}))
$t = Register-ScheduledTask -TaskName $tn -Trigger $tr -Action $a -Principal $p
Start-Sleep ($seconds + 1)
Get-ScheduledTask -TaskName $tn | Unregister-ScheduledTask -Confirm:$false
Remove-Item -Path $schedule_script
}
Invoke-Command -ComputerName $remote_computer -ScriptBlock $task_scriptblock
}
Send-Balloon -To $computer_name -balloon_title "test" -balloon_text "just a test"
This code copies the script from $str into the tempfolder of a given remote computer. Afterwards it tolds the remote computer to execute the created file. After executing it deletes the ps1 file.
This works like intendet and (mostly) flawless. My problem now is, that powershell with '-WindowStyle hidden' is not really hidden. For a split second you can see the powershell console popping up and instantly vanishing.
I've read that this is the 'normal' behaviour and can be counteracted by calling the ps1-file from another context like a vbs script.
vbs
command = "powershell.exe -nologo -command [path to the ps1-file]"
set shell = CreateObject("WScript.Shell")
shell.Run command,0
The thing is, that this seems to be overcomplication everything as i do have a php script to run a ps1 script to copy a ps1 and a vbs file. Then call the copied vbs script, which calls the copied ps1 to show a simple notification.
Is there a simple method to call the ps1 script via php on a remote computer without seeing the powershell console? Or even better: is there is simpler way to trigger 'balloon notifications' on a remote computer which i haven't thought of yet?

Python script jump the line with os and glob modules when is runned in PHP

I have problem with a for cycle and glob and os modules.
In python Shell the print is printed but when i embed my python script in php it does not work.
The python below via PHP print only "first" and "second" but do not print "current file is:...".
Maybe i find another way for reading a directory?
glob and os modules are not compatible with PHP?
python:
print("first")
path = 'cat/tryfile'
for infile in glob.glob( os.path.join(path, '*.jpg') ):
print("current file is: " + infile )
print("second")
PHP:
$param1 = "first";
$param2 = "second";
$param3 = "third";
$command = "C:\\python27\\python C:\\Python27\\execprova.py";
#FIRST PYTHON embedding with popen
$command .= " $param1 $param2 $param3 2>&1";
$temp = exec($command, $return);
echo "INIZIO PID";
$pid = popen( $command,"r");
echo "<body><pre>";
while( !feof( $pid ) )
{
echo fread($pid, 256);
flush();
ob_flush();
usleep(100000);
}
pclose($pid);
#SECOND PYTHON embedding with exec
echo (" {PHP inizio command output return ed exec /PHP} ");
$command = "C:\\python27\\python C:\\Python27\\bp1imgsenzaprint.py";
$output = null;
$temp = exec($command);
function success()
{
$mystring = exec('C:\\python27\\python C:\\Python27\\bp1imgsenzaprint.py', $output);
var_dump($output);
var_dump($mystring);
print_r($output);
}
print("SUCCESS");
success();
Always take care when using relative paths in CLI scripts. The working directory and PATH environment variable are often not what you'd normally expect.
In Python, you can set the working directory (similarly to Windows/*nix's cd command) with os.chdir(path) so that you can safely use relative paths, or use absolute paths instead by either hardcoding or concatenating the containing directory path with the relative file path.

PHP script runs multiple times if it contains shell_exec. How could it be?

I have a very simple PHP script that calls shell_exec to start a 3rd party application.
No matter what application I try to run (including notepad.exe),
if the script contains the call to shell_exec, the script is called multiple times,
if the script doesn't contain this call, it runs just once.
I can provide any source code needed, let me know what do you want to see, I just absolutely don't know where to look.
Windows 2008 R2, PHP 5.5.1, IIS 7.5, Amazon EC2 server
And no, there isn't any loop inside the script, because I have placed
file_put_contents('log.txt', $_SERVER['REQUEST_URI'], FILE_APPEND);
as the first script row and I can see it written multiple times in the log.
EDIT:
It doesn't happen on my local host. And it happens with exec also.
PHP script stripped down to bare minimum:
<?php
//Report any errors
ini_set("MAX_EXECUTION_TIME", "-1");
ini_set('max_input_time', -1);
ini_set ("display_errors", "1");
error_reporting(E_ALL);
require_once('PhpConsole.php');
PhpConsole::start(true, true, dirname(__FILE__));
function writeLog($content, $logname)
{
$temp = $content ." at " .date("D M j G:i:s T Y") ."\r\n";
$f = fopen($logname, 'a+');
fwrite($f,$temp,strlen($temp));
fclose($f);
}
function createBackground()
{
//Set the correct content type
header('content-type: image/png');
//Create our basic image stream 225px width, 225px height
$image1 = imagecreate(1362, 762);
// Set the background color
$white = imagecolorallocate($image1, 255, 255, 255);
// Save the image as a png and output
imagepng($image1, "saves/back.png");
// Clear up memory used
imagedestroy($image1);
}
function buildFramesSequence()
{
array_map('unlink', glob("saves/*"));
array_map('unlink', glob("*.mp4"));
unlink("list.txt");
$url = realpath('') ."/" .$_GET["jfile"] ;
$contents = file_get_contents($url);
$results = json_decode($contents, true);
$noOfFrames = count( $results['ani']);
$lastframe = "saves/back.png";
createBackground();
$elements = createElements($results['pre']);
$frame_elements = array();
$prev_element = null;
for ($i = 0; $i <$noOfFrames; $i++)
{
$format = 'image%1$05d.png';
$imgname = sprintf($format, $i);
copy($lastframe, "saves/" .$imgname);
}
}
function createVideo()
{
writeLog("before build", "log.txt");
buildFramesSequence();
writeLog("after build", "log.txt");
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$localpath1 = realpath('') ."/ffmpeg/ffmpeg.exe";
} else {
$localpath1 = "ffmpeg";
}
$localpath2 = realpath('') ."/saves/image%05d.png";
$mp3name = $_GET["mfile"];
$localpath3 = realpath('') ."/" .$mp3name;
$temp = substr($mp3name, 0, -1);
$localpath4 = realpath('') ."/" .$temp ."4";
writeLog(" before ffmpeg", "log.txt");
$output = shell_exec("notepad.exe");
// $output = shell_exec("ffmpeg $localpath1 .' -f image2 -r 20 -i ' .$localpath2 .' -i ' .$localpath3 .' -force_fps ' .$localpath4. ' 2>&1 &');
// exec("notepad.exe", $output = array());
// debug($output);
writeLog($localpath4, "list.txt");
return $output;
}
file_put_contents('log.txt', $_SERVER['REQUEST_URI'], FILE_APPEND);
set_time_limit(0);
$output = createVideo();
echo $output;
?>
This is a very strange issue that still happens to this day with exec() system() shell_exec() etc. If your command creates a file the quickest solution is to check whether that file exists, like so:
[ -f path/file.mp4 ] || #Your command here#
This checks whether the file path/file.mp4 exists, if not, the second condition runs, which is your command. To check the opposite use the ampersand, like so:
[ -f path/file.mp3 ] && #Command here#
I'm not sure if anyone is still having problems with this, but maybe yours is the same issues that I just had. I was creating a file with exec, and appending a datetime stamp to it.
I was ending up with 5 files. Turns out, because I was redirecting all calls to my index.php thru htaccess, then when I had some images that were directing to relative path assets/images/image.jpg, then it would redirect that thru my index page and call my script multiple times. I had to add a slash to the image path: /assets/images/image.jpg.
Hope this help someone.

wscript.shell running file with space in path with PHP

I was trying to use wscript.shell through COM objects with php to pass some cmd commands to cURL library (the DOS version). here is what I use to perform this task:
function windExec($cmd,$mode=''){
// Setup the command to run from "run"
$cmdline = "cmd /C $cmd";
// set-up the output and mode
if ($mode=='FG'){
$outputfile = uniqid(time()) . ".txt";
$cmdline .= " > $outputfile";
$m = true;
}
else $m = false;
// Make a new instance of the COM object
$WshShell = new COM("WScript.Shell");
// Make the command window but dont show it.
$oExec = $WshShell->Run($cmdline, 0, $m);
if ($outputfile){
// Read the tmp file.
$retStr = file_get_contents($outputfile);
// Delete the temp_file.
unlink($outputfile);
}
else $retStr = "";
return $retStr;
}
now when I run this function like:
windExec("\"C:/Documents and Settings/ermac/Desktop/my project/curl\" http://www.google.com/", 'FG');
curl doesn't run because there is a problem with the path. but when I remove the spaces from the path it works great.
windExec("\"C:/curl\" http://www.google.com/", 'FG');
so my question is how can I escape these spaces in wscript.shell commands?
is there anyway I can fix this?
thanks in advance :)
nvm I found a solution:
there:
windExec("cd C:/Documents and Settings/ermac/Desktop/my project/libs & curl.exe -L http://www.google.com/", 'FG');

Categories