Wednesday, June 25, 2014

Scripting Office 365 and DirSync Replication

If you are running the new version of DirSync, you probably noticed that the "DirSyncConfigShell.psc1" file is missing. They have also changed the way your start a sync. The new way (documented here: Click Me) you have to import the module, then run the command. Well, I attempted to run this remotely on my desktop and it just hung every time. Here is what I was running:
Invoke-Command -ComputerName SERVER -ScriptBlock { import-module dirsync; Start-OnlineCoexistenceSync }
Then, with the help of a friend at http://powershell.org he reminded me to turn on -verbose so that I could see exactly what the PowerShell was doing. I found that when importing the module, it was attempting to dot-source a file named .\importmodules.ps1 put there by DirSync. Ok, now what is wrong with that file? So I cracked it open and ran each command, one at a time, in a ISE environment and found that it was attempting to run with .net 4.0 and since I had .net 2.0 on my PowerShell window (by default), it was hanging.
Whew… ok now let's find a way to change the PowerShell window to get it to run .net 4.0 for this command. Here is what I came up with:

reg add hklm\software\microsoft\.netframework /v OnlyUseLatestCLR /t REG_DWORD /d 1
reg add hklm\software\wow6432node\microsoft\.netframework /v OnlyUseLatestCLR /t REG_DWORD /d 1
Invoke-Command -ComputerName SERVER -ScriptBlock { import-module dirsync -verbose; Start-OnlineCoexistenceSync }
reg delete hklm\software\microsoft\.netframework /v OnlyUseLatestCLR /f
reg delete hklm\software\wow6432node\microsoft\.netframework /v OnlyUseLatestCLR /f

So I through that into my script and BAM it started working again. Thanks to all the people online (twitter, reddit, etc…) for your help.

References:

Friday, October 18, 2013

Migrate users from on-prem Exchange server to Office 365

Moving users one at a time through the EMC was getting super old so I decided to write a script for it to speed it up. Below is the script that I use to migrate a user from the on-prem Exchange 2010 server to Office 365:

A couple of notes on what the script is doing:

 - You will need to edit the lines in the "Declaring the variables" section to fit your environment
 - Pay attention to the help file at the beginning of the script on how to run the script
 - The first thing the script will do is prompt you TWICE for credentials.
       - Once for Exchange on-prem server (LDAP)
       - Second for Microsoft Online (Office 365)
 - Next it will load all the modules/snapins that you will need during this script
 - Starting the script:

1. First thing that we are going to do is disable Unified Messaging (UM) on the on-prem Exchange server. You can't migrate a user while UM is enabled.
2. License the user in Office 365
3. Set the location for the user to US in Office 365
4. Connect to Microsoft Exchange Online with a new session
5. Create the move request for the user from on-prem to Office 365
6. Sends a conformation email to you once the move has been scheduled.

Here is the script:
(quick note: to run this in bulk, just throw in a FOREACH loop in there before the license part)

# **************************************
# ******** NOTES / Help File ***********
# **************************************

<#
.SYNOPSIS
To migrate users one at a time from on-prem Exchange to Office 365

.DESCRIPTION
This script will migrate one user at a time to Office 365. 
It will disable Unified messaging on the local Exchange server, 
then migrate the user to Office 365.  

.EXAMPLE
SingleUserO365migrate.ps1 -UPN username@domain.com -ext 1234

.NOTES
Assumptions - This script is being ran from a server that has 
the following PowerShell modules installed: 

  Exchange 2010 / AD / Microsoft Online / Quest AD
  
The parameters that you will need to include in the script are:
  - UPN = The Users EMAIL address
  - ext = The phone ext of the user that you are migrating

.LINK
Script developed by Bob Ausmus (http://bobausmus.blogspot.com)
#>

#**************************************
#************* Parameters *************
#**************************************

Param(
[parameter(Mandatory=$true)][String]$UPN,
    [parameter(Mandatory=$false)][String]$ext,
[parameter(Mandatory=$false)][String]$officelocation
)

#**************************************
#*******Declaring the variables********
#**************************************


#License to be used is $License
$license = "<License pack of your Office 365 License>"

#On Premises CAS Server is: $OnPremCas
$OnPremCas = "<URL of your OWA from On-Prem Exchange Server>"

#Target Delivery Domain is: $TargetDeliveryDom
$TargetDeliverydom = "<URL of your Office 365 domain>"

#Getting the username of the user that is running the script
$curuser = $env:username

#Creditials for on-prem Exchange Server
$onpremcred = $host.ui.PromptForCredential("Domain Login", "Please enter your LDAP username and password", "DOMAIN\$curuser", "")

# Get Local Users Creditials for MS Online
$cred = $host.ui.PromptForCredential("Microsoft Online Login", "Please enter your email address and password", "$curuser@domain.com", "")

# Setting the name of your Exchange Server
$exchangeserver = <insert name of your Exchange server here>

# Setting for email report
$ToEmail = "to@domain.com"
$FromEmail = "from@domain.com"
$Subject = "Subject for email"
$smtpserver = "mail.domain.com"

#**************************************
#***********Helper Functions***********
#**************************************


# Countdown Function
function CountDown($waitMinutes) {
    $startTime = get-date
    $endTime   = $startTime.addMinutes($waitMinutes)
    $timeSpan = new-timespan $startTime $endTime
    write-host "`nSleeping for $waitMinutes minutes..." -backgroundcolor black -foregroundcolor green
    while ($timeSpan -gt 0) {
        $timeSpan = new-timespan $(get-date) $endTime
        write-host "`r".padright(40," ") -nonewline
        write-host $([string]::Format("`rTime Remaining: {0:d2}:{1:d2}:{2:d2}", `
            $timeSpan.hours, `
            $timeSpan.minutes, `
            $timeSpan.seconds)) `
            -nonewline -backgroundcolor black -foregroundcolor green
        sleep 1
        }
    write-host ""

    }
cls

#*************************************
#*****Checking PowerShell Modules******
#**************************************

# Inserting some blank lines to make the script prettier
write-host 
write-host

# Exchange Module Check

write-host "Checking to see if the Exchange Management PowerShell is installed"
if ((get-pssnapin -name Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction SilentlyContinue | foreach { $_.Name }) -ne "Microsoft.Exchange.Management.PowerShell.E2010") 
{
write-host Exchange Management PowerShell is not added to this session, adding it now...
    Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction SilentlyContinue
. $env:ExchangeInstallPath\bin\RemoteExchange.ps1 
Connect-ExchangeServer $exchangeserver -AllowClobber
}
else
{
write-host Exchange Management PowerShell is good to go. -backgroundcolor black -foregroundcolor green
start-sleep -s 1
}

write-host 
write-host

# AD Module Check

write-host "Checking to see if the Active Directory PowerShell module is installed"
if ((get-module -name ActiveDirectory -ErrorAction SilentlyContinue | foreach { $_.Name }) -ne "ActiveDirectory")
{
write-host ActiveDirectory Management PowerShell is not added to this session, adding it now...
import-module activedirectory
}
else
{
write-host Active Directory PowerShell module is good to go. -backgroundcolor black -foregroundcolor green
start-sleep -s 1
}

write-host 
write-host

# Microsoft Online Module Check

write-host "Checking to see if the Microsoft Online PowerShell module is installed"
if ((get-module -name MSOnline -ErrorAction SilentlyContinue | foreach { $_.Name }) -ne "MSOnline")
{
write-host Microsoft Online Management PowerShell is not added to this session, adding it now...
import-module MSOnline
connect-msolservice -credential $cred
}
else
{
write-host Microsoft Online PowerShell module is good to go. -backgroundcolor black -foregroundcolor green
start-sleep -s 1
}

write-host 
write-host

# Quest AD Module Check

write-host "Checking to see if the Quest AD PowerShell module is installed"
# <old> if (Get-PSSnapin | where {$_.Name -eq "Quest.ActiveRoles.ADManagement"})
if ((get-pssnapin -name Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue | foreach { $_.Name }) -ne "Quest.ActiveRoles.ADManagement")
{
write-host Quest AD Management PowerShell is not added to this session, adding it now...
    Add-PSSnapin Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue
}
else
{
write-host Quest AD PowerShell module is good to go. -backgroundcolor black -foregroundcolor green
start-sleep -s 1
}

write-host 
write-host

#**************************************
#*********Starting the script**********
#**************************************

write-host "Disabling UM for $UPN" -backgroundcolor cyan -foregroundcolor black
$User = $UPN -replace "@domain.com", ""
Disable-UMMailbox -Identity $User -Confirm:$false

# Enable License and Location in MS Online Office 365

# Setting the location for the user in Office 365 to be "United States"
write-host "Setting Usage Location for $UPN to United States" -backgroundcolor cyan -foregroundcolor black
if (get-msoluser -UserPrincipalName $UPN | where {$_.UsageLocation -ne "US"})
{
write-host Setting the location for $UPN to US
set-msoluser -userprincipalname $UPN -usagelocation US
}
else
{
write-host "The location is already set to US, skipping this step"
start-sleep -s 2
}

write-host

# Setting the License for the user to be the proper license in Office 365 
    write-host "Setting License for $UPN to $license" -backgroundcolor cyan -foregroundcolor black
    if (get-msoluser -UserPrincipalName $UPN | where {$_.isLicensed -ne "True"})
    {
        write-host Setting the License in Office 365 for $UPN
        set-msoluserlicense -UserPrincipalName $UPN -Addlicenses $license 
    }
    else
    {
        write-host $UPN already has the $license set, skipping this step
        start-sleep -s 2
    }
write-host

write-host
write-host "Connecting to the Microsoft Online Exchange Server(s)"
# Enabling UM on the mailbox in Office 365 Exchange Environment
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $cred -Authentication Basic -AllowRedirection
import-pssession $session -prefix o365

write-host
write-host "Creating Mailbox Move Request for $UPN" -backgroundcolor cyan -foregroundcolor black
new-o365moverequest -Identity $UPN -Remote -RemoteHostName $OnPremCas -RemoteCredential $onpremcred -TargetDeliveryDomain $TargetDeliveryDom -BadItemLimit 100 -LargeItemLimit 49
Send-MailMessage -To $ToEmail -From $FromEmail -Subject $Subject -SmtpServer $smtpserver -body "$UPN is being moved to Office 365. They are in $officelocation."
write-host
write-host
exit-pssession
write-host "**** The script is complete ****"  -backgroundcolor green -foregroundcolor black


# *****************************************************************
# ****************THIS IS THE BOTTOM OF THE SCRIPT*****************
# *****************************************************************

PowerShell Module and SnapIn Checks

One of the companies that I do a lot of work for uses Office 365 and everything they do is in bulk. Going through the portal to do anything is time consuming for everyone so I have been writing PowerShell scripts to automate as much as possible. The most common thing that I found is that I have to load the following modules and snapin's almost every time I run a script or a command. So rather than opening up several PowerShell windows to accomplish this task, I just load all the modules in the one window and proceed from there.

Here is the script that I put in place for loading all the modules for the following products:

- Exchange 2010
- Active Directory
- MS Online (Office 365)
- Quest AD Tools

The script does a check first to see if you have the module/snapin already loaded. If so, then it will skip to the next one. If not, then it will load the module/snapin. 

# Exchange Module Check
write-host "Checking to see if the Exchange Management PowerShell is installed"
if ((get-pssnapin -name Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction SilentlyContinue | foreach { $_.Name }) -ne "Microsoft.Exchange.Management.PowerShell.E2010")
{
write-host Exchange Management PowerShell is not added to this session, adding it now...
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction SilentlyContinue
}
else
{
write-host Exchange Management PowerShell is good to go. -backgroundcolor black -foregroundcolor green
start-sleep -s 1
}
write-host
write-host


# AD Module Check
write-host "Checking to see if the Active Directory PowerShell module is installed"
if ((get-module -name ActiveDirectory -ErrorAction SilentlyContinue | foreach { $_.Name }) -ne "ActiveDirectory")
{
write-host ActiveDirectory Management PowerShell is not added to this session, adding it now...
import-module activedirectory
}
else
{
write-host Active Directory PowerShell module is good to go. -backgroundcolor black -foregroundcolor green
start-sleep -s 1
}
write-host
write-host



# Microsoft Online Module Check
write-host "Checking to see if the Microsoft Online PowerShell module is installed"
if ((get-module -name MSOnline -ErrorAction SilentlyContinue | foreach { $_.Name }) -ne "MSOnline")
{
write-host Microsoft Online Management PowerShell is not added to this session, adding it now...
import-module MSOnline
connect-msolservice -credential
}
else
{
write-host Microsoft Online PowerShell module is good to go. -backgroundcolor black -foregroundcolor green
start-sleep -s 1
}
write-host
write-host



# Quest AD Module Check
write-host "Checking to see if the Quest AD PowerShell module is installed"
if ((get-pssnapin -name Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue | foreach { $_.Name }) -ne "Quest.ActiveRoles.ADManagement")
{
write-host Quest AD Management PowerShell is not added to this session, adding it now...
Add-PSSnapin Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue
}
else
{
write-host Quest AD PowerShell module is good to go. -backgroundcolor black -foregroundcolor green
start-sleep -s 1
}


Monday, April 1, 2013

Script: Query AD for when users last changed their passwords

I ran into a challenging question today... My manager asked if I could get a report of all the users and when they changed their password. I knew I could get this via "DSGET and DSQUERY" but I wanted to force myself to use PowerShell. So here is the quick little script that I wrote that will do just that...

Assumptions: 
- You already have a TXT file on your computer that has a list of usernames for all the accounts
- You run these commands on a domain controller or a computer with the remote administration tools installed (to get the AD Module for PowerShell)


The Script:


Import-module activedirectory

$ErrorActionPreference="SilentlyContinue"

Stop-Transcript | out-null

$ErrorActionPreference = "Continue"

Start-Transcript -path C:\output.txt -append

$list = get-content c:\<path to the TXT file with your users in it>\users.txt

Foreach ($username in $list) {get-aduser -id $username -Properties passwordlastset |select-object -property name,enabled,passwordlastset}

Stop-Transcript


Notes:
The "Start-Transcript" and "Stop-Transcript"enable you to get the output in a TXT file so you can import it in excel for later use and manipulation.

Good luck!!!

My road to Hyper-V

Here I wanted to track my road to learning Microsoft Hyper-V.

Background:
I have worked with HyperVisors a lot in the past.

- Big fan of VMware ESX
- XenServer is ok (but only have ran Windows on it)
- Hyper-V is a new player to the market.

Microsoft Virtual Server 2005 was.... horrible. Just horrible. I really gave it it's fair shake but... no. Hyper-V 1 was, eh, ok. Worlds better than before but "Quick Migration" was the killer that kept it out of the enterprise. Hyper-V 2 was much better than 1. "Live Migration" means that it is now a contender for the enterprise market, however it still wasn't 100% there for management.

That brings us to Hyper-V 3. From what  have read and seen.... this version hit it out of the park. I love the management aspect of it now that it is MUCH cheaper (and from what I hear will manage vCenter as well).

I am going to concentrate a series of blog post related to what I learn in relation to Hyper-V 3. If you have any suggestions of where to look, gotcha's, examples, etc... please let me know.

Monday, March 11, 2013

Making "Lync Call" default

I just finished installing Lync server 2010 at work and noticed that the "click to call" feature on the client was not making a "lync call" the default for everyone. This is controlled in the CsClientPolicy for users. Here is the Powershell command to change it:

    Set-CsClientPolicy -EnableVOIPCallDefault $True

More information on the full set of options and parameters can be found here: http://technet.microsoft.com/en-us/library/gg398300.aspx

Monday, March 4, 2013

Favorite Tools to stress-test a connection

Recently at work I turned up a new Metro connection between two locations. Once it was up, I was asked how I verified that indeed I was getting the full 100mb/s that we were paying for. I had to find a tool that would "stress-test" the connection to it's max to prove that it was working.

Here are two of the tools that I used and how I used them:

First tool is: "iperf"  (http://en.wikipedia.org/wiki/Iperf)

Great little tool that just works. Tons of options but basically you put it on a laptop at both ends of the connection. One is the client and one is the server. You turn on the server with this command from the command prompt:

    iperf -s

Yup, it's that simple. Then take the other laptop to the other end of the connection and type this command from the command prompt:

    iperf -c <ip address of the server>

Again, it's that simple. The client will contact the server and will run as fast as it can flooding the connection. Once it's done, you will get a report that shows how long it took to send the packets and the max throughput. Great tool, especially for contractors to prove that everything is working.


Second tool is "Pathtest" (http://www.testmypath.com)

This is very similar in the way it works to iperf. Same setup as before, just replace the "iperf" with "pathtest" in the commands. The reason I like this one is the report/output is a little neater and easier for none-techie people (like the CFO) to read and understand. They like seeing reports with neat graphs and Pathtest gives them that.

Both tools are ran from the command prompt. The easiest way to open the command prompt is to following these steps:

1. Press and hold the "Windows key" (usually located just left of the space bar) and then press "r"
2. Type in the RUN box the following:  cmd
3. Press enter (or click OK)
4. This will bring up a black box. That is the command prompt.


Good luck and I hope this helps next time you need to prove to the bean counters that you are getting what they are paying for.