我正在尝试优化我的Powershell脚本。 我有很多日志(文本)文件,我需要搜索特定文本条目的内容。 如果找到该条目,我需要使用sql数据库的插入触发脚本。
这就是我现在所拥有的:
$tidnu = (Get-Date -f dd.MM.yyyy)
$Text = "ERROR MESSAGE STACK"
$PathArray = @()
$NodeName = "SomeName"
$Logfil = "SomeLogFile"
Get-ChildItem $Path -Filter "*ORA11*.log" |
Where-Object { $_.Attributes -ne "Directory"} |
ForEach-Object {
If (Get-Content $_.FullName | Select-String -Pattern $Text)
{
$PathArray += $_.FullName
$cmd.commandtext = "INSERT INTO ErrorTabel (Datotid, Nodename, Logfil, ErrorFound) VALUES('{0}','{1}','{2}','{3}')" -f $tidnu, $NodeName, $Logfil, "Yes"
$cmd.ExecuteNonQuery()
}
else
{
$cmd.commandtext = "INSERT INTO ErrorTabel (Datotid, Nodename, ErrorFound) VALUES('{0}','{1}','{2}')" -f $tidnu, $NodeName, "No"
$cmd.ExecuteNonQuery()
}
}
这工作正常,但是当我需要移动到另一个日志文件名时,我只是使用不同的输入再次使用相同的代码。 我想做的是使用一个数组和一个foreach循环,所以我可以在一个数组中指定所有日志文件,如:
$LogArray = @(Log1.log, log2.log, log3.log)
并指定所有Nodenames,如:
$NodeArray = @(Node1, Node2, Node3)
然后创建一个foreach循环,逐个遍历日志文件并插入数据库,每次循环运行时都匹配nodename。
有人可以帮助我实现这一目标吗?我知道应该怎么做,但我无法弄清楚如何编写代码。非常感谢所有帮助。
编辑:
好的,这就是我现在所拥有的,但我不确定它是否正确放在一起。它给了我一些奇怪的结果。
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Data Source=PCDK03918;Initial Catalog=Rman;Integrated Security=SSPI;"
$conn.open()
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.connection = $conn
$tidnu = (Get-Date -f dd.MM.yyyy)
$Path = "C:\RMAN"
$Text = "ERROR MESSAGE STACK"
$nodes = @{
'NodeName1' = 'Node1log1.log', 'Node1log2.log', 'Node1log3.log'
'NodeName2' = 'Node2log1.log', 'Node2log2.log'
}
foreach ($NodeName in $nodes.Keys) {
foreach ($Logfil in $nodes[$NodeName]) {
Get-ChildItem $Path -Filter "*.log" |
ForEach-Object {
If (Get-Content $_.FullName | Select-String -Pattern $Text)
{
$cmd.commandtext = "INSERT INTO Error (Datotid, Nodename, Logfil, Error) VALUES('{0}','{1}','{2}','{3}')" -f $tidnu, $NodeName, $Logfil, "Yes"
$cmd.ExecuteNonQuery()
}
else
{
$cmd.commandtext = "INSERT INTO Error (Datotid, Nodename, Logfil, Error) VALUES('{0}','{1}','{2}','{3}')" -f $tidnu, $NodeName, $Logfil, "No"
$cmd.ExecuteNonQuery()
}
}
}
}
$conn.close()
我创建了$ nodes中提到的日志文件,在文件夹中,并将“ERROR MESSAGE STACK”放入Node1log1.log和Node1log2.log其余的日志文件里面没有“ERROR MESSAGE STACK”。
但是数据库中的结果很奇怪。它说Error = Yes来记录里面没有“ERROR MESSAGE STACK”的文件,并且对于相同的日志文件,某些行向下显示Error = No。加上它插入双行,所有这一切都没有按预期进行。
可能是因为我的
Get-ChildItem $Path -Filter "*.log" |
使用* .log?
是错误的或者我对此完全错了?
再次编辑:
不确定昨天我在想什么,但我相信我现在已经解决了。
Get-ChildItem $Path -Filter "*.log" |
当然不行。
Get-ChildItem $Path -Filter $logfil |
更有意义,现在我的数据库输出看起来更正确。
@Ansgar Wiechers - 感谢您指点我正确的方向。我从中学到了很多东西。答案 0 :(得分:0)
考虑使用散列表:
$logs = @{
'Log1.log' = 'Node1'
'Log2.log' = 'Node2'
'Log3.log' = 'Node3'
}
这样你可以像这样迭代日志:
foreach ($Logfil in $logs.Keys) {
$NodeName = $logs[$Logfil]
...
}
如果每个节点名称有多个日志文件,则反转映射并将日志文件名存储在数组中会更有效:
$nodes = @{
'Node1' = 'Log1.log', 'Log2.log', 'Log3.log'
'Node2' = 'Log4.log', 'Log5.log'
}
然后您可以使用嵌套循环处理日志文件,如下所示:
foreach ($NodeName in $nodes.Keys) {
foreach ($Logfil in $nodes[$NodeName]) {
...
}
}
您应该能够将管道装入任何一个循环而无需进一步修改。
编辑:作为优化,您可以执行类似的操作,以避免在外部循环的每次迭代中出现不必要的fetchin日志:
$logs = Get-ChildItem $Path -Filter '*.log'
foreach ($NodeName in $nodes.Keys) {
$logs | ? { $nodes[$NodeName] -contains $_.Name } | % {
...
}
}