/// <summary>
        /// Waits temporarily for the pending asynchronous BeginInvoke call to be completed.
        /// </summary>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see cref="Timeout.Infinite"/> (-1) to wait indefinitely. Beyond this limit, the <c>PooledJob</c>s that are still running are forcibly stopped.</param>
        /// <returns><value>true</value> if the pool receives a completion signal; otherwise, <value>false</value>.</returns>
        public bool EndInvoke(int millisecondsTimeout)
        {
            // The EndInvoke method should not be called if the pool is not either running or completed
            lock (_syncObject)
            {
                if (_invocationStateInfo.State != PooledPowershellInvocationState.Running && _invocationStateInfo.State != PooledPowershellInvocationState.Completed)
                    throw new PooledPowershellInvalidOperationException("The pool is either not running or not completed.");
            }

            bool signalReceived = _invokeAsyncResult.AsyncWaitHandle.WaitOne(millisecondsTimeout);
            _invokeAsyncResult.AsyncWaitHandle.Close();

            List<WaitHandle> stoppingJobsWaitHandles = new List<WaitHandle>();

            lock (_syncObject)
            {
                // Let's check if all the jobs are completed and if some aren't, let's stop them
                foreach (PooledJob job in _jobs.Values)
                {
                    // _executionHandler is set to null after job's completion (whatever it sucessed or failed)
                    // So if it's not null, the job is still running and must be stopped
                    if (job._executionHandler != null)
                    {
                        stoppingJobsWaitHandles.Add(job._ps.BeginStop(null, null).AsyncWaitHandle);
                        job._executionHandler = null;
                    }
                }
            }

            // Waiting for all the stop operations to complete
            if (stoppingJobsWaitHandles.Count > 0)
                WaitHandle.WaitAll(stoppingJobsWaitHandles.ToArray());

            lock (_syncObject)
            {
                _invocationStateInfo = new PooledPowershellInvocationStateInfo(PooledPowershellInvocationState.Completed);
            }

            return signalReceived;
        }
        /// <summary>
        /// Asynchronously runs the commands of the <c>PooledJob</c> objects pipeline by using a specified callback method to use when the invocation is complete.
        /// </summary>
        /// <param name="callback">An AsyncCallback delegate that is called when the command invoked by the method is complete.</param>
        /// <param name="state">A user-supplied state to use when the callback method is called.</param>
        /// <returns>An <c>IAsyncResult</c> interface that represents the status of the asynchronous operation. The <see cref="EndInvoke"/> method uses this interface to determine when to return the results of the operation.</returns>
        public IAsyncResult BeginInvoke(AsyncCallback callback, object state)
        {
            lock (_syncObject)
            {
                if (_isDisposed)
                    throw new PooledPowershellObjectDisposedException();

                if (_invocationStateInfo.State == PooledPowershellInvocationState.Running || _invocationStateInfo.State == PooledPowershellInvocationState.Stopping)
                    throw new PooledPowershellInvalidOperationException("The pool is already running.");

                _invokeAsyncResult = new PooledPowershellAsyncResult(_poolGuid, callback, state);
                _invocationStateInfo = new PooledPowershellInvocationStateInfo(PooledPowershellInvocationState.Running);


                foreach (PooledJob job in _jobs.Values)
                    job._executionHandler = job._ps.BeginInvoke((PSDataCollection<PSObject>)null, (PSInvocationSettings)null, _PSCallback, job.InstanceId);
            }

            return (IAsyncResult)_invokeAsyncResult;
        }
        /// <summary>
        /// Method called by the object after each <c>PooledJob</c> has completed.
        /// </summary>
        /// <param name="asyncResult">The result of the asynchronous operation. Must actually contain the <c>PooledJob</c>'s Guid.</param>
        private void _PSCallback(IAsyncResult asyncResult)
        {
            lock (_syncObject)
            {
                PooledJob job = _jobs[(Guid)asyncResult.AsyncState];

                if (asyncResult.IsCompleted)
                {
                    try
                    {
                        job._result = job._ps.EndInvoke(job._executionHandler);
                    }
                    catch
                    {
                        /* Nothing to do. */
                    }
                    finally
                    {
                        job._executionHandler = null;
                        asyncResult.AsyncWaitHandle.Close();
                        _invokeAsyncResult._endedJobs++;

                        if (_invokeAsyncResult._endedJobs == _jobs.Count)
                        {
                            _invokeAsyncResult.SetAsCompleted(null);
                            _invocationStateInfo = new PooledPowershellInvocationStateInfo(PooledPowershellInvocationState.Completed);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Removes all the jobs from the pool.
        /// </summary>
        /// <remarks>When calling this method, the underlying PowerShell pipelines will be disposed.</remarks>
        public void Purge()
        {
            lock (_syncObject)
            {
                if (_invocationStateInfo.State == PooledPowershellInvocationState.Running || _invocationStateInfo.State == PooledPowershellInvocationState.Stopping)
                    throw new PooledPowershellInvalidOperationException("The pool is running. You must stop the pool prior to purge it.");

                _invocationStateInfo = new PooledPowershellInvocationStateInfo();


                foreach (PooledJob job in _jobs.Values)
                {
                    job._ps.RunspacePool = null;
                    job._ps.Dispose();
                }

                _jobs.Clear();
            }
        }