IProcess::read() returns no StdOut or StdErr from web service

Discussion about using the VirtualBox API, Tutorials, Samples.
Post Reply
SmithersTheOracle
Posts: 60
Joined: 28. Dec 2019, 08:58
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Windows, Linux

IProcess::read() returns no StdOut or StdErr from web service

Post by SmithersTheOracle »

I've been working on the VirtualBox PowerShell module and I've been having a problem returning anything from IProcess::read(). Is this something that won't work when using the web service? I'm not getting any errors and the process terminates normally. The guest OS is Windows Server 2016 and the process I'm creating is 'cmd.exe' with the arguments '/c','ping','127.0.0.1'. I think I've followed noteirak's "Run Guest Process and Read Stdout - Java" example as faithfully as possible considering this is PowerShell and I'm using the web service instead of the COM. Only difference is I've expanded on it a little bit to see what else I can get out of it, but it didn't work before I added any of that either.

For reference, the function can be found here:
https://github.com/SmithersTheOracle/Vi ... psm1#L6300

and the loop containing the IProcess::read() call is here:
https://github.com/SmithersTheOracle/Vi ... psm1#L6510

I'm also outputting the $readstdout variable to verbose output every loop and it's showing up empty. My call to this function is this:

Code: Select all

Submit-VirtualBoxVMProcess -Name $machinename -PathToExecutable 'cmd.exe' -Arguments '/c','ping','127.0.0.1' -Credential $serv2016creds -StdOut -StdErr -Verbose
SmithersTheOracle
Posts: 60
Joined: 28. Dec 2019, 08:58
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Windows, Linux

Re: IProcess::read() returns no StdOut or StdErr from web service

Post by SmithersTheOracle »

I've been rewriting the module (offline) to work with the VirtualBox.VirtualBox COM object, when requested on import, and completed changing my Submit-VirtualBoxVMProcess function. I can now confirm that I'm seeing the same issue when using the COM. Therefore, this isn't localized to the web service. It must be something I'm doing wrong. Has anyone gotten this to work? Would you mind posting a sample of code? Any language will work (C, C++, Java, Python, etc.). I'll do the translation to PowerShell if needed.
Magnus Madsen
Posts: 22
Joined: 11. Jun 2013, 08:35
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: WinXP, WinVista, Win7, Win8

Re: IProcess::read() returns no StdOut or StdErr from web service

Post by Magnus Madsen »

Hi!

I believe the issue is the arguments you provide to IGuestSession_processCreate on line 6440: https://github.com/SmithersTheOracle/Vi ... psm1#L6440

You provide a single argument (ProcessCreateFlag.Hidden) however to read StdOut or StdErr from the process you must also provide the ProcessCreateFlag.WaitForStdOut and/or ProcessCreateFlag.WaitForStdErr.

Take a look at the relevant section from the SDK documentation:
6.85 ProcessCreateFlag
Guest process execution flags.
WaitForProcessStartOnly Only use the specified timeout value to wait for starting the guest
process - the guest process itself then uses an infinite timeout.
IgnoreOrphanedProcesses Do not report an error when executed processes are still alive
when VBoxService or the guest OS is shutting down.
Hidden Do not show the started process according to the guest OS guidelines.
Profile Utilize the user’s profile data when exeuting a process. Only available for Windows
guests at the moment.
WaitForStdOut The guest process waits until all data from stdout is read out.
WaitForStdErr The guest process waits until all data from stderr is read out.
Bitwise operations seem difficult in PowerShell, so I'm not certain how to combine the flags with the method you use

Code: Select all

$Global:processcreateflag.ToInt('Hidden')

but it should work with the correct value.

Also looking at your definition of ProcessCreateFlag the values aren't correct in regards to the COM api (I do not know if they differ for the Web API, but I would assume not)

