From e2fe191818f4242334d7eea5b63905ab0ca8b6ff Mon Sep 17 00:00:00 2001 From: "Mathias R. Jessen" Date: Wed, 20 May 2020 01:02:23 +0200 Subject: [PATCH 01/13] Add [timespan]-accepting parameter set to Start-Sleep Re: https://github.com/PowerShell/PowerShell/issues/12305 --- .../commands/utility/StartSleepCommand.cs | 11 +++++++++++ .../Start-Sleep.Tests.ps1 | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index a57d635f3eb..c02bcce50dd 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -55,6 +55,13 @@ public void Dispose() [Alias("ms")] public int Milliseconds { get; set; } + /// + /// Allows sleep time to be specified as a TimeSpan + /// + [Parameter(Position = 0, Mandatory = true, ParameterSetName = "FromTimeSpan", ValueFromPipeline = true)] + [Alias("ts")] + public TimeSpan Duration { get; set; } + #endregion #region methods @@ -104,6 +111,10 @@ protected override void ProcessRecord() case "Milliseconds": sleepTime = Milliseconds; break; + + case "FromTimeSpan": + sleepTime = (int)Math.Floor(Duration.Duration().TotalMilliseconds); + break; default: Dbg.Diagnostics.Assert(false, "Only one of the specified parameter sets should be called."); diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Start-Sleep.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Start-Sleep.Tests.ps1 index 59ac3e9903d..6d2ce313bc0 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Start-Sleep.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Start-Sleep.Tests.ps1 @@ -23,6 +23,15 @@ Describe "Start-Sleep DRT Unit Tests" -Tags "CI" { $watch.ElapsedMilliseconds | Should -BeLessThan $maxTime } + It "Should work properly when sleeping with a [TimeSpan]" { + $duration = [timespan]::FromMilliseconds(1500) + $watch = [System.Diagnostics.Stopwatch]::StartNew() + Start-Sleep -Duration $duration + $watch.Stop() + $watch.ElapsedMilliseconds | Should -BeGreaterThan $minTime + $watch.ElapsedMilliseconds | Should -BeLessThan $maxTime + } + It "Should work properly when sleeping with ms alias" { $watch = [System.Diagnostics.Stopwatch]::StartNew() Start-Sleep -ms 1500 @@ -38,6 +47,15 @@ Describe "Start-Sleep DRT Unit Tests" -Tags "CI" { $watch.ElapsedMilliseconds | Should -BeGreaterThan $minTime $watch.ElapsedMilliseconds | Should -BeLessThan $maxTime } + + It "Should work properly when sleeping without parameters from [timespan]" { + $duration = [timespan]::FromMilliseconds(1500) + $watch = [System.Diagnostics.Stopwatch]::StartNew() + Start-Sleep $duration + $watch.Stop() + $watch.ElapsedMilliseconds | Should -BeGreaterThan $minTime + $watch.ElapsedMilliseconds | Should -BeLessThan $maxTime + } } Describe "Start-Sleep" -Tags "CI" { From d7262978f799282b0c95e4f25aee45181786cf66 Mon Sep 17 00:00:00 2001 From: IISResetMe Date: Thu, 24 Sep 2020 01:04:06 +0200 Subject: [PATCH 02/13] ValidateTimespanRange --- .../engine/Attributes.cs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/System.Management.Automation/engine/Attributes.cs b/src/System.Management.Automation/engine/Attributes.cs index a0411c78df7..1b0c53a5f36 100644 --- a/src/System.Management.Automation/engine/Attributes.cs +++ b/src/System.Management.Automation/engine/Attributes.cs @@ -1088,6 +1088,12 @@ public ValidateRangeAttribute(ValidateRangeKind kind) : base() private static void ValidateRange(object element, ValidateRangeKind rangeKind) { + if(element is TimeSpan ts) + { + ValidateTimeSpanRange(ts, rangeKind); + return; + } + Type commonType = GetCommonType(typeof(int), element.GetType()); if (commonType == null) { @@ -1212,6 +1218,59 @@ private void ValidateRange(object element) } } + private void ValidateTimeSpanRange(TimeSpan element, ValidateRangeKind rangeKind) + { + TimeSpan zero = TimeSpan.Zero; + + switch (rangeKind) + { + case ValidateRangeKind.Positive: + if (zero.CompareTo(element) >= 0) + { + throw new ValidationMetadataException( + "ValidateRangePositiveFailure", + null, + Metadata.ValidateRangePositiveFailure, + element.ToString()); + } + + break; + case ValidateRangeKind.NonNegative: + if (zero.CompareTo(element) > 0) + { + throw new ValidationMetadataException( + "ValidateRangeNonNegativeFailure", + null, + Metadata.ValidateRangeNonNegativeFailure, + element.ToString()); + } + + break; + case ValidateRangeKind.Negative: + if (zero.CompareTo(element) <= 0) + { + throw new ValidationMetadataException( + "ValidateRangeNegativeFailure", + null, + Metadata.ValidateRangeNegativeFailure, + element.ToString()); + } + + break; + case ValidateRangeKind.NonPositive: + if (zero.CompareTo(element) < 0) + { + throw new ValidationMetadataException( + "ValidateRangeNonPositiveFailure", + null, + Metadata.ValidateRangeNonPositiveFailure, + element.ToString()); + } + + break; + } + } + private static Type GetCommonType(Type minType, Type maxType) { Type resultType = null; From 9b7f802339581ae86d5c796697d7b0dc15df0bb3 Mon Sep 17 00:00:00 2001 From: IISResetMe Date: Thu, 24 Sep 2020 01:04:46 +0200 Subject: [PATCH 03/13] Start-Sleep: validate non-negative timespan arg --- .../commands/utility/StartSleepCommand.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index c02bcce50dd..285bf2727e5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -59,6 +59,7 @@ public void Dispose() /// Allows sleep time to be specified as a TimeSpan /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "FromTimeSpan", ValueFromPipeline = true)] + [ValidateRange(ValidateRangeKind.NonNegative)] [Alias("ts")] public TimeSpan Duration { get; set; } @@ -113,7 +114,7 @@ protected override void ProcessRecord() break; case "FromTimeSpan": - sleepTime = (int)Math.Floor(Duration.Duration().TotalMilliseconds); + sleepTime = (int)Math.Floor(Duration.TotalMilliseconds); break; default: From 105d7fce110aaa1b2235314645285bbb36daf7ea Mon Sep 17 00:00:00 2001 From: IISResetMe Date: Fri, 1 Oct 2021 21:40:10 +0200 Subject: [PATCH 04/13] Fix ValidateTimespanRange --- src/System.Management.Automation/engine/Attributes.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/Attributes.cs b/src/System.Management.Automation/engine/Attributes.cs index 1b0c53a5f36..9965824a927 100644 --- a/src/System.Management.Automation/engine/Attributes.cs +++ b/src/System.Management.Automation/engine/Attributes.cs @@ -1088,7 +1088,7 @@ public ValidateRangeAttribute(ValidateRangeKind kind) : base() private static void ValidateRange(object element, ValidateRangeKind rangeKind) { - if(element is TimeSpan ts) + if (element is TimeSpan ts) { ValidateTimeSpanRange(ts, rangeKind); return; @@ -1218,7 +1218,7 @@ private void ValidateRange(object element) } } - private void ValidateTimeSpanRange(TimeSpan element, ValidateRangeKind rangeKind) + private static void ValidateTimeSpanRange(TimeSpan element, ValidateRangeKind rangeKind) { TimeSpan zero = TimeSpan.Zero; From d98806f3a3d2e8afdf0603ec2880e26b2d8d8e87 Mon Sep 17 00:00:00 2001 From: "Mathias R. Jessen" Date: Sun, 28 Nov 2021 15:05:31 +0100 Subject: [PATCH 05/13] Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs Co-authored-by: Dongbo Wang --- .../commands/utility/StartSleepCommand.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index 285bf2727e5..d71b9dc9971 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -58,7 +58,8 @@ public void Dispose() /// /// Allows sleep time to be specified as a TimeSpan /// - [Parameter(Position = 0, Mandatory = true, ParameterSetName = "FromTimeSpan", ValueFromPipeline = true)] + [Parameter(Position = 0, Mandatory = true, ParameterSetName = "FromTimeSpan", ValueFromPipeline = true, + ValueFromPipelineByPropertyName = true)] [ValidateRange(ValidateRangeKind.NonNegative)] [Alias("ts")] public TimeSpan Duration { get; set; } From 3af5de7b2e2cc6afaf170a37cb1ee78b91ab0245 Mon Sep 17 00:00:00 2001 From: IISResetMe Date: Fri, 31 Dec 2021 01:26:17 +0100 Subject: [PATCH 06/13] Add error message to Start-Sleep on receiving exceedingly long timespan duration --- .../commands/utility/StartSleepCommand.cs | 12 ++ .../resources/StartSleepStrings.resx | 123 ++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index d71b9dc9971..03fcd6572b5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -115,6 +115,18 @@ protected override void ProcessRecord() break; case "FromTimeSpan": + if (Duration.TotalMilliseconds > int.MaxValue) + { + PSArgumentException argumentException = PSTraceSource.NewArgumentException( + nameof(Duration), + StartSleepStrings.MaximumDurationExceeded); + + ThrowTerminatingError( + new ErrorRecord( + argumentException, + "MaximumDurationExceeded", + ErrorCategory.InvalidArgument, null)); + } sleepTime = (int)Math.Floor(Duration.TotalMilliseconds); break; diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx new file mode 100644 index 00000000000..0d64637b41a --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Provided TimeSpan exceeds maximum sleep duration + + \ No newline at end of file From 088ca2eb363889afda31f3ee9eaefd10dc58e45b Mon Sep 17 00:00:00 2001 From: IISResetMe Date: Thu, 13 Jan 2022 22:15:04 +0100 Subject: [PATCH 07/13] Update Start-Sleep error string --- .../commands/utility/StartSleepCommand.cs | 4 +++- .../resources/StartSleepStrings.resx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index 03fcd6572b5..1c0f179a9dd 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -119,7 +119,9 @@ protected override void ProcessRecord() { PSArgumentException argumentException = PSTraceSource.NewArgumentException( nameof(Duration), - StartSleepStrings.MaximumDurationExceeded); + StartSleepStrings.MaximumDurationExceeded, + TimeSpan.FromMilliseconds(int.MaxValue), + Duration); ThrowTerminatingError( new ErrorRecord( diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx index 0d64637b41a..53b99529f28 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx @@ -118,6 +118,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Provided TimeSpan exceeds maximum sleep duration + The Duration parameter value must not exceed '{0}', provided value was '{1}'. \ No newline at end of file From ddc2f26ea5f0c3378f50df1e027920061bd7ef77 Mon Sep 17 00:00:00 2001 From: IISResetMe Date: Thu, 13 Jan 2022 22:35:14 +0100 Subject: [PATCH 08/13] Add Start-Sleep [timespan] validation tests --- .../Microsoft.PowerShell.Utility/Start-Sleep.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Start-Sleep.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Start-Sleep.Tests.ps1 index 6d2ce313bc0..e4899ce5439 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Start-Sleep.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Start-Sleep.Tests.ps1 @@ -56,6 +56,12 @@ Describe "Start-Sleep DRT Unit Tests" -Tags "CI" { $watch.ElapsedMilliseconds | Should -BeGreaterThan $minTime $watch.ElapsedMilliseconds | Should -BeLessThan $maxTime } + + It "Should validate [timespan] parameter values" { + { Start-Sleep -Duration '0:00:01' } | Should -Not -Throw + { Start-Sleep -Duration '-0:00:01' } | Should -Throw -ErrorId 'ParameterArgumentValidationError,Microsoft.PowerShell.Commands.StartSleepCommand' + { Start-Sleep -Duration '30.0:00:00' } | Should -Throw -ErrorId 'MaximumDurationExceeded,Microsoft.PowerShell.Commands.StartSleepCommand' + } } Describe "Start-Sleep" -Tags "CI" { From 685d5015e92d68f218ae3eb454729832949bb405 Mon Sep 17 00:00:00 2001 From: IISResetMe Date: Thu, 13 Jan 2022 22:43:17 +0100 Subject: [PATCH 09/13] StartSleepStrings.resx - Add trailing newline --- .../resources/StartSleepStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx index 53b99529f28..beb92398ee0 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx @@ -120,4 +120,4 @@ The Duration parameter value must not exceed '{0}', provided value was '{1}'. - \ No newline at end of file + From 4767568f20c48d0c072e0b2f034a9785f84e1a16 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 13 Jan 2022 14:25:00 -0800 Subject: [PATCH 10/13] Minor update to the resource string --- .../resources/StartSleepStrings.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx index beb92398ee0..32804b9e21b 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/StartSleepStrings.resx @@ -118,6 +118,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - The Duration parameter value must not exceed '{0}', provided value was '{1}'. + The '-Duration' parameter value must not exceed '{0}', provided value was '{1}'. From 8efdf97e730db45f38b8385f98edfe9fcb202df1 Mon Sep 17 00:00:00 2001 From: "Mathias R. Jessen" Date: Fri, 14 Jan 2022 00:11:55 +0100 Subject: [PATCH 11/13] Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs Co-authored-by: Dongbo Wang --- .../commands/utility/StartSleepCommand.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index 1c0f179a9dd..32bc0bceafa 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -127,7 +127,8 @@ protected override void ProcessRecord() new ErrorRecord( argumentException, "MaximumDurationExceeded", - ErrorCategory.InvalidArgument, null)); + ErrorCategory.InvalidArgument, + targetObject: null)); } sleepTime = (int)Math.Floor(Duration.TotalMilliseconds); break; From 1c8f69eb1d29db81788d29453cb28994ec3857e0 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 13 Jan 2022 15:14:38 -0800 Subject: [PATCH 12/13] Address another CodeFactor issue. --- .../commands/utility/StartSleepCommand.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index 32bc0bceafa..99468bf8794 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -130,6 +130,7 @@ protected override void ProcessRecord() ErrorCategory.InvalidArgument, targetObject: null)); } + sleepTime = (int)Math.Floor(Duration.TotalMilliseconds); break; From e560dce6b345193cd73776b950628b0ba85c53fd Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 13 Jan 2022 15:17:16 -0800 Subject: [PATCH 13/13] Add a period as required by CodeFactor --- .../commands/utility/StartSleepCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs index 99468bf8794..a1524e5ed4f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/StartSleepCommand.cs @@ -56,7 +56,7 @@ public void Dispose() public int Milliseconds { get; set; } /// - /// Allows sleep time to be specified as a TimeSpan + /// Allows sleep time to be specified as a TimeSpan. /// [Parameter(Position = 0, Mandatory = true, ParameterSetName = "FromTimeSpan", ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]