Azure Active Directory B2C Role Template Display name is inconssitent - powershell

I have an automation script for creating applications/resources in a ADB2C Tenant. Recently I ran into a troubling issue with the AzureADPreview.
Basically I create an Application, I create it's service principal then I'm assigning roles to this application. One role in particular that is causing me the issues is: User Administrator, or better said User Administrator | User Account Administrator.
What I mean by this? Basically for one tenant, the cmdlet: Get-AzureADDirectoryRoleTemplate either returns User Administrator or User Account Administrator which is strange.
Here is the code:
# Grant needed Service Principals Permissions
foreach ($displayName in $_.ServicePrincipal.ApplicationRoles) {
$adDirectoryRole = Get-AzureADDirectoryRole | Where-Object { $_.displayName -eq $displayName }
if ($null -eq $adDirectoryRole) {
$adDirectoryRoleTemplate = Get-AzureADDirectoryRoleTemplate | Where-Object { $_.displayName -eq $displayName }
Enable-AzureADDirectoryRole -RoleTemplateId $adDirectoryRoleTemplate.ObjectId | Out-Null
$adDirectoryRole = Get-AzureADDirectoryRole | Where-Object { $_.displayName -eq $displayName }
}
Add-AzureADDirectoryRoleMember -ObjectId $adDirectoryRole.ObjectId -RefObjectId $servicePrincipal.ObjectId | Out-Null
}
The line Enable-AzureADDirectoryRole -RoleTemplateId $adDirectoryRoleTemplate.ObjectId | Out-Null throws an error SOMETIMES when the DisplayName is not User Account Administrator.
Please don't tell me the Azure's API code looks like this:
if (rand() > 0.5f) { role.DisplayName = 'User Administrator'; }
else { role.DisplayName = 'User Account Administrator'; }
What is going on? Why is this the case?
The error thrown
Enable-AzureADDirectoryRole : Error occurred while executing ActivateDirectoryRole
Code: Request_BadRequest
Message: Could not resolve request to a valid role template. A valid value must be specified for 'displayName' or 'roleTemplateId'.
RequestId: 6bc26cc3-ce6d-41d0-abe0-2635d9897b75
DateTimeStamp: Thu, 14 Jan 2021 14:50:19 GMT
Details: PropertyName - roleTemplateId, PropertyErrorCode - PropertyRequired
HttpStatusCode: BadRequest
HttpStatusDescription: Bad Request
HttpResponseStatus: Completed
PS module: 2.0.2.119 AzureADPreview
UPDATE
Since a lot of the comments are missing the point, I think I need to emphasize the issue.
Depending on the tenant when I do the queries mentioned above I get different results. That shouldn't be the case at all, it is a BUG. I don't know where is the bug, in the Azure API, in the PowerShell module, this started some days ago to occur. We didn't change nothing, so I'm blaming the Azure API.
I'm going to attach some photos so you can see clearly the results I'm getting on two different tenants. Please understand that I tested this with 5 or more tenants and this randomness occurs on for each of them.
Some return User Administrator and some return User Account Administrator. This value doesn't change for that particular tenant after it's deployed. But at the deployment time, that value varies.
Look over these photos:
These results are obtained from different tenants!!!

After a lot of back and forth with Azure Support, we reached the conclusion that this was indeed a bug. They made a blog post about renaming some user roles:
A 30-day notice announcing the proposed change was posted to the Message center in M365 Admin center in Message ID MC218295 as of July 2020 with information to customers to update their scripts by August 14, 2020.
The update was finalized in January 20 and today January 29 all my tenants have the same value for the User Administrator role.

Related

Why am I unable to delete a folder permission in Exchange Online?

I am trying to delete permissions on a public folder in Exchange Online. We inadvertently desynced mail-enabled security groups in AD-Connect. This caused all permissions to be lost in the migrated public folders (even after resyncing). I've since recreated the security groups in M365 and have the permissions working on the new groups.
However, I am unable to remove the permissions from the folder for any of the synced security groups. If I do it in the GUI it saves without error, but the permission is still there.
In Powershell, I attempt to remove the permission and receive an error of There is no existing permission entry found for user: Finance Group even though the entry shows there is. The Powershell output is below. This is my first post so I am not allowed to embed images yet - apologies.
Get-PublicFolderClientPermission "\Finance\Finance Departmental Calendar"
Powershell Results for Get-PublicFolderClientPermission
Remove-PublicFolderClientPermission -Identity "\Finance\Finance Departmental Calendar" -User "Finance Group"
Powershell Results for Remove-PublicFolderClientPermission
Thanks in advance.
If the issue is not just inheritance, microsoft has some recommendations here: https://learn.microsoft.com/en-us/exchange/troubleshoot/public-folders/public-folder-permission-issues
# check permissions on the primary pf mailbox specifically
Get-PublicFolderClientPermission \puf1 -User User1 -Mailbox (Get-Mailbox -PublicFolder | ?{$_.IsRootPublicFolderMailbox -eq "True"}).Name
# check permissions on the user's pf mailbox
Get-PublicFolderClientPermission "\puf1" -User User1 -Mailbox pubmbx1
# check the hierarchy sync status, and compare between pf mailboxes
$s = Get-PublicFolderMailboxDiagnostics pubmbx1 -IncludeHierarchyInfo
$s.HierarchyInfo
$s.SyncInfo.LastAttemptedSyncTime.LocalTime
$s.SyncInfo.LastFailedSyncTime.LocalTime
$s.SyncInfo.LastSyncFailure
# manually resync permissions to entire pf mailbox
Update-PublicFolderMailbox pubmbx1 -InvokeSynchronizer
Be careful of making changes in O365 if you're in hybrid config. You probably don't want to overwrite the newly-added permissions in O365 by surprise sync up from on-prem
In my anectodal experience, 365 also needs the original user object to exist for some reason. Probably buggy behavior with how it resolves the user name on permission entries. If possible, try and resync the old groups to 365
I have had to export, delete, and recreate a mailbox or publicfolder to fix certain rare situations

How to remove users that have roles scoped to a specific Azure AD Administrative Unit via Powershell

I am trying to understand the correct PowerShell command to remove one or more users which have a role granted to them which is scoped over the members of an Administrative Unit.
For example, a Help Desk Employee that is empowered with Authentication Administrator over an AU that contains all the staff at their office location.
It would appear that the correct way to do this using Azure AD Powershell would be to use Remove-AzureADMSScopedRoleMembership but I cannot find any documentation on what inputs are desired for this command or if this is even the right method to reach the desired outcome.
Documentation: https://learn.microsoft.com/en-us/powershell/module/azuread/remove-azureadmsscopedrolemembership?view=azureadps-2.0
Iterations I have tried:
Remove-AzureADMSScopedRoleMembership -id "Object ID of user with scoped role" -ScopedRoleMembershipId "/administrativeUnits/ObjectId of AU"
Remove-AzureADMSScopedRoleMembership : Error occurred while executing RemoveMSScopedRoleMembership
Code: BadRequest
Message: Resource not found for the segment
Remove-AzureADMSScopedRoleMembership -id "Object ID of AU with scoped roles" -ScopedRoleMembershipId "Object ID of user with scoped role"
Remove-AzureADMSScopedRoleMembership : Error occurred while executing RemoveMSScopedRoleMembership
Code: BadRequest
I have reproduced in my environment and got expected results as below and followed Microsoft-Document:
Firstly, I have added a scopedrole as below:
Connect-AzureAD
$User = Get-AzureADUser -SearchString "Display Name of User"
$Role = Get-AzureADDirectoryRole | Where-Object -Property DisplayName -EQ -Value "User Administrator"
$RoleMember = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo
$Unit = Get-AzureADAdministrativeUnit | Where-Object -Property DisplayName -Eq -Value Test
$RoleMember.ObjectId = $User.ObjectID
Add-AzureADScopedRoleMembership -ObjectId $unit.ObjectId -RoleObjectId $Role.ObjectId -RoleMemberInfo $RoleMember
I have taken ScopedRoleMembershipId from microsoft Graph api using below request:
https://graph.microsoft.com/v1.0/directory/administrativeUnits/{admin-unit-id}/scopedRoleMembers
Then used below command to remove user and I followed Microsoft-Document:
Remove-AzureADScopedRoleMembership -ObjectId $unit.ObjectId -ScopedRoleMembershipId "08ovlLXBT0CMQ7kJaZRJU"
Try to follow the above process user will be removed as mine got.

