从cmdlet中的管道获取正确的文件路径

时间:2016-01-02 20:21:18

标签: c# powershell

我写了一些小测试代码:

namespace Test {
  using System;
  using System.Management.Automation;
  using System.Linq;
  using System.IO;

  [Cmdlet(VerbsCommon.Get, "Test", DefaultParameterSetName="Path")]
  public sealed class GetTestCommand : PSCmdlet {
    private String[] _paths;
    private Boolean  _wildcards;

    [Parameter(
      ParameterSetName="Path",
      Mandatory=true,
      Position=0,
      ValueFromPipeline=true,
      ValueFromPipelineByPropertyName=true
    )]
    public String[] Path {
      get { return _paths; }
      set {
        _wildcards = true;
        _paths = value;
      }
    }

    [Parameter(
      ParameterSetName="LiteralPath",
      Mandatory=true,
      Position=0,
      ValueFromPipeline=false,
      ValueFromPipelineByPropertyName=true
    )]
    public String[] LiteralPath {
      get { return _paths; }
      set { _paths = value; }
    }

    protected override void ProcessRecord() {
      ProviderInfo pi;

      (from p in _paths
      select new {
        FilePath = (_wildcards ?
          this.SessionState.Path.GetResolvedProviderPathFromPSPath(p, out pi)[0] :
          this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(p))
      }).ToList()
      .ForEach(i => WriteObject(i.FilePath));
    }
  }
}

这有效:

Get-Test *.txt

这有效:

Get-ChildItem -Filter *.txt | Get-Test

但这不起作用:

Get-ChildItem -Filter *.txt -Recurse | Get-Test

请解释我的错误,如何解决以及我应该阅读什么来深入理解PowerShell的机制。

1 个答案:

答案 0 :(得分:0)

问题是您实际上没有处理从Powershell cmdlet收到的对象。 正确的方法是将接收参数绑定到适当类型的对象,然后访问其属性,即:

[Cmdlet(VerbsCommon.Get, "Test", DefaultParameterSetName = "Path")]
public sealed class GetTestCommand : PSCmdlet
{
    private FileSystemInfo[] _paths;

    [Parameter(
      ParameterSetName = "Path",
      Mandatory = true,
      Position = 0,
      ValueFromPipeline = true,
      ValueFromPipelineByPropertyName = true
    )]
    public FileSystemInfo[] Path
    {
        get { return _paths; }
        set
        {
            _paths = value;
        }
    }


    protected override void ProcessRecord()
    {
        ProviderInfo pi;

        (from p in _paths
         where (p.GetType() != typeof(DirectoryInfo))
         select new
         {
             FilePath = p.FullName}).ToList()
        .ForEach(i => WriteObject(i.FilePath));
    }
}

为了将来参考,您可能需要检查cmdletGet-ChildItem | foreach-object -process { $_.GetType() }收到的类型。 而且,您可以使用Powershell以相同的方式实现您想要的目标,例如:Get-ChildItem | foreach-object -process { $_.FullName }

要获得与纯Powershell完全相同的结果,请尝试:

Get-ChildItem -Recurse | ForEach-Object -Process { if ($_ -isnot [System.IO.DirectoryInfo]) { Write-Host $_.FullName } }