Search code examples
powershellexchangewebservicescontacts

Set a variable equal to the output of a powershell script


This is a little difficult to explain, but I will do my best. I am writing some code to import AD contacts to users' mailboxes through EWS using Powershell.

I have a Main.ps1 file that calls all the other scripts that do work in the background (for example 1 imports the AD modules) another imports O365 modules.

I have 1 script container that connect to EWS. The code looks like this:

#CONFIGURE ADMIN CREDENTIALS
$userUPN = "[email protected]" 
$AESKeyFilePath = ($pwd.ProviderPath) + "\ConnectToEWS\aeskey.txt"
$SecurePwdFilePath =  ($pwd.ProviderPath) + "\ConnectToEWS\password.txt"
$AESKey = Get-Content -Path $AESKeyFilePath -Force
$securePass = Get-Content -Path $SecurePwdFilePath -Force | ConvertTo-SecureString -Key $AESKey

#create a new psCredential object with required username and password
$adminCreds = New-Object System.Management.Automation.PSCredential($userUPN, $securePass)

Try
{
    [Reflection.Assembly]::LoadFile("\\MBX-Server\c$\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll") | Out-Null
    $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1)
    $service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($userUPN,$adminCreds.GetNetworkCredential().Password)
    $service.Url = new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx");
    
    return $service
}
Catch
{
    Write-Output "Unable to connect to EWS. Make sure the path to the DLL or URL is correct"
}

The output of that code prints out the Service connection, but I want the information for that output stored in a variable such as $service.

Then I would pass that variable to another script that binds to the mailbox I want... The problem I am having is $service doesn't seem to be storing that information. It only print it out once when I return it from the script above, but it doesn't append that information in the main script. When I print out $service it prints out once, but then it clears itself.

Here is my main script

CLS

#Root Path
$rootPath = $pwd.ProviderPath #$PSScriptRoot #$pwd.ProviderPath

Write-Host "Importing all necessary modules."

#******************************************************************
#                            PREREQUISITES
#******************************************************************
#Nuget - Needed for O365 Module to work properly

if(!(Get-Module -ListAvailable -Name NuGet))
{
    #Install NuGet (Prerequisite) first
    Install-PackageProvider -Name NuGet -Scope CurrentUser -Force -Confirm:$False
}

#******************************************************************

#Connect w\ Active Directory Module
& $rootPath\AD-Module\AD-module.ps1

#Load the O365 Module
& $rootPath\O365-Module\O365-module.ps1

#Clear screen after loading all the modules/sessions
CLS

#******************************************************************
#                         PUT CODE BELOW
#******************************************************************

#GLOBAL VARIABLES
$global:FolderName = $MailboxToConnect = $Service = $NULL

#Connect to EWS
& $rootPath\ConnectToEWS\ConnectToEWS.ps1

#Debug
$Service
    
#Create the Contacts Folder

& $rootPath\CreateContactsFolder\CreateContactsFolder.ps1 

#Debug
$service
$ContactsFolder

#Clean up Sessions after use

if($NULL -ne (Get-PSSession))
{
    Remove-PSSession *
}

[GC]::Collect()

The first time I output the $service variable, it prints fine. In the 2nd Debug output it doesn't print out anymore, and I believe that it why the script is failing when I launch "CreateContactsFolder.ps1"

Here is the content of "CreateContactsFolder.ps1"

CLS

Try
{    
    $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxToConnect);
        
    $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
    $RootFolder.Load()
        
    #Check to see if they have a contacts folder that we want
    $FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
    $ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where-Object {$_.DisplayName -eq $FolderName}

    if($ContactsFolderSearch)
    {
        $ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id);

        #If folder exists, connect to it. Clear existing Contacts, and reupload new (UPDATED) Contact Info
        Write-Output "Folder alreads exists. We will remove all contacts under this folder."

        # Attempt to empty the target folder up to 10 times.
        $tries = 0
        $max_tries = 0
        while ($tries -lt 2) 
        {
            try 
            {
                $tries++
                $ErrorActionPreference='Stop'
                $ContactsFolder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true)
                $tries++
            } 
            catch 
            {
                $ErrorActionPreference='SilentlyContinue'
                $rnd = Get-Random -Minimum 1 -Maximum 10
                Start-Sleep -Seconds $rnd
                $tries = $tries - 1
                $max_tries++

                if ($max_tries -gt 100) 
                {
                    Write-Output "Error; Cannot empty the target folder; `t$EmailAddress"
                }
            }
        }
    }
    else 
    {
        #Contact Folder doesn't exist. Let's create it
        try 
        {
            Write-Output "Creating new Contacts Folder called $FolderName"
                
            $ContactsFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($service);
            $ContactsFolder.DisplayName = $FolderName
            $ContactsFolder.Save([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
        } 
        catch 
        {
            Write-Output "Error; Cannot create the target folder; `t$EmailAddress"
        }
    }
}
Catch
{
    Write-Output "Couldn't connect to the user's mailbox. Make sure the admin account you're using to connect to has App Impersonization permissions"
    Write-Output "Check this link for more info: https://help.bittitan.com/hc/en-us/articles/115008098447-The-account-does-not-have-permission-to-impersonate-the-requested-user"
}
    
return $ContactsFolder

Solution

  • In the Main script, capture the returned variable from the EWS script like

    $service = & $rootPath\ConnectToEWS\ConnectToEWS.ps1
    

    Or dot-source that script into the Main script, so the variables from EWS.ps1 are local to the Main script, so you don't need to do return $service in there:

    . $rootPath\ConnectToEWS\ConnectToEWS.ps1
    

    and do the same for the CreateContactsFolder.ps1 script

    OR

    define the important variables in the called scripts with a global scope $global:service and $global:ContactsFolder See About_Scopes