Community Pick: Many members of our community have endorsed this article.

Script to copy or move collection of selected files, plus shortcut target files (referenced by .lnk)

Script to copy or move mouse-selected collection of files plus targets referenced by shortcuts (.lnk)

The purpose of this article is to help illuminate the real challenges and options available (where they may exist) for utilizing simple scripting methods for handling copying/moving of file system objects, ...overcoming the limitation for interfacing with the Windows Clipboard imposed on scripts and the command processor interface (command line).

How would you like to be able to create a script that allows you to simply
 arbitrarily select some files within a Window (directory)
 including shortcuts
 and copy or move all the targets, i.e., the real files in the directory, and the real files the shortcuts point to (but not the shortcuts themselves) another directory location?
Heretofore, the only way via simple scripting I have seen to do this is to create a list from a selection and use that to make a batch you then use for copying or moving the files.  (pita)

The only other way I can think of to otherwise facilitate this is by creating an application, or DLL Wrapper, or shell extension, for interfacing to the system clipboard (which I really want to do for my 2nd dll project)... however, all I want to do right now is use a "SIMPLE" script...
-- what to do??

***Well, I finally figured out a way to do this with a very simple script, although it still must rely on a small outside helper.

There seem to be essentially three problems to tackle here...
#1 - the script must be able to 'receive' a collection of filesystem objects that is passed to it, and
#2 - parse them correctly, i.e., collect the files passed, and collect the targets of the shortcut targets that are passed, and
#3  - the script must be able to then pass that collection of filesystem object 'pointers' to the clipboard, or something, for temporary storage until we are ready to paste the files elsewhere.

If you do any vbs/wsh/bat scripting you have probably run into the following limitations imposed by Microsoft:

1) You cannot directly access the clipboard from a script.  I have looked high and low and have not found a single script-centric workaround for this limitation.
 - So you cannot, say, pass/copy a file selection (control-click/control-select one or several files for a collection) onto your script to be held in the system clipboard for pasting to a destination you later navigate to.  (Trust me... ain't gonna happend without a DLL wrapper or some other utility).
  - As well, I would not accept having to resort to AutoIt or a third-party clipboard manager or anything like those that you have to continually have running in the background.  Sloppy, unnecessary, and unacceptable.
2)You cannot pass several 'arguments' (images) from the shell (e.c., control-click/control-select several files for an images collection) to a "command-line-prepared" script without either parameters/arguments being lost, or the scripts launching multiple instances of themselves (an instance for each image/argument passed).

 Example: Say you setup a context menu in the registry with your script reference looking something like -->>

wscript C:\myscript.vbs "%*"   ::<<--or do something similarly for a batch::

...That type of argument usage (%* in a command line) doesn't exist for scripts, and using, say for instance, "%1" only results in the mulitple instances issue mentioned.  There is no way I found to successfully pass an argument list of arbitrarily selected objects to a command-line-prepared script... again, ain't gonna happen with Batch or VBS. (Well, maybe using a listbox, but obviously  that's too combersome.)

3) Scripts do not support DDE linking (for setting up and passing a collection).  (**However, there may be a command line dde utility you can find out there that can be implemented for the solution being discussed here, ...I have not looked too deeply into that, but it seems viable ;^)

4) I have not yet ventured into PowerShell, but to mention... it may be possible to open multiple images with one instance using PS, either directly or with DDE manipulation or with batch integration.  It may even be possible to utilize the clipboard (like if you can recapture spinoffs of cmdlet extensions Get-Clipboard Out-Clipboard, but I do not know about their object handling capabilities).  
  I have seen some discussions on this, but no SIMPLE VIABLE solution to speak of has presented itself as yet (not that they aren't out there, I just didn't find any within the time allotted for searching on this subject, so I am staying focussed on Batch and/or VBS solution).

***5) You cannot drop a collection of arbitrarily selected files (images) onto a BATCH without causing the script to launch an instance of itself for every file passed (by arbitrarily, again, I mean this assumes you do not have a preconception for the number of files that will be selected - which you 'can' script for).

!!!...but you CAN do this with a vbs script!


PART 1 of 2: A script that can receive and parse arguments.

