13 October 2015

Get-WinEvent from multiple servers Super Fast!

In the past I created a script to pull event log errors and warnings into a file and email the results.

This script stopped working, and after some digging I found that it added all the same events in every log file and combined that in to one file, which got very big. So big that it didn't get delivered to my mailbox, it got up to 75MB way above our send/receive quota. It also ran for 2 hours, while this one runs under 2 minutes!

I found several scripts/howto's and kb article's to get what I wanted and combined those in one script.
There seems to be a strange problem with Get-WinEvents, -ComputerName doesn't accept array input. So i had to write a one liner and repeat that for every server twice, one for the "System log" and one for the "Application log".

It writes 2 files per server, and collects warnings and errors only. On every run it overwrites the old file so there is no history. I made a simple webpage to quickly check the application log or the system log. You should be able to do this yourself in Word for instance.

This is what I came up with:

$ShareName = "\\domain.lan\Eventlogs"
$Date = (get-date) - (new-timespan -day 1)
$SystemLogName = "System"
$AppLogname = "Application"
$now = Get-Date -Format g
$style = "<style>BODY{font-family: Arial; font-size: 10pt;}"
$style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}"
$style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }"
$style = $style + "TD{border: 1px solid black; padding: 5px; }"
$style = $style + "</style>"

# Exchange
Get-WinEvent -FilterHashTable @{LogName='Application'; Level=1,2; StartTime=$date} -ErrorAction SilentlyContinue -ComputerName sr-XXXXX | Select-Object MachineName,TimeCreated,LogName,ProviderName,Id,LevelDisplayName,Message | ConvertTo-HTML -head $style -body "<H2>System log Report From Server SR-XXXXX $now</H2>" | Out-File "$ShareName\SR-XXXXX-$AppLogName.html"
Get-WinEvent -FilterHashTable @{LogName='System'; Level=1,2; StartTime=$date} -ErrorAction SilentlyContinue -ComputerName sr-XXXXX | Select-Object MachineName,TimeCreated,LogName,ProviderName,Id,LevelDisplayName,Message | ConvertTo-HTML -head $style -body "<H2>System log Report From Server SR-XXXXX $now</H2>" | Out-File "$ShareName\SR-XXXXX-$SystemLogName.html"
# Citrix
Get-WinEvent -FilterHashTable @{LogName='Application'; Level=1,2; StartTime=$date} -ErrorAction SilentlyContinue -ComputerName sr-XXXXX | Select-Object MachineName,TimeCreated,LogName,ProviderName,Id,LevelDisplayName,Message | ConvertTo-HTML -head $style -body "<H2>System log Report From Server SR-XXXXX $now</H2>" | Out-File "$ShareName\SR-XXXXX-$AppLogName.html"
Get-WinEvent -FilterHashTable @{LogName='System'; Level=1,2; StartTime=$date} -ErrorAction SilentlyContinue -ComputerName sr-XXXXX | Select-Object MachineName,TimeCreated,LogName,ProviderName,Id,LevelDisplayName,Message | ConvertTo-HTML -head $style -body "<H2>System log Report From Server SR-XXXXX $now</H2>" | Out-File "$ShareName\SR-XXXXX-$SystemLogName.html"

17 September 2015

Not able to mount database - Eseutil.exe to the rescue

The following error may occur:

[PS] D:\Data\mdb1\MDB1>Mount-Database mdb1 -Force -AcceptDataLoss
Failed to mount database "mdb1". Error: An Active Manager operation failed. Error: The database action failed. Error:
Operation failed with message: MapiExceptionDatabaseError: Unable to mount database. (hr=0x80004005, ec=1108)
Diagnostic context:
    Lid: 65256
    Lid: 10722   StoreEc: 0x454
    Lid: 1494    ---- Remote Context Beg ----
    Lid: 45120   dwParam: 0x592663
    Lid: 57728   dwParam: 0x5927CA
    Lid: 46144   dwParam: 0x5931BD
    Lid: 34880   dwParam: 0x5931BD
    Lid: 34760   StoreEc: 0xFFFFFB40
    Lid: 41344   Guid: f3254d9d-1279-4fb4-8ce9-6b830204afac
    Lid: 35200   dwParam: 0x10BC
    Lid: 46144   dwParam: 0x593816
    Lid: 34880   dwParam: 0x593816
    Lid: 54472   StoreEc: 0x1388
    Lid: 42184   StoreEc: 0x454
    Lid: 1750    ---- Remote Context End ----
    Lid: 1047    StoreEc: 0x454      [Database: MDB1, Server: sr-XXXXX-t.domain.lan]
    + CategoryInfo          : InvalidOperation: (MDB1:ADObjectId) [Mount-Database], InvalidOperationException
    + FullyQualifiedErrorId : [Server=SR-XXXXX-T,RequestId=32e76a8d-ed5f-4bc4-9a43-e84014d2a340,TimeStamp=9/17/2015 9:
   40:52 AM] [FailureCategory=Cmdlet-InvalidOperationException] BC20DD3D,Microsoft.Exchange.Management.SystemConfigur
  ationTasks.MountDatabase
    + PSComputerName        : sr-XXXX-t.domain.lan

