This blog will be about me experimenting with Conditional Access and with experimenting, I mean to change the JSON myself and upload it! Why? Just for fun and to include some stuff that isn’t available in the GUI.
Some time ago I was inspired to check something out. Of course, almost all schools are working with Teams nowadays and so is my son’s school. After installing teams and logging in with my son’s Office365 account, I was asked the famous question if I’d wanted to “allow my organization to manage my device”.
![](https://call4cloud.nl/wp-content/uploads/2020/11/image.png)
Okay… So the school allows anyone to register a device to their tenant? I guess the school has a lot of devices to manage. If it was up to me, I would configure the MDM user scope so only teachers could enroll their device to MDM but that’s not what this blog is about.
I will divide this blog into multiple parts
1. The Conditional Access experiment
I could not help my curiosity, so I tried to open portal.azure.com with his account to check out how many devices are registered. It’s good they have disabled access to the Azure AD Portal but luckily there is always PowerShell. Within a few minutes, I had a big CSV file with all devices and the persons who registered it.
Of course, they could’ve blocked access to read other users with this PowerShell command:
Set-MsolCompanySettings -UsersPermissionToReadOtherUsersEnabled $false
I wrote about the pros and cons of this command in this blog a while ago.
But I find it hard to believe there is no option to block “all PowerShell” with Conditional Access. When you have implemented a conditional access rule targeted to the Azure management app, some PowerShell connections will be blocked like login-azurermaccount, but what about connect-azuread and connect-msolservice?
Let’s take a look at what Microsoft has to say about the Azure Management App?
*Source: https://docs.microsoft.com/en-us/azure/role-based-access-control/conditional-access-azure-management
I configured a conditional access rule to test it out. As stated, it simply doesn’t block connect-azure ad or connect-msolservice.
Of course, when targeting all cloud apps your PowerShell sessions will also be blocked. In my opinion, targeting all Cloud Apps is a bad idea. Like my fellow security enthusiasts Workplace Ninja’s write in this blog below.
But targeting all cloud apps and trying to login with all kinds of PowerShell modules showed me something useful in the sign-in log.
![](https://call4cloud.nl/wp-content/uploads/2020/11/image-1.png)
00000002-0000-0000-c000-000000000000 –> AAD Graph API
797f4846-ba00-4fd7-ba43-dac1f8f63013 –> Azure Management
00000003-0000-0000-c000-000000000000 –> Microsoft Graph
1b730954-1685-4b74-9bfd-dac224a7b894 –> Azure Ad Powershell
So, Microsoft has the possibility to block them, just not with the Conditional Access GUI. There are no options to select Azure Active Directory Powershell. It’s a good thing I am not into GUI’s a lot…
UPDATE 20-11-2020 ( I guess Microsoft is working on this?)
![](https://call4cloud.nl/wp-content/uploads/2020/11/image-26.png)
Check out this script (You will notice the Azure Ad PowerShell ID 1b730954-1685-4b74-9bfd-dac224a7b894 ):
login-azurermaccount
$context = Get-AzureRmContext
$tenantId = $context.Tenant.Id
$SubscriptionId = $context.Subscription
$cache = $context.TokenCache
$cacheItem = $cache.ReadItems()
$refreshtoken=$cacheItem[$cacheItem.Count -1].refreshtoken
$body = "grant_type=refresh_token&refresh_token=$($refreshToken)&resource=74658136-14ec-4630-ad9b-26e160ff0fc6"
$apiToken = Invoke-RestMethod "https://login.microsoftonline.com/$tenantId/oauth2/token" -Method POST -Body $body -ContentType 'application/x-www-form-urlencoded'
$headersazurerm = @{
'Authorization' = 'Bearer ' + $apiToken.access_token
'Content-Type' = 'application/json'
'X-Requested-With'= 'XMLHttpRequest'
'x-ms-client-request-id'= [guid]::NewGuid()
'x-ms-correlation-id' = [guid]::NewGuid()
}
$url = "https://main.iam.ad.ext.azure.com/api/Policies/"
$content = '{"users":{"allUsers":1,"included":{"groupIds":[],"userIds":[]},"excluded":{"groupIds":[],"userIds":[]}},"usersV2":{"allUsers":1,"included":{"allGuestUsers":false,"roles":false,"usersGroups":false,"roleIds":[],"groupIds":[],"userIds":[]},"excluded":{"allGuestUsers":false,"roles":false,"usersGroups":true,"roleIds":[],"groupIds":[],"userIds":[]}},"servicePrincipals":{"allServicePrincipals":2,"included":{"ids":["00000003-0000-0000-c000-000000000000","00000002-0000-0000-c000-000000000000","797f4846-ba00-4fd7-ba43-dac1f8f63013","
1b730954-1685-4b74-9bfd-dac224a7b894"]},"excluded":{"ids":[]},"includeAllMicrosoftApps":false,"excludeAllMicrosoftApps":false,"userActions":null},"servicePrincipalsV2":{"allServicePrincipals":2,"included":{"ids":["00000002-0000-0000-c000-000000000000","00000003-0000-0000-c000-000000000000","1b730954-1685-4b74-9bfd-dac224a7b894"]},"excluded":{"ids":[]},"includedAppContext":null,"shouldIncludeAppContext":false},"controls":{"controlsOr":true,"blockAccess":false,"challengeWithMfa":false,"compliantDevice":true,"domainJoinedDevice":true,"approvedClientApp":false,"claimProviderControlIds":[],"requireCompliantApp":false,"requirePasswordChange":false,"requiredFederatedAuthMethod":0},"sessionControls":{"appEnforced":false,"cas":false,"cloudAppSecuritySessionControlType":0,"signInFrequencyTimeSpan":{"type":0,"value":0},"signInFrequency":0,"persistentBrowserSessionMode":0},"conditions":{"minUserRisk":{"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"minSigninRisk":{"noRisk":false,"lowRisk":false,"mediumRisk":false,"highRisk":false,"applyCondition":false},"devicePlatforms":{"all":2,"included":{"android":false,"ios":false,"windowsPhone":false,"windows":true,"macOs":false},"excluded":{"android":false,"ios":false,"windowsPhone":false,"windows":false,"macOs":false},"applyCondition":true},"locations":{"includeLocationType":0,"excludeAllTrusted":false,"applyCondition":false},"namedNetworks":{"includeLocationType":0,"excludeLocationType":2,"includeTrustedIps":false,"excludeTrustedIps":false,"includedNetworkIds":[],"excludedNetworkIds":[],"includeCorpnet":false,"excludeCorpnet":false,"applyCondition":false},"clientApps":{"specificClientApps":true,"webBrowsers":false,"mobileDesktop":true,"exchangeActiveSync":false,"onlyAllowSupportedPlatforms":false,"applyCondition":true},"clientAppsV2":{"webBrowsers":false,"mobileDesktop":true,"modernAuth":true,"exchangeActiveSync":false,"onlyAllowSupportedPlatforms":false,"otherClients":false,"applyCondition":true},"time":{"all":0,"included":{"type":0,"timezoneId":null,"dateRange":{"startDateTime":"10/7/2020 12:00:00 AM","endDateTime":"10/8/2020 12:00:00 AM"},"daysOfWeek":{"day":[0,1,2,3,4,5,6],"startTime":"10/7/2020 12:00:00 AM","endTime":"10/8/2020 12:00:00 AM","allDay":false},"isExcludeSet":false},"excluded":{"type":0,"timezoneId":null,"dateRange":{"startDateTime":"10/7/2020 12:00:00 AM","endDateTime":"10/8/2020 12:00:00 AM"},"daysOfWeek":{"day":[0,1,2,3,4,5,6],"startTime":"10/7/2020 12:00:00 AM","endTime":"10/8/2020 12:00:00 AM","allDay":false},"isExcludeSet":false},"applyCondition":false},"deviceState":{"includeDeviceStateType":0,"excludeDomainJoionedDevice":false,"excludeCompliantDevice":false,"applyCondition":false}},"isAllProtocolsEnabled":true,"isUsersGroupsV2Enabled":true,"isCloudAppsV2Enabled":false,"version":0,"policyId":"45953875-788b-4fd9-8302-dd10390fe801","policyName":"BLOCK - PowerShell_Access_NonManaged_devices","applyRule":true,"policyState":1,"usePolicyState":true,"baselineType":0}'
Invoke-RestMethod –Uri $url –Headers $headersazurerm –Method Post -Body $content -ErrorAction Stop
This script targets the 3 apps I showed you and only grants access to them from a managed device. You can choose to exclude some users who really need it.
Let’s try it, open a PowerShell prompt and try to connect to AzureAd
![](https://call4cloud.nl/wp-content/uploads/2020/11/image-2.png)
![](https://call4cloud.nl/wp-content/uploads/2020/11/image-3.png)
Great!! It works. You can check it out, in the Sign In logs
![](https://call4cloud.nl/wp-content/uploads/2021/09/image-18-1024x52.png)
And the alert details:
![](https://call4cloud.nl/wp-content/uploads/2021/09/image-19.png)
2. Microsoft Their Solution
Looking at a hidden MS Docs telling us how to block PowerShell for Education
Blocking PowerShell for EDU Tenants – School Data Sync | Microsoft Docs
You will probably notice these lines of text, mentioning the possibility to “Block PowerShell for everyone except a list of admins”
![](https://call4cloud.nl/wp-content/uploads/2022/01/image-33.png)
That’s cool!, let’s check it out, shall we?
#Connect to Azure AD and establish a session
$session = Connect-AzureAD
#set the PowerShell App ID as a variable
$appId = "1b730954-1685-4b74-9bfd-dac224a7b894"
#Ensure the service principal is present in the tenant, and if not add it
$sp = Get-AzureADServicePrincipal -Filter "appId eq '$appId'"
if (-not $sp) {
$sp = New-AzureADServicePrincipal -AppId $appId
}
#Require user assignment for the PowerShell app
Set-AzureADServicePrincipal -ObjectId $sp.ObjectId -AppRoleAssignmentRequired $true
# Assign the default app role (0-Guid) to the current user
$admins = import-csv c:\temp\psadmins.csv
Foreach ($admin in $admins) {
$user = Get-AzureADUser -objectId $admin.userprincipalname
New-AzureADServiceAppRoleAssignment -ObjectId $sp.ObjectId -ResourceId $sp.ObjectId -Id ([Guid]::Empty.ToString()) -PrincipalId $user.ObjectId
}
Write-host "Script Complete. PowerShell is now restricted."
Looking at the script above, again uses the AppId 1b730954-1685-4b74-9bfd-dac224a7b894 I mentioned earlier and it makes sure the PowerShell app requires a user assignment, so only the admin’s are allowed to use it. Looks pretty neat! But Please, pretty please… be very careful with this 🙂
Conclusion:
It’s nice to see you can completely block remote PowerShell to your tenant. I had some bad feelings about breaking something by blocking this but so far everything I tested works! Enrolling a new device into AzureAd with autopilot -online works without any problems (don’t forget to exclude your users who need this).
I will be testing some more next week, to make sure nothing breaks. Do you know what else is great? You can also use this trick to exclude some stuff!
Hello! Love your work, a quick update. It seems as though running Microsoft’s solution no longer works. There is no AppID=1b730954-1685-4b74-9bfd-dac224a7b894 in our tenant. Any thoughts or updates?
🙂 as discussed on linkedin.. without global admin… it isn’t going to work.. nice to hear it still works !
There is in fact such an object, you just don’t have acces sto the object from conditional access or the script.. for some reason.
1b730954-1685-4b74-9bfd-dac224a7b894 Azure Active Directory PowerShell
Solution 1 works great for us while testing, question is how can we modify the script to block access based on location? We would like to block Azure Active Directory Powershell from any location except the trusted IPs.
How did you workout the structure of the conditional access $content variable? I want to make a similar policy that requires MFA every day for specific scripting environments.
These are some of the Ids I thought might be useful to target,
Azure Active Directory PowerShell – 1b730954-1685-4b74-9bfd-dac224a7b894
Microsoft Graph PowerShell – 14d82eec-204b-4c2f-b7e8-296a70dab67e
Graph Explorer – de8bc8b5-d9f9-48b1-a8ad-b748da725064
Microsoft Intune PowerShell – d1ddf0e4-d672-4dae-b554-9d5bdfd93547
Microsoft Azure CLI – 04b07795-8ddb-461a-bbee-02f9e1bf7b46
Let me check… as that blog is already a bit old and maybe outdated 🙂
I tried adapting your json to my scenario and I used this powershell cmdlet to get the token, https://github.com/JustinGrote/Az.PortalAPI
But I’m getting Access Denied, that’s with global admin, maybe the API is no longer available?
401 – Unauthorized: Access is denied due to invalid credentials.
Server Error
401 – Unauthorized: Access is denied due to invalid credentials.
You do not have permission to view this directory or page using the credentials that you supplied.
I am trying to block Access to Azure AD powreshell from un-managed devices. I tried the script you shared in Solution 1 however it does not seems to be working. The policy is created however its not applied to the user when i try to connect using Connect-azure AD.
In sign-in logs the policy is not applied: