Category Archives: PSCommands

How to uninstall PowerShell modules with dependencies within a script.

PowerShell module can sometimes become a nightmare if there are dependencies on other modules. I have been recently looking at my AzureADPreview which had one dependency for;

– Microsoft365DSC module

If you run the standard uninstall-module -name AzureADPreview you will receive an error stating the module cannot be uninstalled due to the dependency of the other module as shown below;

If you run install-module AzureADPreview you are likely to receive a duplicate install of the same module which will potential cause issues later down the line.


The following function has made this possible.

Function Uninstall-AllModules
param (
[Parameter(Mandatory = $true)]
[Parameter(Mandatory = $false)]

$AllModules = @()

‘Creating list of dependencies…’
$target = Find-Module $TargetModule
$target.Dependencies | ForEach-Object {
$AllModules += New-Object -TypeName psobject -Property @{ name = $}
$AllModules += New-Object -TypeName psobject -Property @{ name = $TargetModule}

$cnt = 1;
foreach ($module in $AllModules)
Write-Host (“[$cnt] – ” + ‘Uninstalling {0} version’ -f $;
if ($PSCmdlet.ShouldProcess($, ‘Uninstall’))
Uninstall-Module -Name $ -Force:$Force -ErrorAction Stop;
Write-Host (“`t” + $_.Exception.Message)

## – Example using -WhatIf parameter:
Uninstall-AllModules -TargetModule AzureAD -Force

The Author – Blogabout.Cloud

Working with Variables located in PowerShell Functions

I have been recently working on updating a number of my PowerShell scripts and ran into an issue where my variables were unavailable within a function. The resolution for this is making the variables globally available to all the function(s) that are contained within your script.

So, as you can see below. I have configured my script blocks into Functions and converted the Parameter variables into $Global: variables. This will allow the Get-MailMessage function to use the $Global: variables within its own function

Without $Global:
With $Global:

However, there is one more step required to ensure that the variables can use the globally defined variables. I have a configure region within my script that contains all my defined variables and in here I have put for example $Global:Variable = $Global:Variable

$Global:Variables = $Global:Variables

As you can see from above image the variables located in New-MailMessage function are not highlighted in yellow.

Tools of the trade

The reason for the highlighted variables within my script, I use a tool called PowerShell ISE There is a slight cost but well worth it if you are regularly building scripts.


The Author – Blogabout.Cloud

Microsoft Teams module now in GA

Its been a long road but Microsoft Teams PowerShell module version 1.0.0 is now available in GA. Microsoft has been working very hard in creating this module and have removed/introduction features into this release. So lets have a look at what we now can and cannot do with Microsoft Teams

So what’s removed?

So Microsoft have removed the following cmdlets

  • Get-TeamFunSettings
  • Get-TeamGuestSettings
  • Get-TeamMemberSettings
  • Get-TeamMessagingSettings
  • Set-TeamFunSettings
  • Set-TeamGuestSettings
  • Set-TeamMemberSettings
  • Set-TeamMessagingSettings

But do not fear, as the same functionality of these cmdlets have been integrated into Get-Team and Set-Team.

So what’s new?

  • Connect-MicrosoftTeams allows you to specify a Teams Government Environment (-TeamsEnvironmentName) that your organization is homed in.
  • Get-Team allows you to specify new filter and selection criteria to identify specific teams based off of new criteria, including the Visibility or Archived state of the teams.

So its time to start playing with the Teams module and seeing what interesting scripts can be generated.

Please Note: It is recommended to uninstall any previous version you may have installed. So check out this previous blog post i created

The Author – Blogabout.Cloud

Method invocation failed because [System.Management.Automation.PSObject] doesn’t contain a method named ‘op_Addition’.

While constructing a PowerShell script for gathering information about Distribution Lists within a customers environment, I ran into the following error

Method invocation failed because [System.Management.Automation.PSObject] doesn’t contain a method named ‘op_Addition’. 


This error was being generated by a missing array within my PowerShell code

# Call Distribution Lists
$dist = @(Get-DistributionGroup -resultsize unlimited)

# Start Transcript
Start-Transcript -Path $env:USERPROFILE\desktop\DLsandMember.txt

# Report on Distribution List
foreach ($dl in $dist)
  $count =@(Get-DistributionGroup $dl.samaccountname).count
  $report = New-Object -TypeName PSObject
  $report | Add-Member -MemberType NoteProperty -Name 'Group Name' -Value $dl.Name
  $report | Add-Member -MemberType NoteProperty -Name 'samAccountname' -Value $dl.samaccountname
  $report | Add-Member -MemberType NoteProperty -Name 'Group Type' -Value $dl.grouptype
  $report | Add-Member -MemberType NoteProperty -Name 'DN' -Value $dl.distinguishedName
  $report | Add-Member -MemberType NoteProperty -Name 'Manager' -Value $dl.managedby
  $report | Add-Member -MemberType NoteProperty -Name 'Member Depart Restriction' -Value $dl.memberdepartrestriction
  $report | Add-Member -MemberType NoteProperty -Name 'Member Join Restriction' -Value $dl.memberjoinrestriction
  $report | Add-Member -MemberType NoteProperty -Name 'PrimarySMTPAddress' -Value $dl.primarysmtpaddress
  $report | Add-Member -MemberType NoteProperty -Name 'EmailAddress' -Value $dl.emailaddresses
  $report | Add-Member -MemberType NoteProperty -Name 'GrantSendOnBehalfto' -Value $dl.GrantSendOnBehalfto
  $report | Add-Member -MemberType NoteProperty -Name 'EmailAddressPolicyEnabled' -Value $dl.EmailAddressPolicyEnabled
  $report | Add-Member -MemberType NoteProperty -Name 'Number of Members' -Value $count
  Write-Host ('INFO: {0} has {1} members' -f $, ($count))
  $reportoutput += $report

# Stop Transcript

By adding the following lines to my above script I was able to successful export the required information into an Array and dump out to CSV.

# Array


The Author – Blogabout.Cloud

PowerShell – ForEach do action X or do Y

PowerShell is one of the greatest tools within any IT Professional toolkit, it enables you to do far more than any GUI available to you today. In my life as a Consultant for a Global Microsoft SI (System Integrator), I face challenges every day where PowerShell has come to the rescue. One of the best cmdlet I use in a lot of script is

ForEach which is the alias name of ForEach-Object

Imagine you need to modify an ExtensionAttribute for your entire organization or grant a permission to a subset of users, ask yourself this? How would I do this in a GUI? and the answer would be “with great difficulty or very time consuming”. This is Foreach-Object comes into play, in the below example I need to modify the PrimarySMTPAddress due to special characters being used


In order to correct this, I will be using a source CSV file which contains SamAccountName for the identity of each DistributionList and the correct PrimarySMTPAddress.

Source CSV file

Now for the most important element, the powershell script which will be used to modify the PrimarySMTPAddress. The below script has been designed to achieve the required outcome but also includes the ability to;

  • Be ran using native PowerShell for On-Premises Exchange Servers (2007 through to 2019)
  • Be ran against Exchange Online

So as we can see the Foreach command is being used in the following;

  • For each $row within the $csv which is being imported try and get the distribution list using the column heading SamAccountName
    • If the Identity cannot be found the script will move to the catch
    • If the Identity can be found the script will set the distribution list using the column heading PrimarySMTPAddress
  • The catch is alert if there are any unsuccessful attempts at setting the PrimarySMTPAddress


$file = "$env:USERPROFILE\OneDrive\Desktop\groups.csv"
$csv = import-csv -Path $file
region Exchange Module SnapIn
# Exchange 2007
#Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin;
# Exchange 2010
#Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010;
# Exchange 2013/2016
#Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn;
Start-Transcript -Path $env:USERPROFILE\OneDrive\Desktop\Get-DistributionGroup.txt
Foreach ($row in $csv)
try {
Get-DistributionGroup -Identity $row.SamAccountName | Set-DistributionGroup -PrimarySmtpAddress $row.PrimarySmtpAddress
Write-Host 'INFO:' ($row.SamAccountName),'Primary SMTP Address has now been modified to',($row.PrimarySmtpAddress) -BackgroundColor Green
Write-Host 'ERROR:' ($row.SamAccountName),'Primary SMTP Address has not been modified to',($row.PrimarySmtpAddress) -BackgroundColor Red
Image result for meerkat simples gif

I have included Start-Transcript as this will dump out all Write-Host entry whether they was successful or not.


The Author – Blogabout.Cloud

Import Exchange On-Premiese PowerShell Module into your PowerShell ISE console

When working with on-premises Exchange there may be a requirement to create a PowerShell script using PowerShell ISE. Even if you run ISE on a Exchange Server, you are unable to get the Exchange cmdlets in ISE. So whats theworkaround for this is?

Important: Getting Exchange Cmdlets on a client machine

If you are trying to add the Exchange cmdlets to your client machine then you will need to Install the Exchange Management Tools from the Exchange installation media on your device.

Importing the Exchange Cmdlets into PowerShell ISE

The following commands allow the import of the Exchange Management Cmdlets into PowerShell ISE. They are slight different for the listed versions of Exchange.

Exchange 2007

Use the following Add-PSSnapin to bring the cmdlets into PowerShell ISE

 Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin; 

Exchange 2010

Use the following Add-PSSnapin to bring the cmdlets into PowerShell ISE

 Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010; 

Exchange 2013, 2016, 2019

Use the following Add-PSSnapin to bring the cmdlets into PowerShell ISE

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn; 

Exchange Online

If you require the Exchange Online PowerShell Modules, you will need to install the new ExchangeOnlineManagement modules from the PowerShell Gallery.

The Author – Blogabout.Cloud

Do I have duplicate Recipient Alias within my Exchange organization?

So do you know if you have duplicate recipient alias within your Exchange organisation? Heres a quick script that will look at your Exchange Environment and download all recipient address into a handy csv file you to play with.

The script

$start = [datetime]::Now
Start Transcript
Start-Transcript -Path "$env:USERPROFILE\Desktop\Mailbox Alias\mailboxaliaslog.txt"
$Mailboxes = Get-Recipient -ResultSize Unlimited -RecipientType UserMailbox |
Sort-Object -Property @{ Expression = { $_.EmailAddresses.Count } } -Descending
$Results = foreach( $Mailbox in $Mailboxes ){
$Stats = $Mailbox | Get-MailboxStatistics

$Properties = [ordered]@{ FirstName = $Mailbox.FirstName LastName = $Mailbox.LastName DisplayName = $Mailbox.DisplayName TotalItemSize = $Stats.TotalItemSize PrimarySmtpAddress = $Mailbox.PrimarySmtpAddress } $AltAddresses = $Mailbox.EmailAddresses | Where-Object { $_ -match '^smtp:' -and $_ -ne $Mailbox.PrimarySmtpAddress } $i = 1 Write-Host ('INFO: Working {0}.PrimarySmptAddress' -f $Mailbox) foreach( $Address in $AltAddresses ){ $Properties.Add( ('AltAddress{0}' -f $i), $Address -replace '^smtp:' ) $i++ } [pscustomobject]$Properties }

$Results |
Export-Csv -Path "$env:USERPROFILE\desktop\MailboxAliasReport.csv"
$end = [datetime]::Now
$resulttime = $end - $start
Stop Transcript
Write-Host ('Execution : {0}Days:{1}Hr:{2}Min:{3}Sec' -f $resultTime.Days, $resultTime.Hours, $resultTime.Minutes, $resultTime.Seconds)


Get-RecipientAlias (966 downloads)

Is Get-ADUser a bit slow in getting required result? Hello ADSISearcher using PowerShell.

Sometimes Get-ADUser just isn’t enough if you are working thousands upon thousands of AD Objects. In a recent scenario, while resolving an Active Directory Health issue. I needed the ability to be able to compare AD Objects from 2 Active Directory Domains from within a resource forest.

What is ADSISearcher?

ADSISearcher is a command line driven LDAP Lookup procedure has the ability to query Active Directory. As ADSISearcher looks up Active Directory it enables a faster discovery of the required AD Objects.

My scenario

I need to ensure CustomAttribute10 in matches CustomAttribute10 in, yes I could use Get-ADUser | export-csv but this has proved to take to long and needed a faster solution.

ADSISearcher has proved to reduce the time required to execute this script and dumping out to a transcript file with “,” separating the text allows the information to be imported to excel if required.

The script

Write-Host "You are currently running Version 1.0" -BackgroundColor DarkGray
[string] $Menu = @'
ADSISearcher for CustomAttribute10
Created by @thewatchernode
Start-Transcript -Path "$env:userprofile\Desktop\Child1vsChild2.txt"
Start Time
$start = [datetime]::Now
region Client Array
$Child1LDAPFilter = '(objectclass=user)'
$PageSize = 1000
$Child1DN = 'DC=child1,DC=domain,DC=com'
$Child1SB = 'DC=child1,DC=domain,DC=com'
$Child1Searcher = [ADSISearcher]('{0}' -f $child1LDAPFilter)
$Child1Searcher.SearchRoot = [ADSI]('GC://{0}' -f $Child1SB)
$Child1Searcher.SearchRoot = [ADSI]('GC://{0}' -f $child1DN)
$Child1Searcher.PageSize = $PageSize
$Child1Objects = $Child1Searcher.FindAll()
region Collab Array
$Child2SB = 'DC=child2,DC=domain,DC=com'
$Child2DN = 'DC=child2,DC=domain,DC=com'
region Client vs Collab
Foreach($Object in $child1Objects){
$childca10 = $Object.Properties.'customattribute10'
$Child2LDAPFilter = "(objectclass=user,customattribute10=$childca10)"
$child2Searcher1 = [ADSISearcher]("{0}" -f $child2LDAPFilter)
$child2Searcher1.SearchRoot = [ADSI]("GC://{0}" -f $Child2SB)
$child2Searcher1.SearchRoot = [ADSI]("GC://{0}" -f $Child2DN)
$child2Searcher1.PageSize = $PageSize
#$AllObjects1 = $collabSearcher1.FindAll()
$nullvalue = $object.Properties.'customattribute10'
if ($nullvalue -eq $null)
Write-Host 'INFO, Null Value Found in Child Domain 1,' $Object.Properties.samaccountname -BackgroundColor Red
($Object.Properties.'customattribute10' -eq $child2searcher1.Properties.'customattribute10')
Write-Host 'Skipping, Attribute match found in Child domain 2 using Child domain 1,' $Object.Properties.samaccountname -ForegroundColor Green
Write-Host 'INFO, No Attribute match found in Child domain 2 using Child domain 1,' $Object.Properties.samaccountname -BackgroundColor Red
Stop Transcript
End Time
$end = [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)


Get-ADSISearcher (849 downloads)


The Author – Blogabout.Cloud

Merging Excel files using PowerShell, yes it can be done.

Have you ever worked with Excel files where you wanted to match and compare Columns/Rows? In the past, this has been quite difficult tasks to achieve using the native commands within PowerShell.

So have you heard of the PowerShell module ImportExcel?

It’s is a PowerShell module that is available on the PowerShell Gallery and introduces a number of functions that allow you to work with Excel files using the good old blue background.

From this module we will be working with the following function;

  • Merge-Worksheet
Merge-Worksheet [-Referencefile]  [-Differencefile]  [[-WorksheetName] ] [-Startrow ] 
     -Headername  [[-OutputFile] ] [[-OutputSheetName] ] [-Property ] [-ExcludeProperty ] 
     [-Key ] [-KeyFontColor ] [-ChangeBackgroundColor ] [-DeleteBackgroundColor ] 
     [-AddBackgroundColor ] [-HideEqual] [-Passthru] [-Show] [-WhatIf] [-Confirm] []

Example usage of Function

The below shows the Reference and Difference Excel files that are being used in this example. I am going to merge the two excel files based on Column A the EmployeeNumber. During my testing, I have had issues using -HeaderName parameter. In this post I will not be specifying the headings and just modify the output file.

# Variables
$ref = "$env:USERPROFILE\desktop\test\ref.xlsx"
$dif = "$env:USERPROFILE\desktop\test\dif.xlsx"
$out = "$env:USERPROFILE\desktop\test\out.xlsx"

# Script Block
Merge-Worksheet -Referencefile $ref -Differencefile $dif -OutputFile  $out -WorksheetName Sheet1 -Startrow 1 -OutputSheetName Sheet1 -NoHeader 

As we can see from below, the output field has organised Column A and aligned the rows

Every useful if you are working with Excel files but only annoying thing is the HeaderName parameter not working.

The Author – Blogabout.Cloud

Counting Exchange/Exchange Online Mailboxes with a specified SMTP Domain

When working with large organisations that have multiple SMTP Domains, you may run into a requirement where you need to know. How many mailboxes have as their PrimarySMTPAddress or have listed as their EmailAddress.

Using the below PowerShell snippet you can find out exactly

# Primary SMTP Address
get-mailbox -resultsize unlimited | where {$_.primarysmtpaddress -like "*"} | Measure-Object

# Email Address
get-mailbox -resultsize unlimited | where {$_.emailaddress -like "*"} | Measure-Object


The Author – Blogabout.Cloud