Category Archives: PowerShell

Microsoft Teams PowerShell Module versions older than 4.x.x will be retired. Time to update!!!

The Microsoft Teams PowerShell module versions old than 4.x.x will be retired from Mid-June 2022. After this date, you wont be able use the module to administrate Microsoft Teams.

So what do you do to update the module?

Well I have a brilliant PowerShell Script in Github that updates all installed modules on your local device. It checks the installed version against the available online version to see if an update is required. If any updated version is available, the script will remove the legacy version and reinstall the latest module.

Download Script from GitHub Here

Regards

The Author – Blogabout.Cloud

Powershell – Changing the UPN in Office 365 for Bulk Users

It is very normal for IT admins to change people’s names, or domain names in Active Directory because they have got married or completed a deed poll, or purchase a new primary domain name. In doing this, the user’s sign-in address so should also reflect the name change. In this post, I am going to look at how to change the User Principal Name for a single user and multiple users.

Setting Up Your PowerShell Environment

First of all you will require the relevant PowerShell Module to connect to Office 365, this can be obtained by running the following cmdlet;

Install-Module MSOnline

Install-Module AzureAD

It might depend on your environment, ask you to install the NuGet provider, as well as installing a module from the PSGallery. Answer Y to both these questions if you encounter them.

Changing a UserPrincipalName for a single user

Using Connect-MSOL Module

Set-MsolUserPrincipalName -UserPrincipalName andrew.moran@contoso.onmicrosoft.com -NewUserPrincipalName andrew.moran@contoso.com

Using AzureAD Module

Set-AzureADUser -ObjectID andrew.moran@contoso.onmicrosoft.com -UserPrincipalName andrew.moran@contoso.com


Changing UserPrincipalName in bulk for users

The following script requires the following in order to be run;

– AzureAD PowerShell Module
– Source CSV file with the following DisplayName,UserPrincipalName,MailNickName

#region Variables
 
 $Filepath = Get-FileName -initialdirectory "$env:USERNAME\downloads"

 #endregion

 #region Functions
 Function Get-FileName {  
  [CmdletBinding()]
  param
  (
    [Object]$initialdirectory
  )
  Add-Type -AssemblyName System.windows.forms | Out-Null
    
    $OpenFileDialog = New-Object -TypeName System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = $initialdirectory
    $OpenFileDialog.filter = "All files (*.*)| *.*"
    $OpenFileDialog.ShowDialog() | Out-Null
    $OpenFileDialog.filename
}
 #endregion 

Connect-AzureAD

# Start-Time
$start = [system.datetime]::Now

# Output will be added to C:\temp folder. Open the Add-SMTP-Address.log with a text editor. For example, Notepad.
Start-Transcript -Path C:\temp\ChangingUPN.log -Append

# Get all mailboxes
$Mailboxes = Import-Csv -Path $FilePath 

# Loop through each mailbox
foreach ($Mailbox in $Mailboxes) {
	
        # Change @contoso.com to the domain that you want to add
        $Address = "$($Mailbox.MailNickName)@ipfin.co.uk"

        # Remove the -WhatIf parameter after you tested and are sure to add the secondary email addresses
        Set-AzureADUser -ObjectId $Mailbox.MailNickName -UserPrincipalName $Address

        # Write output
        Write-Host "Setting $($Address) to $($Mailbox.UserPrincipalName)" -ForegroundColor Green
    }

    # End-Time
$end = [system.datetime]::Now

$resulttime = $end - $start
Write-Host ('Execution : {0}Days:{1}Hr:{2}Min:{3}Sec' -f $resultTime.Days, $resultTime.Hours, $resultTime.Minutes, $resultTime.Seconds) 

Regards
The Author – Blogabout.Cloud

Export Office 365 Group Members to CSV using PowerShell

If you have ever needed to get a list of all the members in a Microsoft 365 Group then this PowerShell script is for you. You export all Microsoft 365 Groups and members to a CSV:

Function Get-FileName {  
  [CmdletBinding()]
  param
  ([Object]$initialdirectory)
Add-Type -AssemblyName System.windows.forms | Out-Null
    
    $OpenFileDialog = New-Object -TypeName System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = $initialdirectory
    $OpenFileDialog.filter = 'CSV (*.csv)| *.csv'
    $OpenFileDialog.ShowDialog() | Out-Null
    $OpenFileDialog.filename
}

$CSVPath = Get-FileName
 
