diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs
index f2e4598c1bc..4e83eda905f 100644
--- a/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs
+++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/GetContentCommand.cs
@@ -31,48 +31,20 @@ public class GetContentCommand : ContentCommandBase
public long ReadCount { get; set; } = 1;
///
- /// The number of content items to retrieve. By default this
- /// value is -1 which means read all the content.
+ /// The number of content items to retrieve.
///
[Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateRange(0, long.MaxValue)]
[Alias("First", "Head")]
- public long TotalCount
- {
- get
- {
- return _totalCount;
- }
-
- set
- {
- _totalCount = value;
- _totalCountSpecified = true;
- }
- }
-
- private bool _totalCountSpecified = false;
+ public long TotalCount { get; set; } = -1;
///
/// The number of content items to retrieve from the back of the file.
///
[Parameter(ValueFromPipelineByPropertyName = true)]
+ [ValidateRange(0, int.MaxValue)]
[Alias("Last")]
- public int Tail
- {
- get
- {
- return _backCount;
- }
-
- set
- {
- _backCount = value;
- _tailSpecified = true;
- }
- }
-
- private int _backCount = -1;
- private bool _tailSpecified = false;
+ public int Tail { get; set; } = -1;
///
/// A virtual method for retrieving the dynamic parameters for a cmdlet. Derived cmdlets
@@ -98,15 +70,6 @@ internal override object GetDynamicParameters(CmdletProviderContext context)
#endregion Parameters
- #region parameter data
-
- ///
- /// The number of content items to retrieve.
- ///
- private long _totalCount = -1;
-
- #endregion parameter data
-
#region Command code
///
@@ -116,7 +79,7 @@ protected override void ProcessRecord()
{
// TotalCount and Tail should not be specified at the same time.
// Throw out terminating error if this is the case.
- if (_totalCountSpecified && _tailSpecified)
+ if (TotalCount != -1 && Tail != -1)
{
string errMsg = StringUtil.Format(SessionStateStrings.GetContent_TailAndHeadCannotCoexist, "TotalCount", "Tail");
ErrorRecord error = new(new InvalidOperationException(errMsg), "TailAndHeadCannotCoexist", ErrorCategory.InvalidOperation, null);
@@ -124,7 +87,7 @@ protected override void ProcessRecord()
return;
}
- if (TotalCount == 0)
+ if (TotalCount == 0 || Tail == 0)
{
// Don't read anything
return;
@@ -141,11 +104,9 @@ protected override void ProcessRecord()
{
long countRead = 0;
- Dbg.Diagnostics.Assert(
- holder.Reader != null,
- "All holders should have a reader assigned");
+ Dbg.Diagnostics.Assert(holder.Reader != null, "All holders should have a reader assigned");
- if (_tailSpecified && holder.Reader is not FileSystemContentReaderWriter)
+ if (Tail != -1 && holder.Reader is not FileSystemContentReaderWriter)
{
string errMsg = SessionStateStrings.GetContent_TailNotSupported;
ErrorRecord error = new(new InvalidOperationException(errMsg), "TailNotSupported", ErrorCategory.InvalidOperation, Tail);
@@ -153,11 +114,11 @@ protected override void ProcessRecord()
continue;
}
- // If Tail is negative, we are supposed to read all content out. This is same
+ // If Tail is -1, we are supposed to read all content out. This is same
// as reading forwards. So we read forwards in this case.
// If Tail is positive, we seek the right position. Or, if the seek failed
// because of an unsupported encoding, we scan forward to get the tail content.
- if (Tail >= 0)
+ if (Tail > 0)
{
bool seekSuccess = false;
@@ -197,72 +158,61 @@ protected override void ProcessRecord()
}
}
- if (TotalCount != 0)
+ IList results = null;
+
+ do
{
- IList results = null;
+ long countToRead = ReadCount;
- do
+ // Make sure we only ask for the amount the user wanted
+ // I am using TotalCount - countToRead so that I don't
+ // have to worry about overflow
+ if (TotalCount > 0 && (countToRead == 0 || TotalCount - countToRead < countRead))
{
- long countToRead = ReadCount;
+ countToRead = TotalCount - countRead;
+ }
- // Make sure we only ask for the amount the user wanted
- // I am using TotalCount - countToRead so that I don't
- // have to worry about overflow
+ try
+ {
+ results = holder.Reader.Read(countToRead);
+ }
+ catch (Exception e) // Catch-all OK. 3rd party callout
+ {
+ ProviderInvocationException providerException =
+ new(
+ "ProviderContentReadError",
+ SessionStateStrings.ProviderContentReadError,
+ holder.PathInfo.Provider,
+ holder.PathInfo.Path,
+ e);
- if ((TotalCount > 0) && (countToRead == 0 || (TotalCount - countToRead < countRead)))
- {
- countToRead = TotalCount - countRead;
- }
+ // Log a provider health event
+ MshLog.LogProviderHealthEvent(this.Context, holder.PathInfo.Provider.Name, providerException, Severity.Warning);
+ WriteError(new ErrorRecord(providerException.ErrorRecord, providerException));
- try
- {
- results = holder.Reader.Read(countToRead);
- }
- catch (Exception e) // Catch-all OK. 3rd party callout
+ break;
+ }
+
+ if (results != null && results.Count > 0)
+ {
+ countRead += results.Count;
+ if (ReadCount == 1)
{
- ProviderInvocationException providerException =
- new(
- "ProviderContentReadError",
- SessionStateStrings.ProviderContentReadError,
- holder.PathInfo.Provider,
- holder.PathInfo.Path,
- e);
-
- // Log a provider health event
- MshLog.LogProviderHealthEvent(
- this.Context,
- holder.PathInfo.Provider.Name,
- providerException,
- Severity.Warning);
-
- WriteError(new ErrorRecord(
- providerException.ErrorRecord,
- providerException));
-
- break;
+ // Write out the content as a single object
+ WriteContentObject(results[0], countRead, holder.PathInfo, currentContext);
}
-
- if (results != null && results.Count > 0)
+ else
{
- countRead += results.Count;
- if (ReadCount == 1)
- {
- // Write out the content as a single object
- WriteContentObject(results[0], countRead, holder.PathInfo, currentContext);
- }
- else
- {
- // Write out the content as an array of objects
- WriteContentObject(results, countRead, holder.PathInfo, currentContext);
- }
+ // Write out the content as an array of objects
+ WriteContentObject(results, countRead, holder.PathInfo, currentContext);
}
- } while (results != null && results.Count > 0 && ((TotalCount < 0) || countRead < TotalCount));
- }
+ }
+ } while (results != null && results.Count > 0 && (TotalCount == -1 || countRead < TotalCount));
}
}
finally
{
- // close all the content readers
+ // Close all the content readers
CloseContent(contentStreams, false);
@@ -284,7 +234,7 @@ private bool ScanForwardsForTail(in ContentHolder holder, CmdletProviderContext
{
var fsReader = holder.Reader as FileSystemContentReaderWriter;
Dbg.Diagnostics.Assert(fsReader != null, "Tail is only supported for FileSystemContentReaderWriter");
- var tailResultQueue = new Queue