Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
FileSystemProvider.cs9539 linesDownload Raw Back to namespaces
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.Collections.ObjectModel;8using System.ComponentModel;9using System.Diagnostics;10using System.Diagnostics.CodeAnalysis;11using System.Globalization;12using System.IO;13using System.Linq;14using System.Management.Automation;15using System.Management.Automation.Internal;16using System.Management.Automation.Provider;17using System.Management.Automation.Runspaces;18using System.Runtime.InteropServices;19using System.Security;20using System.Security.AccessControl;21using System.Text;22using System.Threading.Tasks;23using System.Xml;24using System.Xml.XPath;25 26using Microsoft.Win32.SafeHandles;27 28using Dbg = System.Management.Automation;29 30namespace Microsoft.PowerShell.Commands31{32    #region FileSystemProvider33 34    /// <summary>35    /// Defines the implementation of a File System Provider.  This provider36    /// allows for stateless namespace navigation of the file system.37    /// </summary>38    [CmdletProvider(FileSystemProvider.ProviderName, ProviderCapabilities.Credentials | ProviderCapabilities.Filter | ProviderCapabilities.ShouldProcess)]39    [OutputType(typeof(FileSecurity), ProviderCmdlet = ProviderCmdlet.SetAcl)]40    [OutputType(typeof(string), typeof(PathInfo), ProviderCmdlet = ProviderCmdlet.ResolvePath)]41    [OutputType(typeof(PathInfo), ProviderCmdlet = ProviderCmdlet.PushLocation)]42    [OutputType(typeof(PathInfo), ProviderCmdlet = ProviderCmdlet.PopLocation)]43    [OutputType(typeof(byte), typeof(string), ProviderCmdlet = ProviderCmdlet.GetContent)]44    [OutputType(typeof(FileInfo), ProviderCmdlet = ProviderCmdlet.GetItem)]45    [OutputType(typeof(FileInfo), typeof(DirectoryInfo), ProviderCmdlet = ProviderCmdlet.GetChildItem)]46    [OutputType(typeof(FileSecurity), typeof(DirectorySecurity), ProviderCmdlet = ProviderCmdlet.GetAcl)]47    [OutputType(typeof(bool), typeof(string), typeof(FileInfo), typeof(DirectoryInfo), ProviderCmdlet = ProviderCmdlet.GetItem)]48    [OutputType(typeof(bool), typeof(string), typeof(DateTime), typeof(System.IO.FileInfo), typeof(System.IO.DirectoryInfo), ProviderCmdlet = ProviderCmdlet.GetItemProperty)]49    [OutputType(typeof(string), typeof(System.IO.FileInfo), typeof(DirectoryInfo), ProviderCmdlet = ProviderCmdlet.NewItem)]50    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "This coupling is required")]51    public sealed partial class FileSystemProvider : NavigationCmdletProvider,52                                                     IContentCmdletProvider,53                                                     IPropertyCmdletProvider,54                                                     ISecurityDescriptorCmdletProvider,55                                                     ICmdletProviderSupportsHelp56    {57        // 4MB gives the best results without spiking the resources on the remote connection for file transfers between pssessions.58        // NOTE: The script used to copy file data from session (PSCopyFromSessionHelper) has a59        // maximum fragment size value for security.  If FILETRANSFERSIZE changes make sure the60        // copy script will accommodate the new value.61        private const int FILETRANSFERSIZE = 4 * 1024 * 1024;62 63        private const int COPY_FILE_ACTIVITY_ID = 0;64        private const int REMOVE_FILE_ACTIVITY_ID = 0;65 66        // The name of the key in an exception's Data dictionary when attempting67        // to copy an item onto itself.68        private const string SelfCopyDataKey = "SelfCopy";69 70        /// <summary>71        /// An instance of the PSTraceSource class used for trace output72        /// using "FileSystemProvider" as the category.73        /// </summary>74        [Dbg.TraceSource("FileSystemProvider", "The namespace navigation provider for the file system")]75        private static readonly Dbg.PSTraceSource s_tracer =76            Dbg.PSTraceSource.GetTracer("FileSystemProvider", "The namespace navigation provider for the file system");77 78        /// <summary>79        /// Gets the name of the provider.80        /// </summary>81        public const string ProviderName = "FileSystem";82 83        /// <summary>84        /// Initializes a new instance of the FileSystemProvider class. Since this85        /// object needs to be stateless, the constructor does nothing.86        /// </summary>87        public FileSystemProvider()88        {89        }90 91        private Collection<WildcardPattern> _excludeMatcher = null;92 93        private static readonly System.IO.EnumerationOptions _enumerationOptions = new System.IO.EnumerationOptions94        {95            MatchType = MatchType.Win32,96            MatchCasing = MatchCasing.CaseInsensitive,97            AttributesToSkip = 0 // Default is to skip Hidden and System files, so we clear this to retain existing behavior98        };99 100        /// <summary>101        /// Converts all / in the path to \102        /// </summary>103        /// <param name="path">104        /// The path to normalize.105        /// </param>106        /// <returns>107        /// The path with all / normalized to \108        /// </returns>109        internal static string NormalizePath(string path)110        {111            return GetCorrectCasedPath(path.Replace(StringLiterals.AlternatePathSeparator, StringLiterals.DefaultPathSeparator));112        }113 114        /// <summary>115        /// Get the correct casing for a path.  This method assumes it's being called by NormalizePath()116        /// so that the path is already normalized.117        /// </summary>118        /// <param name="path">119        /// The path to retrieve.120        /// </param>121        /// <returns>122        /// The path with accurate casing if item exists, otherwise it returns path that was passed in.123        /// </returns>124        private static string GetCorrectCasedPath(string path)125        {126            // Only apply to directories where there are issues with some tools if the casing127            // doesn't match the source like git128            if (Directory.Exists(path))129            {130                string exactPath = string.Empty;131                int itemsToSkip = 0;132                if (Utils.PathIsUnc(path))133                {134                    // With the Split method, a UNC path like \\server\share, we need to skip135                    // trying to enumerate the server and share, so skip the first two empty136                    // strings, then server, and finally share name.137                    itemsToSkip = 4;138                }139 140                var items = path.Split(StringLiterals.DefaultPathSeparator);141                for (int i = 0; i < items.Length; i++)142                {143                    if (itemsToSkip-- > 0)144                    {145                        // This handles the UNC server and share and 8.3 short path syntax146                        exactPath += items[i] + StringLiterals.DefaultPathSeparator;147                        continue;148                    }149                    else if (string.IsNullOrEmpty(exactPath))150                    {151                        // This handles the drive letter or / root path start152                        exactPath = items[i] + StringLiterals.DefaultPathSeparator;153                    }154                    else if (string.IsNullOrEmpty(items[i]) && i == items.Length - 1)155                    {156                        // This handles the trailing slash case157                        if (!exactPath.EndsWith(StringLiterals.DefaultPathSeparator))158                        {159                            exactPath += StringLiterals.DefaultPathSeparator;160                        }161 162                        break;163                    }164                    else if (items[i].Contains('~'))165                    {166                        // This handles short path names167                        exactPath += StringLiterals.DefaultPathSeparator + items[i];168                    }169                    else170                    {171                        // Use GetFileSystemEntries to get the correct casing of this element172                        try173                        {174                            var entries = Directory.GetFileSystemEntries(exactPath, items[i]);175                            if (entries.Length > 0)176                            {177                                exactPath = entries[0];178                            }179                            else180                            {181                                // If previous call didn't return anything, something failed so we just return the path we were given182                                return path;183                            }184                        }185                        catch186                        {187                            // If we can't enumerate, we stop and just return the original path188                            return path;189                        }190                    }191                }192 193                return exactPath;194            }195            else196            {197                return path;198            }199        }200 201        /// <summary>202        /// Checks if the item exist at the specified path. if it exists then creates203        /// appropriate directoryinfo or fileinfo object.204        /// </summary>205        /// <param name="path">206        /// Refers to the item for which we are checking for existence and creating filesysteminfo object.207        /// </param>208        /// <param name="isContainer">209        /// Return true if path points to a directory else returns false.210        /// </param>211        /// <returns>FileInfo or DirectoryInfo object.</returns>212        /// <exception cref="System.ArgumentNullException">213        /// The path is null.214        /// </exception>215        /// <exception cref="System.IO.IOException">216        /// I/O error occurs.217        /// </exception>218        /// <exception cref="System.UnauthorizedAccessException">219        /// An I/O error or a specific type of security error.220        /// </exception>221        private static FileSystemInfo GetFileSystemInfo(string path, out bool isContainer)222        {223            // We use 'FileInfo.Attributes' (not 'FileInfo.Exist')224            // because we want to get exceptions225            // like UnauthorizedAccessException or IOException.226            FileSystemInfo fsinfo = new FileInfo(path);227            var attr = fsinfo.Attributes;228            var exists = (int)attr != -1;229            isContainer = exists && attr.HasFlag(FileAttributes.Directory);230 231            if (exists)232            {233                if (isContainer)234                {235                    return new DirectoryInfo(path);236                }237                else238                {239                    return fsinfo;240                }241            }242 243            return null;244        }245 246        /// <summary>247        /// Overrides the method of CmdletProvider, considering the additional248        /// dynamic parameters of FileSystemProvider.249        /// </summary>250        /// <returns>251        /// whether the filter or attribute filter is set.252        /// </returns>253        internal override bool IsFilterSet()254        {255            bool attributeFilterSet = false;256            GetChildDynamicParameters fspDynamicParam = DynamicParameters as GetChildDynamicParameters;257            if (fspDynamicParam != null)258            {259                attributeFilterSet = (260                    (fspDynamicParam.Attributes != null)261                        || (fspDynamicParam.Directory)262                        || (fspDynamicParam.File)263                        || (fspDynamicParam.Hidden)264                        || (fspDynamicParam.ReadOnly)265                        || (fspDynamicParam.System));266            }267 268            return (attributeFilterSet || base.IsFilterSet());269        }270 271        /// <summary>272        /// Gets the dynamic parameters for get-childnames on the273        /// FileSystemProvider.274        /// We currently only support one dynamic parameter,275        /// "Attributes" that returns an enum evaluator for the276        /// given expression.277        /// </summary>278        /// <param name="path">279        /// If the path was specified on the command line, this is the path280        /// to the item for which to get the dynamic parameters.281        /// </param>282        /// <returns>283        /// An object that has properties and fields decorated with284        /// parsing attributes similar to a cmdlet class.285        /// </returns>286        protected override object GetChildNamesDynamicParameters(string path)287        {288            return new GetChildDynamicParameters();289        }290 291        /// <summary>292        /// Gets the dynamic parameters for get-childitems on the293        /// FileSystemProvider.294        /// We currently only support one dynamic parameter,295        /// "Attributes" that returns an enum evaluator for the296        /// given expression.297        /// </summary>298        /// <param name="path">299        /// If the path was specified on the command line, this is the path300        /// to the item for which to get the dynamic parameters.301        /// </param>302        /// <param name="recurse">303        /// Ignored.304        /// </param>305        /// <returns>306        /// An object that has properties and fields decorated with307        /// parsing attributes similar to a cmdlet class.308        /// </returns>309        protected override object GetChildItemsDynamicParameters(string path, bool recurse)310        {311            return new GetChildDynamicParameters();312        }313 314        /// <summary>315        /// Gets the dynamic parameters for Copy-Item on the FileSystemProvider.316        /// </summary>317        /// <param name="path">Source for the copy operation.</param>318        /// <param name="destination">Destination for the copy operation.</param>319        /// <param name="recurse">Whether to recurse.</param>320        /// <returns></returns>321        protected override object CopyItemDynamicParameters(string path, string destination, bool recurse)322        {323            return new CopyItemDynamicParameters();324        }325 326        #region ICmdletProviderSupportsHelp members327 328        /// <summary>329        /// Implementation of ICmdletProviderSupportsHelp interface.330        /// Gets provider-specific help content for the corresponding cmdlet.331        /// </summary>332        /// <param name="helpItemName">333        /// Name of command that the help is requested for.334        /// </param>335        /// <param name="path">336        /// Not used here.337        /// </param>338        /// <returns>339        /// The MAML help XML that should be presented to the user.340        /// </returns>341        public string GetHelpMaml(string helpItemName, string path)342        {343            // Get the verb and noun from helpItemName344            //345            string verb = null;346            string noun = null;347            XmlReader reader = null;348 349            try350            {351                if (!string.IsNullOrEmpty(helpItemName))352                {353                    CmdletInfo.SplitCmdletName(helpItemName, out verb, out noun);354                }355                else356                {357                    return string.Empty;358                }359 360                if (string.IsNullOrEmpty(verb) || string.IsNullOrEmpty(noun))361                {362                    return string.Empty;363                }364 365                // Load the help file from the current UI culture subfolder366                XmlDocument document = new XmlDocument();367                CultureInfo currentUICulture = CultureInfo.CurrentUICulture;368                string fullHelpPath = Path.Combine(369                    string.IsNullOrEmpty(this.ProviderInfo.ApplicationBase) ? string.Empty : this.ProviderInfo.ApplicationBase,370                    currentUICulture.ToString(),371                    string.IsNullOrEmpty(this.ProviderInfo.HelpFile) ? string.Empty : this.ProviderInfo.HelpFile);372 373                XmlReaderSettings settings = new XmlReaderSettings();374                settings.XmlResolver = null;375                reader = XmlReader.Create(fullHelpPath, settings);376                document.Load(reader);377 378                // Add "msh" and "command" namespaces from the MAML schema379                XmlNamespaceManager nsMgr = new XmlNamespaceManager(document.NameTable);380                nsMgr.AddNamespace("msh", HelpCommentsParser.mshURI);381                nsMgr.AddNamespace("command", HelpCommentsParser.commandURI);382 383                // Compose XPath query to select the appropriate node based on the cmdlet384                string xpathQuery = string.Format(385                    CultureInfo.InvariantCulture,386                    HelpCommentsParser.ProviderHelpCommandXPath,387                    "[@id='FileSystem']",388                    verb,389                    noun);390 391                // Execute the XPath query and return its MAML snippet392                XmlNode result = document.SelectSingleNode(xpathQuery, nsMgr);393                if (result != null)394                {395                    return result.OuterXml;396                }397            }398            catch (XmlException)399            {400                return string.Empty;401            }402            catch (PathTooLongException)403            {404                return string.Empty;405            }406            catch (IOException)407            {408                return string.Empty;409            }410            catch (UnauthorizedAccessException)411            {412                return string.Empty;413            }414            catch (NotSupportedException)415            {416                return string.Empty;417            }418            catch (SecurityException)419            {420                return string.Empty;421            }422            catch (XPathException)423            {424                return string.Empty;425            }426            finally427            {428                if (reader != null)429                {430                    ((IDisposable)reader).Dispose();431                }432            }433 434            return string.Empty;435        }436 437        #endregion438 439        #region CmdletProvider members440 441        /// <summary>442        /// Starts the File System provider. This method sets the Home for the443        /// provider to providerInfo.Home if specified, and %USERPROFILE%444        /// otherwise.445        /// </summary>446        /// <param name="providerInfo">447        /// The ProviderInfo object that holds the provider's configuration.448        /// </param>449        /// <returns>450        /// The updated ProviderInfo object that holds the provider's configuration.451        /// </returns>452        protected override ProviderInfo Start(ProviderInfo providerInfo)453        {454            // Set the home folder for the user455            if (providerInfo != null && string.IsNullOrEmpty(providerInfo.Home))456            {457                // %USERPROFILE% - indicate where a user's home directory is located in the file system.458                string homeDirectory = Environment.GetEnvironmentVariable(Platform.CommonEnvVariableNames.Home);459 460                if (!string.IsNullOrEmpty(homeDirectory))461                {462                    if (Directory.Exists(homeDirectory))463                    {464                        s_tracer.WriteLine("Home = {0}", homeDirectory);465                        providerInfo.Home = homeDirectory;466                    }467                    else468                    {469                        s_tracer.WriteLine("Not setting home directory {0} - does not exist", homeDirectory);470                    }471                }472            }473 474            // OneDrive placeholder support (issue #8315)475            // make it so OneDrive placeholders are perceived as such with *all* their attributes accessible476#if !UNIX477            // The placeholder mode management APIs Rtl(Set|Query)(Process|Thread)PlaceholderCompatibilityMode478            // are only supported starting with Windows 10 version 1803 (build 17134)479            if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134, 0))480            {481                // let's be safe, don't change the PlaceHolderCompatibilityMode if the current one is not what we expect482                if (Interop.Windows.RtlQueryProcessPlaceholderCompatibilityMode() == Interop.Windows.PHCM_DISGUISE_PLACEHOLDER)483                {484                    Interop.Windows.RtlSetProcessPlaceholderCompatibilityMode(Interop.Windows.PHCM_EXPOSE_PLACEHOLDERS);485                }486            }487#endif488 489            return providerInfo;490        }491 492        #endregion CmdletProvider members493 494        #region DriveCmdletProvider members495 496        /// <summary>497        /// Determines if the specified drive can be mounted.498        /// </summary>499        /// <param name="drive">500        /// The drive that is going to be mounted.501        /// </param>502        /// <returns>503        /// The same drive that was passed in, if the drive can be mounted.504        /// null if the drive cannot be mounted.505        /// </returns>506        /// <exception cref="System.ArgumentNullException">507        /// drive is null.508        /// </exception>509        /// <exception cref="System.ArgumentException">510        /// drive root is null or empty.511        /// </exception>512        protected override PSDriveInfo NewDrive(PSDriveInfo drive)513        {514            // verify parameters515            if (drive == null)516            {517                throw PSTraceSource.NewArgumentNullException(nameof(drive));518            }519 520            if (string.IsNullOrEmpty(drive.Root))521            {522                throw PSTraceSource.NewArgumentException("drive.Root");523            }524 525            // -Persist switch parameter is supported only for Network paths.526            if (drive.Persist && !PathIsNetworkPath(drive.Root))527            {528                ErrorRecord er = new ErrorRecord(new NotSupportedException(FileSystemProviderStrings.PersistNotSupported), "DriveRootNotNetworkPath", ErrorCategory.InvalidArgument, drive);529                ThrowTerminatingError(er);530            }531 532            if (IsNetworkMappedDrive(drive))533            {534                // MapNetworkDrive facilitates to map the newly535                // created PS Drive to a network share.536                MapNetworkDrive(drive);537            }538 539            // The drive is valid if the item exists or the540            // drive is not a fixed drive.  We want to allow541            // a drive to exist for floppies and other such\542            // removable media, even if the media isn't in place.543            bool driveIsFixed = true;544            PSDriveInfo result = null;545 546            try547            {548                // See if the drive is a fixed drive.549                string pathRoot = Path.GetPathRoot(drive.Root);550                DriveInfo driveInfo = new DriveInfo(pathRoot);551 552                if (driveInfo.DriveType != DriveType.Fixed)553                {554                    driveIsFixed = false;555                }556 557                // The current drive is a network drive.558                if (driveInfo.DriveType == DriveType.Network)559                {560                    drive.IsNetworkDrive = true;561                }562            }563            catch (ArgumentException) // swallow ArgumentException incl. ArgumentNullException564            {565            }566 567            bool validDrive = true;568 569            if (driveIsFixed)570            {571                // Since the drive is fixed, ensure the root is valid.572                validDrive = Directory.Exists(drive.Root);573            }574 575            if (validDrive)576            {577                result = drive;578            }579            else580            {581                string error = StringUtil.Format(FileSystemProviderStrings.DriveRootError, drive.Root);582                Exception e = new IOException(error);583                WriteError(new ErrorRecord(e, "DriveRootError", ErrorCategory.ReadError, drive));584            }585 586            drive.Trace();587 588            return result;589        }590 591        /// <summary>592        /// MapNetworkDrive facilitates to map the newly created PS Drive to a network share.593        /// </summary>594        /// <param name="drive">The PSDrive info that would be used to create a new PS drive.</param>595        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Can be static on Unix but not on Windows.")]596 597        private void MapNetworkDrive(PSDriveInfo drive)598        {599#if UNIX600            throw new PlatformNotSupportedException();601#else602            // Porting note: mapped network drives are only supported on Windows603            if (drive != null && !string.IsNullOrEmpty(drive.Root))604            {605                // By default the connection is not persisted.606                int connectType = Interop.Windows.CONNECT_NOPERSIST;607 608                string driveName = null;609                byte[] passwd = null;610                string userName = null;611 612                if (drive.Persist)613                {614                    if (IsSupportedDriveForPersistence(drive))615                    {616                        connectType = Interop.Windows.CONNECT_UPDATE_PROFILE;617                        driveName = drive.Name + ":";618                        drive.DisplayRoot = drive.Root;619                    }620                    else621                    {622                        ErrorRecord er = new ErrorRecord(new InvalidOperationException(FileSystemProviderStrings.InvalidDriveName), "DriveNameNotSupportedForPersistence", ErrorCategory.InvalidOperation, drive);623                        ThrowTerminatingError(er);624                    }625                }626 627                // If alternate credentials is supplied then use them to get connected to network share.628                if (drive.Credential != null && !drive.Credential.Equals(PSCredential.Empty))629                {630                    userName = drive.Credential.UserName;631 632                    passwd = SecureStringHelper.GetData(drive.Credential.Password);633                }634 635                try636                {637                    int errorCode = Interop.Windows.WNetAddConnection2(driveName, drive.Root, passwd, userName, connectType);638 639                    if (errorCode != Interop.Windows.ERROR_SUCCESS)640                    {641                        ErrorRecord er = new ErrorRecord(new System.ComponentModel.Win32Exception(errorCode), "CouldNotMapNetworkDrive", ErrorCategory.InvalidOperation, drive);642                        ThrowTerminatingError(er);643                    }644 645                    if (connectType == Interop.Windows.CONNECT_UPDATE_PROFILE)646                    {647                        // Update the current PSDrive to be a persisted drive.648                        drive.IsNetworkDrive = true;649 650                        // PsDrive.Root is updated to the name of the Drive for651                        // drives targeting network path and being persisted.652                        drive.Root = driveName + @"\";653                    }654                }655                finally656                {657                    // Clear the password in the memory.658                    if (passwd != null)659                    {660                        Array.Clear(passwd);661                    }662                }663            }664#endif665        }666 667        /// <summary>668        /// ShouldMapNetworkDrive is a helper function used to detect if the669        /// requested PSDrive to be created has to be mapped to a network drive.670        /// </summary>671        /// <param name="drive"></param>672        /// <returns></returns>673        private static bool IsNetworkMappedDrive(PSDriveInfo drive)674        {675            bool shouldMapNetworkDrive = (drive != null && !string.IsNullOrEmpty(drive.Root) && PathIsNetworkPath(drive.Root)) &&676                                         (drive.Persist || (drive.Credential != null && !drive.Credential.Equals(PSCredential.Empty)));677 678            return shouldMapNetworkDrive;679        }680 681        /// <summary>682        /// RemoveDrive facilitates to remove network mapped persisted PSDrvie.683        /// </summary>684        /// <param name="drive">685        /// PSDrive info.686        /// </param>687        /// <returns>PSDrive info.688        /// </returns>689        protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)690        {691#if UNIX692            return drive;693#else694            if (IsNetworkMappedDrive(drive))695            {696                int flags = Interop.Windows.CONNECT_NOPERSIST;697                string driveName;698                if (drive.IsNetworkDrive)699                {700                    // Here we are removing only persisted network drives.701                    flags = Interop.Windows.CONNECT_UPDATE_PROFILE;702                    driveName = drive.Name + ":";703                }704                else705                {706                    // OSGTFS: 608188 PSDrive leaves a connection open after the drive is removed707                    // if a drive is not persisted or networkdrive, we need to use the actual root to remove the drive.708                    driveName = drive.Root;709                }710 711                // You need to actually remove the drive.712                int errorCode = Interop.Windows.WNetCancelConnection2(driveName, flags, force: true);713 714                if (errorCode != Interop.Windows.ERROR_SUCCESS)715                {716                    ErrorRecord er = new ErrorRecord(new System.ComponentModel.Win32Exception(errorCode), "CouldRemoveNetworkDrive", ErrorCategory.InvalidOperation, drive);717                    ThrowTerminatingError(er);718                }719            }720 721            return drive;722#endif723        }724 725        /// <summary>726        /// IsSupportedDriveForPersistence is a helper method used to727        /// check if the psdrive can be persisted or not.728        /// </summary>729        /// <param name="drive">730        /// PS Drive Info.731        /// </param>732        /// <returns>True if the drive can be persisted or else false.</returns>733        private static bool IsSupportedDriveForPersistence(PSDriveInfo drive)734        {735            bool isSupportedDriveForPersistence = false;736            if (drive != null && !string.IsNullOrEmpty(drive.Name) && drive.Name.Length == 1)737            {738                char driveChar = Convert.ToChar(drive.Name, CultureInfo.InvariantCulture);739 740                if (char.ToUpperInvariant(driveChar) >= 'A' && char.ToUpperInvariant(driveChar) <= 'Z')741                {742                    isSupportedDriveForPersistence = true;743                }744            }745 746            return isSupportedDriveForPersistence;747        }748 749        /// <summary>750        /// Return the UNC path for a given network drive751        /// using the Windows API.752        /// </summary>753        /// <param name="driveName"></param>754        /// <returns></returns>755        internal static string GetUNCForNetworkDrive(string driveName)756        {757#if UNIX758            return driveName;759#else760            string uncPath = null;761            if (!string.IsNullOrEmpty(driveName) && driveName.Length == 1)762            {763                int errorCode = Interop.Windows.GetUNCForNetworkDrive(driveName[0], out uncPath);764 765                if (errorCode != Interop.Windows.ERROR_SUCCESS)766                {767                    throw new System.ComponentModel.Win32Exception(errorCode);768                }769            }770 771            return uncPath;772#endif773        }774 775        /// <summary>776        /// Get the substituted path of a NetWork type MS-DOS device that is created by 'subst' command.777        /// When a MS-DOS device is of NetWork type, it could be:778        ///   1. Substitute a path in a drive that maps to a network location. For example:779        ///         net use z: \\scratch2\scratch\780        ///         subst y: z:\abc\781        ///   2. Substitute a network location directly. For example:782        ///         subst y: \\scratch2\scratch\783        /// </summary>784        /// <param name="driveName"></param>785        /// <returns></returns>786        internal static string GetSubstitutedPathForNetworkDosDevice(string driveName)787        {788#if UNIX789            throw new PlatformNotSupportedException();790        }791#else792            return WinGetSubstitutedPathForNetworkDosDevice(driveName);793        }794 795        private static string WinGetSubstitutedPathForNetworkDosDevice(string driveName)796        {797            string associatedPath = null;798            if (!string.IsNullOrEmpty(driveName) && driveName.Length == 1)799            {800                associatedPath = Interop.Windows.GetDosDeviceForNetworkPath(driveName[0]);801            }802 803            return associatedPath;804        }805#endif806 807        /// <summary>808        /// Get the root path for a network drive or MS-DOS device.809        /// </summary>810        /// <param name="driveInfo"></param>811        /// <returns></returns>812        internal static string GetRootPathForNetworkDriveOrDosDevice(DriveInfo driveInfo)813        {814            Dbg.Diagnostics.Assert(driveInfo.DriveType == DriveType.Network, "Caller should make sure it is a network drive.");815 816            string driveName = driveInfo.Name.Substring(0, 1);817            string rootPath = null;818 819            try820            {821                rootPath = GetUNCForNetworkDrive(driveName);822            }823            catch (Win32Exception)824            {825                if (driveInfo.IsReady)826                {827                    // The drive is ready but we failed to find the UNC path based on the drive name.828                    // In this case, it's possibly a MS-DOS device created by 'subst' command that829                    //  - substitutes a network location directly, or830                    //  - substitutes a path in a drive that maps to a network location831                    rootPath = GetSubstitutedPathForNetworkDosDevice(driveName);832                }833                else834                {835                    throw;836                }837            }838 839            return rootPath;840        }841 842        /// <summary>843        /// Returns a collection of all logical drives in the system.844        /// </summary>845        /// <returns>846        /// A collection of PSDriveInfo objects, one for each logical drive returned from847        /// System.Environment.GetLogicalDrives().848        /// </returns>849        protected override Collection<PSDriveInfo> InitializeDefaultDrives()850        {851            Collection<PSDriveInfo> results = new Collection<PSDriveInfo>();852 853            DriveInfo[] logicalDrives = DriveInfo.GetDrives();854            if (logicalDrives != null)855            {856                foreach (DriveInfo newDrive in logicalDrives)857                {858                    // Making sure to obey the StopProcessing.859                    if (Stopping)860                    {861                        results.Clear();862                        break;863                    }864 865                    // cover everything by the try-catch block, because some of the866                    // DriveInfo properties may throw exceptions867                    try868                    {869                        string newDriveName = newDrive.Name.Substring(0, 1);870 871                        string description = string.Empty;872                        string root = newDrive.Name;873                        string displayRoot = null;874 875                        if (newDrive.DriveType == DriveType.Fixed)876                        {877                            try878                            {879                                description = newDrive.VolumeLabel;880                            }881                            // trying to read the volume label may cause an882                            // IOException or SecurityException. Just default883                            // to an empty description.884                            catch (IOException)885                            {886                            }887                            catch (System.Security.SecurityException)888                            {889                            }890                            catch (System.UnauthorizedAccessException)891                            {892                            }893                        }894 895                        if (newDrive.DriveType == DriveType.Network)896                        {897                            // Platform notes: This is important because certain mount898                            // points on non-Windows are enumerated as drives by .NET, but899                            // the platform itself then has no real network drive support900                            // as required by this context. Solution: check for network901                            // drive support before using it.902#if UNIX903                            continue;904#else905                            displayRoot = GetRootPathForNetworkDriveOrDosDevice(newDrive);906#endif907                        }908 909                        if (newDrive.DriveType == DriveType.Fixed)910                        {911                            if (!newDrive.RootDirectory.Exists)912                            {913                                continue;914                            }915 916                            root = newDrive.RootDirectory.FullName;917                        }918 919#if UNIX920                        // Porting notes: On platforms with single root filesystems, ensure921                        // that we add a filesystem with the root "/" to the initial drive list,922                        // otherwise path handling will not work correctly because there923                        // is no : available to separate the filesystems from each other924                        if (root != StringLiterals.DefaultPathSeparatorString925                            && newDriveName == StringLiterals.DefaultPathSeparatorString)926                        {927                            root = StringLiterals.DefaultPathSeparatorString;928                        }929#endif930 931                        // Porting notes: On non-windows platforms .net can report two932                        // drives with the same root, make sure to only add one of those933                        bool skipDuplicate = false;934                        foreach (PSDriveInfo driveInfo in results)935                        {936                            if (driveInfo.Root == root)937                            {938                                skipDuplicate = true;939                                break;940                            }941                        }942 943                        if (skipDuplicate)944                        {945                            continue;946                        }947 948                        // Create a new VirtualDrive for each logical drive949                        PSDriveInfo newPSDriveInfo =950                            new PSDriveInfo(951                                newDriveName,952                                ProviderInfo,953                                root,954                                description,955                                null,956                                displayRoot);957 958                        // The network drive is detected when PowerShell is launched.959                        // Hence it has been persisted during one of the earlier sessions,960                        if (newDrive.DriveType == DriveType.Network)961                        {962                            newPSDriveInfo.IsNetworkDrive = true;963                        }964 965                        if (newDrive.DriveType != DriveType.Fixed)966                        {967                            newPSDriveInfo.IsAutoMounted = true;968                        }969 970                        // Porting notes: on the non-Windows platforms, the drive never971                        // uses : as a separator between drive and path972                        if (!Platform.IsWindows)973                        {974                            newPSDriveInfo.VolumeSeparatedByColon = false;975                        }976 977                        results.Add(newPSDriveInfo);978                    }979                    // If there are issues accessing properties of the DriveInfo, do980                    // not add the drive981                    catch (IOException)982                    {983                    }984                    catch (System.Security.SecurityException)985                    {986                    }987                    catch (System.UnauthorizedAccessException)988                    {989                    }990                }991            }992 993            results.Add(994                new PSDriveInfo(995                    DriveNames.TempDrive,996                    ProviderInfo,997                    Path.GetTempPath(),998                    SessionStateStrings.TempDriveDescription,999                    credential: null,1000                    displayRoot: null)1001            );1002 1003            return results;1004        }1005 1006        #endregion DriveCmdletProvider methods1007 1008        #region ItemCmdletProvider methods1009 1010        /// <summary>1011        /// Retrieves the dynamic parameters required for the Get-Item cmdlet.1012        /// </summary>1013        /// <param name="path">The path of the file to process.</param>1014        /// <returns>An instance of the FileSystemProviderGetItemDynamicParameters class that represents the dynamic parameters.</returns>1015        protected override object GetItemDynamicParameters(string path)1016        {1017            return new FileSystemProviderGetItemDynamicParameters();1018        }1019 1020        /// <summary>1021        /// Determines if the specified path is syntactically and semantically valid.1022        /// An example path looks like this1023        ///     C:\WINNT\Media\chimes.wav.1024        /// </summary>1025        /// <param name="path">1026        /// The fully qualified path to validate.1027        /// </param>1028        /// <returns>1029        /// True if the path is valid, false otherwise.1030        /// </returns>1031        protected override bool IsValidPath(string path)1032        {1033            // Path passed should be fully qualified path.1034            if (string.IsNullOrEmpty(path))1035            {1036                return false;1037            }1038 1039            // Normalize the path1040            path = NormalizePath(path);1041            path = EnsureDriveIsRooted(path);1042 1043#if !UNIX1044            // Remove alternate data stream references1045            // See if they've used the inline stream syntax. They have more than one colon.1046            int firstColon = path.IndexOf(':');1047            int secondColon = path.IndexOf(':', firstColon + 1);1048            if (secondColon > 0)1049            {1050                path = path.Substring(0, secondColon);1051            }1052#endif1053 1054            // Make sure the path is either drive rooted or UNC Path1055            if (!IsAbsolutePath(path) && !Utils.PathIsUnc(path))1056            {1057                return false;1058            }1059 1060            // Exceptions should only deal with exceptional circumstances,1061            // but unfortunately, FileInfo offers no Try() methods that1062            // let us check if we _could_ open the file.1063            try1064            {1065                FileInfo testFile = new FileInfo(path);1066            }1067            catch (Exception e)1068            {1069                if ((e is ArgumentNullException) ||1070                    (e is ArgumentException) ||1071                    (e is System.Security.SecurityException) ||1072                    (e is UnauthorizedAccessException) ||1073                    (e is PathTooLongException) ||1074                    (e is NotSupportedException))1075                {1076                    return false;1077                }1078                else1079                {1080                    throw;1081                }1082            }1083 1084            // .NET introduced a change where invalid characters are accepted https://learn.microsoft.com/en-us/dotnet/core/compatibility/2.1#path-apis-dont-throw-an-exception-for-invalid-characters1085            // We need to check for invalid characters ourselves.  `Path.GetInvalidFileNameChars()` is a supserset of `Path.GetInvalidPathChars()`1086 1087            // Remove drive root first1088            string pathWithoutDriveRoot = path.Substring(Path.GetPathRoot(path).Length);1089 1090            foreach (string segment in pathWithoutDriveRoot.Split(Path.DirectorySeparatorChar))1091            {1092                if (PathUtils.ContainsInvalidFileNameChars(segment))1093                {1094                    return false;1095                }1096            }1097 1098            return true;1099        }1100 1101        /// <summary>1102        /// Gets the item at the specified path.1103        /// </summary>1104        /// <param name="path">1105        /// A fully qualified path representing a file or directory in the1106        /// file system.1107        /// </param>1108        /// <returns>1109        /// Nothing.  FileInfo and DirectoryInfo objects are written to the1110        /// context's pipeline.1111        /// </returns>1112        /// <exception cref="System.ArgumentException">1113        ///     path is null or empty.1114        /// </exception>1115        protected override void GetItem(string path)1116        {1117            // Validate the argument1118            bool isContainer = false;1119 1120            if (string.IsNullOrEmpty(path))1121            {1122                // The parameter was null, throw an exception1123                throw PSTraceSource.NewArgumentException(nameof(path));1124            }1125 1126            try1127            {1128#if !UNIX1129                bool retrieveStreams = false;1130                FileSystemProviderGetItemDynamicParameters dynamicParameters = null;1131 1132                if (DynamicParameters != null)1133                {1134                    dynamicParameters = DynamicParameters as FileSystemProviderGetItemDynamicParameters;1135                    if (dynamicParameters != null)1136                    {1137                        if ((dynamicParameters.Stream != null) && (dynamicParameters.Stream.Length > 0))1138                        {1139                            retrieveStreams = true;1140                        }1141                        else1142                        {1143                            // See if they've used the inline stream syntax. They have more than one colon.1144                            int firstColon = path.IndexOf(':');1145                            int secondColon = path.IndexOf(':', firstColon + 1);1146                            if (secondColon > 0)1147                            {1148                                string streamName = path.Substring(secondColon + 1);1149                                path = path.Remove(secondColon);1150 1151                                retrieveStreams = true;1152                                dynamicParameters = new FileSystemProviderGetItemDynamicParameters();1153                                dynamicParameters.Stream = new string[] { streamName };1154                            }1155                        }1156                    }1157                }1158#endif1159 1160                FileSystemInfo result = GetFileSystemItem(path, ref isContainer, false);1161                if (result != null)1162                {1163#if !UNIX1164                    // If we want to retrieve the file streams, retrieve them.1165                    if (retrieveStreams)1166                    {1167                        foreach (string desiredStream in dynamicParameters.Stream)1168                        {1169                            // See that it matches the name specified1170                            WildcardPattern p = WildcardPattern.Get(desiredStream, WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant);1171                            bool foundStream = false;1172 1173                            foreach (AlternateStreamData stream in AlternateDataStreamUtilities.GetStreams(result.FullName))1174                            {1175                                if (!p.IsMatch(stream.Stream))1176                                {1177                                    continue;1178                                }1179 1180                                string outputPath = result.FullName + ":" + stream.Stream;1181                                // Alternate data streams can never be containers.1182                                WriteItemObject(stream, outputPath, isContainer: false);1183                                foundStream = true;1184                            }1185 1186                            if ((!WildcardPattern.ContainsWildcardCharacters(desiredStream)) && (!foundStream))1187                            {1188                                string errorMessage = StringUtil.Format(1189                                    FileSystemProviderStrings.AlternateDataStreamNotFound, desiredStream, result.FullName);1190                                Exception e = new FileNotFoundException(errorMessage, result.FullName);1191 1192                                WriteError(new ErrorRecord(1193                                    e,1194                                    "AlternateDataStreamNotFound",1195                                    ErrorCategory.ObjectNotFound,1196                                    path));1197                            }1198                        }1199                    }1200                    else

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