5

Alright, been working on this for hours and researching like crazy, but still not getting something to work. I need a string[] object created from get-childitem to pass to the Copy-Item -exclude parameter.

The hurdle is that I need to do recursion and need to have relative paths, so this is what I came up with:

$((Get-ChildItem -Path $Dest -Recurse -File).FullName.TrimStart($Dest))

This results in a clean list of existing files in $dest that are presented with a relative path to $dest. The problem is, if I add this to the copy-item -exclude parameter it seems to ignore it. Further research online suggests that copy-item will ignore the -exclude parameter if it is not of type string[].

If I check the type returned by the above command, I get System.Object[]. I expect it to be System.String[] or just plain String[].

How do I convert the output of the above command to a string array?

The full command using copy-item, for clarity, is:

Copy-Item -Path (Join-Path $src "*") -Destination $dest -Recurse -Force -Exclude $((Get-ChildItem -Path $Dest -Recurse -File).FullName.TrimStart($Dest))

My end goal is to copy files recursively without overwriting existing files.

3
  • 1
    -Exclude (and -Include) only support file name patterns, not paths. However, adding support for paths is being discussed in this GitHub issue. Commented Oct 31, 2019 at 17:50
  • 1
    Just so you know, that's not how TrimStart() is supposed to be used. It takes an array of characters for which all occurrences will be removed from the beginning of the string, not an exact string to be removed from the beginning; for that you'd want something like .FullName.Substring($Dest.Length). Apparently TrimStart($Dest) works for you here, which suggests $Dest does not contain a trailing backslash. With a trailing backslash it might remove characters from the relative child path beyond the length of $Dest. Commented Oct 31, 2019 at 17:58
  • Trimstart() doesn't do what you think it does. For example, this will result in an empty string: 'ababab'.trimstart('ab'). Commented Oct 31, 2019 at 21:27

3 Answers 3

10

To get a string[] from the names of get-childitem cmdlet use the following

[string[]]$files = (Get-ChildItem).Name
Sign up to request clarification or add additional context in comments.

1 Comment

This should be Flagged as the Answer.
1

This will do what it appears you say that you want? But, I think that may not be everything to your question.

$((Get-ChildItem -Path $Dest -Recurse -File).FullName.Replace("$Dest",'.'))

Comments

0

@mklement0 is right, -Exclude and -Include support file name patterns (i.e. "*.txt") and not an array of explicit paths.

This sounds like an awful lot like an XY Problem ;-)

If you simply want to copy files recursively without overwriting them, use Robocopy with the Mirror switch. e.g.:

robocopy C:/Source C:/Dest /mir

EDIT:

By default Copy-Item will always overwrite the files on copy, and there is no switches to get around this. I usually recommend Robocopy as it really simplifies things like this and is very "robust" and reliable.

If your requirements are for a "pure" PowerShell version, then you have to break the scrip out into two parts, 1. Get a list of all the files 2. Iterate through the filer and test to see if they are already in the destination before copying.

$SrcPath = "C:/Source"
$DestPath = "C:/Dest"

$SrcFiles = Get-ChildItem $SrcPath -Recurse

#Iterate through files testing:
$SrcFiles | ForEach-Object {
    #Calculate Destination File/Folder name/path
    $DestObj = $_.FullName.Replace($SrcPath, $DestPath)

    if(Test-Path -LiteralPath $DestObj)
    {
        #File already Exists
        Write-Host "File already Exists: $DestObj"
    }
    else
    {
        #File Does not exist - Copy
        Write-Host "File Does not Exist Copy: $DestObj"
        Copy-Item -Path $_ -Destination $DestObj
    }
}

3 Comments

Thank you for the answer. I’m aware of RoboCopy and also aware that it is often a proposed solution. However, I expect powershell to be able to easily copy files without overwriting existing files. I do not want to fire up a third party executable and then try to account for errorhandling and logging in that executable to do an extremely simple task.
Yeah, by default Copy-Item always overwrites. Please see edits above where I have provided a full native PowerShell solution.
@Appleoddity, Robocopy.exe is not a third-party executable. It is part of the Windows operating system.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.