Windows Vista Forums

-LiteralPath is a less than optimal solution
  1. #1


    Keith Hill [MVP] Guest

    -LiteralPath is a less than optimal solution

    The team probably already knows this but the -LiteralPath hack is *not*
    ideal. First when you write a script or function library you have to
    pick -path or -literalPath. Unless you are a psychic, you should probably
    pick literalPath if you think someone will ever call your function with a
    path containing special chars ([ ],*, etc). However that precludes the use
    of any wildcard characters. We have run into situations where we have a
    paths that need to be searched that look like this:

    c:\somedir\[productspecific]\*.msi

    We wind up creating a variable for that base dir because we use it all over
    the place:

    $ProductDir = 'C:\TFS\projectdir'
    $InstallDropDir = "$ProductDir\``[productspecific``]"

    You can then do this and it works:

    $LastestMsi = gci "$InstallDropDir\*.msi" | Sort LastWriteTime | select -f 1



    Fine but then we need to copy files to that $InstallDropDir but
    unfortunately Copy-Item doesn't have a -literalpath for the destination. So
    you have to push-location -literalPath ($InstallDropDir .Replace('`',''))
    before doing the copy and then pop-location afterwards. This is a real hack
    and not something that makes generically re-usable functions easy to write.

    I'm not sure what the best solution would be but perhaps rather then
    having -LiteralPath params it would be better to have -NoGlobbing parameters
    e.g.

    dir 'c:\temp\[somedir]' -noglob

    copy-item 'foo.txt' 'c:\temp\[somedir]' -nodestglob
    copy-item 'foo[1].txt' 'c:\temp\[somedir]' -nosrcglob -nodestglob

    or maybe use a special type of string designation:

    copy-item @'foo[1].txt' @"$ProductDir\[somedir]"

    I think I prefer this way because it doesn't require new parameters. I'm
    not sure if it is wise to use the same syntax as here-strings...

    --
    Keith



      My System SpecsSystem Spec

  2. #2


    IJuan Guest

    RE: -LiteralPath is a less than optimal solution

    Copy-Item seems to treat the destination as a literalpath by default. This
    does work:

    copy-item 'foo.txt' 'c:\temp\[somedir]'
    copy-item -literalpath 'c:\[somedir]\foo.txt' 'c:\temp[somedir]'


    -= IJuan =-


    "Keith Hill [MVP]" wrote:

    > The team probably already knows this but the -LiteralPath hack is *not*
    > ideal. First when you write a script or function library you have to
    > pick -path or -literalPath. Unless you are a psychic, you should probably
    > pick literalPath if you think someone will ever call your function with a
    > path containing special chars ([ ],*, etc). However that precludes the use
    > of any wildcard characters. We have run into situations where we have a
    > paths that need to be searched that look like this:
    >
    > c:\somedir\[productspecific]\*.msi
    >
    > We wind up creating a variable for that base dir because we use it all over
    > the place:
    >
    > $ProductDir = 'C:\TFS\projectdir'
    > $InstallDropDir = "$ProductDir\``[productspecific``]"
    >
    > You can then do this and it works:
    >
    > $LastestMsi = gci "$InstallDropDir\*.msi" | Sort LastWriteTime | select -f 1
    >
    > Fine but then we need to copy files to that $InstallDropDir but
    > unfortunately Copy-Item doesn't have a -literalpath for the destination. So
    > you have to push-location -literalPath ($InstallDropDir .Replace('`',''))
    > before doing the copy and then pop-location afterwards. This is a real hack
    > and not something that makes generically re-usable functions easy to write.
    >
    > I'm not sure what the best solution would be but perhaps rather then
    > having -LiteralPath params it would be better to have -NoGlobbing parameters
    > e.g.
    >
    > dir 'c:\temp\[somedir]' -noglob
    >
    > copy-item 'foo.txt' 'c:\temp\[somedir]' -nodestglob
    > copy-item 'foo[1].txt' 'c:\temp\[somedir]' -nosrcglob -nodestglob
    >
    > or maybe use a special type of string designation:
    >
    > copy-item @'foo[1].txt' @"$ProductDir\[somedir]"
    >
    > I think I prefer this way because it doesn't require new parameters. I'm
    > not sure if it is wise to use the same syntax as here-strings...
    >
    > --
    > Keith
    >
    >
    >


      My System SpecsSystem Spec

  3. #3


    Keith Hill [MVP] Guest

    Re: -LiteralPath is a less than optimal solution

    "IJuan" <IJuan@discussions.microsoft.com> wrote in message news:ABCB1E33-5E54-4289-8730-BC854A2EDE3D@microsoft.com...
    > Copy-Item seems to treat the destination as a literalpath by default. This
    > does work:
    >
    > copy-item 'foo.txt' 'c:\temp\[somedir]'
    > copy-item -literalpath 'c:\[somedir]\foo.txt' 'c:\temp[somedir]'


    That's fine but elsewhere I need to have part of that path (the part with []) globbed so I have to define the base part of the path like so:

    $InstallDropDir = "$ProductDir\``[productspecific``]"

    This allows me to do this in one function:

    $LatestMsi = get-childitem "$InstallDropDir\*.msi" | sort LastWriteTime | select -last 1

    However in another function I need to do a copy based on $InstallDropDir:

    copy-item $foo $InstallDropDir

    Doh - that doesn't work, so I have to do a hack like this:

    $dst = $InstallDropDir.Replace('`','')
    copy-item $foo $dst

    These little fits of insanity add to a feeling of frustration with PowerShell - sometimes. Most of the time of course, it is all wine and roses. :-)

    --
    Keith


      My System SpecsSystem Spec

  4. #4


    Don Jones [MVP] Guest

    Re: -LiteralPath is a less than optimal solution

    It's tough to think of a good solution for that. Essentially, you want a parameter that treats some special characters specially, but treats others as literals - sometimes. It almost would another param, right? One where you pass it an array of characters you do/do not want treated as wildcards or whatever?

    get-whatever -path "string" -noGlop @("[","]")

    Right?

    --
    Don Jones
    Windows PowerShell MVP
    Founder: www.ScriptingAnswers.com
    Co-Author: "Windows PowerShell: TFM"

    "Keith Hill [MVP]" <r_keith_hill@no.spam.thank.u.hotmail.com> wrote in message news:uGNDu10kHHA.4904@TK2MSFTNGP05.phx.gbl...
    "IJuan" <IJuan@discussions.microsoft.com> wrote in message news:ABCB1E33-5E54-4289-8730-BC854A2EDE3D@microsoft.com...
    > Copy-Item seems to treat the destination as a literalpath by default. This
    > does work:
    >
    > copy-item 'foo.txt' 'c:\temp\[somedir]'
    > copy-item -literalpath 'c:\[somedir]\foo.txt' 'c:\temp[somedir]'


    That's fine but elsewhere I need to have part of that path (the part with []) globbed so I have to define the base part of the path like so:

    $InstallDropDir = "$ProductDir\``[productspecific``]"

    This allows me to do this in one function:

    $LatestMsi = get-childitem "$InstallDropDir\*.msi" | sort LastWriteTime | select -last 1

    However in another function I need to do a copy based on $InstallDropDir:

    copy-item $foo $InstallDropDir

    Doh - that doesn't work, so I have to do a hack like this:

    $dst = $InstallDropDir.Replace('`','')
    copy-item $foo $dst

    These little fits of insanity add to a feeling of frustration with PowerShell - sometimes. Most of the time of course, it is all wine and roses. :-)

    --
    Keith


      My System SpecsSystem Spec

  5. #5


    IJuan Guest

    Re: -LiteralPath is a less than optimal solution

    I wasn't trying to say that it was perfect the way it is. Not at all. Only
    that you didn't need to do the pushd and popd. I do still see that there is
    an issue with paths. Since I have tried to stay away from such characters in
    my file system I haven't come across that problem but it will definitely be a
    bigger issue as more providers are introduced.

    I'm not sure what the answer is but it would be nice to be able to have wild
    cards and literal wild card characters in the same string used for a path.
    The bigger issue is that it needs to be consistent across all cmdlets. When
    you enter a string for a path for source and destination they should both
    behave the same and right now they don't.


    -= IJuan =-

    "Keith Hill [MVP]" wrote:

    > "IJuan" <IJuan@discussions.microsoft.com> wrote in message news:ABCB1E33-5E54-4289-8730-BC854A2EDE3D@microsoft.com...
    > > Copy-Item seems to treat the destination as a literalpath by default. This
    > > does work:
    > >
    > > copy-item 'foo.txt' 'c:\temp\[somedir]'
    > > copy-item -literalpath 'c:\[somedir]\foo.txt' 'c:\temp[somedir]'

    >
    > That's fine but elsewhere I need to have part of that path (the part with []) globbed so I have to define the base part of the path like so:
    >
    > $InstallDropDir = "$ProductDir\``[productspecific``]"
    >
    > This allows me to do this in one function:
    >
    > $LatestMsi = get-childitem "$InstallDropDir\*.msi" | sort LastWriteTime | select -last 1
    >
    > However in another function I need to do a copy based on $InstallDropDir:
    >
    > copy-item $foo $InstallDropDir
    >
    > Doh - that doesn't work, so I have to do a hack like this:
    >
    > $dst = $InstallDropDir.Replace('`','')
    > copy-item $foo $dst
    >
    > These little fits of insanity add to a feeling of frustration with PowerShell - sometimes. Most of the time of course, it is all wine and roses. :-)
    >
    > --
    > Keith
    >


      My System SpecsSystem Spec

  6. #6


    Roman Kuzmin Guest

    Re: -LiteralPath is a less than optimal solution

    I was going to start the discussion like that long time ago, but I just did
    not have any good practical proposals. Nevertheless, having a year
    experience of everyday PowerShell scripting (not just typing commands in
    console), I would say that having -Path with wildcards (as "default")
    and -Literal Path (leading the second parameter set) looks like a bad idea
    to me (unfortunately).

    Even in console on manual typing it is troublesome. But in scripts
    every -Path parameter sooner or later will got you (well, if a script is in
    use), except relatively rare cases when exactly wildcards are required.

    For me it would be more consistent and convenient to have -Path as literal
    path everywhere + extra parameter everywhere which is a switch(!) telling
    that -Path contains wildcards. This way also avoids necessity of keeping 2
    parameter sets (it is kind of pollution, extra work, and it is error prone
    approach, I guess). Well, I would not mind if -Path is wildcard by default
    and switch tells that it is literal. Approach with 1 parameter set and a
    switch is also much easier to program.

    --
    Thanks,
    Roman Kuzmin



      My System SpecsSystem Spec

  7. #7


    Roman Kuzmin Guest

    Re: -LiteralPath is a less than optimal solution

    Keith,

    I misread your post. It looks like I proposed the same as you did (having 1
    parameter set + a switch, say -NoGlobbing (I would prefer -Literal Path (or
    something with 'Path' in it), because it is for -Path and there can be other
    path related parameters -Xyz with their own -LiteralXyz switches)).

    Unfortunately, it is too late, is not it?

    --
    Thanks,
    Roman Kuzmin



      My System SpecsSystem Spec

  8. #8


    Keith Hill [MVP] Guest

    Re: -LiteralPath is a less than optimal solution

    "Roman Kuzmin" <z@z.z> wrote in message news:O2F$Jc5kHHA.3704@TK2MSFTNGP02.phx.gbl...
    > Keith,
    >
    > I misread your post. It looks like I proposed the same as you did (having 1
    > parameter set + a switch, say -NoGlobbing (I would prefer -Literal Path (or
    > something with 'Path' in it), because it is for -Path and there can be other
    > path related parameters -Xyz with their own -LiteralXyz switches)).
    >
    > Unfortunately, it is too late, is not it?


    Another thing that kind of sucks is that you really need to know whether a path parameter supports wildcards or not. For example, take this apparently buggy behavior:

    592# cpi fail.c 'C:\temp\`[foo`]' -ver
    VERBOSE: Performing operation "Copy File" on Target "Item: C:\Temp\fail.c Destination: C:\temp\`[foo`]".
    593# dir '`[foo`]\*'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp\[foo]


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 5/11/2007 10:38 PM 0 bar


    594# cpi fail.c 'C:\temp\``[foo``]' -ver
    VERBOSE: Performing operation "Copy File" on Target "Item: C:\Temp\fail.c Destination: C:\temp\``[foo``]".
    595# dir '`[foo`]\*'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp\[foo]


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 5/11/2007 10:38 PM 0 bar

    As it turns out -destination doesn't accept wildcards so could just specify the copy command like this and it works:

    596# cpi fail.c 'C:\temp\[foo]' -ver
    VERBOSE: Performing operation "Copy File" on Target "Item: C:\Temp\fail.c Destination: C:\temp\[foo]\fail.c".
    597# dir '`[foo`]\*'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp\[foo]


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 5/11/2007 10:38 PM 0 bar
    -a--- 12/5/2005 9:39 AM 70 fail.c

    However I'm left wonder why the first two attempts above indicated success when they did *not* succeed. BTW why the heck doesn't this work:

    598# gci '`[foo`]'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 12/5/2005 9:39 AM 70 `[foo`]

    or this:

    602# gci '``[foo``]'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    d---- 5/11/2007 11:24 PM <DIR> [foo]

    Of course this does work:

    604# gci -lit '[foo]'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp\[foo]


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 5/11/2007 10:38 PM 0 bar
    -a--- 12/5/2005 9:39 AM 70 fail.c

    --
    Keith









      My System SpecsSystem Spec

  9. #9


    Keith Hill [MVP] Guest

    Re: -LiteralPath is a less than optimal solution

    Nevermind. I see now that it was copying fail.c to new file named `[foo`] which reinforces my point about knownig whether or not a path parameter accepts wildcards.

    --
    Keith
    "Keith Hill [MVP]" <r_keith_hill@no.spam.thank.u.hotmail.com> wrote in message news:OQ5EfaFlHHA.4552@TK2MSFTNGP04.phx.gbl...
    "Roman Kuzmin" <z@z.z> wrote in message news:O2F$Jc5kHHA.3704@TK2MSFTNGP02.phx.gbl...
    > Keith,
    >
    > I misread your post. It looks like I proposed the same as you did (having 1
    > parameter set + a switch, say -NoGlobbing (I would prefer -Literal Path (or
    > something with 'Path' in it), because it is for -Path and there can be other
    > path related parameters -Xyz with their own -LiteralXyz switches)).
    >
    > Unfortunately, it is too late, is not it?


    Another thing that kind of sucks is that you really need to know whether a path parameter supports wildcards or not. For example, take this apparently buggy behavior:

    592# cpi fail.c 'C:\temp\`[foo`]' -ver
    VERBOSE: Performing operation "Copy File" on Target "Item: C:\Temp\fail.c Destination: C:\temp\`[foo`]".
    593# dir '`[foo`]\*'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp\[foo]


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 5/11/2007 10:38 PM 0 bar


    594# cpi fail.c 'C:\temp\``[foo``]' -ver
    VERBOSE: Performing operation "Copy File" on Target "Item: C:\Temp\fail.c Destination: C:\temp\``[foo``]".
    595# dir '`[foo`]\*'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp\[foo]


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 5/11/2007 10:38 PM 0 bar

    As it turns out -destination doesn't accept wildcards so could just specify the copy command like this and it works:

    596# cpi fail.c 'C:\temp\[foo]' -ver
    VERBOSE: Performing operation "Copy File" on Target "Item: C:\Temp\fail.c Destination: C:\temp\[foo]\fail.c".
    597# dir '`[foo`]\*'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp\[foo]


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 5/11/2007 10:38 PM 0 bar
    -a--- 12/5/2005 9:39 AM 70 fail.c

    However I'm left wonder why the first two attempts above indicated success when they did *not* succeed. BTW why the heck doesn't this work:

    598# gci '`[foo`]'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 12/5/2005 9:39 AM 70 `[foo`]

    or this:

    602# gci '``[foo``]'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    d---- 5/11/2007 11:24 PM <DIR> [foo]

    Of course this does work:

    604# gci -lit '[foo]'


    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp\[foo]


    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    -a--- 5/11/2007 10:38 PM 0 bar
    -a--- 12/5/2005 9:39 AM 70 fail.c

    --
    Keith









      My System SpecsSystem Spec

  10. #10


    Keith Hill [MVP] Guest

    Re: -LiteralPath is a less than optimal solution

    Yeah I'm struggling to come up with a PowerShell-based solution even if could pull a Jedi mind trick on the PowerShell team and make them do what I want. :-)

    I think the only issue is with paths that have square braces in them. It isn't legal to have a * char in a pathname, at least not within PowerShell. So the question becomes: when faced with creating a variable for a path that a number of different scripts reference and use in many different ways do you pick:

    $BaseDir = 'c:\project\[somedir]'

    or

    $BaseDir = 'c:\project\``[somedir``]'

    Either choice is going to cause problems if used as is. I guess in retrospect I would pick the first now and then whenever I used it in conjunction with a wildcarded path then I would "escape" the contents of the variable before using it to construct the path that I would send to a path parameter that accepts wildcards. So now what I need to do is create an EscapePath function that introduces the right number of back ticks e.g.

    C:\[dir] ==> C:\``[dir``]
    C:\`[dir`] ==> C:\```[dir```]
    C:\``[dir``] ==> C:\`````[dir`````]

    Of course with a function like that, you don't want to call it on an already escaped path. Hmmm....

    --
    Keith
    "Don Jones [MVP]" <don@sapien.com> wrote in message news:9E2CF513-2BC5-4AF9-B3EC-AB5C4B045068@microsoft.com...
    It's tough to think of a good solution for that. Essentially, you want a parameter that treats some special characters specially, but treats others as literals - sometimes. It almost would another param, right? One where you pass it an array of characters you do/do not want treated as wildcards or whatever?

    get-whatever -path "string" -noGlop @("[","]")

    Right?



      My System SpecsSystem Spec

-LiteralPath is a less than optimal solution problems?

Similar Threads
Thread Thread Starter Forum Replies Last Post
Optimal PrinterSettings Within Vista? DaveGF Vista print fax & scan 1 11 Oct 2009
Split-Path -LiteralPath BUG? ioioio322 PowerShell 0 04 Jul 2009
Playing with -literalpath Werner Hingerl PowerShell 3 06 May 2009
How is optimal CPU frequency computed in Vista? Roof Fiddler Vista performance & maintenance 0 01 Nov 2006
Two SATA drive optimal configuration Dave Nuttall Vista performance & maintenance 1 21 Oct 2006