Script

Update: Exchange 2013 script – automatic installation of prerequisites v2.1 *NEW*

Update: Exchange 2013 script – automatic installation of prerequisites v2.1 *NEW*

*Update*

*********************************************************************************************************************************************

Reuben Welsh came up with a great feature request regarding verifying the checksum of the files that’s being installed.
This has been implemented in the version 2.1 of the script.

*********************************************************************************************************************************************

For a year ago I was publishing a script that helped with installing prerequsites for Exchange 2013, this has now been updated so it also works for Exchange 2013 SP1 and Windows Server 2012 R2.
I hope this script helps someone for a smoother installation.
The script can be downloaded here: http://www.testlabs.se/blog/wp-content/uploads/2014/04/Install-Exchange2013PreReqs_v2.1.zip

*********************************************************************************************************************************************

Feel free to use this, make sure to test it in a test environment before using it inside production.
All contents is provided “AS IS” with no warranties, and confers no rights. You assume all risk for your use.

# +=======================================================================
 # | Blog: <a href="http://www.testlabs.se/blog">http://www.testlabs.se/blog</a>
 # | Twitter: @jonand82
 # | =============================================
 # | Filename: Install-Exchange2013PreReqs_v2.1.ps1
 # |
 # | CREATED BY: Jonas Andersson - Original written by: Pat Richard, Anderson Patricio and Bhargav Shukla
 # | FUNCTION: Installs and configures the prerequisites to install Exchange 2013 on..
 # | ..Windows Server 2008 R2, Windows Server 2012 or Windows Server 2012 R2 server
 # |
 # | CHANGE LOG:
 # | v1.0 - 2013-04-05, *Created*
 # | v2.0 - 2014-04-11, *Updated with functions*
 # | v2.1 - 2014-04-28, *Checksum implemented*
 # |
 # | <a href="http://www.ucblogs.net/blogs/exchange/archive/2009/12/12/Automated-prerequisite-installation-via-PowerShell-for-Exchange-Server-2010-on-Windows-Server-2008-R2.aspx">http://www.ucblogs.net/blogs/exchange/archive/2009/12/12/Automated-prerequisite-installation-via-PowerShell-for-Exchange-Server-2010-on-Windows-Server-2008-R2.aspx</a>
 # | <a href="http://msmvps.com/blogs/andersonpatricio/archive/2009/11/13/installing-exchange-server-2010-pre-requisites-on-windows-server-2008-r2.aspx">http://msmvps.com/blogs/andersonpatricio/archive/2009/11/13/installing-exchange-server-2010-pre-requisites-on-windows-server-2008-r2.aspx</a>
 # | <a href="http://www.bhargavs.com/index.php/powershell/2009/11/script-to-install-exchange-2010-pre-requisites-for-windows-server-2008-r2/">http://www.bhargavs.com/index.php/powershell/2009/11/script-to-install-exchange-2010-pre-requisites-for-windows-server-2008-r2/</a>
 # | <a href="http://www.tinyint.com/index.php/2011/09/14/get-an-md5-or-sha1-checksum-with-powershell/">http://www.tinyint.com/index.php/2011/09/14/get-an-md5-or-sha1-checksum-with-powershell/</a>
 # +=======================================================================

# Detect correct OS here and exit if no match
 if (-not((Get-WMIObject win32_OperatingSystem).OSArchitecture -eq '64-bit') -and (((Get-WMIObject win32_OperatingSystem).Version -eq "6.1.7601") -or ((Get-WMIObject win32_OperatingSystem).Version -eq "6.2.9200") -or ((Get-WMIObject win32_OperatingSystem).Version -eq "6.3.9600"))) {
 Write-Host "This script requires a 64bit version of Windows Server 2008 R2, Windows Server 2012 or Windows Server 2012 R2, which this is not." -ForegroundColor Red -BackgroundColor Black
 Exit
 }

function Get-Checksum
 {
 Param (
 [string]$File=$(throw("You must specify a filename to get the checksum of.")),
 [ValidateSet("sha1","md5")]
 [string]$Algorithm="sha1"
 )

$fs = new-object System.IO.FileStream $File, "Open"
 $algo = [type]"System.Security.Cryptography.$Algorithm"
 $crypto = $algo::Create()
 $hash = [BitConverter]::ToString($crypto.ComputeHash($fs)).Replace("-", "")
 $fs.Close()
 $hash
 }

function Disable-UAC() {

function UAC-status() {

$path = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System"
 $EnableLUA = ""
 $EnableLUA = Get-ItemProperty $path -Name EnableLUA

if ($EnableLUA.EnableLUA -eq "0") {
 [bool]$UACenabled = $false
 }

if ($EnableLUA.EnableLUA -eq "1") {
 [bool]$UACenabled = $true
 }

return $UACenabled
 }

[bool]$status = UAC-status

if ($status -ne $true) {
 Write-Host "UAC already disabled" -ForegroundColor Green
 return
 }

else {

Write-Host "Starting to disable UAC.."

Set-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System" -Name "EnableLUA" -Value 0
 Start-Sleep -Seconds 2

[bool]$status = UAC-status

if ($status -ne $false) {
 Write-Host "An error occurred, try again." -ForegroundColor Red
 return
 }

else {
 Write-Host "UAC Enabled:", $status
 Write-Host "...."
 Write-Host "UAC is now disabled" -ForegroundColor Green
 Write-Host "Registry key HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA has been changed." -ForegroundColor White
 }
 }
 }

function Disable-FW() {

function FW-status() {

$status = ""
 $status = netsh advfirewall show allprofiles state

if ($status | Select-String "ON") {
 [bool]$enabled = $true
 }

else {
 [bool]$enabled = $false
 }

return $enabled
 }

[bool]$fwstatus = FW-status

if ($fwstatus -eq $false) {
 Write-Host "Firewall is already disabled" -ForegroundColor Green
 return
 }

if ($fwstatus -eq $true) {

Write-Host "Starting to disable the firewall.."

$param = "advfirewall set allprofiles state off"
 $run = (Start-Process netsh -ArgumentList $param -Wait -PassThru).ExitCode
 if ($run -ne 0) { Write-Host "Failed!" -ForegroundColor Red }

[bool]$fwstatus = FW-status

if ($fwstatus -ne $false) {
 Write-Host "An error occurred, try again." -ForegroundColor Red
 return
 }

else {
 Write-Host "Firewall enabled:", $fwstatus
 Write-Host "...."
 Write-Host "Firewall is now disabled" -ForegroundColor Green
 }
 }
 }

