Search Mailboxes by Date

Had a requirement to search mailboxes by a specific date. In our case it was to look at the size of a mailbox if looking at the last 6 months. Here is something close, which will search for mail receive by a specific date.


# variables
param (
$path = "C:\temp\output.csv",
$exchangeURI = "http://ExchangeServer/PowerShell/",
$exchangeSession = "ExchangeServer"
)
# function to connect to exchange Server
Function ExchangeConnect
{
If ($Session.ComputerName -like $exchangeSession){
Write-Host "Session already established to exchange" -ForegroundColor Green
}
Else {
Write-Host "Session not made to exchange, creating session now" -ForegroundColor Red
$UserCredential = Get-Credential
$Session = New-PSSession `
-ConfigurationName Microsoft.Exchange `
-ConnectionUri $exchangeURI `
-Authentication Kerberos `
-Credential $UserCredential
Import-PSSession $Session
}
}
# Need to create a Function to Populate a list of users to $List
Function PopulateList {
}
# function to search mailboxes and get size by date range
Function SearchMailboxes {
ForEach ($user in $List){
Search-Mailbox `
-Identity $user `
-SearchQuery "Received:> $('01/01/2017') and Received:< $('08/23/2017')" `
-EstimateResultOnly | `
Export-CSV $path
}
}
# Script Main Body
ExchangeConnect
PopulateList
SearchMailboxes

I did not populate the function that gets the $List of users. This can be done with a simple search of mailboxes or a CSV import of users you want to search. I will write-up something on that if I need to.

Powershell – Getting Formatted Date Info

This is a simple one, want to get today, yesterday, last month or last year .. try this

$Date = Get-Date
$Today = $Date | Get-date -Format MM/dd/yyyy
$Yesterday = $Date.AddDays(-1) | Get-Date -Format MM/dd/yyyy
$LastMonth = $Date.AddMonths(-1) | Get-date -Format MM/dd/yyyy
$LastYear = $Date.AddYears(-1) | Get-Date -Format MM/dd/yyyy

You get the idea .. get last 6 months:
$Last6Months = $Date.AddMonths(-6) | Get-date -Format MM/dd/yyyy

Quick Powershell ShortCut

Shortcut
If you are using the where command
Get-Mailbox * | Where-Object {$_.EmailAddress -like "*something.com"}
you can use a question mark
Get-Mailbox * | ? {$_.EmailAddress -like "*something.com"}

Some others I often use:

    Format-List = FL
    Format-Table = FT
    Get-Item = gi
    Export-CSV = epcsv
    Import-PSSession = ipsn
    Add-PsSnapIn = asnp

More detailed list here: https://ss64.com/ps/

More PowerShell Fun

Here are some commands I had to use this week. For exporting users Mailbox Items to PST (and the ones that were too big to Yearly PST)


# Create PST of users mailbox + By Date - Note - Location must be a UNC Path
New-MailboxExportRequest -ContentFilter {(Received -lt '03/1/2013') -and (Received -gt '03/01/2012')} -Mailbox "User" -FilePath "\\Location\pst\User.pst"

# See mailbox export queue
Get-MailboxExportRequest

# why exports are failing with details
Get-MailboxExportRequest -status failed | Get-MailboxExportRequestStatistics -IncludeReport | Format-List > c:\temp\report.txt

# Clear out completed job queue
Get-MailboxExport Request -Status Completed | Remove-MailboxExportRequest​

LetsEncrypt – Errors

The other day I went to update my certificates and was receiving an error running the letsencrypt script to update. The error was

Error: couldn’t get currently installed version for /root/.local/share/letsencrypt/bin/letsencrypt:
An unexpected error occurred:
VersionConflict: (certbot 0.11.1 (/root/.local/share/letsencrypt/lib/python2.7/site-packages),

Or something along that lines.

After trying to remember what I changed I realized I did upgrade to the latest version of Ubuntu on this system.

After a little more troubleshooting this is how I ended up fixing it.

1. Change to your letsencrypt directory
2. Change to root – sudo su
3. remove the letsencrypt share cache (?) .. run rm -rf ~/.local/share/letsencrypt
4. ReRun the letsencrypt scripot – ./letsencrypt-auto –apache and follow the prompts

I image in could run ./letsencrypt-auto renew and it would have worked also. I will test this theory later.

Hope that helps you .

Excluding a Mailbox Database from being used

Ran into an issue with the service desk trying to use a new Mailbox server I was creating to be used as a backup server. Before I could get the DAG setup on the server we started getting tickets where new users could not access their mailboxes.

Looking into we discovered the Mailbox Database they were using were on the new server which because we kept getting pulled away from was not completely setup yet.

Of course just asking Service Desk to stop provisioning that database did not work .. they continued to do it.

So just run this command to Prevent the Database from being provisioned


Set-MailboxDatabase -Identity "Mailbox Database " -IsExcludedFromProvisioning $true

To turn it back on re-run with $False.

Storing Credentials to be used in Powershell Script

Ran into a need to store credentials for an account to run a powershell script. Examples of how you can use this would be:
1. Have the Service Desk run a script that will do a task higher than they have authorization with their normal accounts.
2. Running a script from a scheduled task
3. Just being lazy and hate typing username and password over and over

This is an example of that.

# Variables
$passwdpath = "C:\Auth\Passwd.txt"
$myusername = "username@domain.com"

# Does the file exist?, If not ask for Password and encrypt it
if(![System.IO.File]::Exists($passwdpath)){
read-host -prompt "Enter password to be encrypted in Passwd.txt " -assecurestring | convertfrom-securestring | out-file $passwdpath
}

# Script Foo Magic here
$mypass = cat $passwdpath | convertto-securestring
$mycreds = new-object `
-typename System.Management.Automation.PSCredential `
-argumentlist $myusername,$mypass

So what this is doing is checking for the Passwd.txt file and if it is not there asks for the password. It then encrypts that password within Passwd.txt.

You can also store the username in $myusername

Then anytime you need to pass the credentials for a task just pass $mycreds. That will be the credentials to run the task.

Update – Ok .. yeah I can hear all the Security Guys (Gals) out there yelling at the screen about storing credentials in files. Yes .. this is not the best solution on paper, but I am not saying to store you admin credentials here. Use common sense and restrict the account to the least privileges it needs and use logging to log who is running the script, and protect the file location .. blah blah blah .. Sometimes you have to do some things that are not best practice but Best for your environment.

Powershell 101 – Keyboard ShortCuts

Here are a few PowerShell Keyboard Shortcuts to help you out.

F7 will give list of recent commands in a popup (doesn’t work in ISE) Select the command to run it again
F9 + number will load that command from F7 if you would like to modify it
CTL + Left Arrows or Right Arrow – Moves cursor per Word vs Letter
Tab – Autocomplete

Powershell – Search all of the forest

This one keeps getting me and I thought if I wrote it down maybe .. just maybe next time I would remember.

In your current session if you are searching for an Object .. A users mailbox in my case, and you are only getting results from one of the exchange servers run the following:


Set-AdServerSettings -ViewEntireForest $true

This will set your commands to search all of the exchange servers. Just so you don’t have to mess with the -server variables.

Powershell Errors

I was tired of my co workers walking by my desk and commenting about all the “red” powershell errors scrolling up my screen. So instead of writing better code I used the simple command to put those errors in a text file instead of onscreen.

For something like:

Set-mailbox -identity $upn -DeliverToMailboxAndForward $False -ForwardingSMTPAddress $email 2>> errors.txt

using the 2>> errors.txt will put those errors in that txt file instead of scrolling up the screen.

Next I will try to work in some error checking and be a better coder .. but for now.. that works.