There are two conceivable scenarios (possibly in combination) in which $_.DirectoryName.Replace($Source, $Destination) wouldn't work as intended, and they're not related to Read-Host per se:
$Source has a trailing \ (e.g., C:\Dir1\ instead of C:\Dir1)
- In this case, the
.Replace() call malfunctions at least for files immediately located in the target path, because .DirectoryName values do not have a trailing \ (except for files in a root path such as C:\).
Perhaps more likely: $Source differs in case from the actual target path; e.g., c:\dir1 vs. C:\Dir1
- In this case, the
.Replace() call fails, because this method is case-sensitive, invariably in Windows PowerShell, by default in PowerShell (Core) 7+.
You could fix those problems by using a substring approach instead of trying to replace the start of the path, which bypasses the case-sensitivity problem:
# Remove the input path from the start and prepend the destination path.
Join-Path $Destination $_.DirectoryName.Substring($Source.Length)
Note that, due to how Join-Path works, the path will be synthesized correctly whether or not $Source has a trailing \, so there is no need to trim one manually first. E.g.,
Join-Path c:\dir2 sub, Join-Path c:\dir2 \sub, and Join-Path c:\dir2\ \sub
all yield the same result: c:\dir2\sub.
Alternative approach: Get-ChildItem has a -Name switch that reports matching files as relative path strings, namely relative to the input directory. This allows for a solution that uses PowerShell cmdlets only, without needing to resort to .NET method calls:
# Note the use of -Name
Get-ChildItem -Name -Path $Source -File -Recurse | ForEach-Object {
# Prepend the destination path to the parent path of the relative source path.
$NewDir = Join-Path $Destination (Split-Path -Parent $_)
# Ensure that the destination dir. exists - note the use of -Force
$null = New-Item -Force -Path $NewDir -ItemType Directory
Copy-Item -LiteralPath $_.FullName -Destination $NewDir
Write-Host '.' -NoNewline
#added to validate time stamp in log file is working
Start-Sleep -Seconds 1
"$([DateTime]::Now) copied - '$($_.name)' from '$($_.DirectoryName)' to '$NewDir' Size: $([System.Math]::Round(($($_.Length)/1KB),2))KB" | Add-Content $LogfilePath
}
Note that, as in your own attempt, both solutions above rely on $Source and $Destination to contain full paths.