function InstallFilterPack() {

function DownloadFilterPack1() {

#Download Microsoft Filter Pack
 Write-Host "Downloading Microsoft Filter Pack..." -nonewline
 $clnt = New-Object System.Net.WebClient
 $url = "<a href="http://download.microsoft.com/download/0/A/2/0A28BBFA-CBFA-4C03-A739-30CCA5E21659/FilterPack64bit.exe&quot;">http://download.microsoft.com/download/0/A/2/0A28BBFA-CBFA-4C03-A739-30CCA5E21659/FilterPack64bit.exe"</a>
 $clnt.DownloadFile($url,$file1)
 Write-Host "done!" -ForegroundColor Green
 }

function DownloadFilterPack2() {

#Download Microsoft Filter Pack SP1
 Write-Host "Downloading Microsoft Filter Pack SP1..." -nonewline
 $clnt = New-Object System.Net.WebClient
 $url = "<a href="http://download.microsoft.com/download/A/A/3/AA345161-18B8-45AE-8DC8-DA6387264CB9/filterpack2010sp1-kb2460041-x64-fullfile-en-us.exe&quot;">http://download.microsoft.com/download/A/A/3/AA345161-18B8-45AE-8DC8-DA6387264CB9/filterpack2010sp1-kb2460041-x64-fullfile-en-us.exe"</a>
 $clnt.DownloadFile($url,$file2)
 Write-Host "done!" -ForegroundColor Green
 }

function InstallFilterPack1() {

#Install Microsoft Filter Packs 1
 Write-Host "Installing Microsoft Filter Packs..."

$args = "/quiet /norestart"
 $setup1 = (Start-Process $file1 -ArgumentList $args -Wait -PassThru).ExitCode
 if ($setup1 -eq 0) {
 Write-Host "Successfully installed $file1" -ForegroundColor Green
 }

if ($setup1 -ne 0) {
 Write-Host "Failed!" -ForegroundColor Red
 }
 }

function InstallFilterPack2() {

$args = "/quiet /norestart"
 $setup2 = (Start-Process $file2 -ArgumentList $args -Wait -PassThru).ExitCode
 if ($setup2 -eq 0) {
 Write-Host "Successfully installed $file2" -ForegroundColor Green
 }

if ($setup2 -ne 0) {
 Write-Host "Failed!" -ForegroundColor Red
 }
 }

if (Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\{95140000-2000-0409-1000-0000000FF1CE}" -ErrorAction SilentlyContinue) {

Write-Host "FilterPack is already installed." -ForegroundColor Yellow
 return
 }

else {

trap {
 Write-Host "Problem downloading FilterPackx64.exe. Please visit: <a href="http://www.microsoft.com/en-us/download/details.aspx?id=26604">http://www.microsoft.com/en-us/download/details.aspx?id=26604</a> and <a href="http://www.microsoft.com/en-us/download/details.aspx?id=17062&quot;">http://www.microsoft.com/en-us/download/details.aspx?id=17062"</a>
 break
 }

#set a var for the folder you are looking for
 $folderPath = 'C:\Temp'

#Check if folder exists, if not, create it
 if (Test-Path $folderpath) {
 Write-Host "The folder $folderPath exists."
 }

else {
 Write-Host "The folder $folderPath does not exist, creating..." -NoNewline
 New-Item $folderpath -type directory | Out-Null
 Write-Host "done!" -ForegroundColor Green
 }

$file1 = $folderPath+"\FilterPack64bit.exe"
 $file1chksum = "9253B09EA9A2ADD0E773CD30FE4120F5732C4D98"

$file2 = $folderPath+"\filterpack2010sp1-kb2460041-x64-fullfile-en-us.exe"
 $file2chksum = "2C7B81D0C148E3E1894A9183FEE6A543EA5DC9B2"

# Check if file exists, if not, download it
 if (Test-Path $file1) {
 Write-Host "The file $file1 exists."

$chksum1 = Get-Checksum $file1
 if ($file1chksum.CompareTo($chksum1) -eq 0) {
 Write-Host "Checksum OK" -ForegroundColor 'Green'
 InstallFilterPack1
 }

else {
 Write-Host "Checksum Error, removing $file1" -ForegroundColor 'Red'
 Remove-Item $file1
 DownloadFilterPack1
 InstallFilterPack1
 }
 }

else {
 #Download Microsoft Filter Pack
 DownloadFilterPack1

#Install FilterPack 1
 InstallFilterPack1
 }

if (Test-Path $file2) {
 Write-Host "The file $file2 exists."

$chksum2 = Get-Checksum $file2
 if ($file2chksum.CompareTo($chksum2) -eq 0) {
 Write-Host "Checksum OK" -ForegroundColor 'Green'
 InstallFilterPack2
 }

else {
 Write-Host "Checksum Error, removing $file2" -ForegroundColor 'Red'
 Remove-Item $file2
 DownloadFilterPack2
 InstallFilterPack2
 }
 }

else {
 #Download Microsoft Filter Pack SP1
 DownloadFilterPack2

#Install Microsoft Filter Pack SP1
 InstallFilterPack2
 }
 }
 }

function InstallUMAPI() {

function InstallMicrosoftUMAPI() {

#Check/Install Media Foundation feature
 $mf = Get-WindowsFeature "Server-Media-Foundation" | select *

Start-Sleep 2

if ($mf.Installed -eq $False) {

Write-Host "Installing Media Foundation feature..."    -ForegroundColor Green
 Add-Windowsfeature Server-Media-Foundation

Write-Host ""
 Write-Host "Installing of Media Foundation feature completed." -ForegroundColor Green
 Write-Host ""
 Write-Host "Restart the server and restart the task" -ForegroundColor Red
 Write-Host "or else the UM API won't be installed" -ForegroundColor Red
 Write-Host ""
 return
 }

if ($mf.Installed -eq $True) {

#Install Microsoft UM API
 Write-Host "Installing Microsoft UM API..." -ForegroundColor Green

$args = "/quiet /norestart"
 $setup = (Start-Process $file -ArgumentList $args -Wait -PassThru).ExitCode
 if ($setup -eq 0) {
 Write-Host "Successfully installed $file" -ForegroundColor Green
 }

if ($setup -ne 0) {
 Write-Host "Failed!" -ForegroundColor Red
 }
 }
 }

function DownloadMicrosoftUMAPI() {

#Download Microsoft UM API
 Write-Host "Downloading Microsoft UM API..." -nonewline
 $clnt = New-Object System.Net.WebClient
 $url = "<a href="http://download.microsoft.com/download/2/C/4/2C47A5C1-A1F3-4843-B9FE-84C0032C61EC/UcmaRuntimeSetup.exe&quot;">http://download.microsoft.com/download/2/C/4/2C47A5C1-A1F3-4843-B9FE-84C0032C61EC/UcmaRuntimeSetup.exe"</a>
 $clnt.DownloadFile($url,$file)
 Write-Host "done!" -ForegroundColor Green
 }

#Checking for regkey
 if (Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\UCMA4" -ErrorAction SilentlyContinue) {

Write-Host "Unified Communications Managed API 4.0 Runtime is already installed." -ForegroundColor yellow
 return
 }

else {

trap {
 Write-Host "Problem downloading UM API. Please visit: <a href="http://www.microsoft.com/en-us/download/details.aspx?id=34992&quot;">http://www.microsoft.com/en-us/download/details.aspx?id=34992"</a>
 break
 }

#set a var for the folder you are looking for
 $folderPath = 'C:\Temp'

#Check if folder exists, if not, create it
 if (Test-Path $folderpath) {
 Write-Host "The folder $folderPath exists."
 }

else {
 Write-Host "The folder $folderPath does not exist, creating..." -NoNewline
 New-Item $folderpath -type directory | Out-Null
 Write-Host "done!" -ForegroundColor Green
 }

# Check if file exists, if not, download it
 $file = $folderPath+"\UcmaRuntimeSetup.exe"
 $filechksum = "5E4D536E916F9C97EE5A91A61952589825AEAA6C"
 if (Test-Path $file) {
 Write-Host "The file $file exists."

$chksum3 = Get-Checksum $file
 if ($filechksum.CompareTo($chksum3) -eq 0) {
 Write-Host "Checksum OK" -ForegroundColor 'Green'

#Install Microsoft UM API
 InstallMicrosoftUMAPI
 }

else {
 #Remove the file with wrong checksum
 Remove-Item $file

#Download Microsoft UM API
 DownloadMicrosoftUMAPI

#Install Microsoft UM API
 InstallMicrosoftUMAPI
 }
 }

else {
 #Download Microsoft UM API
 DownloadMicrosoftUMAPI

#Install Microsoft UM API
 InstallMicrosoftUMAPI
 }
 }
 }

Import-Module ServerManager
 $opt = "None"
 # Do {
 clear
 if ($opt -ne "None") {Write-Host "Last command: "$opt -foregroundcolor Yellow}
 Write-Host
 Write-Host Exchange Server 2013 SP1 - Prerequisites script
 Write-Host Please, select which role you are going to install..
 Write-Host
 Write-Host '1) Client Access Server'
 Write-Host '2) Mailbox'
 Write-Host '3) Typical (CAS/Mailbox)'
 Write-Host
 Write-Host '10) Install Microsoft Filter Pack 2.0'
 Write-Host '    Recommended if installing Mailbox Server roles' -foregroundcolor yellow
 Write-Host '    Automatically set for options 2 and 3' -foregroundcolor yellow
 Write-Host '11) Install Microsoft UM API' -foregroundcolor yellow
 Write-Host '    Automatically set for options 1, 2 and 3' -foregroundcolor yellow
 Write-Host '12) Disable UAC'
 Write-Host '13) Disable Firewall'
 Write-Host
 Write-Host '18) Restart the Server'
 Write-Host '19) End'
 Write-Host
 $opt = Read-Host "Select an option.. [1-19]? "

$Win2008feat = "Desktop-Experience", "NET-Framework", "NET-HTTP-Activation", "RPC-over-HTTP-proxy", "RSAT-Clustering", "RSAT-Web-Server", "WAS-Process-Model", "Web-Asp-Net", "Web-Basic-Auth", "Web-Client-Auth", "Web-Digest-Auth", "Web-Dir-Browsing", "Web-Dyn-Compression", "Web-Http-Errors", "Web-Http-Logging", "Web-Http-Redirect", "Web-Http-Tracing", "Web-ISAPI-Ext", "Web-ISAPI-Filter", "Web-Lgcy-Mgmt-Console", "Web-Metabase", "Web-Mgmt-Console", "Web-Mgmt-Service", "Web-Net-Ext", "Web-Request-Monitor", "Web-Server", "Web-Stat-Compression", "Web-Static-Content", "Web-Windows-Auth", "Web-WMI"
 $Win2012feat = "AS-HTTP-Activation", "Desktop-Experience", "NET-Framework-45-Features", "RPC-over-HTTP-proxy", "RSAT-Clustering", "RSAT-Clustering-CmdInterface", "RSAT-Clustering-Mgmt", "RSAT-Clustering-PowerShell", "Web-Mgmt-Console", "WAS-Process-Model", "Web-Asp-Net45", "Web-Basic-Auth", "Web-Client-Auth", "Web-Digest-Auth", "Web-Dir-Browsing", "Web-Dyn-Compression", "Web-Http-Errors", "Web-Http-Logging", "Web-Http-Redirect", "Web-Http-Tracing", "Web-ISAPI-Ext", "Web-ISAPI-Filter", "Web-Lgcy-Mgmt-Console", "Web-Metabase", "Web-Mgmt-Console", "Web-Mgmt-Service", "Web-Net-Ext45", "Web-Request-Monitor", "Web-Server", "Web-Stat-Compression", "Web-Static-Content", "Web-Windows-Auth", "Web-WMI", "Windows-Identity-Foundation"

switch ($opt) {
 1 {

# Windows Server 2008 R2 SP1
 if ((Get-WMIObject win32_OperatingSystem).Version -eq "6.1.7601") {

InstallUMAPI
 Import-Module ServerManager
 Add-WindowsFeature $Win2008feat -restart
 }

# Windows Server 2012 or Windows Server 2012 R2
 if (((Get-WMIObject win32_OperatingSystem).Version -eq "6.2.9200") -or ((Get-WMIObject win32_OperatingSystem).Version -eq "6.3.9600")) {

InstallUMAPI
 Install-WindowsFeature $Win2012feat -restart
 }
 }

2 {

# Windows Server 2008 R2 SP1
 if ((Get-WMIObject win32_OperatingSystem).Version -eq "6.1.7601") {

Import-Module ServerManager
 InstallUMAPI
 InstallFilterPack
 Add-WindowsFeature $Win2008feat -restart
 }

# Windows Server 2012 or Windows Server 2012 R2
 if (((Get-WMIObject win32_OperatingSystem).Version -eq "6.2.9200") -or ((Get-WMIObject win32_OperatingSystem).Version -eq "6.3.9600")) {

InstallUMAPI
 InstallFilterPack
 Install-WindowsFeature $Win2012feat -restart
 }
 }

3 {

# Windows Server 2008 R2
 if ((Get-WMIObject win32_OperatingSystem).Version -eq "6.1.7601") {

Import-Module ServerManager
 InstallFilterPack
 InstallUMAPI
 Add-WindowsFeature $Win2008feat -restart
 }

# Windows Server 2012 or Windows Server 2012 R2
 if (((Get-WMIObject win32_OperatingSystem).Version -eq "6.2.9200") -or ((Get-WMIObject win32_OperatingSystem).Version -eq "6.3.9600")) {

InstallUMAPI
 InstallFilterPack
 Install-WindowsFeature $Win2012feat -restart
 }
 }

10 {
 # future - auto detect Internet access
 Write-Host 'Can this server access the Internet?'
 $filtpack = Read-Host 'Please type (Y)es or (N)o...'
 switch ($filtpack)                {
 Y { InstallFilterPack }
 N {Write-warning 'Please download and install Microsoft Filter Pack from here: <a href="http://www.microsoft.com/en-us/download/details.aspx?id=26604">http://www.microsoft.com/en-us/download/details.aspx?id=26604</a> and <a href="http://www.microsoft.com/en-us/download/details.aspx?id=17062'}">http://www.microsoft.com/en-us/download/details.aspx?id=17062'}</a>
 }
 }

11 {
 # future - auto detect Internet access
 Write-Host 'Can this server access the Internet?'
 $umapi = Read-Host 'Please type (Y)es or (N)o...'
 switch ($umapi)                {
 Y { InstallUMAPI }
 N {Write-Warning 'Please download and install Microsoft UM API from here: <a href="http://www.microsoft.com/en-us/download/details.aspx?id=34992'}">http://www.microsoft.com/en-us/download/details.aspx?id=34992'}</a>
 }
 }

12 { Disable-UAC }
 13 { Disable-FW }
 18 { Restart-Computer }
 19 {
 Write-Host "Exiting..."
 Exit
 }
 default {Write-Host "You haven't selected any of the available options. "}
 }

Bulk import PST files – [updated] v1.1

Bulk import PST files – [updated] v1.1

Just wrote a basic script for importing PST files into mailboxes, that I want to share with the community.

It is designed to check for PST files in the specified folder. Based on the filenames (of the PST files) it then verifies that a mailbox can be found. This is done by using the filename and adding the @ character and the domain value into a string value. If there is a match, it returns a value of $True and the script continues with running the New-MailboxImportRequest cmdlet.

The script is written just as basic as it can, it provides much information about values and what’s going on.
The most recent updated script can be downloaded here

I hope this will help you to import the PST files into the mailboxes

Ps. Sorry for the word-wrap, see the script file instead of copy the script code below

Changelog
v1.1
– Updated the $name variable due to issues with filenames got trimmed away. Also added so that if errors exists, they will be sent to a errorlog. Thanks to Chris Steding!

# +=======================================================================
# | Blog: http://www.testlabs.se/blog
# | Twitter: @jonand82
# | =============================================
# | Filename: Import-PST v1.1.ps1
# |
# | CREATED BY: Jonas Andersson
# | FUNCTION: Imports PST files into mailboxes, matching on emailaddresses
# |
# | CHANGE LOG: 
# | v1.0 - 2013-09-18, *Created*
# | v1.1 - 2013-09-22, *Update of $name variable*
# |
# |    Required permissions (RBAC) Role: “Mailbox Import Export”, example: New-Managementroleassignment –Role “Mailbox Import Export” –User “Administrator”
# +=======================================================================

# Load snapin
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction 'SilentlyContinue'

# Variables
$error.clear()
$errorlog = "C:\temp\errorlog.txt"
$pstpath = "C:\temp"
$domain = "testlabs.se"
$servername = "tlex01"
$files = Get-ChildItem -Path $pstpath -Filter *.pst

Write-Host $files

if (($files -ne $null) -or ($files -eq "")) {

    foreach ($i in $files) {

        $name = $i.BaseName
        $id = $name + "@" + $domain
        $filename = $i.FullName
        $filename = $filename.Replace(":","$")
        $uncfilepath = "\\" + $servername + "\" + $filename

        Write-Host "#################################################################"
        Write-Host "Filename:" $i -ForegroundColor 'Cyan'
        Write-Host "UNC path:" $uncfilepath -ForegroundColor 'DarkCyan'
        Write-Host "Emailaddress:" $id -ForegroundColor 'DarkGreen'

        $MailboxExists = [bool](Get-Mailbox -Identity $id -ErrorAction SilentlyContinue)

        if ($MailboxExists -eq $false)
        {
            Write-Host "Found mailbox:" $MailboxExists -ForegroundColor 'Red'
            Write-Host "Make sure to match filename to mailaddress, without @domain" -ForegroundColor 'Red'

        }

        if ($MailboxExists -eq $true)
        {
            Write-Host "Found mailbox:" $MailboxExists -ForegroundColor 'Green'
            Write-Host "Importing $uncfilepath into mailbox: $id" -ForegroundColor 'White'

            New-MailboxImportRequest -Mailbox $id -FilePath $uncfilepath

        }

        Write-Host ""
    }

}

else
{
    Write-Host "No PST files found"
}

if ($error -ne $null)
{
    $error | Out-File -FilePath $errorlog -Append
    Write-Host "See $errorlog for errors" -ForegroundColor 'Red'
}
Migration Preparation script

Migration Preparation script

This script idea came up after being involved in a migration project.

Published: 2013-05-22
Updated: 2013-05-24
Version: 1.1

It’s purpose with this script is for getting Quest Migration Manager (QMM) being able to match objects between domains. In a scenario with one-way trust and not being able to use Quest Migration Manager AD or any other tool for providing the SIDHistory into the AD objects. Users, mailboxes and mail contacts are already created, where the contacts are used for having a global address list (GAL) object they can send emails to.

Using QMM you can match by Username, Mailaddress or SIDHistory. In my case the username differs and the SIDHistory is not available (not allowed being copied into the target AD).

I created four different functions within this script, one called “Export-SourceInformation”, which should be used in the source environment. It will export the information from the source regarding Name, DisplayName, PrimarySmtpAddress, RecipientTypeDetails and save it into a CSV file called “users.csv”.

Then bring the CSV file into the target environment. This CSV file should be used as a control file if you don’t want to run all users at the same time (run some tests before running all of them in one batch).
I would recommend a couple of smaller batches for testing the functions before deploying it in full scale.

There is a function called “Verify-TargetInformation”, which uses the CSV file called “users.csv” and retrieves the Name and PrimarySmtpAddress for each object in the CSV file.

Another function is called “Set-SourceAddress”, this part takes care of the target account.
It uses the file called “users.csv” and checks whether there are any contacts for these mailboxes, if there are the mail contact will be deleted and the mailbox forward settings will be removed together with making sure that the mailbox is showed in the GAL. But before any changes are done, the current configuration for both the mail contact and the mailbox object are being saved into a CSV file called “targetinformation.csv”.

Last but not least, the function called “Rollback-TargetInformation” is used for putting back the PrimarySmtpAddress to the value that it was prior to the change, this by using the CSV file “targetinformation.csv”. When the Directory Synchronization have successfully matched the mailboxes this function should be runned for having back the correct information.

You can use this for free, without any guarantee or warranty and at your own risk.
Feel free to post about it, just make sure to link my blog and blogpost.

Download the script

##################################################################################### 
# Filename: Migration-Preparation-testlabs.ps1  
# Description: 
# This PowerShell script exports information, configures objects and prepares for 
# Quest Migration Manager EX Directory Synchronization 
# 
# Usage: Import-Module Migration-Preparation-testlabs.ps1 
# Start with importing the module, then Starting function: Export-SourceInformation; 
# Set-SourceAddress; Rollback-TargetInformation; Verify-TargetInformation 
# 
# Version: 1.1
#
# Changelog:
# v1.1 - Introduced LegacyExchangeDN - X500 preparation
#
# Jonas Andersson, MCC 2011 & 2012 
# http://www.testlabs.se/blog 
# Twitter @jonand82 
#####################################################################################

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction SilentlyContinue
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin -ErrorAction SilentlyContinue

## Exporting the SMTP information from Source mailboxes 
Function Export-SourceInformation(){ 

    $filename = "users.csv" 

    $users = Get-Mailbox -resultsize unlimited | Select Name,DisplayName,PrimarySmtpAddress,RecipientTypeDetails,LegacyExchangeDN
    $users | Export-CSV $filename -notype -Encoding Unicode 

}

