2020-03-24 11:08:37 -07:00
// Copyright (c) Microsoft Corporation.
2018-02-13 09:23:53 -08:00
// Licensed under the MIT License.
2016-03-30 14:20:52 -07:00
using System.Runtime.Serialization ;
2019-04-30 10:25:11 +05:00
2016-08-02 10:08:57 -07:00
using Dbg = System . Management . Automation . Diagnostics ;
2016-03-30 14:20:52 -07:00
namespace System.Management.Automation
{
/// <summary>
2017-01-16 13:31:14 -08:00
/// Defines a data structure used to represent the status of an ongoing operation at a point in time.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <remarks>
/// ProgressRecords are passed to <see cref="System.Management.Automation.Cmdlet.WriteProgress(ProgressRecord)"/>,
/// which, according to user preference, forwards that information on to the host for rendering to the user.
/// </remarks>
/// <seealso cref="System.Management.Automation.Cmdlet.WriteProgress(ProgressRecord)"/>
[DataContract()]
2016-07-29 13:02:49 -07:00
public
2016-03-30 14:20:52 -07:00
class ProgressRecord
{
#region Public API
/// <summary>
/// Initializes a new instance of the ProgressRecord class and defines the activity Id,
/// activity description, and status description.
/// </summary>
/// <param name="activityId">
/// A unique numeric key that identifies the activity to which this record applies.
/// </param>
/// <param name="activity">
/// A description of the activity for which progress is being reported.
/// </param>
/// <param name="statusDescription">
/// A description of the status of the activity.
/// </param>
public
ProgressRecord ( int activityId , string activity , string statusDescription )
{
if ( activityId < 0 )
{
// negative Ids are reserved to indicate "no id" for parent Ids.
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentOutOfRangeException ( nameof ( activityId ), activityId , ProgressRecordStrings . ArgMayNotBeNegative , "activityId" );
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2018-12-31 15:10:15 +05:00
if ( string . IsNullOrEmpty ( activity ))
2016-03-30 14:20:52 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentException ( nameof ( activity ), ProgressRecordStrings . ArgMayNotBeNullOrEmpty , "activity" );
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2018-12-31 15:10:15 +05:00
if ( string . IsNullOrEmpty ( statusDescription ))
2016-03-30 14:20:52 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentException ( nameof ( activity ), ProgressRecordStrings . ArgMayNotBeNullOrEmpty , "statusDescription" );
2016-03-30 14:20:52 -07:00
}
2017-11-09 09:13:34 -08:00
this . id = activityId ;
this . activity = activity ;
this . status = statusDescription ;
2016-03-30 14:20:52 -07:00
}
2023-06-20 01:20:08 +02:00
/// <summary>
/// Initializes a new instance of the ProgressRecord class and defines the activity Id.
/// </summary>
/// <param name="activityId">
/// A unique numeric key that identifies the activity to which this record applies.
/// </param>
public
ProgressRecord ( int activityId )
{
if ( activityId < 0 )
{
// negative Ids are reserved to indicate "no id" for parent Ids.
throw PSTraceSource . NewArgumentOutOfRangeException ( nameof ( activityId ), activityId , ProgressRecordStrings . ArgMayNotBeNegative , "activityId" );
}
this . id = activityId ;
}
2016-03-30 14:20:52 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// Cloning constructor (all fields are value types - can treat our implementation of cloning as "deep" copy)
2016-03-30 14:20:52 -07:00
/// </summary>
/// <param name="other"></param>
internal ProgressRecord ( ProgressRecord other )
{
2017-11-09 09:13:34 -08:00
this . activity = other . activity ;
this . currentOperation = other . currentOperation ;
this . id = other . id ;
this . parentId = other . parentId ;
this . percent = other . percent ;
this . secondsRemaining = other . secondsRemaining ;
this . status = other . status ;
this . type = other . type ;
2016-03-30 14:20:52 -07:00
}
/// <summary>
/// Gets the Id of the activity to which this record corresponds. Used as a 'key' for the
/// linking of subordinate activities.
/// </summary>
public
int
ActivityId
{
get
{
2017-11-09 09:13:34 -08:00
return id ;
2016-03-30 14:20:52 -07:00
}
}
/// <summary>
/// Gets and sets the Id of the activity for which this record is a subordinate.
/// </summary>
/// <remarks>
/// Used to allow chaining of progress records (such as when one installation invokes a child installation). UI:
/// normally not directly visible except as already displayed as its own activity. Usually a sub-activity will be
/// positioned below and to the right of its parent.
2017-01-16 13:31:14 -08:00
///
2016-03-30 14:20:52 -07:00
/// A negative value (the default) indicates that the activity is not a subordinate.
2017-01-16 13:31:14 -08:00
///
2016-03-30 14:20:52 -07:00
/// May not be the same as ActivityId.
2017-01-16 13:31:14 -08:00
/// <!--NTRAID#Windows OS Bugs-1161549 the default value for this should be picked up from a variable in the
/// shell so that a script can set that variable, and have all subsequent calls to WriteProgress (the API) be
2016-03-30 14:20:52 -07:00
/// subordinate to the "current parent id".-->
/// </remarks>
2016-07-29 13:02:49 -07:00
public
int
2016-03-30 14:20:52 -07:00
ParentActivityId
{
get
{
2017-11-09 09:13:34 -08:00
return parentId ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
set
{
if ( value == ActivityId )
{
throw PSTraceSource . NewArgumentException ( "value" , ProgressRecordStrings . ParentActivityIdCantBeActivityId );
}
2018-12-23 22:20:06 -08:00
2017-11-09 09:13:34 -08:00
parentId = value ;
2016-03-30 14:20:52 -07:00
}
}
/// <summary>
/// Gets and sets the description of the activity for which progress is being reported.
/// </summary>
/// <remarks>
/// States the overall intent of whats being accomplished, such as "Recursively removing item c:\temp." Typically
/// displayed in conjunction with a progress bar.
/// </remarks>
2016-07-29 13:02:49 -07:00
public
string
2016-03-30 14:20:52 -07:00
Activity
{
get
{
2017-11-09 09:13:34 -08:00
return activity ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
set
{
2018-12-31 15:10:15 +05:00
if ( string . IsNullOrEmpty ( value ))
2016-03-30 14:20:52 -07:00
{
throw PSTraceSource . NewArgumentException ( "value" , ProgressRecordStrings . ArgMayNotBeNullOrEmpty , "value" );
}
2018-12-23 22:20:06 -08:00
2017-11-09 09:13:34 -08:00
activity = value ;
2016-03-30 14:20:52 -07:00
}
}
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
/// <summary>
/// Gets and sets the current status of the operation, e.g., "35 of 50 items Copied." or "95% completed." or "100 files purged."
/// </summary>
2016-07-29 13:02:49 -07:00
public
string
2016-03-30 14:20:52 -07:00
StatusDescription
{
get
{
2017-11-09 09:13:34 -08:00
return status ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
set
{
2018-12-31 15:10:15 +05:00
if ( string . IsNullOrEmpty ( value ))
2016-03-30 14:20:52 -07:00
{
throw PSTraceSource . NewArgumentException ( "value" , ProgressRecordStrings . ArgMayNotBeNullOrEmpty , "value" );
}
2018-12-23 22:20:06 -08:00
2017-11-09 09:13:34 -08:00
status = value ;
2016-03-30 14:20:52 -07:00
}
}
/// <summary>
/// Gets and sets the current operation of the many required to accomplish the activity (such as "copying foo.txt"). Normally displayed
2017-01-16 13:31:14 -08:00
/// below its associated progress bar, e.g., "deleting file foo.bar"
2016-03-30 14:20:52 -07:00
/// Set to null or empty in the case a sub-activity will be used to show the current operation.
/// </summary>
public
2016-07-29 13:02:49 -07:00
string
2016-03-30 14:20:52 -07:00
CurrentOperation
{
get
{
2017-11-09 09:13:34 -08:00
return currentOperation ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
set
{
// null or empty string is allowed
2017-11-09 09:13:34 -08:00
currentOperation = value ;
2016-03-30 14:20:52 -07:00
}
}
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
/// <summary>
/// Gets and sets the estimate of the percentage of total work for the activity that is completed. Typically displayed as a progress bar.
/// Set to a negative value to indicate that the percentage completed should not be displayed.
/// </summary>
public
int
PercentComplete
{
get
{
2017-11-09 09:13:34 -08:00
return percent ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
set
{
// negative values are allowed
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
if ( value > 100 )
{
2016-07-29 13:02:49 -07:00
throw
2016-03-30 14:20:52 -07:00
PSTraceSource . NewArgumentOutOfRangeException (
"value" , value , ProgressRecordStrings . PercentMayNotBeMoreThan100 , "PercentComplete" );
}
2017-11-09 09:13:34 -08:00
percent = value ;
2016-03-30 14:20:52 -07:00
}
}
/// <summary>
/// Gets and sets the estimate of time remaining until this activity is completed. This can be based upon a measurement of time since
/// started and the percent complete or another approach deemed appropriate by the caller.
///
/// Normally displayed beside the progress bar, as "N seconds remaining."
/// </summary>
2023-01-03 12:12:42 -08:00
/// <remarks>
2016-03-30 14:20:52 -07:00
/// A value less than 0 means "don't display a time remaining."
/// </remarks>
public
int
SecondsRemaining
{
get
{
2017-11-09 09:13:34 -08:00
return secondsRemaining ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
set
{
// negative values are allowed
2017-11-09 09:13:34 -08:00
secondsRemaining = value ;
2016-03-30 14:20:52 -07:00
}
}
/// <summary>
/// Gets and sets the type of record represented by this instance.
/// </summary>
public
ProgressRecordType
RecordType
{
get
{
2017-11-09 09:13:34 -08:00
return type ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
set
{
if ( value != ProgressRecordType . Completed && value != ProgressRecordType . Processing )
{
throw PSTraceSource . NewArgumentException ( "value" );
}
2017-11-09 09:13:34 -08:00
type = value ;
2016-03-30 14:20:52 -07:00
}
}
/// <summary>
/// Overrides <see cref="System.Object.ToString"/>
/// </summary>
/// <returns>
/// "parent = a id = b act = c stat = d cur = e pct = f sec = g type = h" where
/// a, b, c, d, e, f, and g are the values of ParentActivityId, ActivityId, Activity, StatusDescription,
/// CurrentOperation, PercentComplete, SecondsRemaining and RecordType properties.
/// </returns>
2016-07-29 13:02:49 -07:00
public override
string
2016-03-30 14:20:52 -07:00
ToString ()
{
2016-07-29 13:02:49 -07:00
return
2018-12-31 20:44:16 +05:00
string . Format (
2016-03-30 14:20:52 -07:00
System . Globalization . CultureInfo . CurrentCulture ,
"parent = {0} id = {1} act = {2} stat = {3} cur = {4} pct = {5} sec = {6} type = {7}" ,
2017-11-09 09:13:34 -08:00
parentId ,
id ,
activity ,
status ,
currentOperation ,
percent ,
secondsRemaining ,
type );
2016-03-30 14:20:52 -07:00
}
#endregion
#region Helper methods
2016-08-02 19:00:50 -07:00
internal static int? GetSecondsRemaining ( DateTime startTime , double percentageComplete )
2016-03-30 14:20:52 -07:00
{
Dbg . Assert ( percentageComplete >= 0.0 , "Caller should verify percentageComplete >= 0.0" );
Dbg . Assert ( percentageComplete <= 1.0 , "Caller should verify percentageComplete <= 1.0" );
Dbg . Assert (
2016-07-29 13:02:49 -07:00
startTime . Kind == DateTimeKind . Utc ,
2016-03-30 14:20:52 -07:00
"DateTime arithmetic should always be done in utc mode [to avoid problems when some operands are calculated right before and right after switching to /from a daylight saving time" );
if (( percentageComplete < 0.00001 ) || double . IsNaN ( percentageComplete ))
{
return null ;
}
DateTime now = DateTime . UtcNow ;
Dbg . Assert ( startTime <= now , "Caller should pass a valid startTime" );
TimeSpan elapsedTime = now - startTime ;
TimeSpan totalTime ;
try
{
totalTime = TimeSpan . FromMilliseconds ( elapsedTime . TotalMilliseconds / percentageComplete );
}
catch ( OverflowException )
{
return null ;
}
catch ( ArgumentException )
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
TimeSpan remainingTime = totalTime - elapsedTime ;
2016-07-29 13:02:49 -07:00
return ( int )( remainingTime . TotalSeconds );
2016-03-30 14:20:52 -07:00
}
/// <summary>
/// Returns percentage complete when it is impossible to predict how long an operation might take.
/// The percentage complete will slowly converge toward 100%.
/// At the <paramref name="expectedDuration"/> the percentage complete will be 90%.
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="startTime">When did the operation start.</param>
/// <param name="expectedDuration">How long does the operation usually take.</param>
2018-12-25 21:43:03 +05:00
/// <returns>Estimated percentage complete of the operation (always between 0 and 99% - never returns 100%).</returns>
2016-03-30 14:20:52 -07:00
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when
/// 1) <paramref name="startTime"/> is in the future
/// 2) <paramref name="expectedDuration"/> is negative or zero
/// </exception>
2016-08-02 19:00:50 -07:00
internal static int GetPercentageComplete ( DateTime startTime , TimeSpan expectedDuration )
2016-03-30 14:20:52 -07:00
{
DateTime now = DateTime . UtcNow ;
Dbg . Assert (
2016-07-29 13:02:49 -07:00
startTime . Kind == DateTimeKind . Utc ,
2016-03-30 14:20:52 -07:00
"DateTime arithmetic should always be done in utc mode [to avoid problems when some operands are calculated right before and right after switching to /from a daylight saving time" );
2023-05-25 19:12:42 +02:00
ArgumentOutOfRangeException . ThrowIfGreaterThan ( now , startTime );
ArgumentOutOfRangeException . ThrowIfLessThanOrEqual ( TimeSpan . Zero , expectedDuration );
2016-03-30 14:20:52 -07:00
/*
2017-01-16 13:31:14 -08:00
* According to the spec of Checkpoint-Computer
2016-03-30 14:20:52 -07:00
* (http://cmdletdesigner/SpecViewer/Default.aspx?Project=PowerShell&Cmdlet=Checkpoint-Computer)
* we have percentage remaining = f(t) where
* f(inf) = 0%
* f(0) = 100%
* f(90) = <something small> = 10%
2017-01-16 13:31:14 -08:00
*
2016-03-30 14:20:52 -07:00
* The spec talks about exponential decay, but function based on 1/x seems better:
2017-01-16 13:31:14 -08:00
* f(t) = a / (T + b)
*
2016-03-30 14:20:52 -07:00
* This by definition has f(inf) = 0, so we have to find a and b for the last 2 cases:
2017-01-16 13:31:14 -08:00
* E1: f(0) = a / (0 + b) = 100
2016-03-30 14:20:52 -07:00
* E2: f(T = 90) = a / (T + b) = 10
2017-01-16 13:31:14 -08:00
*
2016-03-30 14:20:52 -07:00
* From E1 we have a = 100 * b, which we can use in E2:
* (100 * b) / (T + b) = 10
* 100 * b = 10 * T + 10 * b
* 90 * b = 10 * T
* b = T / 9
2017-01-16 13:31:14 -08:00
*
2016-03-30 14:20:52 -07:00
* Some sample values (for T=90):
2017-01-16 13:31:14 -08:00
* t | %rem
2016-03-30 14:20:52 -07:00
* -----------
* 0 | 100.0%
* 5 | 66.6%
* 10 | 50.0%
* 30 | 25.0%
* 70 | 12.5%
* 90 | 10.0%
* 300 | 3.2%
* 600 | 1.6%
* 3600| 0.2%
*/
TimeSpan timeElapsed = now - startTime ;
double b = expectedDuration . TotalSeconds / 9.0 ;
double a = 100.0 * b ;
double percentageRemaining = a / ( timeElapsed . TotalSeconds + b );
double percentageCompleted = 100.0 - percentageRemaining ;
return ( int ) Math . Floor ( percentageCompleted );
}
#endregion
2017-11-09 09:13:34 -08:00
#region DO NOT REMOVE OR RENAME THESE FIELDS - it will break remoting compatibility with Windows PowerShell
2016-03-30 14:20:52 -07:00
[DataMemberAttribute()]
2020-11-05 03:36:23 +00:00
private readonly int id ;
2016-03-30 14:20:52 -07:00
[DataMemberAttribute()]
2017-11-09 09:13:34 -08:00
private int parentId = - 1 ;
2016-03-30 14:20:52 -07:00
[DataMemberAttribute()]
2017-11-09 09:13:34 -08:00
private string activity ;
2016-03-30 14:20:52 -07:00
[DataMemberAttribute()]
2017-11-09 09:13:34 -08:00
private string status ;
2016-03-30 14:20:52 -07:00
[DataMemberAttribute()]
2017-11-09 09:13:34 -08:00
private string currentOperation ;
2016-03-30 14:20:52 -07:00
[DataMemberAttribute()]
2017-11-09 09:13:34 -08:00
private int percent = - 1 ;
2016-03-30 14:20:52 -07:00
[DataMemberAttribute()]
2017-11-09 09:13:34 -08:00
private int secondsRemaining = - 1 ;
[DataMemberAttribute()]
private ProgressRecordType type = ProgressRecordType . Processing ;
#endregion
2016-03-30 14:20:52 -07:00
#region Serialization / deserialization for remoting
/// <summary>
2017-01-16 13:31:14 -08:00
/// Creates a ProgressRecord object from a PSObject property bag.
2016-03-30 14:20:52 -07:00
/// PSObject has to be in the format returned by ToPSObjectForRemoting method.
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="progressAsPSObject">PSObject to rehydrate.</param>
2016-03-30 14:20:52 -07:00
/// <returns>
/// ProgressRecord rehydrated from a PSObject property bag
2017-01-16 13:31:14 -08:00
/// </returns>
2016-03-30 14:20:52 -07:00
/// <exception cref="ArgumentNullException">
/// Thrown if the PSObject is null.
/// </exception>
/// <exception cref="System.Management.Automation.Remoting.PSRemotingDataStructureException">
/// Thrown when the PSObject is not in the expected format
/// </exception>
2016-08-02 19:00:50 -07:00
internal static ProgressRecord FromPSObjectForRemoting ( PSObject progressAsPSObject )
2016-03-30 14:20:52 -07:00
{
2020-07-30 16:06:38 -07:00
if ( progressAsPSObject == null )
2016-03-30 14:20:52 -07:00
{
2020-05-19 19:57:52 +01:00
throw PSTraceSource . NewArgumentNullException ( nameof ( progressAsPSObject ));
2016-03-30 14:20:52 -07:00
}
string activity = RemotingDecoder . GetPropertyValue < string >( progressAsPSObject , RemoteDataNameStrings . ProgressRecord_Activity );
int activityId = RemotingDecoder . GetPropertyValue < int >( progressAsPSObject , RemoteDataNameStrings . ProgressRecord_ActivityId );
string statusDescription = RemotingDecoder . GetPropertyValue < string >( progressAsPSObject , RemoteDataNameStrings . ProgressRecord_StatusDescription );
ProgressRecord result = new ProgressRecord ( activityId , activity , statusDescription );
result . CurrentOperation = RemotingDecoder . GetPropertyValue < string >( progressAsPSObject , RemoteDataNameStrings . ProgressRecord_CurrentOperation );
result . ParentActivityId = RemotingDecoder . GetPropertyValue < int >( progressAsPSObject , RemoteDataNameStrings . ProgressRecord_ParentActivityId );
result . PercentComplete = RemotingDecoder . GetPropertyValue < int >( progressAsPSObject , RemoteDataNameStrings . ProgressRecord_PercentComplete );
result . RecordType = RemotingDecoder . GetPropertyValue < ProgressRecordType >( progressAsPSObject , RemoteDataNameStrings . ProgressRecord_Type );
result . SecondsRemaining = RemotingDecoder . GetPropertyValue < int >( progressAsPSObject , RemoteDataNameStrings . ProgressRecord_SecondsRemaining );
return result ;
}
/// <summary>
/// Returns this object as a PSObject property bag
/// that can be used in a remoting protocol data object.
/// </summary>
2018-12-25 21:43:03 +05:00
/// <returns>This object as a PSObject property bag.</returns>
2016-03-30 14:20:52 -07:00
internal PSObject ToPSObjectForRemoting ()
{
2023-06-20 01:20:08 +02:00
// Activity used to be mandatory but that's no longer the case.
// We ensure the string has a value to maintain compatibility with older versions.
string activity = string . IsNullOrEmpty ( Activity ) ? " " : Activity ;
2016-03-30 14:20:52 -07:00
2023-06-20 01:20:08 +02:00
PSObject progressAsPSObject = RemotingEncoder . CreateEmptyPSObject ();
2023-07-12 22:16:57 -05:00
2023-06-20 01:20:08 +02:00
progressAsPSObject . Properties . Add ( new PSNoteProperty ( RemoteDataNameStrings . ProgressRecord_Activity , activity ));
2016-03-30 14:20:52 -07:00
progressAsPSObject . Properties . Add ( new PSNoteProperty ( RemoteDataNameStrings . ProgressRecord_ActivityId , this . ActivityId ));
2016-07-29 13:02:49 -07:00
progressAsPSObject . Properties . Add ( new PSNoteProperty ( RemoteDataNameStrings . ProgressRecord_StatusDescription , this . StatusDescription ));
2016-03-30 14:20:52 -07:00
progressAsPSObject . Properties . Add ( new PSNoteProperty ( RemoteDataNameStrings . ProgressRecord_CurrentOperation , this . CurrentOperation ));
progressAsPSObject . Properties . Add ( new PSNoteProperty ( RemoteDataNameStrings . ProgressRecord_ParentActivityId , this . ParentActivityId ));
progressAsPSObject . Properties . Add ( new PSNoteProperty ( RemoteDataNameStrings . ProgressRecord_PercentComplete , this . PercentComplete ));
progressAsPSObject . Properties . Add ( new PSNoteProperty ( RemoteDataNameStrings . ProgressRecord_Type , this . RecordType ));
progressAsPSObject . Properties . Add ( new PSNoteProperty ( RemoteDataNameStrings . ProgressRecord_SecondsRemaining , this . SecondsRemaining ));
return progressAsPSObject ;
}
#endregion
2018-12-20 22:54:10 -08:00
}
2016-03-30 14:20:52 -07:00
/// <summary>
/// Defines two types of progress record that refer to the beginning (or middle) and end of an operation.
/// </summary>
public
enum ProgressRecordType
{
2023-01-03 12:12:42 -08:00
/// <summary>
2023-07-12 22:16:57 -05:00
/// <para>
2019-01-06 04:40:24 +05:00
/// Operation just started or is not yet complete.
2023-07-12 22:16:57 -05:00
/// </para>
/// <para>
2016-03-30 14:20:52 -07:00
/// A cmdlet can call WriteProgress with ProgressRecordType.Processing
/// as many times as it wishes. However, at the end of the operation,
/// it should call once more with ProgressRecordType.Completed.
2017-01-16 13:31:14 -08:00
///
2016-03-30 14:20:52 -07:00
/// The first time that a host receives a progress record
/// for a given activity, it will typically display a progress
/// indicator for that activity. For each subsequent record
/// of the same Id, the host will update that display.
/// Finally, when the host receives a 'completed' record
/// for that activity, it will remove the progress indicator.
2023-07-12 22:16:57 -05:00
/// </para>
/// </summary>
2016-03-30 14:20:52 -07:00
Processing ,
/// <summary>
2023-07-12 22:16:57 -05:00
/// <para>
2019-01-06 04:40:24 +05:00
/// Operation is complete.
2023-07-12 22:16:57 -05:00
/// </para>
/// <para>
2016-03-30 14:20:52 -07:00
/// If a cmdlet uses WriteProgress, it should use
/// ProgressRecordType.Completed exactly once, in the last call
/// to WriteProgress.
2023-07-12 22:16:57 -05:00
/// </para>
/// </summary>
2016-03-30 14:20:52 -07:00
Completed
}
}