Code: Select all

            Switch ($FromStr) {
                'None'                    {$ToInt = 0} # No flag set
                'WaitForProcessStartOnly' {$ToInt = 1} # Only use the specified timeout value to wait for starting the guest process - the guest process itself then uses an infinite timeout.
                'IgnoreOrphanedProcesses' {$ToInt = 2} # Do not report an error when executed processes are still alive when VBoxService or the guest OS is shutting down.
                'Hidden'                  {$ToInt = 3} # Do not show the started process according to the guest OS guidelines.
                'Profile'                 {$ToInt = 4} # Utilize the user’s profile data when exeuting a process. Only available for Windows guests at the moment.
                'WaitForStdOut'           {$ToInt = 5} # The guest process waits until all data from stdout is read out.
                'WaitForStdErr'           {$ToInt = 6} # The guest process waits until all data from stderr is read out.
                'ExpandArguments'         {$ToInt = 7} # Expands environment variables in process arguments. ***Note: This is not yet implemented and is currently silently ignored. We will document the protocolVersion number for this feature once it appears, so don’t use it till then.
                'UnquotedArguments'       {$ToInt = 8} # Work around for Windows and OS/2 applications not following normal argument quoting and escaping rules. The arguments are passed to the application without any extra quoting, just a single space between each. ***Note: Present since VirtualBox 4.3.28 and 5.0 beta 3.
                Default                   {$ToInt = 0} # Default to 0.
            }
where the COM definition is as follows (bitwise flags)

Code: Select all

    public enum ProcessCreateFlag
    {
        ProcessCreateFlag_None = 0,
        ProcessCreateFlag_WaitForProcessStartOnly = 1,
        ProcessCreateFlag_IgnoreOrphanedProcesses = 2,
        ProcessCreateFlag_Hidden = 4,
        ProcessCreateFlag_Profile = 8,
        ProcessCreateFlag_WaitForStdOut = 16,
        ProcessCreateFlag_WaitForStdErr = 32,
        ProcessCreateFlag_ExpandArguments = 64,
        ProcessCreateFlag_UnquotedArguments = 128
    }
Combining the flags, if you want the process to be hidden and to redirect both StdOut and StdErr, the correct value should be (4 + 16 + 32) == 52
SmithersTheOracle
Posts: 60
Joined: 28. Dec 2019, 08:58
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Windows, Linux

Re: IProcess::read() returns no StdOut or StdErr from web service

Post by SmithersTheOracle »

Hey Magnus, thanks for the reply. To sum up what you've asked about with the definition of ProcessCreateFlag, it's a "translator" class I built based on the 6.1.0 SDKRef.pdf page 418. I've been trying to avoid using the built-in classes/enums because the basic Windows COM object doesn't include them. Also, I just found out within the last 24 hours that PowerShell supports enums as of v5.0 when they started supporting classes. :oops:

I know I could use them for the web service because they're built into the WSDL file, but that's a 3MB file which takes ~1 minute to import as a web service proxy (depending on the computer, of course). Therefor, I've undergone the task of coming up with ways to get around using them. (If anyone has a better way I'm not shy about being wrong)

The comments you see in the ProcessCreateFlag class are actually copy/pasted directly from the SDKRef. As I stated in the first post, I got the general outline of how this works from noteirak's "Run Guest Process and Read Stdout - Java" example.

As for using multiple flags, the SDKRef shows it takes an array... which brings me to: HOW DID I MISS THIS?! I was reading the documentation to mean that it would run the process create synchronously which would wait until the process completes before I get anything. Noteirak's example even shows the use of the WaitForStdOut flag.

I figured it was something simple I missed. Thank you so much! I'll fix this immediately and upload it from where it's at so far.
SmithersTheOracle
Posts: 60
Joined: 28. Dec 2019, 08:58
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Windows, Linux

Re: IProcess::read() returns no StdOut or StdErr from web service

Post by SmithersTheOracle »

Also had to throw in a conversion from base64. Quick snip of it working :D :

Code: Select all

PS C:\> Submit-VirtualBoxVMProcess -Name $machinename -PathToExecutable 'cmd.exe' -Arguments '/c','ping','127.0.0.1' -Credential $serv2016creds -StdOut -StdErr

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms
SmithersTheOracle
Posts: 60
Joined: 28. Dec 2019, 08:58
Primary OS: MS Windows 7
VBox Version: PUEL
Guest OSses: Windows, Linux

Re: IProcess::read() returns no StdOut or StdErr from web service

Post by SmithersTheOracle »

I've been working on cleanup, but I finally got back to working on the COM side of things. Thanks again for the enum definition. The whole thing's working now. There's so many different definitions and craziness in the API between languages. I'm really grateful for your help.
Post Reply