![]() |
![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() |
| Welcome to Windows Vista Forums. Our forum is dedicated to helping you find solutions with any problems, errors or issues you are experiencing with Windows Vista. The Vista forum also covers news and updates and has an extensive Windows Vista tutorial section that covers a wide range of tips and tricks. |
| |||||||
![]() |
| |
| | #1 (permalink) |
| | Passing arguments from .BAT to PowerShell script Hi, I'd like to have a PS script, where I can drag some files in explorer and drop them onto the script (for example, the dropped files are moved to a specific directory or something similar). This doesn't work with PS scripts directly. Therefore I wrote a .BAT file which is supposed to call the PS script. However, this doesn't work if there are spaces within the file names. Example: File names are: file with spaces 1.txt file with spaces 2.txt script.ps1: foreach($arg in $args) { write-host "[$arg]" } ..BAT file: powershell .\script.ps1 %* If I drag and drop the files onto the batch file I get the following output: F:\PowerShell>powershell .\test.ps1 "F:\PowerShell\file with spaces 1.txt" "F:\PowerShell\file with spaces 2.txt" [F:\PowerShell\file] [with] [spaces] [1.txt] [F:\PowerShell\file] [with] [spaces] [2.txt] That is clearly not what I want. And in my opinion it's a bug in PowerShell. If I replace %* with "%*" I get the same results. If I replace %* with '%*' I get the following results: F:\PowerShell>powershell .\test.ps1 '"F:\PowerShell\file with spaces 1.txt" "F:\PowerShell\file with spaces 2.txt"' [F:\PowerShell\file with spaces 1.txt F:\PowerShell\file with spaces 2.txt] I'm running out of ideas here. Does anybody have any suggestion how to solve this problem? Thanks a lot for any help. |
My System Specs![]() |
| | #2 (permalink) |
| | Re: Passing arguments from .BAT to PowerShell script Hi wofat68, You can't drag-drop files onto a PowerShell script. For security reasons, PS script files are not associated with PowerShell.exe (when double-clicked they open in notepad). You can put the files in a temp directory (e.g c:\temp) and pass the directory path to a script as an argument: powershell.exe c:\foo.ps1 ## c:\foo.ps1 ## dir c:\temp\*.ps1 | foreach { ...do what ever you need here...} ############ --- Shay Levy Windows PowerShell MVP http://blogs.microsoft.co.il/blogs/ScriptFanatic w> Hi, w> w> I'd like to have a PS script, where I can drag some files in explorer w> and drop them onto the script (for example, the dropped files are w> moved to a specific directory or something similar). This doesn't w> work with PS scripts directly. Therefore I wrote a .BAT file which is w> supposed to call the PS script. However, this doesn't work if there w> are spaces within the file names. w> w> Example: w> w> File names are: w> w> file with spaces 1.txt w> file with spaces 2.txt w> script.ps1: w> w> foreach($arg in $args) { write-host "[$arg]" } w> w> .BAT file: w> w> powershell .\script.ps1 %* w> w> If I drag and drop the files onto the batch file I get the following w> output: w> w> F:\PowerShell>powershell .\test.ps1 "F:\PowerShell\file with spaces w> 1.txt" "F:\PowerShell\file with spaces 2.txt" w> w> [F:\PowerShell\file] w> [with] w> [spaces] w> [1.txt] w> [F:\PowerShell\file] w> [with] w> [spaces] w> [2.txt] w> That is clearly not what I want. And in my opinion it's a bug in w> PowerShell. w> w> If I replace %* with "%*" I get the same results. w> w> If I replace %* with '%*' I get the following results: w> w> F:\PowerShell>powershell .\test.ps1 '"F:\PowerShell\file with spaces w> 1.txt" "F:\PowerShell\file with spaces 2.txt"' w> w> [F:\PowerShell\file with spaces 1.txt F:\PowerShell\file with spaces w> 2.txt] w> w> I'm running out of ideas here. Does anybody have any suggestion how w> to solve this problem? w> w> Thanks a lot for any help. w> |
My System Specs![]() |
| | #3 (permalink) |
| | Re: Passing arguments from .BAT to PowerShell script Wofat, Here's one workaround with PowerShell 1.0 that works. The trick is to generate a complete command line and feed it as input to PowerShell, using the - argument, using a batch file like this: @echo off :: pswrapper.cmd echo.\script.ps1 %* | powershell -NoExit -Command - "wofat68" <atlanticcoast2006@xxxxxx> wrote in message news:5dfe34e9-5747-4c05-ae44-9fe4d958ae3f@xxxxxx Quote: > Hi, > > I'd like to have a PS script, where I can drag some files in explorer > and drop them onto the script (for example, the dropped files are > moved to a specific directory or something similar). This doesn't work > with PS scripts directly. Therefore I wrote a .BAT file which is > supposed to call the PS script. However, this doesn't work if there > are spaces within the file names. > > Example: > > File names are: > > file with spaces 1.txt > file with spaces 2.txt > > script.ps1: > > foreach($arg in $args) { write-host "[$arg]" } > > .BAT file: > > powershell .\script.ps1 %* > > If I drag and drop the files onto the batch file I get the following > output: > > F:\PowerShell>powershell .\test.ps1 "F:\PowerShell\file with spaces > 1.txt" "F:\PowerShell\file with spaces 2.txt" > > [F:\PowerShell\file] > [with] > [spaces] > [1.txt] > [F:\PowerShell\file] > [with] > [spaces] > [2.txt] > > > That is clearly not what I want. And in my opinion it's a bug in > PowerShell. > > If I replace %* with "%*" I get the same results. > > If I replace %* with '%*' I get the following results: > > F:\PowerShell>powershell .\test.ps1 '"F:\PowerShell\file with spaces > 1.txt" "F:\PowerShell\file with spaces 2.txt"' > > [F:\PowerShell\file with spaces 1.txt F:\PowerShell\file with spaces > 2.txt] > > I'm running out of ideas here. Does anybody have any suggestion how to > solve this problem? > > Thanks a lot for any help. > > > |
My System Specs![]() |
| | #4 (permalink) |
| | Re: Passing arguments from .BAT to PowerShell script Thanks for the response. I guess I provided a misleading example. Just for clarification: 1. PS's security restrictions are fine with me. That's the reason I used the intermediate batch file. 2. I still claim that the way PS parses the command line is wrong here. As you can see in the examples, CMD.EXE encapsulates the arguments correctly within double quotes. PS seems to ignore the quotes. 3. I was looking for a general purpose solution, not just moving files. My example was bad. In general I want to select some files in explorer, move (drag) the selected files and drop them onto a script/ batch. Then the script should do with the files whatever I want. Examples: renaming the files, changing time stamps, calculating check sums, and so on. Anyway, your suggestion lead me to another idea: writing the arguments into a temporary file and then reading the file line by line. Quotes have to be removed explicitely. ..BAT file: del /q /f %TEMP%\ps.args 2>NUL for %%f in (%*) do echo %%f>>%TEMP%\ps.args powershell .\script.ps1 %TEMP%\ps.args script.ps1: foreach($arg in get-content $args[0]) { write-host "[$ ($arg.SubString(1, $arg.Length - 2))]" } Thanks for the help. --wofat68 |
My System Specs![]() |
| | #5 (permalink) |
| | Re: Passing arguments from .BAT to PowerShell script This is pretty nice. Much better than the solution I finally came up with. Thanks a lot. --wofat68 |
My System Specs![]() |
| | #6 (permalink) |
| | Re: Passing arguments from .BAT to PowerShell script Comments on a couple of your points here... "wofat68" <atlanticcoast2006@xxxxxx> wrote in message news:628a91ec-b8d7-443d-8601-c60c96fdaad1@xxxxxx Quote: > Thanks for the response. Quote: > 2. I still claim that the way PS parses the command line is wrong > here. As you can see in the examples, CMD.EXE encapsulates the > arguments correctly within double quotes. PS seems to ignore the > quotes. appears that at a lower level the standard argument parsing done by Windows APIs causes the double-quote stripping. The same thing happens with WSH; there is simply no way to pass a literal " to a script within an argument. I'm not sure about the precise details of how things are implemented in PowerShell 2.0, but they do have a -File parameter for PowerShell in V2 that correctly handles a script file and arguments with embedded spaces. I believe what it does is to simply pass everything straight through to the script as an argument array, which modifies how data is interpreted but makes it more straightforward for wrapper scripts. Quote: > 3. I was looking for a general purpose solution, not just moving > files. My example was bad. In general I want to select some files in > explorer, move (drag) the selected files and drop them onto a script/ > batch. Then the script should do with the files whatever I want. > Examples: renaming the files, changing time stamps, calculating check > sums, and so on. couple of other techniques, including using an intermediary WSH script that reassembles arguments inserting SINGLE quotes where you need quoted arguments, but I think the input stream command technique is easiest for drag-and-drop. After all, you aren't going to be using the input stream anyway in that context. Quote: > Anyway, your suggestion lead me to another idea: writing the arguments > into a temporary file and then reading the file line by line. Quotes > have to be removed explicitely. ![]() |
My System Specs![]() |
| | #7 (permalink) |
| | Re: Passing arguments from .BAT to PowerShell script Alex, Thanks for your detailed response. I read your first post after my response to Shay. So it got a little bit confusing. Sorry for that. Anyway. Your suggestion is better than mine. It doesn't involve any temporary files. Regarding the command line parsing: this would probably require more research. But I won't go into that. Your solution works perfectly for me, even if it's "only" a workaround. --wofat68 |
My System Specs![]() |
| | #8 (permalink) |
| | Re: Passing arguments from .BAT to PowerShell script On Aug 1, 4:11*pm, "Alex K. Angelopoulos" <aka(at)mvps.org> wrote: Quote: > @echo off > :: pswrapper.cmd > echo.\script.ps1 %* | powershell -NoExit -Command - unfortunately. If the argument does *not* contain any spaces, it isn't quoted by CMD.EXE. This results in a problem, if the file name contains parenthesis. Obviously, PS is trying to interpret that as an expression. This may be also a security problem, since code could be injected. I just wanted to let you know. Probably I have to use my solution using a temporary file. --wofat68 |
My System Specs![]() |
| | #9 (permalink) |
| | Re: Passing arguments from .BAT to PowerShell script Comments inline, and another solution with some "special" guard rails for drag-and-drop specifically. "wofat68" <atlanticcoast2006@xxxxxx> wrote in message news:8a96d697-8c8c-433c-a09e-80bc9f94fa38@xxxxxx Quote: > On Aug 1, 4:11 pm, "Alex K. Angelopoulos" <aka(at)mvps.org> wrote: > > Quote: >> @echo off >> :: pswrapper.cmd >> echo.\script.ps1 %* | powershell -NoExit -Command - > After some testing, I found that this does not work on some strings, > unfortunately. If the argument does *not* contain any spaces, it isn't > quoted by CMD.EXE. This results in a problem, if the file name > contains parenthesis. Obviously, PS is trying to interpret that as an > expression. even with doublequotes, since several characters that are allowed in file and folder names can cause serious problems to PowerShell - (){}[]$`' are all legal. Quote: > This may be also a security problem, since code could be injected. > > I just wanted to let you know. > not sure I see this. If anything was being piped in, it could theoretically expose something, but since the batch wrapper itself invokes the interactively-specified data explicitly as arguments, you should get no more and no less vulnerability than you have to injection via the script arguments. This did suggest another point to me, however. Since this is explicitly designed to be a drag-and-drop wrapper, items should _always_ be resolvable as filesystem paths. Therefore, it makes sense for a wrapper to actually _test_ for this condition first, and discard any input that isn't a valid path. I've added that to a new solution. Quote: > Probably I have to use my solution using a temporary file. The ideal technique is to pass the items in as single-quoted rather than double-quoted strings. I've tried out another wrapper script, which is shown below. This is actually a WSH script, and theoretically could be made more generic, but for now it acts as a wrapper akin to the batch file concept. Details: (1) The script is totally generic, as long as you observe name and location constraints. You may want to modify the -NoExit and possibly force the PowerShell subscript to run hidden, but those are one-off modifications to this script. (2) As written, the WSH wrapper needs to be in the same location as the PS script, with the same base name - e.g., if the PowerShell script is at c:\apps\scripts\newdemo.ps1, then the WSH script needs to be c:\apps\scripts\newdemo.vbs. You can of course put a shortcut to the WSH script anywhere. (3) The script is _explicitly_ designed for drag-and-drop. It tests every single argument it was passed to see if it is an existing file or folder path. If not, the item is dropped silently. Your comment about potential code injection suggested this addition to me. Since we shouldn't get anything _but_ file/folder paths as arguments, why not explicitly match the argument data? (4) The script works by explicitly single-quoting every argument, whether it has embedded spaces or not. If an argument contains an embedded single-quote (it's a legal filename character) then it is escaped by doubling. This prevents use of any special tricks with filesystem names, but since it's drag-and-drop, it won't matter. (5) The only escaping done to the script name itself is escaping spaces in the script name with a preceding backtick. This allows you to run PowerShell scripts in situ from add-on installation folders that might be under Program Files, or from per-user application folders. ' BEGIN WSH wrapper script ' Should have same basename as PS script it will run, ' and must be in same folder as PS script. ' ex: if c:\tmp\fred.ps1, this must be c:\tmp\fred.vbs dim fso: Set fso = CreateObject("Scripting.FileSystemObject") Dim WshScript: WshScript = WScript.ScriptFullName Dim PsScript PsScript = fso.BuildPath( _ fso.GetFile(WshScript).ParentFolder.Path, _ fso.GetBaseName(WshScript) & ".ps1") ' PowerShell scripters should probably know better than ' using a script name containing embedded spaces, but this ' may be unavoidable for some scripts. ' Just in case, we escape spaces with a backtick. PsScript = Replace(PsScript, " ", "` ") Dim i, arg i = 0 Dim ArgSet: Set ArgSet = CreateObject("Scripting.Dictionary") Argset(i) = PsScript For each arg in WScript.Arguments ' EXPLICITLY ensure these resolve to file/folder paths if fso.FileExists(arg) or fso.FolderExists(arg) then i = i + 1 ' Include escapes for single-quotes used in file/folder names Argset(i) = "'" & Replace(arg, "'", "''") & "'" End If Next ' Remove -NoExit if you don't want PS to stay open when done. Dim Command Command = "powershell -NoLogo -NoExit -Command ""& {" _ & Join(ArgSet.Items) _ & "}""" ' WScript.Echo "command as passed to PowerShell:", Command Dim WshShell: Set WshShell = CreateObject("WScript.Shell") WshShell.Run Command ' Alternative operation (runs script hidden - ONLY use if ' you also remove -NoExit: ' WshShell.Run Command, 0 ' END WSH Wrapper Script |
My System Specs![]() |
![]() |
| Thread Tools | |
| |
Similar Threads | ||||
| Thread | Forum | |||
| Hosting PowerShell & passing parameters to script | PowerShell | |||
| Passing arguments into scripts? | PowerShell | |||
| passing arguments | PowerShell | |||
| Passing arguments to a function | PowerShell | |||
| Executing PS1 script from CMD/SchTasks and passing arguments | PowerShell | |||