将CSV与Array进行比较

时间:2017-04-20 20:29:19

标签: powershell

我有一个空数组,它存储了我的所有Windows服务,这些服务以某些字符串开头,例如OPS-AmazonServer,我提供的代码中没有包含我解析服务的地方,只是说它就是这样。应用名称。

然后我有一个CSV文件,其中包含标有'应用程序名称'的服务名称列表。看起来像这样

应用程序名,例如,优先级
AuthBridge ,, 1个
AmazonServer ,, 1个
AmexEC ,, 1

我想要做的是将存储在数组中的服务与CSV列表进行比较,但我似乎无法弄清楚逻辑是如何流动的。

$services = get-service Centinel* -ComputerName $serverName | select -expand name
$centinelServices = @()

$services = get-service OPS* -ComputerName $serverName | select -expand name
$opsServices = @()

$services = @()
foreach($service in $centinelServices) {
    $services += $service
}

foreach($service in $opsServices) {
    $services += $service
}


$csvLocation = "\\logserver\Cardinal\OPS\QA\Task\conf\Centinel\app-restart.csv" 
$masterList = import-csv $csvLocation
$applications = @() 
$masterList | ForEach-Object {$applications += $_.ApplicationName}

forEach($service in $services){
    forEach($application in $applications){
        if($service -eq $application){
            "$service match found"
        }
        else {
            "$service match not found"
        }
    }

1 个答案:

答案 0 :(得分:2)

好的,最简单的方法是使用Compare-Object,并使用Select进行一些魔术。

我将假设CSV中的ApplicationName列是与Windows服务列表中的Name属性匹配的字符串列表。因此,我们首先导入该CSV,然后将ApplicationName的属性名称更改为Name,以便它与Windows服务对象上的相关属性相匹配。

$masterList = Import-Csv $csvLocation | Select @{l='Name';e={$_.ApplicationName}}

然后我们只需使用Compare-Object查看两个列表中的内容:

Compare-Object (Get-Service) -DifferenceObject $masterList -Property Name -IncludeEqual

如果您想要解析,您可以随时将其传递给Where子句,或使用-IncludeEqual-ExcludeDifferent参数的组合:

$masterList = Import-Csv $csvLocation | Select @{l='Name';e={$_.ApplicationName}}
$myServices = Get-Service
$foundServices = Compare-Object $myServices -DifferenceObject $masterList -Property Name -IncludeEqual -ExcludeDifferent
$servicesNotInMaster = Compare-Object $myServices -DifferenceObject $masterList -Property Name | Where {$_.SideIndicator -eq '<='}
$servicesNotFoundLocally = Compare-Object $myServices -DifferenceObject $masterList -Property Name | Where {$_.SideIndicator -eq '=>'}

或者使用Switch cmdlet一次完成所有操作:

$masterList = Import-Csv $csvLocation | Select @{l='Name';e={$_.ApplicationName}}
$myServices = Get-Service
Switch(Compare-Object $myServices -dif $masterList -prop Name -includeequal -PassThru){
    {$_.SideIndicator -eq '<='} {[array]$servicesNotInMaster += $_}
    {$_.SideIndicator -eq '=>'} {[array]$servicesNotFoundLocally += $_}
    {$_.SideIndicator -eq '=='} {[array]$foundServices += $_}
}

修改:好的,从您对OP的添加进行更新。看起来只需使用Where子句就可以获得良好的服务,而不是一遍又一遍地获取服务。

$services = Get-Service -ComputerName $serverName | Where{$_.Name -like 'ops*' -or $_.Name -like 'Centinel*'} | Select -Expand Name

然后导入CSV,再次使用Select -Expand获取属性的值,而不是像以前那样循环遍历它。

$masterList = Import-Csv $csvLocation | Select -Expand ApplicationName

现在你只有两个字符串数组,所以这实际上比比较对象更简单......你可以在-in语句中使用Where运算符,如下所示:

$services | Where{$_ -in $masterList} | ForEach{"$_ match found"}

这基本上过滤了$services数组,以查找$masterList数组中的任何字符串。这只适用于完全匹配!因此,如果该服务被列为“OPS-AmazonServer”,但在您的CSV文件中,它仅列在“AmazonServer”中,它将无效!我特意使用那个例子,因为你的问题就是你的例子。您专门调用了名为“OPS-AmazonServer”的服务,然后在您的CSV示例中列出了'AmazonServer'。

如果CSV中的列表是您要匹配的部分字符串,则可以使用RegEx来执行此操作。如果您不熟悉RegEx,这可能会有所帮助,但这可行:

$services = Get-Service -ComputerName $serverName | Where{$_.Name -like 'ops*' -or $_.Name -like 'Centinel*'} | Select -Expand Name
$masterList = (Import-Csv $csvLocation | ForEach{[regex]::escape($_.ApplicationName)}) -join '|'
$services | Where{ $_ -match $masterList } | ForEach{"$_ match found"}