Skip to content

Discussion: Use literal paths for OutFile parameter on Invoke-RestMethod / Invoke-WebRequest #3174

Closed

Description

@ThreeFive-O

When using square brackets in the OutFile parameter of the web cmdlets the square brackets in the path act as a wildcard option/range operator.
Hence any square brackets in the OutFile parameter causes an error for the cmdlets.
Personally, when downloading a file, I always use a literal path, instead of specifying a file with wildcard support.

I would like to start a discussion if it makes sense to treat the OutFile parameter as a literal path.
Any opinions on that?

Maybe someone could contribute scenarios where wildcard support makes sense.

Note: Of course there are several workarounds in PowerShell to overcome this minor lack of comfort.

Steps to reproduce

Invoke-WebRequest https://raw.githubusercontent.com/PowerShell/PowerShell/master/README.md -OutFile ReadMe[Powershell].md

Expected behavior

Creates a ReadMe[Powershell].md file in current directory.

Actual behavior

Invoke-WebRequest : Cannot perform operation because the wildcard path ReadMe[Powershell].md did not resolve to a file.
At line:1 char:1
+ Invoke-WebRequest https://raw.githubusercontent.com/PowerShell/PowerS ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (ReadMe[Powershell].md:String) [Invoke-WebRequest], FileNotFoundException
    + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

Environment data

> $PSVersionTable
Name                           Value
----                           -----
PSVersion                      5.1.14393.693
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.14393.693
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

Activity

  1. HumanEquivalentUnit commented on Oct 6, 2017

    @HumanEquivalentUnit
    Contributor

    Agree that -OutFile makes more sense as a literal path. (It only makes sense as a literal path?). If the wildcard resolves to multiple files then Invoke-WebRequest throws an exception.

    But there could be scripts which depend on the wildcard resolving to a single filename - that does work, so it might be a breaking change. In that case -LiteralOutFile as a new parameter?

    Here is the code which saves to the file referencing a property QualifiedOutFile, which is defined here, it calls return (QualifyFilePath(OutFile));

    That's defined here

        private string QualifyFilePath(string path)
        {
            string resolvedFilePath = PathUtils.ResolveFilePath(path, this, false);
            return resolvedFilePath;
        }
    

    The third parameter sets whether ResolveFilePath treats it as literal or not, so changing that to true should make it resolve as a literal path and fix this.

    I can't see any other calls to QualifyFilePath, suggests there wouldn't be much other impact, but I'm not certain.

  2. SteveL-MSFT commented on Oct 6, 2017

    @SteveL-MSFT
    Member

    I think in general, output paths should be literalpaths. The behavior of matching a file seems unpredictable at best and clobbering something unintentional at worst.

  3. added
    Committee-ReviewedPS-Committee has reviewed this and made a decision
    and removed
    Review - CommitteeThe PR/Issue needs a review from the PowerShell Committee
    Breaking-Changebreaking change that may affect users
    on Nov 29, 2017
  4. SteveL-MSFT commented on Nov 30, 2017

    @SteveL-MSFT
    Member

    @PowerShell/powershell-committee reviewed this and believe the right approach is to rename -OutFile to -Path (aliased as -OutFile) and add a -LiteralPath parameter. Existing -OutFile can be used with current globbing behavior to match a single file using a wildcard. For example, if you have a file called helloworld.txt and you want to overwrite it with the output, you can use -OutFile hello*.

  5. ChrisMagnuson commented on Apr 26, 2019

    @ChrisMagnuson

    ThreeFive-O You mention there are work arounds for this, can you add them as a comment?

    I am trying to OutFile to a file that has [1] in the name but I cannot figure out how to escape the [] characters. I tried ` and \ but they do not escape the [] characters.

  6. vexx32 commented on Apr 26, 2019

    @vexx32
    Collaborator

    As I recall, Chris, when escaping a path like this you have to double up, or use a literal string. For example:

    Invoke-RestMethod $Uri -OutFile C:\``[test``].txt
    # or
    Invoke-RestMethod $Uri -OutFile 'C:\`[test`].txt'

    This is because typically the bare strings in a parameter are treated as expandable strings, which means that the backtick is treated as a PS escape character first and evaluated before being passed to the internals. As a result, you need to escape the escape character so PS's expandable string evaluation doesn't eat it. The other option is to force PS to recognise it as a literal string.

  7. mklement0 commented on Apr 26, 2019

    @mklement0
    Contributor

    Rain Sallow (/u/ta11ow) (@vexx32):

    While your escaping technique is correct and ensures that the file path is accepted, there is a bug that affects most cmdlets in that they then use the escaped path as a literal path on output-file creation, which means that the ` chars. are unexpectedly retained - see #9475.

    Therefore, the cumbersome workaround for now is to:

    • escape the input path so that it is accepted
    • and afterwards rename the incorrectly named file by removing ` instances from it.

    See this Stack Overflow answer for details.

  8. vexx32 commented on Apr 26, 2019

    @vexx32
    Collaborator

    Well now, that's no good at all! Thanks for the links!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Committee-ReviewedPS-Committee has reviewed this and made a decisionWG-Cmdletsgeneral cmdlet issues

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions