【问题标题】:Use PowerShell and EWS to impersonate original meeting organiser when creating appointment创建约会时使用 PowerShell 和 EWS 模拟原始会议组织者
【发布时间】:2019-06-12 00:33:53
【问题描述】:

我正在尝试使用 EWS(Exchange Web 服务)API 在 Exchange Online 的资源邮箱中创建约会。

我正在使用 O365 全局管理员帐户向 EWS 进行身份验证。

然后我冒充组织者,然后绑定到邮箱日历文件夹。我已经为此设置了适当的管理角色/范围。

当我创建约会时,组织者显示为会议室邮箱帐户,而不是模拟帐户。我看不出我做错了什么......

我已经使用了各种来源来了解我所拥有的:

https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/dd633680(v=exchg.80)

https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/delegate-access-and-ews-in-exchange

下面的代码成功地在 $roomMailbox 日历中创建了一个约会,虽然组织者被设置为房间邮箱,而不是我试图冒充的组织者...

非常感谢任何指导。

using namespace Microsoft.Exchange.WebServices.Data

Set-StrictMode -Version 5.1

$ErrorActionPreference = 'Stop'

function Connect-EWS
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$false)]
        [System.Management.Automation.PSCredential]$Credential
    )

    try
    {
        [void][Reflection.Assembly]::LoadFile("C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll")
    }
    catch
    {
        throw "Could not import Microsoft Exchange web services library: $($_.Exception.Message)"
    }

    try
    {
        $ews = [ExchangeService]::New()
    }
    catch
    {
        throw "Could not create Microsoft.Exchange.WebServices.Data.ExchangeService object: $($_.Exception.Message)"
    }

    if($credential)
    {
        $ews.Credentials = $Credential.GetNetworkCredential()
    }
    else
    {
        $ews.UseDefaultCredentials = $true
    }

    $validateRedirectionUrlCallback = {

        Param([String]$Url)

        if($Url -eq "https://autodiscover-s.outlook.com/autodiscover/autodiscover.xml")
        {
            return $true
        } 
        else 
        {
            return $false
        }
    }

    try
    {
        $ews.AutodiscoverUrl($Credential.UserName,$validateRedirectionUrlCallback)
    }
    catch
    {
        throw "Autodiscover failed: $($_.Exception.Message)"
    }

    return $ews
}

function New-Appointment
{
    Param
    (
        [Parameter(Mandatory = $true)]
        [String]$Organiser
        ,
        [Parameter(Mandatory = $true)]
        [String]$RoomMailbox
        ,
        [Parameter(Mandatory = $true)]
        [DateTime]$Start
        ,
        [Parameter(Mandatory = $true)]
        [DateTime]$End
        ,
        [Parameter(Mandatory = $true)]
        [String]$Subject
        ,
        [Parameter(Mandatory = $true)]
        [String]$Location
    )


    try # Resolve the organiser ID
    {
        [Void]$ews.ResolveName($Organiser,[ResolveNameSearchLocation]::DirectoryOnly, $false)
    }
    catch
    {
        throw "Could not resolve Organiser identity: $Organiser : $($_.Exception.Message)"
    }

    try # Attempt to enable impersonation as the organiser
    {
        $ews.ImpersonatedUserId = [ImpersonatedUserId]::New([ConnectingIdType]::SmtpAddress, $Organiser)
    }
    catch
    {
        throw "Could not impersonate user $Organiser : $($_.Exception.Message)"
    }

    try # Create a new appointment object
    {
        $appointment = [Appointment]::New($ews)
    }
    catch
    {
        throw "Could not create appointment object: $($_.Exception.MEssage)"
    }

    # Add each of the properties below associated values into the appointment object

    $setProperties = 'Start','End','Subject','Location'

    foreach($p in $setProperties)
    {
        $appointment.$p = Get-Variable $p -ValueOnly
    }

    try # Set the folder ID as the calendar of the room mailbox
    {
        $folderId = [FolderId]::New([WellKnownFolderName]::Calendar, $RoomMailbox)
    }
    catch
    {
        throw "Could not generate target calendar folder id: $($_.Exception.Message)"
    }

    try # Try and bind the EWS connection to the folder
    {
        $folder = [Folder]::Bind($ews, $folderId)
    }
    catch
    {
        throw "Could not bind to user $($folderId.FolderName) $($_.Exception.Message)"
    }

    try # Save the appointment
    {
        $appointment.Save($folderId, [SendInvitationsMode]::SendToAllAndSaveCopy)
    }
    catch
    {
        throw "Could not save appointment as organiser: $Organiser : $($_.Exception.Message)"
    }
}

if(!$credential)
{
    $credential = Get-Credential -UserName $globalAdminUPN -Message "Please enter O365 credentials for user $globalAdminUPN"
}

$Organiser   = 'organiser@domain.com'
$RoomMailbox = 'roommailbox@domain.com'
$Start       = '01/02/2019 22:00'
$End         = '01/02/2019 23:00'
$Subject     = 'Test Appointment'
$Location    = 'Test Location'

$ews = Connect-EWS -Credential $credential

try
{
    New-Appointment -Organiser   $Organiser `
                    -RoomMailbox $RoomMailbox `
                    -Start       $Start `
                    -End         $End `
                    -Subject     $Subject `
                    -Location    $Location
}
catch
{
    Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
} 

【问题讨论】:

  • 您是否尝试将其保存到通用邮箱而不是房间邮箱中的通用文件夹,它是用正确的组织者创建的吗?
  • 我正在尝试将其保存到资源邮箱的日历文件夹中。我正在冒充组织者,但它将组织者设置为房间邮箱,而不是我冒充的组织者。
  • 我知道你在问什么,但我说的是:你是否尝试使用普通邮箱,而不是资源邮箱,并检查模拟是否有效,让我知道......跨度>
  • 我尝试使用标准邮箱和房间邮箱,结果相同,尽管我相信我已经得出结论/解决方案。组织者始终设置为创建约会的邮箱的所有者(除非我弄错了)。我不应该在会议室邮箱中创建会议,而应该在组织者邮箱中创建会议并将会议室邮箱添加为与会者。这实现了我想要的。

标签: powershell calendar exchange-server exchangewebservices impersonation


【解决方案1】:

为什么不在这条线上指定组织者?

$setProperties = 'Start','End','Subject','Location'

*现在阅读该组织者是只读的并自动设置但我找到了这篇文章The Organizer of an Appointment: The Dirty Truth,这里提到了约会.SentOnBehalfOfName

也请查看此链接

Add appointments by using Exchange impersonation

【讨论】:

  • 谢谢,虽然这两篇文章我都看过。我的约会对象没有要设置的 SentOnBehalfOfName 属性,并且我已经在模拟帐户(根据我的代码)。
  • 那么约会.SendUsingAccount 呢? docs.microsoft.com/en-us/office/vba/api/…
  • 另外,我现在看到有一个 PropertyAccessor 对象,它支持创建、获取、设置和删除属性docs.microsoft.com/en-us/office/vba/api/…
  • 我使用的方法应该按照我查看过的各种 Microsoft 文档工作:1. 以服务帐户身份进行身份验证 2. 模拟组织者 3. 在房间邮箱中创建约会我正在这样做虽然结果是房间邮箱设置为组织者,不是我冒充的账号。我怀疑我的实现是错误的,我只是看不出问题是什么......
【解决方案2】:

据我所知,我试图做的似乎是不可能的,无论模拟/委托如何,组织者总是被设置为创建约会的邮箱的所有者。

我通过在组织者日历中创建约会并将会议室邮箱添加为与会者来改变解决问题的方式。这样就实现了我的目标,和之前一样的权利,就是冒充组织者。

下面的脚本包含 Connect-EWS 和 New-Appointment 函数以及执行这些函数的函数。

要求 admin@domain.onmicrosoft.com 帐户对组织者邮箱具有模拟权限。

这仅适用于 Exchange Online,因为不使用自动发现,EWS 的 URL 是手动设置的。

using namespace Microsoft.Exchange.WebServices.Data

Set-StrictMode -Version 5.1

$ErrorActionPreference = 'Stop'

function Connect-EWS
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true)]
        [System.Management.Automation.PSCredential]$Credential
    )

    try
    {
        [void][Reflection.Assembly]::LoadFile("C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll")
    }
    catch
    {
        throw "Could not import Microsoft Exchange web services library: $($_.Exception.Message)"
    }

    try
    {
        $ews = [ExchangeService]::New()
    }
    catch
    {
        throw "Could not create Microsoft.Exchange.WebServices.Data.ExchangeService object: $($_.Exception.Message)"
    }

    if($credential)
    {
        $ews.Credentials = $Credential.GetNetworkCredential()
    }
    else
    {
        $ews.UseDefaultCredentials = $true
    }

    try # Set EWS URL
    {
        $ews.Url = 'https://outlook.office365.com/EWS/Exchange.asmx'
    }
    catch
    {
        throw "Could not set EWS URL: $($_.Exception.Message)"
    }

    return $ews
}

function New-Appointment
{
    Param
    (
        [Parameter(Mandatory = $true)]
        [String]$Organiser
        ,
        [Parameter(Mandatory = $true)]
        [DateTime]$Start
        ,
        [Parameter(Mandatory = $true)]
        [DateTime]$End
        ,
        [Parameter(Mandatory = $true)]
        [String]$Subject
        ,
        [Parameter(Mandatory = $false)]
        [String]$Location
        ,
        [Parameter(Mandatory = $false)]
        [Array]$RequiredAttendees
    )


    try # Resolve the organiser ID
    {
        [Void]$ews.ResolveName($Organiser,[ResolveNameSearchLocation]::DirectoryOnly, $false)
    }
    catch
    {
        throw "Could not resolve Organiser identity: $Organiser : $($_.Exception.Message)"
    }

    try # Attempt to enable impersonation as the organiser
    {
        $ews.ImpersonatedUserId = [ImpersonatedUserId]::New([ConnectingIdType]::SmtpAddress, $Organiser)
    }
    catch
    {
        throw "Could not impersonate user $Organiser : $($_.Exception.Message)"
    }

    try # Create a new appointment object
    {
        $appointment = [Appointment]::New($ews)
    }
    catch
    {
        throw "Could not create appointment object: $($_.Exception.MEssage)"
    }

    try # Add each required attendee to appointment
    {
        foreach($ra in $requiredAttendees)
        {
            [Void]$appointment.RequiredAttendees.Add($ra)
        }
    }
    catch
    {
        throw "Failed to add required attendee: $ra : $($_.Excecption.Message)"
    }

    # Add each of the properties below associated values into the appointment object

    $setProperties = 'Start','End','Subject','Location'

    foreach($p in $setProperties)
    {
        $appointment.$p = Get-Variable $p -ValueOnly
    }

    try # Set the folder ID as the calendar of the room mailbox
    {
        $folderId = [FolderId]::New([WellKnownFolderName]::Calendar, $Organiser)
    }
    catch
    {
        throw "Could not generate target calendar folder id: $($_.Exception.Message)"
    }

    try # Try and bind the EWS connection to the folder
    {
        $folder = [Folder]::Bind($ews, $folderId)
    }
    catch
    {
        throw "Could not bind to mailbox $($folderId.Mailbox) $($_.Exception.Message)"
    }

    try # Save the appointment
    {
        $appointment.Save($folderId, [SendInvitationsMode]::SendToAllAndSaveCopy)
    }
    catch
    {
        throw "Could not save appointment as organiser: $Organiser : $($_.Exception.Message)"
    }
}

$admin = 'admin@domain.onmicrosoft.com'

$credential = Get-Credential -UserName $admin -Message "Please enter O365 credentials for user $admin"

$Organiser   = 'organiser@domain.onmicrosoft.com'
$RoomMailbox = 'roommailbox@domain.onmicrosoft.com'
$Start       = '02/01/2019 12:00'
$End         = '02/01/2019 13:00'
$Subject     = 'Test Appointment'
$Location    = 'Test Location'

$requiredAttendees = $RoomMailbox

$ews = Connect-EWS -Credential $credential

try
{
    New-Appointment -Organiser         $Organiser `
                    -Start             $Start `
                    -End               $End `
                    -Subject           $Subject `
                    -Location          $Location `
                    -RequiredAttendees $requiredAttendees
}
catch
{
    Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
}

【讨论】:

    猜你喜欢
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 2014-08-18
    • 2020-09-28
    • 1970-01-01
    • 2012-03-13
    相关资源
    最近更新 更多