Arrrg! Я сталкиваюсь с тем, что я чувствую, немая проблема с простым сценарием, который я пишу в powershell. Я вызываю команду sql, которая называет сохраненный proc с результатами, я поместил его массив. Результаты выглядят примерно так:
Status ProcessStartTime ProcessEndTime
------ ---------------- --------------
Expired May 22 2010 8:31PM May 22 2010 8:32PM
То, что я пытаюсь сделать, if($s.Contains("Expired"))
, отчет перестал работать. Простой...?:( Проблема, с которой я сталкиваюсь, она похожа, Содержит метод, не загружается, поскольку я получаю ошибку как это:
Вызов метода перестал работать потому что [Система. Объект []] не содержит метод под названием, 'Содержит'. В line:1 char:12 + $s. Содержит <<<<("Истекший") + CategoryInfo: InvalidOperation: (Contains: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."
}
Причина, по которой вы видите метод Get-Members, заключается в том, что powershell пытается быть полезным и разворачивает коллекцию. Если у вас есть массив с несколькими типами элементов, он покажет вам члены для каждого типа (например, если вы 'ls' (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().Name" сначала, чтобы увидеть, с чем я имею дело. В вашем случае это явно массив, поскольку вы инициализировали его как "$s = @(Invo" (@ = это массив. )
Чтобы узнать, содержит ли массив элемент, вы можете использовать оператор -contains:
(9) C:\ -» @(1,2,3) -contains 1
True
Я думаю, у вас массив строк, поэтому вы можете использовать строковый литерал, например:
(10) C:\ -» @("Stuff","you've","got","might have","Expired") -contains "Expired"
True
Но если expired не является точным совпадением (вы искали элемент, содержащий expired, например "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 развернул его в строку. Придурок. Однако если совпадений больше одного, то:
(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
Теперь это массив.
К счастью, и строка, и массив имеют свойство длины:
(39) C:\ -» $xs.Length
2
(40) C:\ -» "Bob".Length
3
Поэтому вы можете проверить длину результатов, содержащих "Expired", чтобы узнать, есть ли среди них просроченные:
(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.
(может быть, у кого-то есть лучший способ проверить, содержит ли коллекция элемент, удовлетворяющий какому-то предикату (как Any в LINQ)?)
Проще говоря, $ s - это массив .NET (вы используете @ ()
, чтобы гарантировать это), и вы пытаетесь вызвать метод (Содержит) которого нет в этом типе .NET.
Самый простой способ решить вашу проблему - использовать оператор PowerShell -contains
, который имеет преимущества работы с массивами напрямую и сравнения без учета регистра, например:
if ($s -contains 'expired') { ... }