After checking the disk space and all other obvious places do the following:

Copy all the original database and log files to somewhere safe. 
Then also copy them into a working directory. 
Eseutil will modify the files in situation so if it goes wrong you don't want your original files modified.

You need to have a copy of the database files (*.edb and *.stm) plus the transaction logs
(Exx*.log where xx is a number relating to the information store).
The location of the files is available from exchange system manager, but you really should know where they all are anyway.

From the database path run:

eseutil /mh databasename.edb

eseutil /p databasename.edb

eseutil /mh databasename.edb

Then  move all the log files away from Exchange log folder:
x:\databasename\Logs\*.* to x:\Temp\databasename\Logs\*.*

Then mount the database:

Mount-Database mdb1 -Force

ESEUTIL explanation:
Defragmentation
/D
Eseutil defragments the database files. This mode reduces the gross size on disk of the database (.edb) and streaming files (.stm) by discarding most empty pages and ad hoc indexes.
Repair
/P
Eseutil repairs corrupt database pages in an offline database but discards any that can't be fixed. In repair mode, the Eseutil utility fixes individual tables but does not adjust the relationships between tables. ISInteg should be used to check logical relationships between tables. 
Restore
/C
Eseutil displays the Restore.env file and controls hard recovery after restoration from online backup.
Recovery
/R
Eseutil replays transaction log files or rolls them forward to restore a database to internal consistency or to bring an older copy of a database up to date.
Integrity
/G
Eseutil verifies the page level and Extensible Storage Engine (ESE) level logical integrity of the database but does not verify database integrity at the Information Store level.
File Dump
/M
Eseutil displays headers of database files, transaction log files, and checkpoint files. The mode also displays database space allocation and metadata.
Checksum
/K
Eseutil verifies checksums on all pages in the database and streaming files.
Copy File
/Y
Eseutil performs a fast copy of very large files.

07 September 2015

Remove BlackBerry throttling policy from Exchange 2010

Find all mailboxes with the "BESPolicy"

Get-Mailbox -ResultSize Unlimited | where {$_.ThrottlingPolicy -eq "BESPolicy"}

Note - The policy name is capital sensitive

Set all found mailboxes to the default throttling policy


Get-Mailbox -ResultSize Unlimited | where {$_.ThrottlingPolicy -eq "BESPolicy"} | Set-Mailbox -ThrottlingPolicy DefaultThrottlingPolicy_7371b684-08b6-4d0a-9116-34ade049caf8

Remove the BESPolicy

[PS] Get-ThrottlingPolicy BESPolicy | Remove-ThrottlingPolicy

Confirm
Are you sure you want to perform this action?
Removing throttling policy "BESPolicy".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [?] Help (default is "Y"): y

01 September 2015

Display all active sync devices

Need a report on all the ActiveSync devices in Exchange 2010 & 2013?
This oneliner will do just that:

Get-MobileDevice | select-object DeviceModel,FriendlyName,DeviceOS,UserDisplayName | 
sort-object devicemodel | Out-GridView

Or get an overview of the number of types per type. (May take a while, depending on the number activesync devices in your organisation)

(Get-CASMailbox -ResultSize unlimited -filter {HasActiveSyncDevicepartnership -eq $true} | Get-Mailbox) | 
Foreach {Get-MobileDeviceStatistics -Mailbox $_} | Group Devicemodel | Sort Count -Descending | Select Count, Name

Find and remove all devices that have not synced over 30 days:

$DevicesToRemove = Get-MobileDevice -result unlimited | 
Get-MobileDeviceStatistics | where {$_.LastSuccessSync -le (Get-Date).AddDays("-30")}
$DevicesToRemove | foreach-object {Remove-MobileDevice ([string]$_.Guid) -confirm:$false}

15 July 2015

Whitespace report

With the help from Paul Cunningham's tutorial on how to send HTML formatted email with powershell, i threw together this small script to quickly get an overview of the available new mailbox database space, also know as "whitespace".

$Date = Get-Date
$smtpServer = "smtp.domain.lan"
$smtpFrom = "WhiteSpace@domain.nl"
$smtpTo = "receipient@domain.nl"
$messageSubject = "WhiteSpace report for $Date"

$message = New-Object System.Net.Mail.MailMessage $smtpfrom, $smtpto
$message.Subject = $messageSubject
$message.IsBodyHTML = $true

$a = "<style>"
$a = $a + "BODY{font-family: Arial; font-size: 10pt;}"
$a = $a + "TABLE{border: 1px solid black; border-collapse: collapse;}"
$a = $a + "TH{border: 1px solid black; background: #dddddd; padding: 5px;}"
$a = $a + "TD{border: 1px solid black; padding: 5px;}"
$a = $a + "</style>"

$message.Body = Get-MailboxDatabase -Status | sort name | select name,@{Name='DB Size (Gb)';Expression={$_.DatabaseSize.ToGb()}},@{Name='Available New Mbx Space Gb)';Expression={$_.AvailableNewMailboxSpace.ToGb()}} | ConvertTo-Html -Head $a

$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($message)

The result looks like this:

Run from the Task scheduler with this line:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command ". 'C:\Program Files\Microsoft\Exchange Server\V14\Bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto; 'C:\_Scripts\Exchange\WhiteSpace.ps1'"

13 July 2015

Exchange 2013 OWA blank page error 400

If you encounter this problem (bad request, http 400 error) on your Exchange 2013 infrastructure.
These are the steps that you can follow to fix it.
Note:The powershell scripts are not mentioned anywhere in the official Technet documentation.
The powershell scripts are only mentioned on several blogposts regarding Microsoft Exchange 2010.
  1. Login to your Exchange 2013 CAS server
  2. Start the Exchange Management Shell
  3. Navigate to your Exchange 2013 binaries location, for example:C:\Program Files\Microsoft\Exchange Server\V15\Bin\
  4. Execute the UpdateCas.ps1 Windows PowerShell script and wait a few moments.
    This script will rebuild your OWA interface.
  5. If you haven’t executed UpdateConfigFiles.ps1 , now is a good time. Execute it.
    It looks like you need to execute this Windows PowerShell script, after each cumulative update of Microsoft Exchange 2013 to keep everything working smooth.

Conclusion
After each installation of a cumulative update for Exchange 2013, remember to execute both the UpdateCas.ps1 and UpdateConfigFiles.ps1 Windows PowerShell scripts.
It will save you a lot of trouble, troubleshooting errors with OWA and ECP.

06 July 2015

Restart all exchange 2013 services

Need to restart all Exchange 2013 services?

Restart the "Microsoft Exchange Active Directory Topology" service and all Exchange related services will restart.



Or do the same in Powershell:

Restart-Service MSExchangeADTopology

02 July 2015

Hide your internal server names from email header

When sending email to an organization outside your lan you also send some information that you don't want to expose and even in some cases those emails are not accepted because the SPF rules state that no local domain names are accepted, as they cannot be resolved by reverse DNS checking the HELO.

One way of dealing with this issue is to remove the anonymous access right on the send connector:

Get-SendConnector “Connector Name” | Remove-ADPermission -AccessRight ExtendedRight -ExtendedRights ms-Exch-Send-Headers-Routing -user “NT AUTHORITY\Anonymous Logon”


In my opinion there's an easier way, one that can be rolled back instantly in case something goes wrong or causes errors.
Create a Transport rule that removes the "header" from all out going messages.


Open Microsoft Exchange Console
Navigate to:
Microsoft Exchange \ Organization Configuration \ Hub Transport \ Transport Rules





  • Right Click and select New Transport Rule 
  • Name it " Remove headers "Received" ” 
  • click Next
  • Choose "From users inside or outside the organization"
  • Select Inside click Next
  • Choose Remove header
  • As message header just write: "Received"
  • Click Next twice

