↓ Skip to main content

Posts

2020

10 suggestions to improve your next PowerShell script

·9 mins
Most of the time PowerShell is my favourite choice to automate processes and tasks. In order to improve the maintainability of my scripts I usually try to focus on some standards combined with a clean scripting style. In this post I want to show you 10 suggestions to improve your next PowerShell script. I’ve tried to order the suggestions according to an actual PowerShell starting from the very first line till the last line. 1. Script prerequisites # Your PowerShell script might need specific modules or elevated user rights to run. The #Requires statement ensures that these prerequisites are met before the actual script get’s executed. So you don’t need to implement your own checks to verify prerequisites. Simply use the #Requires statement at the very first line of your script. Find out more about #Requires statement. Modules # Another benefit of specifying the modules within the requires statement is that scripts hosted on the PowerShell Gallery automatically install the modules mentioned in the #Requires list. To make sure a specific module is installed use: #Requires -module "Microsoft.Graph.Intune" To ensure a module with a specific version is available:

How I migrated my Ghost blog to Jekyll

·4 mins
Another migration of my blog? After running it for almost three years I thought it’s time for another change. The Ghost platform introduced a lot of changes and updates (with features that I don’t need) and caused me quite some expenses on my Azure subscription (around 50$ each month). Furthermore I wanted someting looking more clean with more focus on the writing part without a lot of fancy add-ons and functionalities. But it still had to cover features like tag summaries, yearly archive and a site search (Ghost doesn’t ship with those features out of the box). Because static sites seem to be a thing now I thought let’s hop onto the static site generator train. I did some subjective research and decided that it will be Jekyll. I’ve chosen Jekyll because it’s quite easy to understand compared to hugo. Although hugo offers GraphQL which allows you to generate blog posts basically from any source including a REST API and Ghost has such an API in place which provides access to all posts. To sum up the evolution of my blog: 2017 - 2018: Wordpress (hosted on a free hoster) 2018 - 2020: Ghost (hosted on Azure) 2020 - 20xx: Jekyll (hosted on GitHub Pages) Since the beginning of my blog I had my DNS zones running on Cloudflare including CDN features. When I migrated from Wordpress to Ghost I also migrated the comments to Disqus -> so for this migration I didn’t need to change anything regarding comments.

Exploring the new Microsoft Graph PowerShell Module(s)

·3 mins
Microsoft is working on a new set of PowerShell modules grouped under the umbrella of Microsoft.Graph that will (hopefully) cover all the Microsoft Graph resources available. I’ve already used some of them for my Conditional Access Documentation Script and thought they have some notable features worth sharing. Advantages and changes # The Microsoft Graph modules use the new Microsoft Authentication Library (MSAL) instead of the old Azure AD Authentication Library (ADAL). The MSAL library in the modules implements a token cache which persists the access and refresh tokens. MSAL caches a token after it has been acquired. Application code should try to get a token silently (from the cache), first, before acquiring a token by other means. - Microsoft docs The token cache persists system reboots and re-opening PowerShell sessions. The module allows you to obtain tokens either for authentication via client credentials (certificate only) or device code flow. Furthermore, the new modules support a really broad spectrum of available entities on the Graph API. From an EM+S perspective this means for example: groups, users, identity protection, conditional access, and some of the Intune app management commands are also starting to appear. Just be aware that the modules are currently published as pre-release. If you encounter any issues share them with the development team on GitHub and submit issues or even better contribute directly to the project.

Validating a GUID with PowerShell

For some recent Microsoft Graph scripts I wanted to translate some Azure AD Object ID / GUID entries to their respective display name. The array with the GUID’s contained already some readable text. Of course I only wanted to translate the GUID entries with according Graph API requests. Otherwise the Graph requests would fail. Google offered only some fancy regex functions and helpers but I had that .NET function in my mind which looks much nicer compared to whatever regex pattern that I don’t understand. "applications": { "includeApplications": [ "797f4846-ba00-4fd7-ba43-dac1f8f63013", "Office365" ] } So I needed a way to test a string for a valid GUID and only invoking the Graph calls for GUID values. Matching a GUID with a regex # I found the following regex on this site: "d815c3bc-9c49-4633-9d16-29808242d063" -match '(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$' Matching a GUID with the .NET method # Instead of the complex regex we can invoke this nice .NET member method which returns true or false based on the input: [guid]::TryParse("d815c3bc-9c49-4633-9d16-29808242d063", $([ref][guid]::Empty)) I guess that’s much more convenient. Helper Function # Here’s a helper function which can be used in PowerShell scripts:

Document Conditional Access Configuration with my Modern Workplace Concierge

Documenting things sucks. If it involves a lot of klick(edi klack klack) in portals and copying information around even more. But there’s hope. And it’s called automation. For the Intune part Thomas Kurt did already an awesome job with his IntuneDocumentation. Now the Modern Workplace Concierge is ready to help you with documenting your Conditional Access configuration. I promise you: we will get through this within under 15 minutes! Afterwards you can make an impression on your fellow Enterprise Mobility teammates. What’s inside? # A Conditional Access policy is returned by the Microsoft Graph API in the following JSON representation: { "id": "714b5737-5f13-415e-bf96-d659f3a5928e", "displayName": "PROD - Admin protection - Azure management: Require MFA", "createdDateTime": null, "modifiedDateTime": null, "state": "enabled", "grantControls": { "operator": "OR", "builtInControls": [ "mfa" ], "customAuthenticationFactors": [], "termsOfUse": [] }, "conditions": { "signInRiskLevels": [], "clientAppTypes": [], "platforms": null, "locations": null, "deviceStates": null, "applications": { "includeApplications": [ "797f4846-ba00-4fd7-ba43-dac1f8f63013" ], "excludeApplications": [], "includeUserActions": [] }, "users": { "includeUsers": [ "All" ], "excludeUsers": [], "includeGroups": [], "excludeGroups": [ "04988d96-ad01-4569-9aee-a199a1cb4f8e" ], "includeRoles": [], "excludeRoles": [] } }, "sessionControls": null } That’s not really human readable. Especially the object id’s (32 character UUIDs) make it difficult to guess to which users or apps a policy is assigned. But an API has definitely other goals than showing pretty formatted reports.

I said Connect-AzureAD and not sign-out and re-sign-in!

·1 min
If you are using the “AzureAD” PowerShell module (also applies to the AzureADPreview) you have probably noticed that the Connect-AzureAD Cmdlet ignores existing access tokens and initiates a new sign in to Azure AD even if you are already signed in. Prompt you get when calling the "Connect-AzureAD" cmdlet Long story short, I got annoyed every time when I accidentally recalled Connect-AzureAD (mostly when working with Scripts) until I found this amazing hint on technet and now I want to (re-)share it with you. In your PowerShell scripts simply use the following snippet to connect with Azure AD / check your connection and you wont get any sign-in prompts if you are already connected! Reusing the access token for the MsOnline module # The Azure AD PowerShell access token which gets stored can also be used to connect to the MsOnline resources (because certain attributes like strong authentication details are not available with the AzureAD modules): $token = [Microsoft.Open.Azure.AD.CommonLibrary.AzureSession]::AccessTokens Connect-MsolService -AccessToken $token.AccessToken.AccessToken

Generate a report about assigned Azure Active Directory roles

·2 mins
The Azure AD portal does not really provide an overview about all directory role assignments in your tenant. If you want to review existing Azure AD Directory roles a csv report will probably better server your needs. Therefore I created a PowerShell script to export the role assignments. The Azure AD Portal only displays limited information about the assignments ### PowerShell Script Find the PowerShell script in my techblog GitHub Repository. Make sure that you have the AzureAD PowerShell module installed before running the script. You can install it by running “Install-Module AzureAD”. PowerShell script output Report # The report contains three columns: Role (name of the directory role) Note that the Global Administrator Role is represented as Company Administrator Member If the role is assigned to a user its the UserPrincipalName If the role is assigned to a service principal its the display name with the Azure AD application ID in the brackets ObjectType Indicates whether the role is assigned to user account or a service principal CSV file containing all assigned directory roles Comparing reports # You can compare two reports with the following PowerShell code:

Detect Deleted User Accounts in Azure Active Directory

·2 mins
An account in your Azure Active Directory got deleted and you want to examine who initiated the delete action? Sounds very simple but if you do not want to search your logs manually things become a little bit trickier. The challenge # When a user gets deleted and you only remember it’s userPrincipalName you wont be able to to search for a match. And I doubt that you memorized the Azure AD object id of that user. Here’s what the Azure AD Audit log shows us: The userPrincipalName attribute will get the Azure AD object ID as prefix: userPrincipalName before deletion: [email protected] userPrincipalName after deletion: [email protected] By having a closer look to the Azure Active Directory Audit logs you will notice that the filtering or search capabilities are limited in terms of searching for a specific target: Search is case-sensitive and only supports ‘starts with’ operator Which means we cannot search for the userPrincipalName. The only option in the Azure AD Audit Logs would be to download the logs and perform a search within a text editor which is not really feasible nor efficient.

Managing the new Microsoft Edge Browser with Intune

·7 mins
With the availability of the new Edge browser based on chromium I gained the first experiences about configuring the browser in an enterprise environment. Of course I want to share those with you. This post hopefully helps you to roll-out and configure the new Edge Browser with Microsoft Intune. Install the new Edge Chromium with Intune # The installation of Edge is not the main topic of this post. The Edge browser is available in Intune as built-in app type like the Office 365 suite. More information about the installation process is available here. Set Edge Chromium as default browser # Default applications are configured on the Windows 10 operating system level via app associations. The current app associations of a device can be exported with dism and the command: Dism /Online /Export-DefaultAppAssociations:"appassociations.xml" Which will produce a file containing all associations. For setting Edge as the default browser this one is sufficient: To deploy an app associations file with Intune it needs to be base64 encoded. I used the base64encode online tool. Intune configuration # To distribute the default app association configure the following OMA-URI in a custom device configuration profile:

Prevent Intune devices from getting the Microsoft search (Bing) plugin

·3 mins
Microsoft recently announced to install a Bing extension on new and existing Office 365 ProPlus installations which will set Bing as the default search engine starting with the first Office 365 ProPlus release in 2020 - not appreciated Microsoft and definitely not what customers want! The extension will be shipped for new Office installations and existing clients with Office 365 ProPlus installed when they update. Update 11.02.2020: “ The Microsoft Search in Bing browser extension will not be automatically deployed with Office 365 ProPlus.” - I will keep this post for the archives. Starting with Version 2002 of Office 365 ProPlus, an extension for Microsoft Search in Bing will be installed that makes Bing the default search engine for the Google Chrome web browser only on devices in certain locations. This extension will be installed with new installations of Office 365 ProPlus or when existing installations of Office 365 ProPlus are updated. (Reference) As expected date the 2002 release will be rolling out in March for the monthly update channel. More details are available under: Microsoft Search in Bing and Office 365 ProPlus Affected locations New Office installations # To avoid the plugin being installed with new office installations edit your Office 365 Configuration with the Office Customization Tool . Make sure to toggle the switch for “Set default search engine to Microsoft Search in Bing” to off: