Copying Files to Clients Using ConfigMgr

Copying Files to Clients Using ConfigMgr

This seemingly simple task stumps and trips up a lot of people in both ConfigMgr 2007 and ConfigMgr 2012. It’s not that it’s a difficult task per se, it’s that people go into it with bad assumptions.

The main bad assumption has to do with the current working directory. I discussed this previously (Current Directory in ConfigMgr Programs) but in summary and in general, the current working directory of a program in ConfigMgr is the folder containing the package files whether that be cached locally or on the DP based on where the program is run from. You should never count on it being in one place and thus you should never hard-code a path in. Using a batch file though, you can use the %~dp0 batch file parameter within the batch file itself to refer to the directory the batch file is run from.

The very simple solution presented here can of course be expanded upon and customized but is flexible enough to be just dropped in without any real customization.

1. Create a parent folder in your source file repository.

2. Create a sub-folder in the folder just created called Files2Copy and place the files you are going to copy in this folder.

The Files2Copy Folder

The Files2Copy Folder

4. Create a batch file called filecopy.bat with the below two lines and place it in the parent directory created in step 1. This batch file will create a folder specified on the command-line (if it doesn’t already exist) and copy the files from the Files2Copy folder into it.

if not exist "%~1" md "%~1"
copy /y "%~dp0Files2Copy\*.*" "%~1"

5. Create a package using the parent directory created in step 1 as the source file location.

Package with Source Location

Package with Source Location

6. Create a program and set the command line to

filecopy.bat c:\DesktopTools

Note that although my source directory and destination directory are both named “Desktop Tools”, this was just a convenient naming standard I adopted for this example and does not have to be the case.

Program Command-line

Program Command-line

7. Advertise/Deploy the program to the desired systems.

Done.

