public void InitializeProvider(PsRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            request.Debug("Initializing PowerShell MetaProvider");

            //During the initialization, we load the PowerShellGet only to speeding up a little bit
            var psModules = ScanForPowerShellGetModule(request).WhereNotNull();

            foreach (var psModule in psModules)
            {
                //Check if the PowerShellGet provider exists
                if ((psModule.Key != null) && (psModule.Value != null))
                {
                    //load the PowerShellGet
                    AnalyzeModule(request, psModule.Key, psModule.Value.Version ?? new Version(0, 0), false, psModule.Value);
                }
            }

            if (_availableProviders.ContainsKey(PowerShellGet))
            {
                request.Debug("Loaded PowerShell Provider: PowerShellGet");
            }
            else
            {
                //if we can not load PowerShellGet, we do not fail the initialization
                request.Verbose(string.Format(CultureInfo.CurrentCulture, Resources.Messages.ModuleNotFound, PowerShellGet));
            }
        }
        // lock is on this instance only

        internal void ReportErrors(PsRequest request, IEnumerable <ErrorRecord> errors)
        {
            foreach (var error in errors)
            {
                request.Error(error.FullyQualifiedErrorId, error.CategoryInfo.Category.ToString(), error.TargetObject == null ? null : error.TargetObject.ToString(), error.ErrorDetails == null ? error.Exception.Message : error.ErrorDetails.Message);
                if (!string.IsNullOrWhiteSpace(error.Exception.StackTrace))
                {
                    // give a debug hint if we have a script stack trace. How nice of us.
                    // the exception stack trace gives better stack than the script stack trace
                    request.Debug(Constants.ScriptStackTrace, error.Exception.StackTrace);
                }
            }
        }
        private IEnumerable <KeyValuePair <string, PSModuleInfo> > ScanPrivateDataForProviders(PsRequest request, string baseFolder, Hashtable privateData, PSModuleInfo moduleInfo)
        {
            var providers = privateData.GetStringCollection("PackageManagementProviders").ReEnumerable();

            if (providers.Any())
            {
                // found a module that is advertizing one or more  Providers.

                foreach (var provider in providers)
                {
                    var fullPath = provider;
                    try {
                        if (!Path.IsPathRooted(provider))
                        {
                            fullPath = Path.GetFullPath(Path.Combine(baseFolder, provider));
                        }
                    } catch {
                        // got an error from the path.
                        continue;
                    }
                    if (Directory.Exists(fullPath) || File.Exists(fullPath))
                    {
                        // looks like we have something that could definitely be a
                        // a module path.
                        var result = new KeyValuePair <string, PSModuleInfo>(fullPath, moduleInfo);
                        AddToPowerShellProviderCacheTable(result);
                        yield return(result);
                    }
                    else
                    {
                        request.Verbose(string.Format(CultureInfo.CurrentCulture, Resources.Messages.FileNotFound, fullPath));
                    }
                }
            }
            else
            {
                request.Debug(string.Format(Resources.Messages.PackageManagementProvidersNotFound, baseFolder));
            }
        }
        internal object CallPowerShell(PsRequest request, params object[] args) {
            // the lock ensures that we're not re-entrant into the same powershell runspace
            lock (_lock) {
                if (!_reentrancyLock.WaitOne(0)) {
                    // this lock is set to false, meaning we're still in a call **ON THIS THREAD**
                    // this is bad karma -- powershell won't let us call into the runspace again
                    // we're going to throw an error here because this indicates that the currently
                    // running powershell call is calling back into PM, and it has called back
                    // into this provider. That's just bad bad bad.
                    throw new Exception("Reentrancy Violation in powershell module");
                }
                
                try {
                    // otherwise, this is the first time we've been here during this call.
                    _reentrancyLock.Reset();

                    _powershell.SetVariable("request", request);
                    _powershell.Streams.ClearStreams();

                    object finalValue = null;
                    ConcurrentBag<ErrorRecord> errors = new ConcurrentBag<ErrorRecord>();

                    request.Debug("INVOKING PowerShell Fn {0} with args {1} that has length {2}", request.CommandInfo.Name, String.Join(", ", args), args.Length);

                    var result = _powershell.InvokeFunction<object>(request.CommandInfo.Name,
                        (sender, e) => output_DataAdded(sender, e, request, ref finalValue),
                        (sender, e) => error_DataAdded(sender, e, request, errors),
                        args);

                    if (result == null)
                    {
                        // result is null but it does not mean that the call fails because the command may return nothing
                        request.Debug(Messages.PowershellScriptFunctionReturnsNull.format(_module.Name, request.CommandInfo.Name));
                    }

                    if (errors.Count > 0)
                    {
                        // report the error if there are any
                        ReportErrors(request, errors);
                        _powershell.Streams.Error.Clear();
                    }

                    return finalValue;
                } catch (CmdletInvocationException cie) {
                    var error = cie.ErrorRecord;
                    request.Error(error.FullyQualifiedErrorId, error.CategoryInfo.Category.ToString(), error.TargetObject == null ? null : error.TargetObject.ToString(), error.ErrorDetails == null ? error.Exception.Message : error.ErrorDetails.Message);
                } finally {
                    lock (_stopLock) {
                        if (_stopResult != null){
                            _powershell.EndStop(_stopResult);
                            _stopResult = null;
                        }
                    }
                    _powershell.Clear();
                    _powershell.SetVariable("request", null);
                    // it's ok if someone else calls into this module now.
                    request.Debug("Done calling powershell", request.CommandInfo.Name, _module.Name);
                    _reentrancyLock.Set();
                }

                return null;
            }
        }
        // lock is on this instance only

        internal void ReportErrors(PsRequest request, IEnumerable<ErrorRecord> errors) {
            foreach (var error in errors) {
                request.Error(error.FullyQualifiedErrorId, error.CategoryInfo.Category.ToString(), error.TargetObject == null ? null : error.TargetObject.ToString(), error.ErrorDetails == null ? error.Exception.Message : error.ErrorDetails.Message);
                if (!string.IsNullOrWhiteSpace(error.Exception.StackTrace)) {
                    // give a debug hint if we have a script stack trace. How nice of us.
                    // the exception stack trace gives better stack than the script stack trace
                    request.Debug(Constants.ScriptStackTrace, error.Exception.StackTrace);
                }
            }
        }
        private PackageProvider AnalyzeModule(PsRequest request, string modulePath, Version requiredVersion, bool force, bool logWarning =true, PSModuleInfo psModuleInfo = null)
        {
            if (string.IsNullOrWhiteSpace(modulePath)) {
                return null;
            }

            request.Debug("Attempting to load PowerShell Provider Module [{0}]", modulePath);

            if (string.Equals(Path.GetExtension(modulePath), ".dll", StringComparison.OrdinalIgnoreCase))
            {
                if (psModuleInfo != null)
                {
                    // fake provider and returns it
                    var result = new PackageProvider(new DefaultPackageProvider(psModuleInfo.Name, psModuleInfo.Version.ToString()))
                    {
                        ProviderPath = modulePath,
                        Version = psModuleInfo.Version,
                        IsLoaded = false
                    };

                    AddToPackageProviderCacheTable(result);

                    return result;
                }
                else
                {
                    // psmoduleinfo is only null when this function is called in loadavailableprovider
                    // but in that case we want to load the provider directly anyway so we can do this
                    // if the path is a .dll then we ask packagemanagement to load it for us
                    // it will also register the dll
                    PackageManagementService.LoadProviderAssembly(request, modulePath, true);

                    // now let's checked whether we can find it in the list of loaded providers
                    foreach (var loadedProvider in PackageManagementService.PackageProviders)
                    {
                        // the one loaded should have the same path
                        if (string.Equals(loadedProvider.ProviderPath, modulePath, StringComparison.OrdinalIgnoreCase))
                        {
                            return loadedProvider;
                        }
                    }

                    // if we reached here then we have failed to load the provider :(
                    return null;
                }                
            }

            string requiredVersionString = requiredVersion.ToString();
            var provider = Create(request, modulePath, requiredVersionString, force, logWarning);
            if (provider != null) {
                var providerName = provider.GetPackageProviderName();
                if (!string.IsNullOrWhiteSpace(providerName)) {
                    request.Debug(string.Format(CultureInfo.CurrentCulture, Resources.Messages.SuccessfullyLoadedModule, modulePath));
                    // looks good to me, let's add this to the list of modules this meta provider can create.

                    var packageProvider = new PackageProvider(provider.As<IPackageProvider>()) {
                        IsLoaded = true,
                        Version = provider.GetProviderVersion(),
                        ProviderPath = modulePath
                    };

                    // take out powershell get
                    var psgetprovider = PackageManagementService.PackageProviders.FirstOrDefault(pv => string.Equals(pv.ProviderName, PowerShellGet, StringComparison.OrdinalIgnoreCase));

                    if (psModuleInfo != null)
                    {
                        // add swidtag information using moduleinfo
                        // however, this won't give us as much information yet
                        // we may have to fill this up later
                        ProvideSwidTagInformation(packageProvider, psModuleInfo);
                    }
                    
                    AddToPackageProviderCacheTable(packageProvider);
                    _availableProviders.AddOrSet(providerName, provider);

                    return packageProvider;
                } else {
                    provider.Dispose();
                    provider = null;
                    request.Debug(string.Format(CultureInfo.CurrentCulture, Resources.Messages.ProviderNameIsNullOrEmpty, modulePath));
                }
            }
            return null;
        }
        public void InitializeProvider(PsRequest request) {
            if (request == null) {
                throw new ArgumentNullException("request");
            }

            request.Debug("Initializing PowerShell MetaProvider");

            //During the initialization, we load the PowerShellGet only to speeding up a little bit 
            var psModules = ScanForPowerShellGetModule(request).WhereNotNull();

            foreach (var psModule in psModules) {
                //Check if the PowerShellGet provider exists
                if ((psModule.Key != null) && (psModule.Value != null)) {
                    //load the PowerShellGet
                    AnalyzeModule(request, psModule.Key, psModule.Value.Version ?? new Version(0, 0), false, true, psModule.Value);
                }
            }

            if (_availableProviders.ContainsKey(PowerShellGet))
            {
                request.Debug("Loaded PowerShell Provider: PowerShellGet");
            }
            else
            {
                //if we can not load PowerShellGet, we do not fail the initialization
                request.Verbose(string.Format(CultureInfo.CurrentCulture, Resources.Messages.ModuleNotFound, PowerShellGet));
            }
        }
        private IEnumerable<KeyValuePair<string,PSModuleInfo>> ScanPrivateDataForProviders(PsRequest request, string baseFolder, Hashtable privateData, PSModuleInfo moduleInfo) {
            var providers = privateData.GetStringCollection("PackageManagementProviders").ReEnumerable();
            if (providers.Any()) {
                // found a module that is advertizing one or more  Providers.

                foreach (var provider in providers) {
                    var fullPath = provider;
                    try {
                        if (!Path.IsPathRooted(provider)) {
                            fullPath = Path.GetFullPath(Path.Combine(baseFolder, provider));
                        }
                    } catch {
                        // got an error from the path.
                        continue;
                    }
                    if (Directory.Exists(fullPath) || File.Exists(fullPath)) {
                        // looks like we have something that could definitely be a
                        // a module path.
                        var result = new KeyValuePair<string, PSModuleInfo>(fullPath, moduleInfo);
                        AddToPowerShellProviderCacheTable(result);
                        yield return result;
                    } else {
                        request.Verbose(string.Format(CultureInfo.CurrentCulture, Resources.Messages.FileNotFound, fullPath));
                    }
                }
            } else {
                request.Debug(string.Format(Resources.Messages.PackageManagementProvidersNotFound, baseFolder));
            }
        }
        private PackageProvider AnalyzeModule(PsRequest request, string modulePath, Version requiredVersion, bool force, PSModuleInfo psModuleInfo = null)
        {
            if (string.IsNullOrWhiteSpace(modulePath))
            {
                return(null);
            }

            request.Debug("Attempting to load PowerShell Provider Module [{0}]", modulePath);

            if (string.Equals(Path.GetExtension(modulePath), ".dll", StringComparison.OrdinalIgnoreCase))
            {
                if (psModuleInfo != null)
                {
                    // fake provider and returns it
                    var result = new PackageProvider(new DefaultPackageProvider(psModuleInfo.Name, psModuleInfo.Version.ToString()))
                    {
                        ProviderPath = modulePath,
                        Version      = psModuleInfo.Version,
                        IsLoaded     = false
                    };

                    AddToPackageProviderCacheTable(result);

                    return(result);
                }
                else
                {
                    // psmoduleinfo is only null when this function is called in loadavailableprovider
                    // but in that case we want to load the provider directly anyway so we can do this
                    // if the path is a .dll then we ask packagemanagement to load it for us
                    // it will also register the dll
                    PackageManagementService.LoadProviderAssembly(request, modulePath, true);

                    // now let's checked whether we can find it in the list of loaded providers
                    foreach (var loadedProvider in PackageManagementService.PackageProviders)
                    {
                        // the one loaded should have the same path
                        if (string.Equals(loadedProvider.ProviderPath, modulePath, StringComparison.OrdinalIgnoreCase))
                        {
                            return(loadedProvider);
                        }
                    }

                    // if we reached here then we have failed to load the provider :(
                    return(null);
                }
            }

            string requiredVersionString = requiredVersion.ToString();
            var    provider = Create(request, modulePath, requiredVersionString, force);

            if (provider != null)
            {
                var providerName = provider.GetPackageProviderName();
                if (!string.IsNullOrWhiteSpace(providerName))
                {
                    request.Debug(string.Format(CultureInfo.CurrentCulture, Resources.Messages.SuccessfullyLoadedModule, modulePath));
                    // looks good to me, let's add this to the list of moduels this meta provider can create.

                    var packageProvider = new PackageProvider(provider.As <IPackageProvider>())
                    {
                        IsLoaded     = true,
                        Version      = provider.GetProviderVersion(),
                        ProviderPath = modulePath
                    };

                    // take out powershell get
                    var psgetprovider = PackageManagementService.PackageProviders.FirstOrDefault(pv => string.Equals(pv.ProviderName, PowerShellGet, StringComparison.OrdinalIgnoreCase));

                    if (psModuleInfo != null)
                    {
                        // add swidtag information using moduleinfo
                        // however, this won't give us as much information yet
                        // we may have to fill this up later
                        ProvideSwidTagInformation(packageProvider, psModuleInfo);
                    }

                    AddToPackageProviderCacheTable(packageProvider);
                    _availableProviders.AddOrSet(providerName, provider);

                    return(packageProvider);
                }
                else
                {
                    provider.Dispose();
                    provider = null;
                    request.Debug(string.Format(CultureInfo.CurrentCulture, Resources.Messages.ProviderNameIsNullOrEmpty, modulePath));
                }
            }
            return(null);
        }
        internal object CallPowerShell(PsRequest request, params object[] args)
        {
            // the lock ensures that we're not re-entrant into the same powershell runspace
            lock (_lock) {
                if (!_reentrancyLock.WaitOne(0))
                {
                    // this lock is set to false, meaning we're still in a call **ON THIS THREAD**
                    // this is bad karma -- powershell won't let us call into the runspace again
                    // we're going to throw an error here because this indicates that the currently
                    // running powershell call is calling back into PM, and it has called back
                    // into this provider. That's just bad bad bad.
                    throw new Exception("Reentrancy Violation in powershell module");
                }

                try {
                    // otherwise, this is the first time we've been here during this call.
                    _reentrancyLock.Reset();

                    _powershell.SetVariable("request", request);
                    _powershell.Streams.ClearStreams();

                    object finalValue = null;
                    ConcurrentBag <ErrorRecord> errors = new ConcurrentBag <ErrorRecord>();

                    request.Debug("INVOKING PowerShell Fn {0} with args {1} that has length {2}", request.CommandInfo.Name, String.Join(", ", args), args.Length);

                    var result = _powershell.InvokeFunction <object>(request.CommandInfo.Name,
                                                                     (sender, e) => output_DataAdded(sender, e, request, ref finalValue),
                                                                     (sender, e) => error_DataAdded(sender, e, request, errors),
                                                                     args);

                    if (result == null)
                    {
                        // result is null but it does not mean that the call fails because the command may return nothing
                        request.Debug(Messages.PowershellScriptFunctionReturnsNull.format(_module.Name, request.CommandInfo.Name));
                    }

                    if (errors.Count > 0)
                    {
                        // report the error if there are any
                        ReportErrors(request, errors);
                        _powershell.Streams.Error.Clear();
                    }

                    return(finalValue);
                } catch (CmdletInvocationException cie) {
                    var error = cie.ErrorRecord;
                    request.Error(error.FullyQualifiedErrorId, error.CategoryInfo.Category.ToString(), error.TargetObject == null ? null : error.TargetObject.ToString(), error.ErrorDetails == null ? error.Exception.Message : error.ErrorDetails.Message);
                } finally {
                    lock (_stopLock) {
                        if (_stopResult != null)
                        {
                            _powershell.EndStop(_stopResult);
                            _stopResult = null;
                        }
                    }
                    _powershell.Clear();
                    _powershell.SetVariable("request", null);
                    // it's ok if someone else calls into this module now.
                    request.Debug("Done calling powershell", request.CommandInfo.Name, _module.Name);
                    _reentrancyLock.Set();
                }

                return(null);
            }
        }
        private PackageProvider AnalyzeModule(PsRequest request, string modulePath, Version requiredVersion, bool force)
        {
            if (string.IsNullOrWhiteSpace(modulePath)) {
                return null;
            }
            request.Debug("Attempting to load PowerShell Provider Module [{0}]", modulePath);
            var provider = Create(request, modulePath, requiredVersion.ToString(), force);
            if (provider != null) {
                var providerName = provider.GetPackageProviderName();
                if (!string.IsNullOrWhiteSpace(providerName)) {
                    request.Debug(string.Format(CultureInfo.CurrentCulture, Resources.Messages.SuccessfullyLoadedModule, modulePath));
                    // looks good to me, let's add this to the list of moduels this meta provider can create.

                    var packageProvider = new PackageProvider(provider.As<IPackageProvider>()) {
                        IsLoaded = true,
                        Version = provider.GetProviderVersion(),
                        ProviderPath = modulePath
                    };

                    AddToPackageProviderCacheTable(packageProvider);
                    _availableProviders.AddOrSet(providerName, provider);

                    return packageProvider;
                } else {
                    provider.Dispose();
                    provider = null;
                    request.Debug(string.Format(CultureInfo.CurrentCulture, Resources.Messages.ProviderNameIsNullOrEmpty, modulePath));
                }
            }
            return null;
        }
        private PowerShellPackageProvider Create(PsRequest request, string modulePath, string requiredVersion, bool force) {
            var ps = PowerShell.Create();
            try {
                // load the powershell provider functions into this runspace.
                if (ps.ImportModule(PowerShellProviderFunctions, false) != null) {
                    var result = ps.ImportModule(modulePath, force);
                    if (result != null) {
                        try {
                            return new PowerShellPackageProvider(ps, result, requiredVersion);
                        } catch (Exception e) {
                            e.Dump();
                        }
                    }
                }
            } catch (Exception e) {
                // something didn't go well.
                // skip it.
                e.Dump();
                request.Debug(e.Message);
            }

            // didn't import correctly.
            ps.Dispose();
            return null;
        }