/********************************************************************++ Copyright (c) Microsoft Corporation. All rights reserved. --********************************************************************/ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Management.Automation.Provider; using System.Management.Automation.Runspaces; using System.Text; using Dbg = System.Management.Automation; #pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings #pragma warning disable 56500 namespace System.Management.Automation { /// /// Holds the state of a PowerShell session /// internal sealed partial class SessionStateInternal { /// /// A collection of the providers. Any provider in this collection can /// have drives in any scope in session state. /// internal Dictionary> Providers { get { if (this == ExecutionContext.TopLevelSessionState) return _providers; return ExecutionContext.TopLevelSessionState.Providers; } } private Dictionary> _providers = new Dictionary>( SessionStateConstants.DefaultDictionaryCapacity, StringComparer.OrdinalIgnoreCase); /// /// Stores the current working drive for each provider. This /// allows for retrieving the current working directory for each /// individual provider. /// internal Dictionary ProvidersCurrentWorkingDrive { get { if (this == ExecutionContext.TopLevelSessionState) return _providersCurrentWorkingDrive; return ExecutionContext.TopLevelSessionState.ProvidersCurrentWorkingDrive; } } private Dictionary _providersCurrentWorkingDrive = new Dictionary(); private bool _providersInitialized = false; /// /// Gets called by the RunspaceConfiguration when a PSSnapin gets added or removed. /// /// internal void UpdateProviders() { // This should only be called from Update() on a runspace configuration q.e.d. runspace configuration // should never be null when this gets called... if (this.ExecutionContext.RunspaceConfiguration == null) throw PSTraceSource.NewInvalidOperationException(); if (this == ExecutionContext.TopLevelSessionState && !_providersInitialized) { foreach (ProviderConfigurationEntry providerConfig in this.ExecutionContext.RunspaceConfiguration.Providers) { AddProvider(providerConfig); } _providersInitialized = true; return; } foreach (ProviderConfigurationEntry providerConfig in this.ExecutionContext.RunspaceConfiguration.Providers.UpdateList) { switch (providerConfig.Action) { case UpdateAction.Add: AddProvider(providerConfig); break; case UpdateAction.Remove: RemoveProvider(providerConfig); break; default: break; } } } /// /// Entrypoint used by to add a provider to the current session state /// based on a SessionStateProviderEntry. /// /// internal void AddSessionStateEntry(SessionStateProviderEntry providerEntry) { ProviderInfo provider = AddProvider(providerEntry.ImplementingType, providerEntry.Name, providerEntry.HelpFileName, providerEntry.PSSnapIn, providerEntry.Module ); } /// /// Internal method used by RunspaceConfig for updating providers. /// /// private ProviderInfo AddProvider(ProviderConfigurationEntry providerConfig) { return AddProvider(providerConfig.ImplementingType, providerConfig.Name, providerConfig.HelpFileName, providerConfig.PSSnapIn, null ); } private ProviderInfo AddProvider(Type implementingType, string name, string helpFileName, PSSnapInInfo psSnapIn, PSModuleInfo module) { ProviderInfo provider = null; try { provider = new ProviderInfo( new SessionState(this), implementingType, name, helpFileName, psSnapIn); provider.SetModule(module); NewProvider(provider); // Log the provider start event MshLog.LogProviderLifecycleEvent( this.ExecutionContext, provider.Name, ProviderState.Started); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (SessionStateException sessionStateException) { if (sessionStateException.GetType() == typeof(SessionStateException)) { throw; } else { // NTRAID#Windows OS Bugs-1009281-2004/02/11-JeffJon this.ExecutionContext.ReportEngineStartupError(sessionStateException); } } catch (Exception e) // Catch-all OK, 3rd party callout { // NTRAID#Windows OS Bugs-1009281-2004/02/11-JeffJon this.ExecutionContext.ReportEngineStartupError(e); } return provider; } /// /// Determines the appropriate provider for the drive and then calls the NewDrive /// method of that provider. /// /// /// /// The drive to have the provider verify. /// /// /// /// The command context under which the drive is being added. /// /// /// /// If true, the drive root will be resolved as an MSH path before verifying with /// the provider. If false, the path is assumed to be a provider-internal path. /// /// /// /// The instance of the drive to be added as approved by the provider. /// /// /// /// If the provider is not a DriveCmdletProvider. /// /// /// /// The provider for the could not be found. /// /// /// /// If the provider throws an exception while validating the drive. /// /// private PSDriveInfo ValidateDriveWithProvider(PSDriveInfo drive, CmdletProviderContext context, bool resolvePathIfPossible) { Dbg.Diagnostics.Assert( drive != null, "drive should have been validated by the caller"); DriveCmdletProvider namespaceProvider = GetDriveProviderInstance(drive.Provider); return ValidateDriveWithProvider(namespaceProvider, drive, context, resolvePathIfPossible); } private PSDriveInfo ValidateDriveWithProvider( DriveCmdletProvider driveProvider, PSDriveInfo drive, CmdletProviderContext context, bool resolvePathIfPossible) { Dbg.Diagnostics.Assert( drive != null, "drive should have been validated by the caller"); Dbg.Diagnostics.Assert( driveProvider != null, "driveProvider should have been validated by the caller"); // Mark the drive as being created so that the provider can modify the // root if necessary drive.DriveBeingCreated = true; // Only try to resolve the root as an MSH path if there is a current drive. if (CurrentDrive != null && resolvePathIfPossible) { string newRoot = GetProviderRootFromSpecifiedRoot(drive.Root, drive.Provider); if (newRoot != null) { drive.SetRoot(newRoot); } } PSDriveInfo result = null; try { result = driveProvider.NewDrive(drive, context); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception e) // Catch-all OK, 3rd party callout { ProviderInvocationException pie = NewProviderInvocationException( "NewDriveProviderException", SessionStateStrings.NewDriveProviderException, driveProvider.ProviderInfo, drive.Root, e); context.WriteError( new ErrorRecord( pie.ErrorRecord, pie)); } finally { drive.DriveBeingCreated = false; } return result; } // ValidateDriveWithProvider /// /// Gets an instance of a provider given the provider ID. /// /// /// /// The identifier for the provider to return an instance of. /// /// /// /// An instance of the specified provider. /// /// /// /// If is null. /// /// /// /// If the refers to a provider that doesn't exist or /// the name passed matched multiple providers. /// /// internal Provider.CmdletProvider GetProviderInstance(string providerId) { if (providerId == null) { throw PSTraceSource.NewArgumentNullException("providerId"); } ProviderInfo provider = GetSingleProvider(providerId); return GetProviderInstance(provider); } // GetProviderInstance /// /// Gets an instance of a provider given the provider information. /// /// /// /// The provider to return an instance of. /// /// /// /// An instance of the specified provider. /// /// /// /// If is null. /// /// internal Provider.CmdletProvider GetProviderInstance(ProviderInfo provider) { if (provider == null) { throw PSTraceSource.NewArgumentNullException("provider"); } return provider.CreateInstance(); } // GetProviderInstance /// /// Creates an exception for the case where the provider name matched multiple providers. /// /// /// /// The name of the provider. /// /// /// /// The ProviderInfo of the possible matches. /// /// /// /// An exception representing the error with a message stating which providers are possible matches. /// /// internal static ProviderNameAmbiguousException NewAmbiguousProviderName(string name, Collection matchingProviders) { string possibleMatches = GetPossibleMatches(matchingProviders); ProviderNameAmbiguousException e = new ProviderNameAmbiguousException( name, "ProviderNameAmbiguous", SessionStateStrings.ProviderNameAmbiguous, matchingProviders, possibleMatches); return e; } private static string GetPossibleMatches(Collection matchingProviders) { StringBuilder possibleMatches = new StringBuilder(); foreach (ProviderInfo matchingProvider in matchingProviders) { possibleMatches.Append(" "); possibleMatches.Append(matchingProvider.FullName); } return possibleMatches.ToString(); } /// /// Gets an instance of an DriveCmdletProvider given the provider ID. /// /// /// /// The provider ID of the provider to get an instance of. /// /// /// /// An instance of a DriveCmdletProvider for the specified provider ID. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from NavigationCmdletProvider. /// /// /// /// If the refers to a provider that doesn't exist. /// /// internal DriveCmdletProvider GetDriveProviderInstance(string providerId) { if (providerId == null) { throw PSTraceSource.NewArgumentNullException("providerId"); } DriveCmdletProvider driveCmdletProvider = GetProviderInstance(providerId) as DriveCmdletProvider; if (driveCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.DriveCmdletProvider_NotSupported); } return driveCmdletProvider; } // GetDriveProviderInstance /// /// Gets an instance of an DriveCmdletProvider given the provider information. /// /// /// /// The provider to get an instance of. /// /// /// /// An instance of a DriveCmdletProvider for the specified provider. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from NavigationCmdletProvider. /// /// internal DriveCmdletProvider GetDriveProviderInstance(ProviderInfo provider) { if (provider == null) { throw PSTraceSource.NewArgumentNullException("provider"); } DriveCmdletProvider driveCmdletProvider = GetProviderInstance(provider) as DriveCmdletProvider; if (driveCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.DriveCmdletProvider_NotSupported); } return driveCmdletProvider; } // GetDriveProviderInstance /// /// Gets an instance of an DriveCmdletProvider given the provider ID. /// /// /// /// The instance of the provider to use. /// /// /// /// An instance of a DriveCmdletProvider for the specified provider ID. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from DriveCmdletProvider. /// /// private static DriveCmdletProvider GetDriveProviderInstance(CmdletProvider providerInstance) { if (providerInstance == null) { throw PSTraceSource.NewArgumentNullException("providerInstance"); } DriveCmdletProvider driveCmdletProvider = providerInstance as DriveCmdletProvider; if (driveCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.DriveCmdletProvider_NotSupported); } return driveCmdletProvider; } // GetDriveProviderInstance /// /// Gets an instance of an ItemCmdletProvider given the provider ID. /// /// /// /// The provider ID of the provider to get an instance of. /// /// /// /// An instance of a ItemCmdletProvider for the specified provider ID. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from NavigationCmdletProvider. /// /// /// /// If the refers to a provider that doesn't exist. /// /// internal ItemCmdletProvider GetItemProviderInstance(string providerId) { if (providerId == null) { throw PSTraceSource.NewArgumentNullException("providerId"); } ItemCmdletProvider itemCmdletProvider = GetProviderInstance(providerId) as ItemCmdletProvider; if (itemCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ItemCmdletProvider_NotSupported); } return itemCmdletProvider; } // GetItemProviderInstance /// /// Gets an instance of an ItemCmdletProvider given the provider. /// /// /// /// The provider to get an instance of. /// /// /// /// An instance of a ItemCmdletProvider for the specified provider. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from NavigationCmdletProvider. /// /// internal ItemCmdletProvider GetItemProviderInstance(ProviderInfo provider) { if (provider == null) { throw PSTraceSource.NewArgumentNullException("provider"); } ItemCmdletProvider itemCmdletProvider = GetProviderInstance(provider) as ItemCmdletProvider; if (itemCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ItemCmdletProvider_NotSupported); } return itemCmdletProvider; } // GetItemProviderInstance /// /// Gets an instance of an ItemCmdletProvider given the provider ID. /// /// /// /// The instance of the provider to use. /// /// /// /// An instance of a ItemCmdletProvider for the specified provider ID. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from ItemCmdletProvider. /// /// private static ItemCmdletProvider GetItemProviderInstance(CmdletProvider providerInstance) { if (providerInstance == null) { throw PSTraceSource.NewArgumentNullException("providerInstance"); } ItemCmdletProvider itemCmdletProvider = providerInstance as ItemCmdletProvider; if (itemCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ItemCmdletProvider_NotSupported); } return itemCmdletProvider; } // GetItemProviderInstance /// /// Gets an instance of an ContainerCmdletProvider given the provider ID. /// /// /// /// The provider ID of the provider to get an instance of. /// /// /// /// An instance of a ContainerCmdletProvider for the specified provider ID. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from NavigationCmdletProvider. /// /// /// /// If the refers to a provider that doesn't exist. /// /// internal ContainerCmdletProvider GetContainerProviderInstance(string providerId) { if (providerId == null) { throw PSTraceSource.NewArgumentNullException("providerId"); } ContainerCmdletProvider containerCmdletProvider = GetProviderInstance(providerId) as ContainerCmdletProvider; if (containerCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ContainerCmdletProvider_NotSupported); } return containerCmdletProvider; } // GetContainerProviderInstance /// /// Gets an instance of an ContainerCmdletProvider given the provider. /// /// /// /// The provider to get an instance of. /// /// /// /// An instance of a ContainerCmdletProvider for the specified provider. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from NavigationCmdletProvider. /// /// internal ContainerCmdletProvider GetContainerProviderInstance(ProviderInfo provider) { if (provider == null) { throw PSTraceSource.NewArgumentNullException("provider"); } ContainerCmdletProvider containerCmdletProvider = GetProviderInstance(provider) as ContainerCmdletProvider; if (containerCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ContainerCmdletProvider_NotSupported); } return containerCmdletProvider; } // GetContainerProviderInstance /// /// Gets an instance of an ContainerCmdletProvider given the provider ID. /// /// /// /// The instance of the provider to use. /// /// /// /// An instance of a ContainerCmdletProvider for the specified provider ID. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from ContainerCmdletProvider. /// /// private static ContainerCmdletProvider GetContainerProviderInstance(CmdletProvider providerInstance) { if (providerInstance == null) { throw PSTraceSource.NewArgumentNullException("providerInstance"); } ContainerCmdletProvider containerCmdletProvider = providerInstance as ContainerCmdletProvider; if (containerCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.ContainerCmdletProvider_NotSupported); } return containerCmdletProvider; } // GetContainerProviderInstance /// /// Gets an instance of an NavigationCmdletProvider given the provider. /// /// /// /// The provider to get an instance of. /// /// /// /// An instance of a NavigationCmdletProvider for the specified provider ID. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from NavigationCmdletProvider. /// /// internal NavigationCmdletProvider GetNavigationProviderInstance(ProviderInfo provider) { if (provider == null) { throw PSTraceSource.NewArgumentNullException("provider"); } NavigationCmdletProvider navigationCmdletProvider = GetProviderInstance(provider) as NavigationCmdletProvider; if (navigationCmdletProvider == null) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.NavigationCmdletProvider_NotSupported); } return navigationCmdletProvider; } // GetNavigationProviderInstance /// /// Gets an instance of an NavigationCmdletProvider given the provider ID. /// /// /// /// The instance of the provider to use. /// /// /// /// Specify True if the method should just return the Path if the /// provider doesn't support container overloads. /// /// /// /// An instance of a NavigationCmdletProvider for the specified provider ID. /// /// /// /// if is null. /// /// /// /// if the is not for a provider /// that is derived from NavigationCmdletProvider. /// /// private static NavigationCmdletProvider GetNavigationProviderInstance(CmdletProvider providerInstance, bool acceptNonContainerProviders) { if (providerInstance == null) { throw PSTraceSource.NewArgumentNullException("providerInstance"); } NavigationCmdletProvider navigationCmdletProvider = providerInstance as NavigationCmdletProvider; if ((navigationCmdletProvider == null) && (!acceptNonContainerProviders)) { throw PSTraceSource.NewNotSupportedException(SessionStateStrings.NavigationCmdletProvider_NotSupported); } return navigationCmdletProvider; } // GetNavigationProviderInstance #region GetProvider /// /// Determines if the specified CmdletProvider is loaded. /// /// /// /// The name of the CmdletProvider. /// /// /// /// true if the CmdletProvider is loaded, or false otherwise. /// /// /// /// If is null or empty. /// /// internal bool IsProviderLoaded(string name) { bool result = false; if (String.IsNullOrEmpty(name)) { throw PSTraceSource.NewArgumentException("name"); } // Get the provider from the providers container try { ProviderInfo providerInfo = GetSingleProvider(name); result = providerInfo != null; } catch (ProviderNotFoundException) { } return result; } // IsProviderLoaded /// /// Gets the provider of the specified name /// /// /// /// The name of the provider to retrieve /// /// /// /// The provider of the given name /// /// /// /// If is null or empty. /// /// /// /// The provider with the specified /// could not be found. /// /// internal Collection GetProvider(string name) { if (String.IsNullOrEmpty(name)) { throw PSTraceSource.NewArgumentException("name"); } PSSnapinQualifiedName providerName = PSSnapinQualifiedName.GetInstance(name); if (providerName == null) { ProviderNotFoundException e = new ProviderNotFoundException( name, SessionStateCategory.CmdletProvider, "ProviderNotFoundBadFormat", SessionStateStrings.ProviderNotFoundBadFormat); throw e; } return GetProvider(providerName); } /// /// Gets the provider of the specified name /// /// /// /// The name of the provider to retrieve /// /// /// /// The provider of the given name /// /// /// /// If is null or empty. /// /// /// /// The provider with the specified /// could not be found or the name was ambiguous. /// If the name is ambiguous then the PSSnapin qualified name must /// be specified. /// /// internal ProviderInfo GetSingleProvider(string name) { Collection matchingProviders = GetProvider(name); if (matchingProviders.Count != 1) { if (matchingProviders.Count == 0) { ProviderNotFoundException e = new ProviderNotFoundException( name, SessionStateCategory.CmdletProvider, "ProviderNotFound", SessionStateStrings.ProviderNotFound); throw e; } else { throw NewAmbiguousProviderName(name, matchingProviders); } } return matchingProviders[0]; } internal Collection GetProvider(PSSnapinQualifiedName providerName) { Collection result = new Collection(); if (providerName == null) { ProviderNotFoundException e = new ProviderNotFoundException( "null", SessionStateCategory.CmdletProvider, "ProviderNotFound", SessionStateStrings.ProviderNotFound); throw e; } // Get the provider from the providers container List matchingProviders = null; if (!Providers.TryGetValue(providerName.ShortName, out matchingProviders)) { // If the provider was not found, we may need to auto-mount it. SessionStateInternal.MountDefaultDrive(providerName.ShortName, ExecutionContext); if (!Providers.TryGetValue(providerName.ShortName, out matchingProviders)) { ProviderNotFoundException e = new ProviderNotFoundException( providerName.ToString(), SessionStateCategory.CmdletProvider, "ProviderNotFound", SessionStateStrings.ProviderNotFound); throw e; } } if (ExecutionContext.IsSingleShell && !String.IsNullOrEmpty(providerName.PSSnapInName)) { // Be sure the PSSnapin/Module name matches foreach (ProviderInfo provider in matchingProviders) { if (String.Equals( provider.PSSnapInName, providerName.PSSnapInName, StringComparison.OrdinalIgnoreCase) || String.Equals( provider.ModuleName, providerName.PSSnapInName, StringComparison.OrdinalIgnoreCase)) { result.Add(provider); } } } else { foreach (ProviderInfo provider in matchingProviders) { result.Add(provider); } } return result; } // GetProvider /// /// Gets all the CoreCommandProviders /// /// internal IEnumerable ProviderList { get { Collection result = new Collection(); foreach (List providerValues in Providers.Values) { foreach (ProviderInfo provider in providerValues) { result.Add(provider); } } return result; } // get } // Providers /// /// Copy the Providers from another session state instance... /// /// the session state instance to copy from... internal void CopyProviders(SessionStateInternal ss) { if (ss == null || ss.Providers == null) return; // private Dictionary> providers; _providers = new Dictionary>(); foreach (KeyValuePair> e in ss._providers) { _providers.Add(e.Key, e.Value); } } #endregion GetProvider #region NewProvider /// /// Initializes a provider by loading the assembly, creating an instance of the /// provider, calling its start method followed by the InitializeDefaultDrives method. The /// Drives that are returned from the InitializeDefaultDrives method are then mounted. /// /// /// /// An instance of the provider to use for the initialization. /// /// /// /// The provider to be initialized. /// /// /// /// The context under which the initialization is occurring. If this parameter is not /// null, errors will be written to the WriteError method of the context. /// /// /// /// If or is null. /// /// /// /// If the provider is not a DriveCmdletProvider. /// /// /// /// If a drive already exists for the name of one of the drives the /// provider tries to add. /// /// internal void InitializeProvider( Provider.CmdletProvider providerInstance, ProviderInfo provider, CmdletProviderContext context) { if (provider == null) { throw PSTraceSource.NewArgumentNullException("provider"); } if (context == null) { context = new CmdletProviderContext(this.ExecutionContext); } // Initialize the provider so that it can add any drives // that it needs. List newDrives = new List(); DriveCmdletProvider driveProvider = GetDriveProviderInstance(providerInstance); if (driveProvider != null) { try { Collection drives = driveProvider.InitializeDefaultDrives(context); if (drives != null && drives.Count > 0) { newDrives.AddRange(drives); ProvidersCurrentWorkingDrive[provider] = drives[0]; } } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception e) // Catch-all OK, 3rd party callout { ProviderInvocationException providerException = NewProviderInvocationException( "InitializeDefaultDrivesException", SessionStateStrings.InitializeDefaultDrivesException, provider, String.Empty, e); context.WriteError( new ErrorRecord( providerException, "InitializeDefaultDrivesException", ErrorCategory.InvalidOperation, provider)); } } if (newDrives != null && newDrives.Count > 0) { // Add the drives. foreach (PSDriveInfo newDrive in newDrives) { if (newDrive == null) { continue; } // Only mount drives for the current provider if (!provider.NameEquals(newDrive.Provider.FullName)) { continue; } try { PSDriveInfo validatedNewDrive = ValidateDriveWithProvider(driveProvider, newDrive, context, false); if (validatedNewDrive != null) { // Since providers are global then the drives created // through InitializeDefaultDrives should also be global. GlobalScope.NewDrive(validatedNewDrive); } } catch (SessionStateException exception) { context.WriteError(exception.ErrorRecord); } } // foreach (drive in newDrives) } } // InitializeProvider /// /// Creates and adds a provider to the provider container /// /// /// /// The provider to add. /// /// /// /// The provider that was added or null if the provider failed to be added. /// /// /// /// If is null. /// /// /// /// If the provider already exists. /// /// /// /// If there was a failure to load the provider or the provider /// threw an exception. /// /// internal ProviderInfo NewProvider(ProviderInfo provider) { if (provider == null) { throw PSTraceSource.NewArgumentNullException("provider"); } // Check to see if the provider already exists. // We do the check instead of allowing the hashtable to // throw the exception so that we give a better error // message. ProviderInfo existingProvider = ProviderExists(provider); if (existingProvider != null) { // If it's an already loaded provider, don't return an error... if (existingProvider.ImplementingType == provider.ImplementingType) return existingProvider; SessionStateException sessionStateException = new SessionStateException( provider.Name, SessionStateCategory.CmdletProvider, "CmdletProviderAlreadyExists", SessionStateStrings.CmdletProviderAlreadyExists, ErrorCategory.ResourceExists); throw sessionStateException; } // Make sure we are able to create an instance of the provider. // Note, this will also set the friendly name if the user didn't // specify one. Provider.CmdletProvider providerInstance = provider.CreateInstance(); // Now call start to let the provider initialize itself CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext); ProviderInfo newProviderInfo = null; try { newProviderInfo = providerInstance.Start(provider, context); // Set the new provider info in the instance in case the provider // derived a new one providerInstance.SetProviderInformation(newProviderInfo); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (InvalidOperationException) { throw; } catch (Exception e) // Catch-call OK, 3rd party callout { throw NewProviderInvocationException( "ProviderStartException", SessionStateStrings.ProviderStartException, provider, null, e); } context.ThrowFirstErrorOrDoNothing(true); if (newProviderInfo == null) { throw PSTraceSource.NewInvalidOperationException( SessionStateStrings.InvalidProviderInfoNull); } if (newProviderInfo != provider) { // Since the references are not the same, ensure that the provider // name is the same. if (!string.Equals(newProviderInfo.Name, provider.Name, StringComparison.OrdinalIgnoreCase)) { throw PSTraceSource.NewInvalidOperationException( SessionStateStrings.InvalidProviderInfo); } // Use the new provider info instead provider = newProviderInfo; } // Add the newly create provider to the providers container try { NewProviderEntry(provider); } catch (ArgumentException) { SessionStateException sessionStateException = new SessionStateException( provider.Name, SessionStateCategory.CmdletProvider, "CmdletProviderAlreadyExists", SessionStateStrings.CmdletProviderAlreadyExists, ErrorCategory.ResourceExists); throw sessionStateException; } // Add the provider to the provider current working // drive hashtable so that we can associate a current working // drive with it. ProvidersCurrentWorkingDrive.Add(provider, null); bool initializeProviderError = false; try { // Initialize the provider and give it a chance to // mount some drives. InitializeProvider(providerInstance, provider, context); context.ThrowFirstErrorOrDoNothing(true); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { initializeProviderError = true; throw; } catch (ActionPreferenceStopException) { initializeProviderError = true; throw; } catch (NotSupportedException) { // We can safely ignore NotSupportedExceptions because // it just means that the provider doesn't support // drives. initializeProviderError = false; } catch (SessionStateException) { initializeProviderError = true; throw; } finally { if (initializeProviderError) { // An exception during initialization should remove the provider from // session state. Providers.Remove(provider.Name.ToString()); ProvidersCurrentWorkingDrive.Remove(provider); provider = null; } } // Now write out the result return provider; } // NewProvider private ProviderInfo ProviderExists(ProviderInfo provider) { List matchingProviders = null; if (Providers.TryGetValue(provider.Name, out matchingProviders)) { foreach (ProviderInfo possibleMatch in matchingProviders) { if (provider.NameEquals(possibleMatch.FullName)) { return possibleMatch; } } } return null; } /// /// Creates an entry in the providers hashtable for the new provider. /// /// /// /// The provider being added. /// /// /// /// If a provider with the same name and PSSnapIn name already exists. /// /// private void NewProviderEntry(ProviderInfo provider) { bool isDuplicateProvider = false; // Add the entry to the list of providers with that name if (!Providers.ContainsKey(provider.Name)) { Providers.Add(provider.Name, new List()); } else { // be sure the same provider from the same PSSnapin doesn't already exist List existingProviders = Providers[provider.Name]; foreach (ProviderInfo existingProvider in existingProviders) { //making sure that we are not trying to add the same provider by checking the provider name & type of the new and existing providers. if (string.IsNullOrEmpty(provider.PSSnapInName) && (string.Equals(existingProvider.Name, provider.Name, StringComparison.OrdinalIgnoreCase) && (existingProvider.GetType().Equals(provider.GetType())))) { isDuplicateProvider = true; } //making sure that we are not trying to add the same provider by checking the PSSnapinName of the new and existing providers. else if (string.Equals(existingProvider.PSSnapInName, provider.PSSnapInName, StringComparison.OrdinalIgnoreCase)) { isDuplicateProvider = true; } } } if (!isDuplicateProvider) { Providers[provider.Name].Add(provider); } } #endregion NewProvider #region Remove Provider private void RemoveProvider(ProviderConfigurationEntry entry) { try { CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext); string providerName = GetProviderName(entry); RemoveProvider(providerName, true, context); context.ThrowFirstErrorOrDoNothing(); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception e) // Catch-all OK, 3rd party callout { // NTRAID#Windows OS Bugs-1009281-2004/02/11-JeffJon this.ExecutionContext.ReportEngineStartupError(e); } } private string GetProviderName(ProviderConfigurationEntry entry) { string name = entry.Name; if (entry.PSSnapIn != null) { name = string.Format( System.Globalization.CultureInfo.InvariantCulture, "{0}\\{1}", entry.PSSnapIn.Name, entry.Name); } return name; } /// /// Removes the provider of the given name. /// /// /// /// The name of the provider to remove. /// /// /// /// Determines if the provider should be removed forcefully even if there were /// drives present or errors. /// /// /// /// The context under which the command is being run. /// /// /// /// If is null. /// /// /// /// There are still drives associated with this provider, /// and the "force" option was not specified. /// /// /// /// A provider with name could not be found. /// /// /// /// If a provider throws an exception it gets written to the . /// /// /// /// If is null or empty. /// /// /// /// If is null. /// /// /// /// All drives associated with the provider must be removed before the provider /// can be removed. Call SessionState.GetDrivesForProvider() to determine if there /// are any drives associated with the provider. A SessionStateException /// will be written to the context if any such drives do exist. /// /// internal void RemoveProvider( string providerName, bool force, CmdletProviderContext context) { if (context == null) { throw PSTraceSource.NewArgumentNullException("context"); } if (String.IsNullOrEmpty(providerName)) { throw PSTraceSource.NewArgumentException("providerName"); } bool errors = false; ProviderInfo provider = null; try { provider = GetSingleProvider(providerName); } catch (ProviderNotFoundException) { return; } try { // First get an instance of the provider to make sure it exists Provider.CmdletProvider providerBase = GetProviderInstance(provider); if (providerBase == null) { ProviderNotFoundException e = new ProviderNotFoundException( providerName, SessionStateCategory.CmdletProvider, "ProviderNotFound", SessionStateStrings.ProviderNotFound); context.WriteError(new ErrorRecord(e.ErrorRecord, e)); errors = true; } else { // See if there are any drives present for the provider int driveCount = 0; foreach (PSDriveInfo drive in GetDrivesForProvider(providerName)) { if (drive != null) { ++driveCount; break; } } if (driveCount > 0) { if (force) { // Forcefully remove all the drives foreach (PSDriveInfo drive in GetDrivesForProvider(providerName)) { if (drive != null) { RemoveDrive(drive, true, null); } } } else { errors = true; // Since there are still drives associated with the provider // the provider cannot be removed SessionStateException e = new SessionStateException( providerName, SessionStateCategory.CmdletProvider, "RemoveDrivesBeforeRemovingProvider", SessionStateStrings.RemoveDrivesBeforeRemovingProvider, ErrorCategory.InvalidOperation); context.WriteError(new ErrorRecord(e.ErrorRecord, e)); return; } } // Now tell the provider that they are going to be removed by // calling the Stop method try { providerBase.Stop(context); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } } } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception e) { errors = true; context.WriteError( new ErrorRecord( e, "RemoveProviderUnexpectedException", ErrorCategory.InvalidArgument, providerName)); } finally { if (force || !errors) { // Log the provider stopped event MshLog.LogProviderLifecycleEvent( this.ExecutionContext, providerName, ProviderState.Stopped); RemoveProviderFromCollection(provider); ProvidersCurrentWorkingDrive.Remove(provider); } } } // RemoveProvider /// /// Removes the provider from the providers dictionary. /// /// /// /// The provider to be removed. /// /// /// /// If there are multiple providers with the same name, then only the provider /// from the matching PSSnapin is removed. /// If the last provider of that name is removed the entry is removed from the dictionary. /// /// private void RemoveProviderFromCollection(ProviderInfo provider) { List matchingProviders; if (Providers.TryGetValue(provider.Name, out matchingProviders)) { if (matchingProviders.Count == 1 && matchingProviders[0].NameEquals(provider.FullName)) { Providers.Remove(provider.Name); } else { matchingProviders.Remove(provider); } } } #endregion RemoveProvider /// /// Gets the count of the number of providers that are loaded /// /// internal int ProviderCount { get { int count = 0; foreach (List matchingProviders in Providers.Values) { count += matchingProviders.Count; } return count; } } // ProviderCount } // SessionStateInternal class } #pragma warning restore 56500