public async Task <IEnumerable <IEndpointInfo> > GetEndpointInfoAsync(CancellationToken token)
        {
            var endpointInfos = await _source.GetEndpointInfoAsync(token);

            // Apply process ID filter
            if (_processIdToFilterOut.HasValue)
            {
                endpointInfos = endpointInfos.Where(info => info.ProcessId != _processIdToFilterOut.Value);
            }

            // Apply runtime instance cookie filter
            if (_runtimeInstanceCookieToFilterOut.HasValue)
            {
                endpointInfos = endpointInfos.Where(info => info.RuntimeInstanceCookie != _runtimeInstanceCookieToFilterOut.Value);
            }

            return(endpointInfos);
        }
        public async Task <IEnumerable <IProcessInfo> > GetProcessesAsync(DiagProcessFilter processFilterConfig, CancellationToken token)
        {
            IEnumerable <IProcessInfo> processes = null;

            try
            {
                using CancellationTokenSource extendedInfoCancellation = CancellationTokenSource.CreateLinkedTokenSource(token);
                IList <Task <IProcessInfo> > processInfoTasks = new List <Task <IProcessInfo> >();
                foreach (IEndpointInfo endpointInfo in await _endpointInfoSource.GetEndpointInfoAsync(token))
                {
                    // CONSIDER: Can this processing be pushed into the IEndpointInfoSource implementation and cached
                    // so that extended process information doesn't have to be recalculated for every call. This would be
                    // useful for:
                    // - .NET Core 3.1 processes, which require issuing a brief event pipe session to get the process commmand
                    //   line information and parse out the process name
                    // - Caching entrypoint information (when that becomes available).
                    processInfoTasks.Add(ProcessInfoImpl.FromEndpointInfoAsync(endpointInfo, extendedInfoCancellation.Token));
                }

                // FromEndpointInfoAsync can fill in the command line for .NET Core 3.1 processes by invoking the
                // event pipe and capturing the ProcessInfo event. Timebox this operation with the cancellation token
                // so that getting the process list does not take a long time or wait indefinitely.
                extendedInfoCancellation.CancelAfter(ProcessInfoImpl.ExtendedProcessInfoTimeout);

                await Task.WhenAll(processInfoTasks);

                processes = processInfoTasks.Select(t => t.Result);
            }
            catch (UnauthorizedAccessException)
            {
                throw new InvalidOperationException(Strings.ErrorMessage_ProcessEnumeratuinFailed);
            }

            if (processFilterConfig != null)
            {
                processes = processes.Where(p => processFilterConfig.Filters.All(c => c.MatchFilter(p)));
            }

            return(processes.ToArray());
        }