0

私の最終的な目標は、ドメイン内のすべてのユーザーを手動で入力せずに、以下のコードを見つけて実行することですが、方法がわかりません。次に、スクリプトをタスク スケジューラに入れます。

これは、他の誰かを助ける場合に備えて、この背後にあるストーリーと情報です.

私の COO は、グローバル アドレス帳がすべてのデバイス (つまり、Android、IOS、Windows など) にオフラインで表示されることを望んでいます。スティーブ・グッドマンのメソッド/コードを使用して、Exchange Powershell で一度に 1 人のユーザーを実行する方法を見つけました --> http://www.stevieg.org/2012/02/importing-global-address-list-entries-into -a-users-contacts-folder . これを自分のユーザー名に対して行った後、電話で GAL 情報をオフラインで見ることができました。また、誰かが自分の電話から私に電話をかけると、インポートされた GAL から名前を取得することで、私の電話にその人の名前が表示されるようになりました。

基本的に、彼のコードでは、グローバル アドレス帳を個別のアドレス帳として各人にコピーしています。Outlook を見ると、連絡先が表示され、OrgContacts という名前の新しいアドレス帳が表示されます (この場合)。デバイスが次回 Exchange に同期されると、このアドレス帳も同期され、会社全体があなたと一緒になります。数百人のユーザーがいるので、大したことではありません。

これまでに使用したコードは、一度に 1 人のユーザーです。すべてのユーザー名を見つけて実行するのに助けが必要です。実行文字列でワ​​イルドカードを試しましたが、うまくいきませんでした。また、これを達成するためのまったく異なる方法があれば、それも受け入れます。

お時間をいただき、誠にありがとうございました。

各ユーザーのコードを実行するには、これを使用します...

# example (Billy Smith network username is basmith)
.\Copy-OrgContactsToUserContacts.ps1 -Mailbox basmith -FolderName OrgContacts

Exchange パワー シェル コードは次のとおりです...

param([string]$Mailbox,[string]$FolderName="OrgContacts");
#
# Copy-OrgContactsToUserMailboxContacts.ps1
#
# THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE
# RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
#
# Parameters
#  Mandatory:
# -MailboxFolder : Folder to "own" for these contacts.
#
# Creates s OrgContacts folder in the Mailbox and adds the contacts into it. Does not attempt to 


$EwsUrl = ([array](Get-WebServicesVirtualDirectory))[0].InternalURL.AbsoluteURI

$ContactMapping=@{
    "FirstName" = "GivenName";
    "LastName" = "Surname";
    "Company" = "CompanyName";
    "Department" = "Department";
    "Title" = "JobTitle";
    "WindowsEmailAddress" = "Email:EmailAddress1";
    "Phone" = "Phone:BusinessPhone";
    "MobilePhone" = "Phone:MobilePhone";
}

$UserMailbox  = Get-Mailbox $Mailbox

if (!$UserMailbox)
{
    throw "Mailbox $($Mailbox) not found";
    exit;
}

$EmailAddress = $UserMailbox.PrimarySMTPAddress

# Load EWS Managed API
[void][Reflection.Assembly]::LoadFile("C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll");

$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$service.UseDefaultCredentials = $true;
$service.URL = New-Object Uri($EwsUrl);

# Search for an existing copy of the Folder to store Org contacts 
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
$RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
$RootFolder.Load()