After much searching, and almost giving up, I finally figured out that I may be able to leaverage that last caveat (in #5 above) to my advantage, assuming, of course, that I could write a script to then handle parsing and passed arguments (images or fileObjects) in the way I desire.


1) Create a vbs script (unfortunately a batch will not work) and set it up someplace where you can always drag+drop your selection of files onto it.  
Of course, this is easily accomplished with the Startbar's handy-dandy "Quick Launch" Toolbar.


2) ***You can place a shortcut to your vbscript in Window's "SendTo" context menu !
To quickly access your SendTo folder simply launch Run (Win-R) and type in shell:sendto  ..and hit enter.

Okay, so now that I know the options for acceptable script file 'type' and 'placement', and 'how to use it' so it can successfully receive a collection that I want to hand off to it...,
...well all I need to do now is figure out what goes inside it ;^)

But scripts cannot directly utilize the Windows Clipboard, so now what?

PART 2 of 2: A way to handle the clipboard, or store system object pointers to use for pasting files elsewhere later.

Hmmmm... wait a minute, Houston, we have a serious problem.  There's no way in hell to hand off a "shell objects pointers" collection to the clipboard from a script 8^?  {A shell objects "pointer" is what is passed to the clipboard when typically copying files and folders (not the objects themselves ;^}
You can hand off text collections, or even file contents using a script... but there is no way a script can directly utilize the system clipboard for file system objects, like you do using the 'copy' command  with Ctrl-C or in the context menu when you right-click a file (or group of them).

So what is
 - not an application that has to run in the background constantly, or take time to launch
 - not a clipboard replacement or extenstion
 - not a sendkeys or macro kludge
 ...that can provide a simple bridge to the clipboard?

 The answer, pretty much, is either
a DLL Wrapper for copy/paste api's in Windows
 ...a shell extension.

My favorite choice here, what I think would be perfect for this job and really is needed for other things in Windows too, would be a DLL Wrapper.  Alas, after much searching it appears I am going to have to write the darned thing myself.  I did write one once, and I think I should write this one, but there's no time for that right now (too much learning time to allocate to that project, so later for that).

All righty then, looks like I need to figure a solution utilizing (or coding) some sort of shell extension.  (Yeah, like coding that will take any less effort...)

As it turns out, you can create your own "Copy to" and "Move to" context menu commands with some simple registry editing; however, then you need to figure out how to leaverage those within your script.  Since they are not simple commands this is going to take a little work to sort out.
But Wait... well, duh, there are already several free "Send to" shell extensions out there... maybe one of those is the ticket!


Indeed, what I ended up doing is setting up a sendto extension that my script could talk to for copying and/or moving a system object.

Here's the flow-chart and explanation of how this works.  The example script appears below.
This soluton that seemed so tough to suss (a week of searching turned up nothing but similar questions with half-baked answers), but turns out to be rather simple.

- A shortcut to the below script is placced in the Sendto folder so one can simply: select the desired files, right-click on the selection and then drop it onto the script within the 'Send To' context-menu simply by selecting it.

 - The script takes all the files dropped onto it as a delimited argument list !

 - The list is parsed for shortcuts, i.e., iterated in order to catch the shortcuts and convert those list items into their 'target constituents'.

 - The list is reassembled into a collection of the files we want to copy or move

 - Finally, the new list is passed on to whatever favorite shell extension (or application or utility) we may be vested in for Copying/Moving FileSyustem Objects.
  You simply navigate to and select your intended directory destination  
 ...and all those files get copied/moved there

 - Using the method shown here we can use vbscript/wscript/cscript/powershell for custom-assembling a file system objects collection (i.e., via simple user selection) and handing that off to any application that can handle file system object pointers... so this can actually be quite powerful (well beyond the scope of simple copying/moving files).

 So say you have a folder where you have collected a bunch of shortcuts to files residing in different places on your hard drive and you want to copy those files (not the shortcuts) onto a USB stick or other Drive... this method can accomplish that for you in a couple clicks.
 Say you are staring at a shortcut on your desktop whose target file you want to move or copy to an alternate location... couple clicks, done.
 Say you have a folder with a mix of some files and some shortcuts to other files, and you want to collect those files and target files all into some folder somewhere else... this is the only thing I know of that will do that in a simple couple clicks.

The following example is only intended to provide a model insight into how one might tackle the problem of copying/moving file system objects with simple scripting considering the limitations we are handed in MS Windows.