#Connect to Exchange Online
Connect-ExchangeOnline 
 
#Get All Office 365 Groups
$O365Groups=Get-UnifiedGroup
ForEach ($Group in $O365Groups) 
{ 
    Write-Host "Group Name:" $Group.DisplayName -ForegroundColor Green
    Get-UnifiedGroupLinks -Identity $Group.Id -LinkType Members | Select DisplayName,PrimarySmtpAddress
 
    #Get Group Members and export to CSV
    Get-UnifiedGroupLinks -Identity $Group.Id -LinkType Members | Select-Object @{Name="Group Name";Expression={$Group.DisplayName}},`
         @{Name="User Name";Expression={$_.DisplayName}}, PrimarySmtpAddress | Export-CSV $CSVPath -NoTypeInformation -Append
}
  
#Disconnect Exchange Online
Disconnect-ExchangeOnline

Regards

The Author – Blogabout.Cloud

Microsoft Teams: Admins can use cloud shell from Teams admin center

Microsoft has now launched Cloud Shell within the Microsoft Teams Admin Center (13th January 2022), to enable Admins the ability to run PowerShell scripts direct from the browser.

The ability to use Cloud Shell for Microsoft Teams has been available for a while now but this small addition to the Admin Center resolves the need to have more than one window open to administer your Teams environment.

So if you are a Microsoft Teams Admin, go and check it out today.

Regards
The Author

WARNING: Unable to download the list of available providers. Check your internet connection.

When executing one of my scripts today which I havent used in a while, I ran into the following error.

WARNING: Unable to download from URI ‘https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409’ to ”.
WARNING: Unable to download the list of available providers. Check your internet connection.
PackageManagement\Install-PackageProvider : No match was found for the specified search criteria for the provider
‘NuGet’. The package provider requires ‘PackageManagement’ and ‘Provider’ tags. Please check if the specified package
has the tags.
At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:7405 char:21

  • … $null = PackageManagement\Install-PackageProvider -Name $script:N …
  • ~~~~~~~~~~~~~
    • CategoryInfo : InvalidArgument: (Microsoft.Power…PackageProvider:InstallPackageProvider) [Install-Pac
      kageProvider], Exception
    • FullyQualifiedErrorId : NoMatchFoundForProvider,Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackagePro
      vider

PackageManagement\Import-PackageProvider : No match was found for the specified search criteria and provider name
‘NuGet’. Try ‘Get-PackageProvider -ListAvailable’ to see if the provider exists on the system.
At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:7411 char:21

  • … $null = PackageManagement\Import-PackageProvider -Name $script:Nu …
  • ~~~~~~~~~~~~~
    • CategoryInfo : InvalidData: (NuGet:String) [Import-PackageProvider], Exception
    • FullyQualifiedErrorId : NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.ImportPackageProv
      ider

Thankfully the issues was easily resolved by running the following powershell command

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

After running this command in my PowerShell window I was ability to successfully run my script.

Regards
The Author – Blogabout.Cloud

Create Shortcuts on Desktops using Powershell

Here’s a quick script to create a shortcut to Notepad and put it on the desktop, I had to implement the create of a shortcut recently within a script so breaking it out for a dedicated post.

Step #1: The First step is to define the location and name of your shortcut. The following example will add the shortcut to the user’s desktop with a name of Your Shortcut.

$SourceFileLocation = “$env:SystemRoot\System32\notepad.exe”
$ShortcutLocation = “$env:userprofile\Desktop\Notepad.lnk”

Step #2: The second step is to create a variable referencing a Wscript.Shell COM Object.

$WScriptShell = New-Object -ComObject WScript.Shell

Step #3: The third step is to add the target path to the method

$Shortcut = $WScriptShell.CreateShortcut($ShortcutLocation)
$Shortcut.TargetPath = $SourceFileLocation

Step #4: The final step is to envoke the Save() method to save your shortcut.

$Shortcut.Save()

Final Code

# Create a Shortcut with Windows
PowerShell$SourceFileLocation = "$env:SystemRoot\System32\notepad.exe"
$ShortcutLocation = "$env:userprofile\Desktop\Notepad.lnk"#New-Object : 
Creates an instance of a Microsoft .NET Framework or COM object.
#-ComObject WScript.Shell: This creates an instance of the COM object that represents the WScript.Shell for invoke 
CreateShortCut$WScriptShell = New-Object -ComObject WScript.Shell$Shortcut = $WScriptShell.CreateShortcut($ShortcutLocation)
$Shortcut.TargetPath = $SourceFileLocation
#Save the Shortcut to the TargetPath
$Shortcut.Save()

Regards
The Author – Blogabout.Cloud

Understand how many emails have been sent or received by an Exchange Online Mailbox using Powershell

So had a bit of a weird question today from a colleague, who wanted a quick way to find out how many emails have been sent or received by an individual mailbox.

So Windows PowerShell to the rescue .. First of all you will need the ExchangeOnline module which can be easily installed via the following cmdlet

Install-Module -Name ExchangeOnlineManagement

https://www.powershellgallery.com/packages/ExchangeOnlineManagement/2.0.5-Preview1

Type Connect-ExchangeOnline and login using the relevant permissions

Received Message Count

# Receive Messages
$messages = Get-MessageTrace -RecipientAddress andrew.price@lyncme.co.uk -StartDate (Get-Date).AddDays(-1) -EndDate (Get-Date)
$messages.count

Sent Message Count

# Sent Messages
$messages1 = Get-MessageTrace -SenderAddress andrew.price@lyncme.co.uk -StartDate (Get-Date).AddDays(-1) -EndDate (Get-Date)
$messages1.count

You will now get a number of received and sent messages.

Regards
The Author – Blogabout.Cloud

Invoke-WebRequest: The response content cannot be parsed when adapting a local powershell script for Azure Automation.

I have been recently adapting a PowerShell script that collects the Microsoft 365 Service Health using the Office 365 Service Communication API publishing the information into ServiceNow to log a support ticket to make the helpdesk aware of a potential issue in the service. The script was working is no issues when run manually out of PowerShell ISE but failed when ran by Azure Automation.

The focus of this post is to show two specific steps for adapting a locally executed PowerShell script for an Azure Automation runbook. In addition to standard work in Automation to add credentials/connections and create parameters where needed, the following changes were required to adapt a local script for my runbook.

1) Add -UseBasicParsing to Web Requests

The Management API script is filled with various requests using Invoke-WebRequest. Initially, I received numerous errors stating that the Internet Explorer engine is not available.

Invoke-WebRequest : The response content cannot be parsed because the Internet Explorer engine is not available, or 
Internet Explorer's first-launch configuration is not complete. Specify the UseBasicParsing parameter and try again. 
At line:46 char:9
+ $subs = Invoke-WebRequest -Headers $headerParams -Uri "https://manage ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotImplemented: (:) [Invoke-WebRequest], NotSupportedException
    + FullyQualifiedErrorId : WebCmdletIEDomNotSupportedException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

To overcome this, I needed to add the parameter UseBasicParsing.

Original: $oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-version=1.0 -Body $body
Adapted: $oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-version=1.0 -Body $body –UseBasicParsing

2) Alter $ProgressPreference

PowerShell shows progress using $ProgressPreference, which defaults to “continue”. For Automation, I needed to change the option to “silently continue” and suppress progress bars. Locally, the progress can be convenient to see, but it was causing issues with

Automation.Adapted: $ProgressPreference = “silentlyContinue”

Regards
The Author – Blogabout.Cloud

Configuring Password Expiry within Microsoft 365 admin center and with PowerShell

In this brief blog post I am going to demonstrate how simple it is to configure or modify password expiry policy within the Microsoft 365 Admin Center or using PowerShell to make the necessary change.

Configure using Admin Center

Launch https://admin.microsoft.com and go to Settings –> Org Settings –> Security & Privacy –> Password expiration policy

Here you can untick Set user passwords to expire which will disable this setting or configure/modify “Days before passwords expire”

Configure using PowerShell

Running the following commands has the same effect as changing the configuration in the Microsoft 365 Admin Center.

# Connect to M365
$cred = Get-Credential
Connect-MsolService -Credential $cred

# Configure Password Policy
Set-MsolPasswordPolicy -ValidityPeriod 60 -NotificationDays 14 -DomainName "contoso.com"

Regards
The Author – Blogabout.Cloud

Pushing Microsoft Health Status to Microsoft Teams using Azure Automation.

In this post I am going to demostrate how to push Microsoft Health Status to Microsoft Teams using Azure Automation

In this post it is expected you have configured Office 365 Service Communications API. If not, visit this blog post https://www.blogabout.cloud/2020/10/1884/

Configuring Microsoft Teams for Incoming Webhook

Launch Microsoft Teams right click a channel within a Team and select Connectors. Search for Incoming Webhook and click Add

Click Add

Specify the name of the Webhook and click Create

Make a note of the URL below as you will need this for the PowerShell script later and click Done

Create Automation Account

Launch your Azure Portal and search for Automation Account to create a new account.

Specify;
– Name
– Subscription
– Resource Group
– Location

No should be selected for “Create Azure Run As Account” as this is will enable the Account to run against Office 365.
Click Create

Once the resources has successful created, go into the resource

First of all we need to create a number of variables, these variables will use within the PowerShell script we are going to add to the Runbook.

You will need to add the following variables

– AzO365ServiceHealthApplicationID = Client ID
– AzO365ServiceHealthApplicationKey = Client Secrey
– AzO365TeamsURI = This is the url we created earlier in the post
– AzO365TenantDomain = Tenant ID

If you unsure how to obtain these values, please visit this blog post for more details

We now need to launch Runbooks

Select Create a runbook
– Provide a name
– Runbook Type should equal PowerShell
– Description (is optional)

Press Create

I am now going to use the following PowerShell script available from GitHub within my Runbook. https://github.com/einast/PS_M365_scripts. This script has been created for the sole purpose of extracting the Microsoft 365 Service Health using the Office Service Communication API, which I demonstrated how to configure in another post.

Under the “User Defined Variables” you will need to edit;

Mintues to reflect the same time as your schedule.

Pushover notifications and Services to monitor as shown below

# ------------------------------------- USER DEFINED VARIABLES -------------------------------------

$ApplicationID = Get-AutomationVariable -Name 'AzO365ServiceHealthApplicationID'
$ApplicationKey = Get-AutomationVariable -Name 'AzO365ServiceHealthApplicationKey'
$TenantDomain = Get-AutomationVariable -Name 'AzO365TenantDomain'
$URI = Get-AutomationVariable -Name 'AzO365TeamsURI'
$Minutes = '1440'

# Pushover notifications in case Teams is down.
# Due to limitations and readability, the script will only send the title of the incident/advisory to Pushover. 
# COMMENT OUT THIS SECTION IF YOU DON'T WANT TO USE PUSHOVER!

#$Pushover = 'yes' # Comment out if you don't want to use Pushover. I use 'yes' for readability.
#$PushoverToken = Get-AutomationVariable -Name 'AzO365PushoverToken' # Your API token. Comment out if you don't want to use Pushover
#$PushoverUser = Get-AutomationVariable -Name 'AzO365PushoverUser' # User/Group token. Comment out if you don't want to use Pushover
#$PushoverURI = 'https://api.pushover.net/1/messages.json' # DO NOT CHANGE! Default Pushover URI. Comment out if you don't want to use Pushover

# Service(s) to monitor
# Leave the one(s) you DON'T want to check empty (with '' ), add a value in the ones you WANT to check (I added 'yes' for readability)

$ExchangeOnline = 'yes'
$MicrosoftForms = 'yes'
$MicrosoftIntune = 'yes'
$MicrosoftKaizala = 'yes'
$SkypeforBusiness = 'yes'
$MicrosoftDefenderATP = 'yes'
$MicrosoftFlow = 'yes'
$FlowinMicrosoft365 = 'yes'
$MicrosoftTeams = 'yes'
$MobileDeviceManagementforOffice365 = 'yes'
$OfficeClientApplications = 'yes'
$Officefortheweb = 'yes'
$OneDriveforBusiness = 'yes'
$IdentityService = 'yes'
$Office365Portal = 'yes'
$OfficeSubscription = 'yes'
$Planner = 'yes'
$PowerApps = 'yes'
$PowerAppsinMicrosoft365 = 'yes'
$PowerBI = 'yes'
$AzureInformationProtection = 'yes'
$SharePointOnline = 'yes'
$MicrosoftStaffHub = 'yes'
$YammerEnterprise = 'yes'

# Classification(s) to monitor
# Leave the one(s) you DON'T want to check empty (with '' ), add a value in the ones you WANT to check (I added 'yes' for readability)

$Incident = 'yes'
$Advisory = 'yes'

# ------------------------------------- END OF USER DEFINED VARIABLES -------------------------------------

You will now need to define a schedule within the Runbook for it to execute.

Once you have done all of the above, you will receive a nice notification in Microsoft Teams about the Service Health Status

In my next article I will show how simple it is too trigger this Runbook using Power Automate.

Regards
The Author – Blogabout.Cloud