$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
$FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
$ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where {$_.DisplayName -eq $FolderName}
if ($ContactsFolderSearch)
{
    # Empty if found
    $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
    $ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id);
    $ContactsFolder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true)
} else {

    # Create new contacts folder
    $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
    $ContactsFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($service);
    $ContactsFolder.DisplayName = $FolderName
    $ContactsFolder.Save([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
    # Search for the new folder instance
    $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
    $RootFolder.Load()
    $FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
    $ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where {$_.DisplayName -eq $FolderName}
    $ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id);
}

# Add contacts
$Users = get-user -Filter {WindowsEmailAddress -ne $null -and (MobilePhone -ne $null -or Phone -ne $null) -and WindowsEmailAddress -ne $EmailAddress} 
$Users = $Users | select DisplayName,FirstName,LastName,Title,Company,Department,WindowsEmailAddress,Phone,MobilePhone

foreach ($ContactItem in $Users)
{
    $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);

    $ExchangeContact = New-Object Microsoft.Exchange.WebServices.Data.Contact($service);
    if ($ContactItem.FirstName -and $ContactItem.LastName)
    {
        $ExchangeContact.NickName = $ContactItem.FirstName + " " + $ContactItem.LastName;
    }
    elseif ($ContactItem.FirstName -and !$ContactItem.LastName)
    {
        $ExchangeContact.NickName = $ContactItem.FirstName;
    }
    elseif (!$ContactItem.FirstName -and $ContactItem.LastName)
    {
        $ExchangeContact.NickName = $ContactItem.LastName;
    }
    elseif (!$ContactItem.FirstName -and !$ContactItem.LastName)
    {
        $ExchangeContact.NickName = $ContactItem.DisplayName;
        $ContactItem.FirstName = $ContactItem.DisplayName;
    }

    $ExchangeContact.DisplayName = $ExchangeContact.NickName;
    $ExchangeContact.FileAs = $ExchangeContact.NickName;

    # This uses the Contact Mapping above to save coding each and every field, one by one. Instead we look for a mapping and perform an action on
    # what maps across. As some methods need more "code" a fake multi-dimensional array (seperated by :'s) is used where needed.
    foreach ($Key in $ContactMapping.Keys)
    {
        # Only do something if the key exists
        if ($ContactItem.$Key)
        {
            # Will this call a more complicated mapping?
            if ($ContactMapping[$Key] -like "*:*")
            {
                # Make an array using the : to split items.
                $MappingArray = $ContactMapping[$Key].Split(":")
                # Do action
                switch ($MappingArray[0])
                {
                    "Email"
                    {
                        $ExchangeContact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::($MappingArray[1])] = $ContactItem.$Key.ToString();
                    }
                    "Phone"
                    {
                        $ExchangeContact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::($MappingArray[1])] = $ContactItem.$Key;
                    }
                }                
            } else {
                $ExchangeContact.($ContactMapping[$Key]) = $ContactItem.$Key;            
            }

        }    
    }
    # Save the contact    
    $ExchangeContact.Save($ContactsFolder.Id);

    # Provide output that can be used on the pipeline
    $Output_Object = New-Object Object;
    $Output_Object | Add-Member NoteProperty FileAs $ExchangeContact.FileAs;
    $Output_Object | Add-Member NoteProperty GivenName $ExchangeContact.GivenName;
    $Output_Object | Add-Member NoteProperty Surname $ExchangeContact.Surname;
    $Output_Object | Add-Member NoteProperty EmailAddress1 $ExchangeContact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1]
    $Output_Object;
}
4

2 に答える 2

0

まず、グレン、私にリンクを与えてくれて、これについて考えさせてくれてありがとう。あなたはおそらくそれをすべて綴ることができたでしょうが、私はその過程でいくつかのことを学びました.

自己責任!私はプログラマーではありません。私は実稼働マシンでこれを行うだけではありませんが、それはあなた次第です。これにより、すべての連絡先がすべてのユーザーにコピーされます。次に電話またはデバイスが同期するときに、オフライン時にすべての連絡先が利用可能になります。Outlook オフラインの連絡先でも利用できます。150人しかいません。これ以上のことを提案するつもりはないと思います。これを実行するのに 1 時間以上かかります。このように GAL のコピーを何度も作成するのではなく、GAL を作成してから各ユーザーにコピーする方法がおそらくあります。しかし、私はそれを行うのに十分な知識がありません。

私はそれを働かせました。エレガントな方法ではありませんが、機能します。

誰かがこれを構築したい場合に備えて、ここに段階を追って説明します。変更する必要があるのは、以下の ForEach ループ内のドメイン名または OU だけです (2 番目のコード ブロック)。

まず、このコード (最初のコード ブロック) を、Steve Goodmans のメソッド/コードから Copy-OrgContactsToUserContacts.ps1 として保存しました --> http://www.stevieg.org/2012/02/importing-global-address-list-entries-into -ユーザーの連絡先フォルダー

param([string]$Mailbox,[string]$FolderName="OrgContacts");
#
# Copy-OrgContactsToUserMailboxContacts.ps1
#
# THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE
# RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
#
# Parameters
#  Mandatory:
# -MailboxFolder : Folder to "own" for these contacts.
#
# Creates s OrgContacts folder in the Mailbox and adds the contacts into it. Does not attempt to 


$EwsUrl = ([array](Get-WebServicesVirtualDirectory))[0].InternalURL.AbsoluteURI

$ContactMapping=@{
    "FirstName" = "GivenName";
    "LastName" = "Surname";
    "Company" = "CompanyName";
    "Department" = "Department";
    "Title" = "JobTitle";
    "WindowsEmailAddress" = "Email:EmailAddress1";
    "Phone" = "Phone:BusinessPhone";
    "MobilePhone" = "Phone:MobilePhone";
}

$UserMailbox  = Get-Mailbox $Mailbox

if (!$UserMailbox)
{
    throw "Mailbox $($Mailbox) not found";
    exit;
}

$EmailAddress = $UserMailbox.PrimarySMTPAddress

# Load EWS Managed API
[void][Reflection.Assembly]::LoadFile("C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll");

$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$service.UseDefaultCredentials = $true;
$service.URL = New-Object Uri($EwsUrl);

# Search for an existing copy of the Folder to store Org contacts 
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
$RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
$RootFolder.Load()

$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
$FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
$ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where {$_.DisplayName -eq $FolderName}
if ($ContactsFolderSearch)
{
    # Empty if found
    $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
    $ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id);
    $ContactsFolder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true)
} else {

    # Create new contacts folder
    $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);
    $ContactsFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($service);
    $ContactsFolder.DisplayName = $FolderName
    $ContactsFolder.Save([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
    # Search for the new folder instance
    $RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
    $RootFolder.Load()
    $FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
    $ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where {$_.DisplayName -eq $FolderName}
    $ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id);
}

# Add contacts
$Users = get-user -Filter {WindowsEmailAddress -ne $null -and (MobilePhone -ne $null -or Phone -ne $null) -and WindowsEmailAddress -ne $EmailAddress} 
$Users = $Users | select DisplayName,FirstName,LastName,Title,Company,Department,WindowsEmailAddress,Phone,MobilePhone

foreach ($ContactItem in $Users)
{
    $service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress);

    $ExchangeContact = New-Object Microsoft.Exchange.WebServices.Data.Contact($service);
    if ($ContactItem.FirstName -and $ContactItem.LastName)
    {
        $ExchangeContact.NickName = $ContactItem.FirstName + " " + $ContactItem.LastName;
    }
    elseif ($ContactItem.FirstName -and !$ContactItem.LastName)
    {
        $ExchangeContact.NickName = $ContactItem.FirstName;
    }
    elseif (!$ContactItem.FirstName -and $ContactItem.LastName)
    {
        $ExchangeContact.NickName = $ContactItem.LastName;
    }
    elseif (!$ContactItem.FirstName -and !$ContactItem.LastName)
    {
        $ExchangeContact.NickName = $ContactItem.DisplayName;
        $ContactItem.FirstName = $ContactItem.DisplayName;
    }

    $ExchangeContact.DisplayName = $ExchangeContact.NickName;
    $ExchangeContact.FileAs = $ExchangeContact.NickName;

    # This uses the Contact Mapping above to save coding each and every field, one by one. Instead we look for a mapping and perform an action on
    # what maps across. As some methods need more "code" a fake multi-dimensional array (seperated by :'s) is used where needed.
    foreach ($Key in $ContactMapping.Keys)
    {
        # Only do something if the key exists
        if ($ContactItem.$Key)
        {
            # Will this call a more complicated mapping?
            if ($ContactMapping[$Key] -like "*:*")
            {
                # Make an array using the : to split items.
                $MappingArray = $ContactMapping[$Key].Split(":")
                # Do action
                switch ($MappingArray[0])
                {
                    "Email"
                    {
                        $ExchangeContact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::($MappingArray[1])] = $ContactItem.$Key.ToString();
                    }
                    "Phone"
                    {
                        $ExchangeContact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::($MappingArray[1])] = $ContactItem.$Key;
                    }
                }                
            } else {
                $ExchangeContact.($ContactMapping[$Key]) = $ContactItem.$Key;            
            }

        }    
    }
    # Save the contact    
    $ExchangeContact.Save($ContactsFolder.Id);

    # Provide output that can be used on the pipeline
    $Output_Object = New-Object Object;
    $Output_Object | Add-Member NoteProperty FileAs $ExchangeContact.FileAs;
    $Output_Object | Add-Member NoteProperty GivenName $ExchangeContact.GivenName;
    $Output_Object | Add-Member NoteProperty Surname $ExchangeContact.Surname;
    $Output_Object | Add-Member NoteProperty EmailAddress1 $ExchangeContact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1]
    $Output_Object;
}

次に、foreach ループ ファイルを作成し、CopyGalToALLusers.ps1 という名前を付けました。このファイルは、作成した前のファイルと同じフォルダーに保存する必要があります。この foreach ループでは、ドメイン全体を検索しています。別の OU などを選択できます。ここで説明されている Get-Mailbox を参照してください https://technet.microsoft.com/en-us/library/Bb123685(v=EXCHG.150).aspx . 連絡先を保存するフォルダー名も変更できます。OrgContacts の代わりに別の名前を付けるだけです。

   $mailboxes = Get-Mailbox -OrganizationalUnit "indy.int/Esco Users"
foreach ($mailbox in $mailboxes)
{
. "C:\Program Files\Microsoft\Scripts\Copy Global Contact to Users\Copy-OrgContactsToUserContacts.ps1" -Mailbox $mailbox.alias -FolderName OrgContacts
}

最後の手順は、foreach ループで作成した Exchange PowerShell ファイルを手動で実行するか、タスク スケジューラでスケジュールすることです。

.\CopyGalToALLusers.ps1

それをスケジュールして適切なpowershellを使用するために、タスクスケジューラに行き、毎日午前2時に実行するように設定しました。実行するプログラムボックスに、次のように入力しました。これは、server2012r2 上の exchange 2010 です。最初の部分では、powershell を開くだけでなく、exchange に接続して、コマンドを理解できるようにします。ここに配置する適切な文字列を見つける方法は、Exchange PowerShell アイコンのプロパティを見て、すべてをコピーしたことです。最後の行は、forloop スクリプトの場所です。セミコロンと ".'forloop ファイルの場所'" を追加するだけです。これをコマンドラインに貼り付けて、スケジュールされたタスクを作成する前にテストすることもできます.

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command ". 'C:\Program Files\Microsoft\Exchange Server\V15\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto -ClientApplication:ManagementShell;  ". 'C:\Program Files\Microsoft\Scripts\Copy Global Contact to Users\CopyGALtoAllUsers.ps1'"
于 2015-08-26T15:51:22.127 に答える