Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
SessionStateDriveAPIs.cs1437 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Collections.ObjectModel;6using System.ComponentModel;7using System.Globalization;8using System.IO;9using System.Management.Automation.Provider;10 11using Dbg = System.Management.Automation;12 13#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings14#pragma warning disable 5650015 16namespace System.Management.Automation17{18    /// <summary>19    /// Holds the state of a Monad Shell session.20    /// </summary>21    internal sealed partial class SessionStateInternal22    {23        /// <summary>24        /// The currently active drive. It determines the current working directory.25        /// </summary>26        private PSDriveInfo _currentDrive;27 28        #region NewDrive29 30        /// <summary>31        /// Adds the specified drive to the current scope.32        /// </summary>33        /// <param name="drive">34        /// The drive to be added to the current scope.35        /// </param>36        /// <param name="scopeID">37        /// The ID for the scope to add the drive to. The scope ID can be any of the38        /// "special" scope identifiers like "global", "local", or "private" or it39        /// can be a numeric identifier that is a count of the number of parent40        /// scopes up from the current scope to put the drive in.41        /// If this parameter is null or empty the drive will be placed in the42        /// current scope.43        /// </param>44        /// <returns>45        /// The drive that was added, if any.46        /// </returns>47        /// <exception cref="ArgumentNullException">48        /// If <paramref name="drive"/> is null.49        /// </exception>50        /// <exception cref="ArgumentException">51        /// If the drive already exists,52        /// or53        /// If <paramref name="drive"/>.Name contains one or more invalid characters; ~ / \\ . :54        /// </exception>55        /// <exception cref="NotSupportedException">56        /// If the provider is not a DriveCmdletProvider.57        /// </exception>58        /// <exception cref="ProviderNotFoundException">59        /// The provider for the <paramref name="drive"/> could not be found.60        /// </exception>61        /// <exception cref="ProviderInvocationException">62        /// If the provider threw an exception or returned null.63        /// </exception>64        internal PSDriveInfo NewDrive(PSDriveInfo drive, string scopeID)65        {66            if (drive == null)67            {68                throw PSTraceSource.NewArgumentNullException(nameof(drive));69            }70 71            PSDriveInfo result = null;72 73            // Construct a CmdletProviderContext and call the override74 75            CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext);76 77            NewDrive(drive, scopeID, context);78 79            context.ThrowFirstErrorOrDoNothing();80 81            Collection<PSObject> successObjects = context.GetAccumulatedObjects();82 83            if (successObjects != null &&84                successObjects.Count > 0)85            {86                Dbg.Diagnostics.Assert(87                    successObjects.Count == 1,88                    "NewDrive should only add one PSDriveInfo object to the pipeline");89 90                // set the return value to the first drive (should only be one).91 92                if (!successObjects[0].ImmediateBaseObjectIsEmpty)93                {94                    result = (PSDriveInfo)successObjects[0].BaseObject;95                }96            }97 98            return result;99        }100 101        /// <summary>102        /// Adds a drive to the PowerShell namespace.103        /// </summary>104        /// <param name="drive">105        /// The new drive to be added.106        /// </param>107        /// <param name="scopeID">108        /// The ID for the scope to add the drive to. The scope ID can be any of the109        /// "special" scope identifiers like "global", "local", or "private" or it110        /// can be a numeric identifier that is a count of the number of parent111        /// scopes up from the current scope to put the drive in.112        /// If this parameter is null or empty the drive will be placed in the113        /// current scope.114        /// </param>115        /// <param name="context">116        /// The context which the core command is running.117        /// </param>118        /// <exception cref="ArgumentNullException">119        /// If <paramref name="drive"/> or <paramref name="context"/> is null.120        /// </exception>121        /// <exception cref="ArgumentException">122        /// If the drive already exists123        /// or124        /// If <paramref name="drive"/>.Name contains one or more invalid characters; ~ / \\ . :125        /// </exception>126        /// <exception cref="ArgumentOutOfRangeException">127        /// If <paramref name="scopeID"/> is less than zero or greater than the number of currently128        /// active scopes.129        /// </exception>130        /// <exception cref="NotSupportedException">131        /// If the provider is not a DriveCmdletProvider.132        /// </exception>133        /// <exception cref="ProviderNotFoundException">134        /// The provider for the <paramref name="drive"/> could not be found.135        /// </exception>136        /// <exception cref="ProviderInvocationException">137        /// If the provider threw an exception or returned null.138        /// </exception>139        internal void NewDrive(PSDriveInfo drive, string scopeID, CmdletProviderContext context)140        {141            if (drive == null)142            {143                throw PSTraceSource.NewArgumentNullException(nameof(drive));144            }145 146            if (context == null)147            {148                throw PSTraceSource.NewArgumentNullException(nameof(context));149            }150 151            if (!IsValidDriveName(drive.Name))152            {153                ArgumentException e =154                    PSTraceSource.NewArgumentException(155                        "drive.Name",156                        SessionStateStrings.DriveNameIllegalCharacters);157 158                throw e;159            }160 161            // Allow the provider a chance to approve the drive and set162            // provider specific data163 164            PSDriveInfo result = ValidateDriveWithProvider(drive, context, true);165 166            // We assume that the provider wrote the error message as they167            // are suppose to.168            if (result == null)169            {170                return;171            }172 173            if (string.Equals(result.Name, drive.Name, StringComparison.OrdinalIgnoreCase))174            {175                // Set the drive in the current scope.176 177                try178                {179                    SessionStateScope scope = _currentScope;180 181                    if (!string.IsNullOrEmpty(scopeID))182                    {183                        scope = GetScopeByID(scopeID);184                    }185 186                    scope.NewDrive(result);187                }188                catch (ArgumentException argumentException)189                {190                    // Wrap up the exception and write it to the error stream191 192                    context.WriteError(193                        new ErrorRecord(194                            argumentException,195                            "NewDriveError",196                            ErrorCategory.InvalidArgument,197                            result));198                    return;199                }200                catch (SessionStateException)201                {202                    // This should be a pipeline terminating condition203                    throw;204                }205 206                if (ProvidersCurrentWorkingDrive[drive.Provider] == null)207                {208                    // Set the new drive as the current209                    // drive for the provider since there isn't one set.210 211                    ProvidersCurrentWorkingDrive[drive.Provider] = drive;212                }213 214                // Upon success, write the drive to the pipeline215 216                context.WriteObject(result);217            }218            else219            {220                ProviderInvocationException e =221                    NewProviderInvocationException(222                        "NewDriveProviderFailed",223                        SessionStateStrings.NewDriveProviderFailed,224                        drive.Provider,225                        drive.Root,226                        PSTraceSource.NewArgumentException("root"));227 228                throw e;229            }230        }231 232        private static bool IsValidDriveName(string name)233        {234            const string CharactersInvalidInDriveName = ":/\\.~";235 236            return !string.IsNullOrEmpty(name)237                && name.AsSpan().IndexOfAny(CharactersInvalidInDriveName) < 0;238        }239 240        /// <summary>241        /// Tries to resolve the drive root as an MSH path. If it successfully resolves242        /// to a single path then the resolved provider internal path is returned. If it243        /// does not resolve to a single MSH path the root is returned as it was passed.244        /// </summary>245        /// <param name="root">246        /// The root path of the drive to be resolved.247        /// </param>248        /// <param name="provider">249        /// The provider that should be used when resolving the path.250        /// </param>251        /// <returns>252        /// The new root path of the drive.253        /// </returns>254        private string GetProviderRootFromSpecifiedRoot(string root, ProviderInfo provider)255        {256            Dbg.Diagnostics.Assert(257                root != null,258                "Caller should have verified the root");259 260            Dbg.Diagnostics.Assert(261                provider != null,262                "Caller should have verified the provider");263 264            string result = root;265 266            SessionState sessionState = new SessionState(ExecutionContext.TopLevelSessionState);267            Collection<string> resolvedPaths = null;268            ProviderInfo resolvedProvider = null;269 270            try271            {272                // First try to resolve the root as an MSH path273 274                resolvedPaths =275                    sessionState.Path.GetResolvedProviderPathFromPSPath(root, out resolvedProvider);276 277                // If a single path was resolved...278 279                if (resolvedPaths != null &&280                    resolvedPaths.Count == 1)281                {282                    // and the provider used to resolve the path,283                    // matches the one specified by the drive...284 285                    if (provider.NameEquals(resolvedProvider.FullName))286                    {287                        // and the item exists288 289                        ProviderIntrinsics providerIntrinsics =290                            new ProviderIntrinsics(this);291 292                        if (providerIntrinsics.Item.Exists(root))293                        {294                            // then use the resolved path as the root of the drive295 296                            result = resolvedPaths[0];297                        }298                    }299                }300            }301            catch (LoopFlowException)302            {303                throw;304            }305            catch (PipelineStoppedException)306            {307                throw;308            }309            catch (ActionPreferenceStopException)310            {311                throw;312            }313            // If any of the following exceptions are thrown we assume that314            // the path is a file system path not an MSH path and try315            // to create the drive with that root.316            catch (DriveNotFoundException)317            {318            }319            catch (ProviderNotFoundException)320            {321            }322            catch (ItemNotFoundException)323            {324            }325            catch (NotSupportedException)326            {327            }328            catch (InvalidOperationException)329            {330            }331            catch (ProviderInvocationException)332            {333            }334            catch (ArgumentException)335            {336            }337 338            return result;339        }340 341        /// <summary>342        /// Gets an object that defines the additional parameters for the NewDrive implementation343        /// for a provider.344        /// </summary>345        /// <param name="providerId">346        /// The provider ID for the drive that is being created.347        /// </param>348        /// <param name="context">349        /// The context under which this method is being called.350        /// </param>351        /// <returns>352        /// An object that has properties and fields decorated with353        /// parsing attributes similar to a cmdlet class.354        /// </returns>355        /// <exception cref="NotSupportedException">356        /// If the <paramref name="providerId"/> is not a DriveCmdletProvider.357        /// </exception>358        /// <exception cref="ProviderNotFoundException">359        /// If <paramref name="providerId"/> does not exist.360        /// </exception>361        internal object NewDriveDynamicParameters(string providerId, CmdletProviderContext context)362        {363            if (providerId == null)364            {365                // If the provider hasn't been specified yet, just return null.366                // The provider can be specified as pipeline input.367                return null;368            }369 370            DriveCmdletProvider provider = GetDriveProviderInstance(providerId);371 372            object result = null;373            try374            {375                result = provider.NewDriveDynamicParameters(context);376            }377            catch (Exception e) // Catch-all OK, 3rd party callout378            {379                throw380                    NewProviderInvocationException(381                        "NewDriveDynamicParametersProviderException",382                        SessionStateStrings.NewDriveDynamicParametersProviderException,383                        provider.ProviderInfo,384                        null,385                        e);386            }387 388            return result;389        }390 391        #endregion NewDrive392 393        #region GetDrive394 395        /// <summary>396        /// Searches through the session state scopes to find a drive.397        /// </summary>398        /// <param name="name">399        /// The name of a drive to find.400        /// </param>401        /// <returns>402        /// The drive information if the drive is found.403        /// </returns>404        /// <exception cref="ArgumentNullException">405        /// If <paramref name="name"/> is null.406        /// </exception>407        /// <exception cref="DriveNotFoundException">408        /// If there is no drive with <paramref name="name"/>.409        /// </exception>410        internal PSDriveInfo GetDrive(string name)411        {412            return GetDrive(name, true);413        }414 415        private PSDriveInfo GetDrive(string name, bool automount)416        {417            if (name == null)418            {419                throw PSTraceSource.NewArgumentNullException(nameof(name));420            }421 422            PSDriveInfo result = null;423 424            // Start searching through the scopes for the drive until the drive425            // is found or the global scope is reached.426 427            SessionStateScopeEnumerator scopeEnumerator = new SessionStateScopeEnumerator(CurrentScope);428 429            int scopeID = 0;430 431            foreach (SessionStateScope processingScope in scopeEnumerator)432            {433                result = processingScope.GetDrive(name);434 435                if (result != null)436                {437                    if (result.IsAutoMounted)438                    {439                        // Validate or remove the auto-mounted drive440 441                        if (!ValidateOrRemoveAutoMountedDrive(result, processingScope))442                        {443                            result = null;444                        }445                    }446 447                    if (result != null)448                    {449                        s_tracer.WriteLine("Drive found in scope {0}", scopeID);450                        break;451                    }452                }453 454                // Increment the scope ID455                ++scopeID;456            }457 458            if (result == null && automount)459            {460                // Attempt to automount as a file system drive461                // or as a BuiltIn drive (e.g. "Cert"/"Certificate"/"WSMan")462                result = AutomountFileSystemDrive(name) ?? AutomountBuiltInDrive(name);463            }464 465            if (result == null)466            {467                DriveNotFoundException driveNotFound =468                    new DriveNotFoundException(469                        name,470                        "DriveNotFound",471                        SessionStateStrings.DriveNotFound);472 473                throw driveNotFound;474            }475 476            return result;477        }478 479        /// <summary>480        /// Searches through the session state scopes looking481        /// for a drive of the specified name.482        /// </summary>483        /// <param name="name">484        /// The name of the drive to return.485        /// </param>486        /// <param name="scopeID">487        /// The scope ID of the scope to look in for the drive.488        /// If this parameter is null or empty the drive will be489        /// found by searching the scopes using the dynamic scoping490        /// rules.491        /// </param>492        /// <returns>493        /// The drive for the given name in the given scope or null if494        /// the drive was not found.495        /// </returns>496        /// <exception cref="ArgumentNullException">497        /// If <paramref name="name"/> is null.498        /// </exception>499        /// <exception cref="ArgumentException">500        /// If <paramref name="scopeID"/> is less than zero, or not501        /// a number and not "script", "global", "local", or "private"502        /// </exception>503        /// <exception cref="ArgumentOutOfRangeException">504        /// If <paramref name="scopeID"/> is less than zero or greater than the number of currently505        /// active scopes.506        /// </exception>507        internal PSDriveInfo GetDrive(string name, string scopeID)508        {509            if (name == null)510            {511                throw PSTraceSource.NewArgumentNullException(nameof(name));512            }513 514            PSDriveInfo result = null;515 516            // The scope ID wasn't defined or wasn't recognizable517            // so do a search through the scopes looking for the518            // drive.519 520            if (string.IsNullOrEmpty(scopeID))521            {522                SessionStateScopeEnumerator scopeEnumerator =523                    new SessionStateScopeEnumerator(CurrentScope);524 525                foreach (SessionStateScope scope in scopeEnumerator)526                {527                    result = scope.GetDrive(name);528 529                    if (result != null)530                    {531                        if (result.IsAutoMounted)532                        {533                            // Validate or remove the auto-mounted drive534 535                            if (!ValidateOrRemoveAutoMountedDrive(result, scope))536                            {537                                result = null;538                            }539                        }540 541                        if (result != null)542                        {543                            break;544                        }545                    }546                }547 548                if (result == null)549                {550                    result = AutomountFileSystemDrive(name);551                }552            }553            else554            {555                SessionStateScope scope = GetScopeByID(scopeID);556                result = scope.GetDrive(name);557 558                if (result != null)559                {560                    if (result.IsAutoMounted)561                    {562                        // Validate or remove the auto-mounted drive563 564                        if (!ValidateOrRemoveAutoMountedDrive(result, scope))565                        {566                            result = null;567                        }568                    }569                }570                else571                {572                    if (scope == GlobalScope)573                    {574                        result = AutomountFileSystemDrive(name);575                    }576                }577            }578 579            return result;580        }581 582        private PSDriveInfo AutomountFileSystemDrive(string name)583        {584            PSDriveInfo result = null;585 586            // Check to see if it could be a "auto-mounted"587            // file system drive.  If so, add the new drive588            // to the global scope and return it589 590            if (name.Length == 1)591            {592                try593                {594                    System.IO.DriveInfo driveInfo = new System.IO.DriveInfo(name);595                    result = AutomountFileSystemDrive(driveInfo);596                }597                catch (LoopFlowException)598                {599                    throw;600                }601                catch (PipelineStoppedException)602                {603                    throw;604                }605                catch (ActionPreferenceStopException)606                {607                    throw;608                }609                catch (Exception)610                {611                    // Catch all exceptions and continue since the drive does not exist612                    // This action wasn't requested by the user and as such we don't613                    // want to expose the user to any error conditions other than614                    // DriveNotFoundException which will be thrown by the caller615                }616            }617 618            return result;619        }620 621        private PSDriveInfo AutomountFileSystemDrive(System.IO.DriveInfo systemDriveInfo)622        {623            PSDriveInfo result = null;624 625            if (!IsProviderLoaded(this.ExecutionContext.ProviderNames.FileSystem))626            {627                s_tracer.WriteLine("The {0} provider is not loaded", this.ExecutionContext.ProviderNames.FileSystem);628                return null;629            }630 631            // Since the drive does exist, add it.632 633            try634            {635                // Get the FS provider636 637                DriveCmdletProvider driveProvider =638                    GetDriveProviderInstance(this.ExecutionContext.ProviderNames.FileSystem);639 640                if (driveProvider != null)641                {642                    // Create a new drive643                    string systemDriveName = systemDriveInfo.Name.Substring(0, 1);644                    string volumeLabel = string.Empty;645                    string displayRoot = null;646 647                    try648                    {649                        // When run in an AppContainer, we may not have access to the volume label.650                        volumeLabel = systemDriveInfo.VolumeLabel;651                    }652                    catch (UnauthorizedAccessException) { }653 654                    // Get the actual root path for Network type drives655                    if (systemDriveInfo.DriveType == DriveType.Network)656                    {657                        try658                        {659                            displayRoot = Microsoft.PowerShell.Commands.FileSystemProvider660                                            .GetRootPathForNetworkDriveOrDosDevice(systemDriveInfo);661                        }662                        // We want to get root path of the network drive as extra information to display to the user.663                        // It's okay we failed to get the root path for some reason. We don't want to throw exception664                        // here as it would break the current behavior.665                        catch (Win32Exception) { }666                        catch (InvalidOperationException) { }667                    }668 669                    PSDriveInfo newPSDriveInfo =670                        new PSDriveInfo(671                            systemDriveName,672                            driveProvider.ProviderInfo,673                            systemDriveInfo.RootDirectory.FullName,674                            volumeLabel,675                            null,676                            displayRoot);677 678                    newPSDriveInfo.IsAutoMounted = true;679 680                    CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext);681 682                    newPSDriveInfo.DriveBeingCreated = true;683 684                    // Validate the drive with the provider685                    result = ValidateDriveWithProvider(driveProvider, newPSDriveInfo, context, false);686 687                    newPSDriveInfo.DriveBeingCreated = false;688 689                    if (result != null && !context.HasErrors())690                    {691                        // Create the drive in the global scope.692                        GlobalScope.NewDrive(result);693                    }694                }695            }696            catch (LoopFlowException)697            {698                throw;699            }700            catch (PipelineStoppedException)701            {702                throw;703            }704            catch (ActionPreferenceStopException)705            {706                throw;707            }708            catch (Exception e)709            {710                // Since the user isn't expecting this behavior, we don't711                // want to let errors find their way out. If there are any712                // failures we just don't mount the drive.713 714                MshLog.LogProviderHealthEvent(715                    this.ExecutionContext,716                    this.ExecutionContext.ProviderNames.FileSystem,717                    e,718                    Severity.Warning);719            }720 721            return result;722        }723 724        /// <summary>725        /// Auto-mounts a built-in drive.726        /// </summary>727        /// <remarks>728        /// Calls GetDrive(name, false) internally.729        /// </remarks>730        /// <param name="name">The name of the drive to load.</param>731        /// <returns></returns>732        internal PSDriveInfo AutomountBuiltInDrive(string name)733        {734            MountDefaultDrive(name, ExecutionContext);735            PSDriveInfo result = GetDrive(name, false);736 737            return result;738        }739 740        /// <summary>741        /// Automatically mount the specified drive.742        /// </summary>743        /// <remarks>744        /// Neither 'WSMan' nor 'Certificate' provider works in UNIX PS today.745        /// So this method currently does nothing on UNIX.746        /// </remarks>747        internal static void MountDefaultDrive(string name, ExecutionContext context)748        {749#if !UNIX750            PSModuleAutoLoadingPreference moduleAutoLoadingPreference =751                CommandDiscovery.GetCommandDiscoveryPreference(context, SpecialVariables.PSModuleAutoLoadingPreferenceVarPath, "PSModuleAutoLoadingPreference");752            if (moduleAutoLoadingPreference == PSModuleAutoLoadingPreference.None)753            {754                return;755            }756 757            string moduleName = null;758 759            // Note: For the certificate provider, we actually support the provider name as an alternative to760            // mount the default drive, since the provider names can be used for provider-qualified paths.761            // The WSMAN drive is the same as the provider name.762            if (763                string.Equals("Cert", name, StringComparison.OrdinalIgnoreCase) ||764                string.Equals("Certificate", name, StringComparison.OrdinalIgnoreCase)765                )766            {767                moduleName = "Microsoft.PowerShell.Security";768            }769            else if (string.Equals("WSMan", name, StringComparison.OrdinalIgnoreCase))770            {771                moduleName = "Microsoft.WSMan.Management";772            }773 774            if (!string.IsNullOrEmpty(moduleName))775            {776                s_tracer.WriteLine("Auto-mounting built-in drive: {0}", name);777                CommandInfo commandInfo = new CmdletInfo("Import-Module", typeof(Microsoft.PowerShell.Commands.ImportModuleCommand), null, null, context);778                Exception exception = null;779                s_tracer.WriteLine("Attempting to load module: {0}", moduleName);780                CommandDiscovery.AutoloadSpecifiedModule(moduleName, context, commandInfo.Visibility, out exception);781                if (exception != null)782                {783                    // Call-out to user code, catch-all OK784                }785            }786#endif787        }788 789        /// <summary>790        /// Determines if the specified automounted drive still exists. If not,791        /// the drive is removed.792        /// </summary>793        /// <param name="drive">794        /// The drive to validate or remove.795        /// </param>796        /// <param name="scope">797        /// The scope the drive is in.  This will be used to remove the drive798        /// if necessary.799        /// </param>800        /// <returns>801        /// True if the drive is still valid, false if the drive was removed.802        /// </returns>803        private bool ValidateOrRemoveAutoMountedDrive(PSDriveInfo drive, SessionStateScope scope)804        {805            bool result = true;806            try807            {808                System.IO.DriveInfo systemDriveInfo = new System.IO.DriveInfo(drive.Name);809                result = systemDriveInfo.DriveType != DriveType.NoRootDirectory;810            }811            catch (LoopFlowException)812            {813                throw;814            }815            catch (PipelineStoppedException)816            {817                throw;818            }819            catch (ActionPreferenceStopException)820            {821                throw;822            }823            catch (Exception)824            {825                // Assume any exception means the drive is no longer valid and needs826                // to be removed.827 828                result = false;829            }830 831            if (!result)832            {833                DriveCmdletProvider driveProvider = null;834 835                try836                {837                    driveProvider =838                        GetDriveProviderInstance(this.ExecutionContext.ProviderNames.FileSystem);839                }840                catch (NotSupportedException)841                {842                }843                catch (ProviderNotFoundException)844                {845                }846 847                if (driveProvider != null)848                {849                    CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext);850 851                    try852                    {853                        // Give the provider a chance to cleanup854                        driveProvider.RemoveDrive(drive, context);855                    }856                    // Ignore any exceptions the provider throws because we857                    // are doing this without an explicit request from the858                    // user. Since the provider can throw any exception859                    // we must catch all exceptions here.860                    catch (Exception)861                    {862                    }863 864                    scope.RemoveDrive(drive);865                }866            }867 868            return result;869        }870 871        /// <summary>872        /// If a VHD is mounted to a drive prior to the PowerShell session being launched,873        /// then such a drive has to be validated for its existence before performing874        /// any operations on that drive to make sure that the drive is not unmounted.875        /// </summary>876        /// <param name="drive"></param>877        /// <returns>Absence of mounted drive for FileSystem provider or False for other provider types.</returns>878        private bool IsAStaleVhdMountedDrive(PSDriveInfo drive)879        {880            bool result = false;881 882            // check that drive's provider type is FileSystem883            if ((drive.Provider != null) && (!drive.Provider.NameEquals(this.ExecutionContext.ProviderNames.FileSystem)))884            {885                return false;886            }887 888            // A VHD mounted drive gets detected with a DriveType of DriveType.Fixed889            // when the VHD is mounted, however if the drive is unmounted, such a890            // stale drive is no longer valid and gets detected with DriveType.NoRootDirectory.891            // We would hit this situation in the following scenario:892            //  1. Launch Powershell session 'A' and mount the VHD.893            //  2. Launch different powershell session 'B'.894            //  3. Unmount the VHD in session 'A'.895            // The drive pointing to VHD in session 'B' gets detected as DriveType.NoRootDirectory896            // after the VHD is removed in session 'A'.897            if (drive != null && !string.IsNullOrEmpty(drive.Name) && drive.Name.Length == 1)898            {899                try900                {901                    char driveChar = Convert.ToChar(drive.Name, CultureInfo.InvariantCulture);902 903                    if (char.ToUpperInvariant(driveChar) >= 'A' && char.ToUpperInvariant(driveChar) <= 'Z')904                    {905                        DriveInfo systemDriveInfo = new DriveInfo(drive.Name);906 907                        if (systemDriveInfo.DriveType == DriveType.NoRootDirectory)908                        {909                            if (!Directory.Exists(drive.Root))910                            {911                                result = true;912                            }913                        }914                    }915                }916                catch (ArgumentException)917                {918                    // At this point, We dont care if the drive is not a valid drive that does not host the VHD.919                }920            }921 922            return result;923        }924 925        /// <summary>926        /// Gets all the drives for a specific provider.927        /// </summary>928        /// <param name="providerId">929        /// The identifier for the provider to retrieve the drives for.930        /// </param>931        /// <returns>932        /// An IEnumerable that contains the drives for the specified provider.933        /// </returns>934        internal Collection<PSDriveInfo> GetDrivesForProvider(string providerId)935        {936            if (string.IsNullOrEmpty(providerId))937            {938                return Drives(null);939            }940 941            // Ensure that the provider name resolves to a single provider942            GetSingleProvider(providerId);943 944            Collection<PSDriveInfo> drives = new Collection<PSDriveInfo>();945 946            foreach (PSDriveInfo drive in Drives(null))947            {948                if (drive != null &&949                    drive.Provider.NameEquals(providerId))950                {951                    drives.Add(drive);952                }953            }954 955            return drives;956        }957 958        #endregion GetDrive959 960        #region RemoveDrive961        /// <summary>962        /// Removes the drive with the specified name.963        /// </summary>964        /// <param name="driveName">965        /// The name of the drive to remove.966        /// </param>967        /// <param name="force">968        /// Determines whether drive should be forcefully removed even if there was errors.969        /// </param>970        /// <param name="scopeID">971        /// The ID of the scope from which to remove the drive.972        /// If the scope ID is null or empty, the scope hierarchy will be searched973        /// starting at the current scope through all the parent scopes to the974        /// global scope until a drive of the given name is found to remove.975        /// </param>976        internal void RemoveDrive(string driveName, bool force, string scopeID)977        {978            if (driveName == null)979            {980                throw PSTraceSource.NewArgumentNullException(nameof(driveName));981            }982 983            PSDriveInfo drive = GetDrive(driveName, scopeID);984 985            if (drive == null)986            {987                DriveNotFoundException e = new DriveNotFoundException(988                    driveName,989                    "DriveNotFound",990                    SessionStateStrings.DriveNotFound);991                throw e;992            }993 994            RemoveDrive(drive, force, scopeID);995        }996 997        /// <summary>998        /// Removes the drive with the specified name.999        /// </summary>1000        /// <param name="driveName">1001        /// The name of the drive to remove.1002        /// </param>1003        /// <param name="force">1004        /// Determines whether drive should be forcefully removed even if there was errors.1005        /// </param>1006        /// <param name="scopeID">1007        /// The ID of the scope from which to remove the drive.1008        /// If the scope ID is null or empty, the scope hierarchy will be searched1009        /// starting at the current scope through all the parent scopes to the1010        /// global scope until a drive of the given name is found to remove.1011        /// </param>1012        /// <param name="context">1013        /// The context of the command.1014        /// </param>1015        internal void RemoveDrive(1016            string driveName,1017            bool force,1018            string scopeID,1019            CmdletProviderContext context)1020        {1021            if (driveName == null)1022            {1023                throw PSTraceSource.NewArgumentNullException(nameof(driveName));1024            }1025 1026            Dbg.Diagnostics.Assert(1027                context != null,1028                "The caller should verify the context");1029 1030            PSDriveInfo drive = GetDrive(driveName, scopeID);1031 1032            if (drive == null)1033            {1034                DriveNotFoundException e = new DriveNotFoundException(1035                    driveName,1036                    "DriveNotFound",1037                    SessionStateStrings.DriveNotFound);1038                context.WriteError(new ErrorRecord(e.ErrorRecord, e));1039            }1040            else1041            {1042                RemoveDrive(drive, force, scopeID, context);1043            }1044        }1045 1046        /// <summary>1047        /// Removes the specified drive.1048        /// </summary>1049        /// <param name="drive">1050        /// The drive to be removed.1051        /// </param>1052        /// <param name="force">1053        /// Determines whether drive should be forcefully removed even if there was errors.1054        /// </param>1055        /// <param name="scopeID">1056        /// The ID of the scope from which to remove the drive.1057        /// If the scope ID is null or empty, the scope hierarchy will be searched1058        /// starting at the current scope through all the parent scopes to the1059        /// global scope until a drive of the given name is found to remove.1060        /// </param>1061        internal void RemoveDrive(PSDriveInfo drive, bool force, string scopeID)1062        {1063            if (drive == null)1064            {1065                throw PSTraceSource.NewArgumentNullException(nameof(drive));1066            }1067 1068            CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext);1069 1070            RemoveDrive(drive, force, scopeID, context);1071 1072            if (context.HasErrors() && !force)1073            {1074                context.ThrowFirstErrorOrDoNothing();1075            }1076        }1077 1078        /// <summary>1079        /// Removes the specified drive.1080        /// </summary>1081        /// <param name="drive">1082        /// The drive to be removed.1083        /// </param>1084        /// <param name="force">1085        /// Determines whether drive should be forcefully removed even if there was errors.1086        /// </param>1087        /// <param name="scopeID">1088        /// The ID of the scope from which to remove the drive.1089        /// If the scope ID is null or empty, the scope hierarchy will be searched1090        /// starting at the current scope through all the parent scopes to the1091        /// global scope until a drive of the given name is found to remove.1092        /// </param>1093        /// <param name="context">1094        /// The context which the core command is running.1095        /// </param>1096        /// <exception cref="ArgumentOutOfRangeException">1097        /// If <paramref name="scopeID"/> is less than zero or greater than the number of currently1098        /// active scopes.1099        /// </exception>1100        internal void RemoveDrive(1101            PSDriveInfo drive,1102            bool force,1103            string scopeID,1104            CmdletProviderContext context)1105        {1106            // Make sure that the CanRemoveDrive is called even if we are forcing1107            // the removal because we want the provider to have a chance to1108            // cleanup.1109 1110            bool canRemove = false;1111 1112            try1113            {1114                canRemove = CanRemoveDrive(drive, context);1115            }1116            catch (LoopFlowException)1117            {1118                throw;1119            }1120            catch (PipelineStoppedException)1121            {1122                throw;1123            }1124            catch (ActionPreferenceStopException)1125            {1126                throw;1127            }1128            catch (ProviderInvocationException)1129            {1130                if (!force)1131                {1132                    throw;1133                }1134            }1135 1136            // Now remove the drive if there was no error or we are forcing the removal1137 1138            if (canRemove || force)1139            {1140                // The scope ID wasn't defined or wasn't recognizable1141                // so do a search through the scopes looking for the1142                // drive.1143 1144                if (string.IsNullOrEmpty(scopeID))1145                {1146                    SessionStateScopeEnumerator scopeEnumerator =1147                        new SessionStateScopeEnumerator(CurrentScope);1148 1149                    foreach (SessionStateScope scope in scopeEnumerator)1150                    {1151                        try1152                        {1153                            PSDriveInfo result = scope.GetDrive(drive.Name);1154                            if (result != null)1155                            {1156                                scope.RemoveDrive(drive);1157 1158                                // If the drive is the current drive for the provider, remove1159                                // it from the current drive list.1160 1161                                if (ProvidersCurrentWorkingDrive[drive.Provider] == result)1162                                {1163                                    ProvidersCurrentWorkingDrive[drive.Provider] = null;1164                                }1165 1166                                break;1167                            }1168                        }1169                        catch (ArgumentException)1170                        {1171                        }1172                    }1173                }1174                else1175                {1176                    SessionStateScope scope = GetScopeByID(scopeID);1177                    scope.RemoveDrive(drive);1178 1179                    // If the drive is the current drive for the provider, remove1180                    // it from the current drive list.1181 1182                    if (ProvidersCurrentWorkingDrive[drive.Provider] == drive)1183                    {1184                        ProvidersCurrentWorkingDrive[drive.Provider] = null;1185                    }1186                }1187            }1188            else1189            {1190                PSInvalidOperationException e =1191                    (PSInvalidOperationException)PSTraceSource.NewInvalidOperationException(1192                        SessionStateStrings.DriveRemovalPreventedByProvider,1193                        drive.Name,1194                        drive.Provider);1195 1196                context.WriteError(1197                    new ErrorRecord(1198                        e.ErrorRecord,1199                        e));1200            }

Showing the first 1,200 of 1437 lines. Download the file for the rest.