使用PowerShell for-each循环读取XML文件

时间:2018-02-22 11:19:04

标签: xml powershell for-loop

我是PowerShell的新手,我想从多个XML文件中读取每个文件,每个文件都有服务器和服务。这些XML文件的结构各不相同。

<application name="AutoCAD">
    <server name="server1">
        <services>
            <service name="Flexlm Service 1" />
        </services>
    </server>
    <server name="server2">
        <services>
            <service name="Flexlm Service 1" />
        </services>
    </server>
    <server name="server3">
        <services>
            <service name="Flexlm Service 1" />
        </services>
    </server>
</application>

我想阅读每个XML文件并提取服务器名称以及我想要检查它是否正在运行的服务。

我目前的代码几乎正常运行,但它认为每台服务器有3项服务。我尝试了很多东西,但现在卡住了。

$stopped = "ERROR"
$running = "RUNNING"

Get-ChildItem "C:\Users\rjohnso1\Desktop\Reports\XML" -Filter *.xml | 

Foreach-Object {
    $content = [xml](Get-Content $_.FullName)
    $servicesReport = @()
    $computer = $content.application.server.name
    $appName = $content.application.name
    $service = $content.application.server.services.service.name

    foreach ($computers in $computer){
        foreach ($services in $service){
            $serviceName = Invoke-Command -ComputerName $computers -ScriptBlock {Get-WmiObject -Class Win32_Service}
                if ($serviceName.State -eq 'Running'){
                    $row = "$($appName) $($computers) $($services) $($running) "
                }
                elseif ($serviceName.State -eq 'Stopped'){
                    $row = "$($appName) $($services) $($stopped) "
                    $error = "$($appName) $($service) "
                }
        $row += $servicesReport
        Write-Host $row
       }
    }
 }

任何帮助将不胜感激,谢谢。

1 个答案:

答案 0 :(得分:0)

由于您已经在xml文档中的第一个循环之前已经使用所有服务节点填充了$service,因此您将在每个循环中循环遍历所有这些服务节点服务器。将其更改为:

$content = [xml](Get-Content $_.FullName)

$servicesReport = @()
$appName = $content.application.name

foreach ($computer in $content.application.server){
    foreach ($service in $computer.services.service){
        $serviceName = $service.Name
        Write-Host $serviceName
        $serviceInstance = Invoke-Command -ComputerName $computer.name -ScriptBlock {Get-WmiObject -Class Win32_Service -Filter "DisplayName = '$serviceName'"}
        if ($serviceInstance.State -eq 'Running'){
            $row = "$($appName) $($computer) $($service) $($running) "
        }
        elseif ($serviceName.State -eq 'Stopped'){
            $row = "$($appName) $($service) $($stopped) "
            $error = "$($appName) $($service) "
        }
        $servicesReport += $row
        Write-Host $row
    }
}

现在,如果$row$appName中包含任何空格,则每个$serviceName作为单个字符串并不是非常有用。要让它输出结构化数据,请改为创建一堆对象:

$stopped = "ERROR"
$running = "RUNNING"

Get-ChildItem "C:\Users\rjohnso1\Desktop\Reports\XML" -Filter *.xml | ForEach-Object {
    $content = [xml](Get-Content $_.FullName)
    $servicesReport = @()
    $appName = $content.application.name

    foreach ($computer in $content.application.server){
        foreach ($service in $computer.services.service){
            $serviceName = $service.name
            Write-Host $serviceName
            $serviceInstance = Invoke-Command -ComputerName $computer.name -ScriptBlock {Get-WmiObject -Class Win32_Service -Filter "DisplayName = '$serviceName'"}
            $row = [pscustomobject]@{
                AppName = $appName
                Server  = $computer.name
                Service = $serviceName
                State   = if($serviceInstance.State -eq 'Running'){$running}else{$stopped}
            }
            $servicesReport += $row
        }
    }

    # Here you could export your $servicesReport to CSV or HTML with Export-Csv or ConvertTo-Html |Out-File
}