I need to add a safety net in my script. I'm trying to do a copy job based on a list of users provided through a txt file. Copy the files from that users home directory to a new location. Once the files are copied, check if the file exists in the new location. If yes, then Remove-Item.
Can someone help me? I just don't know how to implement the "if file exists" logic.
$username = Get-Content '.\users.txt'
foreach ($un in $username)
{
$dest = "\\server\homedirs\$un\redirectedfolders"
$source = "\\server\homedirs\$un"
New-Item -ItemType Directory -Path $dest\documents, $dest\desktop
Get-ChildItem $source\documents -Recurse -Exclude '*.msg' | Copy-Item -Destination $dest\documents
Get-ChildItem $source\desktop -Recurse -Exclude '*.msg' | Copy-Item -Destination $dest\desktop
Get-ChildItem $source\mydocuments, $source\desktop -Recurse -Exclude '*.msg' | Remove-Item -Recurse
}
The Copy-Item cmdlet copies an item from one location to another location in the same namespace. For instance, it can copy a file to a folder, but it can't copy a file to a certificate drive. This cmdlet doesn't cut or delete the items being copied.
By default, when you will copy item in PowerShell using the Copy-Item, it will overwrite the files in the destination folder. The above PowerShell script will overwrite the files but it will show an error for folders: Copy-Item : An item with the specified name D:\Bijay\Destination\Folder1 already exists.
Subscribe to ShellGeek! PowerShell Test-Path cmdlet check if file exists or not. If file exists, it will return $True and $False if the file doesn't exist on a specified path. PowerShell Remove-Item cmdlet is used to delete the file if exists from the specified path by the $FileName variable.
The shortest way to delete file if it doesn't exist is NOT to use Test-Path
but:
rm my_file.zip -ea ig
This is short version of
rm my_file.zip -ErrorAction Ignore
which is much more readable and more DRY then
if (Test-Path my_file.zip) { rm my_file.zip }
To answer your question per se, you can do it like this:
Get-ChildItem $source\mydocuments, $source\desktop -Recurse -Exclude '*.msg' | %{
if (Test-Path ($_. -replace "^$([regex]::escape($source))","$dest")) {
Remove-Item $_ -Recurse
}
}
$_ -replace "^$([regex]::escape($source))","$dest"
converts the path of each source item you're enumerating with the corresponding destination path, by replacing $source at the beginning of the path with $dest.^$source
(which means "match the value of $source at the beginning of the string"). However, you need to use [regex]::escape in case $source contains any regex special characters, which is in fact extremely likely with Windows paths, since they contain backslashes. For example, the value you've given here for $source contains \s
, which in a regex means "any whitespace character". $([regex]::escape($source))
will interpolate the value of $source with any regex special characters properly escaped, so that you're matching the explicit value.That said, if your purpose is to copy each item to a new location, and remove the original only if the copy to the new location is successful, it seems like you're reinventing the wheel. Why not just use Move-Item instead of Copy-Item?
Not directly related to the question, but rather than repeating the same command for each subdirectory, you can use a foreach loop:
foreach ($subdir in (echo documents desktop)) {
# Whatever command you end up using to copy or move the items,
# using "$source\$subdir" and "$dest\$subdir" as the paths
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With