Powershell: Get users with multiple specified Product Licences - powershell

I'm trying to get output from O365 via PowerShell for users with specific product licenses assigned.
There's plenty of articles out there of how to get this information but not found information explaining how to grab users with multiple specified products.
So far I have the following (taken from here):
Get-MsolUser -All |
Where-Object {
($_.licenses).AccountSkuId -match "EXCHANGEENTERPRISE" `
-and ($_.licenses).AccountSkuId -match "EMS" `
-and ($_.licenses).AccountSkuId -notmatch "ENTERPRISEPACK"
} |
Select-Object displayname,userprincipalname,{$_.Licenses.AccountSkuId} |
Export-Csv "C:\Temp\EOP2+EMSLicensedUsers.csv" -NoTypeInformation
However, this still shows users who have ENTERPRISEPACK assigned.

PowerShell operators do not work like you think they do.
.AccountSkuId is an array of values. Doing AccountSkuId -notmatch "ENTERPRISEPACK" does not tell you whether "ENTERPRISEPACK" is contained in that array or not. It gives you all the values from that array that do not match "ENTERPRISEPACK".
It's a filter. Try executing "1","2","3" -notmatch "3" to see what I mean.
Therefore, if even one value in AccountSkuId does not match "ENTERPRISEPACK", you still get some values back, and "some values" (i.e. a non-empty list) evaluates to $true in a Boolean expression.
You wanted to write this:
Get-MsolUser -All |
Where-Object {
($_.licenses).AccountSkuId -match "EXCHANGEENTERPRISE"
-and ($_.licenses).AccountSkuId -match "EMS"
-and -not (($_.licenses).AccountSkuId -match "ENTERPRISEPACK")
} |
Select-Object displayname,userprincipalname,{$_.Licenses.AccountSkuId} |
Export-Csv "C:\Temp\EOP2+EMSLicensedUsers.csv" -NoTypeInformation
Note the change. ($_.licenses).AccountSkuId -match "ENTERPRISEPACK" gives you all values that match "ENTERPRISEPACK" (normally 1 or 0) and the -not simply negates that result.
Other things to try with PowerShell operators:
1,2,2,3 -eq 2
1,2,2,3 -ne 2
1,2,2,3 -gt 1
"hallo","hello","foo" -like "*ll*"
"hallo","hello","foo" -replace 'l','L'
Keep in mind that PowerShell operates on lists when it can. A single value is nothing but a list of length 1.

Related

Find VM with exact name in get-vm incase of multiple entries

I am having code where I am searching VM details using Get-VM -Name $VM_Name.
It is not giving any output in below case where I have 2 entries for same VM name like below
001_MBM1P
001_MBM1P_Clone_Prj_Win
was trying something like blow but getting error
get-vm $VM_Name | where {($_.Name -match $VM_Name) -and ($VM_Name -notcontains 'Clone*')}
get-vm : 1/10/2022 11:36:52 AM Get-VM VM with name '001_MBM1P' was not found using the specified filter(s).
Please let me know how can I filter the search which will work in both cases.
The -contains and -notcontains operators work on arrays only, they are not string operations.
You may use the efficient String::Contains() method:
get-vm | where {($_.Name -match $VM_Name) -and (-not $_.Name.Contains('Clone'))}
Alternatively use the -notlike operator:
get-vm | where {($_.Name -match $VM_Name) -and ($_.Name -notlike '*Clone*')}
Note that Contains() is case-sensitive whereas -like and -notlike are not. This Q/A shows some ways for case-insensitive "contains" operation using String methods.

read the value from registry rather than hard code in if statement

i have below powershell line. It will return 1 when there is account found in administrators group other than built-in administrator, group1, group2, group3.
If ((Get-LocalGroupMember -Group Administrators | Where-Object {($_.ObjectClass -eq 'User' -or $_.ObjectClass -eq 'Group') -and (($_.Name -notlike "$env:computername\administrator") -and ($_.Name -notlike 'group1') -and ($_.Name -notlike 'group2') -and ($_.Name -notlike 'group3') )}).Count -gt 0) {
echo 1
}else{
echo 0
}
how do i change the above if statement to read in the string value (which has commas) in registry so I don’t need to hard code group1, group2, group3 in the if statement?? Thanks
example i had set it at hklm:\system\test , named as adm and string value of group1,group2,group3
i am able to pull the value i set at registry using this line.
$listofadm = (Get-ItemProperty -Path "HKLM:\system\test" -ErrorAction Stop -Name adm).adm
Not sure why you are checking if user or group, if you can omit that it will simplify your check. To streamline this I would make a regex pattern of all the groups including the computer\adminsitrator account. If the groups indeed do not have a space then you can simply replace the commas with a pipe | character.
$listofadm = "$env:computername\administrator|" +
(Get-ItemProperty -Path "HKLM:\system\test" -ErrorAction Stop -Name adm).adm -replace ',','|'
This will make $listofadm contain something like
DESKTOP-NEKK74J\administrator|group1|group2|group3
Now if you just want to find any object whose name is not any of those 4
Get-LocalGroupMember -Group Administrators | where name -NotMatch $listofadm
Single item checks in the Where clause can omit the { } curly braces. If you do need to ensure it's a user or group object then this is how that would look.
Get-LocalGroupMember -Group Administrators |
Where-Object {($_.ObjectClass -eq 'User' -or $_.ObjectClass -eq 'Group') -and $_.name -NotMatch $listofadm}

Simple Powershell where filter not working