Determine if an account is restricted to deny interactive login

Problem: Determine accounts with password does not expire across multiple environments, excluding accounts that can not be used to sign in interactively.
I am attempting to use powershell to generate a report that will show me account's who's passwords are set to never expire, however I want to exclude service accounts (accounts that have been restricted via GPO to only logon as service, similar process described in http://paulasitblog.blogspot.com/2017/01/deny-interactive-logon-for-service.html). I have found a few ways to pull this via powershell however it requires me to generate a list of servers, and run against accounts 1 at a time to see if they are restricted. Is there any switch that can be added to this that would be able to determine if an account has interactive logon disabled?
Current script I am using:
$b = $env:COMPUTERNAME
$c = Get-Date -Format "MM/dd/yyyy"
get-aduser -filter * -properties Name, PasswordNeverExpires |
where {$_.passwordNeverExpires -eq "true" } |
Select-Object DistinguishedName,Name,Enabled |
Export-csv Export-csv c:\Automation\$c-pw_never_expires-$b.csv -NoTypeInformation
The closest solutions I was able to find:
https://morgantechspace.com/2014/11/set-allow-log-on-locally-user-rights-via-powershell-cmd-csharp.html
Issue: This requires a 3rd party .dll, and I am unsure if this can be integrated to provide a single output.
https://www.powershellbros.com/get-user-rights-assignment-security-policy-settings/
This requires me to generate a server list, then run against the accounts to determine which accounts are limited.

Powershell - last logged on user - same input, different output

UPDATE
# HAL9256
Your answer really made me think!
I did some more googling, and found this website which offers another approach
http://blogs.technet.com/b/heyscriptingguy/archive/2012/02/19/use-powershell-to-find-last-logon-times-for-virtual-workstations.aspx
So far, it works!
I remote into another server to run a powershell script that displays the last logged on user.
Several things
It only works when I run it in the context of a service account, not
the Administrator
It takes several minutes to output
But when I run it in the contenxt of a service account, I get different output for the same input
$line_array = #()
$multi_array = #()
[hashtable]$my_hash = #{}
foreach ($i in $args){
$line_array+= $i.split(" ")
}
foreach ($j in $line_array){
$multi_array += ,#($j.split("="))
}
foreach ($k in $multi_array){
$my_hash.add($k[0],$k[1])
}
$Sender_IP = $my_hash.Get_Item("sender-ip")
$eventList = #()
Get-EventLog "Security" -computername $Sender_IP `
| Where -FilterScript {$_.EventID -eq 4624 -and $_.ReplacementStrings[4].Length -gt 10 -and $_.ReplacementStrings[5] -notlike "*$"} `
| Select-Object -First 2 `
| foreach-Object {
$row = "" | Select UserName, LoginTime
$row.UserName = $_.ReplacementStrings[5]
$row.LoginTime = $_.TimeGenerated
$eventList += $row
}
$userId = $eventList[0].UserName
$userId
For instance, I invoke the script on commandline with
script.ps1 "sender-ip=10.10.10.10"
The first time I run it, it outputs the user's Window's logon name
The second time I run the same script with same input, it outputs the same service account I used to run the powershell script with
And when I try to run same script with same input, I get the output of this same service account.
~~~~~~~
Next, I try to run the script with another IP address
First time I run the script it outputs the Window's logon name
Second time I run the script, it outputs that same service account from which the powershell script is running
~~~~~~~
This seems to be a pattern. First time script it run, it return correct input, second time it is run, it returns the service account.
Why is this happening?
How to make the script always return the correct output no matter how many times it is invoked?
How to troubleshoot this?
This is because of how your script gets the information about the last logged on user.
You are getting the last logged on user from the security event log. This logs everyone who "logs on" to the computer... including accesses by WMI, service accounts, etc.
What's happening is:
Before Script Runs
Contoso\User1 logs onto computer
EventID 4624 - Logon Success - Contoso\User1 is Logged
Run Script the First time
Script runs as Contoso\ServiceAccount
Script access computer Via WMI to pull Security Event Log
Security Event Log shows last logged on user was Contoso\User1
EventID 4624 - Logon Success - Contoso\ServiceAccount is Logged
EventID 4634 - Logoff Success - Contoso\ServiceAccount is Logged
Run Script the Second time
Script runs as Contoso\ServiceAccount
Script access computer Via WMI to pull Security Event Log
Security Event Log shows last logged on user was Contoso\ServiceAccount
EventID 4624 - Logon Success - Contoso\ServiceAccount is Logged
EventID 4634 - Logoff Success - Contoso\ServiceAccount is Logged
This is because in order to access WMI, you have to authenticate on the computer. Essentially, WMI uses your service account to "log onto" the computer, access the information that it needs, returns the information, and logs off.
This is why you are getting the weird results.
To fix this, you have 3 options:
1.Continue to use the same script to pull out the event log entries. Add code to Filter out the service account name. i.e. use this to get the username:
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name
Then use the "Where -FilterScript" to filter out the user that the script is running as.
The only downside to this method, is that there could be a lot of other service accounts that are running various scheduled tasks, or startup scripts that could change who the "last" logged on user was. It may be better to pull the last 5 logged on users, and then you would have a better idea of what's going on.
2.Use this code to get the currently logged on user:
(gwmi -class win32_computerSystem -computer "ComputerName").username
3.A different and unique way of getting the last logged on user is to use the last write access time on the user profile file (ntuser.dat). Typically only a user logging in "Interactively" will get have a user profile created.
(Get-ChildItem C:\users\*\ntuser.dat -Force | select #{e={(Split-path $_.Directory -Leaf)}},last* | sort lastwritetime -Descending

O365 PowerShell: Find users that have specific product license services enabled

I'm using the following article View account license and service details with Office 365 PowerShell to try to obtain a report of all users in our tenant where the product license Office 365 Enterprise E3 is assigned but with only the the service Exchange Online (Plan 2) enabled.
The article suggests this can be done with a command similar to the following:
Get-MsolUser |
Where-Object {
$_.isLicensed -eq $true
-and $_.Licenses[0].ServiceStatus[16].ProvisioningStatus -eq "Enabled"
}
In my case [16] being the 17th service in the list for Office 365 Enterprise E3.
There are additional lines before to set the criteria for the rest of the services as "disabled" but hopefully you get the idea however, the article also states that the index number reflects the order that the product license and service plan appears when running either of the below script blocks:
Licenses:
Get-MsolUser -UserPrincipalName o365.test1#tenant.com | Format-List DisplayName,Licenses
Services:
Get-MsolUser -UserPrincipalName o365.test2#tenant.com).Licenses.ServiceStatus
The issue with the above is that many users have different combinations of plans enabled so for some, a license index of [0] would refer to a different service plan. e.g. user1 has Visio Online Plan 2 and Office 365 Enterprise E3 product licenses assigned but user2 only Office 365 Enterprise E3. Index [0] in this instance would be different making the initial script block useless in finding all users with a specific service enabled regardless of combination of product licenses assigned.
Am I missing something here?
Not really sure how I missed it on my searches but the following will provide the information I require without the need to script it: Office 365 License Reporting and Management Tool -Assign Remove Licenses in Bulk
I know it's a bit old but today I've had exactly same problem and managed to write a quick function which just does what you asked for.
[cmdletbinding()]
param (
#Provide service name e.g. SWAY
[Parameter(Mandatory)]
[string]$Service,
#Specifies if to search for enabled or disabled service. Success = enabled.
[Parameter(Mandatory)]
[ValidateSet("Success","Disabled")]
[string]$Status
)
foreach ($User in ($Users = Get-MsolUser -All) ) {
$ServiceStatus = $user.licenses.ServiceStatus
$ProvisionName = $ServiceStatus | Where {$_.ServicePlan.ServiceName -eq "$Service" }
$Data = [PSCustomObject]#{
"USER" = $User.UserPrincipalName
"Software" = $ProvisionName.ServicePlan.ServiceName
"Status" = $ProvisionName.ProvisioningStatus
}
$Data | Where {$_.Status -eq "$Status" }
}