|
6 | 6 | using System.Collections.Generic;
|
7 | 7 | using System.Collections.ObjectModel;
|
8 | 8 | using System.ComponentModel;
|
| 9 | +using System.Diagnostics; |
9 | 10 | using System.Diagnostics.CodeAnalysis;
|
10 | 11 | using System.Globalization;
|
11 | 12 | using System.IO;
|
|
18 | 19 | using System.Security;
|
19 | 20 | using System.Security.AccessControl;
|
20 | 21 | using System.Text;
|
| 22 | +using System.Threading.Tasks; |
21 | 23 | using System.Xml;
|
22 | 24 | using System.Xml.XPath;
|
23 | 25 |
|
@@ -58,6 +60,8 @@ public sealed partial class FileSystemProvider : NavigationCmdletProvider,
|
58 | 60 | // copy script will accommodate the new value.
|
59 | 61 | private const int FILETRANSFERSIZE = 4 * 1024 * 1024;
|
60 | 62 |
|
| 63 | + private const int COPY_FILE_ACTIVITY_ID = 0; |
| 64 | + |
61 | 65 | // The name of the key in an exception's Data dictionary when attempting
|
62 | 66 | // to copy an item onto itself.
|
63 | 67 | private const string SelfCopyDataKey = "SelfCopy";
|
@@ -3548,14 +3552,73 @@ protected override void CopyItem(
|
3548 | 3552 | }
|
3549 | 3553 | else // Copy-Item local
|
3550 | 3554 | {
|
| 3555 | + if (Context != null && Context.ExecutionContext.SessionState.PSVariable.Get(SpecialVariables.ProgressPreferenceVarPath.UserPath).Value is ActionPreference progressPreference && progressPreference == ActionPreference.Continue) |
| 3556 | + { |
| 3557 | + { |
| 3558 | + Task.Run(() => |
| 3559 | + { |
| 3560 | + GetTotalFiles(path, recurse); |
| 3561 | + }); |
| 3562 | + _copyStopwatch.Start(); |
| 3563 | + } |
| 3564 | + } |
| 3565 | + |
3551 | 3566 | CopyItemLocalOrToSession(path, destinationPath, recurse, Force, null);
|
| 3567 | + if (_totalFiles > 0) |
| 3568 | + { |
| 3569 | + _copyStopwatch.Stop(); |
| 3570 | + var progress = new ProgressRecord(COPY_FILE_ACTIVITY_ID, " ", " "); |
| 3571 | + progress.RecordType = ProgressRecordType.Completed; |
| 3572 | + WriteProgress(progress); |
| 3573 | + } |
3552 | 3574 | }
|
3553 | 3575 | }
|
3554 | 3576 |
|
3555 | 3577 | _excludeMatcher.Clear();
|
3556 | 3578 | _excludeMatcher = null;
|
3557 | 3579 | }
|
3558 | 3580 |
|
| 3581 | + private void GetTotalFiles(string path, bool recurse) |
| 3582 | + { |
| 3583 | + bool isContainer = IsItemContainer(path); |
| 3584 | + |
| 3585 | + try |
| 3586 | + { |
| 3587 | + if (isContainer) |
| 3588 | + { |
| 3589 | + var enumOptions = new EnumerationOptions() |
| 3590 | + { |
| 3591 | + IgnoreInaccessible = true, |
| 3592 | + AttributesToSkip = 0, |
| 3593 | + RecurseSubdirectories = recurse |
| 3594 | + }; |
| 3595 | + |
| 3596 | + var directory = new DirectoryInfo(path); |
| 3597 | + foreach (var file in directory.EnumerateFiles("*", enumOptions)) |
| 3598 | + { |
| 3599 | + if (!SessionStateUtilities.MatchesAnyWildcardPattern(file.Name, _excludeMatcher, defaultValue: false)) |
| 3600 | + { |
| 3601 | + _totalFiles++; |
| 3602 | + _totalBytes += file.Length; |
| 3603 | + } |
| 3604 | + } |
| 3605 | + } |
| 3606 | + else |
| 3607 | + { |
| 3608 | + var file = new FileInfo(path); |
| 3609 | + if (!SessionStateUtilities.MatchesAnyWildcardPattern(file.Name, _excludeMatcher, defaultValue: false)) |
| 3610 | + { |
| 3611 | + _totalFiles++; |
| 3612 | + _totalBytes += file.Length; |
| 3613 | + } |
| 3614 | + } |
| 3615 | + } |
| 3616 | + catch |
| 3617 | + { |
| 3618 | + // ignore exception |
| 3619 | + } |
| 3620 | + } |
| 3621 | + |
3559 | 3622 | private void CopyItemFromRemoteSession(string path, string destinationPath, bool recurse, bool force, PSSession fromSession)
|
3560 | 3623 | {
|
3561 | 3624 | using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create())
|
@@ -3864,6 +3927,22 @@ private void CopyFileInfoItem(FileInfo file, string destinationPath, bool force,
|
3864 | 3927 |
|
3865 | 3928 | FileInfo result = new FileInfo(destinationPath);
|
3866 | 3929 | WriteItemObject(result, destinationPath, false);
|
| 3930 | + |
| 3931 | + if (_totalFiles > 0) |
| 3932 | + { |
| 3933 | + _copiedFiles++; |
| 3934 | + _copiedBytes += file.Length; |
| 3935 | + double speed = (double)(_copiedBytes / 1024 / 1024) / _copyStopwatch.Elapsed.TotalSeconds; |
| 3936 | + var progress = new ProgressRecord( |
| 3937 | + COPY_FILE_ACTIVITY_ID, |
| 3938 | + StringUtil.Format(FileSystemProviderStrings.CopyingLocalFileActivity, _copiedFiles, _totalFiles), |
| 3939 | + StringUtil.Format(FileSystemProviderStrings.CopyingLocalBytesStatus, Utils.DisplayHumanReadableFileSize(_copiedBytes), Utils.DisplayHumanReadableFileSize(_totalBytes), speed) |
| 3940 | + ); |
| 3941 | + var percentComplete = (int)Math.Min(_copiedBytes * 100 / _totalBytes, 100); |
| 3942 | + progress.PercentComplete = percentComplete; |
| 3943 | + progress.RecordType = ProgressRecordType.Processing; |
| 3944 | + WriteProgress(progress); |
| 3945 | + } |
3867 | 3946 | }
|
3868 | 3947 | else
|
3869 | 3948 | {
|
@@ -4788,6 +4867,12 @@ private bool PathIsReservedDeviceName(string destinationPath, string errorId)
|
4788 | 4867 | return pathIsReservedDeviceName;
|
4789 | 4868 | }
|
4790 | 4869 |
|
| 4870 | + private long _totalFiles; |
| 4871 | + private long _totalBytes; |
| 4872 | + private long _copiedFiles; |
| 4873 | + private long _copiedBytes; |
| 4874 | + private readonly Stopwatch _copyStopwatch = new Stopwatch(); |
| 4875 | + |
4791 | 4876 | #endregion CopyItem
|
4792 | 4877 |
|
4793 | 4878 | #endregion ContainerCmdletProvider members
|
|
0 commit comments