profesorfalken / jPowerShell

Simple Java API to interact with PowerShell console
Apache License 2.0
218 stars 84 forks source link

Timeout on Executing PowerShell Script #6

Closed ashishpatel1992 closed 8 years ago

ashishpatel1992 commented 8 years ago

Hello, I am trying to execute powershell script using jPowershell but it throws error

Apr 27, 2016 6:13:01 PM com.profesorfalken.jpowershell.PowerShell waitUntilClose

SEVERE: Unexpected error when closing PowerShell: TIMEOUT!

Here is my Code which grabs CPU temerature

$ThermalInformation = Get-WmiObject -Namespace  'root\wmi' -Class 'MSAcpi_ThermalZoneTemperature'

$count=0
if($ThermalInformation -is [system.array]){
    $xcount=0;
    # Calculate CPU Temperature
    $CpuTempList = New-Object System.Collections.ArrayList

    $i=0
    $length=$ThermalInformation.Count
    while ($i -lt $length)
    {
    $CpuTemp = New-Object System.Collections.ArrayList
    $HostCPUTemperature = [math]::round((($ThermalInformation[$i].CurrentTemperature - 2732) / 10), 0)
    $thermalInfo=$ThermalInformation[$i].InstanceName
    $thermalInfoFinal=$thermalInfo -replace 'ACPI\\ThermalZone\\',''

    $x=$CpuTemp.add('InstanceName:'+$thermalInfoFinal)
    $x=$CpuTemp.add('CPU Temp:'+ $HostCPUTemperature +'°C')
    $count=$CpuTempList.Add($CpuTemp)
    $i++

    }
}else{
    $CpuTempList= New-Object System.Collections.ArrayList
    $HostCPUTemperature = [math]::round((($ThermalInformation.CurrentTemperature - 2732) / 10), 0)
    $count= $CpuTempList.Add('InstanceName:'+$ThermalInformation.InstanceName+'CPU Temp:'+ $HostCPUTemperature +'°C')
}
$CpuTempList|ConvertTo-Json

Any solution to execute powershell script?

profesorfalken commented 8 years ago

Hello,

I do not know the details of your system.

In my case (Windows 7 64 bits), it returns an error:

