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

Regex Powershell匹配数组/对象中的两个值,regex,powershell,Regex,Powershell,我会先解释我想要达到的目标,以防有比我写的更好的方法。我试图获取Exchange计划设置为禁用的用户列表(但在下面的示例中,我只查询一个用户来测试脚本) 我需要应用的筛选器位于licenses.servicestatus对象上。如果运行并输出此对象,您将获得: ServicePlan ProvisioningStatus ----------- ------------------ INTUNE_O365 PendingActivati

我会先解释我想要达到的目标,以防有比我写的更好的方法。我试图获取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

我下面的脚本并没有这样做,相反,如果它发现disabled和exchange以任何顺序出现,它将返回true,即只要disabled和exchange在表中的任何位置,而不是它们在同一行上匹配的位置,它将始终返回true。这是我能得到的最接近我想要的

Get-MsolUser -UserPrincipalName "exampleuser@dom.com"| ? {"disabled" -in $_.licenses.servicestatus.provisioningstatus -and ($_.licenses.servicestatus| Out-String| ? {$_ -like "*exchange*"})}
我知道我哪里出了问题,我只是不知道如何解决它。该脚本实际上是在运行两个单独的搜索,而不是将它们组合在一起

还要注意,我使用out字符串的原因是上表没有将serviceplan作为字符串输出

如果有更好的方法,请告知,否则我只需要知道如何匹配同一行中数组中的两个条件

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
不起作用,因为

$\许可证
是一个具有两个属性的对象
Servicestatus
&
provisiongstatus

因此,您可以使用
$\.licenses.servicestatus
$\.licenses.provisioningstatus
而不是像
$\.licenses.servicestatus.provisioningstatus
那样同时使用这两个属性


还用于检查数组中是否包含不适合您所做操作的值。

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

我已经把它放进了这样一个模块

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
现在,正如您可能已经注意到的,还有一个testall函数。此示例不使用此选项,但可能会派上用场

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

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
注意,我已经用一些正确的测试数据替换了获取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!"
}

希望它有意义。

我自己设法解决了这个问题:

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

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

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

$users = Get-Msoluser -EnabledFilter EnabledOnly | 
Where { ($_.licenses.serviceplan.tostring() -match 'Exchange') `
-and ($_.licenses.ProvisioningStatus -eq 'Disabled') }
您得到的是在其许可证属性中的某个位置同时具有“Exchange”和“Disabled”的用户,但他们可能不在同一行

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

}
如果您正在寻找“未经许可”的用户,请务必小心,因为许可证可以重新分配。这里我使用的是
getazureaduser
和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值的用户,请在两个属性上使用
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许可证的用户,则需要反转逻辑以查找所有许可证均未启用的帐户

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

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

  • 使用嵌套的Where对象检查树中的每个对象
  • 如果在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" } }