Functions/Set-GSuiteUser.ps1


<#
.SYNOPSIS
    This function updates a GSuite user.
    https://developers.google.com/admin-sdk/directory/v1/reference/users/update
#>

function Set-GSuiteUser {
    [CmdletBinding(PositionalBinding=$false)]
    [OutputType([Bool])]
    param (
        # The primary email address of the user.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$primaryEmailAddress,

        # The first name of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$firstName,

        # The last name of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$lastName,

        # The telephone number of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$telephoneNumber,

        # The mobile phone number of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$mobilePhoneNumber,

        # The email address of the manager of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$managerEmailAddress,

        # The company name of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$companyName,

        # The department of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$department,

        # The job title of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$jobTitle,

        # The country or region of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$countryOrRegion,

        # The work address of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$addressLine1,

        # The city of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$city,

        # The state or province of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$stateOrProvince,

        # The postal or zip code address of the user.
        [Parameter(Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [String]$postalOrZipCode
    )

    # Validate that the 'connection' has been established
    if (!$Global:GSuiteAccessTokensHashTable) {
        throw "You must call the Connect-GSuiteAdminAccount cmdlet before calling any other GSuite cmdlets."
    }

    # Validate that the user access token exists in the hash table
    if ([String]::IsNullOrWhiteSpace($Global:GSuiteAccessTokensHashTable.User)) {
        throw "User access token is required to call Set-GSuiteUser."
    }

    # Retrieve information of the user
    try {
        $userInformation = Get-GSuiteUser -PrimaryEmailAddress $primaryEmailAddress
    }
    catch {
        throw "Exception occurred while retrieving user '$($primaryEmailAddress)'.`r`n$($_.Exception.Message)"
    }
    if (!$userInformation) {
        throw "Failed to retrieve user '$($primaryEmailAddress)'."
    }

    # Initialize the body of the PUT request
    $updateUserBody = @{ }

    # Update names
    if (![String]::IsNullOrWhiteSpace($lastName) -or ![String]::IsNullOrWhiteSpace($firstName)) {
        $name = $userInformation.name

        # Update first name and last name
        if (![String]::IsNullOrWhiteSpace($lastName)) {
            $name.familyName = $lastName
        }
        if (![String]::IsNullOrWhiteSpace($firstName)) {
            $name.givenName = $firstName
        }
        $updateUserBody.Add("name", $name)
    }

    # Update manager email address
    if (![String]::IsNullOrWhiteSpace($managerEmailAddress)) {
        # Get the current relations
        $relations = ConvertTo-Array $userInformation.relations
        $manager = $relations | Where-Object { $_.type -eq "manager" }

        # If manager exists, update the manager value
        if ($manager) {
            $manager.value = $managerEmailAddress
        }

        # If not, append the object to the array
        else {
            $relations += [PSCustomObject]@{
                type  = "manager"
                value = $managerEmailAddress
            }
        }
        $updateUserBody.Add("relations", $relations)
    }

    # Update phone numbers
    if (![String]::IsNullOrWhiteSpace($telephoneNumber) -or ![String]::IsNullOrWhiteSpace($mobilePhoneNumber)) {
        $phones = ConvertTo-Array $userInformation.phones

        # Update telephone number
        if (![String]::IsNullOrWhiteSpace($telephoneNumber)) {
            $telephone = $phones | Where-Object { $_.type -eq "home" }

            # If telephone exists, update the telephone value
            if ($telephone) {
                $telephone.value = $telephoneNumber
            }

            # If not, append the object to the array
            else {
                $phones += [PSCustomObject]@{
                    type  = "home"
                    value = $telephoneNumber
                }
            }
        }

        # Update mobile phone number
        if (![String]::IsNullOrWhiteSpace($mobilePhoneNumber)) {
            $mobilePhone = $phones | Where-Object { $_.type -eq "mobile" }

            # If mobile phone exists, update the mobile phone value
            if ($mobilePhone) {
                $mobilePhone.value = $mobilePhoneNumber
            }

            # If not, append the object to the array
            else {
                $phones += [PSCustomObject]@{
                    type  = "mobile"
                    value = $mobilePhoneNumber
                }
            }
        }
        $updateUserBody.Add("phones", $phones)
    }

    # Update primary organization information
    if (![String]::IsNullOrWhiteSpace($companyName) -or ![String]::IsNullOrWhiteSpace($department) -or ![String]::IsNullOrWhiteSpace($jobTitle)) {
        $organizations = ConvertTo-Array $userInformation.organizations
        $primaryOrganization = $organizations | Where-Object { $_.primary -eq $true }

        # If primary organization does not exist, create one
        if (!$primaryOrganization) {
            $primaryOrganization = [PSCustomObject]@{
                primary = $true
            }
            $organizations += $primaryOrganization
        }

        # Update company name, department, and job title
        if (![String]::IsNullOrWhiteSpace($companyName)) {
            $primaryOrganization | Add-Member -NotePropertyName "name" -NotePropertyValue $companyName -Force
        }
        if (![String]::IsNullOrWhiteSpace($department)) {
            $primaryOrganization | Add-Member -NotePropertyName "department" -NotePropertyValue $department -Force
        }
        if (![String]::IsNullOrWhiteSpace($jobTitle)) {
            $primaryOrganization | Add-Member -NotePropertyName "title" -NotePropertyValue $jobTitle -Force
        }
        $updateUserBody.Add("organizations", $organizations)
    }

    # Update work address
    if (![String]::IsNullOrWhiteSpace($countryOrRegion) -or ![String]::IsNullOrWhiteSpace($city) -or ![String]::IsNullOrWhiteSpace($addressLine1) -or ![String]::IsNullOrWhiteSpace($stateOrProvince) -or ![String]::IsNullOrWhiteSpace($postalOrZipCode)) {
        $addresses = ConvertTo-Array $userInformation.addresses
        $workAddress = $addresses | Where-Object { $_.type -eq "work" }

        # If work address does not exist, create one
        if (!$workAddress) {
            $workAddress = [PSCustomObject]@{
                type = "work"
            }
            $addresses += $workAddress
        }

        # Create an address property map, where names are property names in MSPComplete, values are property names in GSuite
        $addressPropertyMap = [PSCustomObject]@{
            AddressLine1    = "streetAddress"
            City            = "locality"
            StateOrProvince = "region"
            CountryOrRegion = "country"
            PostalOrZipCode = "postalCode"
        }

        # Initialize formatted address, which is the only visible property in UI
        $formattedAddress = ""

        # Update address properties
        foreach($addressNameInMSPComplete in $addressPropertyMap.PSObject.Properties.Name){
            $addressNameInGSuite = $addressPropertyMap.$addressNameInMSPComplete
            $addressValue = Invoke-Expression "`$$($addressNameInMSPComplete)"

            # Update the property if provided
            if (![String]::IsNullOrWhiteSpace($addressValue)) {
                $workAddress | Add-Member -NotePropertyName $addressNameInGSuite -NotePropertyValue $addressValue -Force
            }

            # Update the formatted address
            if (![String]::IsNullOrWhiteSpace($workAddress.$addressNameInGSuite)) {
                $formattedAddress += ($workAddress.$addressNameInGSuite + "`r`n")
            }
        }

        # Update the request body
        $workAddress | Add-Member -NotePropertyName "formatted" -NotePropertyValue $formattedAddress.TrimEnd() -Force
        $updateUserBody.Add("addresses", $addresses)
    }

    # Prepare REST call parameters
    $invokeRestMethodParams = @{
        Uri     = "https://www.googleapis.com/admin/directory/v1/users/$($primaryEmailAddress)"
        Method  = "PUT"
        Headers = @{
            "Content-Type" = "application/json"
            Accept         = "application/json"
            Authorization  = "Bearer $($Global:GSuiteAccessTokensHashTable.User)"
        }
        Body    = $updateUserBody | ConvertTo-Json
    }

    # Invoke the REST call
    $response = Invoke-RestMethod @invokeRestMethodParams

    # Return true if there is response, and return false otherwise
    if ($response) {
        return $true
    }
    return $false
}