<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Roman Zarka: Notes From the Field</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/zarkatech/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/zarkatech/feed.xml</link>
    <description />
    <lastBuildDate>Mon, 15 May 2017 13:45:23 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Analyzing MRS Move Requests in Exchange and Exchange Online</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/analyzing-mrs-move-requests-in-exchange-and-exchange-online</link>
      <pubDate>Mon, 15 May 2017 13:45:23 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/?p=195</guid>
      <description><![CDATA[As an Exchange and Office 365 delivery consultant, I am often asked to troubleshoot mailbox...]]></description>
      <content:encoded><![CDATA[As an Exchange and Office 365 delivery consultant, I am often asked to troubleshoot mailbox migrations and help identify why move requests stall or fail.  When using the Exchange Mailbox Replication Service (MRS) for local, cross-forest, or hybrid moves the move request detail report from EAC offers some useful clues, but it is usually vague and cryptic for identifying specific issues.  As a result, I often parse the data using PowerShell or ask a customer to export the report to XML for further analysis.  Here are a couple common examples:
<pre>Get-MoveRequestStatistics user.name -IncludeReport | fl

(Get-MoveRequestStatistics user.name -IncludeReport).Report

$r = Get-MoveRequest user.name | Get-MoveRequestStatistics -IncludeReport
$r.Report.Failures

Get-MoveRequestStatistics user.name -IncludeReport | Export-CliXml export.xml
$r = Import-CliXml export.xml
$r.Report</pre>
There is actually quite a bit of valuable logging and debug information stored in the move report, but parsing through it using PowerShell and building collections can be quite tedious.  I have tried using a generic XML browser, but found the serialized MRS data simply does not render correctly.  Therefore, I developed my own tool.

<a href="https://gallery.technet.microsoft.com/MRS-Explorer-for-Exchange-b55c0c67">MRS Explorer </a>is a PowerShell script which renders a graphical user interface (GUI) for retrieving, auditing, and analyzing Exchange and Exchange Online (Office 365) move request reports from serialized XML data.  As I was developing the tool, I shared it with few colleagues for field testing and it generated a surprising amount of interest and feedback.  I continued to evolve the script refining the import and export functionality, enabling retrieval of move request data directly from on-premises Exchange and O365 tenants, and adding search and filter capabilities... and its popularity continued to grow.

I use MRS Explorer nearly every day and have received countless emails from MCS, PFE, and CSS associates who also find it extremely useful.  The script is currently published to TechNet Gallery and will continue to receive updates as required: <a href="https://gallery.technet.microsoft.com/MRS-Explorer-for-Exchange-b55c0c67">https://gallery.technet.microsoft.com/MRS-Explorer-for-Exchange-b55c0c67</a>

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Migrate Mailbox Permissions to Office 365</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/migrate-mailbox-permissions-to-office-365</link>
      <pubDate>Thu, 11 Jun 2015 16:04:00 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/2015/06/11/migrate-mailbox-permissions-to-office-365/</guid>
      <description><![CDATA[Mailbox permission are typically translated to O365 during properly batched hybrid MRS moves,...]]></description>
      <content:encoded><![CDATA[Mailbox permission are typically translated to O365 during properly batched hybrid MRS moves, however there are still many scenarios where permissions must be audited on-premises and re-applied after migration. One example may be when using 3rd party migration tools.

2/10/2017 - Script has been updated to include new features based on feedback.
Download package and documentation is available from <a href="https://gallery.technet.microsoft.com/scriptcenter/Migrate-Mailbox-Permissions-2f262f8b">Microsoft Script Center.</a>

<strong>Export-MailboxPermissions.ps1</strong> should be run from on-premises Exchange Management Shell (EMS) and will collect mailbox access, send as, send on behalf, and folder delegate permissions into separate CSV datasets. Retrieval of each permission type can be toggled "$true" or "$false" in the script depending on requirements.  Note that retrieving folder delegates can add considerable time to script processing.  Therefore, evaluating only common folders (Inbox, Calendar) is toggled "$true" by default.  Specifying a list of users (rather than running against the entire Org) can also be toggled "$true" or "$false", however PrimarySmtpAddress column must be present in the file. Since mailbox permissions in O365 can only be assigned using mail-enabled objects, script won’t export delegates which are not mail-enabled on-premises (e.g. security groups) and will write warnings to an error log file for review.  If groups are used to assign permissions, the option to expand memberships and apply explicit user access can also be toggled "$true".

<strong>Import-MailboxPermissions.ps1</strong> should be run from O365 remote PowerShell after mailboxes have been provisioned/migrated and will re-apply permissions according to collected on-premises datasets. Import of each export file can be toggled "$true" or "$false" in the script and re-applied separately if needed.

<a href="https://gallery.technet.microsoft.com/scriptcenter/Migrate-Mailbox-Permissions-2f262f8b">Migrate-MailboxPermissions.zip</a>]]></content:encoded>
    </item>
    <item>
      <title>Synchronize Mail-Enabled Public Folders to Distribution Groups in Office 365</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/synchronize-mail-enabled-public-folders-to-distribution-groups-in-office-365</link>
      <pubDate>Thu, 16 Jan 2014 15:03:00 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/2014/01/16/synchronize-mail-enabled-public-folders-to-distribution-groups-in-office-365/</guid>
      <description><![CDATA[In an Office 365 hybrid deployment, DirSync is typically&nbsp;used to ensure the on-premises and...]]></description>
      <content:encoded><![CDATA[<p>In an Office 365 hybrid deployment, DirSync is typically&nbsp;used to ensure the on-premises and online&nbsp;directories remain synchronized.&nbsp; DirSync does not however synchronize mail-enabled public folders, so PowerShell scripts must be run periodically to manually&nbsp;publish&nbsp;them&nbsp;to the O365 address book:<br /><a title="https://technet.microsoft.com/en-us/library/dn249373(v=exchg.150).aspx" href="https://technet.microsoft.com/en-us/library/dn249373(v=exchg.150).aspx">https://technet.microsoft.com/en-us/library/dn249373(v=exchg.150).aspx</a></p>
<p>What also&nbsp;doesn&#39;t synchronize is mail-enabled public folders&nbsp;that are members of distribution groups.&nbsp; DirSync will synchronize the on-premises group object, but the public folder is not&nbsp;included as a group member.&nbsp; Therefore, the on-premise public folder does not receive the message when migrated users send email to the distribution group.&nbsp; The solution is to create a contact which represents the mail-enabled public folder and make it a member of the distribution group so that DirSync can synchronize it.&nbsp; This can&nbsp;be automated using PowerShell.</p>
<p>Let&rsquo;s start by setting a few variables for the data files, the SMTP domain, and the target OU where contacts will be created:</p>
<blockquote>
<p><span style="font-family:Courier New;font-size:small;">$MailFolders = &quot;.\MailFolders.csv&quot;</span></p>
<p><span style="font-family:Courier New;font-size:small;">$MailFolderMembers = &quot;.\MailFolderMembers.csv&quot;</span></p>
<p><span style="font-family:Courier New;font-size:small;">&quot;FolderName,FolderAlias,FolderEmail,GroupName,GroupAlias,GroupEmail&quot; | Out-File $MailFolderMembers</span></p>
<p><span style="font-family:Courier New;font-size:small;"><span style="font-family:Courier New;font-size:small;">$SmtpDomain = &quot;@contoso.com&quot;</span></span></p>
<p><span style="font-family:Courier New;font-size:small;">$TargetOu = &quot;OU=PFContacts,DC=contoso,DC=com&quot;<br /></span></p>
</blockquote>
<p>In addition to Exchange Management Shell,&nbsp;the script will&nbsp;require the Active Directory module:</p>
<blockquote>
<p><span style="font-family:Courier New;font-size:small;">Import-Module ActiveDirectory</span></p>
<p><span style="font-family:Courier New;font-size:small;">If ((Get-Module -Name ActiveDirectory) -eq $null) { Break }<br /></span></p>
</blockquote>
<p>The script will first enumerate all the mail-enabled public folders and export them to a CSV dataset:</p>
<blockquote>
<p><span style="font-family:Courier New;font-size:small;">Get-MailPublicFolder -ResultSize Unlimited | Select Alias, DisplayName, PrimarySmtpAddress | Export-Csv $MailFolders &ndash;NoTypeInformation<br /></span></p>
</blockquote>
<p>Next we will search every distribution group to&nbsp;check if its membership includes a mail-enabled public folder and export the results to another CSV dataset:</p>
<blockquote>
<p><span style="font-family:Courier New;font-size:small;">$DistributionGroups = Get-DistributionGroup -ResultSize Unlimited</span></p>
<p><span style="font-family:Courier New;font-size:small;">ForEach ($Group in $DistributionGroups) {</span></p>
<p><span style="font-family:Courier New;font-size:small;">$GroupName = $Group.Name</span></p>
<p><span style="font-family:Courier New;font-size:small;">$GroupAlias = $Group.Alias</span></p>
<p><span style="font-family:Courier New;font-size:small;">$GroupEmail = $Group.PrimarySmtpAddress</span></p>
<p><span style="font-family:Courier New;font-size:small;">Get-DistributionGroupMember $Group -ResultSize Unlimited | Where { $_.RecipientType -eq &quot;PublicFolder&quot; } | ForEach {</span></p>
<p><span style="font-family:Courier New;font-size:small;">$MemberName = $_.Name</span></p>
<p><span style="font-family:Courier New;font-size:small;">$MemberAlias = $_.Alias</span></p>
<p><span style="font-family:Courier New;font-size:small;">$MemberEmail = $_.PrimarySmtpAddress</span></p>
<p><span style="font-family:Courier New;font-size:small;">&quot;$MemberName,$MemberAlias,$MemberEmail,$GroupName,$GroupAlias,$GroupEmail&quot; | Out-File $MailFolderMembers -Append } }<br /></span></p>
</blockquote>
<p>Then we need to create a hidden contact which represents the mail-enabled public folder.&nbsp; However, the mail attributes we need to use for the contact (alias, email address, etc.) are already assigned to the public folder.&nbsp; Therefore, we need to create the contact using temporary values and forcibly manipulate the AD attributes after creation:</p>
<blockquote>
<p><span style="font-family:Courier New;font-size:small;">Import-Csv $MailFolders | ForEach {</span></p>
<p><span style="font-family:Courier New;font-size:small;">$ContactName = $_.Alias + &quot;-PFContact&quot;</span></p>
<p><span style="font-family:Courier New;font-size:small;">$ContactAlias = $_.Alias + &quot;-PFContact&quot;</span></p>
<p><span style="font-family:Courier New;font-size:small;">$ContactSmtp = $_.Alias + &quot;-PFContact&quot; + $SmtpDomain</span></p>
<p><span style="font-family:Courier New;font-size:small;">New-MailContact -Name $ContactName -Alias $ContactAlias -ExternalEmailAddress $ContactSmtp -PrimarySmtpAddress $ContactSmtp -OrganizationalUnit $TargetOu</span></p>
<p><span style="font-family:Courier New;font-size:small;">Set-MailContact $ContactAlias -HiddenFromAddressListsEnabled $true</span></p>
<p><span style="font-family:Courier New;font-size:small;">$Contact = Get-ADObject -Filter { MailNickname -eq $ContactAlias }</span></p>
<p><span style="font-family:Courier New;font-size:small;">Set-ADObject $Contact -Replace @{TargetAddress=$_.PrimarySmtpAddress}</span></p>
<p><span style="font-family:Courier New;font-size:small;">Set-ADObject $Contact -Replace @{info=$_.DisplayName} }<br /></span></p>
</blockquote>
<p>And finally, we replace the public folder object found&nbsp;in each distribution group with the corresponding contact.&nbsp; Exchange cmdlets don&#39;t seem to work for adding/removing public folders, so we&#39;ll&nbsp;use AD cmdlets instead:</p>
<blockquote>
<p><span style="font-family:Courier New;"><span style="font-size:small;">Import-Csv $MailFolderMembers | ForEach {</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$GroupEmail = $_.GroupEmail</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$FolderEmail = $_.FolderEmail</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$ContactAlias = $_.FolderAlias + &quot;-PFContact&quot;</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$GroupDN = &quot;LDAP://&quot; + (Get-ADObject -LDAPFilter &quot;(mail=$GroupEmail)&quot;).DistinguishedName</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$FolderDN = &quot;LDAP://&quot; + (Get-ADObject -LDAPFilter &quot;(mail=$FolderEmail)&quot;).DistinguishedName</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$ContactDN = &quot;LDAP://&quot; + (Get-ADObject -LDAPFilter &quot;(mailNickname=$ContactAlias)&quot;).DistinguishedName</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$Group = [ADSI]$GroupDN</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$Folder = [ADSI]$FolderDN</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$Contact = [ADSI]$ContactDN</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$Group.Add($Contact.ADsPath)</span></span></p>
<p><span style="font-family:Courier New;"><span style="font-size:small;">$Group.Remove($Folder.ADsPath) }</span><br /></span></p>
</blockquote>
<p>After a couple runs, DirSync will synchronize the new contacts and&nbsp;update the&nbsp;distribution group membership in O365.&nbsp; As always, the script should be tested thoroughly before running against a production environment.&nbsp; Each task can also be split into separate scripts so that the process can be run against a smaller dataset.&nbsp; RjZ</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9242/00/00/03/62/06/27/PFtoDL.zip" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9242-00-00-03-62-06-27/PFtoDL.zip">PFtoDL.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Bulk Migrate Office 365 Licenses</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/bulk-migrate-office-365-licenses</link>
      <pubDate>Wed, 05 Dec 2012 18:31:00 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/2012/12/05/bulk-migrate-office-365-licenses/</guid>
      <description><![CDATA[This is a follow-up post to Bulk Enable Office 365 License Options and reflects an unusually...]]></description>
      <content:encoded><![CDATA[<p>This is a follow-up post to <a title="Bulk Enable Office 365 License Options  " href="https://blogs.technet.com/b/zarkatech/archive/2012/12/05/bulk-enable-office-365-license-option.aspx" target="_blank">Bulk Enable Office 365 License Options</a> and reflects an unusually complex&nbsp;scenario where O365 licenses must be migrated to a different SKU.&nbsp; Here is a real-world example&hellip;</p>
<p>Customer initially purchases E1 licenses and begins to provision and migrate accounts using the included service options (i.e. Exchange, SharePoint, and/or Lync).&nbsp; Customer then realizes they&nbsp;require an expanded feature set and decides to purchases E3 licenses to replace the E1.&nbsp; However, by this time many users already have a live Exchange mailbox under E1.&nbsp; To complicate matters further, some users have now been enabled for SharePoint and/or Lync using the new E3 license while Exchange is still enabled under the original E1.&nbsp; (Yes, this is possible as long as the same service is not enabled in both SKUs.)&nbsp; Wow, what a mess!&nbsp; So, how do we &ldquo;flip&rdquo; all the E1 licenses to E3 without data loss?&nbsp; I&rsquo;m glad you asked :-)</p>
<p>First, a couple key considerations:&nbsp; (1) un-assigning an Exchange license for users which have already been enabled can result in the re-provisioning of an empty mailbox; (2) at no point can the same service be enabled under two different SKUs; (3) if Office Web Apps is to enabled under E3 then SharePoint must also be assigned under E3.&nbsp; Scared yet?&nbsp; Here we go&hellip;</p>
<p>We will definitely need some logging for this:</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">$LogFile = "c:\o365\SwitchLicense.log"; Get-Date | Out-File $LogFile</span></p>
<p>We already know that if the user does not have a mailbox under E1, we will not be enabling the Exchange option under E3.&nbsp; So, let&rsquo;s define that license option:</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">$NoExchange = New-MsolLicenseOptions -AccountSkuId "tenant:ENTERPRISEPACK" -DisabledPlans "EXCHANGE_S_ENTERPRISE"</span></p>
<p>Next, we&rsquo;ll create a data set to run against.&nbsp; As always, I prefer to use a CSV import when making bulk changes.&nbsp; But, the task could be run against all accounts.&nbsp; In either case, keep in mind that some users may have both E1 and E3 assigned.&nbsp; So, we must query for each.&nbsp; If the user is not licensed at all, then we&rsquo;ll make note of that in the log file and move on:</p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">Import-Csv "c:\o365\ImportFile.csv" | ForEach {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">#Get-MsolUser -All | ForEach {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">$Upn = $_.UserPrincipalName; $Licensed = $_.IsLicensed</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">$UserLicense0 = (Get-MsolUser -User $Upn).Licenses[0]</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">$UserLicense1 = (Get-MsolUser -User $Upn).Licenses[1]</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($Licensed -eq $False) { "SKIP: No license currently assigned [$Upn]" | Out-File $LogFile -Append }</span></p>
<p>If the user is currently licensed for <span style="text-decoration: underline;">only</span> E3, then there is nothing to &ldquo;flip&rdquo;.&nbsp; We&rsquo;ll make note of that in the log and continue:</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($UserLicense0.AccountSkuId -eq "tenant:ENTERPRISEPACK" -and $UserLicense1 -eq $null)</span><br /><br /><span style="font-family: courier new,courier;">{ "SKIP: Only E3 license currently assigned [$Upn]" | Out-File $LogFile -Append }</span></p>
<p>If the user is <span style="text-decoration: underline;">only</span> licensed for E1, then we can easily flip to E3.&nbsp; However, we don&rsquo;t necessarily want to enable options under E3 that were not enabled under E1.&nbsp; For now, let&rsquo;s assume all options under E1 are disabled.&nbsp; We will query the assigned E1 license to determine which options are actually enabled and write the result to the log file:</p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($UserLicense0.AccountSkuId -eq "tenant:STANDARDPACK" -and $UserLicense1 -eq $null) {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">$Lync = "Disabled"; SharePoint = "Disabled"; $Exchange = "Disabled"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">(Get-MsolUser -User $Upn).Licenses[0].ServiceStatus | ForEach {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "MCOSTANDARD" -and $_.ProvisioningStatus -ne "Disabled") { $Lync = "Enabled" }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "SHAREPOINTSTANDARD" -and $_.ProvisioningStatus -ne "Disabled") { $SharePoint = "Enabled" }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "EXCHANGE_S_STANDARD" -and $_.ProvisioningStatus -ne "Disabled") { $Exchange = "Enabled" } }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">"SCAN: Only E1 license currently assigned [$Upn] Lync:$Lync, SharePoint:$SharePoint, Exchange:$Exchange" | Out-File $LogFile -Append</span></p>
<p>If the E1 user <span style="text-decoration: underline;">does not</span> have Exchange assigned, we can&nbsp;safely flip to E3 with Exchange disabled.&nbsp; However, if the E1 user <span style="text-decoration: underline;">does</span> have Exchange assigned, then we must transition to E3 by removing the old license and assigning the new license in a single command.&nbsp; In both cases, we will write the results to the log file:</p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($Exchange -eq "Disabled") { Set-MsolUserLicense -User $Upn -RemoveLicenses "tenant:STANDARDPACK" -AddLicenses "tenant:ENTERPRISEPACK" -LicenseOptions $NoExchange }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">Else { Set-MsolUserLicense -User $Upn -RemoveLicenses "tenant:STANDARDPACK" -AddLicenses "tenant:ENTERPRISEPACK" }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">"MOVE: E1 license moved to E3 [$Upn] Office:Enabled, Lync:Enabled, SharePoint:Enabled, WebApps:Enabled, Exchange:$Exchange" | Out-File $LogFile -Append }</span></p>
<p>This is where it gets tricky.&nbsp; If the user has both E1 and E3 assigned, we must determine under which license Exchange is enabled.&nbsp; Once again, we&rsquo;ll assume all options are disabled, query both licenses to identify which options are actually enabled, and write the results to the log file:</p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($UserLicense0.AccountSkuId -eq "tenant:ENTERPRISEPACK" -and $UserLicense1.AccountSkuId -eq "tenant:STANDARDPACK") {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">$Office = "Disabled"; $Lync = "Disabled"; $WebApps = "Disabled"; $SharePoint = "Disabled"; $Exchange0 = "Disabled"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">(Get-MsolUser -User $Upn).Licenses[0].ServiceStatus | ForEach {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "OFFICESUBSCRIPTION" -and $_.ProvisioningStatus -ne "Disabled") { $Office = "Enabled" }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "MCOSTANDARD" -and $_.ProvisioningStatus -ne "Disabled") { $Lync = "Enabled" }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "SHAREPOINTWAC" -and $_.ProvisioningStatus -ne "Disabled") { $WebApps = "Enabled" }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "SHAREPOINTENTERPRISE" -and $_.ProvisioningStatus -ne "Disabled") { $SharePoint = "Enabled" }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "EXCHANGE_S_ENTERPRISE" -and $_.ProvisioningStatus -ne "Disabled") { $Exchange0 = "Enabled" } }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">"SCAN: E3 license currently split [$Upn] Office:$Office, Lync:$Lync, WebApps:$WebApps, SharePoint:$SharePoint, Exchange:$Exchange0" | Out-File $LogFile -Append&nbsp;&nbsp;&nbsp;</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">$Lync = "Disabled"; $SharePoint = "Disabled"; $Exchange1 = "Disabled"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">(Get-MsolUser -User $Upn).Licenses[1].ServiceStatus | ForEach {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "MCOSTANDARD" -and $_.ProvisioningStatus -ne "Disabled") { $Lync = "Enabled" }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "SHAREPOINTSTANDARD" -and $_.ProvisioningStatus -ne "Disabled") { $SharePoint = "Enabled" }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($_.ServicePlan.ServiceName -eq "EXCHANGE_S_STANDARD" -and $_.ProvisioningStatus -ne "Disabled") { $Exchange1 = "Enabled" } }</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">"SCAN: E1 license currently split [$Upn] Lync:$Lync, SharePoint:$SharePoint, Exchange:$Exchange1" | Out-File $LogFile &ndash;Append</span></p>
<p>We&rsquo;re getting close.&nbsp; If Exchange is enabled under E3 in a &ldquo;split license&rdquo; scenario, we can safely remove E1 and enable any previously assigned options under E3.&nbsp; Remember, Exchange is already enabled under E3:</p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($Exchange0 -eq "Enabled" -and $Exchange1 -eq "Disabled") {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">$Exchange = "Enabled"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">Set-MsolUserLicense -User $Upn -RemoveLicenses "tenant:STANDARDPACK"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">Set-MsolUserLicense -User $Upn -AddLicenses "tenant:ENTERPRISEPACK" }</span></p>
<p>However, if Exchange is enabled under E1 we must first remove E3 and then flip the entire E1 license (Exchange included) in a single command:</p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($Exchange0 -eq "Disabled" -and $Exchange1 -eq "Enabled") {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">$Exchange = "Enabled"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">Set-MsolUserLicense -User $Upn -RemoveLicenses "tenant:ENTERPRISEPACK"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">Set-MsolUserLicense -User $Upn -RemoveLicenses "tenant:STANDARDPACK" -AddLicenses "tenant:ENTERPRISEPACK }</span></p>
<p>The last possible scenario would be that Exchange is not enabled under either license.&nbsp; So, we will simply remove both licenses and reassign E3 without Exchange:</p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">If ($Exchange0 -eq "Disabled" -and $Exchange1 -eq "Disabled") {</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">$Exchange = "Disabled"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">Set-MsolUserLicense -User $Upn -RemoveLicenses "tenant:ENTERPRISEPACK"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">Set-MsolUserLicense -User $Upn -RemoveLicenses "tenant:STANDARDPACK"</span></p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">Set-MsolUserLicense -UserPrincipalName $Upn -AddLicenses "tenant:ENTERPRISEPACK" -LicenseOptions $NoExchange }</span></p>
<p>Of course, we will write the results of all this license manipulation to the log file:</p>
<p class="Command" style="padding-left: 30px;"><span style="font-family: courier new,courier;">"JOIN: E1 license merged into E3 [$Upn] Office:Enabled, Lync:Enabled, SharePoint:Enabled, WebApps:Enabled, Exchange:$Exchange" | Out-File $LogFile &ndash;Append } }</span></p>
<p>Problem solved!&nbsp; This scenario reflects an incredibly complex scenario that I hope you won&rsquo;t encounter.&nbsp; But, if you find yourself facing similar circumstance, I trust some of these concepts will prove useful.&nbsp; It obviously goes without saying that you <span style="text-decoration: underline;">must</span> thoroughly test this solution on sample accounts or a test tenant before running it against your production environment.&nbsp; RjZ</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9242/00/00/03/53/90/74/BulkMigrateLicenses.zip" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9242-00-00-03-53-90-74/BulkMigrateLicenses.zip">BulkMigrateLicenses.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Bulk Enable Office 365 License Options</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/bulk-enable-office-365-license-options</link>
      <pubDate>Wed, 05 Dec 2012 10:30:00 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/2012/12/05/bulk-enable-office-365-license-options/</guid>
      <description><![CDATA[There are a number of online PowerShell resources which describe how to bulk assign an O365 license...]]></description>
      <content:encoded><![CDATA[<p>There are a number of online PowerShell resources which describe how to bulk assign an O365 license while enabling only certain service options.&nbsp; In general, you would&nbsp;define the <span style="font-family:courier new,courier;">&ndash;DisabledPlans</span> parameter&nbsp;using <span style="font-family:courier new,courier;">New-MsolLicenseOptions</span> and assign the license using <span style="font-family:courier new,courier;">New-MsolUserLicense</span>.&nbsp; However, how do you&nbsp;go back and bulk enable a specific service option after the license has been assigned?</p>
<p>Let&rsquo;s consider the following scenario&hellip; you have just completed a mail migration to O365 and all accounts were successfully licensed with only the Exchange option enabled.&nbsp; Team Sites are now ready and you need to&nbsp;assign the SharePoint and Office Web Apps service for all users.&nbsp; One option would be to simply&nbsp;enable all the remaining services in the license:</p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">$Options = New-MsolLicenseOptions &ndash;AccountSkuId &quot;tenant:ENTERPRISEPACK&quot;</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">Set-MsolUserLicense &ndash;UserPrincipalName [UPN] &ndash;LicenseOptions $Options</span></p>
<p>Notice the absence of <span style="font-family:courier new,courier;">&ndash;AddLicenses</span> parameter from the <span style="font-family:courier new,courier;">Set-MsolUserLicense</span> cmdlet.&nbsp; Trying to add a license that is already assigned results in an error.&nbsp; Therefore, we simply enable all the other service options contained within the license.&nbsp; Another&nbsp;method might be to remove the currently assigned license and re-apply it using the desired service options.&nbsp; However, there is risk associated with removing a license.&nbsp; The existing Exchange mailbox&nbsp;could become orphaned and an empty one re-provisioned.&nbsp; Also, any related O365 service data associated with the user account&nbsp;might&nbsp;be lost.</p>
<p>Now, let&rsquo;s consider a similar but slightly more complicated scenario. User accounts&nbsp;each have an&nbsp;inconsistent mix of service options enabled; some have SharePoint enabled, some have Lync enabled, and not all have Exchange.&nbsp; How do you assign the Office subscription (for example)&nbsp;to all accounts?&nbsp; You can&rsquo;t blindly enable all remaining options, as this would provide access to services which may not be desired.&nbsp; Removing the license and re-applying it also proves difficult.&nbsp;The solution is to query&nbsp;each user accounts to determine which service options are currently active or inactive, add the service you would like to enable, and assign the results.&nbsp; (NOTE: This is written&nbsp;for E3 license, but easily adapted for other SKUs.)</p>
<p>First, we&#39;ll create a data set to run against.&nbsp; I typically prefer using a CSV import file when making bulk changes, but the task could also be run against all licensed accounts:</p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">Import-Csv c:\o365\AssignOption.csv | ForEach {</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">#Get-MsolUser &ndash;All | Where { $_.IsLicensed &ndash;eq $true } | ForEach {</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">$Upn = $_.UserPrincipalName</span></p>
<p>Let&rsquo;s initially assume all service options for the user are currently disabled:</p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">$Exchange = &quot;Disabled&quot;; $SharePoint = &quot;Disabled&quot;; $Lync = &quot;Disabled&quot;; $Office = &quot;Disabled&quot;; $WebApps = &quot;Disabled&quot;</span></p>
<p>We retrieve the assigned license and make note of which options are actually enabled for the user:</p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">(Get-MsolUser -User $Upn).Licenses[0].ServiceStatus | ForEach {</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">If ($_.ServicePlan.ServiceName -eq &quot;EXCHANGE_S_ENTERPRISE&quot; &ndash;and $_.ProvisioningStatus -ne &quot;Disabled&quot; { $Exchange = &quot;Enabled&quot; }</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">If ($_.ServicePlan.ServiceName -eq &quot;SHAREPOINTENTERPRISE&quot; &ndash;and $_.ProvisioningStatus -ne &quot;Disabled&quot;) { $SharePoint = &quot;Enabled&quot; }</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">If ($_.ServicePlan.ServiceName -eq &quot;MCOSTANDARD&quot; &ndash;and $_.ProvisioningStatus -ne &quot;Disabled&quot;) { $Lync = &quot;Enabled&quot; }</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">If ($_.ServicePlan.ServiceName -eq &quot;OFFICESUBSCRIPTION&quot; &ndash;and $_.ProvisioningStatus &ndash;ne &quot;Disabled&quot;) { $Office = &quot;Enabled&quot; }</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">If ($_.ServicePlan.ServiceName -eq &quot;SHAREPOINTWAC&quot; -and $_.ProvisioningStatus -ne &quot;Disabled&quot;) { $WebApps = &quot;Enabled&quot; } }</span></p>
<p>Next, we create an array and populate the variable with the results from the license audit.&nbsp; In this example, Office is <span style="text-decoration:underline;">not</span> added as a disabled option since we will be enabling this service for all users:</p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">$DisabledOptions = @()</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">If ($Exchange -eq &quot;Disabled&quot;) { $DisabledOptions += &quot;EXCHANGE_S_ENTERPRISE&quot; }</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">If ($SharePoint -eq &quot;Disabled&quot;) { $DisabledOptions += &quot;SHAREPOINTENTERPRISE&quot; }</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">If ($Lync -eq &quot;Disabled&quot;) { $DisabledOptions += &quot;MCOSTANDARD&quot; }</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">#If ($Office -eq &quot;Disabled&quot;) { $DisabledOptions += &quot;OFFICESUBSCRIPTION&quot; }</span></p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">If ($WebApps -eq &quot;Disabled&quot;) { $DisabledOptions += &quot;SHAREPOINTWAC&quot; }</span></p>
<p>Now we can create the license option variable which assigns all services except those that were not already enabled:</p>
<p class="Command" style="padding-left:30px;"><span style="font-family:courier new,courier;">$LicenseOptions = New-MsolLicenseOptions &ndash;AccountSkuId &quot;tenant:ENTERPRISEPACK&quot; &ndash;DisabledPlans $DisabledOptions</span></p>
<p>And finally, we apply the license to the user account:</p>
<p class="Command">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family:courier new,courier;">Set-MsolUserLicense &ndash;User $Upn &ndash;LicenseOptions $LicenseOptions</span></p>
<p>These same concepts can be used in a number of different scenarios&nbsp;for which only certain O365 license options must be bulk enabled.&nbsp; For a more complex scenario and some advanced license reconciliation concepts,&nbsp;please&nbsp;refer to&nbsp;<a title="Bulk Migrate Office 365 Licenses" href="/b/zarkatech/archive/2012/12/05/bulk-migrate-office-365-licenses.aspx" target="_blank">Bulk Migrate Office 365 Licenses</a>.&nbsp; RjZ</p>
<p><b>UPDATE</b>:&nbsp; I received&nbsp;feedback that this script may not work properly when more than one license or stand-alone SKU is&nbsp;assigned.&nbsp; Therefore, I have revised it to detect and evaluate the E3 license <span>only</span>, even if other SKUs are assigned.&nbsp; This is easily changed in the script to look for other SKUs too.&nbsp; I have also included logic for Yammer.</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9242/00/00/03/53/89/85/Enable-LicenseOptions.zip" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9242-00-00-03-53-89-85/Enable_2D00_LicenseOptions.zip">Enable-LicenseOptions.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Automatically Provision New Office 365 Mailboxes</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/automatically-provision-new-office-365-mailboxes</link>
      <pubDate>Thu, 18 Oct 2012 08:23:00 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/2012/10/18/automatically-provision-new-office-365-mailboxes/</guid>
      <description><![CDATA[Transitioning from an on-premise messaging solution to Exchange Online is often only half the...]]></description>
      <content:encoded><![CDATA[<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF"><span id="ms-rterangecursor-start"></span><span id="ms-rterangepaste-start"></span>Transitioning from an on-premise messaging solution to Exchange Online is often only half the battle.&nbsp; A long-term administration strategy is just as important as a sound migration plan.&nbsp; Many organizations use identity management software to on-board new employees, and any reputable product can easily create AD accounts and assign the necessary attributes to mail-enable the object.&nbsp; However, even after DirSync picks up the new object and creates it in O365, assigning the appropriate license and provisioning the Exchange Online mailbox is still a manual process.&nbsp; So, I set out to automate mailbox provisioning using export files generated by IDM solutions.</p>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">To begin, I created a file share on the Exchange 2010 CAS where IDM can write its export files.&nbsp; Now, each time new users are created in AD, the data is written to CSV files on the IDM share.&nbsp; The contents of&nbsp;the&nbsp;export file include CN (Name), UserPrincipalName (Upn), and EmployeeType.&nbsp; The employee type (or a similar identifier) will be used to determine which O365 license gets assigned.</p>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">Now, let's begin developing the script.&nbsp; First, we need to connect to O365.&nbsp; The script will be running as a scheduled task, so, I need to include the O365 credentials without prompts.&nbsp; I describe the steps for creating a secure password file in a <a href="https://blogs.technet.com/b/zarkatech/archive/2011/08/09/automatically-disable-pop3-amp-imap-in-office-365.aspx" target="_blank">previous post</a>:</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$Username = "admin@domain.onmicrosoft.com"</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$Password = Get-Content c:\o365\remoteps.pwd | ConvertTo-SecureString</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$Credential = New-Object System.Management.Automation.PSCredential($Username,$Password)</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell" -Credential $Credential -Authentication Basic -AllowRedirection</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$ImportResults = Import-PSSession $Session</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">Import-Module MSOnline</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">Connect-MSOLService -Credential $Credential</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">I'll set a timestamp that can be used to identify each&nbsp;processing run:</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$TimeStamp = Get-Date -Format "yyMMddhhmmss"</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">Next, well read all the CSV export files created by the identity management solution and write the aggregated results into a temporary file:</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">Get-ChildItem -Path c:\IDM\*.csv | ForEach { Import-Csv $_ } | Export-Csv -NoTypeInformation "c:\IDM\$TimeStamp.tmp"</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">Once all the CSV export files are processed, we'll move the original files to a Processed folder along with any old log files:</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">Move-Item "c:\IDM\*.csv" "c:\IDM\Processed"</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">Move-Item "c:\IDM\*.log" "c:\IDM\Processed"</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">And then we'll create a new export file and log file to save our provisioning results:</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$ExportFile = "c:\IDM\$TimeStamp.csv"</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">"CN,EmployeeType,UserPrincipalName" | Out-File $ExportFile</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$LogFile = "c:\IDM\$TimeStamp.log"</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">Now, let's do some work!&nbsp; We will import the temporary CSV file that contains the aggregated data from each of the IDM export files and set some variables:</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">Import-Csv "c:\IDM\$TimeStamp.tmp" | ForEach {</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$Name = $_.CN; $Type = $_.EmployeeType</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$Upn = $_.UserPrincipalName</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$CheckMailbox = $null; $CheckMailUser = $null</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">For each user, we will run Get-Mailbox to check if a mailbox already exists in O365.&nbsp; If a mailbox cannot be found, the cmdlet will error out and the $CheckMailbox variable will remain null.</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">$CheckMailbox = Get-Mailbox $Upn</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">If there is no mailbox already provisioned for the user, we run Get-MsolUser to check if the account has been mail-enabled and synchronized to O365.&nbsp; Once again, if the account has not been successfully mail-enabled, then the cmdlet will error out and the $CheckMailUser variable will remain null.</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">If ($CheckMailbox -eq $null) {</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp; $CheckMailUser = Get-MsolUser -User $Upn</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">If the new account has been successfully mail-enabled, then we'll set the usage location and assign an O365 license.&nbsp; In this example, I am using the EmployeeType column from the IDM export files to determine whether the user gets an Exchange Standard license or a Kiosk license.&nbsp; We'll also write the results to a log file:</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">If ($CheckMailUser -ne $null) {</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp;&nbsp; Set-MsolUser -User $Upn -UsageLocation US</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp;&nbsp; If ($Type -eq "E") {</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp;&nbsp;&nbsp;&nbsp; Set-MsolUserLicense -User $Upn -AddLicenses "tenant:EXCHANGESTANDARD"</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp;&nbsp;&nbsp;&nbsp; "SUCCESS: New user account provisioned with Plan1 mailbox [$Upn]" |<br />&nbsp;&nbsp;&nbsp;&nbsp; Out-File $LogFile -Append }</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp;&nbsp; If ($Type -eq "N") {</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp;&nbsp;&nbsp;&nbsp; Set-MsolUserLicense -User $Upn -AddLicenses "tenant:EXCHANGEDESKLESS"</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp;&nbsp;&nbsp;&nbsp; "SUCCESS: New account provisioned with Kiosk mailbox [$Upn]" |<br />&nbsp;&nbsp;&nbsp;&nbsp; Out-File&nbsp;$LogFile -Append }</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">After assigning the license, we will run Test-MapiConnectivity which seems to help initialize newly created mailboxes:</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp; Test-MapiConnectivity $Upn }</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">Finally, we'll write data to the log file if the account was not mail-enabled.&nbsp; It's possible, however,&nbsp;that DirSync has not yet run for the newly created account.&nbsp; So, instead of discarding the user, I will write the data to a new CSV file so that it can be processed again.</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp; Else {</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp;&nbsp;&nbsp; "ERROR: New account not synchronized to O365 [$Upn]" | Out-File<br />&nbsp;&nbsp;&nbsp;&nbsp;$LogFile -Append</span></p>
<p><span class="ms-rteFontFace-10 ms-rteFontSize-1" style="font-family: terminal,monaco;">&nbsp;&nbsp;&nbsp; "$Name,$Type,$Upn" | Out-File $ExportFile -Append } }</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">I will also write to the log if an O365 mailbox already existed for the user.</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">Else { "ERROR: O365 mailbox already exists for new user account [$Upn]" |<br />Out-File $LogFile -Append } }</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">As a bonus, we can email the log file to a user (or group of users) for review:</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$SmtpServer = "smtp.domain.com"</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$Smtp = New-Object Net.Mail.SmtpClient($SmtpServer)</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$SmtpFile = New-Object Net.Mail.Attachment($LogFile)</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$SmtpMsg = New-Object Net.Mail.MailMessage</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$SmtpMsg.From = "admin@domain.com"</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$SmtpMsg.To.Add("user@domain.com")</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$SmtpMsg.Subject = "New Mailbox Provisioning"</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$SmtpMsg.Body = "Attached is the latest O365 mailbox provisioning log."</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$SmtpMsg.Attachments.Add($SmtpFile)</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$Smtp.Timeout = "30000"</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$Smtp.Send($SmtpMsg)</span></p>
</blockquote>
<p>And as a best practice, we will gracefully disconnect our remote PowerShell session.&nbsp; I am also deleting our temporary file and "releasing" the log file.</p>
<blockquote class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF" style="margin-right: 0px;" dir="ltr">
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">Remove-PSSession -Session $Session</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">Remove-Item "c:\IDM\$TimeStamp.tmp"</span></p>
<p><span class="ms-rteFontSize-1 ms-rteFontFace-10" style="font-family: terminal,monaco;">$SmtpFile.Dispose()</span></p>
</blockquote>
<p class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF">Now, the script&nbsp;can&nbsp;be run periodically as a scheduled task.&nbsp; Here is a summary of what it actually does...</p>
<div class="ExternalClass9A6864964BC74CBDB2464B53E29FC4BF"><ol>
<li>Establish remote PowerShell session to MSO</li>
<li>Read all CSV files on IDM share and aggregate data into single temp CSV</li>
<li>Move all processed CSV file(s) to Processed directory on IDM share</li>
<li>Read consolidated data from temp CSV and check if mailbox may already exist</li>
<li>If mailbox does not exist, check if accounts have been mail-enabled and synchronized to O365</li>
<li>If accounts have been mail-enabled, assign Plan1 or Kiosk license according to EmployeeType and provision mailbox</li>
<li>Write any failed or skipped users to new CSV file on IDM share</li>
<li>Write log file and email to administrator for review</li>
<li>Delete temp CSV file</li>
</ol></div>
<p>On subsequent runs, the script will read any new CSV files IDM has exported to the share, <span style="text-decoration: underline;">plus</span> the CSV created for any failed or skipped users... and the whole process repeats.&nbsp; RjZ</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9242/00/00/03/52/73/85/AutoProvisionMailbox.zip" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9242-00-00-03-52-73-85/AutoProvisionMailbox.zip">AutoProvisionMailbox.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Audit File Server Permissions Using PowerShell</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/audit-file-server-permissions-using-powershell</link>
      <pubDate>Sat, 14 Jan 2012 14:48:00 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/2012/01/14/audit-file-server-permissions-using-powershell/</guid>
      <description><![CDATA[A customer recently asked me to help refine a VBScript which they use to enumerate permissions on...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: small;" size="2">A customer recently asked me to help refine a VBScript which they use to enumerate permissions on all their file servers.&nbsp; The team periodically queries the entire file system and imports the results into a database for historical auditing.&nbsp; Their existing VBScript did provide the required information using nested loops to walk the file system and WMI calls to &ldquo;Win32_LogicalFileSecuritySettings&rdquo; to enumerate permissions.&nbsp; However, the script took up to 3 days to run on large volumes, and server resources fluctuated greatly depending on folder depth and often crashed.&nbsp; </span></p>
<p><span style="font-size: small;" size="2">My first instinct was to parse through the 1,600 lines of their current script and look for ways to streamline and improve it.&nbsp; However, I instead decided to re-write the script from scratch using PowerShell&hellip;</span></p>
<p><span style="font-size: small;" size="2">First, let&rsquo;s define a few variables.&nbsp; I set &ldquo;ErrorActionPreference&rdquo; so that the script would continue if it encountered any exit errors:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">$ErrorActionPreference = "Continue"</span></span></p>
<p><span style="font-size: small;" size="2">I also define the local computer name so that we can include it in the results:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">$strComputer = $env:ComputerName</span></span></p>
<p><span style="font-size: small;" size="2">Next, I enumerate all the drive letters and store them in a collection variable:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">$colDrives = Get-PSDrive -PSProvider Filesystem</span></span></p>
<p><span style="font-size: small;" size="2">Now, let&rsquo;s begin doing some work.&nbsp; For each drive letter I need to output the permissions of every file and folder on the volume.&nbsp; The easiest way to walk the file system is to specify the starting root directory and use &ldquo;Get-ChildItem&rdquo; with the &ldquo;Recurse&rdquo; parameter.&nbsp; I also use the &ldquo;LiteralPath&rdquo; parameter in case file or folder names include special characters, such as square brackets or ampersands:</span></p>
<p><span style="font-size: small;"><span size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">ForEach ($DriveLetter in $colDrives) {</span></span><span style="font-family: Consolas;" face="Consolas" size="2"> <br />&nbsp;&nbsp;&nbsp; $StartPath = "$DriveLetter`:\" <br />&nbsp;&nbsp;&nbsp; Get-ChildItem -LiteralPath $StartPath &ndash;Recurse }</span></span></p>
<p><span style="font-size: small;" size="2">Next, we can use &ldquo;Get-Acl&rdquo; and expand the &ldquo;Access&rdquo; column to return all the data related to the ACE:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">Get-Acl | Select * -Expand Access</span></span></p>
<p><span style="font-size: small;" size="2">But, wait&hellip; I&rsquo;ve discovered a problem!&nbsp; Get-Acl crashes if I try to enumerate permissions on a file or folder which contains special characters.&nbsp; Unfortunately, Get-Acl does not support the LiteralPath parameter, which is a well-documented shortcoming.&nbsp; So, we will need to &ldquo;escape&rdquo; any special characters in the path name.</span></p>
<p><span style="font-size: small;" size="2">I found several examples of various subroutines and functions which parse the path name and escapes special characters.&nbsp; But, I couldn&rsquo;t help thinking these methods simply added overhead to the script.&nbsp; Therefore, I changed my approach and instead used Get-Item (which does support the LiteralPath parameter) and the GetAccessControl method which returns the same information as Get-Acl:</span></p>
<p><span style="font-size: small;"><span size="2">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Consolas;" face="Consolas" size="2">ForEach { <br />&nbsp;&nbsp;&nbsp; $FullPath = Get-Item -LiteralPath (Get-Item -LiteralPath $_.PSPath) <br />&nbsp;&nbsp;&nbsp; (Get-Item -LiteralPath $FullPath).GetAccessControl() }</span></span></p>
<p><span style="font-size: small;" size="2">Now, with all our data exposed, we can begin to select the columns and transform them into the required export format.&nbsp; My customer had specific guidelines for how the data should be labeled and formatted.&nbsp; But, this can obviously be changed to suit other requirements.</span></p>
<p><span style="font-size: small;" size="2">In the first column, we&rsquo;ll write the server name:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">Select @{N='Server Name';E={$strComputer}}</span></span></p>
<p><span style="font-size: small;" size="2">Then we&rsquo;ll write the full path of the file or folder:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">@{N='Full Path';E={$FullPath}}</span></span></p>
<p><span style="font-size: small;" size="2">If the object is a directory, write &ldquo;D&rdquo;.&nbsp; Otherwise, write &ldquo;F&rdquo;:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">@{N='Type';E={If($FullPath.PSIsContainer -eq $True) {'D'} Else {'F'}}}</span></span></p>
<p><span style="font-size: small;" size="2">Write the owner:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">@{N='Owner';E={$_.Owner}}</span></span></p>
<p><span style="font-size: small;" size="2">Write each of the accounts associated with the ACE:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">@{N='Trustee';E={$_.IdentityReference}}</span></span></p>
<p><span style="font-size: small;" size="2">For each ACE, write whether the permissions are inherited:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">@{N='Inherited';E={$_.IsInherited}}</span></span></p>
<p><span style="font-size: small;" size="2">Write the inheritance flags:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">@{N='Inheritance Flags';E={$_.InheritanceFlags}}</span></span></p>
<p><span style="font-size: small;" size="2">Write the propagation flags:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">@{N='Ace Flags';E={$_.PropagationFlags}}</span></span></p>
<p><span style="font-size: small;" size="2">Write the access control type:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">@{N='Ace Type';E={$_.AccessControlType}}</span></span></p>
<p><span style="font-size: small;" size="2">Write the permissions:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">@{N='Access Masks';E={$_.FileSystemRights}}</span></span></p>
<p><span style="font-size: small;" size="2">And finally, we&rsquo;ll stream the results into an export file whose name includes the server and drive letter.&nbsp; My customer also asked that each column be separated by &ldquo;|&rdquo; as a delimiter:</span></p>
<p><span style="font-size: small;" size="2">&nbsp;&nbsp;&nbsp; <span style="font-family: Consolas;" face="Consolas">Export-CSV -NoTypeInformation -Delimiter "|" -Path "$strComputer`_$DriveLetter.csv"</span></span></p>
<p><span style="font-size: small;" size="2">That's it.&nbsp; The resulting script is very fast and very efficient.&nbsp; What used to take 3 days now runs in just over 1 hour and utilizes minimal resources.&nbsp; The only drawback is that the script depends on expanded capabilities of PowerShell v2 which had to be installed on some of the servers.&nbsp; RjZ</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9242/00/00/03/47/72/73/AuditFilePermissions.zip" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9242-00-00-03-47-72-73/AuditFilePermissions.zip">AuditFilePermissions.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Customize Role-Based Access Control in Office 365</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/customize-role-based-access-control-in-office-365</link>
      <pubDate>Thu, 03 Nov 2011 14:45:00 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/2011/11/03/customize-role-based-access-control-in-office-365/</guid>
      <description><![CDATA[Office 365 includes several default RBAC roles which allow end-users to access ECP and manage...]]></description>
      <content:encoded><![CDATA[<div class="ExternalClassCDD2698C0A2E429294108FD3A4E095F5">   <p><font size="2">Office 365 includes several default RBAC roles which allow end-users to access ECP and manage their own account properties or advanced mailbox features.&#160; A summary of the built-in roles can be found at </font><a title="https://help.outlook.com/en-us/140/Dd207272.aspx" href="https://help.outlook.com/en-us/140/Dd207272.aspx"><font size="2">https://help.outlook.com/en-us/140/Dd207272.aspx</font></a><font size="2">.&#160; An O365 administrator can also enable and disable certain roles to control what properties and/or features a user can manage.&#160; There are several roles, however, that may not provide the desired functionality in Office 365.&#160; For example, allowing a federated user to modify their own contact information results in an error since that information is synchronized from on-premise.&#160; Similarly, a customer may not want users managing their own distribution groups, or may have policies which forbid connected mailboxes.&#160; In these cases, the default user role assignment policy can be customized to remove many of the RBAC roles.</font></p>    <ol>     <li><font size="2">Logon to O365 and administrator </font></li>      <li><font size="2">On the Admin Overview page, click Manage under Exchange Online </font></li>      <li><font size="2">From ECP, select Roles &amp; Auditing </font></li>      <li><font size="2">Select Default Role Assignment Policy and click Details </font></li>      <li><font size="2">From the list of RBAC roles, uncheck the options/features that are not required and click Save. </font></li>   </ol>    <p><font size="2">In my customer’s case, we unchecked all options except MyBaseOptions.&#160; This allowed a user to view their contact information, but not make any changes.&#160; In addition, it removed most of the other advanced settings and self-service features.&#160; However, we discovered it does not remove the user’s ability to forward incoming email to alternate address.&#160; My customer had a strict policy related to automatic email forwarding, so this feature also had to be removed and controlled as a separate management role. We accomplished this by customizing the RBAC roles in O365 using a remote PowerShell session.</font></p>    <ol>     <li><font size="2">Export MyBaseOptions management role entries for reference:          <br /><font face="Consolas">Get-ManagementRoleEntry MyBaseOptions\* | ConvertTo-Html &gt; C:\MyBaseOptions.htm</font></font> </li>      <li><font size="2">Copy the existing MyBaseOptions management role as new MyMailForwarding Role:          <br /><font face="Consolas">New-ManagementRole –Parent MyBaseOptions –Name MyMailForwarding</font> </font></li>      <li><font size="2">Copy the existing MyBaseOptions management role as a new MyMailbox role:          <br /><font face="Consolas">New-ManagementRole –Parent MyBaseOptions –Name MyMailbox</font> </font></li>      <li><font size="2">Remove all Set-Mailbox parameters (which include mail forwarding permissions) from the new MyMailbox role:          <br /><font face="Consolas">Remove-ManagementRoleEntry MyMailbox\Set-Mailbox</font> </font></li>      <li><font size="2">Add Set-Mailbox parameters back to MyMailbox role except those associated with mail forwarding:          <br /><font face="Consolas">Add-ManagementRoleEntry MyMailbox\Set-Mailbox –Parameters AcceptMessagesOnlyFrom, AcceptMessagesOnlyFromDLMembers, AcceptMessagesOnlyFromSendersOrMembers, ErrorAction, ErrorVariable, ExternalOofOptions, GrantSendOnBehalfTo, Identity, Languages, MailTip, MailTipTranslations, OutBuffer, OutVariable, Password, RejectMessagesFrom, RejectMessagesFromDLMembers, RejectMessagesFromSendersOrMembers, RequireSenderAuthenticationEnabled, UserCertificate, UserSMimeCertificate, WarningAction, WarningVariable</font> </font></li>   </ol>    <p><font size="2">Now we modify the Default Role Assignment Policy so that includes only the new MyMailbox role which we’ve customized.&#160; It includes all the same settings as MyBaseOption, minus the mail forwarding feature.</font></p>    <ol>     <li><font size="2">Logon to ECP as administrator account </font></li>      <li><font size="2">Click Roles &amp; Auditing along the left </font></li>      <li><font size="2">Click User Roles along the top </font></li>      <li><font size="2">Select “Default Role Assignment Policy” and click Details </font></li>      <li><font size="2">Uncheck all management roles except MyMailbox and click Save </font></li>   </ol>    <blockquote>     <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/92/42/metablogapi/0172.Capture_thumb_1_57A3C484_04F93055.jpg" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-92-42-metablogapi/0172.Capture_5F00_thumb_5F00_1_5F00_57A3C484_5F00_04F93055.jpg"><font size="2"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture_thumb_1_57A3C484" border="0" alt="Capture_thumb_1_57A3C484" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/92/42/metablogapi/0677.Capture_thumb_1_57A3C484_thumb_563377B2.jpg" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-92-42-metablogapi/0677.Capture_5F00_thumb_5F00_1_5F00_57A3C484_5F00_thumb_5F00_563377B2.jpg" width="240" height="118" /></font></a></p>   </blockquote>    <p><font size="2">With the customizations complete and the new policy defined, all O365 users now have only the bare minimum of features approved by the customer.&#160; However, we all agreed that there may be exceptions where mail forwarding must be enabled for select accounts.&#160; Therefore, we created an new role assignment policy which could selectively be applied to specific mailboxes.</font></p>    <ol>     <li><font size="2">Logon to ECP as administrator account </font></li>      <li><font size="2">Click Roles &amp; Auditing along the left </font></li>      <li><font size="2">Click User Roles along the top </font></li>      <li><font size="2">Under Role Assignment Policies, click New </font></li>      <li><font size="2">Name the new policy Enable Mail Forwarding and provide a description </font></li>      <li><font size="2">Select only MyBaseOptions role which now contains both MyMailbox and MyMailForwarding </font></li>      <li><font size="2">Click Save </font></li>   </ol>    <blockquote>     <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/92/42/metablogapi/7522.Capture2_thumb_57A3C484_55C744BD.jpg" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-92-42-metablogapi/7522.Capture2_5F00_thumb_5F00_57A3C484_5F00_55C744BD.jpg"><font size="2"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture2_thumb_57A3C484" border="0" alt="Capture2_thumb_57A3C484" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/92/42/metablogapi/4073.Capture2_thumb_57A3C484_thumb_03486481.jpg" original-url="https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-92-42-metablogapi/4073.Capture2_5F00_thumb_5F00_57A3C484_5F00_thumb_5F00_03486481.jpg" width="240" height="117" /></font></a></p>   </blockquote>    <p><font size="2">To allow mail forwarding for specific users, the new Enable Mail Forwarding policy can be applied to their mailbox.</font></p>    <ol>     <li><font size="2">Logon to ECP as administrator account </font></li>      <li><font size="2">Click Users &amp; Groups along the left </font></li>      <li><font size="2">Click Mailboxes along the top </font></li>      <li><font size="2">Locate and select a specific user and click Details </font></li>      <li><font size="2">Expand Mailbox Settings </font></li>      <li><font size="2">Change the role assignment policy to Enable Mail Forwarding </font></li>      <li><font size="2">Click Save </font></li>   </ol>    <p><font size="2">These instructions reflect a real-world scenario in which RBAC roles in O365 had to be customized.&#160; They outline the steps to explicitly manage email forwarding, but can be applied to any situation where individual features must be enabled or disabled.&#160; RjZ</font></p> </div>  <p><font size="2"></font></p>  <p><font size="2"></font></p>  <p><font size="2"></font></p>]]></content:encoded>
    </item>
    <item>
      <title>Automatically Disable POP3 &amp; IMAP in Office 365</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/automatically-disable-pop3-imap-in-office-365</link>
      <pubDate>Tue, 09 Aug 2011 17:30:00 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/2011/08/09/automatically-disable-pop3-imap-in-office-365/</guid>
      <description><![CDATA[?Office 365 automatically enables IMAP for Kiosk (Deskless) accounts, and both POP3 and IMAP for...]]></description>
      <content:encoded><![CDATA[<p>?Office 365 automatically enables IMAP for Kiosk (Deskless) accounts, and both POP3 and IMAP for Enterprise accounts.&nbsp; Mailbox protocols can be disabled using EMC connected to the O365 remote forest or through a remote PowerShell session.&nbsp; However, this is a manual process that requires an administrator to configure each mailbox after it has been provisioned.&nbsp; For on-premise Exchange, I&rsquo;ve often used a scheduled task which automatically disables POP3 and/or IMAP protocols based on group membership.&nbsp; So, I set out to duplicate this functionality for O365&hellip;</p>
<p>The script will first need to connect to O365:</p>
<blockquote>
<p><span style="font-family: Consolas;" face="Consolas">$Credential = Get-Credential</span></p>
<p><span style="font-family: Consolas;" face="Consolas">$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell" -Credential $Credential -Authentication Basic &ndash;AllowRedirection</span></p>
<p><span><span style="font-family: Consolas;" face="Consolas">$ImportResults = Import-PSSession $Session</span></span></p>
</blockquote>
<p>The groups which contain the users that should be enabled for POP3 and/or IMAP need to be identified.&nbsp; A remote PowerShell session includes the <span class="ms-rteFontFace-2">Get-Group </span>cmdlet.&nbsp; But, this only seems to return mail-enabled groups and distribution lists.&nbsp; In my case, the POP3 and IMAP groups are security groups synchronized to O365.&nbsp; Therefore, I had to download and install the Microsoft Online Services Module for PowerShell which gave me access to <span class="ms-rteFontFace-2">Get-MSOLGroup </span>cmdlet to query security groups.&nbsp; In order to utilize the MSOL cmdlets, I must now import and connect the module from within the script:</p>
<blockquote>
<p><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">Import-Module MSOnline</span></span></p>
<p><span class="ms-rteFontFace-2"></span><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">Connect-MSOLService -Credential $Credential</span></span></p>
</blockquote>
<p><span class="ms-rteFontFace-2"></span>With the MSOL module loaded, I can now query the O365 security groups (in my case &ldquo;POP3-Users&rdquo; and &ldquo;IMAP-Users&rdquo;) whose members should be enabled for POP3 and/or IMAP access:</p>
<blockquote>
<p><span class="ms-rteFontFace-2">$PopGroup = Get-MSOLGroup -All | Where-Object {$_.DisplayName -eq "POP3-Users"}</span></p>
<p><span class="ms-rteFontFace-2"></span><span class="ms-rteFontFace-2">$ImapGroup = Get-MSOLGroup -All | Where-Object {$_.DisplayName -eq "IMAP-Users"}</span></p>
</blockquote>
<p><span class="ms-rteFontFace-2"></span>And from the groups, we can identify the individual members:</p>
<blockquote>
<p><span class="ms-rteFontFace-2">$EnablePOP = Get-MSOLGroupMember -GroupObjectId $PopGroup.ObjectId -All | Select-Object -ExpandProperty DisplayName</span></p>
<p><span class="ms-rteFontFace-2"></span><span class="ms-rteFontFace-2">$EnableImap = Get-MSOLGroupMember -GroupObjectId $ImapGroup.ObjectId -All | Select-Object -ExpandProperty DisplayName</span></p>
</blockquote>
<p><span class="ms-rteFontFace-2"></span>Finally, we will collect all the mailboxes currently provisioned in O365:</p>
<blockquote>
<p><span class="ms-rteFontFace-2">$Mailboxes = Get-Mailbox -ResultSize Unlimited</span></p>
</blockquote>
<p><span class="ms-rteFontFace-2"></span>With all the variables defined, we will now increment through each of the mailboxes and determine if the account is a member of the POP3 or IMAP group.&nbsp; If we find a match in either group, then the appropriate mailbox protocol(s) will be enabled.&nbsp; Otherwise, both POP3 and IMAP will be disabled:</p>
<blockquote>
<p><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">ForEach ($Mailbox in $Mailboxes) {</span></span><span class="ms-rteFontFace-2"> <br /></span><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">&nbsp; If ($EnablePop -Contains $Mailbox) { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">$Mailbox | Set-CASMailbox -PopEnabled $True } <br />&nbsp; </span></span><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">Else { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">$Mailbox | Set-CASMailbox -PopEnabled $False } <br />&nbsp; </span></span><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">If ($EnableImap -Contains $Mailbox) { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">$Mailbox | Set-CASMailbox -ImapEnabled $True } <br />&nbsp; </span></span><span style="font-family: Consolas;" face="Consolas"><span class="ms-rteFontFace-2">Else { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span class="ms-rteFontFace-2">$Mailbox | Set-CASMailbox -ImapEnabled $False }}</span></span></p>
</blockquote>
<p>&nbsp;&nbsp;&nbsp; As a best practice, we will disconnect from the remote session when the script is complete:</p>
<blockquote>
<p><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">Remove-PSSession $Session</span></span></p>
</blockquote>
<p><span class="ms-rteFontFace-2"></span>The functionality of the script is now complete and should work great by running it manually and entering O365 admin credentials when prompted.&nbsp; However, I want the script to run automatically as a daily scheduled task without having to enter credentials.&nbsp; Therefore, I must securely store my password so that I can call it into the script.&nbsp; The following commands are not part of the final script and should be typed in a local PowerShell session while logged on to the computer as the user account which will run the scheduled task.&nbsp; Only the account that creates the password file can decrypt the password file.&nbsp; In my case, I&rsquo;m logged on to the machine as Administrator and that will be the account used to run the scheduled task:</p>
<blockquote>
<p><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">$Credential = Get-Credential</span></span></p>
</blockquote>
<blockquote>
<p><span class="ms-rteFontFace-2"></span><span class="ms-rteFontFace-2"><span style="font-family: Consolas;" face="Consolas">$Credential.Password | ConvertFrom-SecureString | Set-Content "c:\o365\remoteps.pwd"</span></span></p>
</blockquote>
<p><span class="ms-rteFontFace-2"></span>I&rsquo;ll modify the script to retrieve the stored password instead of prompting for credentials:</p>
<blockquote>
<p><span style="text-decoration: line-through;"><span style="font-family: Consolas;" face="Consolas">$Credential = Get-Credential</span></span></p>
</blockquote>
<blockquote>
<p><span style="text-decoration: line-through;"></span><span style="font-family: Consolas;" face="Consolas"><span>$Username = "</span><span>o365admin@domain.onmicrosoft.com</span><span>"</span></span></p>
</blockquote>
<blockquote>
<p><span><span style="font-family: Consolas;" face="Consolas">$Password = Get-Content c:\o365\remoteps.pwd | ConvertTo-SecureString</span></span></p>
</blockquote>
<blockquote>
<p><span><span style="font-family: Consolas;" face="Consolas">$Credential = New-Object System.Management.Automation.PSCredential($Username,$Password)</span></span></p>
</blockquote>
<p><span class="ms-rteFontFace-2"></span>We should now be able to run the script manually with no authentication prompts.&nbsp; So, let's create a new scheduled task:</p>
<ol>
<li>From Administrative Tools, run Task Scheduler and select Create Task.</li>
<li>On the General tab, type a friendly name and description for the task.</li>
<li>Click Change User or Group button and specify the account under which the secure O365 password was created.</li>
<li>Select &ldquo;Run whether user is logged on or not&rdquo; and enable &ldquo;Run with highest privileges&rdquo;.</li>
<li>On the Triggers tab, click New and define a schedule for when the task will run.</li>
<li>On the Actions tab, click New and type &ldquo;powershell.exe&rdquo; as the Program/Script name and add the following arguments:&nbsp; -file &ldquo;c:\o365\ScriptName.ps1&rdquo;</li>
<li>Save Scheduled Task</li>
</ol>
<p>I have the script scheduled to run from the on-premise Exchange 2010 coexistence server.&nbsp; However, it can be scheduled to run from any computer on which PowerShell and the MSOL module can be installed.&nbsp; RjZ</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/9242/00/00/03/47/72/94/DisablePopImap.zip" original-url="https://blogs.technet.com/cfs-filesystemfile.ashx/__key/telligent-evolution-components-attachments/01-9242-00-00-03-47-72-94/DisablePopImap.zip">DisablePopImap.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Delegation of Active Directory Recycle Bin</title>
      <link>https://docs.microsoft.com/archive/blogs/zarkatech/delegation-of-active-directory-recycle-bin</link>
      <pubDate>Tue, 14 Jun 2011 16:49:00 GMT</pubDate>
      <dc:creator><![CDATA[Roman Zarka]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/zarkatech/2011/06/14/delegation-of-active-directory-recycle-bin/</guid>
      <description><![CDATA[While working on an AD 2008 R2 upgrade project, I was asked by my customer whether Active Directory...]]></description>
      <content:encoded><![CDATA[<p><a name="_GoBack"></a><font size="2">While working on an AD 2008 R2 upgrade project, I was asked by my customer whether Active Directory Recycle Bin could be delegated. They already had a delegated OU administration model for managing accounts, and wanted it to also include the recovery of deleted objects. I did some research and found a vague reference that AD RB could be delegated, but no specific information on how to actually do it. In fact, the general consensus was that Domain Admin was the minimum permissions required to restore deleted objects and that AD RB delegation wasn't possible. So, I decided to experiment in my lab and discovered a relatively simple way to delegate the recovery of deleted objects...     <br /></font></p>  <ul>   <li><font size="2">Logon as Domain Admin and take ownership of Deleted Objects container:        <br />dsacls “CN=Deleted Objects,DC=domain,DC=com” /takeownership         <br /></font></li>    <li><font size="2">Grant delegated user/group permissions (List, Read, Write) to view and restore deleted objects:       <br />dsacls “CN=Deleted Objects,DC=domain,dc=com” /g domain\accountname:LCRPWP         <br /></font></li>    <li><font size="2">Using ADUC, grant user/group rights to reanimate tombstone: </font></li>    <ul>     <li><font size="2">Right-click domain root and select Properties</font></li>      <li><font size="2">On the Security tab, click Advanced</font></li>      <li><font size="2">Click Add and select user/group account </font></li>      <li><font size="2">Allow the Reanimate Tombstones permission and click OK </font></li>   </ul> </ul>  <p><font size="2">A couple of additional notes worth mentioning…      <br />Delegated permissions only seem to apply to objects deleted after configuration; objects deleted before configuration must be restored by Domain Admin. Also, delegated administrators must have permissions on the source/target OU where deleted objects will be restored. In my customer's case, they already had a well-defined OU administration model. So, while all delegated administrators could view AD RB, they could only restore objects deleted from their own OU. Perfect! RjZ</font></p>]]></content:encoded>
    </item>
  </channel>
</rss>