public static class IOExtensions { public static void CopyTo(this DirectoryInfo source, DirectoryInfo destination, bool recursive = false, Regex? pattern = null, bool negatePattern = false) { if (destination.FullName.StartsWith(source.FullName)) throw new InvalidOperationException("The target directory must not be inside the source directory"); if (!source.Exists) throw new DirectoryNotFoundException($"Source directory not found: '{source.FullName}'"); if (!destination.Exists) { destination.Create(); } else if (destination.EnumerateFiles("*", SearchOption.AllDirectories).Any()){ throw new IOException("Target directory not empty"); } List exceptions = new List(); foreach(var subInfo in source.EnumerateFileSystemInfos().Where(i => pattern != null ? (negatePattern ? !pattern.IsMatch(i.Name) : pattern.IsMatch(i.Name)) : true)){ try { var destinationPath = Path.Combine(destination.FullName, subInfo.Name); if (subInfo is DirectoryInfo) { if (recursive) { ((DirectoryInfo)subInfo).CopyTo(new DirectoryInfo(destinationPath), recursive); } else { new DirectoryInfo(destinationPath).Create(); } } else if (subInfo is FileInfo) { ((FileInfo)subInfo).CopyTo(destinationPath, false); } } catch (Exception ex) { exceptions.Add(ex); } } if (exceptions.Any()) { throw new AggregateException("Copying files completed with errors", exceptions); } } }