Arrrg!我正在用PowerShell写一个简单的脚本,我觉得这是一个愚蠢的问题.我正在调用一个调用存储过程的sql命令,结果我把它放在一个数组.结果看起来像这样:
Status ProcessStartTime ProcessEndTime
------ ---------------- --------------
Expired May 22 2010 8:31PM May 22 2010 8:32PM
Run Code Online (Sandbox Code Playgroud)
我想做的是if($s.Contains("Expired"))报告失败.简单...?:(问题我遇到的是它看起来像没有加载Contains方法,因为我得到这样的错误:
方法调用失败,因为[System.Object []]不包含名为"Contains"的方法.在行:1 char:12 + $ s.Contains <<<<("Expired")+ 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."
}
Run Code Online (Sandbox Code Playgroud)
简单地说,$ s是一个.NET数组(您可以使用@()确保),并且您正在尝试调用此.NET类型中不存在的方法(包含).
解决问题的最简单方法是使用PowerShell的-contains运算符,它具有直接处理数组和进行不区分大小写比较的优点,例如:
if ($s -contains 'expired') { ... }
Run Code Online (Sandbox Code Playgroud)
你看到方法是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()
…
Run Code Online (Sandbox Code Playgroud)
我通常做的是确保我不看待展开的成员,首先尝试"$ s.GetType().Name"来看看我正在处理什么.在你的情况下,它显然是数组,因为你初始化它像"$ s = @(Invo"(@ =它是一个数组).
要确定数组是否包含项,可以使用-contains运算符:
(9) C:\ -» @(1,2,3) -contains 1
True
Run Code Online (Sandbox Code Playgroud)
我认为你有一个字符串数组,所以你可以使用字符串文字,如:
(10) C:\ -» @("Stuff","you've","got","might have","Expired") -contains "Expired"
True
Run Code Online (Sandbox Code Playgroud)
但是如果过期不是完全匹配(你正在寻找一个包含过期的元素,比如"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
Run Code Online (Sandbox Code Playgroud)
在这种情况下,只有一个匹配,因此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
Run Code Online (Sandbox Code Playgroud)
现在它是一个数组.
幸运的是,字符串和数组都有一个length属性:
(39) C:\ -» $xs.Length
2
(40) C:\ -» "Bob".Length
3
Run Code Online (Sandbox Code Playgroud)
因此,您可以检查包含"已过期"的结果的长度,以查看是否有过期的:
(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.
Run Code Online (Sandbox Code Playgroud)
(也许有人有更好的方法来检查一个集合是否包含一个满足某些谓词的项目(如LINQ的Any)?)