27 June 2015

Installing Office 2016 Preview, error 0-1028 (0)

When trying to install the Office 2016 Preview, you may receive error 0-1028 (0).

To get past this error delete the following folder:
C:\Program Files\Common Files\Microsoft Shared\ClickToRun

09 June 2015

Remove the Exchange 2013 default database after installation

After installing Exchange 2013 there is always a standard/default mailbox database.
When trying to remove it, you get errors stating that there are still mailboxes on it.

Move all those mailboxes to your newly created mailbox database:

Get-Mailbox -Database “Mailbox Database 1905367170″ -Arbitration -PublicFolder -Monitoring | New-MoveRequest –TargetDatabase “Your Mailbox Database

Install Exchange with the correct Database and log files path:

For Exchange 2010:
setup /mode:install /roles:c,h,m,t /mdbname:MDB01 /DbFilePath:E:\MDB01DB\MDB01.edb /LogFolderPath:D:\MDB01LOG


For Exchange 2013:
setup /mode:install /roles:c,m -MDBDBPath C:\MailboxData\MDB1\DB -MDBLogPath C:\MailboxData\MDB1\Log -MDBName MDB1


If you're migrating from Exchange 2010 to Exchange 2013, you still get an error:

Error:
This mailbox database contains one or more mailboxes, mailbox plans, archive mailboxes, or arbitration mailboxes. To get a list of all mailboxes in this database, run the command Get-Mailbox -Database <Database ID>. To get a list of all mailbox plans in this database, run the command Get-MailboxPlan. To get a list of archive mailboxes in this database, run the command Get-Mailbox -Database <Database ID> -Archive. To get a list of all arbitration mailboxes in this database, run the command Get-Mailbox -Database <Database ID> -Arbitration. To disable a non-arbitration mailbox so that you can delete the mailbox database, run the command Disable-Mailbox <Mailbox ID>. To disable an archive mailbox so you can delete the mailbox database, run the command Disable-Mailbox <Mailbox ID> -Archive. Arbitration mailboxes should be moved to another server; to do this, run the command New-MoveRequest <parameters>. If this is the last server in the organization, run the command Disable-Mailbox <Mailbox ID> -Arbitration -DisableLastArbitrationMailboxAllowed to disable the arbitration mailbox. Mailbox plans should be moved to another server; to do this, run the command Set-MailboxPlan <MailboxPlan ID> -Database <Database ID>.

This is because the exchange setup process setup /p or /prepareAD creates these accounts.

First run the cmdlet to see that you have the Arbitration mailboxes alive:

Set-AdServerSettings -ViewEntireForest $True

This is because Arbitration mailboxes are created on the root domain by default.


Now run:


Get-Mailbox -Arbitration | Ft Name, Database

Now if you need to remove it and have another database available to home these, run the cmdlet:


Get-Mailbox -Arbitration | Set-Mailbox -Arbitration -Database “Name of the new Database”
If you want to Move Arbitration to a new mailbox store and the old store is mounted and well,

Get-Mailbox -Arbitration -Database “CurrentDatabase” | New-MoveRequest -TargetDatabase “NewDatabaseName”

Lets say the database contains mailboxes other than Arbitration and you want to move all of them to a new mailbox store and the old store is mounted and well,


Get-Mailbox -Database “CurrentDatabase” | New-MoveRequest -TargetDatabase “NewDatabaseName”

If you want to Disable Arbitration mailboxes run:


Get-Mailbox -Arbitration -Database “CurrentDatabase” | Disable-Mailbox -Arbitration
If you want to remove Arbitration mailboxes run:

Get-Mailbox -Arbitration -Database “CurrentDatabase” | Remove-Mailbox -Arbitration –RemoveLastArbitrationMailboxAllowed

Now for some reason these Arbitration mailboxes went missing, then find the version of your exchange server using the cmdlet, then download the appropriate service pack and run setup /p

GCM exsetup |%{$_.Fileversioninfo}

You may also replace the homeMDB value of the Arbitration mailbox with the DN of a mailbox database too.


To move Arbitration mailboxes from Exchange 2010 to Exchange 2013:

Get-MailboxDatabase -IncludePreExchange2013 | FL Name,Server,AdminDisplayVersion

Get-Mailbox -Arbitration | New-MoveRequest -TargetDatabase <NewDatabaseinExchange2013>

Source
Source