## Changing Target mailboxes to Source PrimarySmtpAddress for QMM to match on it 
Function Set-SourceAddress(){ 

    $data = Import-CSV .\users.csv 
    $filename = "targetinformation.csv" 

    ## Saving Target Information into CSV file before changing 
    $MasterList = @() 
    Foreach($t in $data) 
    { 
        $str = $t.displayname 
        $MyObject = New-Object PSObject -Property @{ 

        Name = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").Name 
        DisplayName = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").DisplayName 
        PrimarySmtpAddress = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").PrimarySmtpAddress 
        RecipientTypeDetails = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").RecipientTypeDetails 
        Email = ((Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").EmailAddresses -Join ";") 
        DeliverToMailboxAndForward = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").DeliverToMailboxAndForward 
        ForwardingAddress = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").ForwardingAddress 
        ForwardingSmtpAddress = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").ForwardingSmtpAddress 
        HiddenFromAddressListsEnabled = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").HiddenFromAddressListsEnabled 
        LegacyExchangeDN = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").LegacyExchangeDN
        ContactName = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").Name 
        ContactDisplayName = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").DisplayName 
        ContactPrimarySmtpAddress = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").PrimarySmtpAddress 
        ContactEmail = ((Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").EmailAddresses -Join ";") 
        ContactExternalEmailAddress = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").ExternalEmailAddress 
        ContactHiddenFromAddressListsEnabled = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").HiddenFromAddressListsEnabled

        } 

        $MasterList += $MyObject 
    } 

    $MasterList | Export-Csv $filename -NoTypeInformation -Encoding Unicode 
    Write-Host "Information is saved into the CSV file: $filename" -ForegroundColor White 

    Foreach($i in $data) 
    { 
        $str = $i.displayname 

        ## Removing mail contacts for Source users 
        $c = Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'" 
        Write-Host $c -ForegroundColor Yellow 

        ## Multiple matching, no changes will be done 
        if ($c.count -ge 1) 
        { 
            Write-Host "ERROR: Multiple matching" 
            Write-Host "Matches: $c.count" 
            return 
        } 

        ## Unique contact found, removing it 
        if ($c.count -eq $null) 
        { 
            Write-Host "Unique matching: $c" 
            Write-Host "Removing the mail contact object for: $c" 

            Remove-MailContact -Identity $c -Confirm:$false 

        } 

        ## Starting the configuration for Target Mailboxes 
        $u = Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'" 

        Write-Host $u -ForegroundColor Yellow 

        ## Multiple matching, no changes made 
        if ($u.count -ge 1) 
        { 
            Write-Host "ERROR: Multiple matching" 
            Write-Host "Matches: $u.count" 
            return 
        } 

        ## Setting the Source PrimarySmtpAddress on the Target Mailboxes 
        if ($u.count -eq $null) 
        { 
            Write-Host "Unique matching: $u" 
            Write-Host "Setting Source SMTP as PrimaryAddress for matching using QMM" 
            Write-Host "Configuring the mailbox for showing up in GAL and remove the forwarding configuration"
            Write-Host "Adding the LegacyExchangeDN as X500 for Outlook auto-complete cache"
 

            $email = $i.PrimarySmtpAddress
            $x500 = $i.LegacyExchangeDN

            Set-Mailbox -Identity $u -ForwardingAddress $null -DeliverToMailboxAndForward:$false -HiddenFromAddressListsEnabled:$false -PrimarySmtpAddress $email -EmailAddressPolicyEnabled:$false 

            $ProxyAddresses = (Get-Mailbox -Identity $u).EmailAddresses
            $ProxyAddresses += [Microsoft.Exchange.Data.CustomProxyAddress]("X500:$x500")
            Set-Mailbox -Identity $u -EmailAddresses $ProxyAddresses
        } 

        else 
        { 
            Write-Host "No match" 
            return 
        } 

    } 

    Write-Host "" 
    Write-Host "#################################################################" -ForegroundColor White 
    Write-Host "# First run the Verify-TargetInformation..                        #" -ForegroundColor White 
    Write-Host "# Start the QMM Synchronization for matching Source <-> Target  #" -ForegroundColor White 
    Write-Host "# Finally run the Rollback-TargetInformation when sync is done  #" -ForegroundColor White 
    Write-Host "#################################################################" -ForegroundColor White 
    Write-Host "" 
}

## Rollback of Target PrimarySmtpAddress 
Function Rollback-TargetInformation(){ 

    $data = Import-CSV .\targetinformation.csv 

    $MasterList = @() 
    Foreach($i in $data) 
    { 

        $str = $i.displayname 
        $user = Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'" 

        ## Predicts there is only one @testlabs.se address 
        $pri = Get-Mailbox -Identity $user | Select-Object -ExpandProperty EmailAddresses | Where-Object {$_.SmtpAddress -like '*@testlabs.se'} | Select-Object SmtpAddress 
        $adr = $pri.SmtpAddress 

        Write-Host "Configuring mailbox: $user with adress: $adr" -ForegroundColor White 
        Set-Mailbox -Identity $user -PrimarySmtpAddress $adr -EmailAddressPolicyEnabled:$False 

    } 

}

## Verifying the Target PrimarySmtpAddress 
Function Verify-TargetInformation(){

    $data = Import-CSV .\users.csv 

    $filetime = (get-date -format yyyyMMddhhmm) 
    $filename = "verify-$filetime.csv" 
    $MasterList = @() 

    ## Verifying the PrimarySmtpAddress 
    Foreach($i in $data) 
    { 

        $MyObject = New-Object PSObject -Property @{ 

            Name = (Get-Mailbox -Identity $i.PrimarySmtpAddress).Name 
            PrimarySmtpAddress = (Get-Mailbox -Identity $i.PrimarySmtpAddress).PrimarySmtpAddress 
            Database = (Get-Mailbox -Identity $i.PrimarySmtpAddress).Database
            EmailAddresses = ((Get-Mailbox -Identity $i.PrimarySmtpAddress).EmailAddresses -Join ";") 
        } 

        $MasterList += $MyObject 

    } 

    $MasterList | Export-Csv $filename -NoTypeInformation -Encoding Unicode 
    Import-CSV $filename 

    Write-Host "" 
    Write-Host "SMTP Verification is saved into the CSV file: $filename" -ForegroundColor White 
    Write-Host "" 
}
Exchange 2013 script – automatic installation of prerequisites

Exchange 2013 script – automatic installation of prerequisites

I’ve updated a script that was intended for installing prerequisites for Exchange 2010 that were released by a couple of peoples (Anderson Patricio, Pat Richard and Bhargav Shukla). This script have now been updated and applies to Exchange 2013.

It will help you with installing all prerequisites (features) plus the FilterPack(s) and the Unified Communications Managed API. It also provides the option to disable the UAC (User Access Control) and the Windows Firewall.

You can download the script here
Feel free to use it as much as you want, I just want to mention I do not provide support for it and there are no warranty.

The script/code can be viewed below:

#############################################################################
 # Install-Exchange2013PreReqs.ps1
 # Configures the necessary prerequisites to install Exchange 2013 on a
 # Windows Server 2008 R2 server or Windows Server 2012 server
 #
 # Updated by: Jonas Andersson
 # Original written by: Pat Richard, Anderson Patricio and Bhargav Shukla
 #
 # Some info taken from
 # http://www.ucblogs.net/blogs/exchange/archive/2009/12/12/Automated-prerequisite-installation-via-PowerShell-for-Exchange-Server-2010-on-Windows-Server-2008-R2.aspx">http://www.ucblogs.net/blogs/exchange/archive/2009/12/12/Automated-prerequisite-installation-via-PowerShell-for-Exchange-Server-2010-on-Windows-Server-2008-R2.aspx
 # http://msmvps.com/blogs/andersonpatricio/archive/2009/11/13/installing-exchange-server-2010-pre-requisites-on-windows-server-2008-r2.aspx">http://msmvps.com/blogs/andersonpatricio/archive/2009/11/13/installing-exchange-server-2010-pre-requisites-on-windows-server-2008-r2.aspx
 # http://www.bhargavs.com/index.php/powershell/2009/11/script-to-install-exchange-2010-pre-requisites-for-windows-server-2008-r2/">http://www.bhargavs.com/index.php/powershell/2009/11/script-to-install-exchange-2010-pre-requisites-for-windows-server-2008-r2/
 #############################################################################

# Detect correct OS here and exit if no match
 if (-not((Get-WMIObject win32_OperatingSystem).OSArchitecture -eq '64-bit') -and (((Get-WMIObject win32_OperatingSystem).Version -eq "6.1.7601") -or (Get-WMIObject win32_OperatingSystem).Version -eq "6.2.9200")){
 Write-Host "This script requires a 64bit version of Windows Server 2008 R2 or Windows Server 2012, which this is not." -ForegroundColor Red -BackgroundColor Black
 Exit
 }

Function Disable-UAC(){

$path = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System"
 $a = Get-ItemProperty $path -Name EnableLUA

if ($a | Select-String "0")
 {
 Write-Host "UAC is already disabled" -ForegroundColor Green
 return
 }

if ($a | Select-String "1")
 {
 Write-Host "Enabled" -ForegroundColor Red
 Set-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System" -Name "EnableLUA" -Value 0
 Write-host "Registry key HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA has been changed." -ForegroundColor yellow
 Write-Host "UAC is now disabled" -ForegroundColor Green
 }

}

Function Disable-FW(){

$status = netsh advfirewall show allprofiles state

if ($status | Select-String "ON")
 {
 $enabled = $true
 }
 else
 {
 $enabled = $false
 }

if ($enabled -eq $true) {

netsh advfirewall set allprofiles state off
 Write-Host "Firewall is now disabled" -ForegroundColor yellow
 return
 }

if ($enabled -eq $false) {
 Write-Host "Firewall is already disabled" -ForegroundColor Green
 }

}

Function InstallFilterPack(){

if (Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\{95140000-2000-0409-1000-0000000FF1CE}" -ErrorAction SilentlyContinue) {

Write-host "FilterPack is already installed." -ForegroundColor yellow
 return
 }

else
 {

trap {
 Write-Host "Problem downloading FilterPackx64.exe. Please visit: <a href="http://www.microsoft.com/en-us/download/details.aspx?id=26604">http://www.microsoft.com/en-us/download/details.aspx?id=26604</a> and <a href="http://www.microsoft.com/en-us/download/details.aspx?id=17062&quot;">http://www.microsoft.com/en-us/download/details.aspx?id=17062"</a>

break
 }

#set a var for the folder you are looking for
 $folderPath = 'C:\Temp'

#Check if folder exists, if not, create it
 if (Test-Path $folderpath){
 Write-Host "The folder $folderPath exists."
 } else{
 Write-Host "The folder $folderPath does not exist, creating..." -NoNewline
 New-Item $folderpath -type directory | Out-Null
 Write-Host "done!" -ForegroundColor Green
 }

# Check if file exists, if not, download it
 $file1 = $folderPath+"\FilterPack64bit.exe"
 $file2 = $folderPath+"\filterpack2010sp1-kb2460041-x64-fullfile-en-us.exe"

if (Test-Path $file1){
 write-host "The file $file1 exists."
 } else {
 #Download Microsoft Filter Pack
 Write-Host "Downloading Microsoft Filter Pack..." -nonewline
 $clnt = New-Object System.Net.WebClient
 $url = "<a href="http://download.microsoft.com/download/0/A/2/0A28BBFA-CBFA-4C03-A739-30CCA5E21659/FilterPack64bit.exe&quot;">http://download.microsoft.com/download/0/A/2/0A28BBFA-CBFA-4C03-A739-30CCA5E21659/FilterPack64bit.exe"</a>
 $clnt.DownloadFile($url,$file1)
 Write-Host "done!" -ForegroundColor Green
 }

if (Test-Path $file2){
 write-host "The file $file2 exists."
 } else {
 #Download Microsoft Filter Pack SP1
 Write-Host "Downloading Microsoft Filter Pack SP1..." -nonewline
 $clnt = New-Object System.Net.WebClient
 $url = "<a href="http://download.microsoft.com/download/A/A/3/AA345161-18B8-45AE-8DC8-DA6387264CB9/filterpack2010sp1-kb2460041-x64-fullfile-en-us.exe&quot;">http://download.microsoft.com/download/A/A/3/AA345161-18B8-45AE-8DC8-DA6387264CB9/filterpack2010sp1-kb2460041-x64-fullfile-en-us.exe"</a>
 $clnt.DownloadFile($url,$file2)
 Write-Host "done!" -ForegroundColor Green
 }

#Install Microsoft Filter Packs
 Write-Host "Installing Microsoft Filter Packs..."

$args = "/quiet /norestart"
 $setup1 = (Start-Process $file1 -ArgumentList $args -Wait -PassThru).ExitCode
 if ($setup1 -eq 0) { write-host "Successfully installed $file1" -ForegroundColor Green }
 if ($setup1 -ne 0) { write-host "Failed!" -ForegroundColor Red }

$setup2 = (Start-Process $file2 -ArgumentList $args -Wait -PassThru).ExitCode
 if ($setup2 -eq 0) { write-host "Successfully installed $file2" -ForegroundColor Green }
 if ($setup2 -ne 0) { write-host "Failed!" -ForegroundColor Red }

}
 }

Function InstallUMAPI(){

#Change reg key below!
 if (Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\UCMA4" -ErrorAction SilentlyContinue) {

Write-host "Unified Communications Managed API 4.0 Runtime is already installed." -ForegroundColor yellow
 return
 }

else
 {

trap {
 Write-Host "Problem downloading UM API. Please visit: <a href="http://www.microsoft.com/en-us/download/details.aspx?id=34992&quot;">http://www.microsoft.com/en-us/download/details.aspx?id=34992"</a>

break
 }
 #set a var for the folder you are looking for
 $folderPath = 'C:\Temp'

#Check if folder exists, if not, create it
 if (Test-Path $folderpath){
 Write-Host "The folder $folderPath exists."
 } else{
 Write-Host "The folder $folderPath does not exist, creating..." -NoNewline
 New-Item $folderpath -type directory | Out-Null
 Write-Host "done!" -ForegroundColor Green
 }

# Check if file exists, if not, download it
 $file = $folderPath+"\UcmaRuntimeSetup.exe"
 if (Test-Path $file){
 write-host "The file $file exists."
 } else {

#Download Microsoft UM API
 Write-Host "Downloading Microsoft UM API..." -nonewline
 $clnt = New-Object System.Net.WebClient
 $url = "<a href="http://download.microsoft.com/download/2/C/4/2C47A5C1-A1F3-4843-B9FE-84C0032C61EC/UcmaRuntimeSetup.exe&quot;">http://download.microsoft.com/download/2/C/4/2C47A5C1-A1F3-4843-B9FE-84C0032C61EC/UcmaRuntimeSetup.exe"</a>
 $clnt.DownloadFile($url,$file)
 Write-Host "done!" -ForegroundColor Green
 }

#Check/Install Media Foundation feature
 $mf = Get-WindowsFeature "Server-Media-Foundation" | select *

Start-Sleep 2

if ($mf.Installed -eq $False)
 {
 Write-Host "Installing Media Foundation feature..."    -ForegroundColor Green
 Add-Windowsfeature Server-Media-Foundation

Write-Host ""
 Write-Host "Installing of Media Foundation feature completed." -ForegroundColor Green
 Write-Host ""
 Write-Host "Restart the server and restart the task" -ForegroundColor Red
 Write-Host "or else the UM API won't be installed" -ForegroundColor Red
 Write-Host ""

return

}

if ($mf.Installed -eq $True)
 {
 #Install Microsoft UM API
 Write-Host "Installing Microsoft UM API..." -ForegroundColor Green

$args = "/quiet /norestart"
 $setup = (Start-Process $file -ArgumentList $args -Wait -PassThru).ExitCode
 if ($setup -eq 0) { write-host "Successfully installed $file" -ForegroundColor Green }
 if ($setup -ne 0) { write-host "Failed!" -ForegroundColor Red }

}
 }

}

Import-Module ServerManager
 $opt = "None"
 # Do {
 clear
 if ($opt -ne "None") {write-host "Last command: "$opt -foregroundcolor Yellow}
 write-host
 write-host Exchange Server 2013 - Prerequisites script
 write-host Please, select which role you are going to install..
 write-host
 write-host '1) Client Access Server'
 write-host '2) Mailbox'
 write-host '3) Typical (CAS/Mailbox)'
 write-host
 write-host '10) Install Microsoft Filter Pack 2.0'
 write-host '    Required if installing Mailbox Server roles' -foregroundcolor yellow
 write-host '    Automatically set for options 2 and 3' -foregroundcolor yellow
 write-host '11) Install Microsoft UM API'
 write-host '    Required if installing Mailbox Server roles' -foregroundcolor yellow
 Write-Host '12) Disable UAC'
 Write-Host '13) Disable Firewall'
 write-host
 write-host '15) Restart the Server'
 write-host '16) End'
 write-host
 $opt = Read-Host "Select an option.. [1-14]? "

switch ($opt)    {
 1 {

# Windows Server 2008 R2 SP1
 if ((Get-WMIObject win32_OperatingSystem).Version -eq "6.1.7601") {

Import-Module ServerManager
 Add-WindowsFeature "Desktop-Experience", "NET-Framework", "NET-HTTP-Activation", "RPC-over-HTTP-proxy", "RSAT-Clustering", "RSAT-Web-Server", "WAS-Process-Model", "Web-Asp-Net", "Web-Basic-Auth", "Web-Client-Auth", "Web-Digest-Auth", "Web-Dir-Browsing", "Web-Dyn-Compression", "Web-Http-Errors", "Web-Http-Logging", "Web-Http-Redirect", "Web-Http-Tracing", "Web-ISAPI-Ext", "Web-ISAPI-Filter", "Web-Lgcy-Mgmt-Console", "Web-Metabase", "Web-Mgmt-Console", "Web-Mgmt-Service", "Web-Net-Ext", "Web-Request-Monitor", "Web-Server", "Web-Stat-Compression", "Web-Static-Content", "Web-Windows-Auth", "Web-WMI" -restart

}

# Windows Server 2012
 if ((Get-WMIObject win32_OperatingSystem).Version -eq "6.2.9200") {

Install-WindowsFeature "AS-HTTP-Activation", "Desktop-Experience", "NET-Framework-45-Features", "RPC-over-HTTP-proxy", "RSAT-Clustering", "RSAT-Clustering-CmdInterface", "RSAT-Clustering-Mgmt", "RSAT-Clustering-PowerShell", "Web-Mgmt-Console", "WAS-Process-Model", "Web-Asp-Net45", "Web-Basic-Auth", "Web-Client-Auth", "Web-Digest-Auth", "Web-Dir-Browsing", "Web-Dyn-Compression", "Web-Http-Errors", "Web-Http-Logging", "Web-Http-Redirect", "Web-Http-Tracing", "Web-ISAPI-Ext", "Web-ISAPI-Filter", "Web-Lgcy-Mgmt-Console", "Web-Metabase", "Web-Mgmt-Console", "Web-Mgmt-Service", "Web-Net-Ext45", "Web-Request-Monitor", "Web-Server", "Web-Stat-Compression", "Web-Static-Content", "Web-Windows-Auth", "Web-WMI", "Windows-Identity-Foundation" -restart

}

}

2 {

# Windows Server 2008 R2 SP1
 if ((Get-WMIObject win32_OperatingSystem).Version -eq "6.1.7601") {

Import-Module ServerManager
 InstallFilterPack
 Add-WindowsFeature "Desktop-Experience", "NET-Framework", "NET-HTTP-Activation", "RPC-over-HTTP-proxy", "RSAT-Clustering", "RSAT-Web-Server", "WAS-Process-Model", "Web-Asp-Net", "Web-Basic-Auth", "Web-Client-Auth", "Web-Digest-Auth", "Web-Dir-Browsing", "Web-Dyn-Compression", "Web-Http-Errors", "Web-Http-Logging", "Web-Http-Redirect", "Web-Http-Tracing", "Web-ISAPI-Ext", "Web-ISAPI-Filter", "Web-Lgcy-Mgmt-Console", "Web-Metabase", "Web-Mgmt-Console", "Web-Mgmt-Service", "Web-Net-Ext", "Web-Request-Monitor", "Web-Server", "Web-Stat-Compression", "Web-Static-Content", "Web-Windows-Auth", "Web-WMI" -restart

}

# Windows Server 2012
 if ((Get-WMIObject win32_OperatingSystem).Version -eq "6.2.9200") {

InstallFilterPack
 Install-WindowsFeature "AS-HTTP-Activation", "Desktop-Experience", "NET-Framework-45-Features", "RPC-over-HTTP-proxy", "RSAT-Clustering", "RSAT-Clustering-CmdInterface", "RSAT-Clustering-Mgmt", "RSAT-Clustering-PowerShell", "Web-Mgmt-Console", "WAS-Process-Model", "Web-Asp-Net45", "Web-Basic-Auth", "Web-Client-Auth", "Web-Digest-Auth", "Web-Dir-Browsing", "Web-Dyn-Compression", "Web-Http-Errors", "Web-Http-Logging", "Web-Http-Redirect", "Web-Http-Tracing", "Web-ISAPI-Ext", "Web-ISAPI-Filter", "Web-Lgcy-Mgmt-Console", "Web-Metabase", "Web-Mgmt-Console", "Web-Mgmt-Service", "Web-Net-Ext45", "Web-Request-Monitor", "Web-Server", "Web-Stat-Compression", "Web-Static-Content", "Web-Windows-Auth", "Web-WMI", "Windows-Identity-Foundation" -restart

}

}

3 {

if ((Get-WMIObject win32_OperatingSystem).Version -eq "6.1.7601") {

Import-Module ServerManager
 InstallFilterPack
 Add-WindowsFeature "Desktop-Experience", "NET-Framework", "NET-HTTP-Activation", "RPC-over-HTTP-proxy", "RSAT-Clustering", "RSAT-Web-Server", "WAS-Process-Model", "Web-Asp-Net", "Web-Basic-Auth", "Web-Client-Auth", "Web-Digest-Auth", "Web-Dir-Browsing", "Web-Dyn-Compression", "Web-Http-Errors", "Web-Http-Logging", "Web-Http-Redirect", "Web-Http-Tracing", "Web-ISAPI-Ext", "Web-ISAPI-Filter", "Web-Lgcy-Mgmt-Console", "Web-Metabase", "Web-Mgmt-Console", "Web-Mgmt-Service", "Web-Net-Ext", "Web-Request-Monitor", "Web-Server", "Web-Stat-Compression", "Web-Static-Content", "Web-Windows-Auth", "Web-WMI" -restart

}

# Windows Server 2012
 if ((Get-WMIObject win32_OperatingSystem).Version -eq "6.2.9200") {

InstallFilterPack
 Install-WindowsFeature "AS-HTTP-Activation", "Desktop-Experience", "NET-Framework-45-Features", "RPC-over-HTTP-proxy", "RSAT-Clustering", "RSAT-Clustering-CmdInterface", "RSAT-Clustering-Mgmt", "RSAT-Clustering-PowerShell", "Web-Mgmt-Console", "WAS-Process-Model", "Web-Asp-Net45", "Web-Basic-Auth", "Web-Client-Auth", "Web-Digest-Auth", "Web-Dir-Browsing", "Web-Dyn-Compression", "Web-Http-Errors", "Web-Http-Logging", "Web-Http-Redirect", "Web-Http-Tracing", "Web-ISAPI-Ext", "Web-ISAPI-Filter", "Web-Lgcy-Mgmt-Console", "Web-Metabase", "Web-Mgmt-Console", "Web-Mgmt-Service", "Web-Net-Ext45", "Web-Request-Monitor", "Web-Server", "Web-Stat-Compression", "Web-Static-Content", "Web-Windows-Auth", "Web-WMI", "Windows-Identity-Foundation" -restart

}

}
 10 {
 # future - auto detect Internet access
 write-host 'Can this server access the Internet?'
 $filtpack = read-host 'Please type (Y)es or (N)o...'
 switch ($filtpack)                {
 Y { InstallFilterPack }
 N {Write-warning 'Please download and install Microsoft Filter Pack from here: <a href="http://www.microsoft.com/en-us/download/details.aspx?id=26604">http://www.microsoft.com/en-us/download/details.aspx?id=26604</a> and <a href="http://www.microsoft.com/en-us/download/details.aspx?id=17062'}">http://www.microsoft.com/en-us/download/details.aspx?id=17062'}</a>
 }
 }
 11 {
 # future - auto detect Internet access
 write-host 'Can this server access the Internet?'
 $umapi = read-host 'Please type (Y)es or (N)o...'
 switch ($umapi)                {
 Y { InstallUMAPI }
 N {Write-warning 'Please download and install Microsoft UM API from here: <a href="http://www.microsoft.com/en-us/download/details.aspx?id=34992'}">http://www.microsoft.com/en-us/download/details.aspx?id=34992'}</a>
 }
 }
 12 { Disable-UAC }
 13 { Disable-FW }
 15 { Restart-Computer }
 16 {
 Write-Host "Exiting..."
 Exit
 }
 default {write-host "You haven't selected any of the available options. "}
 }
Author of a book – PowerShell cookbook

Author of a book – PowerShell cookbook

If you have missed the news on my twitter, I can tell you that the last 6 months I’ve been busy with writing a book called “Microsoft Exchange 2013 PowerShell Cookbook: second edition” for Packt Publishing.

That’s also why the blog not have been updated that much lately, now it’s time to startup with the activities for the online community work again since the book more or less is completed. Just doing the final updates of the chapters. I want to thank both Anderson Patricio [MVP] and Marcelo Vighi [MVP] for doing a great job with the review.
I also want to send a special thank you to Magnus Björk [MVP] for helping me out when bugs were found.

It have been a great experience doing this project, both exciting and exhausting in the same time because of high tempo and tight time schedules. But I can recommend everyone that thinking of doing this kind of job, DO IT!

You might wonder when it will be released? mid June..

9427EN_MockupCover_Cookbook

More info about the book can be found here:
http://www.packtpub.com/microsoft-exchange-server-2013-powershell-2e-cookbook/book
http://www.amazon.com/Microsoft-Exchange-PowerShell-Cookbook-ebook/dp/B00BP47WHE/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1364252267&sr=1-1

And some information about me:
http://www.packtpub.com/authors/profiles/jonas-andersson

Search for PST files on clients

Search for PST files on clients

Wrote a basic PowerShell script that searches all computers listed in the clients.txt file.

Saving the pst files into the destination path.

For each computer, a folder is created with the corresponding computer name so that the PST files is collected per client.

Before the PST Capture Tool was released I wrote a post about “How to consolidate PST” files.
This script is just a little adjustment of that one.

Also have a look at the PST Capture Tool, it can be found here.

Anyway, feel free to use the script below and comment on it

#############################################################################
# Search.ps1
# Description:
# This PowerShell script searches for *.pst files on the clients listed in
# the clients.txt file (one hostname per row). Then saves them on the path specified
# in $SavePath, one folder per computer is created in the destionationpath.
#
# Jonas Andersson, MCC 2011
# http://www.testlabs.se/blog
# Twitter @jonand82
#############################################################################

$data = Get-Content .\clients.txt
$Date = Get-Date -Format yyyyMMddHHmm
$Log = "log_{0:yyyyMMdd-HHmm}.txt" -f (Get-Date)

#Writes to log file
Function WriteLog ([string] $sLogMsg) {
$sLogLine=(get-date).Tostring("yyyy-MM-dd-HHmm")+","+$sLogMsg
$sLogLine| out-file $log -noclobber -append
}

foreach ($row in $data)
{
WriteLog "Starting the search for PST files on $row."
$FindPath = "\\$row\c$"
$SavePath = "\\destionaionpath\pstshare"

$PSTFiles = Get-ChildItem -Path $FindPath -Recurse -Filter "*.pst"

if ($PSTFiles.count -eq $null) {
WriteLog "No PST files were found on computer $row."
}
else {
$PSTFiles | New-Item -path $SavePath -name $row -itemtype directory -force
$PSTFiles | Copy-Item -Destination "$SavePath\$row"
WriteLog "PST files was found and copied successfully on computer $row."
}
}

WriteLog "Script completed!"

Download link

Consolidate PST files

Consolidate PST files

Published: 2012-01-25
Updated: –
Version: 1.0

A time ago I was developing a PowerShell script for finding all PST files on a drive and copying them to a folder.
Type in a drive that should be searched and the UNC path to save them on
The script have been tested and verified on Exchange 2010 SP2

They are divided into two separate scripts.

Feel free to give feedback on it.

It can be downloaded here.


#############################################################################
# Search&Copy-PSTFiles.ps1
# Description
# This PowerShell script searches for *.pst files and copies them into the
# specified UNC location for the final step, the import of the pst contents
# into the associated mailboxes.
#
#
# Jonas Andersson, MCC 2011
# http://www.testlabs.se/blog
# Twitter @jonand82
#############################################################################

# Find PST Files

#Date
$date = Get-Date
$filename = "PST_Files_{0:yyyyMMdd-HHmm}.csv" -f (Get-Date)
$log = "log_{0:yyyyMMdd-HHmm}.txt" -f (Get-Date)
# End of variables

#Functions
#Searching for PST files

Function Search ($PST) {

[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$drive = [Microsoft.VisualBasic.Interaction]::InputBox("Which drive do you want to search? (C:\)", "Drive (C:\)", "C:\")

[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$unc = [Microsoft.VisualBasic.Interaction]::InputBox("Where do you want to save the PST files? UNC path for the Fileshare (\\server\share)", "UNC path", "Example: \\server\share")

WriteLog "Starting the search for PST files.."

$PSTFiles = Get-ChildItem -Path $drive -Recurse -Filter "*.pst"

if ($PSTFiles.count -eq $null){
WriteLog "No PST files were found.."
}
else{
$PSTFiles | Select-Object Name,Length,Directory | Out-File $log -append
$PSTFiles | Copy-Item -Destination $unc | Out-File $log -append
$PSTFiles | Select-Object Name,Length,Directory | Export-CSV -path $filename -Encoding Unicode -NoTypeInformation
WriteLog "PST files was found and copied successfully."
}
}

#Writes to log file
Function WriteLog ([string] $sLogMsg) {
$sLogLine=(get-date).Tostring("yyyy-MM-dd-HHmm")+","+$sLogMsg
$sLogLine| out-file $log -noclobber -append
}

#Script starts here
Search
WriteLog "Script completed!"

[System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)
[Windows.Forms.MessageBox]::Show("Script completed!", "Information", [Windows.Forms.MessageBoxButtons]::OK, [Windows.Forms.MessageBoxIcon]::Information)

End of script

The import script starts below


#############################################################################
# Import-PSTFiles.ps1
# Description
# This is the second part of the script that does the actual import of the
# pst contents into the associated mailboxes.
# Filenames is matched with the Alias value on the mailboxes.
#
#
# Jonas Andersson, MCC 2011
# http://www.testlabs.se/blog
# Twitter @jonand82
#############################################################################

# Find PST Files

# Load Exchange snapin
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction SilentlyContinue

#Date
$date = Get-Date
$filename = "PST_Files_{0:yyyyMMdd-HHmm}.csv" -f (Get-Date)
$log = "log_import_{0:yyyyMMdd-HHmm}.txt" -f (Get-Date)

# End of variables

#Functions
#Searching for PST files

Function Import ($PST) {

[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$path = [Microsoft.VisualBasic.Interaction]::InputBox("Where are the PST files stored? UNC path for the Fileshare (\\server\share)", "UNC path", "Example: \\server\share")

[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
$archive = [Microsoft.VisualBasic.Interaction]::MsgBox("Should they be imported to the archive mailbox?",'YesNo,Question', "Import to archive?")

WriteLog "Starting the import of PST files.."

$PSTFiles = Get-ChildItem -Path $path -Filter "*.pst"
$PSTFiles | Select-Object Name,Length,Directory | Export-CSV -path $filename -Encoding Unicode -NoTypeInformation

if ($archive -eq "Yes"){
WriteLog "Starting the import to mailbox archive.."
Dir $path\*.pst | Out-File $log -append

$PSTFiles | %{ New-MailboxImportRequest -Name ImportToArchive -BatchName ImportToArchive -Mailbox $_.BaseName -FilePath $_.FullName -IsArchive } | Out-File $log -append

}
Else{
WriteLog "Starting the import to normal mailbox.."
Dir $path\*.pst | Out-File $log -append

$PSTFiles | %{ New-MailboxImportRequest -Name ImportToMailbox -BatchName ImportToMailbox -Mailbox $_.BaseName -FilePath $_.FullName } | Out-File $log -append
}
WriteLog "PST files was imported successfully."

}

#Writes to log file
Function WriteLog ([string] $sLogMsg) {
$sLogLine=(get-date).Tostring("yyyy-MM-dd-HHmm")+","+$sLogMsg
$sLogLine| out-file $log -noclobber -append
}

#Script starts here
Import
WriteLog "Script completed!"

[System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)
[Windows.Forms.MessageBox]::Show("Script completed!", "Information", [Windows.Forms.MessageBoxButtons]::OK, [Windows.Forms.MessageBoxIcon]::Information)

Feel free spread them just make sure to include a link to the blog as the source, use them at your own risk.

Download link