Powershell匹配数组/对象中的两个值

时间:2015-08-11 00:12:56

标签: regex powershell

如果有比我写的更好的方法,我会先解释我想要实现的目标。我正在尝试获取一个用户列表(但在下面的示例中,我只是查询一个用户来测试脚本),他们将Exchange计划设置为禁用。

我需要应用的过滤器位于licenses.servicestatus对象上。如果您运行并输出此对象,则获取:

ServicePlan           ProvisioningStatus
-----------           ------------------
INTUNE_O365           PendingActivation 
YAMMER_ENTERPRISE     PendingInput      
RMS_S_ENTERPRISE      Success           
OFFICESUBSCRIPTION    Success           
MCOSTANDARD           Disabled          
SHAREPOINTWAC         Disabled          
SHAREPOINTENTERPRISE  Disabled          
EXCHANGE_S_ENTERPRISE Success  

我需要的是如果查询在provisioningstatus列中找到“disabled”并且在serviceplan列中找到匹配的“exchange”通配符,则返回true。

我的下面的脚本没有这样做,相反,如果它发现已禁用并以任何顺序进行交换,则返回true,只要禁用和交换在表中的任何位置,IE将始终返回true,而不是它们在一个位置匹配的位置行。这和我想要的一样接近。

Get-MsolUser -UserPrincipalName "exampleuser@dom.com"| ? {"disabled" -in $_.licenses.servicestatus.provisioningstatus -and ($_.licenses.servicestatus| Out-String| ? {$_ -like "*exchange*"})}

我可以看到我出错的地方,我只是不知道如何解决它。该脚本有效地运行两个单独的搜索,而不是将它们组合在一起。

另请注意我使用out-string的原因是因为上表没有将serviceplan作为字符串输出。

如果有更好的方法可以做到这一点,那么请指教,否则我只需要知道如何匹配同一行中数组中的两个条件。

5 个答案:

答案 0 :(得分:1)

Get-MsolUser -UserPrincipalName "exampleuser@dom.com" | 
  ForEach-Object {
    if( ($_.licenses.serviceplan.tostring() -match 'Exchange') -and ($_.licenses.ProvisioningStatus -eq 'Disabled') )
    {
        $true
    }
    Else
    {
        $false
    }

}

检查你的代码:

"disabled" -in $_.licenses.servicestatus.provisioningstatus

因为

而无法工作

$_.licenses是一个包含2个属性Servicestatus& Provisioningstatus

因此您可以$_.licenses.servicestatus$_.licenses.provisioningstatus使用$_.licenses.servicestatus.provisioningstatusmodule MyUtils def self.build_collection_full_email(collection) I18n.t('app_name') + " <" + self.build_collection_email(collection) + ">" end end ,而不是sender_name = MyUtils.build_collection_full_email(@collection) ,因为没有这样的属性。

此外,-in用于检查数组中是否包含不适合您正在执行的操作的值。

答案 1 :(得分:0)

你的问题让我考虑使用我在@JaredPar撰写的文章中读到的Test-Any。基本思想是评估对象数组中的任何项是否具有一组匹配条件。

我把它放到这样的模块中。

function Test-Any {
    [CmdletBinding()]
    param([scriptblock]$EvaluateCondition,
        [Parameter(ValueFromPipeline = $true)] $ObjectToTest)
    begin {
        $any = $false
    }
    process {
        if (-not $any -and (& $EvaluateCondition $ObjectToTest)) {
            $any = $true
        }
    }
    end {
        $any
    }
}


function Test-All {
    [CmdletBinding()]
    param([scriptblock]$EvaluateCondition,
        [Parameter(ValueFromPipeline = $true)] $ObjectToTest)
    begin {
        $all = $true
    }
    process {
        if ($all -and ((& $EvaluateCondition $ObjectToTest) -eq $false)) {
            $all = $false
        }
    }
    end {
        $all
    }
}

Export-ModuleMember -Function Test-Any, Test-All

现在您可能已经注意到还有一个Test-All功能。这不用于此示例,但可能会派上用场。

