Quick question regarding the PowerShell Copy-Item command. I was wondering if you have a directory structure and wanted to overwrite another directory structure is there a way to run the Copy-Item command in a 'preview' mode. It would output what files its overwriting from directory a to directory b but not actually perform the Copy-Item command.
Any help or advice appreciated.
Thanks.
Interesting question!
Here is my attempt of doing it all in Powershell, so not needing RoboCopy.
function Copy-Preview {
[CmdletBinding(DefaultParameterSetName = 'ByPath')]
param(
[Parameter(ValueFromPipeline = $true, Mandatory = $true, ParameterSetName = 'ByPath', Position = 0)]
[ValidateScript({ Test-Path $_ })]
[string]$Path,
[Parameter(ValueFromPipeline = $true, Mandatory = $true, ParameterSetName = 'ByLiteralPath', Position = 0)]
[ValidateScript({ Test-Path $_ })]
[string]$LiteralPath,
[Parameter(ValueFromPipeline = $true, Mandatory = $true, Position = 1)]
[string]$Destination,
[string]$Filter = $null,
[string]$Include = $null,
[string]$Exclude = $null,
[switch]$Recurse,
[switch]$Force
)
if ($PSCmdlet.ParameterSetName -eq 'ByLiteralPath') { $Path = $LiteralPath }
# determine if $Path and $Destination hold a file or a directory
$srcIsFolder = (Test-Path $Path -PathType Container -ErrorAction SilentlyContinue)
# cannot use Test-Path here because then the path has to exist.
# assume if it has an extension the path is a file, otherwise a directory
# NOTE:
# This is certainly not fullproof, so to avoid problems, always make sure
# the destination ends with a backslash if a directory is intended.
$destIsFolder = (-not ([System.IO.Path]::HasExtension($Destination)))
if ($destIsFolder -and !(Test-Path $Destination -PathType Container)) {
Write-Host "Destination path does not exist yet. All files from '$Path' will be copied fresh" -ForegroundColor Green
return
}
elseif ($srcIsFolder -and (!$destIsFolder)) {
# should not happen: source is a directory, while the destination is a file..
Write-Error "When parameter Path points to a directory, the Destination cannot be a file.."
return
}
$count = 0
if ($srcIsFolder -and $destIsFolder) {
# Both the source and the destinations are folders
# make sure both paths are qualified for .Replace() further down
if (-not $Path.EndsWith("\")) { $Path += "\" }
if (-not $Destination.EndsWith("\")) { $Destination += "\" }
$splat = #{
Filter = $Filter
Include = $Include
Exclude = $Exclude
Recurse = $Recurse
Force = $Force
}
# add either Path or LiteralPath to the parameters as they are mutually exclusive
if ($PSCmdlet.ParameterSetName -eq 'ByPath') { $splat.Path = $Path }
else { $splat.LiteralPath = $LiteralPath }
$srcFiles = Get-ChildItem #splat | Select-Object -ExpandProperty FullName
# reuse the splat parameters hash for the destination, but change the Path
if ($splat.LiteralPath) {($splat.Remove("LiteralPath"))}
$splat.Path = $Destination
$destFiles = Get-ChildItem #splat | Select-Object -ExpandProperty FullName
foreach ($srcItem in $srcFiles) {
$destItem = $srcItem.Replace($Path, $Destination)
if ($destFiles -contains $destItem) {
Write-Host "'$destItem' would be overwritten"
$count++
}
}
}
elseif (!$srcIsFolder) {
# the source is a file
if (!$destIsFolder) {
# the destination is also a file
if (Test-Path $Destination -PathType Leaf) {
Write-Host "'$Destination' would be overwritten"
$count++
}
}
else {
# source is file, destination is a directory
$destItem = Join-Path $Destination (Split-Path $Path -Leaf)
if (Test-Path $destItem -PathType Leaf) {
Write-Host "'$destItem' would be overwritten"
$count++
}
}
}
$msg = "$count item{0} would be overwritten by Copy-Item" -f $(if ($count -ne 1) { 's' })
$dash = "-" * ($msg.Length)
Write-Host "$dash`r`n$msg" -ForegroundColor Green
}
tl;dr:
Copy-Item -WhatIf will not give you the level of detail you're looking for - see below.
Use robocopy.exe -l instead (Windows only), as Ansgar Wiechers recommends, because it individually lists what files would be copied, including dynamically omitting those already present in the target dir (with the same size and last-modified time stamp, by default).
Generally, robocopy is faster and more fully featured than Copy-Item, and it avoids a notable pitfall of the latter.
Get-Help about_CommonParameters documents the -WhatIf common parameter supported by many (but not all) cmdlets, whose purpose is to preview an operation without actually performing it.
However, this feature is implemented in an abstract fashion, and often doesn't provide information as detailed as one would hope.
Case in point: while Copy-Item does support -WhatIf, it probably won't give you the level of detail you're looking for, because if the source item is a directory, only a single line such as the following is output:
What if: Performing the operation "Copy Directory" on target "Item: sourceDir Destination: destDir".
Note that you'll see the same line whether or not your Copy-Item call includes the -Recurse switch.
Even if you ensure existence of the target directory manually and append /* to the source directory path in order to see individual filenames, you'd only see them at the child level, not further down the subtree, and you'd never get the dynamic information that robocopy -l provides with respect to what files actually need replacement.
You can use the -whatif parameter.
Copy-item -path myfile.txt -destination myfoldertoCopyTo\ -whatif
Related
In other words, does PowerShell's Expand-Archive have an equivalent to unzip's -j command-line argument? If not, are there alternatives on Windows?
I have tried Expand-Archive -Path thing.zip -DestinationPath "somepath" -Force, which just puts the directory structure in another folder called somepath.
This function will do what you want, obviously handling of possible file collision is not implemented, up to you how you want to implement that. Currently, if a file already exists with the same name it will give you an error and skip it. The function is a simplified version of the one from this answer which does actually keep the folder structure.
If no argument is passed to the -DestinationPath parameter, the zip entries will be extracted to the current location.
using namespace System.IO
using namespace System.IO.Compression
function Expand-ZipArchive {
[CmdletBinding(DefaultParameterSetName = 'Path')]
param(
[Parameter(ParameterSetName = 'Path', Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
[string] $Path,
[Parameter(ParameterSetName = 'LiteralPath', Mandatory, ValueFromPipelineByPropertyName)]
[Alias('PSPath')]
[string] $LiteralPath,
[Parameter()]
[string] $DestinationPath
)
begin {
Add-Type -AssemblyName System.IO.Compression
$DestinationPath = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($DestinationPath)
}
process {
$arguments = switch($PSCmdlet.ParameterSetName) {
Path { $Path, $false, $false }
LiteralPath { $LiteralPath, $false, $true }
}
$null = [Directory]::CreateDirectory($DestinationPath)
foreach($item in $ExecutionContext.InvokeProvider.Item.Get.Invoke($arguments)) {
try {
$fileStream = $item.Open([FileMode]::Open)
$zipArchive = [ZipArchive]::new($fileStream, [ZipArchiveMode]::Read)
foreach($entry in $zipArchive.Entries) {
try {
# if it's a folder, exclude it
if(-not $entry.Name) {
continue
}
$path = [Path]::Combine($DestinationPath, $entry.Name)
# will throw if a file with same name exists, intended
# error handling should be implemented in `catch` block
$fs = [FileStream]::new($path, [FileMode]::CreateNew)
$wrappedStream = $entry.Open()
$wrappedStream.CopyTo($fs)
}
catch {
$PSCmdlet.WriteError($_)
}
finally {
$fs, $wrappedStream | ForEach-Object Dispose
}
}
}
catch {
$PSCmdlet.WriteError($_)
}
finally {
$zipArchive, $fileStream | ForEach-Object Dispose
}
}
}
}
Expand-ZipArchive .\myZip.zip
As a PowerShell-only way you could extract the archive to a temporary directory and then move the files to the final location, discarding directory structure.
$archiveName = 'test.zip'
$destination = 'test'
# Create temp path as a sub directory of actual destination path, so the files don't
# need to be moved (potentially) across drives.
$destinationTemp = Join-Path $destination "~$((New-Guid).ToString('n'))"
# Create temp directory
$null = New-Item $destinationTemp -ItemType Directory
# Extract to temp dir
Expand-Archive $archiveName -DestinationPath $destinationTemp
# Move files from temp dir to actual destination, discarding directory structure
Get-ChildItem $destinationTemp -File -Recurse | Move-Item -Destination $destination
# Remove temp dir
Remove-Item $destinationTemp -Recurse -Force
With PowerShell 7+, you could even move each file immediately after extraction, using the new -PassThru switch of Expand-Archive:
$archiveName = 'test.zip'
$destination = 'test'
# Create temp path as a sub directory of actual destination path, so the files don't
# need to be moved (potentially) across drives.
$destinationTemp = Join-Path $destination "~$((New-Guid).ToString('n'))"
# Create temp directory
$null = New-Item $destinationTemp -ItemType Directory
# Expand to temp dir and move to final destination, discarding directory structure
Expand-Archive $archiveName -DestinationPath $destinationTemp -PassThru |
Where-Object -not PSIsContainer | Move-Item -Destination $destination
# Remove temp dir
Remove-Item $destinationTemp -Recurse -Force
I am trying to copy all files in folders and sub-folders not older than 300 minutes, but the code I got working only copies the files in the main folder, it doesn't copy the files in subfolders.
At the destination I don't want to maintain the folder structure of the original files, I just want to put all the origin files into a single specific destination folder.
This is the code I have:
Powershell -NoL -NoP -C "&{$ts=New-TimeSpan -M 300;"^
"Get-ChildItem "C:\Origin" -Filter '*.dat'|?{"^
"$_.LastWriteTime -gt ((Get-Date)-$ts)}|"^
%%{Copy-Item $_.FullName 'C:\Destination'}}"
Could someone help me out please?
Thanks in advance.
Here's a modified script for you you can save as "Copy-Unique.ps1" you can run from a batch file.
function Copy-Unique {
# Copies files to a destination. If a file with the same name already exists in the destination,
# the function will create a unique filename by appending '(x)' after the name, but before the extension.
# The 'x' is a numeric sequence value.
[CmdletBinding(SupportsShouldProcess)] # add support for -WhatIf switch
Param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[Alias("Path")]
[ValidateScript({Test-Path -Path $_ -PathType Container})]
[string]$SourceFolder,
[Parameter(Mandatory = $true, Position = 1)]
[string]$DestinationFolder,
[Parameter(Mandatory = $false)]
[int]$NewerThanMinutes = -1,
[Parameter(Mandatory = $false)]
[string]$Filter = '*',
[switch]$Recurse
)
# create the destination path if it does not exist
if (!(Test-Path -Path $DestinationFolder -PathType Container)) {
Write-Verbose "Creating folder '$DestinationFolder'"
$null = New-Item -Path $DestinationFolder -ItemType 'Directory' -Force
}
# get a list of file FullNames in this source folder
$sourceFiles = #(Get-ChildItem -Path $SourceFolder -Filter $Filter -File -Recurse:$Recurse)
# if you want only files not older than x minutes, apply an extra filter
if ($NewerThanMinutes -gt 0) {
$sourceFiles = #($sourceFiles | Where-Object { $_.LastWriteTime -gt (Get-Date).AddMinutes(-$NewerThanMinutes) })
}
foreach ($file in $sourceFiles) {
# get an array of all filenames (names only) of the files with a similar name already present in the destination folder
$destFiles = #((Get-ChildItem $DestinationFolder -File -Filter "$($file.BaseName)*$($file.Extension)").Name)
# for PowerShell version < 3.0 use this
# $destFiles = #(Get-ChildItem $DestinationFolder -Filter "$baseName*$extension" | Where-Object { !($_.PSIsContainer) } | Select-Object -ExpandProperty Name)
# construct the new filename
$newName = $file.Name
$count = 1
while ($destFiles -contains $newName) {
$newName = "{0}({1}){2}" -f $file.BaseName, $count++, $file.Extension
}
# use Join-Path to create a FullName for the file
$newFile = Join-Path -Path $DestinationFolder -ChildPath $newName
Write-Verbose "Copying '$($file.FullName)' as '$newFile'"
$file | Copy-Item -Destination $newFile -Force
}
}
# you can change the folder paths, file pattern to filter etc. here
$destFolder = Join-Path -Path 'C:\Destination' -ChildPath ('{0:yyyy-MM-dd_HH-mm}' -f (Get-Date))
Copy-Unique -SourceFolder "C:\Origin" -DestinationFolder $destFolder -Filter '*.dat' -Recurse -NewerThanMinutes 300
Changed the code to now take a datetime object to compare against rather than an amount of minutes. This perhaps makes the code easier to understand, but certainly more flexible.
function Copy-Unique {
# Copies files to a destination. If a file with the same name already exists in the destination,
# the function will create a unique filename by appending '(x)' after the name, but before the extension.
# The 'x' is a numeric sequence value.
[CmdletBinding(SupportsShouldProcess)] # add support for -WhatIf switch
Param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[Alias("Path")]
[ValidateScript({Test-Path -Path $_ -PathType Container})]
[string]$SourceFolder,
[Parameter(Mandatory = $true, Position = 1)]
[string]$DestinationFolder,
[string]$Filter = '*',
[datetime]$NewerThan = [datetime]::MinValue,
[switch]$Recurse
)
# create the destination path if it does not exist
if (!(Test-Path -Path $DestinationFolder -PathType Container)) {
Write-Verbose "Creating folder '$DestinationFolder'"
$null = New-Item -Path $DestinationFolder -ItemType 'Directory' -Force
}
# get a list of file FullNames in this source folder
$sourceFiles = #(Get-ChildItem -Path $SourceFolder -Filter $Filter -File -Recurse:$Recurse)
# if you want only files newer than a certain date, apply an extra filter
if ($NewerThan -gt [datetime]::MinValue) {
$sourceFiles = #($sourceFiles | Where-Object { $_.LastWriteTime -gt $NewerThan })
}
foreach ($file in $sourceFiles) {
# get an array of all filenames (names only) of the files with a similar name already present in the destination folder
$destFiles = #((Get-ChildItem $DestinationFolder -File -Filter "$($file.BaseName)*$($file.Extension)").Name)
# for PowerShell version < 3.0 use this
# $destFiles = #(Get-ChildItem $DestinationFolder -Filter "$baseName*$extension" | Where-Object { !($_.PSIsContainer) } | Select-Object -ExpandProperty Name)
# construct the new filename
$newName = $file.Name
$count = 1
while ($destFiles -contains $newName) {
$newName = "{0}({1}){2}" -f $file.BaseName, $count++, $file.Extension
}
# use Join-Path to create a FullName for the file
$newFile = Join-Path -Path $DestinationFolder -ChildPath $newName
Write-Verbose "Copying '$($file.FullName)' as '$newFile'"
$file | Copy-Item -Destination $newFile -Force
}
}
# you can change the folder paths, file pattern to filter etc. here
$destFolder = Join-Path -Path 'D:\Destination' -ChildPath ('{0:yyyy-MM-dd_HH-mm}' -f (Get-Date))
Copy-Unique -SourceFolder "C:\Origin" -DestinationFolder $destFolder -Filter '*.dat' -Recurse -NewerThan (Get-Date).AddMinutes(-300)
When you have saved the above code to let's say 'C:\Scripts\Copy-Unique.ps1' you can then call it from a batch file like:
Powershell.exe -NoLogo -NoProfile -File "C:\Scripts\Copy-Unique.ps1"
when i tried to run the script
only first and second condition is triggered
when i tried for "e.g D:\random " where random folder is not exists, i got error message instead of triggering 3rd conditional "else"
function listChildFolder($folderPath)
{
#write your script here
$folderPath = Read-Host "input"
if ((Get-ChildItem $folderPath) -ne $null)
{ $folderPath| Get-ChildItem |Sort-Object -Property LastWriteTime -Descending |Format-Table name }
elseif ((Get-ChildItem $folderPath) -eq $null)
{ "Folder Empty" }
else {"Error: <Error message>"}
return
}
Since Get-ChildItem throws a terminating error when the folder path does not exist, the function will end there and the rest of the elseif or else conditions are never executed.
I would suggest doing this in a try{..} catch{..} so you can capture exceptions like that:
Something like
function listChildFolder {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string]$folderPath
)
# capture the terminating error message when the path does not exist
# by specifying -ErrorAction Stop
try {
# since we do not add switch '-File' or '-Directory',
# the Get-ChildItem cmdlet will return both types
$filesAndFolders = Get-ChildItem -Path $folderPath -ErrorAction Stop
# next, find out if we found any files or folders in the path
# the '#()' forces the $filesAndFolders variable into an array, so we can use the .Count property
if (#($filesAndFolders).Count) {
$filesAndFolders | Sort-Object LastWriteTime -Descending | Select-Object Name
}
else {
Write-Host "No files or subfolders found in '$folderPath'"
}
}
catch {
Write-Warning "Error: $($_.Exception.Message)"
}
}
$folderPath = Read-Host "Please enter a folder path"
# call the function
listChildFolder $folderPath
Another recommendation is that you use the PowerShell Verb-Noun naming convention for your function
As per your comment where you say you may not use try{..} catch{..}, there are other ways of course.
How about this:
function listChildFolder {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string]$folderPath
)
# test if the given folder path exists
if (Test-Path -Path $folderPath -PathType Container) {
# since we do not add switch '-File' or '-Directory',
# the Get-ChildItem cmdlet will return both types
$filesAndFolders = Get-ChildItem -Path $folderPath
# next, find out if we found any files or folders in the path
# the '#()' forces the $filesAndFolders variable into an array, so we can use the .Count property
if (#($filesAndFolders).Count) {
$filesAndFolders | Sort-Object LastWriteTime -Descending | Select-Object Name
}
else {
Write-Host "No files or subfolders found in '$folderPath'"
}
}
else {
Write-Warning "Error: '$folderPath' does not exist"
}
}
$folderPath = Read-Host "Please enter a folder path"
# call the function
listChildFolder $folderPath
I´m facing to an issue that i can´t figure it out, how can i solve.
Basically i´ve an function that copy files from one directory to another directory, and rename it, if they already exists.
In the mean while, if any file with case sensitive name, it don´t copy it at all.
example:
TEXT.xml
text.xml
It just copy one of them. i need to copy both files.
Now, is the Rename-Item or the Copy-Item, that can´t deal with this case sensitive? Any idea how can i solve this?
Thanks for any help
My code:
Function Copy-File {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$Origin,
[Parameter(Mandatory = $true, Position = 1)]
[string]$Destination
)
# check if a file with that name already exists within the destination
$fileName = Join-Path $Destination ([System.IO.Path]::GetFileName($Origin))
if (Test-Path $fileName -PathType Leaf){
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($Origin)
$extension = [System.IO.Path]::GetExtension($Origin) # this includes the dot
$allFiles = Get-ChildItem $Destination | Where-Object {$_.PSIsContainer -eq $false} | Foreach-Object {$_.Name}
$newName = $baseName + $extension
$count = 1
while ($allFiles -contains $newName) {
$newName = [string]::Format("{0}({1}){2}", $baseName, $count.ToString(), $extension)
$count++
}
# rename the file already in the destination folder
# Write-Verbose -Message "Renaming file '$fileName' to '$newName'"
Rename-Item $fileName -NewName $newName
}
#Write-Verbose -Message "Moving file '$Origin' to folder '$Destination'"
Copy-Item $Origin $Destination
}
All of what you are after here is just doing this...
(always use validation testing for all destructive commands/code --- (Delete/Rename/Modify/Update/Move))
Clear-Host
$SourceFiles = 'D:\Temp\Source'
$Destination = 'D:\Temp\Destination'
$Counter = 0
Get-ChildItem -Path $SourceFiles |
ForEach{
Try
{
If(Test-Path -Path $Destination\$PSItem)
{
$Counter++
Write-Warning -Message "$($PSItem.Name) already exits. Renaming destination file."
Rename-Item -Path $Destination\$PSItem -NewName "$($PSItem.Basename)_$Counter$($PSitem.Extension)" -WhatIf
# Copy-Item -Path $PSItem.FullName -Destination $Destination -WhatIf
}
Else
{
Write-Verbose -Message "$($PSItem.Name) does not exist. Copying file." -Verbose
Copy-Item -Path $PSItem.FullName -Destination $Destination -WhatIf
}
}
Catch {$PSItem.Exception.Message}
}
# Results
<#
VERBOSE: 5 Free Software You'll Wish You Knew Earlier! 2019 - YouTube.url does not exist. Copying file.
What if: Performing the operation "Copy File" on target "Item: D:\Temp\Source\5 Free Software You'll Wish You Knew Earlier! 2019 - YouTube.url Destination: D:\Temp\Destination\5 Free Software You'll Wish You Knew Earlier! 2019 - YouTube.url".
WARNING: audiolengthCLEAN.csv already exits. Renaming destination file.
What if: Performing the operation "Rename File" on target "Item: D:\Temp\Destination\audiolengthCLEAN.csv Destination: D:\Temp\Destination\audiolengthCLEAN_2.csv".
...
#>
Update as per your function question.
Function Sync-FileArchive
{
[CmdletBinding(SupportsShouldProcess)]
[Alias('sfa')]
Param
(
[Parameter(Mandatory = $true, Position = 0)]
[string]$SourceFiles,
[Parameter(Mandatory = $true, Position = 1)]
[string]$Destination
)
$Counter = 0
Get-ChildItem -Path $SourceFiles |
ForEach{
Try
{
If(Test-Path -Path $Destination\$PSItem)
{
$Counter++
Write-Warning -Message "$($PSItem.Name) already exits. Renaming destination file."
Rename-Item -Path $Destination\$PSItem -NewName "$($PSItem.Basename)_$Counter$($PSitem.Extension)" -WhatIf
}
Else
{
Write-Verbose -Message "$($PSItem.Name) does not exist. Copying file." -Verbose
Copy-Item -Path $PSItem.FullName -Destination $Destination
}
}
Catch {$PSItem.Exception.Message}
}
}
# Example1 - Remove the -WhatIf to fully execute.
Sync-FileArchive -SourceFiles 'D:\Temp\Source' -Destination 'D:\Temp\Destination' -WhatIf
# Example2
sfa 'D:\Temp\Source' 'D:\Temp\Destination' -WhatIf
I am using PowerShell copy files to multiple locations, then do a check after copy done, I want to send a message on failure if one or more files does not exist on one of the destinations.
$SRCDIR1 = "C:\temp\Copy\00_S"
$DST = "C:\temp\Copy\01_D","C:\temp\Copy\02_D","C:\temp\Copy\03_D"
$File_list = Get-ChildItem -Path $SRCDIR1\*.xml
$DST | %{ Copy-Item $SRCDIR1\*.xml -Destination $_ }
Foreach ($item in $File_list) {
If (Test-Path $DST ) {
Write-Host $item exists in $DST
}
else {
Write-Host $item DOES NOT exists in $DST
}
}
It works when all files are in all destinations, but if I delete different files from different destinations testing "write-host if not exist", it still "write-host" everything exists.
On failure, i want it "write-host" which file doest not exist on which destination separately. How can I modify the code?
Update made it working. has to be loop in loop....
$FileList = Get-ChildItem -Path $SRCDIR1\*.xml | Select -ExpandProperty Name
Foreach ($item in $FileList){
$DST |
% {if (Test-Path ($_ + "\" + "$item")){
write-host $item exist in $_ -ForegroundColor Green
}else{
write-host $item does not exist in $_ -ForegroundColor Red
}
}
}
Your $DST is an Array of Strings and this is the "problem", as Test-Path will return one boolean value for each path in that array:
PS> $DST = "C:\temp\Copy\01_D","C:\temp\Copy\02_D","C:\temp\Copy\03_D"
PS> Test-Path $DST
True
True
False
Which means if(Test-Path $DST) will be the same as if(#($true, $true, $false)). Let's see how they are evaluated:
PS> if ($false) {"HA!"} else {"Ney"}
Ney
PS> if (#($false, $false)) {"HA!"} else {"Ney"}
HA!
As you can see, if ($variable) evaluates to $true, when $variable is any non-null value which is not $false, so even #($false, $false, $false) will evaluate to $true.
Don't check $DST, instead check for $item's existence:
if (Test-Path $item) {
Write-Host $item exists in $DST
}