/ Powershell

Some neat Powershell-snippets for connecting to Office 365 and Exchange Online (and managing credentials)

Every now and then (or every day) you need to run the Connect-MsolService cmdlet and open a new session to Exchange Online. The cmdlets themselves are pretty straight forward, if you run them from a normal up-to-date Powershell. But - of course - we want to make a function out of it that requires as little effort as possible to run.

Prerequisites

Note: if the above links doesn't work, check this Microsoft page out for a more up-to-date version: Technet: Connect to Office 365 PowerShell

Exporting (saving) and Importing credentials

First of all we want to store our credentials (safely) to be used later for the Connect-MsolService cmdlet. For that we will use a little function:

function Export-PSCredential {
    param (  
        [Parameter(Position=0)]
        [PSCredential]
        #Pass Credential or UserName to the Cmdlet or get prompted for credentials
        $Credential = (Get-Credential), 

        [Parameter(Position=1)]
        [string]
        #The Path where to store the XML-file with the encrypted credentials.     
        $Path = "$env:APPDATA\PSCredentials.xml"
    )

    if (Test-Path ($Path))
    {
        $Yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes",""
        $No = New-Object System.Management.Automation.Host.ChoiceDescription "&No",""
        $choices = [System.Management.Automation.Host.ChoiceDescription[]]($Yes,$No)
        $caption = "The file `'$Path`' already exists!"
        $message = "Do you want to replace it?"
        $result = $Host.UI.PromptForChoice($caption,$message,$choices,1)

        if ($result -eq 1)
        {
            break
        }
    } 
    $export = "" | Select-Object Username, EncryptedPassword

    $export.PSObject.TypeNames.Insert(0,’ExportedPSCredential’)
    $export.Username = $Credential.Username

    # Encrypt SecureString password using Data Protection API
    # Only the current user account can decrypt this cipher
    $export.EncryptedPassword = $Credential.Password | ConvertFrom-SecureString

    $export | Export-Clixml $Path

    return $Credential
}

An example of how to use the function is: Export-PSCredential -Path C:\Secrets\Cred.cred or if you are lazy just: Export-PSCredential (and have your credentials saved to C:\Users\UserName\AppData\Roaming\PSCredentials.xml). The credentials will be encrypted with your User-Key and only you can decrypt it again.

While we're at it, lets take a look at the decrypt function:

function Import-PSCredential {

param (  
    [Parameter(Position=0)]
    [string]
    #The Path where to read the XML-file with the encrypted credentials    
    $Path = "$env:APPDATA\PSCredentials.xml"
)
 
    if (!(Test-Path ($Path)))
    {
        throw "File not found exception, exiting."
    }
 
    # Import credential file
    $import = Import-Clixml $Path

    if (!$import.UserName -or !$import.EncryptedPassword ) 
    {
        Throw "Input is not a valid ExportedPSCredential object, exiting."
    }

    try
    {
        $SecurePass = $import.EncryptedPassword | ConvertTo-SecureString -ErrorAction Stop
    }
    catch
    {
        Throw "Could not decrypt password!"
    }

    New-Object System.Management.Automation.PSCredential $import.Username, $SecurePass
}

This function is even more simplified. To import a saved credentials file all you have to do is: $Cred = Import-PSCredential -Path C:\Secrets\Cred.cred. Whenever you want to use the imported credentials all you have to do is to pass along the [PSCredential] object $Cred. Go ahead and save this function (I'll use C:\Functions\Import-PSCredential.ps1 for the next part).

Connecting to Online

Now that we have nice proper credentials (with full UPN, such as userName@domain.com or userName@tenant.onmicrosoft.com) safely stored the next step is to use the credentials in a "Connect-To-O365" function. An important thing to know is that each user can only have 3 concurrent sessions active against O365-Powershell. This means we need some logic to check whether or not we already have an open session because this function will be used every time we run scripts against O365 and you do not want to go above the connection limit - trust me ;).

function Connect-Online
{
    param (
        $PathtoCred = "C:\Secrets\Cred.cred"
    )

    if (!(Get-PSSession | ? {$_.ComputerName -eq "outlook.office365.com" -and $_.State -eq "Opened"}))
    {
        #Import the function for importing credentials if it's not present
        if (!(Test-Path function:Import-PSCredential)) {. 'C:\Functions\Import-PSCredential.ps1' } 
        try
        {
	        if (Test-Path ($PathtoCred))
	        {
		        $Cred = Import-PSCredential -Path $PathtoCred
	            $Session = New-PsSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/?proxymethod=rps -Credential $Cred -Authentication Basic -AllowRedirection 
	            Import-PsSession $Session -AllowClobber 
	            Connect-MsolService -Credential $Cred 
	        }
        }
        catch
        {
            throw "Error in Credentials section for function 'Connect-Online' $_"  
        }
    }   
}

By running: Connect-Online or: Connect-Online -PathtoCred C:\Secrets\Cred.cred you now get access to all the O365 and Exchange Online cdmlets and you don't have to worry about typing in your credentials, or concurrent sessions, ever again. Except when you run scripts from different machines... or different Powershell-windows simultaneously...

To remove the session just do a: Get-PSSession | ? ComputerName -eq outlook.office365.com | Remove-PSSession or if you are lazy (who isn't?): Get-PSSession | Remove-PSSession.

Enjoy!

Andreas Selevik

Andreas Selevik

Solution Architect specialized in Windows & Azure Architecture, Office 365, PowerShell, Identity management and automation. Manchester United fanatic, father, husband and a very good winner...

Read More