Use PowerShell’s Get-Content cmdlet to Copy Files to Multiple Computers

Automating monotonous tasks using PowerShell can save Windows Server administrators time. In this Ask the Admin, I’ll show you how to extract data stored in text files so that you can solve more complex problems using scripts.

If you have ever tried to parse text files using VBScript, the scripting language most commonly used with Windows Scripting Host (WSH) prior to the release of PowerShell, you will know that it is not always as straightforward as it could be. But PowerShell’s get-content cmdlet makes life much easier and there’s no reason why you can’t quickly and efficiently add code to your PowerShell scripts to extract the information needed. While get-content can’t parse comma-delimited files, I’ll describe how to use import-csv to simply perform that task in a future post.

Copy files to multiple computers

In my previous Ask the Admin, Copy, Move and Rename Files Using Windows PowerShell, I showed you how to perform basic file management operations using PowerShell. In this article, I’m going to use the copy-item cmdlet to copy a file to multiple computers listed in a .txt file.

The text file contains a list of computer names as follows, one on each line. The file is named computers.txt:

​computer1
computer2
computer3

Now let’s start with the PowerShell script. At the top of the script we’ll define some variables for the path to the text file containing the computer names, i.e. computers.txt; the path of the file to be copied ($sourcefile), and the last part of the UNC path for the destination.

We’ll only include the last part of the UNC in the $destination variable, because the full UNC path will be generated by the script. For computer1 it will look like this: \computer1c$temp. As the first part of the UNC path is different for every remote computer, we only need to specify the destination folder in the $destination variable and let the script do the rest.

​$computers = “c:tempcomputers.txt”
$sourcefile = “c:licensedusers.csv”
$destination = “temp”

The get-content cmdlet is then used to open and read the computers.txt file, and the result is piped to a foreach loop containing the copy-item cmdlet. In this example, copy-item is executed three times, once for each computer in the computers.txt file.

​get-content $computers | foreach {copy-item -path $sourcefile -destination \$_c$$destination}

The foreach loop in the command above requires you to wait for each copy operation to complete before proceeding to the next remote computer in the list. Depending on the number of computers in the text file, the size of the file being copied and the speed of the network, the script could take a considerable amount of time to complete. To run copy-item commands in parallel, see my article Stop Microsoft Azure Virtual Machines in Parallel using PowerShell on Petri, which shows you how to run commands in parallel using PowerShell Jobs.

More on PowerShell’s get-content cmdlet

There are various other ways you can use the get-content cmdlet to read information stored in the text file. The following piece of code can be added to the above script and adds an additional variable ($quantity) that’s calculated by using get-content to determine the number of lines in the computers.txt ($computers) file. Then the write-host cmdlet is used to output some information about the copy operations that the script will perform to the console.

​$quantity = (get-content $computers).length
write-host $sourcefile "will be copied to the" $destination "folder on" $quantity "remote computers."
Use Windows PowerShell's get-content cmdlet to return the number of lines in a text file (Image Credit: Russell Smith)
Use Windows PowerShell’s get-content cmdlet to return the number of lines in a text file (Image Credit: Russell Smith)

Specifying ranges

Another cool thing you can do with get-content is to specify a range. For example, you might want to process only the first line in the .txt file, the last three lines, or line 5 to 8. In the code below, I’ve modified the original line of code containing the foreach loop and added an additional variable ($process) to hold the results of the get-content cmdlet.

The snippet of code that follows reads only the first line from the text file, which get-content reads as an array of strings starting at zero.

​$process = (get-content $computers)[0]
$process | foreach {copy-item -path $sourcefile -destination \$_c$$destination}

In this example, I’m processing the first five lines of the text file, although you can start at any line number, it doesn’t have to be zero.

​$process = (get-content $computers)[0..4]

And here the last five lines:

​$process = (get-content $computers)[-5..-1]