如何在PowerShell PSDrive“function:”上向函数对象添加属性?

时间:2022-04-05 19:41:13

I've attempted using the $function:foo value and get-item function:foo. All attempts succeed in modifying the temporary function object, but the additional property is missing when reassigned to the stored function (either through $function:foo = ... or set-item function:foo ...).

我尝试使用$ function:foo值和get-item函数:foo。所有尝试都成功修改了临时函数对象,但在重新分配给存储函数时(通过$ function:foo = ...或set-item function:foo ...),缺少附加属性。

Here are the results of my attempts (all fail):

以下是我尝试的结果(全部失败):

Setup

$=>function foo { "foo" }
$=>$f = $function:foo
$=>$f = $f | add-member noteproperty bar BARvalue -pass
$=>$f | gm b*

   TypeName: System.Management.Automation.ScriptBlock

Name                 MemberType   Definition
----                 ----------   ----------
bar                  NoteProperty System.String bar=BARvalue

#1

$=>set-item function:f  $f -force
$=>$function:foo | gm b*
>

#2

$=>$function:f = $f
$=>$function:foo | gm b*
>

#3

$=>$f = get-item function:foo
$=>$f | gm

   TypeName: System.Management.Automation.FunctionInfo

Name                MemberType   Definition
----                ----------   ----------
Equals              Method       System.Boolean Equals(Object obj)
GetHashCode         Method       System.Int32 GetHashCode()
GetType             Method       System.Type GetType()
ToString            Method       System.String ToString()
PSDrive             NoteProperty System.Management.Automation.PSDriveInfo PSDrive=Function
PSIsContainer       NoteProperty System.Boolean PSIsContainer=False
PSPath              NoteProperty System.String PSPath=Microsoft.PowerShell.Core\Function::foo
PSProvider          NoteProperty System.Management.Automation.ProviderInfo PSProvider=Microsoft....
CmdletBinding       Property     System.Boolean CmdletBinding {get;}
CommandType         Property     System.Management.Automation.CommandTypes CommandType {get;}
DefaultParameterSet Property     System.String DefaultParameterSet {get;}
Definition          Property     System.String Definition {get;}
Description         Property     System.String Description {get;set;}
Module              Property     System.Management.Automation.PSModuleInfo Module {get;}
ModuleName          Property     System.String ModuleName {get;}
Name                Property     System.String Name {get;}
Options             Property     System.Management.Automation.ScopedItemOptions Options {get;set;}
Parameters          Property     System.Collections.Generic.Dictionary`2[[System.String, mscorli...
ParameterSets       Property     System.Collections.ObjectModel.ReadOnlyCollection`1[[System.Man...
ScriptBlock         Property     System.Management.Automation.ScriptBlock ScriptBlock {get;}
Visibility          Property     System.Management.Automation.SessionStateEntryVisibility Visibi...

$=>$f = $f | add-member noteproperty bar barValue -pass
$=>$f | gm b*

   TypeName: System.Management.Automation.FunctionInfo

Name                MemberType   Definition
----                ----------   ----------
bar                 NoteProperty System.String bar=barValue

$=>set-item function:foo $f
$=>$function:foo | gm b*
>

Not sure what I'm doing wrong. It seems like the properties are being stripped out when reassigned. Is that correct? the defined behavior? I haven't seen any documentation saying that FunctionInfo objects or ScriptBlocks are treated unusually. Is this some esoteric corner of the language?

不知道我做错了什么。看起来这些属性在重新分配时被剥离了。那是对的吗?定义的行为?我没有看到任何文档说FunctionInfo对象或ScriptBlocks被异常处理。这是语言的一些深奥的角落吗?

1 个解决方案

#1


My first thought is when you are attaching this property to an object, you are attaching it to a specific instance of that object. When your variable losses the reference to that object, any knowledge of that new property is lost.

我首先想到的是,当您将此属性附加到对象时,您将它附加到该对象的特定实例。当您的变量丢失对该对象的引用时,对该新属性的任何知识都将丢失。

My guess is the next time you get that item, you are creating a new FunctionInfo object with foo's properties (as stored in the function provider).

我的猜测是下次你得到那个项目时,你正在用foo的属性创建一个新的FunctionInfo对象(存储在函数提供程序中)。

When you call Get-Item or Get-ChildItem, it returns object references to the .NET types that represent the underlying items. Those items do not exist in memory indefinitely (imagine a FileInfo object for every file on every local drive and every mapped drive living in memory.. ouch). Since PowerShell is creating a new instance every time you call Get-Item, you are getting the basic FunctionInfo object.

当您调用Get-Item或Get-ChildItem时,它返回对表示基础项的.NET类型的对象引用。这些项目无限期地存在于内存中(假设每个本地驱动器上的每个文件都有一个FileInfo对象,并且每个映射的驱动器都存在于内存中... ouch)。由于PowerShell每次调用Get-Item时都会创建一个新实例,因此您将获得基本的FunctionInfo对象。

If you want to add a property to all items of a particular type, you can with PowerShell's extensible type system. You can create a custom .ps1xml file and load that into a PowerShell session that can add a property to every instance of a type. Some great examples on the PowerShell Team Blog are here -> Hate Add-Member and Leveraging the PowerShell Type Extensions to Get Documentation.

如果要将属性添加到特定类型的所有项目,可以使用PowerShell的可扩展类型系统。您可以创建自定义.ps1xml文件并将其加载到PowerShell会话中,该会话可以向某个类型的每个实例添加属性。 PowerShell团队博客上的一些很好的示例在这里 - >仇恨添加成员并利用PowerShell类型扩展来获取文档。

EDIT (addressing comment): I understand what you are trying to do, but the failure is due to the new property being "grafted" on to a PSObject wrapper that allows for the on-the-fly addition of properties. The new property is never really part of that FunctionInfo object that you are retrieving from the PSDrive.

EDIT(寻址评论):我理解你要做的是什么,但失败的原因是新属性被“嫁接”到PSObject包装器上,允许动态添加属性。新属性永远不会是您从PSDrive中检索的FunctionInfo对象的一部分。

In addition, the function provider (the function: psdrive), does not have a mechanism for storing that additional property. It knows and works with FunctionInfo objects. When you ask for an item from the Function: PSDrive, the Function provider returns a FunctionInfo object. When you save a function to the Function: PSDrive, the provider can only store values for properties it knows how to handle. One could write a custom provider that would handle new properties from the PSObject wrapper, but that is not part of the default functionality in this provider.

此外,函数提供程序(函数:psdrive)没有用于存储该附加属性的机制。它知道并使用FunctionInfo对象。当您从Function:PSDrive中请求一个项目时,Function提供程序返回一个FunctionInfo对象。将函数保存到Function:PSDrive时,提供程序只能存储它知道如何处理的属性的值。可以编写一个自定义提供程序来处理PSObject包装器中的新属性,但这不是此提供程序中默认功能的一部分。

EDIT #2: Ok, this has been bugging me. I blogged about a workaround.

编辑#2:好的,这一直困扰着我。我在博客上写了一个解决方法。

#1


My first thought is when you are attaching this property to an object, you are attaching it to a specific instance of that object. When your variable losses the reference to that object, any knowledge of that new property is lost.

我首先想到的是,当您将此属性附加到对象时,您将它附加到该对象的特定实例。当您的变量丢失对该对象的引用时,对该新属性的任何知识都将丢失。

My guess is the next time you get that item, you are creating a new FunctionInfo object with foo's properties (as stored in the function provider).

我的猜测是下次你得到那个项目时,你正在用foo的属性创建一个新的FunctionInfo对象(存储在函数提供程序中)。

When you call Get-Item or Get-ChildItem, it returns object references to the .NET types that represent the underlying items. Those items do not exist in memory indefinitely (imagine a FileInfo object for every file on every local drive and every mapped drive living in memory.. ouch). Since PowerShell is creating a new instance every time you call Get-Item, you are getting the basic FunctionInfo object.

当您调用Get-Item或Get-ChildItem时,它返回对表示基础项的.NET类型的对象引用。这些项目无限期地存在于内存中(假设每个本地驱动器上的每个文件都有一个FileInfo对象,并且每个映射的驱动器都存在于内存中... ouch)。由于PowerShell每次调用Get-Item时都会创建一个新实例,因此您将获得基本的FunctionInfo对象。

If you want to add a property to all items of a particular type, you can with PowerShell's extensible type system. You can create a custom .ps1xml file and load that into a PowerShell session that can add a property to every instance of a type. Some great examples on the PowerShell Team Blog are here -> Hate Add-Member and Leveraging the PowerShell Type Extensions to Get Documentation.

如果要将属性添加到特定类型的所有项目,可以使用PowerShell的可扩展类型系统。您可以创建自定义.ps1xml文件并将其加载到PowerShell会话中,该会话可以向某个类型的每个实例添加属性。 PowerShell团队博客上的一些很好的示例在这里 - >仇恨添加成员并利用PowerShell类型扩展来获取文档。

EDIT (addressing comment): I understand what you are trying to do, but the failure is due to the new property being "grafted" on to a PSObject wrapper that allows for the on-the-fly addition of properties. The new property is never really part of that FunctionInfo object that you are retrieving from the PSDrive.

EDIT(寻址评论):我理解你要做的是什么,但失败的原因是新属性被“嫁接”到PSObject包装器上,允许动态添加属性。新属性永远不会是您从PSDrive中检索的FunctionInfo对象的一部分。

In addition, the function provider (the function: psdrive), does not have a mechanism for storing that additional property. It knows and works with FunctionInfo objects. When you ask for an item from the Function: PSDrive, the Function provider returns a FunctionInfo object. When you save a function to the Function: PSDrive, the provider can only store values for properties it knows how to handle. One could write a custom provider that would handle new properties from the PSObject wrapper, but that is not part of the default functionality in this provider.

此外,函数提供程序(函数:psdrive)没有用于存储该附加属性的机制。它知道并使用FunctionInfo对象。当您从Function:PSDrive中请求一个项目时,Function提供程序返回一个FunctionInfo对象。将函数保存到Function:PSDrive时,提供程序只能存储它知道如何处理的属性的值。可以编写一个自定义提供程序来处理PSObject包装器中的新属性,但这不是此提供程序中默认功能的一部分。

EDIT #2: Ok, this has been bugging me. I blogged about a workaround.

编辑#2:好的,这一直困扰着我。我在博客上写了一个解决方法。