使用 EWS 在其他邮箱中创建文件夹 API

Create Folder in other Mailbox with EWS API

我尝试在其他邮箱中创建联系人文件夹。由于 Powershell 无法执行此操作,因此我通过此 MSDN 站点下载了一个 c# 示例:

https://code.msdn.microsoft.com/exchange/Exchange-2013-Create-35e4948c/view/Discussions#content

然后我将 createFolder_CS.cs 修改为:

    class Ex15_CreateFolder_CS
    {
    static ExchangeService service = Service.ConnectToService(UserDataFromConsole.GetUserData(), new TraceListener());

    static void Main(string[] args)
        {
        CreateFolder(service, "Test", WellKnownFolderName.MsgFolderRoot);

        Console.WriteLine("\r\n");
        Console.WriteLine("Press or select Enter...");
        Console.Read();
        }

    static void CreateFolder(ExchangeService service, string DisplayName, WellKnownFolderName DestinationFolder)
        {
        // Instantiate the Folder object.
        Folder folder = new ContactsFolder(service);

        // Specify the name of the new folder.
        folder.DisplayName = DisplayName;

        // Create the new folder in the specified destination folder.
        folder.Save(DestinationFolder);

        Console.WriteLine("Folder created:" + folder.DisplayName);
        }
    }

更改后我启动了程序。我输入了我的电子邮件和密码,它在我的邮箱中创建了联系人文件夹。但是当我使用不同的电子邮件地址时,程序无法运行。

我编译了它并以(其他用户)身份启动了 exe 文件 domain/exchange-admin 但它仍然不适用于另一个邮箱。

所以我阅读了有关 ImpersonatedUserId 的内容,但这已经包含在程序中。

既然我是 c# 的初学者,也许你可以给我一些如何使它工作的提示?

你的代码的问题是你没有告诉它你想在哪个邮箱中保存新文件夹。你需要使用 FolderId 重载来指定这个或者它总是将它保存到凭据的邮箱中运行宁下eg修改你分赞

        static void CreateFolder(ExchangeService service, string DisplayName, WellKnownFolderName DestinationFolder,String TargetMailboxSMTPAddress)
    {
    // Instantiate the Folder object.
    Folder folder = new ContactsFolder(service);

    // Specify the name of the new folder.
    folder.DisplayName = DisplayName;


     FolderId ParentFolder = new FolderId(DestinationFolder,TargetMailboxSMTPAddress);
    // Create the new folder in the specified destination folder.
    folder.Save(ParentFolder);

    Console.WriteLine("Folder created:" + folder.DisplayName);
    }

如果你想使用 Impersonation 那么你只需要在代码中添加一行

service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress,TargetMailboxSMTPAddress);

您需要分配 ApplicationImpersonation RBAC 角色才能使用此 https://msdn.microsoft.com/en-us/library/office/bb204095(v=exchg.140).aspx

如果您在 poweshell 中为 运行 创建一个控制台应用程序,我建议您只使用 Powershell 中的托管 API 例如这里的脚本模块将使用托管 API

function Connect-Exchange{ 
    param( 
        [Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
        [Parameter(Position=1, Mandatory=$true)] [PSCredential]$Credentials
    )  
    Begin
         {
        Load-EWSManagedAPI

        ## Set Exchange Version  
        $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1

        ## Create Exchange Service Object  
        $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)  

        ## Set Credentials to use two options are availible Option1 to use explict credentials or Option 2 use the Default (logged On) credentials  

        #Credentials Option 1 using UPN for the windows Account  
        #$psCred = Get-Credential  
        $creds = New-Object System.Net.NetworkCredential($Credentials.UserName.ToString(),$Credentials.GetNetworkCredential().password.ToString())  
        $service.Credentials = $creds      
        #Credentials Option 2  
        #service.UseDefaultCredentials = $true  
         #$service.TraceEnabled = $true
        ## Choose to ignore any SSL Warning issues caused by Self Signed Certificates  

        Handle-SSL  

        ## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use  

        #CAS URL Option 1 Autodiscover  
        $service.AutodiscoverUrl($MailboxName,{$true})  
        Write-host ("Using CAS Server : " + $Service.url)   

        #CAS URL Option 2 Hardcoded  

        #$uri=[system.URI] "https://casservername/ews/exchange.asmx"  
        #$service.Url = $uri    

        ## Optional section for Exchange Impersonation  

        #$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName) 
        if(!$service.URL){
            throw "Error connecting to EWS"
        }
        else
        {       
            return $service
        }
    }
}

function Load-EWSManagedAPI{
    param( 
    )  
    Begin
    {
        ## Load Managed API dll  
        ###CHECK FOR EWS MANAGED API, IF PRESENT IMPORT THE HIGHEST VERSION EWS DLL, ELSE EXIT
        $EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + "Microsoft.Exchange.WebServices.dll")
        if (Test-Path $EWSDLL)
            {
            Import-Module $EWSDLL
            }
        else
            {
            "$(get-date -format yyyyMMddHHmmss):"
            "This script requires the EWS Managed API 1.2 or later."
            "Please download and install the current version of the EWS Managed API from"
            "http://go.microsoft.com/fwlink/?LinkId=255472"
            ""
            "Exiting Script."
            exit
            } 
    }
}

