Showing posts with label powershell. Show all posts
Showing posts with label powershell. Show all posts

Tuesday, May 24, 2016

Reconnecting Deleted Users on O365

If the Directory  Sync connection between an Office 365 and AD account breaks for some reason (AD user is deleted, server corruption etc) it can be tricky to get them reconnected. These steps may help:
1) Use Office 365 Control panel to restore deleted user.  It will now be marked as “In Cloud” instead of “Synced with Active Directory”.
2) Use the local AD tools to re-create user if it is missing. Local Exchange tools should be used to create a new mail user with an SMTP address that matches the SMTP address of the Office 365 User.
3) Fire up Powershell and connect to the Office 365 Azure Cloud using the following commands:
Import-Module MSOnline 
$O365Cred = Get-Credential 
$O365Session = New-PSSession –ConfigurationName Microsoft.Exchange -ConnectionUri -Credential $O365Cred -Authentication Basic -AllowRedirection 
Import-PSSession $O365Session -AllowClobber 
Connect-MsolService –Credential $O365Cred
4) Use the following command to delete the ImmutableID from the Office 365 Account where ‘User Principal Name’ is either the name or the email address of the user being reset:
Set-MsolUser -UserPrincipalName 'User Principal Name' -ImmutableId '$null'
5) Wait for, or force, the AD Sync and it should reconnect the accounts.

Tuesday, November 18, 2014

Missing mailbox / Distribution list in Offline Address Book

You might experience this error during an Offline Address Book generation cycle:

Index : 94460
EntryType : Warning
EventID : 9327
Message : OALGen skipped some entries in the offline address list ‘\Global Address List’. To see which entries are affected, event logging for the OAL Generator must be set to at least medium.
- Default Offline Address List
Category : OAL Generator
CategoryNumber : 13
ReplacementStrings : {\Global Address List, Default Offline Address List}
Source : MSExchangeSA

After you set the event log level for the OAL Generator to at least medium, eg. by using this EMS command:
Set-EventLogLevel ‘MSExchangeSA\OAL Generator’ -level Medium
You start seeing these errors:

Index : 94454
EntryType : Error
EventID : 9325
Message : OALGen will skip user entry ‘user1′ in address list ‘\Global Address List’ because the SMTP address ” is invalid.
- Default Offline Address List
Category : OAL Generator
CategoryNumber : 13
ReplacementStrings : {user1, \Global Address List, , Default Offline Address List}
Source : MSExchangeSA

As we can see from the error in the Event Log, OAL Generator claims that the SMTP address ” (blank) is invalid. This is not surprising, as a blank address can not be used for anything.
I have discovered one reason for this error, there might be more. If the user’s primary SMTP address does not match the value in the mail attribute in Active Directory, this error is generated. This happens if you change the primary SMTP address in EMC. EMC does not update the address in the mail attribute. To see if you have any recipients in your organization that have a mismatch between these two values, run these EMS commands:

get-mailbox -resultsize unlimited | where { $_.WindowsEmailAddress -ne $_.PrimarySmtpAddress } | ft –auto

get-distributiongroup -resultsize unlimited | where { $_.WindowsEmailAddress -ne $_.PrimarySmtpAddress } | ft –auto

get-dynamicdistributiongroup -resultsize unlimited | where { $_.WindowsEmailAddress -ne $_.PrimarySmtpAddress } | ft –auto

This should be possible to do with Get-Recipient as well, but I cannot make it work. Get-Recipient always return every recipient in the organization.

To remedy this situation, these EMS commands may be of interest:

get-mailbox -resultsize unlimited | where { $_.WindowsEmailAddress -ne $_.PrimarySmtpAddress } | ForEach { Set-Mailbox $_ -WindowsEmailAddress $_.PrimarySMTPAddress }

get-distributiongroup -resultsize unlimited | where { $_.WindowsEmailAddress -ne $_.PrimarySmtpAddress } | ForEach { Set-distributiongroup $_ -WindowsEmailAddress $_.PrimarySMTPAddress}

get-dynamicdistributiongroup -resultsize unlimited | where { $_.WindowsEmailAddress -ne $_.PrimarySmtpAddress } | ForEach { Set-dynamicdistributiongroup $_ -WindowsEmailAddress $_.PrimarySMTPAddress}

You should probably test these commands with the –whatif parameter added to the Set cmdlets.
A good pointer as to which recipients have a mismatch between these values, are those recipients who no longer have their Email addresses updated by a recipient policy. You can quickly list which recipients are in this state:

