As regular readers of this blog know, I am keen that Microsoft 365 tenants protect user accounts with multi-factor authentication (MFA), especially Azure AD admin roles. Despite all the promises made by security vendors about products to protect your tenants, the single most effective step that an organization can take is to make sure that accounts use MFA to sign into Microsoft 365. Some years ago, Microsoft reported that MFA blocks 99.9% of account compromise attacks. That statistic remains unquestioned.
Over the years, I’ve written several scripts to help tenant administrators understand the use of MFA within user accounts. The original 2018 article focused on reporting the enablement of accounts to use MFA. I followed up in 2019 with an article explaining how to find unprotected accounts that hold an administrative role. The downside of both articles is that the PowerShell code described in the text uses cmdlets from the old Microsoft Online Services (MSOL) module, which Microsoft is in the process of deprecating. The code still works, but the articles are good examples of advice you can find on the internet that is degrading and will soon be obsolete, as discussed yesterday.
Microsoft would like everyone to rewrite their PowerShell scripts to use Graph API requests or the cmdlets in the Microsoft Graph PowerShell SDK. The unavailability of equivalent API support undermined Microsoft’s aspiration. It’s been possible to report the authentication methods used by Azure AD accounts, but replicating a report showing administrative accounts and their MFA status has been harder.
Graph Registration Details
Enter the Microsoft Graph userRegistrationDetails resource type. This is a beta API that returns a list of authentication methods for users in a manner that’s easier to process than before. Two requests are available:
List: Returns the authentication methods for every Azure AD account in the organization. This isn’t as useful as it seems because the data returned includes guest accounts and unlicensed member accounts used for purposes like room mailboxes.
Get: Returns the authentication methods for a single Azure AD account. In practice, this API is much more useful.
The authentication methods data returned for a user account is shown below. In this case, the account is not MFA-enabled.
Name Value
---- -----
userPrincipalName Andy.Ruth@office365itpros.com
defaultMfaMethod none
isMfaCapable False
isSsprCapable False
@odata.context https://graph.microsoft.com/beta/$metadata#reports/authenticationMethods/userRegistrationDetails/$entity
isSsprEnabled False
id fdc6b121-44b8-4262-9ca7-3603a16caa3e
methodsRegistered {email}
isMfaRegistered False
isPasswordlessCapable False
isSsprRegistered True
userDisplayName Andy Ruth (Director)
The Microsoft Graph PowerShell SDK includes the Get-MgReportAuthenticationMethodUserRegistrationDetail cmdlet (you’ve got to love the automatically generated cmdlet names!). If you run the cmdlet without any parameters, you get the same data as returned by the List API. To return the data for an individual account, include a filter to specify their User Principal Name. For example:
Knowing how to get information about an individual account, we can consider how to check all user accounts paying special attention to those holding one or more administrative roles. I took these steps, using a mixture of Graph API requests and cmdlets from the Microsoft Graph PowerShell SDK:
Connect to the Microsoft Graph SDK. You’ll need to specify the UserAuthenticationMethod.Read.All and AuditLog.Read.All permissions.
Select the beta profile (Select-MgProfile Beta) to ensure that the Graph retrieves the registration information.
Run Get-MgDirectoryRole to find the set of available roles. Note: this cmdlet reports the set of administrative roles assigned in the tenant. There are usually a bunch of unassigned roles that don’t show up. The full set of roles defined in Azure AD can be found by running Get-MgDirectoryRoleTemplate | Select-Object DisplayName, Id | Sort-Object DisplayName. Don’t use role template identifiers as an input to Get-MgDirectoryRoleMember as they won’t work.
For each role, run Get-MgDirectoryRoleMember to find the current holders of the role.
Create an array of accounts that hold administrative roles.
Run Get-MgUser to find the set of licensed user accounts (it’s reasonable to assume that administrative accounts have at least one license).
For each account, get the authentication methods. You can use the Graph API request or the Get-MgReportAuthenticationMethodUserRegistrationDetail cmdlet.
Check if the account holds administrative roles and if so, fetch the roles held by the account.
Output a warning message if the script detects any unprotected administrative accounts (Figure 1).
Figure 1: Highlighting unprotected Azure AD admin roles
The Excel worksheet (Figure 2) is particularly useful in terms of being able to slice and dice the data to generate whatever report you need. For instance, you can see that many of the accounts listed use mobile phones (SMS messages) for the second authentication method. The Microsoft authenticator app is a better option, so you could pull the data about accounts currently using mobile phones to encourage them to move to the authenticator app.
Figure 2: Viewing details of Azure AD admin roles for accounts
So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.!
22 Replies to “How to Report Azure AD Admin Accounts Not Protected by MFA”
This doesn’t take into account Admin Roles assigned to groups so additional code would have to be written to check groups were returned and expand them. it also makes a false assumption that admin accounts are licensed. Best practice that Microsoft advises is use a separate admin account for admin work which is more likely not to be licensed.
Correct. It’s a PowerShell script that doesn’t proclaim itself to be an off-the-shelf solution. The intention is to show people how to approach the problem. As to admin accounts being unlicensed, that might be true in some circumstances, but as I discuss in this article https://practical365.com/protecting-administrator-mailboxes-from-threats/, admin accounts often need to receive email and therefore will have Exchange Online licenses (albeit with controls to stop people sending email to those accounts). Like most of the stuff I post, it’s here for people to read, get ideas from, and hopefully make use of the concepts in their environment.
I have installed the Microsoft.Graph module and connected but I am getting this error when trying to run the script.
Get-MgReportAuthenticationMethodUserRegistrationDetail: The term ‘Get-MgReportAuthenticationMethodUserRegistrationDetail’ is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
You will have to use Beta version of Microsoft Graph PowerShell for this command
Run Select-MgProfile -Name “beta” and then Get-MgReportAuthenticationMethodUserRegistrationDetail for it to work.
The problem that I’m finding is that the MS Graph API doesn’t report the true status of MFA for a user: that only seems to be available via the old MSOL module in PowerShell. I have users who the Graph API returns IsMfaRegistered as True, with default methods showing, etc, but their MFA Status shows as “Disabled” in the M365 MFA web UI, and sign-in logs confirm that they’re only using Single Factor Authentication.
The information from the MS Graph API doesn’t seem to currently be capable of distinguishing between whether someone is actually using MFA, or if they’re just fully registered and configured, but not actually using it. I’m shocked that’s the case, but from everything I’m seeing, that’s the way it is.
There are definitely some issues that Microsoft is working on. It would be good if you could report the problem formally to Microsoft Support so that they can gather the details and escalate to engineering. If you give me the support ticket number, I’ll share it with some folks I know who might be able to accelerate fixes. The Graph SDK is built every month and I know Microsoft is working on a major release, so you never know when a fix might come.
Thanks, Tony! This seems like it’s not really a bug that I could report to Support, though, it’s a lack of functionality….they used to use UserVoice for enhancement requests for lack of functionality like this, but I think they’ve transitioned to their own feedback portal. After some searching, I think this item is related to the current lack of functionality, but the comment from Stephen Talley is the thing that I’m talking about: the functionality from the Per-User MFA screen in MS365 Admin is just missing from the Graph API. https://feedbackportal.microsoft.com/feedback/idea/12d10bfb-10e3-ec11-a81b-000d3a03dba2
I could create a separate feedback item with just what I’ve noticed, if file a Support request if you’re sure that’s the way to go on this.
Loading...
I’ve asked the SDK architect if this specific functionality is due to come to the SDK. Stay tuned.
Loading...
Hi Tony, I wondered if you ever got a reply from the SDK architect regarding this. Unless it’s coming in the near future, I’m going to have to hack something with a webserver with PHP calling PowerShell in order to get accurate data on whether MFA is enforced for a user. Thanks!
Loading...
Nothing so far. Sorry!
Loading...
This doesn’t work for me. After running the script, a browser window opens asking for various access to 365, which I grant, but then the next page doesn’t load:
Secure Connection Failed
An error occurred during a connection to localhost:48722. SSL received a record that exceeded the maximum permissible length.
Error code: SSL_ERROR_RX_RECORD_TOO_LONG
The page you are trying to view cannot be shown because the authenticity of the received data could not be verified.
Please contact the web site owners to inform them of this problem.
Congratulations! You’ve hit an error I have never seen before. This is a PowerShell script, so you can extract lines and run sections at a time until you find where the problem lies and then we might know how to solve the issue.
Is it possible for Powershell to query the Web API (Graph Explorer) and parse the data as a table?
MgGraph is really slow at reporting data. Not sure if it is Powershell that makes it this way or just how the module works but if I run your script (your script is not the issue) or query anything tennant wide on MgGraph, it will take between 2 and 5 minutes due to the hundreds of accounts.
When querying the API directly, results are displayed in less than 2 seconds (see example below):
Hey this works great and performance is miles ahead of the Graph PsModule. Sure, I now have to go trough the trouble to create my Objects but this is well worth it
More efficiency gained by commenting out the following (particularly in larger organizations):
#[array]$Users = Get-MgUser -Filter “assignedLicenses/`$count ne 0 and userType eq ‘Member'” -ConsistencyLevel eventual -CountVariable Records -All
Good example of taking code published here and adapting to make it better… I always emphasize that I am not a pro developer. My code invariably can be improved…
I reported the commands are not working for Update-MgReportAuthenticationMethodUserRegistrationDetail or New-MgReportAuthenticationMethodUserRegistrationDetail so Microsoft removed the Technet articles and now its a broken 404 page
{"id":null,"mode":"button","open_style":"in_modal","currency_code":"EUR","currency_symbol":"\u20ac","currency_type":"decimal","blank_flag_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":100,"top_media_type":"featured_image","featured_image_url":"https:\/\/office365itpros.com\/wp-content\/uploads\/2022\/11\/cover-141x200.jpg","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":true,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Virtual Tip Jar","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"Office 365 for IT Pros","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"Office 365 for IT Pros","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for supporting the work of Office 365 for IT Pros!","payment_confirmation_title":"Office 365 for IT Pros","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":null,"terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}
This doesn’t take into account Admin Roles assigned to groups so additional code would have to be written to check groups were returned and expand them. it also makes a false assumption that admin accounts are licensed. Best practice that Microsoft advises is use a separate admin account for admin work which is more likely not to be licensed.
Correct. It’s a PowerShell script that doesn’t proclaim itself to be an off-the-shelf solution. The intention is to show people how to approach the problem. As to admin accounts being unlicensed, that might be true in some circumstances, but as I discuss in this article https://practical365.com/protecting-administrator-mailboxes-from-threats/, admin accounts often need to receive email and therefore will have Exchange Online licenses (albeit with controls to stop people sending email to those accounts). Like most of the stuff I post, it’s here for people to read, get ideas from, and hopefully make use of the concepts in their environment.
I can also recommend this article/script on the topic of finding MFA users: https://lazyadmin.nl/powershell/list-office365-mfa-status-powershell/ or https://github.com/ruudmens/LazyAdmin/blob/master/Office365/MFAStatus.ps1
I have installed the Microsoft.Graph module and connected but I am getting this error when trying to run the script.
Get-MgReportAuthenticationMethodUserRegistrationDetail: The term ‘Get-MgReportAuthenticationMethodUserRegistrationDetail’ is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
What version of the module are you using? I see the cmdlet in 1.10.0
get-module
ModuleType Version Name ExportedCommands
———- ——- —- —————-
Script 1.10.0 Microsoft.Graph.Applications {Add-MgApplicationKey, Add-MgApplicationPassword, Add-MgSer…
Script 1.10.0 Microsoft.Graph.Authentication {Add-MgEnvironment, Connect-MgGraph, Disconnect-MgGraph, Ge…
Script 1.10.0 Microsoft.Graph.Groups {Add-MgGroupDriveListContentTypeCopy, Add-MgGroupDriveListC…
Script 1.10.0 Microsoft.Graph.Identity.Directo… {Complete-MgDirectoryImpactedResource, Complete-MgDirectory..
You will have to use Beta version of Microsoft Graph PowerShell for this command
Run Select-MgProfile -Name “beta” and then Get-MgReportAuthenticationMethodUserRegistrationDetail for it to work.
The problem that I’m finding is that the MS Graph API doesn’t report the true status of MFA for a user: that only seems to be available via the old MSOL module in PowerShell. I have users who the Graph API returns IsMfaRegistered as True, with default methods showing, etc, but their MFA Status shows as “Disabled” in the M365 MFA web UI, and sign-in logs confirm that they’re only using Single Factor Authentication.
The information from the MS Graph API doesn’t seem to currently be capable of distinguishing between whether someone is actually using MFA, or if they’re just fully registered and configured, but not actually using it. I’m shocked that’s the case, but from everything I’m seeing, that’s the way it is.
There are definitely some issues that Microsoft is working on. It would be good if you could report the problem formally to Microsoft Support so that they can gather the details and escalate to engineering. If you give me the support ticket number, I’ll share it with some folks I know who might be able to accelerate fixes. The Graph SDK is built every month and I know Microsoft is working on a major release, so you never know when a fix might come.
Thanks, Tony! This seems like it’s not really a bug that I could report to Support, though, it’s a lack of functionality….they used to use UserVoice for enhancement requests for lack of functionality like this, but I think they’ve transitioned to their own feedback portal. After some searching, I think this item is related to the current lack of functionality, but the comment from Stephen Talley is the thing that I’m talking about: the functionality from the Per-User MFA screen in MS365 Admin is just missing from the Graph API. https://feedbackportal.microsoft.com/feedback/idea/12d10bfb-10e3-ec11-a81b-000d3a03dba2
I could create a separate feedback item with just what I’ve noticed, if file a Support request if you’re sure that’s the way to go on this.
I’ve asked the SDK architect if this specific functionality is due to come to the SDK. Stay tuned.
Hi Tony, I wondered if you ever got a reply from the SDK architect regarding this. Unless it’s coming in the near future, I’m going to have to hack something with a webserver with PHP calling PowerShell in order to get accurate data on whether MFA is enforced for a user. Thanks!
Nothing so far. Sorry!
This doesn’t work for me. After running the script, a browser window opens asking for various access to 365, which I grant, but then the next page doesn’t load:
Secure Connection Failed
An error occurred during a connection to localhost:48722. SSL received a record that exceeded the maximum permissible length.
Error code: SSL_ERROR_RX_RECORD_TOO_LONG
The page you are trying to view cannot be shown because the authenticity of the received data could not be verified.
Please contact the web site owners to inform them of this problem.
Congratulations! You’ve hit an error I have never seen before. This is a PowerShell script, so you can extract lines and run sections at a time until you find where the problem lies and then we might know how to solve the issue.
Hello Tony
Is it possible for Powershell to query the Web API (Graph Explorer) and parse the data as a table?
MgGraph is really slow at reporting data. Not sure if it is Powershell that makes it this way or just how the module works but if I run your script (your script is not the issue) or query anything tennant wide on MgGraph, it will take between 2 and 5 minutes due to the hundreds of accounts.
When querying the API directly, results are displayed in less than 2 seconds (see example below):
https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$filter=isAdmin+eq+true
Like:
$uri = “https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails?$filter=isAdmin+eq+true”
[array]$Data = Invoke-MgGraphRequest -Uri $Uri
$Data = $Data.Value
$Data is an array holding the results of the API request.
Hey this works great and performance is miles ahead of the Graph PsModule. Sure, I now have to go trough the trouble to create my Objects but this is well worth it
Thanks
Excellent sample code.
More efficiency gained by commenting out the following (particularly in larger organizations):
#[array]$Users = Get-MgUser -Filter “assignedLicenses/`$count ne 0 and userType eq ‘Member'” -ConsistencyLevel eventual -CountVariable Records -All
and replacing it with the following….
$Users = [System.Collections.Generic.List[Object]]::new()
ForEach ($UniqueAdmin in $UniqueAdminRoleHolders) {
$Admin = Get-MgUser -UserID $UniqueAdmin.Id
$Users.Add($Admin)
}
Good example of taking code published here and adapting to make it better… I always emphasize that I am not a pro developer. My code invariably can be improved…
I reported the commands are not working for Update-MgReportAuthenticationMethodUserRegistrationDetail or New-MgReportAuthenticationMethodUserRegistrationDetail so Microsoft removed the Technet articles and now its a broken 404 page
Welcome to the cloud!