You can of course modify this very simple batch file to do some more complex things or use xcopy (http://technet.microsoft.com/en-us/library/bb491035.aspx) to perform advanced filtering and selective copying of files and sub-folders.

OSD and Multicast

Next Article

OSD and Multicast

38 Comments

Cancel

  1. Hi There!

    Thank You very much for this valuable information, it helped me out a lot. However there is one minor thing, I would like to copy the files to the everyone/public desktop thought. The procedure you gave only copies to their c:

    I’ve tried to change to the path C:UsersPublicDesktop and it failed. Any suggestion?

    Regards,
    Joev

    • Not sure what issue you may be having. There is no reason it shouldn’t be able to copy any directory and the example given does just that. Have you reviewed the execmgr.log for an exit code? Have you configured the program to run with Admin privileges?

  2. Thanks for the useful information your blog provides. This works when advertising or making a deployment “available” but when I set it to “required” it doesn’t work despite showing 100% compliance.

    Any ideas?

    • Without seeing the log files and knowing the details of what you’re copying, I wouldn’t be able to say anything definitive.

  3. I am so going nuts here. I am running 2012 and I am trying to copy one files from the sccm 2012 server…dow to the client. It simply wont work…I must be doing something dumb.

    So I create a package
    I check the box package has source files
    I specify the folder where the file resides on the sccm server
    I specify a standard program
    next…

    I name the program and specify in the command line:

    copy /y “myservere$PKGSOURCEprogramnameserver.dat” “C:Program Files (x86)programname”

    I run whether or not logged in

    I distribute the package, the deploy to the client.

    No errors, does not work….

    Syntax?

    • You need to put the files you want to copy to the client in the package source folder also exactly as the blog post outlines. Copying from a network location means that you will have to adjust the permissions on that network location (ConfigMgr can’t magically override those). Also, using an admin share for anything except interactive work is a terrible practice. In this case, since you can’t change the permissions on an admin share, it will never work.

    • @Steve
      Mate you will first need to specify cmd.exe /c before the copy command e.g.
      cmd.exe /c copy /y “” “”
      Secondly you will need to use “%programfiles(x86)%”
      Also make sure it’s running under System not user context of course

  4. Awesome… I trolled for hours looking for something that was not written in code speak and an assumed knowledge base. I do not code save for the real basics and SCCM is still a struggle sometimes but your explanation saved the day. I was able to adapt it as I needed.
    The one thing I could not make work was to create a folder in a directory. When I used if not exist “%1” md “%1” it created a file of some sort but not a folder for which I could then drop the file into.

    I also need to look into %~dp0 and see what that accomplishes and why and when to use it. I know it was my salvation as I had the FQ path in there and it worked but only out side of SCCM.

    Thanks for a great great post J.M.

  5. Is there a way to remove the files, or overwrite them if needed later on? Or is that a whole other topic 🙂

    • The copy command given would will certainly overwrite any existing files. You could also get creative and use robocopy (instead of the copy command) with the /purge command to delete files that no longer existed. There are lots of ways you could get it done depending upon your exact requirements and expectations. You would of course have to update the source files and update the package also for this to work.

  6. Hi.

    I’m using this code to update some software where I need to replace one file after install to automatically fill out our proxy details.

    So, I’ve followed the above, but because I need to copy my file to a specific folder that already exists on the system with spaces included the code seems to be falling over. In SCCM log files it just tells me it is timing out.

    If I run it manually in the following way: filecopy.bat C:UsersPublicSecureAssess Central – SecureClient CANDGconfigfiles

    Then it works but only to the C:UsersPublicSecureAssess part, missing out the rest of the path I assume because of the space.

    If I try filecopy.bat “C:UsersPublicSecureAssess Central – SecureClient CANDGconfigfiles”

    Then it bombs out because it’s putting in two lots of ” around the path

    if not exist “”C:UsersPublicSecureAssess Central – SecureClient CANDGconfigfiles”” md “”C:UsersPublicSecureAssess Central – SecureClient CANDGconfigfiles””

    C;windowsccmcache57> copy /y “C:Windowsccmcache57Files2Copy*.*” “”C:UsersPublicSecureAssess Central – SecureClient CANDGconfigfiles””
    The syntax of the command is incorrect.

    Any suggestions?

    • Interesting. Here’s an easy fix (just replace %1 with %* in the batch file and then don’t surround your parameter with quotes even if it has spaces in it):
      if not exist “%*” md “%*”
      copy /y “%~dp0Files2Copy*.*” “%*”

  7. Step 6, the screenshot got right path but the text is missing ”
    filecopy.bat c:DesktopTools

    should be

    filecopy.bat c:DesktopTools

  8. Hi ,
    thanks for your helpful page, i tried your instructions and everything looked good.
    But now i try to start a new Paket and from now on i will allways get a 0x1(1) error message.
    Maybe i think i have a node in my head, i can’t find the right way.
    I use the following parameters:
    I create a package
    I check the box package has source files
    I specify the folder where the files are: serversubfolder$lib
    I specify a standard program
    next…
    I name the program (copy) and specify in the command line:
    filecopy.bat
    (that looks like :
    cmd.exe /c copy /y “%~dp0Files2Copy*.*” “%programfilesJavajdk1.8.0_45jrelibsecurity”)
    I run whether or not logged in with admin rights
    I distribute the package, the deploy to the client.

    in ccmcache i can see all the files (batch and the subfolder) = check!
    But in the exexecmgr.log i see:
    Execution is completet for program copy. the exit cod is 1, the execution status is FailureNonRetry.

    Do you have any suggestion ?
    I hope you can help me…

    Thanks

    • Assuming you’ve directly copied and pasted the line from your batch file, you’re missing a % sign after programfiles. You have “%programfilesJavajdk1.8.0_45jrelibsecurity” when it should be “%programfiles%Javajdk1.8.0_45jrelibsecurity”.

  9. To all struggling…
    Seems like HTML removes backslash sign, so the paths shown in the article are not displayed correctly (at least in Chrome)…
    So let’s say backslash = B, the paths in the article should be:
    filecopy.bat c:BDesktopTools
    copy /y “%~dp0BFiles2CopyB*.*” “%1”
    Hope that helps 🙂

    • Partially correct (I’ve updated the snippet in the post). There’s no need for the backslash after %~dp0 because that variable already contains a trailing backslash. As for the one after Files2Copy, it’s not HTML that stripped it, it was my blog migration 🙂

  10. Hi Jason, Thankyou for the post – it is very helpful however it is not working for me. I am trying to copy a couple of files from the server source to a client machine but it doesn’t work. I checked my execmgr.log and found “Execution is completed for program copy. the exit cod is 1, the execution status is FailureNonRetry”. Below is what I put in my batch file
    if not exist “%1” md “%1”
    cmd.exe /c copy /y “%~dp0Files2Copy/*.*”%Nush%”%1”

    Nush is the name of the folder on the client where I need the files to be copied to. Hoping you could help.

    Thank you so much in advance
    Nush.

    • Sorry I updated the batch file to
      if not exist “%1” md “%1”
      copy /y “%~dp0Files2Copy*.*””%1”
      I executed the batch file and it does what it is meant to but the deployment is still failing with the same exit code 1 and the execution status is FailedNonRetry 🙁 Hoping you could help please

      Thanks,
      Nush

      • Hi Nush, Based on the above, you’re missing a space after the *.*”. ALso, make sure your script isn’t using smart quotes.

  11. I am not sure what I have in correct. I am trying to place two files in an existing directory in Program Files (x86). The files are all showing in ccmcache but the bat file is failing with error “The system cannot find the file specified” in the copy portion. When it is copying, it is not looking in my “Files2Copy” folder but the parent folder instead. Am I missing something obvious? Thanks!

    Error:
    C:Windowsccmcache66test1.txt
    The system cannot find the file specified.

    **The file is in C:Windowsccmcache66New_Filestest1.txt

  12. Hello thanks for the great post. It’s working for me if my destination directory is a simple name but it is not working if my destination directory has a space between the name. This is what my command line looks like: filecopy.bat “c:dell test” I have also tried it without the quotes but it simply copied it to the c:dell directory. Any help to resolve this would be much appreciated. Thanks

    • Hi Yves, After some quick research, I updated and tested the batch file code above. This will work now for folders with spaces in their names.

  13. What would i enter after the copy command in the batch file so after the copy is done it then calls a vb script to run from the folder. If the vb script runs from the DP or cache it fails as it needs admin lvl to run on the system….. This seems like it will work if the files are copied to a folder on c then the vb script calls everything else to run….

    Thank you for the help!

    • To call a script in a batch file, you’d call it just like you would at the command-line as that’s all a batch file is: cscript //b //nologo c:mydirectorymyscript.vbs. Running as admin has nothing to do with where it’s run from though; that’s controlled by the Run Mode setting on the Environment tab of the program. Copying the script locally is completely unnecessary. See Current Directory in ConfigMgr Programs for details on this.

  14. easlyer with…

    Robocopy . “c:\destination-folder-here” *.*

    • Sorry, not sure what is easier here? The point of the blog is to copy content from a ConfigMgr package and thus “c:\destination-folder-here” above won’t work as that’s not known.

  15. FYI the Russ above isn’t me :). I would agree, robocopy doesn’t make this any easier! I shared this page with a customer today and saw my name and thought I might’ve been sleep-surfing for a second 😀 Hope you’re doing well Jason!

    • Doing great here. Thanks for chiming in Russ and Happy New Year (and such)! Hope all is well with you as well.

  16. Hello!
    Any easy way of doing this through PowerShell? We’ve standardized on PowerShell internally for all our scripts.

    • Hi Greg. Sure. The following is identical in usage and functionality. I haven’t tested it explicitly in ConfigMgr but there’s no reason it shouldn’t work:

      if (-not (Test-Path -Path $args[0]))
      {
      New-Item -Path $args[0] -ItemType Directory
      }

      Copy-Item -Path “$(Convert-Path -Path “.\Files2Copy\”)*” -Destination $args[0] -Force

  17. Hello Jason
    This article is interesting one however the task I am doing is to copy some files and execute a PS command once copied, I can copy the files locally but it copies the whole path that includes the name of the ccmcached file as well e.g. it copies files from c:\windows\ccmcache\ to c:\programname\n\files. “n” is the package downloaded by CM agent. However I need to make sure that i copies only c:\programname\files

    PS command:

    #Locations of where to copy the Zabbix agent and location of the agent files
    $ProgramDir = “$env:SystemDrive\Program”

    $ProgramInstallDir = $PSScriptRoot

    if (!(Test-Path -Path $ProgramDir))
    {
    New-Item $ProgramDir -ItemType Directory
    }

    Copy-Item $ProgramInstallDir $ProgramDir -Recurse

    Start-Process -FilePath “C:\Program\bin\program.exe” -ArgumentList “-c C:\program\conf\program.conf -i” -NoNewWindow -Wait
    Start-Sleep -Seconds 2
    Start-Process -FilePath “C:\Program\bin\Program.exe” -ArgumentList “-c C:\program\conf\program.conf -s”

    [Environment]::Exit(0)

    • Then you need to change the Path parameter to Copy-Item cmdlet to only specify the files subdirectory; i.e., $ProgramInstallDir = “$PSScriptRoot\files”.

  18. I keep getting failed – bad environment. Any idea what I’m doing wrong?