为什么我不能从我的数组中调用Contains方法?

时间:2010-05-28 17:08:54

标签: powershell

Arrrg!我正在用PowerShell写一个简单的脚本,我觉得这是一个愚蠢的问题。我正在调用一个调用存储过程的sql命令,结果我把它放在一个数组。结果看起来像这样:

Status                                       ProcessStartTime                            ProcessEndTime                             
------                                       ----------------                            --------------                             
Expired                                      May 22 2010  8:31PM                         May 22 2010  8:32PM

我要做的是if($s.Contains("Expired")),报告失败了。简单...? :(问题我遇到的是它看起来像没有加载Contains方法,因为我得到这样的错误:

方法调用失败,因为[System.Object []]不包含名为“Contains”的方法。在行:1个字符:12 + $ s.Contains<<<< ( “过期”)     + CategoryInfo:InvalidOperation :(包含:String)[],RuntimeException     + FullyQualifiedErrorId:MethodNotFound

那么,我该怎么做才能阻止PowerShell将其展开为字符串?下面的实际ps脚本 -

$s = @(Invoke-Sqlcmd -Query "USE DB
       GO
       exec Monitor_TEST_ps 'EXPORT_RUN',NULL,20" `
       -ServerInstance testdb002\testdb_002
      )

if ($s.Contains("Expired"))   
{
    Write-Host "Expired found, FAIL."
}
else 
{
    Write-Host "Not found, OK." 
}

2 个答案:

答案 0 :(得分:7)

简单地说,$ s是一个.NET数组(您使用@()确保)并且您正在尝试调用此.NET类型中不存在的方法(包含)。

解决问题的最简单方法是使用PowerShell的-contains运算符,该运算符具有直接处理数组并进行不区分大小写的优点,例如:

if ($s -contains 'expired') { ... }

答案 1 :(得分:5)

你看到方法的原因是Get-Members是powershell试图提供帮助并展开集合。如果你有一个包含多种类型项目的数组,它会显示每种类型的成员(比如你是否'(Get-ChildItem),并且你所在的目录中有FileInfos和DirectoryInfos,你管道ls | gm ,它将向您显示FileInfos的成员以及DirectoryInfos的另一组成员:

(7) C:\ -» ls


    Directory: C:\


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         5/28/2010   8:19 AM            .hg
d----         5/13/2010   3:37 PM            Build
…
-a---         4/22/2010  11:21 AM       2603 TODO.org


(8) C:\ -» ls | gm


   TypeName: System.IO.DirectoryInfo

Name                      MemberType     Definition
----                      ----------     ----------
Mode                      CodeProperty   System.String Mode{get=Mode;}
Create                    Method         System.Void Create(System.Security.AccessControl.Direct...
…

   TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
Mode                      CodeProperty   System.String Mode{get=Mode;}
AppendText                Method         System.IO.StreamWriter AppendText()
…

我通常做的是,为了确保我不看待展开的成员,请先尝试“$ s.GetType()。姓名”,先看看我在处理什么。在你的情况下,它显然是数组,因为你初始化它像“$ s = @(Invo”(@ =它是一个数组)。

要查明数组是否包含项目,可以使用-contains运算符:

(9) C:\ -» @(1,2,3) -contains 1
True

我认为你有一个字符串数组,所以你可以使用字符串文字,比如:

(10) C:\ -» @("Stuff","you've","got","might have","Expired") -contains "Expired"
True

但是如果过期不是完全匹配(你正在寻找一个包含过期的元素,比如“Connection Expired 1/1/2010”),你需要找到匹配并检查计数,我想:

(23) C:\ -» @("Stuff","you've","got","might have","Connection Expired 1/1/2010") -contains "Expired"
False
(24) C:\ -» @("Stuff","you've","got","might have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")}
Connection Expired 1/1/2010
(33) C:\ -» $xs = @("Stuff","you've","got","might have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")}
(34) C:\ -» $xs.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object


(35) C:\ -» $xs
Connection Expired 1/1/2010

在这种情况下,只有一个匹配,所以powershell将其展开为字符串。混蛋。但是,如果匹配次数超过1次:

(36) C:\ -» $xs = @("Stuff","you've","got","might Expired  have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")}
(37) C:\ -» $xs.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array


(38) C:\ -» $xs
might Expired  have
Connection Expired 1/1/2010

现在它是一个数组。

幸运的是,字符串和数组都有一个length属性:

(39) C:\ -» $xs.Length
2
(40) C:\ -» "Bob".Length
3

因此,您可以检查包含“已过期”的结果的长度,以查看是否有任何已过期的内容:

(41) C:\ -» $xs = @("Stuff","you've","got","might Expired  have","Connection Expired 1/1/2010") | ?{$_.Contains("Expired")} 
(42) C:\ -» if ($xs.Length -gt 0) { Write-Host "Whoas, stuff's expired, dog." }
Whoas, shit's expired, dog.

(也许有人有更好的方法来检查一个集合是否包含一个满足某些谓词的项目(如LINQ的Any)?)