+ $CpuTempList|ConvertTo-Json <<<<
+ CategoryInfo          : ObjectNotFound: (ConvertTo-Json:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException

Does it work correctly if you launch it from a Powershell console?

Thank you

ashishpatel1992 commented 8 years ago

@profesorfalken I am on Windows 10, may be windows 7 doesnt support ConvertTo-Json Try removing ConvertTo-Json and let me know the output

profesorfalken commented 8 years ago

Ok, I have tested it on Windows 10.

We should be careful before launching the script because we have to change the execution policy to allow executing Powershell scripts and we also need to launch it as administrator to get access to thermal info.

In my case I have (what I think is) the right result:

[
[
    "InstanceName:TZ00_0",
    "CPU Temp:28°C"
],
[
    "InstanceName:TZ01_0",
    "CPU Temp:30°C"
]
]
ashishpatel1992 commented 8 years ago

@profesorfalken Can you share the java code through which you are calling the script code?

profesorfalken commented 8 years ago

Ok... no, sorry but I did not perform the test properly.

In fact in my case it always fails because of rights. Even if I am in an administrator console and I have set the executionpolicy, when I try to execute it (JPowerShell.executeSingleCommand("./temp.ps1")) I get this error:

.\temp.ps1 : File C:\users\javier\temp.ps1 cannot be loaded because running scripts is disabled on       this system. For
more information, see about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ .\temp.ps1
+ ~~~~~~~~~~
    + CategoryInfo          : SecurityError: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

JPowershell launch a new PowerShell session when called so I guess that the execution policy is not inherited in the new session...

Do you have an idea on how to bypass it? Is there a way to fully disable the security policy in the system? In my case I try always to execute in an administrator PowerShell console: set-executionpolicy unrestricted -Force But it does not seem to work...

Thanks

ashishpatel1992 commented 8 years ago

Hello, What is your system architecture? Try opening this file C:\Windows\SysWOW64\WindowsPowerShell\v1.0\ powershell.exe and execute the command set-executionpolicy unrestricted -Force

profesorfalken commented 8 years ago

Hi, Ok, I have done it and, after that, I have executed a test that runs the script using PowerShell:

This is the only code on TestPSScript.java:

public class TestPSScript{
    public static void main(String[] args) {
        System.out.println(com.profesorfalken.jpowershell.PowerShell.executeSingleCommand(args[0]).getCommandOutput());
    }
}

And this is the result:

PS C:\Users\Javier> set-executionpolicy unrestricted -Force
PS C:\Users\Javier> java TestPSScript .\temp.ps1
[
    [
        "InstanceName:TZ00_0",
        "CPU Temp:28øC"
    ],
    [
        "InstanceName:TZ01_0",
        "CPU Temp:30øC"
    ]
]

I have tested it on Windows 10 - 64 bits.

ashishpatel1992 commented 8 years ago

Hello, I am actually making a Web based project in Netbeans using JSP and Servlets. So if I use absolute path for script it gets changed on compilation of the project. Is there any possibility to write Script in a string variable and pass it to PowerShell?

profesorfalken commented 8 years ago

Hi,

I don't think so. Powershell console attends a command or a script file, not a script in a string.

Maybe the problem is that it cannot find the file. How have you implement it? Have you tried to test setting the file in a fixed place (Ex: c:/) instead of a project related path just to check if it is that the problem? Anyway, it is weird that you try to monitorize temperature in a web application. Are you trying to show in the web clients the temperature of the server machine?

Thanks

ashishpatel1992 commented 8 years ago

Ok For scripts I can execute using netbeans using relative or absolute path. But upon compilation a WAR file is generated the problem is that in war file the scripts dont get copied.

Assume my project name as TestPS and I made a folder TestPS\scripts\myscript.ps1 now upon compilation inside war file I cant find this file. Due to which I cannot distribute my project and have to manually copy at some path.

Also, I am building Web System Monitor project that allows user to monitor the PC by accessing that systems IP or domain name.

If people are interested in it I can make it on github! Well I am not a very good coder just started few months ago. So maybe my code goes poor at some places.

profesorfalken commented 8 years ago

Ok your project looks really interesting. Hope to see it one day on github.

Anyway, in your case you have many solutions.

-When constructing and deploying the project, it is quite easy to configure the deployment of resources. These can be deployed anywhere in the target system. This is easy to do with managements utils as Ant, Maven or Gradle. I do not know with Netbeans, but I think it uses Ant under the hood so it should be possible.

-Another easier solution is to generate each time a temp file with the script content and execute it. I am using this technique to get WMI data when using the VBS engine, for example. Here you are an example (executeScript method): https://github.com/profesorfalken/WMI4Java/blob/master/src/main/java/com/profesorfalken/wmi4java/WMIVBScript.java

ashishpatel1992 commented 8 years ago

Thanks for your solution and it seems more interesting to write temp file and execute the file. I recently figured out myself regarding adding files to scripts folder

Also, one more thing I have tested. Using jPowerShell takes more time to run than directly executing commands through Runtime.getRuntime().exec(".....");

Even more optimizing and faster solution was PS2EXE Using PS2EXE we can convert Powershell script as Exe File which is the fastest way till now I have figured out. But still I am looking for more faster solution that can get me details instantly.

profesorfalken commented 8 years ago

Ok, your solution to read the script looks right.

Regarding the Runtime.getRuntime().exec("....."), it is strange because jPowershell does more or less the same thing, but avoiding the hanging produced when you have to recover the output. Did it work to you using only the Runtime.getRuntime().exec(".....") ?? can you get the output of the command without problems?

I am not sure either about ps2exe... That tools simply wraps the script into binary code, but for the kind of script you want to execute, the 99.99% of time is taken by the OS to query the WMI registry, so you should not see any difference in performance. Have you performed microbenchmarks in order to compare that? In my case I had compare the jPowershell approach with a code that queried WMI directly using COM interface in C/C++ code and I did not notice any difference. I was also slow as hell, as any WMI query...

ashishpatel1992 commented 8 years ago

Yes I feel too that both does the same thing. But main Advantage is that JPowerShell Looks more modular and easy for novice users

Here is my code that I have tested using Runtime.getRuntime().exec("...")

Process proc = Runtime.getRuntime().exec("powershell.exe .\\scripts\\cpuTemp.ps1");
// OR 
//Process proc = Runtime.getRuntime().exec("powershell.exe Get-WmiObject -Class win32_bios|ConvertTo-Json");
        BufferedReader stdInput = new BufferedReader(new 
        InputStreamReader(proc.getInputStream()));

        BufferedReader stdError = new BufferedReader(new 
             InputStreamReader(proc.getErrorStream()));

        // read the output from the command
        System.out.println("Here is the standard output of the command:\n");
        String s = null;
        String text="";
        while ((s = stdInput.readLine()) != null) {
            text+=s;
        }
        System.out.println("FINAL OUTPUT:"+text);

        // read any errors from the attempted command
        System.out.println("Here is the standard error of the command (if any):\n");
        while ((s = stdError.readLine()) != null) {
            System.out.println(s);
        }

Yes you are right major time is taken by wmi script and the difference in time using Runtime and jPowerShell is just 400ms.

I think may be for more faster execution I should use JNA and write my own dll files to get the info.

Well this is my first Web based System Monitoring System Tool I still need to learn more and explore. I will add some feature to it.

I have one question in my mind I know its completly related to powershell but May be if you can help As you know to look any remote computer info in powershell we need to use -ComputerName and -Credential Eg.: Get-WmiObject -Class Win32_OperatingSystem -ComputerName XYZ-PC -Credential Username But problem with this is it asks for the password on Screen. I am looking for a way by which I can supply password itself in the command. If this is possible then I can make my System Monitor to Monitor any windows system on the network.

If you know a good solution to it let me know :+1:

profesorfalken commented 8 years ago

Euh..., I am more a linux guy and I do not really master powershell, but the first thing to come to my mind is to use a pipe:

echo "yourpassword" | Get-WmiObject -Class Win32_OperatingSystem -ComputerName XYZ-PC -Credential Username
ashishpatel1992 commented 8 years ago

That wont work because Windows pops up a Login Window like this. Also the command does not takes the pipeline input image We need to find out some other way to supress pop window and pass the password

profesorfalken commented 8 years ago

Ok in that case you have to Google to find a solution. Some links to start: http://www.computerperformance.co.uk/powershell/powershell_get_credential.htm https://www.reddit.com/r/PowerShell/comments/1f9pn0/prompt_for_credentials_without_a_dialog_box/

Since this is not related with jPowerShell support itself but with general Powershell usage that should be discussed in Powershell comunity forums. I close this issue.