Working with Variables located in PowerShell Functions

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 http://www.powertheshell.com. There is a slight cost but well worth it if you are regularly building scripts.

Regards

The Author – Blogabout.Cloud

Microsoft Teams module now in GA

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

http://www.blogabout.cloud/2018/09/240/


Regards
The Author – Blogabout.Cloud

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

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’. 

ERROR!!!
1

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 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 $dl.name, ($count))
 
  $reportoutput += $report
}

# Stop Transcript
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.


1
2
# Array
$reportoutput=@()

Regards

The Author – Blogabout.Cloud

PowerShell – ForEach do  action X or do Y

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

Get-DistributionGroup

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

Simples!!

 Clear-Host
$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;
endregion
Transcript
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
}
catch
{
Write-Host 'ERROR:' ($row.SamAccountName),'Primary SMTP Address has not been modified to',($row.PrimarySmtpAddress) -BackgroundColor Red
}
}
Stop-Transcript
Get-DistributionGroup
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.

Regards

The Author – Blogabout.Cloud

Import Exchange PowerShell Module into your PowerShell ISE console

Import Exchange PowerShell Module into your PowerShell ISE console

When working with 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 cmdlet in ISE, so the workaround for this is to use the following command;

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

The command to import the Exchange modules is different for each version – please use the appropriate command below:

Exchange 2007

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

Exchange 2010

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

Exchange 2013, 2016, 2019

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

Regards
The Author – Blogabout.Cloud


Do I have duplicate Recipient Alias within my Exchange organization?

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

 Clear-Host
$start = [datetime]::Now
Start Transcript
Start-Transcript -Path "$env:USERPROFILE\Desktop\Mailbox Alias\mailboxaliaslog.txt"
Get-Recipent
$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
Stop-Transcript
Write-Host ('Execution : {0}Days:{1}Hr:{2}Min:{3}Sec' -f $resultTime.Days, $resultTime.Hours, $resultTime.Minutes, $resultTime.Seconds)

Download

Get-RecipientAlias (36 downloads)

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

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 Child1.domain.com matches CustomAttribute10 in Child2.domain.com, 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

 Clear-Host
Write-Host "You are currently running Version 1.0" -BackgroundColor DarkGray
[string] $Menu = @'
┌─────────────────────────────────────────────────────────────┐
ADSISearcher for CustomAttribute10
Created by @thewatchernode
└─────────────────────────────────────────────────────────────┘
'@
Menu
$Menu
Transcript
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()
endregion
region Collab Array
$Child2SB = 'DC=child2,DC=domain,DC=com'
$Child2DN = 'DC=child2,DC=domain,DC=com'
endregion
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
}
else
{
try
{
($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
}
catch
{
Write-Host 'INFO, No Attribute match found in Child domain 2 using Child domain 1,' $Object.Properties.samaccountname -BackgroundColor Red
}
}
}
endregion
Stop Transcript
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)

Download

Get-ADSISearcher (27 downloads)

Regards

The Author – Blogabout.Cloud

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

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

Syntax
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.

Regards
The Author – Blogabout.Cloud


Counting Exchange/Exchange Online Mailboxes with a specified SMTP Domain

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 blogabout.cloud as their PrimarySMTPAddress or have blogabout.cloud listed as their EmailAddress.

Using the below PowerShell snippet you can find out exactly

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


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

Regards,

The Author – Blogabout.Cloud