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