在PowerShell cmdlet中导航父子关系

时间:2012-08-03 23:56:31

标签: c# powershell pipeline cmdlet

假设我的对象具有这样的父子关系:

public class Node
{
   public string Name { get; set; }
   public string Type { get; set; }
   public Node Parent { get; set; }
}

现在,我想创建一个支持如下语法的cmdlet:

Get-Node | where {$_.Type -eq "SomeType" -and $_.Parent.Name -eq "SomeName" }

这里,Parent属性需要以某种方式引用管道中的另一个对象。在PowerShell中甚至可以这样吗?如果没有,有哪些替代方案?

[编辑] 如果我像这样使用上面的类:

var root = new Node
{
    Name = "root",
    Type = "root",
    Parent = null
};
var nodeA = new Node
{
    Name = "A",
    Type = "node",
    Parent = root
}
WriteObject(root);
WriteObject(nodeA);

然后加载模块并尝试以下命令:

Get-MyNode | where {$_.Parent.Name = "root"}

我收到此错误:

Property 'Name' cannot be found on this object; make sure it exists and is settable.
At line:1 char:31
+ Get-MyNode | where {$_.Parent. <<<< Name = "root"}
    + CategoryInfo          : InvalidOperation: (Name:String) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

我希望Parent属性像真正的Node对象一样引用管道中的另一个对象。

[编辑]此错误是由类定义中缺少的public关键字引起的。添加关键字修复了问题并使示例正常工作。

1 个答案:

答案 0 :(得分:2)

我希望您的Get-Node cmdlet会返回一个完全填充的对象图。以下是使用XML的类似示例:

$xml = [xml]@'
<?xml version="1.0" encoding="ISO-8859-1"?>
 <bookstore>
     <book>
       <title lang="eng">Harry Potter</title>
       <price>29.99</price>
     </book>
     <book>
       <title lang="eng">Learning XML</title>
       <price>39.95</price>
     </book>
 </bookstore> 
'@

$xml.SelectNodes('//*') | Where {$_.ParentNode.Name -eq 'book'}

在回答有关访问管道中另一个对象的问题时,将中间变量创建为可在以后引用的管道的一部分并不罕见:

Get-Process | Foreach {$processName = $_.Name; $_.Modules} | 
              Foreach {"$processName loaded $($_.ModuleName)"}

在这种情况下,我将System.Diagnostics.Process对象的名称存储起来,然后在管道中传播完全不同的类型,即System.Diagnostic.ProcessModule。然后我可以将隐藏的进程名称与模块的名称组合以生成我想要的输出。

上述方法适用于教学目的,但不是真正的规范PowerShell。这是在PowerShell中执行此操作的更典型方法:

Get-Process | Select Name -Exp Modules | Foreach {"$($_.Name) loaded $($_.ModuleName)"}

在这种情况下,我们采用了Process的名称并将其投影到每个ProcessModule对象中。 请注意,当您尝试枚举其模块集合时,某些进程将生成错误。