【问题标题】:Is my understanding of PSPropertyAdapter correct?我对 PSPropertyAdapter 的理解正确吗?
【发布时间】:2021-09-01 16:36:29
【问题描述】:

我正在编写一个二进制 PowerShell 模块,该模块与 ActiveDirectory 模块非常相似,它将具有许多 cmdlet 和类型,这些 cmdlet 和类型可能会返回比默认属性集更多的属性 - 而这些属性 (100+) 取决于用户请求。就像 AD 模块一样,我想返回具有所请求属性的类型,以便它对用户透明,即不是一个包含许多他们没有请求的空属性的巨大类。

我正在查看 ActiveDirectory 模块的文档,我注意到像 ADUserADComputer 这样的东西最终是从 ADPropertyCollection 继承的.

这并没有真正解释 PowerShell 如何灵活地呈现 AD 类型,即

(Get-ADUser -Identity some.user).GetType()
(Get-ADUser -Identity some.user -Properties *).GetType()
# Both return a type of ADUser, despite have drastically different amounts of properties.

直到我查看了 AD 模块的 Types ps1xml 文件,它呈现如下内容:

<Types>
    <!-- other types -->
     <Type>
        <Name>Microsoft.ActiveDirectory.Management.ADUser</Name>
        <TypeAdapter>
            <TypeName>Microsoft.ActiveDirectory.Management.ADEntityAdapter</TypeName>
        </TypeAdapter>
    </Type>
</Types>

所以我猜“magic”属性的来源是ADEntityAdapter,它继承自抽象类PSPropertyAdapter

我现在的问题是我不确定如何实现它,并且没有任何易于搜索的示例来实现它。我很欣赏它是一个真正的边缘案例。我在下面的一个非常粗略的实现中做了一个小的尝试,请忽略任何代码错误——我当然不会真正编写下面的代码。我只是想至少尝试表明我已经考虑过这一点。

using System.Collections.Generic;

namespace Sample
{
    public class PropertyCollection
    {
        public string Id { get; set; }

        public Dictionary<string, object> Attributes { get; set; }

        public PropertyCollection()
        {
            this.Id = "SampleID";
            this.Attributes = new Dictionary<string, object>();

            for (var i = 0; i < 10; i++)
            {
                this.Attributes.Add("KeyAttribute" + i, i);
            }

            for (var i = 10; i < 100; i++)
            {
                this.Attributes.Add("OtherAttribute" + i, i);
            }
        }
    }
}
namespace Sample
{
    public class ReturnedClass : PropertyCollection
    {
        public string SomeName { get; set; }

        public ReturnedClass() : base() { }
    }
}
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;

namespace Sample
{
    public class PropertyEntityAdapter : PSPropertyAdapter
    {
        public override Collection<PSAdaptedProperty> GetProperties(object baseObject)
        {
            PropertyCollection pc = baseObject as PropertyCollection;
            if (pc == null)
            {
                throw new Exception("Some Exception");
            }
            Collection<PSAdaptedProperty> collection = new Collection<PSAdaptedProperty>();
            foreach (string name in pc.Attributes.Keys)
            {
                collection.Add(new PSAdaptedProperty(name, null));
            }
            return collection;
        }

        public override PSAdaptedProperty GetProperty(object baseObject, string propertyName)
        {
            PropertyCollection pc = baseObject as PropertyCollection;
            if (pc.Attributes.TryGetValue(propertyName, out object pcValue))
            {
                return new PSAdaptedProperty(propertyName, pcValue);
            }
            throw new Exception("Prop not found");
        }

        public override string GetPropertyTypeName(PSAdaptedProperty adaptedProperty)
        {
            if (adaptedProperty == null)
            {
                throw new Exception("prop null");
            }
            PropertyCollection pc = adaptedProperty.BaseObject as PropertyCollection;
            if (pc == null)
            {
                throw new Exception("not found");
            }
            if (pc.Attributes.TryGetValue(adaptedProperty.Name, out object pcValue))
            {
                return pcValue.GetType().FullName;
            }
            return pc.GetType().FullName;
        }

        public override object GetPropertyValue(PSAdaptedProperty adaptedProperty)
        {
            if (adaptedProperty?.BaseObject == null || adaptedProperty?.Name == null)
            {
                throw new Exception("prop null");
            }
            PropertyCollection pc = adaptedProperty.BaseObject as PropertyCollection;
            if (pc == null)
            {
                throw new Exception("not found");
            }
            if (pc.Attributes.TryGetValue(adaptedProperty.Name, out object pcValue))
            {
                return pcValue;
            }
            return null;
        }

        public override bool IsGettable(PSAdaptedProperty adaptedProperty)
        {
            if (adaptedProperty == null)
            {
                throw new Exception("prop null");
            }
            PropertyCollection pc = adaptedProperty.BaseObject as PropertyCollection;
            if (pc == null)
            {
                throw new Exception("not found");
            }
            if (pc.Attributes.ContainsKey(adaptedProperty.Name))
            {
                return true;
            }
            return false;
        }

        public override bool IsSettable(PSAdaptedProperty adaptedProperty)
        {
            return false;
        }

        public override void SetPropertyValue(PSAdaptedProperty adaptedProperty, object value)
        {
            throw new System.NotImplementedException();
        }
    }
}

** 我故意没有为 Set* 方法添加任何代码以减少此处所需的代码。如果上面看起来是对的,那么我确定我知道该怎么做。

以前有人做过吗?有没有非常基本的例子?我是在正确的道路上,还是我误解了?提前致谢。

【问题讨论】:

  • 是否值得添加 activedirectory 标签来吸引合适的受众?
  • 嗨@SantiagoSquarzon,是的,我想过,但这只是对所需行为的说明,而不是对 ActiveDirectory 本身的查询。我想将此通用保留为二进制 cmdlet。我可以反编译模块 dll,但这些代码库通常令人困惑(我不知道我在做什么),我希望有人能说我的基本理解是正确的,建议修复或链接到我的示例或许有机会了解。 :-)

标签: c# powershell


【解决方案1】:

如果有人来找这个并且有兴趣做类似的事情,那么我的问题实际上或多或少是如何完成的。我希望它对从事二进制模块工作的其他人有用或感兴趣。

我确实发现了一些通过GetProperty 方法传递的附加属性,这些属性似乎来自 PowerShell 引擎本身,即PSComputerName,因此无需在此处抛出错误,只需返回带有空对象的新 PSAdaptedProperty

public override PSAdaptedProperty GetProperty(object baseObject, string propertyName)
{
    PropertyCollection pc = baseObject as PropertyCollection;
    if (pc.Attributes.TryGetValue(propertyName, out object pcValue))
    {
        return new PSAdaptedProperty(propertyName, pcValue);
    }
    return new PSAdaptedProperty(propertyName, null);
}

然后您可以通过模块清单或在控制台中使用Update-Typedata -PrependPath path_to_file\file_name 加载类型数据。

返回字典中的所有属性,以显示它们是类的完整属性。

【讨论】:

    猜你喜欢
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多