I've written a Powershell cmdlet in C# which returns details about one or more employees' direct manager(s) using a home-grown API. The cmdlet is supposed to return a collection of one or more objects of type Associate. The problem I'm having is that the output type of the Cmdlet is not consistent.
I designed the Cmdlet such that if you already have a collection of Associate objects, you can pass that in via the pipeline. Otherwise, you need to pass in one or more userIds under the -Identity parameter.
Here is the behavior I'm seeing, though in terms of the Cmdlet output:
- If I pass in one or more userIds with the -Identity parameter, I get the expected collection of Associate:
> $test1 = Get-Manager -Identity 'user1','user2'
> $test1.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True List`1 System.Object
PS H:> $test1 | select displayName
displayName
-----------
John Doe
Jane Lee
- If I pass in one or more Associate objects by explicitly using the -Assoc parameter, I also get the expected collection
> $folks = Get-Associate 'brunomik','abcdef2'
> $test2 = Get-Manager -Assoc $folks
> $test2.getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True List`1 System.Object
PS H:> $test2 | Select displayName
displayName
-----------
John Doe
Jane Lee
- However, if I pass in a collection of Associate objects using the pipeline, I seem to get back a multidimensional array!:
> $test3 = $folks | Get-Manager
> $test3.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
> $test3 | select displayName
displayName
-----------
># Select-Object can't find a property called displayName
># But if I run GetType() on the first element of the collection:
> $test3[0].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True List`1 System.Object
># It appears to be yet another collection!
># Now, if I run Select-Object on that first element of $test3, I do see the data:
> $test3[0] | Select displayName
displayName
-----------
John Doe
Jane Lee
Here is the source code for the Cmdlet:
[Cmdlet(VerbsCommon.Get, "Manager", DefaultParameterSetName = @"DefaultParamSet")]
[OutputType(typeof(Associate))]
public class GetManager : Cmdlet
{
private Associate[] assoc = null;
private string[] identity = null;
private bool assocSet = false;
private bool identitySet = false;
//The Assoc parameter supports the pipeline and accepts one or more objects of type Associate
[Parameter(ParameterSetName = @"DefaultParamSet",
ValueFromPipeline = true,
HelpMessage = "An Associate object as returned by the "Get-Associate" cmdlet. Cannot be used with the "Identity" parameter")]
public Associate[] Assoc
{
get
{
return assoc;
}
set
{
assoc = value;
assocSet = true;
}
}
//The Identity parameter accepts one or more string expressions (user IDs)
[Parameter(HelpMessage = "An Associate user Id. Not to be used with the "Assoc" parameter")]
public string[] Identity
{
get
{
return identity;
}
set
{
identitySet = true;
identity = value;
}
}
//This will contain the output of the Cmdlet
private List<Associate> Result = new List<Associate>();
protected override void BeginProcessing()
{
base.BeginProcessing();
}
protected override void ProcessRecord()
{
base.ProcessRecord();
BuildOutputObject();
WriteObject(Result);
}
//Builds the Cmdlet Output object
private void BuildOutputObject()
{
List<Associate> Subordinates = new List<Associate>();
//Only the Assoc or Identity parameter may be set; not both.
if (!(assocSet ^ identitySet))
{
throw new ApplicationException($"Either the {nameof(Assoc).InQuotes()} or the {nameof(Identity).InQuotes()} parameter must be set, but not both.");
}
//If Assoc is set, we already have an array of Associate objects, so we'll simply define Subordinates by calling Assoc.ToList()
if (assocSet)
{
Subordinates = Assoc.ToList();
}
//Otherwise, we'll need to create an associate object from each userID passed in with the "Identity" parameter. The MyApi.GetAssociates() method returns a list of Associate objects.
else
{
Subordinates = MyApi.GetAssociates(Identity);
if (!MyApi.ValidResponse)
{
throw new ApplicationException($"No associate under the identifiers {string.Join(",",Identity).InQuotes()} could be found.");
}
}
//Now, to build the output object:
Subordinates.ForEach(p => Result.Add(p.GetManager()));
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…