Dears,
Executing the below powershell command returns no value even though it should return some matched values. Am i missing something?
get-vm | select VMName ReplicationMode, State | Where-Object {(state -eq 'Running') -and (ReplicationMode -eq 'None')}
Is there a way to fix this without using "$_" syntax?
Thanks,
Why do you not want to use $_?
$_ represent each occurrence of your selection.
I did my own example. Where is the problem?
Get-Process | select Id, ProcessName | Where-Object {($_.ProcessName -eq 'chrome') -and ($_.Id -gt 30000)}

Using Variable in Filter

I'm trying to query AD for a list of users from their Surname, which are help in a list.
I've tried most of the afternoon, but I just get a blank Excel sheet.
Also I want to know if there is more than one person with that username in AD, no idea how to even start with that one.
What I have so far:
Import-module ActiveDirectory
$names = get-content c:\tempfiles\Final.txt
$names | ForEach-Object {
$ADUserParams=#{
'Searchbase' = 'OU=Administrators,OU=Locations,DC=The,DC=group,DC=com'
'Searchscope'= 'Subtree'
}
get-aduser #ADUserParams -filter 'surname -like "$Names*"' | Select-Object Samaccountname, UserPrincipalName | export-csv C:\TempFiles\Usernames.csv
}
Do I even need a filter if it's a foreach-object? And is there a way to then check AD within that OU if there are more than one surname that are the same, and how would I count them? I can pull out a list of users surnames and then run the following, but it's then a manual task to locate the missing names. (If that makes sense)
What I have for that so far is:
get-content C:\TempFiles\Users.txt | sort -u > C:\TempFiles\users_cleaned.txt
This should do it (however is untested as I don't have access to an AD right now):
Import-module ActiveDirectory
$names = get-content c:\tempfiles\Final.txt
$ADUserParams=#{
'Searchbase' = 'OU=Administrators,OU=Locations,DC=The,DC=group,DC=com'
'Searchscope'= 'Subtree'
}
$names | ForEach-Object {
$CurrentUser = get-aduser #ADUserParams -filter "surname -like '$_*'" | Select-Object Samaccountname, UserPrincipalName
If ($CurrentUser) {
If ($CurrentUser.Count -gt 1){ $DuplicateSurname = $true }Else{ $DuplicateSurname=$false }
$CurrentUser | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name DuplicateSurname -Value $DuplicateSurname
Write-Output $_
}
} Else {
Write-Warning "$_* did not matched any users."
}
} | export-csv C:\TempFiles\Usernames.csv
Explanation:
Within a ForEach-Object loop the current item in the pipeline is represented by $_. You also need to use double quotes for the filter string, as variables (like $_) are expanded in double quoted strings, not single quoted strings.
You don't need to declare your $ADUserParams hashtable within the loop (that's wasteful) so I moved it outside.
The result of Get-ADUser will be returned to the pipeline, so finally I moved the | export-csv outside of the ForEach-Object so that the result of the processing is piped in to it. I think without this you'd only get the final result.
"Also I want to know if there is more than one person with that username in AD"
To handle this I have put a second ForEach-Object that loops through every user returned in to $CurrentUser and adds a "DuplicateSurname" property to the object (which should then be an additional column in your CSV) based on whether the count of $CurrentUser is more than 1 or not.
Finally we have to make sure that the contents of $_ are put back in to the pipeline which we do with Write-Object $_.

Powershell Where-Object and DN exclusions

I am trying to query a list of users while excluding a specific OU. This is also using Quest's AD snap-in for Get-QADUser. I have this:
$ExcludedOU = "Service Accounts"
$inactiveUsers = Get-QADUser -SizeLimit 3 -SearchRoot $sourceOu -NotLoggedOnFor $InactiveFor -Enabled | Where-Object {$_.description -notlike $DescriptionPrefix -and #{n="ParentContainerDN";e={($_.ParentContainerDN -split ",*..=")[0]}} -notlike $ExcludedOU }
The goal is to exclude any users where the parent OU is "Service Accounts". ParentContainerDN looks like OU=Service Accounts,OU=Our Users,DC=DOMAINNAME,DC=ORG
This query does not error, but it does not exclude either. This is the part I may not have the syntax correct on?
#{n="ParentContainerDN";e={($_.ParentContainerDN -split ",*..=")[0]}} -notlike $ExcludedOU
I was partially wrong about the regex portion of your split. I am still correct in that the string supports regular expressions. That query will split on the CN=, OU= and DN=.
However you placed calculated property syntax into a where-object clause. It didn't error out since it is a valid hashtable and hashtables support like and notlike. Calculated properties are used for things like Format-Table and Select-Object which you can then reference those "new" properties later in other pipes.
$inactiveUsers = Get-QADUser -SizeLimit 3 -SearchRoot $sourceOu -NotLoggedOnFor $InactiveFor -Enabled |
Select-Obejct Name,SamAccountName,Description,#{n="ParentContainerDN";e={($_.ParentContainerDN -split ",*..=")[0]}} |
Where-Object {$_.description -notlike $DescriptionPrefix -and $_.ParentContainerDN -notlike $ExcludedOU }
The above syntax is what was also done in the code you linked to on Social Technet
I cannot make this return false for the life of me. This will evaluate to true which might be why your query was not working as expected. This is valid PowerShell just not correct to use.
#{n="ParentContainerDN";e={$_.WhatEver}} -notlike "string"
However like Kai Zhao mentioned in comments this is not really used effectively and you can get the same results without the calculated property.
$inactiveUsers = Get-QADUser -SizeLimit 3 -SearchRoot $sourceOu -NotLoggedOnFor $InactiveFor -Enabled |
Where-Object {$_.description -notlike $DescriptionPrefix -and ($_.ParentContainerDN -split ",*..=")[1] -notlike $ExcludedOU}