get-mailbox -ResultSize unlimited | where { $_.EmailAddressPolicyEnabled -eq $false } | ft –auto

get-distributiongroup -ResultSize unlimited | where { $_.EmailAddressPolicyEnabled -eq $false } | ft –auto

get-dynamicdistributiongroup -ResultSize unlimited | where { $_.EmailAddressPolicyEnabled -eq $false } | ft –auto

Also recipients who are targets of E-Mail address policies (EAP), but where those policies have not been applied, are candidates for this error.

Lastly, you cannot set the mail attribute if a recipient is a target of an EAP.
Remember to set the Event Log level back to it’s original value after you have finished troubleshooting:

Set-EventLogLevel ‘MSExchangeSA\OAL Generator’ -level lowest

Friday, July 18, 2014

Exchange 2010 Health Check Report

This script is a fast and efficient way of checking if you have any severe issues with your Exchange 2010 setup.
All credits to go to the scripts original author at ExchangeServerPro

All that is need is to download the file from the link above.

The command line in PowerShell to run the script is as follows

Single Server
.\test-ExchangeServerHealth.ps1 -reportmode $true -sendemail $true -server <Exchange Server Name>

Entire Organization
.\test-ExchangeServerHealth.ps1 -reportmode $true -sendemail $true -server *

Servers Starting with perhaps a site with Server Prefixed with "SIN"
.\test-ExchangeServerHealth.ps1 -reportmode $true -sendemail $true -server sin*

The PS script can be downloaded from the link below

The Test-ExchangeServerHealth.ps1 script is run from the Exchange Management Shell. You can use a few builtin parameters to control what it does.
Perform a health check of a single server

Set to $true to generate a HTML report. A default file name
is used if none is specified.

Allows you to specify a different HTML report file name than
the default. Implies -ReportMode

Sends the HTML report via email using the SMTP configuration
within the script. Implies -ReportMode

Only sends the email report if at least one error or warning
was detected.

Writes a log file to help with troubleshooting.
If you use the report mode you’ll get a HTML file containing the health check results, and/or an email to your designated address if you also use the send email option.
For the email functionality to work please update these variables in the script to suit your environment.

# Modify these Email Settings

