Repository: PowerShell/PowerShell
File: src/System.Management.Automation/namespaces/FileSystemProvider.cs (C#)

Code before:
            // but unfortunately, FileInfo offers no Try() methods that
            // let us check if we _could_ open the file.
            try
            {
                FileInfo testFile = new FileInfo(path);
            }
            catch (Exception e)
            {
                if ((e is ArgumentNullException) ||
                    (e is ArgumentException) ||
                    (e is System.Security.SecurityException) ||
                    (e is UnauthorizedAccessException) ||
                    (e is PathTooLongException) ||
                    (e is NotSupportedException))
                {
                    return false;
                }
                else
                {
                    throw;
                }
            }

            return true;
        }

        /// <summary>
        /// Gets the item at the specified path.
        /// </summary>
        /// <param name="path">
        /// A fully qualified path representing a file or directory in the
        /// file system.
        /// </param>
        /// <returns>
        /// Nothing.  FileInfo and DirectoryInfo objects are written to the
        /// context's pipeline.
        /// </returns>
        /// <exception cref="System.ArgumentException">
        ///     path is null or empty.
        /// </exception>
        protected override void GetItem(string path)
        {
            // Validate the argument
            bool isContainer = false;

            if (string.IsNullOrEmpty(path))
            {
                // The parameter was null, throw an exception
                throw PSTraceSource.NewArgumentException(nameof(path));
            }


Review comment (bug):
I think this logic might not be incorrect, on non-Windows you get the following values for these functions

+ `GetInvalidPathChars()` - `0x00 NULL`
+ `GetInvalidFileNameChars()` - Above plus `0x2F '/'`

On Windows these are

+ `GetInvalidPathChars()` - `0x00` to `0x1F`, `0x7C '|'`
+ `GetInvalidFileNameChars()` - Above plus `0x22 - '"'`, `0x2A - '*'`, `0x2F - '/'`, `0x3A - ':'`, `0x3C - '<'`, `0x3E - '>'`, `0x3F - '?'`, `0x5C - '\'`

Currently the code here is only going to check those extra chars for the filename but each folder component in the path cannot be one of the invalid FileNameChars. For example `C:\Windows\Foo*Bar\test` is invalid as `Foo*Bar` contains `*` which is an invalid filename but the code here is only going to check `test` with those extra chars.

Even splitting the path may not be enough as you'll need to validate the drive root is a valid path.

Finally NTFS ADS parts in the filename will trigger this check

```powershell
[System.IO.Path]::GetFileName('C:\temp\test\file.txt:$data')
file.txt:$data
```

The ADS portion is separated by `:` but `GetFileName` won't split that out and `:` in there is going to trigger the check.

Code after:
            // but unfortunately, FileInfo offers no Try() methods that
            // let us check if we _could_ open the file.
            try
            {
                FileInfo testFile = new FileInfo(path);
            }
            catch (Exception e)
            {
                if ((e is ArgumentNullException) ||
                    (e is ArgumentException) ||
                    (e is System.Security.SecurityException) ||
                    (e is UnauthorizedAccessException) ||
                    (e is PathTooLongException) ||
                    (e is NotSupportedException))
                {
                    return false;
                }
                else
                {
                    throw;
                }
            }

            // .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-characters
            // We need to check for invalid characters ourselves.  `Path.GetInvalidFileNameChars()` is a supserset of `Path.GetInvalidPathChars()`

            // Remove drive root first
            string pathWithoutDriveRoot = path.Substring(Path.GetPathRoot(path).Length);
            char[] invalidFileChars = Path.GetInvalidFileNameChars();

            foreach (string segment in pathWithoutDriveRoot.Split(Path.DirectorySeparatorChar))
            {
                if (segment.IndexOfAny(invalidFileChars) != -1)
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Gets the item at the specified path.
        /// </summary>
        /// <param name="path">
        /// A fully qualified path representing a file or directory in the
        /// file system.
        /// </param>
        /// <returns>
        /// Nothing.  FileInfo and DirectoryInfo objects are written to the
        /// context's pipeline.