现在你可以像这样解决你的任务。

注意我已经用一些适当的测试数据替换了对Get-msoluser的调用。

Import-Module AllAny

$testdata = @(
    (new-object psobject -Property @{ServicePlan="ExchangePlan";licenses = new-object psobject -Property @{ProvisioningStatus="Disabled"}}),
    (new-object psobject -Property @{ServicePlan="SomeOtherPlan";licenses = new-object psobject -Property @{ProvisioningStatus="Enabled"}}))

$userProp = $testdata #Get-MsolUser -UserPrincipalName "exampleuser@dom.com" 

if ($userProp | Test-Any {$Args.serviceplan -match "Exchange" -and $Args.licenses.ProvisioningStatus -eq 'Disabled'})
{
    echo "Do your thing!"
}

希望它有意义。

答案 2 :(得分:0)

我自己解决了这个问题:

Get-MsolUser -UserPrincipalName "exampleuser@dom.com" | ? {$_.licenses.servicestatus| Out-String  | ? {$_ -like "*exchange*disabled*"}}

答案 3 :(得分:0)

这是相当古老的,但是鉴于Azure查询的局限性,这是我想出的一个稍微整洁的解决方案。

首先,创建一个至少包含您需要匹配的条件的用户列表

$users = Get-Msoluser -EnabledFilter EnabledOnly | 
Where { ($_.licenses.serviceplan.tostring() -match 'Exchange') `
-and ($_.licenses.ProvisioningStatus -eq 'Disabled') }

您得到的是在其Licenses属性内某处同时具有“ Exchange”和“ Disabled”的用户,但它们可能不在同一行。

如果您正在寻找“未经许可”的用户,请小心,因为可以重新分配许可。在这里,我使用Get-AzureADUser和AssignedPlans属性。此用户已获得SfB的两次许可,但仍然有效。

AssignedTimestamp   CapabilityStatus Service                       ServicePlanId
-----------------   ---------------- -------                       -------------
2019-12-05 03:46:34 Enabled          MicrosoftCommunicationsOnline 3e26ee1f-8a5f-4d52-aee2-b81ce45c8f40
2019-09-26 07:16:48 Deleted          MicrosoftCommunicationsOnline 4828c8ec-dc2e-4779-b502-87ac9ce28ab7

在执行第一遍以填充$users列表之后,要使用户至少拥有一个具有Exchange&Disabled值的行,请在每个用户的Licenses属性上均使用Where语句检查属性。以下内容将UPN转储到$licensedUsers中,以便以后导出。

$licensedUsers = @()
$users | Foreach {
    $u = $_
    if ($u.licenses | where { ($_.serviceplan.tostring() -match 'Exchange') `
        -and ($_.ProvisioningStatus -eq 'Disabled') }) {
        $licensedUsers += $u.userPrincipalName
        #if you want more properties in the report, create a PSCustomObject here instead
    }
}

如果您只想让根本没有任何有效的Exchange许可证的用户使用,则希望颠倒逻辑以查找未启用所有许可证的帐户。< / p>

if (-not ($u.licenses | where { ($_.serviceplan.tostring() -match 'Exchange') `
-and ($_.ProvisioningStatus -eq 'Enabled')) })

答案 4 :(得分:0)

在同一行中有两件事可以做到这一点(据我所知):

  • 使用嵌套的Where-Objects检查树上的每个对象
  • 如果您在ServicePlan属性下使用“ servicename”属性,则无需将其转换为字符串

因此,我认为这应该在单个命令中满足原始海报的要求:

Get-MsolUser -UserPrincipalName "exampleuser@dom.com" | Where-Object { $_.Licenses.ServiceStatus | Where-Object { $_.ServicePlan.ServiceName -like "*exchange*" -and $_.ProvisioningStatus -eq "Disabled" } }

或更短的命令:

Get-MsolUser -UserPrincipalName "exampleuser@dom.com" | ? { $_.Licenses.ServiceStatus | ? { $_.ServicePlan.ServiceName -like "*exchange*" -and $_.ProvisioningStatus -eq "Disabled" } }