Based on the following, it should be possible to elaborate on this code (quite simply) to create a script for also handling Folders and SubFolders and their collections.

I hope you find this information, along with the following example, insightful and useful.

***PS: If you figure out how to set this up (in the registry) with its own ContextMenu item  --that actually works-- I would really be interested in hearing about that, as well as any other potentially relevant wrapper, shell extension, or PowerShell script being shared for assisting scripts to interface with the Windows Clipboard for handling file system objects (not text or file contents, but files and folders and the like) !

                      ' TwoHawks' Simple CopyTargetFiles.vbs script
                      ' Free to Use your own risk, of course ;^)
                      ' The code here is set up to provide information about what is being passed/parsed via alerts.
                      ' Of course, none of the alerts are necessary for the code to carry out its primary function
                      ' You should test carefully before presuming to implement this method as a solution on your system
                      ' This example currently handles only files, and shortcuts to files, and is NOT setup for handling FOLDERS !
                      ' Copy into a file, say, CopyTargetFiles.vbs and place a shortcut into your SendTo Folder
                      Set WSHELL = Wscript.CreateObject("Wscript.Shell")
                      Set FSO = CreateObject("Scripting.FileSystemObject")
                      Dim ARG()
                      Dim ARGS()
                      WScript.Echo "The Number of Items Passed is: " & Wscript.Arguments.Count
                      For i = 0 to Wscript.Arguments.Count - 1
                        'Enumerate the collection and provide details of each item
                        Redim Preserve ARG(i)
                        ARG(i) = Wscript.Arguments(i)
                        Wscript.Echo "Current Argument String: " & ARG(i)
                        'Obviously there are various ways to handle looking at the filesystem object properties...
                        Set f = FSO.GetFile(ARG(i))
                        Wscript.Echo ("File : " & f)
                        Wscript.Echo ("FileType : " & f.type)
                        Wscript.Echo ("FilenameObj: " & FileName)
                        Wscript.Echo ("FilePathObj: " & FilePath)
                        'Transform List-Item Links into their actual targets
                        fExt = FSO.GetExtensionName(ARG(i))
                        Wscript.Echo ("FileExtension is : " & fExt)
                        ifExt = StrComp(fExt, "LNK", vbTextCompare)
                        IF ifExt = 0 THEN
                          set oSHLink = WSHELL.CreateShortcut(FilePath)
                          target = oSHLink.TargetPath
                          Set f = FSO.GetFile(target)
                          Wscript.Echo "Target is : " & target
                          Wscript.Echo "New File is : " & f
                          Wscript.Echo ("FileType : " & f.type)
                        End If
                        'Recreate a new collection containing all hard targets (no links)
                        Redim Preserve ARGS(i)
                        ARGS(i) = f
                        Wscript.Echo ("ARGS Array is now: " & Join(ARGS," "))
                        Wscript.Echo ("ARG Array is now: " & Join(ARG," "))
                      ' Now send this off to a Shell Extension for Copying/Moving file system objects
                      ' Note: Usually you send a list of arguments to an application separated by a space ;^)
                      ' So if you use this for other application you need to be mindful of the correct/expected delimiter
                      WSHELL.Run (chr(34) &  "C:\Program Files\Send To Toys\SendToFolder.exe"  &  chr(34) & Join(ARGS," ") &  chr(34) & chr(34))
                      Set oSHLink = Nothing
                      Set FSO = Nothing
                      Set WSHELL = Nothing
                      ' END SCRIPT

Open in new window


Comments (4)

Mark WillsTopic Advisor
Distinguished Expert 2018

Thanks twohawks.

Handy script. Will think about that contextmenu challenge :)


Thanks Mark !


A gentleman, stoyanov, who was unable to register, wrote the following to me, so I figured I would post it for posterity.  I do not have time to test viability myself, but it was nice he took the time to write...


I found this one:

could be useful registering context menu for your script.

And also that "Send to Toys" has a settings called "Resolve shortcuts" (which works little bit strange, but hope it will go better), and this option works also for folders.

Sorry for writing you a personal mail, but i can't register to experts-exchange forum.

Thanks for shared knowledge :)

Wish you all best.
I use the Q-DIR (alternative windows explorer) and the Program or Quick-Links buttons to create menus.
Q-Dir Software Page
It runs my scripts/batches/powershell files all very well.

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.