protected virtual bool YieldDetails(PsRequest r) { if (_details != null && _details.Count > 0) { // we need to send this back as a set of key/path & value pairs. return _details.Flatten().All(kvp => r.YieldKeyValuePair(kvp.Key, kvp.Value)); } return true; }
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 IEnumerable<object> LoadAvailableProvider(PsRequest request, string modulePath, Version requiredVersion, bool force) { if (request == null) { throw new ArgumentNullException("request"); } if (string.IsNullOrEmpty(modulePath)) { throw new ArgumentNullException("modulePath"); } EnsurePowerShellInitialized(); //Check if it is already in the cache table var providersAlreadyImported = FindMatchedProvidersFromInternalCacheTable(request, modulePath).ToArray(); if (providersAlreadyImported.Any() && !force) { return providersAlreadyImported; } //Trying to load it from the path directly var pkgProvider = AnalyzeModule(request, modulePath, requiredVersion ?? new Version(0, 0), force); if (pkgProvider != null) { return new[] { pkgProvider }.WhereNotNull(); } request.Error(PackageManagement.Internal.Constants.Messages.FailedToImportProvider, ErrorCategory.InvalidOperation.ToString(), PowerShellGet, string.Format(CultureInfo.CurrentCulture, Resources.Messages.FailedToImportProvider, modulePath)); return Enumerable.Empty<PackageProvider>(); }
private IEnumerable<PackageProvider> FindMatchedProvidersFromInternalCacheTable(PsRequest request, string providerPath) { //Search from the internal table to see if we can the matched provider var providers = PackageManagementService.ProviderCacheTable .Select(each => each.Value).Select(list => list .Where(each => each.ProviderPath.EqualsIgnoreCase(providerPath) && each.IsLoaded) .Select(each => each)); return providers.SelectMany(list => { var packageProviders = list as PackageProvider[] ?? list.ToArray(); return packageProviders; }); }
public void RefreshProviders(PsRequest request, string providerName, Version requiredVersion, Version minimumVersion, Version maximumVersion, bool logWarning) { //find and load the latest versions of the providers if only providerName exists, e.g., get-pp -name or import-pp -name //find and load the particular provider if both providerName and version are provided _psProviderCacheTable.Clear(); EnsurePowerShellInitialized(); if (!string.IsNullOrWhiteSpace(providerName)) { //Get the list of available providers var modules = ScanForModules(request, requiredVersion, minimumVersion, maximumVersion, ProviderOption.AllProvider).ReEnumerable(); var tasks = modules.AsyncForEach(modulePath => AnalyzeModule(request, modulePath.Key, modulePath.Value.Version ?? new Version(0, 0), false, logWarning, modulePath.Value)); tasks.WaitAll(); } else { //find all providers but only load the latest if no name nor version exists, e.g. get-pp -list //Scan for the all available providers var results = ScanForModules(request, null, null, null, ProviderOption.AllProvider).ToArray(); if (!_psProviderCacheTable.Any()) { return; } foreach (var list in _psProviderCacheTable.Values.WhereNotNull()) { var psInfo = list.OrderByDescending(each => each.ModuleInfo.Version).ToArray(); if (!psInfo.Any()) { continue; } PackageProvider pkgProvider = null; for (var index = 0; index < psInfo.Length; index++) { var providerItem = psInfo[index]; if (providerItem == null) { continue; } // if the provider is a dll, we will just provide a default provider, assuming the module name will be the name of the provider and add to the cache table (if it is not already loaded) if (string.Equals(Path.GetExtension(providerItem.ProviderPath), ".dll", StringComparison.OrdinalIgnoreCase)) { // check whether it is already loaded or not var loadedProvider = PackageManagementService.PackageProviders.FirstOrDefault(item => string.Equals(item.ProviderPath, providerItem.ProviderPath, StringComparison.OrdinalIgnoreCase)); // only provide default provider if it is not loaded if (loadedProvider == null) { // here moduleinfo.providercategory is the module name. // we are applying the guideline that module name is the same as provider name so we use that as the provider name AddToPackageProviderCacheTable(new PackageProvider(new DefaultPackageProvider(providerItem.ModuleInfo.Name, providerItem.ModuleInfo.Version.ToString())) { ProviderPath = providerItem.ProviderPath, Version = providerItem.ModuleInfo.Version, IsLoaded = false }); } continue; } //load the provider that has the latest version if (pkgProvider == null) { // analyze the module pkgProvider = AnalyzeModule(request, providerItem.ProviderPath, providerItem.ModuleInfo.Version, false, logWarning, providerItem.ModuleInfo); } else { //the rest of providers under the same module will just create a provider object for the output but not loaded var packageProvider = new PackageProvider(new DefaultPackageProvider(pkgProvider.ProviderName, providerItem.ModuleInfo.Version.ToString())) { ProviderPath = providerItem.ProviderPath, Version = providerItem.ModuleInfo.Version, IsLoaded = false }; AddToPackageProviderCacheTable(packageProvider); } } } _psProviderCacheTable.Clear(); } }
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 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 void error_DataAdded(object sender, DataAddedEventArgs e, PsRequest request, ConcurrentBag<ErrorRecord> errors) { PSDataCollection<ErrorRecord> errorStream = sender as PSDataCollection<ErrorRecord>; if (errorStream == null) { return; } var error = errorStream[e.Index]; if (error != null) { // add the error so we can report them later errors.Add(error); } }
private IEnumerable<KeyValuePair<string, PSModuleInfo>> ScanForPowerShellGetModule(PsRequest request) { var psget = _powershell.GetModule("PowerShellGet").FirstOrDefault(); return psget != null ? GetPackageManagementModules(request, psget, null, null, null) : Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>(); }
//key = path, value = PSModuleInfo private IEnumerable<KeyValuePair<string, PSModuleInfo>> ScanForModules( PsRequest request, Version requiredVersion, Version minimumVersion, Version maximumVersion, ProviderOption providerOption = ProviderOption.LatestVersion) { // two places we search for modules // 1. in this assembly's folder, look for all psd1 and psm1 files. // // 2. modules in the PSMODULEPATH // // Import each one of those, and check to see if they have a PackageManagementProviders section in their private data var allAvailableModules = _powershell .Clear() .AddCommand("Get-Module") .AddParameter("ListAvailable") .Invoke<PSModuleInfo>(); return allAvailableModules.WhereNotNull() .SelectMany(each => GetPackageManagementModules(request, each, requiredVersion, minimumVersion, maximumVersion)); }
private IEnumerable<KeyValuePair<string, PSModuleInfo>> GetPackageManagementModules(PsRequest request, PSModuleInfo module, Version requiredVersion, Version minimumVersion, Version maximumVersion) { // skip modules that we know don't contain any PM modules if (!_exclusionList.Contains(module.Name)) { var privateData = module.PrivateData as Hashtable; if (privateData != null) { if (requiredVersion != null) { if ((FourPartVersion)module.Version == (FourPartVersion)requiredVersion) { return ScanPrivateDataForProviders(request, Path.GetDirectoryName(module.Path), privateData, module).ToArray(); } else { return Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>(); } } if ((minimumVersion != null) && ((FourPartVersion)module.Version < (FourPartVersion)minimumVersion)) { return Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>(); } if ((maximumVersion != null) && ((FourPartVersion)module.Version > (FourPartVersion)maximumVersion)) { return Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>(); } return ScanPrivateDataForProviders(request, Path.GetDirectoryName(module.Path), privateData, module).ToArray(); } } return Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>(); }
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)); } }
public abstract bool YieldResult(PsRequest r);
//key = path, value = PSModuleInfo private IEnumerable<KeyValuePair<string, PSModuleInfo>> ScanForModules( PsRequest request, Version requiredVersion, Version minimumVersion, Version maximumVersion, ProviderOption providerOption = ProviderOption.LatestVersion) { // two places we search for modules // 1. in this assembly's folder, look for all psd1 and psm1 files. // // 2. modules in the PSMODULEPATH // // Import each one of those, and check to see if they have a PackageManagementProviders section in their private data return AlternativeModuleScan(request, requiredVersion, minimumVersion, maximumVersion, providerOption).WhereNotNull() .Where(modulePath => File.ReadAllText(modulePath).IndexOf("PackageManagementProviders", StringComparison.OrdinalIgnoreCase) > -1) .SelectMany(each => _powershell.TestModuleManifest(each)) .SelectMany(each => GetPackageManagementModules(request, each, requiredVersion, minimumVersion, maximumVersion)); }
// 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<string> AlternativeModuleScan( PsRequest request, Version requiredVersion, Version minimumVersion, Version maximumVersion, ProviderOption providerOption = ProviderOption.LatestVersion) { var psModulePath = Environment.GetEnvironmentVariable("PSModulePath") ?? ""; IEnumerable<string> paths = psModulePath.Split(new char[] {';'}, StringSplitOptions.RemoveEmptyEntries); // add assumed paths just in case the environment variable isn't really set. try { #if CORECLR paths = paths.ConcatSingleItem(Path.Combine(Environment.GetEnvironmentVariable("windir"), "system32", @"WindowsPowerShell\v1.0\Modules")); #else paths = paths.ConcatSingleItem(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), @"WindowsPowerShell\v1.0\Modules")); #endif } catch { // skip the folder if it's not valid } try { #if CORECLR paths = paths.ConcatSingleItem(Path.Combine(Environment.GetEnvironmentVariable("userprofile"), "documents", @"WindowsPowerShell\Modules")); #else paths = paths.ConcatSingleItem(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), @"WindowsPowerShell\Modules")); #endif } catch { // skip the folder if it's not valid } if (!string.IsNullOrWhiteSpace(BaseFolder) && BaseFolder.DirectoryExists()) { paths = paths.ConcatSingleItem(BaseFolder); } var moduleFolders = paths.Distinct(new PathEqualityComparer(PathCompareOption.Full)).Where(each => each.DirectoryExists()).SelectMany(each => Directory.EnumerateDirectories(each).Where(dir => !_exclusionList.Contains(Path.GetFileName(dir)))); foreach (var module in moduleFolders) { var moduleManifest = Path.Combine(module, Path.GetFileName(module) + ".psd1"); if (File.Exists(moduleManifest)) { //The version check is defered in the GetPackageManagementModules() because we do not know the version without looking into the content. yield return moduleManifest; } //The following are the cases where there are multiple modules installed on the system. The file folder is the module version. var selectedVersions = Directory.EnumerateDirectories(module).Select(dir => new { folder = dir, ver = (FourPartVersion)Path.GetFileName(dir) }).Where(each => each.ver > 0L); if (requiredVersion != null) { var version = selectedVersions.Where(each => each.ver == (FourPartVersion)requiredVersion).Select(each => each.folder).FirstOrDefault(); if (version != null) { var file = Path.Combine(version, Path.GetFileName(Path.GetFileName(module)) + ".psd1"); if (File.Exists(file)) { yield return file; } } } if (minimumVersion != null) { selectedVersions = selectedVersions.Where(each => each.ver >= (FourPartVersion)minimumVersion); } if (maximumVersion != null) { selectedVersions = selectedVersions.Where(each => each.ver <= (FourPartVersion)maximumVersion); } var results = (providerOption == PackageManagementService.ProviderOption.AllProvider) ? selectedVersions.Select(version => Path.Combine(version.folder, Path.GetFileName(Path.GetFileName(module)) + ".psd1")).Where(File.Exists) : new[] { selectedVersions.OrderByDescending(each => each.ver) .Select(version => Path.Combine(version.folder, Path.GetFileName(Path.GetFileName(module)) + ".psd1")) .FirstOrDefault(File.Exists) }; foreach (var result in results.WhereNotNull()) { yield return result; } } }
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 PowerShellPackageProvider Create(PsRequest request, string modulePath, string requiredVersion, bool force, bool logWarning) { 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(); if (logWarning) { request.Warning(e.Message); } } // didn't import correctly. ps.Dispose(); return null; }
private void output_DataAdded(object sender, DataAddedEventArgs e, PsRequest request, ref object finalValue) { PSDataCollection<PSObject> outputstream = sender as PSDataCollection<PSObject>; if (outputstream == null) { return; } PSObject psObject = outputstream[e.Index]; if (psObject != null) { var value = psObject.ImmediateBaseObject; var y = value as Yieldable; if (y != null) { // yield it to stream the result gradually y.YieldResult(request); } else { finalValue = value; return; } } }
public void RefreshProviders(PsRequest request, string providerName, Version requiredVersion, Version minimumVersion, Version maximumVersion) { //find and load the latest versions of the providers if only providerName exists, e.g., get-pp -name or import-pp -name //find and load the particular provider if both providerName and version are provided _psProviderCacheTable.Clear(); EnsurePowerShellInitialized(); if (!string.IsNullOrWhiteSpace(providerName)) { //Get the list of available providers var modules = ScanForModules(request, requiredVersion, minimumVersion, maximumVersion, ProviderOption.AllProvider).ReEnumerable(); var tasks = modules.AsyncForEach(modulePath => AnalyzeModule(request, modulePath.Key, modulePath.Value.Version ?? new Version(0, 0), false)); tasks.WaitAll(); } else { //find all providers but only load the lastest if no name nor version exists, e.g. get-pp -list //Scan for the all available providers var results = ScanForModules(request, null, null, null, ProviderOption.AllProvider).ToArray(); if (!_psProviderCacheTable.Any()) { return; } foreach (var list in _psProviderCacheTable.Values.WhereNotNull()) { var psInfo = list.OrderByDescending(each => each.ProviderVersion).ToArray(); if (!psInfo.Any()) { continue; } PackageProvider pkgProvider = null; for (var index = 0; index < psInfo.Length; index++) { var moduleInfo = psInfo[index]; if (moduleInfo == null) { continue; } //load the provider that has the latest version if (index == 0) { pkgProvider = AnalyzeModule(request, moduleInfo.ProviderPath, moduleInfo.ProviderVersion, false); } else { if (pkgProvider != null) { //the rest of providers under the same module will just create a provider object for the output but not loaded var packageProvider = new PackageProvider(new DefaultPackageProvider(pkgProvider.ProviderName, moduleInfo.ProviderVersion.ToString())) { ProviderPath = moduleInfo.ProviderPath, Version = moduleInfo.ProviderVersion, IsLoaded = false }; AddToPackageProviderCacheTable(packageProvider); } } } } _psProviderCacheTable.Clear(); } }