applications (Azure), list – see Azure enterprise applications, list
array, remove members of one array from another array
I do this when I want to enable MFA to a whole domain but exclude system accounts
$usersAvengers
=
Get-MsolUser
-All |
?
{$_.userprincipalname
-match
"Avengers.com"
-and
$_.StrongAuthenticationRequirements.State
-eq
$null
-and
$_.UserType
-ne
"Guest"
-and
$_.isLicensed
-eq
$true} | sort UserPrincipalName
$exclude
=
@("[email protected]",
"[email protected]",
"[email protected]")
$AvengersNoSystemUsers
=
$usersAvengers
|
?
{$_.UserPrincipalName
-notin
$exclude}
let's focus on one user. What to use for the -UserIds
field?
It seems that the first part before the "@" sign will work.
$someGuy = Search-UnifiedAuditLog -UserIds "someGuy" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) -ResultSize 5000
how many records associated this user:
$someGuy.Count
count of unique operations performed by this user:
$someGuy.Operations | select -Unique
let's home in on what files he modified.
$someGuy | ? {$_.Operations -eq "FileModified"} | fl
Yuck! It looks like the data we're interested is all clumped
together in a somewhat unreadable AuditData
variable.
Luckily, we can parse it out pretty easily.
$ConvertedOutput = $someGuy | Select-Object -ExpandProperty AuditData | ConvertFrom-Json
Now that the AuditData
variable is parsed out,
display some relevant fields.
$ConvertedOutput | Select-Object CreationTime, UserId, Operation, Workload, ObjectID, SiteUrl, SourceFileName, ClientIP, UserAgent | ogv
Azure, connect to – see connect to Azure
Azure enterprise applications, list
to list all Azure enterprise applications
Get-AzureADServicePrincipal -All $True | Sort-Object DisplayName | ft
Note that if you omit the -All $true
parameter,
you'll get fewer groups than if you don't.
Azure groups, show – see also Azure security groups, show
to list all groups
Get-AzureADGroup -All $True | Sort-Object DisplayName | ft
Note that if you omit the -All $true
parameter,
you'll get fewer groups than if you don't.
for just one user
$UserIdentity = "someUser"
$User = Get-ADUser -Identity $UserIdentity
all the Azure groups to which the user belongs
Get-AzureADUser -SearchString $User.UserPrincipalName | Get-AzureADUserMembership
remove the user from all Azure groups to which he belongs
Get-AzureADUser -SearchString $User.UserPrincipalName | Get-AzureADUserMembership | % {Remove-AzureADGroupMember -ObjectId $_.ObjectId -MemberId (Get-MsolUser -UserPrincipalName $User.UserPrincipalName).ObjectId}
the Get-AzureADUser
command doesn't work anymore.
Instead, use Get-MgUser
:
Get-MgUser -ConsistencyLevel eventual -Count userCount -Search "DisplayName:Marley, Bob"
"pure" security groups (not email enabled)
Get-AzureADGroup -All $true | ? {$_.MailEnabled -eq $false -and $_.SecurityEnabled -eq $true}
email enabled security groups
Get-AzureADGroup -All $true | ? {$_.MailEnabled -eq $true -and $_.SecurityEnabled -eq $true}
Azure version – see version of Azure
capital letters, change to proper case – see proper case
connect to Azure – see also Connect-AzureAD not recognized
$User
=
"[email protected]"
$PWord
=
ConvertTo-SecureString
-String
"topSecret"
-AsPlainText -Force
$cred
=
New-Object
-TypeName System.Management.Automation.PSCredential -ArgumentList
$User,
$PWord
Connect-AzureAD
-Credential
$cred
under some circumstances,you'll instead want to use:
Connect-MSOLservice -Credential $cred
And if that has problems, check which version of MSOnline you have: you may need to update
Connect-AzureAD not recognized
Install-Module
az
Import-Module
az
create user – see user, create
created user, when? – see user created, when?
$User
=
"[email protected]"
$PWord
=
ConvertTo-SecureString
-String
"topSecret"
-AsPlainText -Force
$cred
=
New-Object
-TypeName System.Management.Automation.PSCredential -ArgumentList
$User,
$PWord
delete user – see user, delete
delete orphaned synced user attempt, but system won't allow you to delete – see synced user in AAD has no corresponding user in AD and won't let you delete
deleted user (soft deleted), delete permanently – see user, soft deleted - delete permanantly - useful in a situation where you're trying to delete a user but the system claims some other, similarly named user is already clogging up the deleted users
deleted users (soft deleted), list one in particular
This will also get his immutable ID
Get-MsolUser -All -ReturnDeletedUsers | ? {$_.UserPrincipalName -eq "[email protected]"} | Select-Object UserprincipalName,ImmutableID,LastDirSyncTime
deleted users (soft deleted), list
Get-MsolUser -All -ReturnDeletedUsers | Sort-Object UserPrincipalName | ft UserPrincipalName, DisplayName, ObjectId
deleted user (soft deleted), restore when UserPrincipalName has a domain not accepted by the tenant - see user, restore when UserPrincipalName has a domain not accepted by the tenant
deleted groups, show – see groups deleted, show
display name, change
Set-MsolUser -UserPrincipalName "[email protected]" -DisplayName "Diana, Princess of Wales"
But once I got
Unable to update parameter. Parameter name: DISPLAYNAME
I found out this happens when you try to do it with a user that's synced. And, sure enough, the user was synced. But the display name was right in local AD. So, how could I possibly set it again to the right value in the cloud? I read somewhere that this command would fix:
Set-MsolDirSyncEnabled -EnableDirSync $false
And, sure enough, I could then run the Set-MsoluUser
command above just fine.
But then I couldn't reverse the command to set EnableDirSync
to true
afterwards! I kept getting the error:
You cannot turn off Active Directory synchronization
Not only that, but my sync server started complaining "stopped-server-down"! Argh, what to do? Well, it turns out when you run the command to top syncing, it puts it in a "pending" state as revealed by this command:
Get-MsolCompanyInformation | select DirectorySynchronizationStatus
which, indeed, showed:
DirectorySynchronizationStatus
------------------------------
PendingDisabled
So you just have to wait (12 hours?) for that to settle down before attempting to set back to "true". That is, wait for the result of the command above to change before finally issuing:
Set-MsolDirSyncEnabled -EnableDirSync $True
Not sure it was worth going through all that just to fix that little display problem!
distribution group, allow external users to mail to internal distribution group – see group, allow external senders
distribution group, find by wildcard – see wild card search
domain, display domain part of UserPrincipalName
Get-MsolUser -UserPrincipalName Jack@Daniel.com | Select @{n="Dom";e={$_.UserPrincipalName.split("@")[1]}}
domain, filter MsolUser by – see Get-MsolUser filter
domain, find users who belong to a particular domain
fast
Get-Msoluser -DomainName needleinhaystack.com -All
for better or worse, this brings in not only users with this particular domain in their UserPrincipalName but also any users with this domain in any of their proxyAddresses. So, if you really only want users with this domain in their UserPrincipalName, go slow.
slow
Get-MsolUser -All | where {($_.userprincipalname -match "needleinhaystack.com")}
domain, find all users - sort by domain
Get-MsolUser -All | Select-Object @{n="Dom";e={$_.UserPrincipalName.split("@")[1]}}, displayName, userprincipalname | Sort-Object dom, displayName
domain, force removal from tenant
Remove-MsolDomain -DomainName "yourdomain.com" -Force
domains, list all for a tenant
new
Get-MgDomain | sort ID | select ID, AuthenticationType
old
Get-MsolDomain | sort name | select Name
domain licensed mailboxes – see multifactor authentication (MFA), find all mailboxes for a domain, whether and how their MFA is enabled and what licenses they have
domains, list all accepted in a tenant
dupes, find users with duplicate display names – see Find IDs With Duplicate Display Name or ghost users, track down (duplicates, etc.)
Some commands seem to only work by using the DisplayName
or the only other alternative might be to specify the ObjectId
.
This means if you try to update or add using this, system will complain that
more than one user has the same DisplayName
.
dynamic distribution group, create
New-DynamicDistributionGroup -Name "Employees US" -RecipientFilter "CustomAttribute5 -eq 'United States'"
dynamic distribution group email address, change
Set-DynamicDistributionGroup -Identity "Employees US" -WindowsEmailAddress "[email protected]"
dynamic distribution groups, list
Get-DynamicDistributionGroup
dynamic distribution group, list members
Get-DynamicDistributionGroupMember -Identity "Employees US" | ft
email-enabled security group - see also group member, add
email user info
Get-MsolUser -userprincipalname [email protected] | fl
enterprise applications (Azure), list – see Azure enterprise applications, list
extended attributes or properties – see New-AzureADApplicationExtensionProperty
external user, invite – see invitation, send
external users, allow to mail to internal distribution group – see group, allow external senders
external users - this has to do with SharePoint users - see also guest users
For an external user to be listed using this PowerShell cmdlet, they need to have accepted the invitation to the SharePoint Online environment, and have logged in at least once.
Get-SPOExternalUser | Select DisplayName,Email,AcceptedAs,WhenCreated | Format-Table
But the Get-SPOExternalUser
cmdlet only returns first 50 users.
So, we need to amend the script a bit to get all external users in SharePoint Online.
So:
Try
{
For
($x=0;;$x+=50) {
$ExternalUsers
+=
Get-SPOExternalUser
-PageSize
50
-Position
$x
-ErrorAction Stop
}
}
Catch
{}
$ExternalUsers
| ft
In some cases, the Get-SPOExternalUser
cmdlet doesn't
return all external users. So, use Get-SPOUser
cmdlet to get
external users by site collection. See
here for details and a script to do that.
external users belonging to groups – see groups with external users
filter MsolUser on domain – see Get-MsolUser filter
Get-MgUser -ConsistencyLevel eventual -Search "DisplayName:HealthMailbox"
Get-MgUser, permissions required to run
Find-MgGraphCommand -command Get-MgUser | Select -First 1 -ExpandProperty Permissions
filter on domain
Get-Msoluser -DomainName NewlyMigrated.com -All
filter on usage location
Get-Msoluser -UsageLocation UK -All
Deprecated in favor of Get-MgUser. Start with
Connect-MgGraph
should bring up
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code EE9GLGY6J to authenticate.
(with a unique code, not the one above). Once connected:
Welcome to Microsoft Graph!
Connected via delegated access using 14d82cec-204b-4c2f-b7e8-297a70deb67a
Readme: https://aka.ms/graph/sdk/powershell
SDK Docs: https://aka.ms/graph/sdk/powershell/docs
API Docs: https://aka.ms/graph/docs
NOTE: You can use the -NoWelcome parameter to suppress this message.
again, with another unique code, not the one above
But if you run Connect-MgGraph all by itself, then commands like Get-MgUser won't even be recognized. You may instead want to connect with:
Connect-MgGraph -Scopes 'User.Read.All'
Or, check to make sure you're logged on to the right account:
Get-MgContext
If it's wrong,
Disconnect-AzAccount
Disconnect-MgGraph
And then connect again to the right account.
After reconnecting to the right account:
Get-MgUser -Top 5
ghost users, track down (duplicates, etc.) - see also Find IDs With Duplicate Display Name
Sometimes the system claims there's interference with users you just can't seem to find anywhere. This is a list of commands to try to find locations of these interferences.
$m="[email protected]"
Get-MsolUser
-All |
where-Object {$_.ProxyAddresses -match "$m"} | fl
Get-MsolUser
-All |
Where-Object {$_.UserPrincipalName
-match
"$m"} | fl
Get-MsolContact
-All |
Where {$_.EmailAddress -match "$m"} | FL
Get-MsolGroup
-All |
Where-Object {$_.ProxyAddresses
-match
"$m"} | fl
Get-MsolUser
-ReturnDeletedUsers -All |
Where-Object {$_.ProxyAddresses
-match
"$m"} | fl
#Get-Recipient
-ResultSize unlimited | Where {$_.EmailAddresses
-match "$m"} | FL Name, RecipientType, emailAddresses
Get-Recipient
-ResultSize unlimited |
Where
{$_.EmailAddresses
-match
"$m"} | FL
Get-Mailbox
-SoftDeletedMailbox |
Where
{$_.EmailAddresses
"$m"} | FL
Get-Recipient
-Filter:
"name -like '*cnf*'" | fl
Get-Mailbox
-PublicFolder | FL EmailAddresses
global admins, list
Get-MsolRoleMember -RoleObjectId $(Get-MsolRole -RoleName "Company Administrator").ObjectId
global admin role, add
Add-MsolRoleMember -RoleName "Company Administrator" -RoleMemberType User -RoleMemberEmailAddress "[email protected]"
global admin role, remove
Remove-MsolRoleMember -RoleName "Company Administrator" -RoleMemberType User -RoleMemberEmailAddress "[email protected]"
group, add (create)
Azure group:
New-AzureADGroup -DisplayName "Employees US Security" -MailEnabled $false -SecurityEnabled $true -MailNickName "EmployeesUSSecurity"
Oddly, you seem to need the MailNickName
even if you set -MailEnabled
to $False
.
And you can't set -MailEnabled
to $True
.
If you want an email-enabled security group, you need to
create an email-enabled distribution group of type "security" instead:
New-DistributionGroup -Name "Accounting NetSuite" -Alias AccountingNetSuite -Type Security
New-UnifiedGroup -DisplayName "Accounting NetSuite2" -Name "Accounting NetSuite2"
populate variable with list of groups
$distGroups = Get-DistributionGroup -identity LetEmALLIn*
display current settings
$distGroups | select Name, DisplayName, RequireSenderAuthenticationEnabled
change settings
$distGroups | Set-DistributionGroup -RequireSenderAuthenticationEnabled $False
group, copy all members from one group to another group – see also group, move users listed in CSV from one group to another
This assumes you already know the ObjectID
of your target.
Get-AzureADGroup -All $True | ? {$_.DisplayName -eq "SourceGroup"} | Get-AzureADGroupMember | % {Add-AzureADGroupMember -ObjectId "73ea0b84-006d-48f6-ba34-8a1d2bdb7cad" -RefObjectId $_.ObjectId}
where 73ea0b84-006d-48f6-ba34-8a1d2bdb7cad&
is the
ObjectID
of your target in this example.
group deleted, delete permanently
first, get the ID
Get-AzureADMSDeletedGroup
once you have the ID, use it to permanently delete
Remove-AzureADMSDeletedDirectoryObject -Id cfcd3d3d-e488-41d1-b358-b13d8f7a9306
group, find – see also wild card search
Get-AzureADGroup -SearchString "IT Gr"
or, if that doesn't know but you know the objectID:
Get-AzureADObjectByObjectId -ObjectIds 4ac67f63-275e-49ca-9a57-f36271c533f3 | fl
dynamic group, disable message to users telling them they've joined
Get-UnifiedGroup
-Identity
"[email protected]"
| select WelcomeMessageEnabled
Set-UnifiedGroup
-Identity
"[email protected]"
-UnifiedGroupWelcomeMessageEnable:$false
group, licenses for each member
This
- lists all members in a group
- splits off and discards the useless tenant name prefixing each user's license and concatenates all their licenses into one string in the "licenses" field
- splits out whether or not the user does or does not have two particular licenses ("Intune" and "O365 Premium" in this example) into two correspondingly labeled True/False fields dedicated those two licenses
- puts the results into an grid view so we can separately sort on those two licenses which interest us.
$tenant
= (Get-MsolAccountSku)[0].AccountSkuId.split(":")[0]
$prefixLength
=
$tenant.Length+1
$IntuneServiceNotInstalled
=
Get-AzureADGroupMember
-ObjectId (Get-AzureADGroup
-SearchString
"IntuneServiceNotInstalled").ObjectID
$licenses
=
$IntuneServiceNotInstalled
|
%
{
$MsolUser
=
Get-MsolUser
-UserPrincipalName
$_.UserPrincipalName;
$licensesThisUser
=
$MsolUser.Licenses.AccountSkuId.Substring($prefixLength)
$licensesCombinedIntoOneString
=
$licensesThisUser
-join
', '
$intune
=
$licensesThisUser
-contains
"INTUNE_A"
$O365Premium
=
$licensesThisUser
-contains
"O365_BUSINESS_PREMIUM"
New-Object
-TypeName PSObject -Property
@{
"Display Name"
=
$_.DisplayName
licenses
=
$licensesCombinedIntoOneString
intune
=
$intune
O365Premium
=
$O365Premium
}}
$licenses
| ogv
groups, list – see Azure groups, show
group member? Is someone a member of a group?
$division
=
"Clean plate club"
$UPN
=
"[email protected]"
$members
=
Get-DistributionGroupMember
-Identity
$division
$members.Count
$members
| ogv
If
($members
-contains
$UPN) {Write-Host
"'$UPN' is a member of '$division'"
-ForegroundColor Green}
Else
{Write-Host
"'$UPN' is NOT a member
of '$division'"
-ForegroundColor Red}
group member, add (aimed at email-enabled security groups but should also work for distribution groups) – see also group, move users listed in CSV from one group to another
What you might think ought to work (if you search how to add users to a group) but doesn't:
normally you'd have to dig up the object IDs, which is a pain:
Add-AzureADGroupMember -RefObjectId fd51d77f-5906-4ffa-a890-40c2dac9243 -ObjectId 37e9523e-4c8e-446f-8cc5-9bcb58d59c87
The above should work. But it usually fails with
“Unable to update the specified properties for objects that have
originated within an external service
”.
another way which will also probably not work:
Add-AzureADGroupMember -RefObjectId (Get-AzureADUser -SearchString "Frodo" | ? {$_.DisplayName -eq "Frodo Baggins"}).ObjectID -ObjectId (Get-AzureADGroup -SearchString "Fellowship" | ? {$_.DisplayName -eq "Fellowship of the Ring"}).ObjectID
There are a couple extra SearchString
in there that might
seem redundant. But filtering ahead of time before the "?
"
clause reduces the time taken for the searches. Otherwise, you'd have to put an
-All:$true
in right after the Get-AzureADUser
to make sure you got all AzureAD records and that adds time.
This also works
Add-AzureADGroupMember -ObjectId (Get-AzureADGroup -SearchString "Fellowship of the Ring" ).ObjectID -RefObjectId (Get-MsolUser -UserPrincipalName frodo@shire.com).ObjectID
as should this for a CSV containing several users you want to add:
$Groupid
= (Get-MsolGroup
-SearchString
"Fellowship of the Ring").ObjectID
Import-CSv
-Path
"FellowshipOfTheRing.csv"
|
% {
$UserID
= (Get-MsolUser
-UserPrincipalName
$_.UserPrincipalName).ObjectID
Add-MsolGroupMember
-GroupObjectId
$GroupID
-GroupMemberObjectId
$UserID
-GroupMemberType User
}
What actually works
Instead, you must use
the Add-DistributionGroupMember
Exchange command.
$DeweyCheetumIDs
=
Get-MsolUser
-All |
?
{$_.UserPrincipalName
-like
"*DeweyCheetum*"}
foreach
($user
in
$DeweyCheetumIDs) {
Add-DistributionGroupMember
-Identity
"Employees AndHowe"
-Member
$user.DisplayName
}
find IDs with duplicate DisplayName
you may get complaints if
you have multiple users with the same DisplayName
.
The only way I've found is to find the dupes.
First, load all users into an array.
$AllUsers
=
Get-MsolUser
-All | sort DisplayName
$DisplayNames
=
@()
$AllUsersCount
=
$AllUsers.count
foreach
($user
in
$AllUsers) {
$i++
$DisplayNames
+=
"$($user.DisplayName)"
}
Note we expand our scope beyond the original where statement above
by not only not restricting it by the where
statement but also using the -All
filter.
Find the dupes:
$ht
=
@{}<
$DisplayNames
|
foreach
{$ht["$_"] +=
1}<
$ht.keys
|
where
{$ht["$_"] -gt
1} |
foreach
{write-host
"Duplicate element
found $_"}
After you find this to find the dupes, then manually delete them.
And then run the same looped Add-DistributionGroupMember
command above.
group members, show (for AzureADGroup)
first, make sure you have the group name right
Get-AzureADGroup | sort DisplayName
then list all the members
Get-UnifiedGroupLinks -Identity "Some Group" -LinkType Members | select name, RecipientType, RecipientTypeDetails, UserState | sort name
distribution group
Get-DistributionGroupMember -Identity "Golden Horde"
azure group
Get-AzureADGroupMember -ObjectId (Get-AzureADGroup -SearchString "Auditor Meetings").ObjectID
security group
this will show a compressed list of one line per group with concatenated owners and members as fields in each line for all security groups with the word "marketing" in the group's DisplayName
$marketingGroups
=
Get-AzureADGroup
-All
$True
-SearchString
"marketing"
$result
=
@()
$marketingGroups
|
ForEach-Object
{
$group
=
$_
$owners
=
Get-AzureADGroupOwner
-ObjectId
$group.ObjectId
| select DisplayName
$members
=
Get-AzureADGroupMember
-ObjectId
$group.ObjectId
| select DisplayName
$result
+=
New-Object
PSObject -property
@{
GroupName
=
$group.DisplayName
members
=
$Members.DisplayName
-join
","
owners
=
$owners.DisplayName
-join
","
description
=
$group.Description
}
}
$result | ogv
$result
|
Export-Csv
-Path
"$([environment]::getfolderpath("mydocuments"))\MarketingGroups$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv" -NoTypeInformation -Encoding UTF8
same as above except expanded out into separate line for each member instead of concatenated (and, of course, no owners)
foreach
($group
in
$marketingGroups) {
$thisGroup
=
Get-AzureADGroupMember
-ObjectId
$group.ObjectID
| sort DisplayName
foreach
($member
in
$thisGroup) {
$result
+=
New-Object
PSObject -property
@{
GroupName
=
$group.DisplayName
member
=
$Member.DisplayName}
}
}
group members, show whether members are users or computers – see also group members, show
# use Get-ADGroupMember
to list group members and determine whether each member
is a user or a workstation
$groupName
=
"SPM-Users"
$groupMembers
=
Get-ADGroupMember
-Identity
$groupName
# Get group members
$memberDetails
=
@()
# Create array to
hold the custom objects
foreach
($member
in
$groupMembers) {
# Loop through each member and create a custom object
$memberDetails
+=
[PSCustomObject]@{
Name
=
$member.Name
Type
=
$member.objectClass
}
}
$memberDetails
|
sort type,
Name
|
Out-GridView
group members who have been issued an invitation but have not accepted – see guest users belonging to a group, invitations not accepted
group, move users listed in CSV from one group to another
$dir
= [environment]::getfolderpath("mydocuments")
$docName
=
"$($dir)/ListUsersToMoveFromOneGroupToAnother.csv"
$ListUsersToMoveFromOneGroupToAnother
=
Import-Csv
$docName
$removeFromGroup
=
"remove from this source group"
$addToGroup
=
"add to this target group"
$i
=
0
foreach
($person
in
$ListUsersToMoveFromOneGroupToAnother)
{
$i++
$percent
=
$i/$($ListUsersToMoveFromOneGroupToAnother.count)
$percentTxt
=
$percent.ToString("P")
$user
=
Get-MsolUser
-UserPrincipalName
$person.UserPrincipalName
$userID
=
$user.UserPrincipalName.split("@")[0]
$userObjectIDTxt
=
$user.ObjectId.ToString()
$isContractor
= (Get-DistributionGroupMember
$addToGroup
|
?
{$_.Name
-eq
$userID}).Guid
$isEmployee
= (Get-DistributionGroupMember
$removeFromGroup
|
?
{$_.Name
-eq
$userID}).Guid
Write-Host
"$i
-
$($user.FirstName)
$($user.LastName)
$($user.UserPrincipalName
$percentTxt% complete"
-ForegroundColor Blue
if
($isContractor) {Write-Host
"
$userName in target group no need to do anything"
-ForegroundColor Green -NoNewline}
else
{
Write-Host
" $userName NOT in target group, must add"
ForegroundColor Yellow -NoNewline
Add-DistributionGroupMember
-Identity
$addToGroup
-Member
$userObjectIDTxt
-Confirm:$false
}
if
($isEmployee) {
Write-Host
$userName
in source group, must remove" -ForegroundColor Red
Remove-DistributionGroupMember
-Identity
$removeFromGroup
-Member
$userObjectIDTxt
-Confirm:$false
}
else
{Write-Host
"
$userName
NOT in source group, no need to do anything"
-ForegroundColor Cyan}
}
groups, show all groups to whom someone belongs
Get-AzureADUser -SearchString social@butterfly.com | Get-AzureADUserMembership | % {Get-AzureADObjectByObjectId -ObjectId $_.ObjectId | select DisplayName, ObjectType, MailEnabled, SecurityEnabled, Description} | ft -a
perhaps we want to copy & paste output - hence the "-a" so description won't get chopped
groups (Azure), show – see Azure groups, show
Get-AzureADMSDeletedGroup
$Groups
= (Get-UnifiedGroup
|
?
{$_.GroupExternalMemberCount
-gt
0})
If
($Groups.Count
-gt
0) {
ForEach
($G
in
$Groups)
{
Write-Host
"Members in"
$G.DisplayName
$Members
=(Get-UnifiedGroupLinks
-Identity
$G.Alias
-LinkType Members)
ForEach
($M
in
$Members)
{
If
($M.Name
-Like
"*#Ext#*")
{
Write-Host
"External member:"
$M.Name}
}
}
}
guest user, invite – see invitation, send
guest users – see also external users
Get-AzureADUser | ? {($_.UserType -eq 'Guest')}
Note: Get-AzureADUser
seems to max out at 100 records returned!
If you want more, then you have to filter. Filter conditions are a little different than normal
PowerShell conditions. For example, you need to use eq
without the normal preceeding dash.
I think Get-MsolUser
will eventually be deprecated
and replaced with Get-AzureADUser
. But, for now, some of the Get-MsolUser
below still work.
or
Get-AzureADUser -All $True -Filter "userType eq 'Guest'"
or
Get-AzureADUser -All:$true -Filter "userType eq 'Guest'"
What if we don't know the identity?
Get-AzureADUser -SearchString "elvis"
guest users, created recently (like since yesterday)
Get-MsolUser -All | ? {($_.UserType -eq 'Guest') -and ($_.WhenCreated -ge [DateTime]::Today.AddDays(-1))} | Select-Object UserPrincipalName, DisplayName, WhenCreated
Remember: Get-AzureADUser
seems to max out at 100 records returned!
This means the command above might not get all the recent records!
guest users, invitations not accepted
Get-AzureADUser -All $true | ? {$_.ExtensionProperty.userState -eq "PendingAcceptance"}
But this only gets the first few records because Get-AzureADUser
seems to max out at 100 records returned. But below works better:
Get-AzureADUser -Filter "UserState eq 'PendingAcceptance'" | select Department, DisplayName, Mail, RefreshTokensValidFromDateTime | Sort-Object RefreshTokensValidFromDateTime | ft
Probably because it filters up front and there's some kind
of size restriction on the number of records which Get-AzureADUser
can return. Here it's sorted by RefreshTokensValidFromDateTime
(which I think corresponds to "time created") which is the same order
that's returned in the AAD GUI. Other times I sort by Department instead:
Get-AzureADUser -Filter "UserState eq 'PendingAcceptance'" | select Department, DisplayName, Mail, RefreshTokensValidFromDateTime | Sort-Object Department, LastName, DisplayName | ft
If you sent out a bunch of invitations all within a short time and want to see which users accepted:
Get-AzureADUser
-All
$true
|
?
{$_.RefreshTokensValidFromDateTime
-gt
'12/26/19'
guest users belonging to a group, invitations not accepted
Get-AzureADGroup -Filter "DisplayName eq 'Some Group'" | Get-AzureADGroupMember | ? {$_.ExtensionProperty.userState -eq "PendingAcceptance"} | select Department, DisplayName, Mail, RefreshTokensValidFromDateTime | Sort-Object Department, LastName, DisplayName | ft
guest users, order by department
two different ways to do this:
Get-MsolUser
- might eventually be deprecated
Get-MsolUser -All | ? {($_.UserType -eq 'Guest')} | Select-Object Department, UserPrincipalName, DisplayName, FirstName, LastName, RefreshTokensValidFromDateTime | Sort-Object Department, LastName, DisplayName | ft
Get-AzureADUser
- newer, I think. And probably faster
since we can filter up front instead of getting all records and then
filtering.
Get-AzureADUser -Filter "userType eq 'Guest'" | select Department, DisplayName, UserPrincipalName, Mail, RefreshTokensValidFromDateTime, CreationType | Sort-Object Department, LastName, DisplayName | ft
Remember: Get-AzureADUser
seems to max out at 100 records returned.
This means the command above might not get all records for all departments. So maybe this might work better:
$guestUsers
=
Get-AzureADUser
-Filter
"userType eq 'Guest' and (Department eq 'Your Department' or
Department eq 'Another Department')"
|
Select-Object
Department, DisplayName, UserPrincipalName, Mail,
RefreshTokensValidFromDateTime, CreationType, UserType
$guestUsers.Count
$guestUsers | ogv
GUID for a user
Get-Mailbox -identity someUser | select DisplayName, GUID, ExchangeGUID
history for user activity – see audit log, search
immutable ID
clear (that is, to delete it so the ID will no longer sync)
First, either delete the ID in local AD or move it to an OU that you don't have set up to sync. Then run a sync on your sync server. This will put your cloud version of this ID into a "soft-deleted" state.
Then you'll want to eventually run a command further below to delete his ImmutableID. But if you run it right away without first
- delete the ID in local AD or move to an OU that's not set up to sync
- sync to "soft-delete" that ID on the cloud
- stop syncing on your sync server
you'll get:
Set-MsoLUser : Unable to update parameter. Parameter name: IMMUTABLEID.
At line:1 char:1
+ Set-MsoLUser -UserPrincipalName [email protected] -Immutabl ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [Set-MsolUser], MicrosoftOnlineException
+ FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.PropertyNotSettableException,Microsoft.Online.Administration.Automation.SetUser
And you'll get this error even if you do stop syncing and try to run that command to clear out the ImmutableID if you haven't already first deleted it first on AD or moved it to an OU that doesn't sync.
Anyway, after you
- either delete the ID in local AD or move it to an OU that doesn't sync and
- then sync to (soft) delete it from the cloud
Run the following command on your sync server to stop syncing:
Set-MsolDirSyncEnabled -EnableDirSync $false
Restore the ID that you put into the "soft-deleted" state on the cloud:
Restore-MsolUser -UserPrincipalName freeFromTether@CloudCompany.com
Run the command to remove the user's ImmutableID
Set-MSOLUser -UserPrincipalName freeFromTether@CloudCompany.com -ImmutableID "$null"
Note: you need the quotes around null
above or it won't clear properly
Go back to your sync server re-instate syncing:
Set-MsolDirSyncEnabled -EnableDirSync $true
Another reason to turn off syncing on your sync server before you try to
delete on AAD directly without first deleting from AD is that you may
get stopped-server-down
errors on the sync server when it runs its regularly scheduled sync.
But you can only set to false & then back to true about once a day (maybe 12 hours?).
If you try to do again too soon, you get:
Set-MsolDirSyncEnabled : You cannot turn off Active Directory synchronization.
At line:1 char:1
+ Set-MsolDirSyncEnabled -EnableDirSync $false
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [Set-MsolDirSyncEnabled], MicrosoftOnlineException
+ FullyQualifiedErrorId :
Microsoft.Online.Administration.Automation.DirSyncStatusChangeNotAllowedException,Microsoft.Online.Administration.Automation.SetDirSyncEnabled
find the Immutable ID for a user:
Get-MsolUser -UserPrincipalName someUser@yourDomain.com | Select-Object UserprincipalName,ImmutableID,LastDirSyncTime
set (if you don't know the value for the $immutableID
variable below, probably best to see
sync local user to cloud user)
Set-MSOLuser -UserPrincipalName someUser@yourdomain.com -ImmutableID $immutableID
sync local user to cloud user – see sync local user to cloud user
$DisplayName
=
"Princess Di"
$email
=
"[email protected]"
$messageInfo
=
New-Object
Microsoft.Open.MSGraph.Model.InvitedUserMessageInfo
$messageInfo.customizedMessageBody
=
"Please accept
this invitation to be able to access https://royalfamily.sharepoint.com/BuckinghamPalace/SitePages/Home.aspx"
New-AzureADMSInvitation
-InvitedUserDisplayName
$DisplayName
-InvitedUserEmailAddress
$email
-SendInvitationMessage
$true
-InviteRedirectUrl
"https://royalfamily.sharepoint.com/BuckinghamPalace/"
-InvitedUserType guest -InvitedUserMessageInfo
$messageInfo
invitations to be a guest user not accepted – see guest users, invitations not accepted
invitations to be a guest user not accepted by members belonging to a group, find which – see guest users belonging to a group, invitations not accepted
licenses available on this tenant– see also licenses for a user
Get-MsolAccountSku
which returns the same thing as those licenes ostensibly used
Get-MsolAccountSku | Where {$_.ConsumedUnits -ge 1}
license, add to users – see also licenses for a user
don't assume no one on your list of users won't already have the license because if they do have the license and you try to add it, failure.
$needLicenses
=
@("[email protected]",
"[email protected]",
"[email protected]")
$licenseWithoutTenantName
=
"INTUNE_A"
$tenantName
= (Get-MsolAccountSku)[0].AccountSkuID.split(":")[0]
$licenseWithTenantName
=
"$($tenantName):$licenseWithoutTenantName"
foreach
($needsLicense
in
$needLicenses) {
$user
=
Get-MsolUser
-UserPrincipalName
$needsLicense
#.UserPrincipalName
if
($user.Licenses.ServiceStatus.ServicePlan.ServiceName
-match
$licenseWithoutTenantName) {
Write-Host"'$($needsLicense.DisplayName)' already has '$licenseWithoutTenantName'"
-ForegroundColor Green
}
else
{
Write-Host
"'$needsLicense' needs '$licenseWithoutTenantName'"
-ForegroundColor
Red
Set-MsolUserLicense
-UserPrincipalName
$needsLicense
-AddLicenses
$licenseWithTenantName
-ErrorVariable
$ErrHandle
}
}
replace one license for another for each person in a group.
In this case, replace "Microsoft 365 Business Standard"
with "Office 365 E3" for everyone in the "Executive Team".
Instead of a raw array, we now have an object from which we must peel off
the Display Name
and UserPrincipalName
$needLicenses
=
Get-AzureADGroupMember
-ObjectId(Get-AzureADGroup
-SearchString
"Executive Team")[0].ObjectID | select UserPrincipalName
$tenantName
= (Get-MsolAccountSku)[0].AccountSkuID.split(":")[0]
$licenseToAddWithoutTenantName
=
"ENTERPRISEPACK"
$licenseToAddWithTenantName
=
"$($tenantName):$licenseToAddWithoutTenantName"
$licenseToRemoveWithoutTenantName
="O365_BUSINESS_PREMIUM"
$licenseToRemoveWithTenantName
=
"$($tenantName):$licenseToRemoveWithoutTenantName"
foreach
($needsLicense
in
$needLicenses) {
$user = Get-MsolUser
-UserPrincipalName
$needsLicense.UserPrincipalName
if
($user.Licenses.AccountSkuID
-match
$licenseToAddWithoutTenantName) {
Write-Host
"'$($user.DisplayName)' already has '$licenseToAddWithoutTenantName'"
-ForegroundColor Green
}
else
&{
Write-Host
"'$($user.DisplayName)' needs '$licenseToAddWithoutTenantName'"
-ForegroundColor Red
Set-MsolUserLicense
-UserPrincipalName
$needsLicense.UserPrincipalName
-RemoveLicenses
$licenseToRemoveWithTenantName-AddLicenses
$licenseToAddWithTenantName
-ErrorVariable
$ErrHandle
}
}
licensed users for a domain – see multifactor authentication (MFA), find all mailboxes for a domain, whether and how their MFA is enabled and what licenses they have
strictly speaking, this isn't quite getting "licensed users for a domain". But still useful.
licenses for a user – see also licenses, remove all for a particular user
new MSGraph version
Install-Module
Microsoft.Graph -Scope AllUsers
Import-Module
Microsoft.Graph
Connect-MgGraph
-Scopes "User.Read.All",
"Directory.Read.All"
# need admin approval
Connect-MgGraph
-
Scopes"User.Read"
# works for just my account
$userId
=
(Get-MgUser
-UserId
"[email protected]").Id
$licenses
=
Get-MgUserLicenseDetail
-UserId
$userId
old, deprecated short version
Get-MsolUser -UserPrincipalName user@yourdomain.com | Select-Object Licenses
old, deprecated longer version that lists all the doo-dads associated with a license
Get-MsolUser -UserPrincipalName user@yourdomain.com | Select-Object -ExpandProperty Licenses | Select-Object -ExpandProperty ServiceStatus
licenses for each user of a group – see group, licenses for each member
licenses, how many left?
$tenantName
=
(Get-MsolAccountSku)[0].AccountSkuID.split(":")[0]
$licenseName
=
"O365_BUSINESS_PREMIUM"
$license
=
"$($tenantName):$license"
$Account
=
Get-MsolAccountSku
|
Where-Object
{$_.AccountSkuId
-eq
$license}
$Result
=
$Account.ActiveUnits
-
$Account.ConsumedUnits
If you don't know the license name, then list the licenses available on this tenant to give you a clue
licenses, remove all for a domain
In particular, the code below is intended to find and remove licenses for users remaining in an old tenant after you've migrated them to a new tenant. (This assumes you weren't prescient enough to first assign all these users in your old tenant a "dummy" domain while you still had them all identified in an array in memory. Or that you tried that once but other users still left in the old domain got all confused because users they recognized now had that strange "dummy" domain.)
- capture list of all users recently migrated to a new domain in that new domain
- convert that list from an object to plain-text suitable to print out as the feedstock to create a new array in the old tenant
- read in that array in the old domain
- use this array to remove licenses from the old tenant and optionally delete the users
On the new tenant
First, capture an object containing all the users you've migrated in
the new tenant. Because you had to transfer the domain before you migrated, that
probably means the old users on the old tenant have a nodescript
@yourOldTenant.onmicrosoft.com
email suffix
which makes them hard to distinguish from any other emails with the same
@yourOldTenant.onmicrosoft.com
email suffix.
This, indeed, is the whole point of this exercise; if the users on the old tenant
are easily identifiable some other way (like if you reassigned them all a
"dummy" domain while you had them all identified in an array in memory),
then we don't have to go through all this rigamarole!
$DomainUsers = Get-Msoluser -DomainName NewlyMigrated.com -All
Convert the object into an array
$DomainUsersArrayNewTenant = $DomainUsers | % {"$($_.UserPrincipalName)"}
Convert the array into a string to print out suitable to import into a new array in the old tenant
$DomainUsersArrayNewTenant = $DomainUsersArrayNewTenat -join '", "'
Print out the array (which has been converted
into a string so we can read it into an array in the old tenant)
and copy into the clipboard. You may want to capture this string
and substitute the old tenant's "@oldTenant.onmicrosoft.com
"
for the new tenant's "@NewlyMigrated.com
"
in a text editor before pasting it in for the next step.
Or write 1 line of code to make the substitution for you.
$DomainUsersArrayOldTenant
On the old tenant
Read in the array; you'll simply paste in what you printed out in the prior step inside the parentheses
$DomainUsersArrayOldTenant = ("[email protected]", "[email protected]", "[email protected]")
Execute code against the array to clean up the old tenant
$DomainUsersArrayOldTenant
|
%
{
# does the user even exist?
if
(Get-MsolUser
-UserPrincipalName
$_
-ErrorAction SilentlyContinue)
{ # if user
exists, find license info
$user
=
Get-MsolUser
-UserPrincipalName
$_
$licensed
=
$False
# remove all licenses
For
($i=0; $i
-le ($user.Licenses | Measure).Count;
$i++) {
If
([string]::IsNullOrEmpty($user.Licenses[$i].AccountSkuId) -ne
$True) {
$licensed
=
$true}
}
If($licensed -eq $true) {
Write-Host "$($user.UserPrincipalName) is licensed ($(($user.Licenses | Measure).Count))" -ForegroundColor Green
$licenses = Get-MsolUser -UserPrincipalName
$user.UserPrincipalName | Select-Object -ExpandProperty Licenses
# show all licenses
for this user prior to deleting
# $licenses.AccountSkuId # short 'n' sweet version
$licenses | Select-Object -ExpandProperty ServiceStatus
# delete all licenses for this user
($licenses).AccountSkuId | %
{Set-MsolUserLicense
-UserPrincipalName
$user.UserPrincipalName
-RemoveLicenses $_}
else
{Write-Host "$($user.UserPrincipalName)
($($_)) not licensed"
-ForegroundColor Magenta}
# remove user if you want
Remove-MsolUser
-UserPrincipalName
$user.UserPrincipalName
-Force
}
else
{Write-Host
"$($_)
does not exist"
-ForegroundColor Cyan}
}
Or, if you were prescient enough to first assign all these users in your old tenant a "dummy" domain, easier:
$BAGUsersUKAfterRename
=
Get-MsolUser
-All |
?
{$_.UserPrincipalName
-match
"oldDomain.eu"
foreach
$user
in
$BAGUsersUKAfterRename) {
$licensed
$False
#remove all licenses
For
($i=0;
$i
-le ($user.Licenses
| Measure).Count;
$i++) {
If
([string]::IsNullOrEmpty($user.Licenses[$i].AccountSkuId) -ne
$True) {
$licensed=
$true}
}
If($licensed
-eq
$true) {
Write-Host "$($user.UserPrincipalName)
is licensed ($(($user.Licenses | Measure).Count))"
-ForegroundColor Green
$licenses = $user
|
Select-Object
-ExpandProperty Licenses
# show all licenses for this user prior to deleting
#$licenses.AccountSkuId # short 'n' sweet version
$licenses
|
Select-Object
-ExpandProperty ServiceStatus
# delete all licenses for this user
($licenses).AccountSkuId |
%
{Set-MsolUserLicense
-UserPrincipalName
$user.UserPrincipalName
-RemoveLicenses
$_}
}
else
{Write-Host
"$($user.UserPrincipalName)
($($_)) not licensed"
-ForegroundColor Magenta}
}
licenses, remove all for a particular user – see also licenses for a user
$licenses
=
Get-MsolUser
-UserPrincipalName
"[email protected]"
|
Select-Object
-ExpandProperty Licenses
# show all licenses for this user prior to deleting
$licenses
|
Select-Object
-ExpandProperty ServiceStatus
# delete all licenses for this user
($licenses).AccountSkuId |
%
{Set-MsolUserLicense
-UserPrincipalName
$DepartingUser.UserPrincipalName
-RemoveLicenses
$_}
licenses, who has a particular – see also licenses for a user
In this case, Office Premium
Get-MsolUser -All | where {$_.isLicensed -eq "TRUE" -and $_.Licenses.AccountSKUID -eq "yourtenant:O365_BUSINESS_PREMIUM"} | select DisplayName,UserPrincipalName,isLicensed
What if we want to know who with an email ending in a particular domain does not have a particular license?
Get-Mailbox *yourDomain.com -RecipientTypeDetails UserMailbox | Get-MsolUser | ? { $_.isLicensed -eq "TRUE" -and $_.Licenses.AccountSKUID -notcontains "yourTenant:O365_BUSINESS_PREMIUM"}
licenses, who has what on this tenant?
$Sku = @{
"EMS"
=
"Enterprise Mobility Suite"
"EXCHANGEDESKLESS"
=
"Exch Kisok"
#"Exchange
Online Kiosk"
"EXCHANGESTANDARD"
=
"O356 Exch Only"
#"Office 365
Exchange Online Only"
"O365_BUSINESS_PREMIUM"
=
"O365 Prem"
#"Office
Business Premium"
"OFFICESUBSCRIPTION" = "O365 Pro+"
# "Office 365
ProPlus"
"POWER_BI_STANDARD" = "Power-BI standard"
"SHAREPOINTENTERPRISE" = "SP Pl2"
#"SharePoint
Online (Plan 2)"
"SHAREPOINTSTANDARD_YAMMER" = "SP Pl1
Ymr"
#
"SharePoint Online (Plan 1) with Yammer"
"VISIOCLIENT" = "Visio"
#"Visio Pro
Online"
}
$logfile
=
"Office_365_License"
+
[DateTime]::Now.ToString("yyyy-MM-dd_HH-mm-ss")
+
".csv"
$mytemp
=
[environment]::getfolderpath("mydocuments")
$logfile
=
$mytemp
+
"\"
+
$logfile # your local "My Documents"
$licenseType
=
Get-MsolAccountSku
|
Where
{$_.ConsumedUnits
-ge
1} # list all licenses in the tenant
$headerString
=
"Display Name, Domain, UPN"
# Build the Header for the CSV file
$numLicenses
=
0
write-host
"Getting the licenses and writing the header..."
foreach
($license
in
$licenseType)
# Loop through all license types found in the tenant to add licenseTypes
{
$headerString
=
$headerString
+
","
+
$Sku.Item($license.SkuPartNumber)
$numLicenses++
}
$headerString
=
$headerString
+
",Errors, ImmutableId, BlockCredential"
# Add other attributres
Out-File
-FilePath
$LogFile
-InputObject
$headerString -Encoding UTF8 -append
write-host
"Getting all users in the Office 365 tenant..."
# Get a list of all the users in the tenant
$users
=
Get-MsolUser
-all |
where
{
$_.isLicensed
-eq
"True"}
foreach
($user
in
$users)
# Loop through all users found in the tenant
{
$lineString
=
$user.displayname
-Replace",",""
# use last name, comma first name as
display name so remove the comma
write-host
("Processing "
+
$lineString)
$lineString
=
$lineString
+
","
+
$user.UserPrincipalName.Split("@")[1] +
","
+
$user.userprincipalname #+ "," +
$user.isLicensed
for($j=0;$j
-lt
$numLicenses; ++$j) # Loop through all license types found in the tenant
{
$userhaslicense
""
foreach
($row
in
$user.licenses)
# Loop through all licenses assigned to this user
{
if
($row.AccountSkuId.ToString()
-eq
$licenseType.AccountSkuId[$j])
{
$userhaslicense
=
"x"
}
}
$lineString = $lineString + "," + $userhaslicense
}
$lineString = $lineString + "," + $user.Errors + "," + $user.ImmutableId
+
","
+
$user.BlockCredential
Out-File -FilePath $LogFile -InputObject $lineString
-Encoding UTF8 -append
color:#D4D4D4'> -Encoding UTF8 -append
}
write-host
("Script Completed. Results available in " + $LogFile)
to unlock
Set-AzureADUser -ObjectID someUser@yourDomain.com -AccountEnabled $true
this only works if user has a mailbox
(Get-MailboxStatistics -Identity rip@vanWinkle.com).LastLogonTime
log onto Azure – see connect to Azure
logs, search – see audit log, search
lower case, change to proper case – see proper case
Get-AzureADUserManager -ObjectId (Get-MsolUser -UserPrincipalName BobCratchit@scrooge.com).ObjectId
Remove-AzureADUserManager -ObjectId (Get-MsolUser -UserPrincipalName BobCratchit@scrooge.com).ObjectId
Set-AzureADUserManager -ObjectId (Get-MsolUser -UserPrincipalName BobCratchit@scrooge.com).ObjectId -RefObjectId (Get-MsolUser -UserPrincipalName Ebenezer@scrooge.com).ObjectId
member of groups to which someone belongs – see groups, show all groups to whom someone belongs
members of a group – see group members, show
(Get-Item C:\Windows\System32\WindowsPowerShell\v1.0\Modules\MSOnline\Microsoft.Online.Administration.Automation.PSModule.dll).VersionInfo.FileVersion
this can be important when using Connect-MSOLservice
multifactor authentication (MFA), enable for one user.
The code below not only enables MFA but also sets his default method. In the case below we set his default to merely sending verification requests to the phone authenticator app.
put the user's UserPrincipalName
into a variable
$UserPrincipalName = "[email protected]"
What is the user's current status before we change? Note: if we're using Conditional Access policies, those supersede whatever's in here so we don't care. That is, whatever's set here at the individual level doesn't matter.
(Get-MsolUser
-UserPrincipalName
$UserPrincipalName).StrongAuthenticationMethods
(Get-MsolUser
-UserPrincipalName
$UserPrincipalName).StrongAuthenticationRequirements.State
queue up whether or not the user is to be enabled or enforced or whatever
$st
=
New-Object
-TypeName
Microsoft.Online.Administration.StrongAuthenticationRequirement
$st.RelyingParty
=
"*"
$st.State
=
"Enforced"
$sta
=
@($st)
To begin with and by default, users don't have anything
in their StrongAuthenticationMethods
array.
Queue up the stuff we intend to change for the methods into an array.
In this instance, we want requests sent to user's phone authenticator app
so he only need approve to be the default.
That is, we set that
PhoneAppNotification
array element to be$True
and the- other three array elements to be
$False
We set it this way to make it easiest for him (so he doesn't have to key in those 6 digits).
$SMS
=
New-Object
-TypeName
Microsoft.Online.Administration.StrongAuthenticationMethod apply changes Set-MsolUser
-UserPrincipalName
$UserPrincipalName
-StrongAuthenticationRequirements
$sta
-StrongAuthenticationMethods
$PrePopulate the multifactor authentication (MFA),
enable for all mailboxes for a domain, excluding service accounts. Assuming you've already put all your system users into an array,
start by
array, remove members of one array from another array
to get the domain users who aren't system users. Then foreach
($user
in
$AvengersNoSystemUsers) { the first 2 lines help get rid of the extraneous
tenant name when listing licenses. We limit returned results to only
a single domain (DraggingOurFeetToEnableMFA.com). We omit shared mailboxes (because they aren't actively involved
with loggin on or receiving/sending emails) and Room mailbox resources
(including them will cause errors because they have no users associated with them) This adds time to execute because we must execute a
$tenant
= (Get-MsolAccountSku)[0].AccountSkuId.split(":")[0] You can also add a field to display whether or not these
users have PowerShell enabled. This adds time to execute because a second time-consuming
command ( $tenant
= (Get-MsolAccountSku)[0].AccountSkuId.split(":")[0] useful to group users by their MFA status $mailboxes
|
Group-Object
-Property MFA -NoElement not so useful if folks have different combinations of licenses $mailboxes
|
Group-Object
-Property licenses -NoElement |
Sort-Object
-Property Count -Descending | ogv multifactor authentication (MFA), who doesn't have enabled? – see also
multifactor authentication (MFA), find all mailboxes
for a domain, whether and how their MFA is enabled
and what licenses they have for a more detailed account Only care about licensed users who aren't guests. Also good to have the email domain. Get-MsolUser
-All |
?
{$_.UserType
-ne
"Guest"
-and
$_.isLicensed
-eq
$true} |
?
{$_.StrongAuthenticationRequirements.State
-eq
$null} | select DisplayName, UserPrincipalName,
@{N="Domain";
E={$_.UserPrincipalName.split("@")[1]}} | ogv New-AzureADApplicationExtensionProperty if you haven't already, first step before you can create extension properties
is to have an "application" to hang them off of. It doesn't have to be a
"real" application. It can be a "dummy" application.
So run $MyApp
= (New-AzureADApplication
-DisplayName
"Enchanted Kingdom Properties"
-IdentifierUris
"https://EnchantedKingdom.com").ObjectId As an aside, either before or right after you run the command above, you might
want to run this command to see all the other apps and how the one you just
created above (or plan to create real soon) might fit in: Get-AzureADApplication
| select IdentifierUris, DisplayName, ObjectID, AppID | sort DisplayName | ogv If you're like me, you probably never even knew most of these existed.
But it seems a lot of 3rd-party apps get registered here. This command (or some variation) can also come in handy if you don't want to bother recording the value of
the Anyway, now we're ready to create a new New-AzureADServicePrincipal
-AppId (Get-AzureADApplication
-SearchString
"FoodChainID Properties").AppId OK, that's out of the way. Mow we're finally ready to create a new New-AzureADApplicationExtensionProperty
-ObjectId
$MyApp
-Name
"UserType"
-DataType
"String"
-TargetObjects
"User" Now we're finally ready to assign a value to a user for this property $SnowWhite
=
Get-MsolUser
-UserPrincipalName
SnowWhite@EnchantedKingdom.com Get-AzureADObjectByObjectId
-ObjectIds 4ac67f63-275e-49ca-9a57-f36271c533f3 | fl organizational relationships between tenants, list Get-OrganizationRelationship
| select Name,
Enabled, OrganizationalUnitRoot, FreeBusyAccessEnabled, FreeBusyAccessLevel,
WhenCreated, WhenChanged,
@{n="Dom";e={$_.DomainNames
-join
", "}} |
Export-Csv
-Path
"$([environment]::getfolderpath("mydocuments"))\OrganizationRelationship
$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv"
-NoTypeInformation -Encoding UTF8 orphaned synced user, can't delete – see
synced user in AAD has no corresponding user in AD and won't let you delete password change Set-MsolUserPassword
-UserPrincipalName
"someEmail_gmail.com#EXT#@yourTenant.onmicrosoft.com"
-NewPassword
"topSecret" in bulk - also forces users to change their password on first login Import-Csv
c:\user-boxes.csv |
%{Set-MsolUserPassword -userPrincipalName
$_.UserPrincipalName
-NewPassword
"Welcome"
-ForceChangePassword
$true} password expires, set to never first verify status Get-MsolUser
-UserPrincipalName gollum@MistyMtn.com
| Select PasswordNeverExpires then set Set-MsolUser
-UserPrincipalName
"[email protected]"
-PasswordNeverExpires
$True password expiring soon, whose? In an environment where most users' IDs are maintained in local
Active Directory, our local group policy determines whether and when users
passwords expire. But what about cloud-only IDs? There are cloud-only policies
for those users as well. Perhaps all of our domains' password policies are set for
cloud users' passwords to expire after one year. So capture that in a variable
in order to figure out how far away actual users' expiration is from that figure
in a subsequent command: $PasswordPolicy
=
Get-MsolPasswordPolicy
-DomainName
yourDomain.com Find out Get-MsolUser
-All
|Where-Object
{(($_.licenses).AccountSkuId -match "EXCHANGEDESKLESS") -and ($_.immutableid
-eq
$null)} |
select UserPrincipalName, LastPasswordChangeTimestamp,
@{n="whenExpires";e={$_.LastPasswordChangeTimestamp.AddDays($PasswordPolicy.ValidityPeriod)}} or $domain
=
Get-MSOLDomain
|
where
{$_.IsDefault
-eq
$true} password, force change on next login - change setting default is true, below changes to false so he's not forced to change when he logs in next Set-MsolUserPassword
-UserPrincipalName
"[email protected]"
-ForceChangePassword
$false
-NewPassword
"myPrecious" PowerShell command execution (remotely) -
can a group of mail users execute PowerShell commands remotely?
Select the select the group you want to target $ugroup
=
Get-User
-ResultSize Unlimited -Filter
"(RecipientType -eq 'UserMailbox')
-and (UserPrincipalName -like '*yourDomain.com')" to disable these users from being able to execute PowerShell commands: $ugroup
|
%
{Set-User
-identity
$_.UserPrincipalName
-RemotePowerShellEnabled
$false} proper case, change all users' display name from all caps to proper case $TextInfo
= (Get-Culture).TextInfo properties - all properties for a user Get-MsolUser -UserPrincipalName '[email protected]' | Select-Object * recycle bin, remove user from Remove-MsolUser -UserPrincipalName
user@yourdomain.com
-RemoveFromRecycleBin recycle bin, restore user from the domain is no longer accepted by the tenant Restore-MsolUser
-UserPrincipalName someUser@baddomain.com
-AutoReconcileProxyConflicts -NewUserPrincipalName someUser@yourTenant.onmicrosoft.com rename just one user: Set-User
-Identity someUser@yourDomain.com
-Name
"Some User" rename several users that satisfy some criteria: Get-User
-RecipientTypeDetails UserMailbox |
?
{$_.whenCreated
-gt
"6/19/19 9:53 am"
-and$_.whenCreated
-lt
"6/19/19 10:15 am"} |
%{Set-User
-Identity
$_.UserPrincipalName
-Name
$_.DisplayName} Note: when you change the replicate domain controllers – see
domain controllers, replicate role, assign New-ManagementRoleAssignment -Role ApplicationImpersonation -User '[email protected]' security groups, list – see Azure security groups, show send guest user invitation – see invitation, send session, kill existing Get-PSSession
|
Remove-PSSession This doesn't do diddly squat to get rid of O365 session.
When I run Get-MsolUser, I get results - even after
I run the command above and run
soft deleted user, delete permanantly – see
user, soft deleted - delete permanantly -
useful in a situation where you're trying to delete a user but the system claims some other,
similarly named user is already clogging up the deleted users sync local user to cloud user -
see also synced user, stop syncing $guid=
(get-Aduser
someUser).ObjectGuid This alone, all by itself, doesn't work so good
if you have one user synced that you don't care about but whose
immutable ID you want to steal to apply to a cloud-only user
which actually has useful stuff you care about in it that
you want to attach to a local AD user.
Let's say you have two similarly-named users: Get-MSOLuser -SearchString "someUser" | Select-Object UserPrincipalName,
ImmutableID Assume the command returns two results:
one synced & one cloud-only. And you want to sync the cloud-only
ID with your local ID. So you attempt to set your cloud-only ID's
immutable ID to that of your converted local ID's GUID by running: Set-MSOLuser -UserPrincipalName someUser@yourTenant.onmicrosoft.com -ImmutableID $immutableID which will return the following error:
Set-MSOLuser : Uniqueness violation. Property: SourceAnchor. which makes sense because you already have
a synced ID with that same immutableID! Run the command to show both your users
(both the synced one as well as the one in the cloud)
and show both the UPN and ObjectID. Get-MsolUser
-ReturnDeletedUsers -All -SearchString someUser@yourDomain.com
| FL UserPrincipalName, ObjectID At some point, move your synced object in your
local AD from an OU that's synced over to an OU that's not
synced. Or simply delete it from your local AD.
Then sync your local AD to the cloud. This should have the
effect of deleting the synced object.
But you still can't reassign the old synced object's
immutable ID to the cloud-only version until you also delete it
from the recycle bin. For some reason, trying to stuff
the value of the Object ID into a variable… $objectID = Get-MsolUser -ReturnDeletedUsers -SearchString someUser@yourDomain.com | Select-Object ObjectID …and then use the variable to try to delete it
doesn't work: Remove-MsolUser -ObjectId $objectID -RemoveFromRecycleBin -Force you get an error:
Remove-MsolUser : Cannot bind parameter 'ObjectId'. Cannot convert the @{ObjectId=3540aa84-5a35-4b2c-bdb9-2671ff28ad9c} value of type Selected.Microsoft.Online.Administration.User to type System.Guid. Instead, you have to actually paste the value in
from the command you ran above: Remove-MsolUser -ObjectId 3540aa84-5a35-4b2c-bdb9-3782ff28ad9c
-RemoveFromRecycleBin -Force which works better. There's probably some way
to simply use the variable rather than cutting and pasting the value
into your subsequent command. Maybe this might work: $objectID = (Get-MsolUser -ReturnDeletedUsers -SearchString someUser@yourDomain.com).ObjectID I'll try that next time. sync problems
Get-MsolDirSyncProvisioningError -ErrorCategory
PropertyConflict -PropertyName UserPrincipalName $syncedUsers
=
Get-MSOlUser
-All |
?
{$null
-ne
$_.LastDirSyncTime} synced user in AAD has no corresponding user in
AD and won't let you delete Remove-MsolUser
-UserPrincipalName dontWannaSeeYourFace@RoundHereNoMore.onmicrosoft.com -force On the syncing server, stop synchronization Set-ADSyncScheduler
-SyncCycleEnabled
$false At this point, it's probably also a good idea to either move the
local ID counterpart of this soon-to-be-liberated ID from an OU that syncs to
another OU that doesn't. Or simply remove from local AD altogether.
Either way, make sure you do this before you re-enable syncing below On the cloud, get his immutable ID. We'll probably never need it.
But just in case we change our mind, it's better to have it and not need it than
need it and not have it. Get-MsolUser
-UserPrincipalName newly.ascended@master.com
|
Select-Object
UserprincipalName,ImmutableID,LastDirSyncTime
# T30kIiXhSEeE1eEPlfjZoA== Get rid of his immutable ID Get-MsolUser
-UserPrincipalName newly.ascended@master.com
|
Set-MsolUser
-ImmutableId
$null On the syncing server, resume synchronization Set-ADSyncScheduler
-SyncCycleEnabled
$true tenants, organizational relationships between – see
organizational relationships between tenants, list tenant, which one am I on? This will list licenses with how many license you have (ActiveUnits)
as well as how many consumed:
Get-MsolAccountSku This will give the actual tenant name: (Get-MsolAccountSku)[0].AccountSkuID.split(":")[0] What we do above is load up all the licenses, pick the first instance of the returned results
and then split off the tenant name from that - which is the first part of the string before the
":". term 'xx' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again. (Exchange) for example: get-mailbox -ResultSize Unlimited returns: get-mailbox : The term 'get-mailbox' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the name, or if a path was included,
verify that the path is correct and try again. need to run: add-pssnapin *exchange* -erroraction SilentlyContinue title case – see proper case unlicensed users Get-MsolUser
-All -UnlicensedUsersOnly unlicensed users, suppress entries from showing up in the Offline Address Book (OAB)
or Global Address List (GAL)
– see Global Address List (GAL), suppress entries unlock user – see locked out Update-Module
-Name Azure -Verbose failed, complaining Update-Module : Module 'Azure' was not installed by
using Install-Module, so it cannot be updated. So, I had to specify the Install-Module
-Name Azure -Scope CurrentUser -Verbose -Force -AllowClobber Without the WARNING: Version '1.3.2' of module
'Azure' is already installed at
'C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure'.
To install version '5.3.0', run Install-Module and add the
-Force parameter, this command will install version '5.3.0'
side-by-side with version '1.3.2'. I also had to add PackageManagement\Install-Package :
The following commands are already available on this system:'Get-AzureStorageContainerAcl,Start-CopyAzureStorageBlob,Stop-CopyAzureStorageBlob'.
This module 'Azure.Storage' may override the existing commands.
If you still want to install this module 'Azure.Storage', use -AllowClobber parameter. After you install this way, if you check the version,
you'll see both the old and the new show up. Also note that the install location is
in your 'My Documents' instead of in the usual 'C:\Program Files (x86)\Microsoft
SDKs\Azure\PowerShell\ServiceManagement' location upper case, change to proper case – see proper case usage location for all users this sorts by domain name, display name Get-MsolUser
-All
| Select-Object @{n="Dom";e={$_.UserPrincipalName.split("@")[1]}}, UsageLocation, UserPrincipalName, displayName
| Sort-Object dom, displayName | ft dom, displayName, UsageLocation,
UserPrincipalName user history – see audit log, search New-MsolUser
-UserPrincipalName
"[email protected]"
-DisplayName
"Some User"
-FirstName
"Some"
-LastName
"User" or $NewUserParams = @{
$SMS.IsDefault
=
$False
$SMS.MethodType
=
"OneWaySMS"
# user must enter 6-digit code sent to his phone via regular SMS
$Phone
=
New-Object
-TypeName
Microsoft.Online.Administration.StrongAuthenticationMethod
$Phone.IsDefault
=
$False
$Phone.MethodType
=
"TwoWayVoiceMobile"
# user must enter 6-digit code from automated call to his phone
$App
=
New-Object
-TypeName
Microsoft.Online.Administration.StrongAuthenticationMethod
$App.IsDefault
=
$False
$App.MethodType
=
"PhoneAppOTP"
# user must enter 6-digit code from phone app
$PhoneAppNotification
=
New-Object
-TypeName
Microsoft.Online.Administration.StrongAuthenticationMethod
$PhoneAppNotification.IsDefault
=
$True
$PhoneAppNotification.MethodType
=
"PhoneAppNotification"
# user must approve request sent to phone app on his phone
$PrePopulate
=
@($App,
$Phone,
$SMS,
$PhoneAppNotification)
# not sure order of the array is important.�
Clearing & resetting order doesn't appear to have any effect on
the order as it's displayed using Get-MsolUser.
#$PrePopulate = @() # clear out array that gets stored for user
StrongAuthenticationRequirements
and
StrongAuthenticationMethods
properties can be set independently of each other.
But in this case above we set them both at the same time.
$st
=
New-Object
-TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$st.RelyingParty
=
"*"
$st.State
=
"Enabled"
$sta
=
@($st)
Set-MsolUser
-UserPrincipalName
$user.UserPrincipalName
-StrongAuthenticationRequirements
$sta}Get-MsolUser
command inside the loop.
$prefixLength
=
$tenant.Length+1
$mailboxes
=
@(Get-Mailbox
-ResultSize unlimited *DraggingOurFeetToEnableMFA.com
|
?
{$_.IsShared
-eq
$false
-and
$_.RecipientTypeDetails
-ne
'RoomMailbox'}) |
%
{
$MsolUser
=
Get-MsolUser
-UserPrincipalName
$_.UserPrincipalName;
New-Object
-TypeName PSObject -Property
@{
"Display Name"
=
$_.DisplayName
"Domain"
=
$_.UserPrincipalName.split("@")[1]
"Primary Smtp Address"
=
$_.PrimarySmtpAddress
"Name"
=
$_.Name
"Alias"
=
$_.Alias
"MFA"
=
$MsolUser.StrongAuthenticationRequirements.State
"licenses"
=
$MsolUser.Licenses.AccountSkuId.Substring($prefixLength) -join
', '}}
$mailboxes
| ogvGet-User
) is added inside the loop.
Unlike the code above, the code below doesn't limit results to just one domain.
$prefixLength
=
$tenant.Length+1
$mailboxes
=
@(Get-Mailbox
-ResultSize unlimited
|
?
{$_.IsShared
-eq
$false
-and
$_.RecipientTypeDetails
-ne
'RoomMailbox'}) |
%
{
$MsolUser
=
Get-MsolUser
-UserPrincipalName
$_.UserPrincipalName;
New-Object
-TypeName PSObject -Property
@{
"Display Name"
=
$_.DisplayName
"Domain"
=
$_.UserPrincipalName.split("@")[1]
"MFA"
=
$MsolUser.StrongAuthenticationRequirements.State
"RemotePowerShellEnabled"
= (Get-User
$_.UserPrincipalName).RemotePowerShellEnabled
"Primary Smtp Address"
=
$_.PrimarySmtpAddress
"Name"
=
$_.Name
"Alias"
=
$_.Alias
"licenses"
=
$MsolUser.Licenses.AccountSkuId.Substring($prefixLength) -join
', '}}
$mailboxes
| ogvNew-AzureADApplication
below to create a new dummy application.
The DisplayName
name can be anything. But the IdentifierUris
must be a domain accepted in your tenant. You might want to record the value of the
$MyApp
variable because after you leave this session and then maybe want to
come back some later date to add more ExtensionProperty
,
this app's objectID
will come in real handy.$MyApp
variable above but you need to create a new extension property days or weeks later.New-AzureADServicePrincipal
.
Not sure we'll ever really need this again. But we need to run this step before we finally can create what we're
after: new extension propertiesNew-AzureADServicePrincipal
.
Not sure we'll ever really need this again. But we need to run this step before we finally can create what we're
after: new extension properties
Set-AzureADUserExtension
-ObjectId
$SnowWhite.ObjectId
-ExtensionName
"extension_546ae66f87c839087f943fe980b41f99_UserType"
-ExtensionValue
"employee"
$PasswordPolicy.ValidityPeriod
= one year, in our example)
from that to determine when passwords will expire.$_.licenses).AccountSkuId -match EXCHANGEDESKLESS
).
Otherwise, we'll also get a whole bunch of guest accounts which aren't
really that important to us.
$validityPeriod
= (Get-MsolPasswordPolicy
-DomainName
$domain.Name).ValidityPeriod # 730
$expireindays
=
30
if($null
-eq
$validityPeriod){$validityPeriod
=
New-TimeSpan
-Days
90}
$maxPasswordAge
=
$validityPeriod.ToString()
$users
=
Get-MSOLuser
-EnabledFilter EnabledOnly -All |
?
{"Guest"
-ne
$_.UserType
-and
$true
-ne
$_.PasswordNeverExpires
-and (New-TimeSpan
-Start (Get-Date) -End ($_.LastPasswordChangeTimestamp
+
$maxPasswordAge)).Days -le ($expireindays)} | Select DisplayName, LastPasswordChangeTimestamp,
@{Name="passwordExpires";Expression={$_.LastPasswordChangeTimestamp
+
$maxPasswordAge}},
@{n="DaysTilExpire";e={(New-TimeSpan
-Start (Get-Date) -End ($_.LastPasswordChangeTimestamp
+
$maxPasswordAge)).Days}}, PasswordNeverExpires,
@{Name="PrimaryEmailAddress";Expression={($_.ProxyAddresses
|
?{$_
-cmatch
'^SMTP\:.*'}).split(":")[1]}}, UserPrincipalName,
@{N="Licenses";
E={($_.Licenses.AccountSkuID
|
%
{$_.split(":")[1]}) -join
", "}}
$users
| ogv-RemotePowerShellEnabled attribute
foreach
($user
in
$users) {
$fixedDisplayName
=
$TextInfo.ToTitleCase(($user.DisplayName).ToLower()) # must first set to
lower because ToTitleCase doesn't touch all caps
"will change $($user.DisplayName) to
$fixedDisplayName
for $($user.UserPrincipalName)"
Set-MsolUser
-UserPrincipalName
$user.UserPrincipalName
-DisplayName
$fixedDisplayName
}name
property,
ID
and Identity
properties also seem to get resetGet-PSSession
by itself (which returns no results).
$immutableID
=
[System.Convert]::ToBase64String($guid.tobytearray())
Set-MSOLuser
-UserPrincipalName
someUser@yourdomain.com
-ImmutableID
$immutableID
At line:1 char:1
+ Set-MSOLuser -UserPrincipalName [email protected] ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [Set-MsolUser],
MicrosoftOnlineException
+ FullyQualifiedErrorId :
Microsoft.Online.Administration.Automation.UniquenessValidationException,Microsoft.Online.Administration.Automation.SetUser
At line:1 char:27
+ Remove-MsolUser -ObjectId $objectID -RemoveFromRecycleBin -Force
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Remove-MsolUser],
ParameterBindingException
+ FullyQualifiedErrorId :
CannotConvertArgumentNoMessage,Microsoft.Online.Administration.Automation.RemoveUser
Get-MsolDirSyncProvisioningError
-ErrorCategory PropertyConflict -PropertyName ProxyAddresses
Get-MsolUser
-UserPrincipalName [email protected] | fl DirSyncProvisioningErrors
$syncedUsers.Count
$syncedUsers
| select DisplayName, LastDirSyncTime | ogv
At line:1 char:1
+ get-mailbox -ResultSize Unlimited
+ ~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (get-mailbox:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException-Scope
as CurrentUser
. This installs the new version side-by-side
with the old version.-Force
I got-AllowClobber
because
'UserPrincipalName' = $UPN
'DisplayName' = $DisplayName
'FirstName' = $FirstName
'LastName' = $LastName
'Title' = $Title
'Department' = $Department
'Password'
=
$DefaultPassword
}
New-MsolUser
Import-Csv -Path userList.csv | %{New-MsolUser -UserPrincipalName $_.UserPrincipalName -DisplayName $_.DisplayName -FirstName $_.FirstName -LastName $_.LastName -Department -Password $_.Password $_.Department -country $_.Country} | ogv
Get-MsolUser -UserPrincipalName '[email protected]' | select WhenCreated
Normally remove users through GUI interface. But sometimes the GUI is convinced that a particular onmicrosoft.com user is synced even though you see no trace of it in local AD. In this case, the following command sometimes works:
Remove-MsolUser -UserPrincipalName emperor@Palpatine.onmicrosoft.com -Force
use "-Force" above instead of "-Confirm"
or
Remove-AzureADUser -ObjectId "[email protected]"
user, does he exist?
succinctly
$UPN = "[email protected]"
new way that works now using Get-MgUser
if (Get-MgUser -UserPrincipalName $UPN -ErrorAction SilentlyContinue){"there IS a user for $UPN"} else {"there is NO user for $UPN"}
old way that no longer works using the deprecated Get-MsolUser
if (Get-MsolUser -UserPrincipalName $UPN -ErrorAction SilentlyContinue){"there IS a user for $UPN"} else {"there is NO user for $UPN"}
or a little more verbose (new way that works now using Get-MgUser
)
$User = Get-MgUser -UserPrincipalName $UPN -ErrorAction SilentlyContinue -ErrorVariable errorVariable
old way that no longer works using the deprecated Get-MsolUser
$User = Get-MsolUser -UserPrincipalName $UPN -ErrorAction SilentlyContinue -ErrorVariable errorVariable
follow either of the statements above with:
If
($User
-ne
$Null)
{
Write-Host
"$UPN
exists"
-Foregroundcolor green
}
Else
{
Write-Host
"$UPN
does not exist"
-Foregroundcolor yellow
}
user, groups to which he belongs – see groups, show all groups to whom someone belongs
user info
old way that no longer works using the deprecated Get-MsolUser
Get-MsolUser -UserPrincipalName someUser@yourDomain.com | fl
new way that works now using Get-MgUser
Get-MgUser -UserID someUser@yourDomain.com | fl
will likely need to run of these two before attempting to use
Get-MsolUser
. If you get a message with the first that you don‘t
have permission, try the second.
Connect-MgGraph
-Scopes
"User.Read.All"
Connect-MgGraph
-Scopes
"User.Read"
But this doesn't give you many properties. To see all properties:
Get-MgUser -UserID "[email protected]" | Select-Object *
user info
individual - use either UPN:
Get-MsolUser -userprincipalname [email protected] | fl
or objectID:
Get-MsolUser -ObjectId 81701046-cb37-439b-90ce-2afd9630af7d | fl
everyone:
Get-MsolUser | Sort-Object DisplayName,UserPrincipalName
users, list those that match a string
Get-MsolUser -SearchString 'jm'
users, list all sorted by domain – see domain, find all users - sort by domain
user locked out – see locked out
user, rename – see rename user
user, restore when UserPrincipalName has a domain not accepted by the tenant
Restore-MsolUser -UserPrincipalName [email protected] -AutoReconcileProxyConflicts -NewUserPrincipalName [email protected]
user, soft deleted - delete permanantly
Sometimes you run into a situation where you're trying to delete a user but the system claims some other, similarly named user is already clogging up the deleted users
Get-MsolUser -ReturnDeletedUsers -SearchString zombie@undead.com | FL UserPrincipalName, ObjectID
Sometimes, can't return a soft deleted user by name even though you see him right there. In that case, run:
Get-MsolUser -All -ReturnDeletedUsers | ft DisplayName, ObjectId
and grab the appropriate ObjectID so you can delete it that way. Whichever way you get it, once you have it, use the ObjectId to delete:
Remove-MsolUser -ObjectId 8b0b9ca0-a3cf-4444-9b1b-c8dc92e69261 -RemoveFromRecycleBin -Force
Now, finally, you can delete the object you orginally intended
Remove-MsolUser -UserPrincipalName zombie@undead.com -RemoveFromRecycleBin -Force
user soft deleted, restore when UserPrincipalName has a domain not accepted by the tenant
Restore-MsolUser -UserPrincipalName someUser@baddomain.com -AutoReconcileProxyConflicts -NewUserPrincipalName someUser@yourTenant.onmicrosoft.com
userPrincipalName
change:
Set-MsolUserPrincipalName -UserPrincipalName "[email protected]" -NewUserPrincipalName "[email protected]"
userPrincipalName
change individual:
Set-MsolUserPrincipalName -UserPrincipalName "[email protected]" -NewUserPrincipalName "[email protected]"
bulk change - in this case, change a recent batch of added users
Get-MsolUser -All | ?{$_.WhenCreated -gt "6/19/2019 5 pm"} | %{Set-MsolUserPrincipalName -UserPrincipalName $_.UserPrincipalName -NewUserPrincipalName "$($_.UserPrincipalName.split("@")[0])@yourDomain.com"}
Get-Module -ListAvailable -Name Azure -Refresh
or
Get-Module -ListAvailable -Name Azure -Refresh | Select-Object Name, Version, Path, PowerShellVersion
or
(Get-Module -ListAvailable -Name Azure -Refresh).Version
To update, see update Azure module
when was a user created – see user created, when?
Where am I? As in: which tenant am I on? – see which tenant am I on (right below)
Which tenant am I on? - the closest I can find is the command to list
all the licenses that a tenant has available: Get-MsolAccountSku
.
This will return a list of license SKUs.
Embedded in each AccountSkuId will be the tenant name before the :. Pretty hokey.
wild card search - sometimes when someone asks you to add someone to a "group", you don't really know whether they mean a distribution group, an email-enabled group, a Team or a shared mailbox. They often have no idea. So, sometimes you need to go on a fishing expedition to find out more.
email-enabled security groups or distribution groups
Get-AzureADGroup -SearchString "Tech" | select DisplayName
Teams
Teams search is retarded in that the purported wildcard only works for stuff at the beginning; if the string you're looking for is somewhere in the middle, forget it. The code below works around this.
$match
=
"Tech"
$AzureGroups
=
Get-AzureADmsGroup
-All
100000
|
?
{$_.Grouptypes
-ne
""} | select ID,DisplayName,GroupTypes | Sort DisplayName
foreach
($azGroup
in
$AzureGroups)
{
$DisplayName
=
$azGroup.DisplayName
if
($DisplayName
-match
$match)
{
[pscustomObject]@{
#ID = $azGroup.ID
DisplayName
=
$DisplayName
GroupTypes
=
$azGroup.GroupTypes
}
}
}
users (as in shared mailboxes)
Get-MsolUser -SearchString "Tech" | select DisplayName