{"id":86028,"date":"2015-12-20T06:29:32","date_gmt":"2015-12-20T14:29:32","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/scripting\/?p=86028"},"modified":"2019-06-12T07:07:09","modified_gmt":"2019-06-12T15:07:09","slug":"build-a-better-copy-item-cmdlet-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/build-a-better-copy-item-cmdlet-2\/","title":{"rendered":"Build a Better Copy-Item Cmdlet"},"content":{"rendered":"<p><b>Summary<\/b>: Sean Kearney investigates how to navigate file system content.<\/p>\n<p>Honorary Scripting Guy, Sean Kearney, is here with an early holiday gift&mdash;a way to deal with copying many files and getting some kind of progress on the update.<\/p>\n<p>I ran into this problem when I was duplicating file structures onto USB keys for Windows to Go a few months ago. Maybe &ldquo;problem&rdquo; is not the correct word. When I execute <b>Copy-Item<\/b> to duplicate a file structure, it works properly. There is, of course, some &ldquo;finicky&rdquo; issues.<\/p>\n<p>As one reader correctly pointed out the other week, one issue arises if the folder name already exists when you copy. It creates a new folder under the parent instead of merging.<\/p>\n<p>Another issue (and for me personally, the more irritating one) is when I copy a large pile of files. There is no status on exactly where it is.<\/p>\n<p>When I copy a Nano Server structure, this is seconds, so I may not care. However, if you&rsquo;re copying a larger structure, and in the midst is, oh I don&rsquo;t know, a 3&nbsp;gigabyte WIM file for Windows to Go, that might be annoying. It&rsquo;s always good to know if you need to grab a coffee.<\/p>\n<p>Why not use Robocopy? Nothing wrong with it. I personally like seeing how I can do it with Windows PowerShell in the event that Robocopy.exe falls into the category of Netsh and becomes deprecated.<\/p>\n<p>And I&rsquo;m a bit of a nerd&hellip;so, &ldquo;Just cuz.&rdquo;<\/p>\n<p>Let&rsquo;s imagine we&rsquo;re going to duplicate a massive structure. The current PowerShell process is:<\/p>\n<p style=\"margin-left:30px;\">Copy-Item C:\\Foo D:\\Foo &ndash;recurse &ndash;force<\/p>\n<p>It all works. It &ldquo;runs away for a bit&rdquo; and then returns when it&rsquo;s done.<\/p>\n<p>Our other option is to build a little script (or maybe an advanced function) to play with <b>Get-Childitem<\/b> and <b>Copy-Item<\/b>. That could work!<\/p>\n<p>First I&rsquo;ll define a command that includes two key parameters, <b>Source<\/b> and <b>Destination<\/b>:<\/p>\n<p style=\"margin-left:30px;\">Function Copy-WithProgress<\/p>\n<p style=\"margin-left:30px;\">{<\/p>\n<p style=\"margin-left:30px;\">&nbsp;[CmdletBinding()]<\/p>\n<p style=\"margin-left:30px;\">&nbsp;Param<\/p>\n<p style=\"margin-left:30px;\">&nbsp;(<\/p>\n<p style=\"margin-left:30px;\">&nbsp; [Parameter(Mandatory=$true,<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp; ValueFromPipelineByPropertyName=$true,<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp; Position=0)]<\/p>\n<p style=\"margin-left:30px;\">&nbsp; $Source,<\/p>\n<p style=\"margin-left:30px;\">&nbsp; [Parameter(Mandatory=$true,<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp; ValueFromPipelineByPropertyName=$true,<\/p>\n<p style=\"margin-left:30px;\">&nbsp;&nbsp;&nbsp;&nbsp; Position=0)]<\/p>\n<p style=\"margin-left:30px;\">&nbsp; $Destination<\/p>\n<p style=\"margin-left:30px;\">&nbsp;)<\/p>\n<p>I will start by ensuring that the <b>$Source<\/b> folder is in all lowercase letters. This will come in handy later when I use it to replace itself. (Yes, you heard that correctly.)<\/p>\n<p style=\"margin-left:30px;\">$Source=$Source.tolower()<\/p>\n<p>Now I get the entire folder structure and store it as an object:<\/p>\n<p style=\"margin-left:30px;\">$Filelist=Get-Childitem $Source &ndash;Recurse<\/p>\n<p>Now that I have this as a full object, I can get useful properties to use with the <b>Write-Progress<\/b> cmdlet. I can get the count of all the objects that would be copied with this command:<\/p>\n<p style=\"margin-left:30px;\">$Total=$Filelist.count<\/p>\n<p>I establish a counter so that as I copy each file, I can determine how far I am from the end:<\/p>\n<p style=\"margin-left:30px;\">$Position=0<\/p>\n<p>Stepping through the list of files is quite simple in PowerShell by using a For loop:<\/p>\n<p style=\"margin-left:30px;\">&nbsp;foreach ($File in $Filelist)<\/p>\n<p style=\"margin-left:30px;\">&nbsp;{<\/p>\n<p>On each file, I&rsquo;m going to need only the part that does not include the original source folder. I can pull this off with a simple <b>Replace<\/b> method on the content:<\/p>\n<p style=\"margin-left:30px;\">&nbsp; $Filename=$File.Fullname.tolower().replace($Source,&#39;&#39;)<\/p>\n<p>Now I rebuild the path for the destination:<\/p>\n<p style=\"margin-left:30px;\">&nbsp; $DestinationFile=($Destination+$Filename)<\/p>\n<p>I can now do something more useful&mdash;show what I&rsquo;m doing and how far I am!<\/p>\n<p style=\"margin-left:30px;\">&nbsp; Write-Progress -Activity &quot;Copying data from $source to $Destination&quot; -Status &quot;Copying File $Filename&quot; -PercentComplete (($Position\/$total)*100)<\/p>\n<p style=\"margin-left:30px;\">&nbsp; Copy-Item $File.FullName -Destination $DestinationFile<\/p>\n<p>I can bump up the counter:<\/p>\n<p style=\"margin-left:30px;\">&nbsp; $Position++<\/p>\n<p style=\"margin-left:30px;\">&nbsp;}<\/p>\n<p style=\"margin-left:30px;\">}<\/p>\n<p>And voila!<\/p>\n<p>If you copy a big folder in this manner, you&rsquo;ll get something like this:<\/p>\n<p style=\"margin-left:30px;\">Copy-WithProgress &ndash;source C:\\NanoServer &ndash;Destination C:\\NanoNew<\/p>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/1526.1.png\"><img decoding=\"async\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/1526.1.png\" alt=\"image of command output\" width=\"626\" height=\"111\" class=\"aligncenter size-full wp-image-86030\" srcset=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/1526.1.png 626w, https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2015\/12\/1526.1-300x53.png 300w\" sizes=\"(max-width: 626px) 100vw, 626px\" \/><\/a><\/p>\n<p>Of course, this command is far from complete. This is a direct &ldquo;assume you&rsquo;re going to copy it all&rdquo; approach. We could improve with some better error trapping and perhaps a way to pass more data for <b>Get-Childltem<\/b> to filter on.<\/p>\n<p>But this was fun to play with on the weekend. Save yourself some typing. This command is sitting in its current state in the <b>DeployImage<\/b> module that I discussed earlier in the month. You can find it in the PowerShell Gallery, GitHub, and even on the TechNet Script Repository. For more details, see the series <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/use-deployimage-module-and-powershell-to-build-a-nano-server-part-1\/\" target=\"_blank\">Use DeployImage Module and PowerShell to Build a Nano Server<\/a>.<\/p>\n<p>We&rsquo;ll see you all tomorrow with our annual Scripting Guys Holiday Special: The Five Days of PowerShell 5!<\/p>\n<p>I invite you to follow the Scripting Guys on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to them at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, always remember that with great PowerShell comes great responsibility.<\/p>\n<p><b>Sean Kearney<\/b>, Honorary Scripting Guy, Cloud and Datacenter Management MVP&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Sean Kearney investigates how to navigate file system content. Honorary Scripting Guy, Sean Kearney, is here with an early holiday gift&mdash;a way to deal with copying many files and getting some kind of progress on the update. I ran into this problem when I was duplicating file structures onto USB keys for Windows to [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-86028","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting"],"acf":[],"blog_post_summary":"<p>Summary: Sean Kearney investigates how to navigate file system content. Honorary Scripting Guy, Sean Kearney, is here with an early holiday gift&mdash;a way to deal with copying many files and getting some kind of progress on the update. I ran into this problem when I was duplicating file structures onto USB keys for Windows to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/86028","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=86028"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/86028\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=86028"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=86028"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=86028"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}