$smtpsettings = @{
 To =  ""
 From = ""
 Subject = "Exchange Server Health Report - $now"
 SmtpServer = ""

Thursday, July 17, 2014

Useful SCOM 2007 R2 Powershell

Get list Operations Manager Commands

Get list of unavailable/unresponsive agents
Get-Monitoringclass -name "Microsoft.Windows.Computer" | Get-MonitoringObject | Where-Object {$_.IsAvailable -eq $False} | Select-Object DisplayName, IsAvailable | Format-Table

Resolve the healthserviceid to Agent Name
Get-Agent | Where-Object {$ -eq "healthserviceid"} | Select-Object name

Export All Unsealed Management Packs to UnsealedMPBackup Folder
Get-ManagementPack | where {$_.Sealed -eq $false} | Export-Managementpack -path C:\UnsealedMPBackup

Get the Management Server information including the Management Server Action Account identity
Get-ManagementServer | Select-Object DisplayName, IsRootManagementServer, ActionAccountIdentity, HealthState | Format-Table -autosize

Get the User Roles and its Members
Get-Userrole | Select-Object DisplayName, Users

Export all rules in imported management packs to rules.csv
Get-rule | select-object @{Name="MP";Expression={ foreach-object {$_.GetManagementPack().DisplayName }}},DisplayName | sort-object -property MP | export-csv "c:\rules.csv"

Get List of agent managed machines and their ip address
Get-agent | format-list -property, displayname, IPAddress

Enable Agent Proxy for all agents where it is disabled
$NoProxy = get-agent | where {$_.ProxyingEnabled -match "false"}
$NoProxy|foreach {$_.ProxyingEnabled = $true}
$NoProxy|foreach {$_.ApplyChanges()}

Friday, May 9, 2014

All System Center Cmdlets you are looking for

Microsoft has released System Center CmdLets reference for all the system center components.
It will definitely be a great help to any System Center Admins.

The reference can be downloaded from the below

Thursday, April 24, 2014

Mass Import IP for Exchange Receive Connector

There are times when you are required to add many IPs addresses to the receive connector on Exchange 2010. This IPs are required to enable the exchange server to relay emails for alerts etc.
The powershell script below is something that is found from the community that is extremely useful

Copy the below and save it as a ps1 file

Simple Powershell script that can bulk import remote IP ranges from a text file in a determined Exchange Receive Connector.
The Import of the Remote IP ranges maintains the original values which are already present on the Selected Connector.
None - execute directly from the Exchange Management Shell


Exchange 2007
Exchange 2010
Exchange 2013
function Select-FileDialog
param([string]$Title,[string]$Directory,[string]$Filter="Text Files (*.txt)|*.txt")
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
$objForm = New-Object System.Windows.Forms.OpenFileDialog
$objForm.InitialDirectory = $Directory
$objForm.Filter = $Filter
$objForm.Title = $Title
$objForm.ShowHelp = $true
$Show = $objForm.ShowDialog()

if ($Show -eq "OK")
return $objForm.FileName
function get_RecConnector{
$RecConns = Get-ReceiveConnector | Select -ExpandProperty Identity
$Count = 0;
Write-Host "Bulk Import of Remote IP Addresses for Exchange Receive Connectors" -ForegroundColor Green
Write-Host "Version 0.1" -ForegroundColor Green
Write-Host "" -ForegroundColor Green
Write-Host ""
Write-Host "Detected Receive Connectors: " -ForegroundColor Cyan
Write-Host ""
foreach($Connector in $RecConns){

Write-Host $Count "." $Connector -ForegroundColor White
$Count ++

Write-Host ""
$Choice = Read-Host "Please select the Receive Connector that you wish to work with."
Write-Host ""
import_RemoteIPRanges $RecConns[$Choice]
function import_RemoteIPRanges{
$FileName = Select-FileDialog "Open IP Range Text File..."
$IPs = Get-Content $FileName

foreach($IP in $IPs){
Write-Host "Adding IP Address :" $IP " to "$ConnectorID -ForegroundColor Cyan
$Rcnn = Get-ReceiveConnector "$ConnectorID"
$Rcnn.RemoteIPRanges += $IP
Set-ReceiveConnector "$ConnectorID" -RemoteIPRanges $Rcnn.RemoteIPRanges

Write-Host ""
Write-Host "Script Completed." -ForegroundColor Yellow

How to use

Before you use the script you should ensure that you have all of the IP addresses that you wish to add to a particular Receive Connector stored within a text file.

Each host should appear on a separate line. You can also use the CDIR address notation for an entire subnet if you wish to allow all hosts in a range to relay (for example add a line for .

1) Open the Exchange Management Shell, navigate to the directory where you have downloaded the script file and type:

<path>.\<FileName of th3 ps1 file you saved earlier>.ps1

2) You will then be presented with a list of all the detected receive connectors that the script has located. Choose the connector via its numerical identifier (the numbers on the left hand side).

3) You will then be prompted to locate your IP Range text file which you created earlier – browse to it and then click on the “Open” button.

4)The script will then process each host entry and add it to the selected Receive Connector.

5) After the script has completed – if you check the [ Network –> Receive Mail from remote servers that these IP addresses ] in the Exchange Management Console, you should see that your addresses have been added.

Thursday, April 10, 2014

Powershell not responsive on tab

Powershell is everywhere now. Exchange, SCOM etc.. you name it.

Since I use the tab expansion function frequently, I noticed immediately that for some odd reason the Command Shell would paused for ~30 seconds every time I used the tab completion function. I had to remind myself never to use it or I’d be staring at the screen for a while. Sometimes it’s quicker to just close Command Shell and launch it again, but usually there is history saved which I don’t want to lose.

So I wait…and wait. :(
Lincoln Atkinson created a workaround for this, which I stumbled across on the Technet forum. This was such a wonderful find, I feel like I should spread the news. Run the following script, or add it to your $profile, and tab away!

$tabExpand = (get-item function:\tabexpansion).Definition
if($tabExpand -match 'try {Resolve-Path.{49}(?=;)')
$tabExpand = $tabExpand.Replace($matches[0], "if((get-location).Provider.Name -ne 'OperationsManagerMonitoring'){ $($matches[0]) }" )
invoke-expression "function TabExpansion{$tabExpand}"

Wednesday, February 22, 2012

Retrieving SCOM monitor thresholds by Powershell

Part of managing the SCOM infrastructure will include knowing what thresholds are being configured for the countless monitors that are available from the many Management Packs that comes from Microsoft or other vendors.
To compile all these thresholds tying them to their respective counters and monitors proves to be a challenge.
There is some powershell cmdlets that are provided on the Microsoft Site that enables us to do that but the thresholds suck as “Logical Disk Free Space” does not appear in the exported CSV.
The result will be something as per the format in the screenshot below

I have made some amendments to the cmdlet to provide this as below.
Other thresholds that are missing can be added by getting the information of the tag from the management pack xml or using the SCOM Management Pack Authoring console that can be downloaded from (Example of the tag for the threshold I added for logical Disk Free Space is as the screenshot below)

PowerShell Cmdlet (To use copy the entire contents and save it as <your filename>.ps1

    function GetThreshold ([String] $configuration)
    $config = [xml] ("<config>" + $configuration + "</config>")
    $threshold = $config.Config.Threshold
    if($threshold -eq $null)
    $threshold = $config.Config.MemoryThreshold
    if($threshold -eq $null)
    $threshold = $config.Config.CPUPercentageThreshold
    if($threshold -eq $null)
    if($config.Config.Threshold1 -ne $null -and $config.Config.Threshold2 -ne $null)
                    $threshold = "Error threshold is: " + $config.Config.Threshold1 + " Warning threshold is: " + $config.Config.Threshold2
    if($threshold -eq $null)
    if($config.Config.ThresholdWarnSec -ne $null -and $config.Config.ThresholdErrorSec -ne $null)
     $threshold = "warning threshold is: " + $config.Config.ThresholdWarnSec + " error threshold is: " + $config.Config.ThresholdErrorSec
if($threshold -eq $null)
if($config.Config.SystemDriveErrorPercentThreshold -ne $null -and $config.Config.SystemDriveErrorMBytesThreshold -ne $null -and $config.Config.NonSystemDriveErrorMBytesThreshold -ne $null -and $config.Config.SystemDriveWarningPercentThreshold -ne $null)
$threshold = "System Drive Error/Warning(%) is: " + $config.Config.SystemDriveErrorPercentThreshold + "% / " + $config.Config.SystemDriveWarningPercentThreshold + "% System Drive Error/Warning (MB) threshold is: " + $config.Config.SystemDriveErrorMBytesThreshold + "%/ " + $config.Config.SystemDriveWarningMBytesThreshold + ". " + "Non-System Drive Error/Warning (%) is : " + $config.Config.NonSystemDriveErrorPercentThreshold + "% / " + $config.Config.SystemDriveWarningPercentThreshold + "%. " + "% Non-System Drive Error/Warning (MB) threshold is: " + $config.Config.NonSystemDriveErrorMBytesThreshold + "%/ " + $config.Config.NonSystemDriveWarningMBytesThreshold
    if($threshold -eq $null)
     if($config.Config.LearningAndBaseliningSettings -ne $null)
      $threshold = "no threshold (baseline monitor)"
    return $threshold
Function GetFrequency ([String] $configuration)
$config = [xml] ("<config>" + $configuration + "</config>")
$Frequency = $config.Config.Frequency
if($Frequency -eq $null)
$frequency = $config.Config.Frequency;
 return ($frequency)
Function GetNumsamples ([String] $configuration)
$config = [xml] ("<config>" + $configuration + "</config>")
$Samples = $config.Config.Samples
if($Samples -eq $null)
$Samples = $config.Config.NumSamples;
 return ($Samples)
Function GetCounterName ([String] $configuration)
$config = [xml] ("<config>" + $configuration + "</config>")
$Counter = $config.Config.Counter
if($Counter -eq $null)
$Counter = $config.Config.CounterName;
 return ($Counter)
Function GetObject ([String] $configuration)
$config = [xml] ("<config>" + $configuration + "</config>")
$Object = $config.Config.Object
if($Object -eq $null)
$Object = $config.Config.ObjectName;
 return ($Object)

    $perfMonitors = get-monitor -Criteria:"IsUnitMonitor=1"

$perfMonitors | select-object @{Name="MP";Expression={ foreach-object {$_.GetManagementPack().DisplayName }}},@{name="Target";expression={foreach-object {(Get-MonitoringClass -Id:$_.Target.Id).DisplayName}}},DisplayName,enabled,@{name="Threshold";expression={foreach-object {GetThreshold $_.Configuration}}}, @{name="Frequency";expression={foreach-object {GetFrequency $_.Configuration}}}, @{name="Samples";expression={foreach-object {GetNumSamples $_.Configuration}}}, @{name="Counter";expression={foreach-object {GetCounterName $_.Configuration}}}, @{name="Object";expression={foreach-object {GetObject $_.Configuration}}} | sort Target, DisplayName | export-csv "c:\temp\monitor_thresholds.csv"