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."
}
答案 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)?)