Centralised Microsoft 365 Add in deployments with PowerShell

Almost 4 years ago I wrote this article:

Centralised Office 365 Add in deployments with PowerShell

Upon review, it seems that the Finedtime addin is no longer available. I have therefore updated the script:

https://github.com/directorcia/Office365/blob/master/o365-addin-deploy.ps1

to remove this and prevent errors.

If you have any Office addins that you believe should be deployed as a ‘standard’ to all users in a tenant, please let me know and I’ll look at adding them to the script.

blockMsolPowerShell blocks all users if set to true

One of the options in the EntraID Authorization policy in the Default user permissions section is a setting blockMsolPowerShell which means when you dig into it:

Specifies whether the user-based access to the legacy service endpoint used by MSOL PowerShell is blocked or not.

Screenshot 2024-03-12 210611

Using my script:

https://github.com/directorcia/Office365/blob/master/graph-idauthpolicy-get.ps1

you can see whether this is enabled, which it is as shown above.

Screenshot 2024-03-12 205633

With this setting blockMsolPowerShell set to True, then all user access to the msolservice PowerShell commands are blocked as shown above. This applies to users, ordinary and administrators (even Global Administrators, which is the result I tested in the above screenshot). The user can connect to the service BUT they can’t run an msol commands as shown above.

Now given that the msolservice module will be deprecated on March 30, 2024 there shouldn’t be any issue disabling this for ALL users. However, you may want to make sure you test any Outlook add-ins or other third party apps you have in place that might have a dependency on the old msolservice module. The easiest way to achieve this is probably to simply disable the settings and see if problems arise. If they do, just make sure you know how to revert the setting back. I think is going to be the fastest way to determine if and what any dependencies you may have.

I would suggest that unless you have a dependency it should be disabled to improve the security of your environment.

CIAOPS M365 Best Practice Repo is now available

One of the big challenges I have found with securing a Microsoft 365 environment is determining and setting best practices settings for the environment. Recommendations can be found in many different locations from many different sources. I have always done my best to pull all these together and convert them into a single place that I can apply.

With that in mind I am happy to announce the availability of a new CIAOPS Best Practices repository for Microsoft 365here:

https://github.com/directorcia/bp/tree/main

The aim is for it to be the one place you can go that centralizes all the best practice information, security and otherwise, for Microsoft 365.

Let me give you an example of the benefits of this. In the repo you’ll find the following JSON file for an Entra ID authorization policy:

https://github.com/directorcia/bp/blob/main/EntraID/authorization.json

The idea is that you can use a script like I just uploaded:

https://github.com/directorcia/Office365/blob/master/graph-idauthpolicy-get.ps1

To read these settings and compare them to your own environment.

image

You can see the results above when you run this script. The items that are in red do not match the best practice settings that are in repo.

Not only can you use the repo to compare settings but you can also use it to apply settings. Again, you’d just read the JSON setting in the repo and apply that to your environment. Thus, you could take the Entra ID authorization policy JSON and use a script to actually apply, or write,  those settings to your environment. CIAOPS Patron subscribers will have access to the scripts that I develop that will do both the reading and setting of these parameters. Thus, if you don’t to actually write the code to do all this then become a CIAOPS Patron subscriber.

Having these settings available publicly also means people can examine and comment on them and help develop what is best practices in the Microsoft 365 environment. Remember, that best practices are not absolute, they are what works best for the majority of people. You may want to take these as a base and modify them to suit your needs. The benefits of using Github is that is easy to achieve. Thus, you could create your own repo, based on mine, and that as you base for your environment.

The repo also contains links to best practices I have found like this :

https://github.com/directorcia/bp/blob/main/best-practices.txt

That you can also use. Again, the idea is to bring all these resources for Microsoft 365 into a single location.

This best practices repo is far from complete but I wanted to get it out there so people can provide me feedback and we can all build this out to make all our lives easier. Going forward, I plan to spend time developing the repo wiki to provide documentation for all this. However, feel free to take a look at what is there and provide any suggestions for improvement or addition. I’m all ears.

I’ve moved sec-test

show a man moving a lot of files that are contaminated and need special care to move them

It was bound to happen sooner or later, my security testing PowerShell script called sec-test.ps1 is being detected as malware on local machines.

Thus, I have relocated it from more common Office365 repo into the less common examples repo here;

https://github.com/directorcia/examples/blob/main/sec-test.ps1

which contains a range of security testing files that typically get detected as malicious and is generally not recommended to sync locally.

Thus, you can sync the Office365 repo down to your desktop to do all the Microsoft 365 PowerShell connecting and use the utilities there without something in there being detected as malware.

Using PowerShell to get Secure Score history

image

I’ve created a new PowerShell script that is available in my Github repo:

https://github.com/directorcia/Office365/blob/master/mggraph-sscore-get.ps1

that when run, will use the Microsoft Graph (via the mggraph SDK) to return the history of the tenant you login to.

If you do not already have the Microsoft Graph permissions to allow this access you’ll need to allow these once. The scope is securityevents.readwrite.all. You’ll also need to have the Microsoft Graph PowerShell module installed, which can be found here:

https://www.powershellgallery.com/packages/Microsoft.Graph/

Given that connection to the Microsoft Graph can be persistent at times, I’ve also created this simple Graph disconnect script:

https://github.com/directorcia/Office365/blob/master/mggraph-disconnect.ps1

that will also close down any Graph sessions that exist. This is handy when you want to use the Microsoft Graph with other tenants.

I have a few more script ideas for the information you get using this method. More about those soon.

Adding a secret to an Azure Key Vault

An Azure Key Vault is a great location for storing credential securely. In a recent article I cover how to:

Create a new Azure Key Vault

next, I want to cover how you can actually put credentials in there.

image

Step one is to navigate the Azure Key Vault you have created, and select the Secrets option from the menu on the left as shown above. From the menu on the right select +Generate/Import as shown.

image

Simply complete the fields as shown and select the Create button at the bottom of the window.

You will note that your secret (say a password) has a Name and potentially an activation and expiration date if desired. You can also enable or disable if desired.

image

You should now see that the secret has been created as shown above. To view the details simply click on the secret.

image

Here you’ll now see all the details about the secret. The good thing about information about an Azure Key Vault credential is that you can easily update it if required and previous versions will be retained. You can also control access to this individual secret via the Access control (IAM) on the menu on the left hand side.

If you now select the Current version displayed in the middle of the page you will get more details like so:

image

Here, you can update the settings for secret as well as reveal what the secret is by selecting the Show Secret Value button as shown.

image

You see the super secret password shown above.

One of the main reasons reasons for using an Azure Key Vault is that we can access this information also programmatically, for example by using PowerShell.

image

If I connect to Azure using the Azure PowerShell module with a user that has rights to access the vault and secret, I can run a command like:

get-azkeyvaultsecret -vaultname “vaultname” -name “secretname”

and the results will be shown above. But how do I get to the actual secret?

image

Basically, you repeat the previous command but this time assign it to a variable and add the –asplaintext option, like shown above. The command would look like:

$pwd = get-azkeyvaultsecret -vaultname “vaultname” -name “secretname” –asplaintext

Now the secret value (say password) is in the variable $pwd for use in my code.

PowerShell is not the only method you can use to obtain what is in an Azure Key Vault. You can use something like Power Automate and Flow, which I’ll cover off in an upcoming articles. However, PowerShell allows just about any function with vaults including creating, reading, deleting, updating and so on. Thus, using an Azure Key Vault provides a secure yet flexible method of storing credentials you want to protect as well as make potentially portable (i.e. you can use them anywhere on any device that runs PowerShell and connect to the internet).

So an Azure Key Vault provides secure storage for credentials that you can easily access programmatically using something like PowerShell and Power Automate. What can now be achieved with this? Stay tuned to find out more.

Connect to PnP PowerShell script

The latest pnp.powershell module (V2.X and above) now won’t work with PowerShell v5. Thus, I have updated my PnP connection script:

https://github.com/directorcia/Office365/blob/master/o365-connect-pnp.ps1

to accommodate this.

Thus, if you attempt to run this script in PowerShell version 5 with the latest pnp.powershell module you will typically see:

image

and the error is:

Could not load file or assembly ‘System.Management.Automation, Version=7.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ or one of its dependencies. The system cannot find the file specified.

However, when you run the script in PowerShell V7 you’ll see:

image

that the connection is successful.

I have also taken the opportunity to remove the dependency in the script as well on the now depreciated module MSONLINE and replaced it the Microsoft.Graph module.

This kind of signals the beginning of the end for modern cloud modules in PowerShell 5. However, some still require PowerShell 5 but I expect that to change.

In summary, the latest pnp.powershell modules require PowerShell version 7 and I have updated my connection script to accommodate this.