function Handle-SSL{
    param( 
    )  
    Begin
    {
        ## Code From http://poshcode.org/624
        ## Create a compilation environment
        $Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
        $Compiler=$Provider.CreateCompiler()
        $Params=New-Object System.CodeDom.Compiler.CompilerParameters
        $Params.GenerateExecutable=$False
        $Params.GenerateInMemory=$True
        $Params.IncludeDebugInformation=$False
        $Params.ReferencedAssemblies.Add("System.DLL") | Out-Null

$TASource=@'
  namespace Local.ToolkitExtensions.Net.CertificatePolicy{
    public class TrustAll : System.Net.ICertificatePolicy {
      public TrustAll() { 
      }
      public bool CheckValidationResult(System.Net.ServicePoint sp,
        System.Security.Cryptography.X509Certificates.X509Certificate cert, 
        System.Net.WebRequest req, int problem) {
        return true;
      }
    }
  }
'@ 
        $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
        $TAAssembly=$TAResults.CompiledAssembly

        ## We now create an instance of the TrustAll and attach it to the ServicePointManager
        $TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
        [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll

        ## end code from http://poshcode.org/624

    }
}

function Get-FolderFromPath{
    param (
            [Parameter(Position=0, Mandatory=$true)] [string]$FolderPath,
            [Parameter(Position=1, Mandatory=$true)] [string]$MailboxName,
            [Parameter(Position=2, Mandatory=$true)] [Microsoft.Exchange.WebServices.Data.ExchangeService]$service,
            [Parameter(Position=3, Mandatory=$false)] [Microsoft.Exchange.WebServices.Data.PropertySet]$PropertySet
          )
    process{
        ## Find and Bind to Folder based on Path  
        #Define the path to search should be seperated with \  
        #Bind to the MSGFolder Root  
        $folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$MailboxName)   
        $tfTargetFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)  
        #Split the Search path into an array  
        $fldArray = $FolderPath.Split("\") 
         #Loop through the Split Array and do a Search for each level of folder 
        for ($lint = 1; $lint -lt $fldArray.Length; $lint++) { 
            #Perform search based on the displayname of each folder level 
            $fvFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1) 
            if(![string]::IsNullOrEmpty($PropertySet)){
                $fvFolderView.PropertySet = $PropertySet
            }
            $SfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$fldArray[$lint]) 
            $findFolderResults = $service.FindFolders($tfTargetFolder.Id,$SfSearchFilter,$fvFolderView) 
            if ($findFolderResults.TotalCount -gt 0){ 
                foreach($folder in $findFolderResults.Folders){ 
                    $tfTargetFolder = $folder                
                } 
            } 
            else{ 
                Write-host ("Error Folder Not Found check path and try again")  
                $tfTargetFolder = $null  
                break  
            }     
        }  
        if($tfTargetFolder -ne $null){
            return [Microsoft.Exchange.WebServices.Data.Folder]$tfTargetFolder
        }
        else{
            throw ("Folder Not found")
        }
    }
}


####################### 
<# 
.SYNOPSIS 
 Creates a Folder in a Mailbox using the  Exchange Web Services API 

.DESCRIPTION 
  Creates a Folder in a Mailbox using the  Exchange Web Services API 

  Requires the EWS Managed API from https://www.microsoft.com/en-us/download/details.aspx?id=42951

.EXAMPLE
    Example 1 To create a Folder named test in the Root of the Mailbox
     Create-Folder -Mailboxname mailbox@domain.com -NewFolderName test

    Example 2 To create a Folder as a SubFolder of the Inbox
     Create-Folder -Mailboxname mailbox@domain.com -NewFolderName test -ParentFolder '\Inbox'

     Example 3 To create a new Folder Contacts SubFolder of the Contacts Folder
     Create-Folder -Mailboxname mailbox@domain.com -NewFolderName test -ParentFolder '\Contacts' -FolderClass IPF.Contact

#> 
########################
function Create-Folder{
    param( 
        [Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
        [Parameter(Position=1, Mandatory=$true)] [PSCredential]$Credentials,
        [Parameter(Position=2, Mandatory=$true)] [String]$NewFolderName,
        [Parameter(Position=3, Mandatory=$false)] [String]$ParentFolder,
        [Parameter(Position=4, Mandatory=$false)] [String]$FolderClass
    )  
    Begin
     {
        $service = Connect-Exchange -MailboxName $MailboxName -Credentials $Credentials
        $NewFolder = new-object Microsoft.Exchange.WebServices.Data.Folder($service)  
        $NewFolder.DisplayName = $NewFolderName 
        if(([string]::IsNullOrEmpty($folderClass))){
            $NewFolder.FolderClass = "IPF.Note"
        }
        else{
            $NewFolder.FolderClass = $folderClass
        }
        $EWSParentFolder = $null
        if(([string]::IsNullOrEmpty($ParentFolder))){
            # Bind to the MsgFolderRoot folder  
            $folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$MailboxName)   
            $EWSParentFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
        }
        else{
            $EWSParentFolder =  Get-FolderFromPath -MailboxName $MailboxName -service $service -FolderPath $ParentFolder
        }
        #Define Folder Veiw Really only want to return one object  
        $fvFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1)  
        #Define a Search folder that is going to do a search based on the DisplayName of the folder  
        $SfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$NewFolderName)  
        #Do the Search  
        $findFolderResults = $service.FindFolders($EWSParentFolder.Id,$SfSearchFilter,$fvFolderView)  
        if ($findFolderResults.TotalCount -eq 0){  
            Write-host ("Folder Doesn't Exist")  
            $NewFolder.Save($EWSParentFolder.Id)  
            Write-host ("Folder Created")  
        }  
        else{  
            Write-error ("Folder already Exist with that Name")  
        }  


     }
}