Skip to content

Instantly share code, notes, and snippets.

@asmattic
Last active November 8, 2023 02:25
Show Gist options
  • Save asmattic/1c8fb4aa8df94580f0aedcace66bc7df to your computer and use it in GitHub Desktop.
Save asmattic/1c8fb4aa8df94580f0aedcace66bc7df to your computer and use it in GitHub Desktop.
Export Contacts As CSV In Outlook 365

To export personal contacts, use this EWSContacts Credit: nestorisyynimaa

Here is a quickly built script to get users' contacts.

Before running the script you need to give impersonation rights to the user who runs the script:

Enable-OrganizationCustomization
New-ManagementRoleAssignment -Role "ApplicationImpersonation" -User script@company.com

Here is the actual script, which gets contacts for the give user.

function Export-Contacts
{
    [cmdletbinding()]
    Param(
        [Parameter(Mandatory=$True, HelpMessage="Credentials used to connect to Exchange Online.")]
        [System.Management.Automation.PSCredential]$Credentials,
    
        [Parameter(Mandatory=$True, HelpMessage="User whose email activity is queried. Should be in email format.")]
        [String]$User,
        
        [Parameter(Mandatory=$False, HelpMessage="The maximum number of activities returned (default 200).")]
        [Int]$MaxResults=200,

        [Parameter(Mandatory=$False, HelpMessage="The number contacts to skip.")]
        [Int]$Skip=0

    )

    Write-Verbose ("Getting contacts for $User as "+$Credentials.UserName)

    # EWS service url for Exchange Online
    $webServiceUrl="https://outlook.office365.com/EWS/Exchange.asmx"

    # SOAP message for getting contact ItemIds
    $getItemIds="<?xml version=""1.0"" encoding=""utf-8""?>"+
    "<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" "+
    "               xmlns:m=""http://schemas.microsoft.com/exchange/services/2006/messages"" "+
    "               xmlns:t=""http://schemas.microsoft.com/exchange/services/2006/types"" "+
    "               xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope"">"+
    "  <soap:Header>"+
    "    <t:ExchangeImpersonation>"+
    "      <t:ConnectingSID>"+
    "        <t:PrimarySmtpAddress>$User</t:PrimarySmtpAddress>"+
    "      </t:ConnectingSID>"+
    "    </t:ExchangeImpersonation>"+    
    "  </soap:Header>"+
    "  <soap:Body>"+
    "    <m:FindItem Traversal=""Shallow"">"+
    "      <m:ItemShape>"+
    "        <t:BaseShape>IdOnly</t:BaseShape>"+
    "      </m:ItemShape>"+
    "      <m:IndexedPageItemView MaxEntriesReturned=""$MaxResults"" Offset=""$Skip"" BasePoint=""Beginning"" />"+
    "      <m:ParentFolderIds>"+
    "        <t:DistinguishedFolderId Id=""contacts"" />"+
    "      </m:ParentFolderIds>"+
    "    </m:FindItem>"+
    "  </soap:Body>"+
    "</soap:Envelope>"

    Write-Verbose "Id Request: $getItemIds"

    # Invoke request and convert to XML document
    $IdResponse=Invoke-WebRequest -Uri $webServiceUrl -Credential $Credentials -Body $getItemIds -Method Post 
    [xml]$xmlIdResponse=$IdResponse.Content

    Write-Verbose ("Id Response: "+$IdResponse.Content)

    # Get the number of found contacts
    $numOfContacts=$xmlIdResponse.Envelope.Body.FindItemResponse.ResponseMessages.FindItemResponseMessage.RootFolder.TotalItemsInView

    if($numOfContacts -gt 0)
    {
        # Get the contacts from the response
        $contactIds=$xmlIdResponse.Envelope.Body.FindItemResponse.ResponseMessages.FindItemResponseMessage.RootFolder.Items.Contact
    
        # Print out the number of results
        Write-Host "$numOfContacts contact(s) found for $user" -ForegroundColor Red

        # Loop through the results and build ItemIds block for GetItem SOAP request
        $ItemIds=""
        foreach($contactId in $contactIds)
        {
            $ItemIds+="<t:ItemId Id="""+$contactId.ItemId.Id+""" />"
        }

        # SOAP message for getting contacts
        $getItems="<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" "+
        "               xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" "+
        "               xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope"" "+
        "               xmlns:t=""http://schemas.microsoft.com/exchange/services/2006/types"">"+
        "  <soap:Header>"+
        "    <t:ExchangeImpersonation>"+
        "      <t:ConnectingSID>"+
        "        <t:PrimarySmtpAddress>$User</t:PrimarySmtpAddress>"+
        "      </t:ConnectingSID>"+
        "    </t:ExchangeImpersonation>"+    
        "  </soap:Header>"+
        "  <soap:Body>"+
        "    <GetItem xmlns=""http://schemas.microsoft.com/exchange/services/2006/messages"">"+
        "      <ItemShape>"+
        "        <t:BaseShape>AllProperties</t:BaseShape>"+
        "      </ItemShape>"+
        "      <ItemIds>"+
        $ItemIds+
        "      </ItemIds>"+
        "    </GetItem>"+
        "  </soap:Body>"+
        "</soap:Envelope>"

        Write-Verbose "Item Request: $getItems"

        # Invoke request and convert to XML document
        $ItemResponse=Invoke-WebRequest -Uri $webServiceUrl -Credential $Credentials -Body $getItems -Method Post 
        [xml]$xmlItemResponse=$ItemResponse.Content

        Write-Verbose ("Item Response: "+$ItemResponse.Content)

        # Retrieve contacts
        $contacts=$xmlItemResponse.Envelope.Body.GetItemResponse.ResponseMessages.GetItemResponseMessage.Items.Contact

        # Loop through the contacts
        foreach($contact in $contacts)
        {
            # Retrieve email addresses
            $emailAddresses = @()
            foreach($emailAddress in $contact.EmailAddresses.Entry)
            {
                $emailAddresses+=$emailAddress.'#text'
            }

            # Create a custom return object
            $contactDetails= @{}
            $contactDetails.Subject = $contact.Subject
            $contactDetails.Created = $contact.DateTimeCreated
            $contactDetails.DisplayName = $contact.DisplayName
            $contactDetails.GivenName = $contact.GivenName
            $contactDetails.Surname = $contact.Surname
            $contactDetails.EmailAddresses = $emailAddresses
            
            # Return contacts
            New-Object -TypeName PSObject -Property $contactDetails
        }
    }
    else
    {
        Write-Host "No contacts found for $user" -ForegroundColor Red
    }
}

You can now export user's contacts by calling the Export-Contacts function:

$creds=Get-Credential
Export-Contacts -Credentials $creds -User user@company.com

The function returns contact information as PS object, so you easily export them to csv:

Export-Contacts -Credentials $creds -user user@company.com | Export-Csv user.csv -NoTypeInformation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment