FastTrack-ScheduleManagement.psm1
Add-Type -AssemblyName System.Web -ErrorAction SilentlyContinue Function Get-ResponseError { <# .SYNOPSIS Get-ResponseError converts HtmlWebResponse error to HtmlWebResponseObject for output .DESCRIPTION Get-ResponseError inputs HtmlWebResponse error and converts to HtmlWebResponseObject for output .PARAMETER Response is the error response returned from webrequest .EXAMPLE Get-ResponseError $_.Exception.Response .INPUTS System.Net.HttpWebResponse .OUTPUTS HtmlWebResponseObject .LINK #> param([System.Net.HttpWebResponse]$Response) $streamReader = New-Object System.IO.StreamReader($Response.GetResponseStream()) $streamReader.BaseStream.Position = 0 $streamReader.DiscardBufferedData() $body = ConvertFrom-Json($streamReader.ReadToEnd()) if([string]::IsNullOrEmpty($body)) { $body = ConvertFrom-Json("{}") } Add-Member -InputObject $body -MemberType NoteProperty -Name "StatusCode" -Value $_.Exception.Response.StatusCode $body } Function Invoke-GetRequest { <# .SYNOPSIS Call Rest API with input variables to retrieve appropriate response .DESCRIPTION The Invoke-GetRequest cmdlet utilizes the header parameter to perform the REST API call to modify a FastTrack migration. The REST API is defined in the URI parameter and returns the API's webresponse. .PARAMETER Uri as the endpoint HTML address for the REST API Headers is a collection of header keys and values required by the API to return results .EXAMPLE $JsonResult = Invoke-GetRequest -Uri ([System.String]::Format("{0}/{1}/DSR/Status/TransactionId/{2}?{3}", $global:CsiApiBaseUriFormat, $TenantId, $TransactionId, $query)) -Headers $header .INPUTS System.String System.Collections.Hashtable .OUTPUTS HtmlWebResponseObject .LINK #> param([String]$Uri, [hashtable]$Headers) $response = try { Invoke-RestMethod -Method GET -Uri $Uri -ContentType 'application/json' -Headers $Headers } catch { Get-ResponseError $_.Exception.Response } return $response } Function Invoke-PostRequest { <# .SYNOPSIS Call Rest API with input variables to retrieve appropriate response .DESCRIPTION The Invoke-PostRequest cmdlet utilizes the body and header parameters to perform the REST API call to modify a FastTrack migration. The REST API is defined in the URI parameter and returns the API's webresponse. .PARAMETER Uri as the endpoint HTML address for the REST API Headers is a collection of header keys and values required by the API to return results Body is the collected form data required by the API to return results .EXAMPLE .INPUTS System.String System.Collections.Hashtable .OUTPUTS HtmlWebResponseObject .LINK #> param([String]$Uri, [hashtable]$Headers, [String]$Body) $response = try { Invoke-RestMethod -Method POST -Uri $Uri -ContentType 'application/json;charset=utf-8' -Headers $Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) } catch { Get-ResponseError $_.Exception.Response } return $response } Function Invoke-PutRequest { <# .SYNOPSIS Call Rest API with input variables to retrieve appropriate response .DESCRIPTION The Invoke-PutRequest cmdlet utilizes the body and header parameters to perform the REST API call to modify a FastTrack migration. The REST API is defined in the URI parameter and returns the API's webresponse. .PARAMETER Uri as the endpoint HTML address for the REST API Headers is a collection of header keys and values required by the API to return results Body is the collected form data required by the API to return results .EXAMPLE .INPUTS System.String System.Collections.Hashtable .OUTPUTS HtmlWebResponseObject .LINK #> param([String]$Uri, [hashtable]$Headers, [String]$Body) $response = try { Invoke-RestMethod -Method PUT -Uri $Uri -ContentType 'application/json' -Headers $Headers -Body $Body } catch { Get-ResponseError $_.Exception.Response } return $response } Function Invoke-DeleteRequest { <# .SYNOPSIS Deletes Transaction .DESCRIPTION The Invoke-DeleteRequest cmdlet utilizes the body and header parameters to perform the REST API call to delete a FastTrack migration. The REST API is defined in the URI parameter and returns the API's webresponse. .PARAMETER Uri as the endpoint HTML address for the REST API Headers is a collection of header keys and values required by the API to return results Body is the collected form data required by the API to return results .EXAMPLE $JsonResult = Invoke-DeleteRequest -Uri ([System.String]::Format("{0}KeyVault",$global:CsiApiBaseUriFormat)) -Headers $header -Body $serializedJson .INPUTS System.String System.Collections.Hashtable .OUTPUTS HtmlWebResponseObject .LINK #> param([String]$Uri, [hashtable]$Headers, [String]$Body) $response = try { Invoke-RestMethod -Method DELETE -Uri $Uri -ContentType 'application/json' -Headers $Headers -Body $Body } catch { Get-ResponseError $_.Exception.Response } return $response } Function Waiting-TransactionComplete() { <# .SYNOPSIS Find status of Transaction .DESCRIPTION The Waiting-TransactionComplete cmdlet calls Get-FastTrackMigrationStatus repetatively while migration is not complete or not failed. When the transaction has completed or failed, Waiting-TransactionComplete returns the transaction object to caller. In order to use this cmdlet, you must first login using the Login-FastTrackMigrationAccount cmdlet. .PARAMETER TransactionId is the GUID representing the specified transaction .EXAMPLE Waiting-TransactionComplete -TransactionID ($JsonResult.TransactionId) .INPUTS System.String .OUTPUTS System.Management.Automation.PSObject This cmdlet generates System.Management.Automation.PSObject object that represents transaction ID. .LINK #> param([string] $TransactionID = $(throw "Transaction ID unable to find, Please try again.")) [array]$FinalResults = "Completed","Failed" $current = $previous = 1; do { $Transaction = Get-FastTrackMigrationTransactionStatus -TransactionID $TransactionID for ($j = 1; (!$FinalResults.Contains($Transaction.Status) -and $j -le $current); $j++) { sleep -Milliseconds 1000 Write-Progress -Id 1 -Activity Waiting -Status 'Next attempt will start ' -PercentComplete ($j/$current*100) -SecondsRemaining ($current-$j) } $current,$previous = ($current + $previous),$current } while ($current -lt 60 -and !$FinalResults.Contains($Transaction.Status)) return $Transaction } Function SetIdentityRecipientValues { <# .SYNOPSIS Set recipient identity .DESCRIPTION The SetIdentityRecipientValues cmdlet, intended for Global Administrators, to create an identity-object from input parameters. This new identity is returned to caller. In order to use this cmdlet, you must first login using the Login-FastTrackMigrationAccount cmdlet. .EXAMPLE $CustomerIdentity = SetIdentityRecipientValues .INPUTS None .OUTPUTS PSObject Identity .LINK #> [string] $TenantID = $global:MsoAdminProperties['MSO-CompanyTenantInfo'] [string] $CompanyName = $global:MsoAdminProperties["MSO-CompanyInfo"].DisplayName [string] $LogonUserEmail = $global:MsoAdminProperties["MSO-LoggedOnUser"].Account $Identity = (New-Object PSObject | Add-Member -PassThru NoteProperty TenantId $TenantID | Add-Member -PassThru NoteProperty CompanyName $CompanyName | Add-Member -PassThru NoteProperty LogonUserEmail $LogonUserEmail) return $Identity } Function SetCreateRequestValues { <# .SYNOPSIS Set recipient request .DESCRIPTION The SetCreateRequestValues cmdlet, intended for Global Administrators, to create a customer-object from input parameters that are used to define details to be used in REST API calls to create a FastTrack migration schedule. In order to use this cmdlet, you must first login using the Login-FastTrackMigrationAccount cmdlet. .PARAMETER Tenant ID for customer request .PARAMETER Company name for customer request .PARAMETER User email used for customer login .PARAMETER MigrationType Type of migration. Mig-ExHybrid Exchange to Exchange hybrid migration Mig-ExSimpleMRS Exchange to Exchange hybrid migration Mig-ExStaged Staged Migration Mig-ExCutover Cutover Migration Mig-Box Box drive to OneDrive migration Mig-FileSharesToOneDrive FileShare to OneDrive migration Mig-FileSharesToTeamSites FileShare to TeamSite migration Mig-Domino-BAM Notes user documents into BAM (Binary Tree Application Manager) migration Mig-Domino-ODME Notes user documents into ODME migration Mig-GoogleDrive Google drive to OneDrive migration Mig-GmailCutover Gmail Cutover Migration Mig-GmailStaged Gmail staged Migration Mig-IMAP IMAP Migration Mig-GroupWise GroupWise Migration Mig-GoogleSites GoogleSites Migration MIG-SPOnPrem SP On Prem Migration .PARAMETER Source Source for different migration types. .PARAMETER Target Target for different migration types. .PARAMETER MigrationDate Date of migration. .PARAMETER MigrationWindow Migration event window. .PARAMETER MigrationGroup Migration group. .PARAMETER Size Size of source storage. .PARAMETER IsCutover Is cutover true | false | null. .PARAMETER Region Name of region. .PARAMETER PropertyBag .EXAMPLE $jsonObj = SetCreateRequestValues -RecipientId $RecipientId -FirstName $FirstName -LastName $LastName -EmailAddress $EmailAddress -Description $Description .INPUTS System.String .OUTPUTS PSObject CustomerObject .LINK #> param ( [string] $TenantID, [string] $CompanyName, [string] $LogonUserEmail, [string] $MigrationType, [string] $Source, [string] $Target, [string] $MigrationDate, [string] $MigrationWindow, [string] $MigrationGroup, [string] $Size, [string] $PropertyBag, [string] $IsCutover, [string] $Region ) $CustomerIdentity = (New-Object PSObject | Add-Member -PassThru NoteProperty TenantId $TenantID | Add-Member -PassThru NoteProperty CompanyName $CompanyName | Add-Member -PassThru NoteProperty LogOnUserEmail $LogonUserEmail) $CustomerObject = (New-Object PSObject | Add-Member -PassThru NoteProperty Customer $CustomerIdentity | Add-Member -PassThru NoteProperty MigrationType $MigrationType | Add-Member -PassThru NoteProperty Source $Source | Add-Member -PassThru NoteProperty Target $Target | Add-Member -PassThru NoteProperty MigrationDate $MigrationDate | Add-Member -PassThru NoteProperty MigrationWindow $MigrationWindow | Add-Member -PassThru NoteProperty MigrationGroup $MigrationGroup | Add-Member -PassThru NoteProperty Size $Size | Add-Member -PassThru NoteProperty IsCutover $IsCutover | Add-Member -PassThru NoteProperty Region $Region | Add-Member -PassThru NoteProperty PropertyBag $PropertyBag | Add-Member -PassThru NoteProperty TransactionId "00000000-0000-0000-0000-000000000000" | Add-Member -PassThru NoteProperty ScheduleIdentifier "00000000-0000-0000-0000-000000000000" | Add-Member -PassThru NoteProperty EnvironmentType $global:MsoComOrGov ) return $CustomerObject } Function SetUpdateRequestValues { <# .SYNOPSIS Update recipient request .DESCRIPTION The SetUpdateRequestValues cmdlet, intended for Global Administrators, to create a customer-object from input parameters that are used to define details to be used in REST API calls to update migration update details. In order to use this cmdlet, you must first login using the Login-FastTrackMigrationAccount cmdlet. .PARAMETER Tenant ID for customer request .PARAMETER Company name for customer request .PARAMETER User email used for customer login .PARAMETER MigrationType Type of migration. Mig-ExHybrid Exchange to Exchange hybrid migration Mig-ExSimpleMRS Exchange to Exchange hybrid migration Mig-ExStaged Staged Migration Mig-ExCutover Cutover Migration Mig-Box Box drive to OneDrive migration Mig-FileSharesToOneDrive FileShare to OneDrive migration Mig-FileSharesToTeamSites FileShare to TeamSite migration Mig-Domino-BAM Notes user documents into BAM (Binary Tree Application Manager) migration Mig-Domino-ODME Notes user documents into ODME migration Mig-GoogleDrive Google drive to OneDrive migration Mig-GmailCutover Gmail Cutover Migration Mig-GmailStaged Gmail staged Migration Mig-IMAP IMAP Migration Mig-GroupWise GroupWise Migration Mig-GoogleSites GoogleSites Migration MIG-SPOnPrem SP On Prem Migration .PARAMETER Source Source for different migration types. .PARAMETER Target Target for different migration types. .PARAMETER MigrationDate Date of migration. .PARAMETER MigrationWindow Migration event window. .PARAMETER MigrationGroup Migration group. .PARAMETER Size Size of source storage. .PARAMETER IsCutover Is cutover true | false | null. .PARAMETER Region Name of region. .PARAMETER PropertyBag .EXAMPLE $jsonObj = SetUpdateRequestValues -RecipientId $RecipientId -FirstName $FirstName -LastName $LastName -EmailAddress $EmailAddress -Description $Description .INPUTS System.String .OUTPUTS PSObject CustomerObject .LINK #> param ( [string] $TenantID, [string] $CompanyName, [string] $LogonUserEmail, [string] $MigrationType, [string] $Source, [string] $Target, [string] $MigrationDate, [string] $MigrationWindow, [string] $MigrationGroup, [string] $Size, [string] $PropertyBag, [string] $IsCutover, [string] $Region ) $CustomerIdentity = (New-Object PSObject | Add-Member -PassThru NoteProperty TenantId $TenantID | Add-Member -PassThru NoteProperty CompanyName $CompanyName | Add-Member -PassThru NoteProperty LogOnUserEmail $LogonUserEmail) $CustomerObject = (New-Object PSObject | Add-Member -PassThru NoteProperty Customer $CustomerIdentity | Add-Member -PassThru NoteProperty TransactionId "00000000-0000-0000-0000-000000000000" | Add-Member -PassThru NoteProperty MigrationType $MigrationType | Add-Member -PassThru NoteProperty Source $Source | Add-Member -PassThru NoteProperty Target $Target | Add-Member -PassThru NoteProperty MigrationDate $MigrationDate | Add-Member -PassThru NoteProperty MigrationWindow $MigrationWindow | Add-Member -PassThru NoteProperty MigrationGroup $MigrationGroup | Add-Member -PassThru NoteProperty Size $Size | Add-Member -PassThru NoteProperty IsCutover $IsCutover | Add-Member -PassThru NoteProperty Region $Region | Add-Member -PassThru NoteProperty PropertyBag $PropertyBag | Add-Member -PassThru NoteProperty EnvironmentType $global:MsoComOrGov ) return $CustomerObject } Function GetObjectFromSchedule { <# .SYNOPSIS Get Schedule .DESCRIPTION The GetObjectFromSchedule cmdlet is intended to convert the input Schedule parameter into a powershell custom schedule-object. The created custom object is returned to caller. .PARAMETER Schedule as input object from HtmlWebResponseObject .EXAMPLE $result += GetObjectFromSchedule -Schedule $sch .INPUTS HtmlWebResponseObject .OUTPUTS PSObject .LINK #> param ($Schedule) $newObject = New-Object -Typename PSCustomObject -Property @{ MigrationType = $Schedule.MigrationType Source = $Schedule.Source Target = $Schedule.Target MigrationDate = $Schedule.MigrationDate MigrationWindow = $Schedule.MigrationWindow MigrationGroup = $Schedule.MigrationGroup Region = $Schedule.Region Size = $Schedule.Size ScheduleUserId = $Schedule.ScheduleUserId ScheduleStatus = $Schedule.ScheduleStatus } if($Schedule.PropertyBag -ne $null) { $prop = ConvertFrom-Json $Schedule.PropertyBag $prop.PSObject.Properties | ForEach-Object { if($myObject.PSobject.Properties.Name -contains "Name" -or $myObject.PSobject.Properties.Name -contains "Value") { $newObject | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value } } } return $newObject } Function SetPropertyBag { <# .SYNOPSIS The SetPropertyBag cmdlet uses the MigrationType parameter and appropriate input values, dependent on the type of migration defined. The, newly defined, property bag is converted into a json-object and returned to the caller. .DESCRIPTION This cmdlet to create a new PropertyBag. In order to use this cmdlet, you must first login using the Login-FastTrackAcount cmdlet. .PARAMETER MigrationType Type of migration. Mig-ExHybrid Exchange to Exchange hybrid migration Mig-ExSimpleMRS Exchange to Exchange hybrid migration Mig-ExCutover Cutover Migration Mig-ExStaged Staged Migration Mig-IMAP IMAP Migration Mig-GmailCutover Gmail Cutover Migration Mig-GmailStaged Gmail staged Migration Mig-GroupWise GroupWise Migration Mig-GoogleDrive Google drive to OneDrive migration Mig-GoogleSites GoogleSites Migration Mig-Box Box drive to OneDrive migration Mig-FileSharesToOneDrive FileShare to OneDrive migration Mig-FileSharesToTeamSites FileShare to TeamSite migration Mig-Domino-BAM Notes user documents into BAM (Binary Tree Application Manager) migration Mig-Domino-ODME Notes user documents into ODME migration MIG-SPOnPrem Sharepoint Migration .EXAMPLE $PropertyBag = SetPropertyBag -MigrationType $MigrationType .INPUTS System.String .OUTPUTS PSObject PropertyBag .LINK #> param ( [string] $MigrationType ) if ($MigrationType -eq "Mig-ExHybrid" -or $MigrationType -eq "Mig-ExSimpleMRS" -or $MigrationType -eq "Mig-ExCutover" -or $MigrationType -eq "Mig-ExStaged") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty MigrationEndpoint $MigrationEndpoint.Value) } elseif ($MigrationType -eq "Mig-FileSharesToOneDrive") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty Office365UPNAccount $Office365UPNAccount.Value | Add-Member -PassThru NoteProperty TargetDocumentLibrary $TargetDocumentLibrary.Value | Add-Member -PassThru NoteProperty FileCount $FileCount.Value) } elseif ($MigrationType -eq "Mig-FileSharesToTeamSites") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty TargetSharePointSite $TargetSharePointSite.Value | Add-Member -PassThru NoteProperty TargetDocumentLibrary $TargetDocumentLibrary.Value | Add-Member -PassThru NoteProperty FileCount $FileCount.Value) } elseif ($MigrationType -eq "Mig-Domino-BAM") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty O365UsageLocation $O365UsageLocation.Value | Add-Member -PassThru NoteProperty O365DisplayName $O365DisplayName.Value | Add-Member -PassThru NoteProperty LicenseSubscriptionID $LicenseSubscriptionID.Value | Add-Member -PassThru NoteProperty InPlaceHoldIdentity $InPlaceHoldIdentity.Value | Add-Member -PassThru NoteProperty HasBlackBerry $HasBlackBerry.Value | Add-Member -PassThru NoteProperty VIP $VIP.Value | Add-Member -PassThru NoteProperty DominoBESServer $DominoBESServer.Value | Add-Member -PassThru NoteProperty SecondPassEmailAddress $SecondPassEmailAddress.Value) } elseif ($MigrationType -eq "Mig-Box" -or $MigrationType -eq "Mig-GoogleDrive") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty FilesOwned $FilesOwned.Value) } elseif ($MigrationType -eq "Mig-Domino-ODME") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty O365UsageLocation $O365UsageLocation.Value | Add-Member -PassThru NoteProperty O365DisplayName $O365DisplayName.Value | Add-Member -PassThru NoteProperty LotusNotesName $LotusNotesName.Value | Add-Member -PassThru NoteProperty Location $Location.Value | Add-Member -PassThru NoteProperty Resource $Resource.Value ) } elseif ($MigrationType -eq "Mig-IMAP") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty Password $Password.Value) } elseif ($MigrationType -eq "Mig-GroupWise") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty PoHostingTheMailbox $PoHostingTheMailbox.Value | Add-Member -PassThru NoteProperty SoapPort $SoapPort.Value) } elseif ($MigrationType -eq "Mig-GoogleSites") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty Hold $Hold.Value) } elseif ($MigrationType -eq "MIG-SPOnPrem") { $PropertyBagObj = (New-Object PSObject | Add-Member -PassThru NoteProperty Hold $Hold.Value) } else { } return ($PropertyBagObj | ConvertTo-Json -Compress: $true) } Function Get-CsvAsJson { <# .SYNOPSIS Read CSV file contents .DESCRIPTION The Get-CsvAsJson cmdlet reads an input CSV file contents, converting the individual elements of data into a json-compatible object which is returned to the caller. .PARAMETER File path to csv file for input .EXAMPLE $FileContentStr = Get-CsvAsJson -FilePath $FilePath .INPUTS System.String .OUTPUTS Json object .LINK #> param ( [string] $FilePath ) [string] $targetBaseUrl = "" $readData = Get-Content $FilePath -Encoding UTF8 | ForEach-Object { #csv is FileShareManager [string] $line = $_.ToString().ToLower() $lineNumber++ if($targetBaseUrl -eq "") { [int] $index = $line.IndexOf("https://") if($index -gt 0) { $indexOfComma = $line.IndexOf(',', $index) if($indexOfComma -le 0){ $indexOfComma = line.Length; } $targetBaseUrl = $line.Substring($index, $indexOfComma - $index).TrimEnd('/'); $targetBaseUrl += "/"; } } else { if($line -match '^([,"]+|[\s]*$)') { if(!$endLine) { $endLine = $lineNumber } } } } if($targetBaseUrl -ne "") #If csv is FileShareManager { $FileContent = Get-Content $FilePath -Encoding UTF8 | select -Skip 1 -First ($endLine-2) | Out-String | ConvertFrom-Csv foreach ($obj in $FileContent) { $obj."Target SharePoint Site" = $targetBaseUrl + $obj."Target SharePoint Site" } } else { $FileContent = Get-Content $FilePath -Encoding UTF8 | Out-String | ConvertFrom-Csv } if($FileContent -isnot [Array]) { #csv contails single row $FileContentStr = $FileContent | ConvertTo-Json -Compress: $true $FileContentStr = "[" + $FileContentStr + "]" } else { $FileContentStr = $FileContent | ConvertTo-Json -Compress: $true } return $FileContentStr } Function Get-FastTrackMigrationSchedule { <# .SYNOPSIS Get FastTrack schedule list. .DESCRIPTION The Get-FastTrackMigrationSchedule cmdlet invokes the REST API to retrieve the FastTrack migration schedule for the input ScheduleUserId parameter. Retrieved scheduled migrations are input to an array of schedules adn returned to the caller. In order to use this cmdlet, you must first login using the Login-FastTrackAcount cmdlet. .PARAMETER ScheduleUserId Unique Guid for FastTrack schedule. .EXAMPLE Get-FastTrackMigrationSchedule -ScheduleUserId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" .INPUTS System.String .OUTPUTS System.Management.Automation.PSObject This cmdlet generates a System.Management.Automation.PSObject object that represents the list of FastTrack schedule details. .LINK New-FastTrackMigrationSchedule Set-FastTrackMigrationSchedule Remove-FastTrackMigrationSchedule New-FastTrackMigrationScheduleFromCsv Get-FastTrackMigrationDeleteTypes #> param ( [Parameter(Mandatory=$false,ValueFromPipeline=$true)] [alias("ScheduleId")] [string] $ScheduleUserId ) try { if($global:MsoAdminProperties.Count -eq 0) { Write-Warning "Unable to retrieve Office 365 credentials! :: Please call [Login-FastTrackAccount] function." return } [string] $TenantId = $global:MsoAdminProperties["MSO-CompanyTenantInfo"] $header = @{} if($global:v2FeatureFlag -eq $true){ $header.Add("Authorization", $global:MsoAdminProperties["AuthorizationResult"].CreateAuthorizationHeader())} else{ $header.Add("ACCESS_TOKEN",$global:MsftAccessToken)} $header.Add("TENANT_ID",$TenantId) Write-Host "Sending Schedule Get Request..." $query += "environmentType=$global:MsoComOrGov" if (!$ScheduleUserId) { $requestUri = [System.String]::Format("{0}{1}/Schedule?$($query)", $global:CsiApiBaseUriFormat, $TenantId) } else { try { $isError = [GUID]::Parse($ScheduleUserId) } catch { Write-Warning "ScheduleUserId is not a valid GUID format. To obtain the ScheduleUserId , please run 'Get-FastTrackMigrationSchedule' to retrieve a list of all schedules." return } $requestUri = [System.String]::Format("{0}{1}/Schedule/{2}?$($query)", $global:CsiApiBaseUriFormat, $TenantId, $ScheduleUserId) } $JsonResult = Invoke-GetRequest -Uri ([System.String]::Format($requestUri, $TenantId, $ScheduleUserId)) -Headers $header if($JsonResult.StatusCode -ne $null) { # Error? Write-Warning "Request failed! : $($JsonResult.StatusCode) - Error Message: $($JsonResult)" } else { Write-Host "Get request completed" if ($JsonResult.Schedules) { $result = @() foreach($sch in $JsonResult.Schedules) { $result += GetObjectFromSchedule -Schedule $sch } return $result } } return (GetObjectFromSchedule -Schedule $JsonResult) } catch { Write-Warning -Message:"An error occurred attempting to authenticate with this module" Write-Warning -Message: $_.Exception.Message Write-Host "Press the [enter] key to close this process" Read-Host } } Function New-FastTrackMigrationSchedule { <# .SYNOPSIS Creates a new FastTrack schedule. .DESCRIPTION The New-FastTrackMigrationSchedule cmdlet invokes the REST API to create a new FastTrack migration schedule. The Waiting-TransactionComplete cmdlet is invoked to return the "completed" or "failed" status of the migration transaction invoked. In order to use this cmdlet, you must first login using the Login-FastTrackAcount cmdlet. .PARAMETER MigrationType Type of migration. Mig-ExHybrid Exchange to Exchange hybrid migration Mig-ExSimpleMRS Exchange to Exchange hybrid migration Mig-ExCutover Cutover Migration Mig-ExStaged Staged Migration Mig-IMAP IMAP Migration Mig-GmailCutover Gmail Cutover Migration Mig-GmailStaged Gmail staged Migration Mig-GroupWise GroupWise Migration Mig-GoogleDrive Google drive to OneDrive migration Mig-GoogleSites GoogleSites Migration Mig-Box Box drive to OneDrive migration Mig-FileSharesToOneDrive FileShare to OneDrive migration Mig-FileSharesToTeamSites FileShare to TeamSite migration Mig-Domino-BAM Notes user documents into BAM (Binary Tree Application Manager) migration Mig-Domino-ODME Notes user documents into ODME migration MIG-SPOnPrem Sharepoint Migration .PARAMETER Source Source for different migration types. .PARAMETER Target Target for different migration types. .PARAMETER MigrationDate Date of migration. .PARAMETER MigrationWindow Migration event window. .PARAMETER MigrationGroup Migration group. .PARAMETER Size Size of source storage. .PARAMETER IsCutover Is cutover true | false | null. .PARAMETER Region Name of region. .EXAMPLE New-FastTrackMigrationSchedule -MigrationType "Mig-Box" -Source "joe@contoso.com" -Target "Jane@contoso.net" -MigrationDate "YYYY-DD-MMTHH:MIN:SS" -MigrationWindow "Window1" -MigrationGroup "Group1" -Size 2 -PropertyBag "FilesOwned" .INPUTS System.String .OUTPUTS System.Management.Automation.PSObject This cmdlet generates a System.Management.Automation.PSObject object that represents the Transaction ID . .LINK Get-FastTrackMigrationSchedule Remove-FastTrackMigrationSchedule Set-FastTrackMigrationSchedule New-FastTrackMigrationScheduleFromCsv Get-FastTrackMigrationDeleteTypes #> [cmdletbinding()] param( [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)] [ValidateSet("Mig-ExHybrid","Mig-ExSimpleMRS","Mig-ExCutover","Mig-ExStaged","Mig-IMAP","Mig-GmailCutover","Mig-GmailStaged","Mig-GroupWise","Mig-GoogleDrive","Mig-GoogleSites","Mig-Box","Mig-FileSharesToOneDrive","Mig-FileSharesToTeamSites","Mig-Domino-BAM","Mig-Domino-ODME","MIG-SPOnPrem")] [string] $MigrationType, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $Source, [Parameter(Mandatory=$false,ValueFromPipeline=$true)] [string] $Target, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $MigrationDate, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $MigrationWindow, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $MigrationGroup, [Parameter(Mandatory=$false,ValueFromPipeline=$true)] [string] $Size = 0, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $Region ) DynamicParam { if($MigrationType) { $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary } if ($MigrationType -eq "Mig-ExHybrid" -or $MigrationType -eq "Mig-ExSimpleMRS" -or $MigrationType -eq "Mig-ExCutover" -or $MigrationType -eq "Mig-ExStaged") { $EpAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $IscutoverAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($EpAttribute) $attributeCollection2.Add($IscutoverAttribute) $MigrationEndpoint = New-Object System.Management.Automation.RuntimeDefinedParameter('MigrationEndpoint', [String], $attributeCollection1) $paramDictionary.Add('MigrationEndpoint', $MigrationEndpoint) $IsCutover = New-Object System.Management.Automation.RuntimeDefinedParameter('IsCutover', [Nullable[boolean]], $attributeCollection2) $paramDictionary.Add('IsCutover', $IsCutover) } elseif ($MigrationType -eq "Mig-FileSharesToOneDrive") { $Office365UPNAccountAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $TargetDocumentLibraryAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $FileCountAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection3 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($Office365UPNAccountAttribute) $attributeCollection2.Add($TargetDocumentLibraryAttribute) $attributeCollection3.Add($FileCountAttribute) $Office365UPNAccount = New-Object System.Management.Automation.RuntimeDefinedParameter('Office365UPNAccount', [String], $attributeCollection1) $paramDictionary.Add('Office365UPNAccount', $Office365UPNAccount) $TargetDocumentLibrary = New-Object System.Management.Automation.RuntimeDefinedParameter('TargetDocumentLibrary', [String], $attributeCollection2) $paramDictionary.Add('TargetDocumentLibrary', $TargetDocumentLibrary) $FileCount = New-Object System.Management.Automation.RuntimeDefinedParameter('FileCount', [String], $attributeCollection3) $paramDictionary.Add('FileCount', $FileCount) } elseif ($MigrationType -eq "Mig-FileSharesToTeamSites") { $TargetSharePointSiteAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $TargetDocumentLibraryAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $FileCountAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection3 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($TargetSharePointSiteAttribute) $attributeCollection2.Add($TargetDocumentLibraryAttribute) $attributeCollection3.Add($FileCountAttribute) $TargetSharePointSite = New-Object System.Management.Automation.RuntimeDefinedParameter('TargetSharePointSite', [String], $attributeCollection1) $paramDictionary.Add('TargetSharePointSite', $TargetSharePointSite) $TargetDocumentLibrary = New-Object System.Management.Automation.RuntimeDefinedParameter('TargetDocumentLibrary', [String], $attributeCollection2) $paramDictionary.Add('TargetDocumentLibrary', $TargetDocumentLibrary) $FileCount = New-Object System.Management.Automation.RuntimeDefinedParameter('FileCount', [String], $attributeCollection3) $paramDictionary.Add('FileCount', $FileCount) } elseif ($MigrationType -eq "Mig-Domino-BAM") { $O365UsageLocationAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $O365DisplayNameAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $LicenseSubscriptionIDAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $InPlaceHoldIdentityAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $HasBlackBerryAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $VIPAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $DominoBESServerAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $SecondPassEmailAddressAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection3 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection4 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection5 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection6 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection7 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection8 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($O365UsageLocationAttribute) $attributeCollection2.Add($O365DisplayNameAttribute) $attributeCollection3.Add($LicenseSubscriptionIDAttribute) $attributeCollection4.Add($InPlaceHoldIdentityAttribute) $attributeCollection5.Add($HasBlackBerryAttribute) $attributeCollection6.Add($VIPAttribute) $attributeCollection7.Add($DominoBESServerAttribute) $attributeCollection8.Add($SecondPassEmailAddressAttribute) $O365UsageLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('O365UsageLocation', [String], $attributeCollection1) $paramDictionary.Add('O365UsageLocation', $O365UsageLocation) $O365DisplayName = New-Object System.Management.Automation.RuntimeDefinedParameter('O365DisplayName', [String], $attributeCollection2) $paramDictionary.Add('O365DisplayName', $O365DisplayName) $LicenseSubscriptionID = New-Object System.Management.Automation.RuntimeDefinedParameter('LicenseSubscriptionID', [String], $attributeCollection3) $paramDictionary.Add('LicenseSubscriptionID', $LicenseSubscriptionID) $InPlaceHoldIdentity = New-Object System.Management.Automation.RuntimeDefinedParameter('InPlaceHoldIdentity', [String], $attributeCollection4) $paramDictionary.Add('InPlaceHoldIdentity', $InPlaceHoldIdentity) $HasBlackBerry = New-Object System.Management.Automation.RuntimeDefinedParameter('HasBlackBerry', [String], $attributeCollection5) $paramDictionary.Add('HasBlackBerry', $HasBlackBerry) $VIP = New-Object System.Management.Automation.RuntimeDefinedParameter('VIP', [String], $attributeCollection6) $paramDictionary.Add('VIP', $VIP) $DominoBESServer = New-Object System.Management.Automation.RuntimeDefinedParameter('DominoBESServer', [String], $attributeCollection7) $paramDictionary.Add('DominoBESServer', $DominoBESServer) $SecondPassEmailAddress = New-Object System.Management.Automation.RuntimeDefinedParameter('SecondPassEmailAddress', [String], $attributeCollection8) $paramDictionary.Add('SecondPassEmailAddress', $SecondPassEmailAddress) } elseif ($MigrationType -eq "Mig-Box" -or $MigrationType -eq "Mig-GoogleDrive") { $FilesOwnedAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($FilesOwnedAttribute) $FilesOwned = New-Object System.Management.Automation.RuntimeDefinedParameter('FilesOwned', [String], $attributeCollection) $paramDictionary.Add('FilesOwned', $FilesOwned) } elseif ($MigrationType -eq "Mig-Domino-ODME") { $O365UsageLocationAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $O365DisplayNameAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $LotusNotesNameAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $LocationAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $ResourceAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection3 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection4 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection5 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($O365UsageLocationAttribute) $attributeCollection2.Add($O365DisplayNameAttribute) $attributeCollection3.Add($LotusNotesNameAttribute ) $attributeCollection4.Add($LocationAttribute) $attributeCollection5.Add($ResourceAttribute) $O365UsageLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('O365UsageLocation', [String], $attributeCollection1) $paramDictionary.Add('O365UsageLocation', $O365UsageLocation) $O365DisplayName = New-Object System.Management.Automation.RuntimeDefinedParameter('O365DisplayName', [String], $attributeCollection2) $paramDictionary.Add('O365DisplayName', $O365DisplayName) $LotusNotesName= New-Object System.Management.Automation.RuntimeDefinedParameter('LotusNotesName', [String], $attributeCollection3) $paramDictionary.Add('LotusNotesName', $LotusNotesName ) $Location = New-Object System.Management.Automation.RuntimeDefinedParameter('Location', [String], $attributeCollection4) $paramDictionary.Add('Location', $Location) $Resource = New-Object System.Management.Automation.RuntimeDefinedParameter('Resource', [String], $attributeCollection5) $paramDictionary.Add('Resource', $Resource) } elseif ($MigrationType -eq "Mig-IMAP") { $PasswordAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($PasswordAttribute) $Password = New-Object System.Management.Automation.RuntimeDefinedParameter('Password', [String], $attributeCollection) $paramDictionary.Add('Password', $Password) } elseif ($MigrationType -eq "Mig-GroupWise") { $PoHostingTheMailboxAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $SoapPortAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($PoHostingTheMailboxAttribute) $attributeCollection2.Add($SoapPortAttribute) $PoHostingTheMailbox = New-Object System.Management.Automation.RuntimeDefinedParameter('PoHostingTheMailbox', [String], $attributeCollection1) $paramDictionary.Add('PoHostingTheMailbox', $PoHostingTheMailbox) $SoapPort = New-Object System.Management.Automation.RuntimeDefinedParameter('SoapPort', [String], $attributeCollection2) $paramDictionary.Add('SoapPort', $SoapPort) } elseif ($MigrationType -eq "Mig-GoogleSites") { $HoldAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($HoldAttribute) $Hold = New-Object System.Management.Automation.RuntimeDefinedParameter('Hold', [String], $attributeCollection) $paramDictionary.Add('Hold', $Hold) } elseif ($MigrationType -eq "MIG-SPOnPrem") { $HoldAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($HoldAttribute) $Hold = New-Object System.Management.Automation.RuntimeDefinedParameter('Hold', [String], $attributeCollection) $paramDictionary.Add('Hold', $Hold) } else { } if($MigrationType) { return $paramDictionary } } Process { if($global:MsoAdminProperties.Count -eq 0) { Write-Warning "Unable to retrieve Office 365 credentials! :: Please call [Login-FastTrackAccount] function." return } try { [string] $TenantId = $global:MsoAdminProperties["MSO-CompanyTenantInfo"] $PropertyBag = SetPropertyBag -MigrationType $MigrationType $jsonObj = SetCreateRequestValues -TenantID: $TenantId ` -CompanyName: $global:MsoAdminProperties["MSO-CompanyInfo"].DisplayName ` -LogonUserEmail: $global:MsoAdminProperties["MSO-LoggedOnUser"].Account ` -MigrationType: $MigrationType ` -Source: $Source ` -Target: $Target ` -MigrationDate: $MigrationDate ` -MigrationWindow: $MigrationWindow ` -MigrationGroup: $MigrationGroup ` -Size: $Size ` -IsCutover $IsCutover.Value ` -Region $Region ` -PropertyBag: $PropertyBag $serializedJson = $jsonObj | ConvertTo-Json -Compress: $true $header = @{} if($global:v2FeatureFlag -eq $true){ $header.Add("Authorization", $global:MsoAdminProperties["AuthorizationResult"].CreateAuthorizationHeader())} else{ $header.Add("ACCESS_TOKEN",$global:MsftAccessToken)} $header.Add("TENANT_ID",$TenantId) Write-Host "Sending Schedule Create Request..." $JsonResult = Invoke-PostRequest -Uri ([System.String]::Format("{0}Schedule/Create",$global:CsiApiBaseUriFormat)) -Headers $header -Body $serializedJson if($JsonResult.StatusCode -ne $null) { # Error? Write-Warning "Request failed! : $($JsonResult.StatusCode) - Error Message: $($JsonResult)" } else { Waiting-TransactionComplete -TransactionID ($JsonResult.TransactionId) } } catch { Write-Warning -Message: $_.Exception.Message Write-Host "Press the [enter] key to close this process" Read-Host } } } Function Set-FastTrackMigrationSchedule { <# .SYNOPSIS Updates an existing FastTrack schedule. .DESCRIPTION The Set-FastTracikMigrationSchedule cmdlet invokes REST API with input ScheduleId parameter. The ScheduleId is used by the API to define the migration schedules to be udpated. The Waiting-TransactionComplete cmdlet is invoked to return the "completed" or "failed" status of the migration transaction invoked. In order to use this cmdlet, you must first login using the Login-FastTrackAcount cmdlet. .PARAMETER ScheduleUserId Unique GUID For FastTrack Schedule. .PARAMETER MigrationType Type of migration. Mig-ExHybrid Exchange to Exchange hybrid migration Mig-ExSimpleMRS Exchange to Exchange hybrid migration Mig-ExCutover Cutover Migration Mig-ExStaged Staged Migration Mig-IMAP IMAP Migration Mig-GmailCutover Gmail Cutover Migration Mig-GmailStaged Gmail staged Migration Mig-GroupWise GroupWise Migration Mig-GoogleDrive Google drive to OneDrive migration Mig-GoogleSites GoogleSites Migration Mig-Box Box drive to OneDrive migration Mig-FileSharesToOneDrive FileShare to OneDrive migration Mig-FileSharesToTeamSites FileShare to TeamSite migration Mig-Domino-BAM Notes user documents into BAM (Binary Tree Application Manager) migration Mig-Domino-ODME Notes user documents into ODME migration MIG-SPOnPrem Sharepoint Migration .PARAMETER Source Source for different migration types. .PARAMETER Target Target for different migration types. .PARAMETER MigrationDate Date of migration. .PARAMETER MigrationWindow Migration event window. .PARAMETER MigrationGroup Migration group. .PARAMETER Size Size of source storage .PARAMETER IsCutover Is cutover true | false | null. .PARAMETER Region Name of region. .PARAMETER PropertyBag Properties for different migration types. .EXAMPLE New-FastTrackMigrationSchedule -ScheduleUserId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -MigrationType "Mig-Box" -Source "joe@contoso.com" -Target "Jane@contoso.net" -MigrationDate "YYYY-DD-MMTHH:MIN:SS" -MigrationWindow "Window1" -MigrationGroup "Group1" -Size 2 -PropertyBag "FilesOwned" .INPUTS System.String .OUTPUTS System.Management.Automation.PSObject This cmdlet generates a System.Management.Automation.PSObject object that represents the Transaction ID . .LINK Get-FastTrackMigrationSchedule Remove-FastTrackMigrationSchedule New-FastTrackMigrationSchedule New-FastTrackMigrationScheduleFromCsv Get-FastTrackMigrationDeleteTypes #> [cmdletbinding()] param( [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)] [Alias("ScheduleId")] [string] $ScheduleUserId, [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=1)] [ValidateSet("Mig-ExHybrid","Mig-ExSimpleMRS","Mig-ExCutover","Mig-ExStaged","Mig-IMAP","Mig-GmailCutover","Mig-GmailStaged","Mig-GroupWise","Mig-GoogleDrive","Mig-GoogleSites","Mig-Box","Mig-FileSharesToOneDrive","Mig-FileSharesToTeamSites","Mig-Domino-BAM","Mig-Domino-ODME","MIG-SPOnPrem")] [string] $MigrationType, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $Source, [Parameter(Mandatory=$false,ValueFromPipeline=$true)] [string] $Target, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $MigrationDate, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $MigrationWindow, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $MigrationGroup, [Parameter(Mandatory=$false,ValueFromPipeline=$true)] [string] $Size = 0, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $Region ) DynamicParam { if($MigrationType) { $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary } if ($MigrationType -eq "Mig-ExHybrid" -or $MigrationType -eq "Mig-ExSimpleMRS" -or $MigrationType -eq "Mig-ExCutover" -or $MigrationType -eq "Mig-ExStaged") { $EpAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $IscutoverAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($EpAttribute) $attributeCollection2.Add($IscutoverAttribute) $MigrationEndpoint = New-Object System.Management.Automation.RuntimeDefinedParameter('MigrationEndpoint', [String], $attributeCollection1) $paramDictionary.Add('MigrationEndpoint', $MigrationEndpoint) $IsCutover = New-Object System.Management.Automation.RuntimeDefinedParameter('IsCutover', [Nullable[boolean]], $attributeCollection2) $paramDictionary.Add('IsCutover', $IsCutover) } elseif ($MigrationType -eq "Mig-FileSharesToOneDrive") { $Office365UPNAccountAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $TargetDocumentLibraryAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $FileCountAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection3 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($Office365UPNAccountAttribute) $attributeCollection2.Add($TargetDocumentLibraryAttribute) $attributeCollection3.Add($FileCountAttribute) $Office365UPNAccount = New-Object System.Management.Automation.RuntimeDefinedParameter('Office365UPNAccount', [String], $attributeCollection1) $paramDictionary.Add('Office365UPNAccount', $Office365UPNAccount) $TargetDocumentLibrary = New-Object System.Management.Automation.RuntimeDefinedParameter('TargetDocumentLibrary', [String], $attributeCollection2) $paramDictionary.Add('TargetDocumentLibrary', $TargetDocumentLibrary) $FileCount = New-Object System.Management.Automation.RuntimeDefinedParameter('FileCount', [String], $attributeCollection3) $paramDictionary.Add('FileCount', $FileCount) } elseif ($MigrationType -eq "Mig-FileSharesToTeamSites") { $TargetSharePointSiteAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $TargetDocumentLibraryAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $FileCountAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection3 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($TargetSharePointSiteAttribute) $attributeCollection2.Add($TargetDocumentLibraryAttribute) $attributeCollection3.Add($FileCountAttribute) $TargetSharePointSite = New-Object System.Management.Automation.RuntimeDefinedParameter('TargetSharePointSite', [String], $attributeCollection1) $paramDictionary.Add('TargetSharePointSite', $TargetSharePointSite) $TargetDocumentLibrary = New-Object System.Management.Automation.RuntimeDefinedParameter('TargetDocumentLibrary', [String], $attributeCollection2) $paramDictionary.Add('TargetDocumentLibrary', $TargetDocumentLibrary) $FileCount = New-Object System.Management.Automation.RuntimeDefinedParameter('FileCount', [String], $attributeCollection3) $paramDictionary.Add('FileCount', $FileCount) } elseif ($MigrationType -eq "Mig-Domino-BAM") { $O365UsageLocationAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $O365DisplayNameAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $LicenseSubscriptionIDAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $InPlaceHoldIdentityAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $HasBlackBerryAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $VIPAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $DominoBESServerAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $SecondPassEmailAddressAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection3 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection4 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection5 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection6 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection7 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection8 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($O365UsageLocationAttribute) $attributeCollection2.Add($O365DisplayNameAttribute) $attributeCollection3.Add($LicenseSubscriptionIDAttribute) $attributeCollection4.Add($InPlaceHoldIdentityAttribute) $attributeCollection5.Add($HasBlackBerryAttribute) $attributeCollection6.Add($VIPAttribute) $attributeCollection7.Add($DominoBESServerAttribute) $attributeCollection8.Add($SecondPassEmailAddressAttribute) $O365UsageLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('O365UsageLocation', [String], $attributeCollection1) $paramDictionary.Add('O365UsageLocation', $O365UsageLocation) $O365DisplayName = New-Object System.Management.Automation.RuntimeDefinedParameter('O365DisplayName', [String], $attributeCollection2) $paramDictionary.Add('O365DisplayName', $O365DisplayName) $LicenseSubscriptionID = New-Object System.Management.Automation.RuntimeDefinedParameter('LicenseSubscriptionID', [String], $attributeCollection3) $paramDictionary.Add('LicenseSubscriptionID', $LicenseSubscriptionID) $InPlaceHoldIdentity = New-Object System.Management.Automation.RuntimeDefinedParameter('InPlaceHoldIdentity', [String], $attributeCollection4) $paramDictionary.Add('InPlaceHoldIdentity', $InPlaceHoldIdentity) $HasBlackBerry = New-Object System.Management.Automation.RuntimeDefinedParameter('HasBlackBerry', [String], $attributeCollection5) $paramDictionary.Add('HasBlackBerry', $HasBlackBerry) $VIP = New-Object System.Management.Automation.RuntimeDefinedParameter('VIP', [String], $attributeCollection6) $paramDictionary.Add('VIP', $VIP) $DominoBESServer = New-Object System.Management.Automation.RuntimeDefinedParameter('DominoBESServer', [String], $attributeCollection7) $paramDictionary.Add('DominoBESServer', $DominoBESServer) $SecondPassEmailAddress = New-Object System.Management.Automation.RuntimeDefinedParameter('SecondPassEmailAddress', [String], $attributeCollection8) $paramDictionary.Add('SecondPassEmailAddress', $SecondPassEmailAddress) } elseif ($MigrationType -eq "Mig-Box" -or $MigrationType -eq "Mig-GoogleDrive") { $FilesOwnedAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($FilesOwnedAttribute) $FilesOwned = New-Object System.Management.Automation.RuntimeDefinedParameter('FilesOwned', [String], $attributeCollection) $paramDictionary.Add('FilesOwned', $FilesOwned) } elseif ($MigrationType -eq "Mig-Domino-ODME") { $O365UsageLocationAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $O365DisplayNameAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $LotusNotesNameAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $LocationAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $ResourceAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection3 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection4 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection5 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($O365UsageLocationAttribute) $attributeCollection2.Add($O365DisplayNameAttribute) $attributeCollection3.Add($LotusNotesNameAttribute ) $attributeCollection4.Add($LocationAttribute) $attributeCollection5.Add($ResourceAttribute) $O365UsageLocation = New-Object System.Management.Automation.RuntimeDefinedParameter('O365UsageLocation', [String], $attributeCollection1) $paramDictionary.Add('O365UsageLocation', $O365UsageLocation) $O365DisplayName = New-Object System.Management.Automation.RuntimeDefinedParameter('O365DisplayName', [String], $attributeCollection2) $paramDictionary.Add('O365DisplayName', $O365DisplayName) $LotusNotesName= New-Object System.Management.Automation.RuntimeDefinedParameter('LotusNotesName', [String], $attributeCollection3) $paramDictionary.Add('LotusNotesName', $LotusNotesName ) $Location = New-Object System.Management.Automation.RuntimeDefinedParameter('Location', [String], $attributeCollection4) $paramDictionary.Add('Location', $Location) $Resource = New-Object System.Management.Automation.RuntimeDefinedParameter('Resource', [String], $attributeCollection5) $paramDictionary.Add('Resource', $Resource) } elseif ($MigrationType -eq "Mig-IMAP") { $PasswordAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($PasswordAttribute) $Password = New-Object System.Management.Automation.RuntimeDefinedParameter('Password', [String], $attributeCollection) $paramDictionary.Add('Password', $Password) } elseif ($MigrationType -eq "Mig-GroupWise") { $PoHostingTheMailboxAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $SoapPortAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection1 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection1.Add($PoHostingTheMailboxAttribute) $attributeCollection2.Add($SoapPortAttribute) $PoHostingTheMailbox = New-Object System.Management.Automation.RuntimeDefinedParameter('PoHostingTheMailbox', [String], $attributeCollection1) $paramDictionary.Add('PoHostingTheMailbox', $PoHostingTheMailbox) $SoapPort = New-Object System.Management.Automation.RuntimeDefinedParameter('SoapPort', [String], $attributeCollection2) $paramDictionary.Add('SoapPort', $SoapPort) } elseif ($MigrationType -eq "Mig-GoogleSites") { $HoldAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($HoldAttribute) $Hold = New-Object System.Management.Automation.RuntimeDefinedParameter('Hold', [String], $attributeCollection) $paramDictionary.Add('Hold', $Hold) } elseif ($MigrationType -eq "MIG-SPOnPrem") { $HoldAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($HoldAttribute) $Hold = New-Object System.Management.Automation.RuntimeDefinedParameter('Hold', [String], $attributeCollection) $paramDictionary.Add('Hold', $Hold) } else { } if($MigrationType) { return $paramDictionary } } Process { try { if($global:MsoAdminProperties.Count -eq 0) { Write-Warning "Unable to retrieve Office 365 credentials! :: Please call [Login-FastTrackAccount] function." return } [string]$tenantId = $global:MsoAdminProperties["MSO-CompanyTenantInfo"] [string] $TenantId = $global:MsoAdminProperties["MSO-CompanyTenantInfo"] $PropertyBag = SetPropertyBag -MigrationType $MigrationType $jsonObj = SetUpdateRequestValues -TenantID: $global:MsoAdminProperties["MSO-CompanyTenantInfo"] ` -CompanyName: $global:MsoAdminProperties["MSO-CompanyInfo"].DisplayName ` -LogonUserEmail: $global:MsoAdminProperties["MSO-LoggedOnUser"].Account ` -MigrationType: $MigrationType ` -Source: $Source ` -Target: $Target ` -MigrationDate: $MigrationDate ` -MigrationWindow: $MigrationWindow ` -MigrationGroup: $MigrationGroup ` -Size: $Size ` -IsCutover $IsCutover.Value ` -Region $Region ` -PropertyBag: $PropertyBag $serializedJson = $jsonObj | ConvertTo-Json -Compress: $true $header = @{} if($global:v2FeatureFlag -eq $true){ $header.Add("Authorization", $global:MsoAdminProperties["AuthorizationResult"].CreateAuthorizationHeader())} else{ $header.Add("ACCESS_TOKEN",$global:MsftAccessToken)} $header.Add("TENANT_ID",$TenantId) Write-Host "Sending Schedule Update Request..." $JsonResult = Invoke-PutRequest -Uri ([System.String]::Format("{0}Schedule/{1}",$global:CsiApiBaseUriFormat, $ScheduleUserId)) -Headers $header -Body $serializedJson if($JsonResult.StatusCode -ne $null) { # Error? Write-Warning "Request failed! : $($JsonResult.StatusCode) - Error Message: $($JsonResult)" } else { Waiting-TransactionComplete -TransactionID ($JsonResult.TransactionId) } } catch { Write-Warning -Message:"An error occurred attempting to authenticate with this module" Write-Warning -Message: $_.Exception.Message Write-Host "Press the [enter] key to close this process" Read-Host } } } Function Remove-FastTrackMigrationSchedule { <# .SYNOPSIS Remove an existing FastTrack schedule. .DESCRIPTION The Remove-FastTracikMigrationSchedule cmdlet invokes REST API with input ScheduleId parameter. The ScheduleId is used by the API to define the migration schedules to be deleted. The DeleteType paramter is used to define the type of delete operation to be performed on the migration. In order to use this cmdlet, you must first login using the Login-FastTrackAcount cmdlet. .PARAMETER ScheduleUserId Unique Guid for FastTrack schedule. .PARAMETER DeleteType Delete type to remove specified FastTrack schedule. This can be either ForceDelete or VerifyDelete. .EXAMPLE Remove-FastTrackMigrationSchedule -ScheduleUserId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -DeleteType: "ForceDelete" .INPUTS System.String .OUTPUTS System.Management.Automation.PSObject This cmdlet generates a System.Management.Automation.PSObject object that represents the Transaction ID . .LINK Get-FastTrackMigrationSchedule Set-FastTrackMigrationSchedule New-FastTrackMigrationSchedule New-FastTrackMigrationScheduleFromCsv Get-FastTrackMigrationDeleteTypes #> param( [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [Alias("ScheduleId")] [string] $ScheduleUserId, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $DeleteType ) try { try { $isError = [GUID]::Parse($ScheduleUserId) } catch { Write-Warning "ScheduleUserId is not a valid GUID format. To obtain the ScheduleUserId , please run Get-FastTrackMigrationSchedule to retrieve a list of all schedules." return } if($global:MsoAdminProperties.Count -eq 0) { Write-Warning "Unable to retrieve Office 365 credentials! :: Please call [Login-FastTrackAccount] function." return } [string] $ApiKey = $global:MsftApiKey [string] $TenantId = $global:MsoAdminProperties["MSO-CompanyTenantInfo"] $Identity = SetIdentityRecipientValues $CustomerObject = (New-Object PSObject | Add-Member -PassThru NoteProperty Customer $Identity | Add-Member -PassThru NoteProperty DeleteType $DeleteType | Add-Member -PassThru NoteProperty EnvironmentType $global:MsoComOrGov ) $serializedJson = $CustomerObject | ConvertTo-Json -Compress: $true $header = @{} if($global:v2FeatureFlag -eq $true){ $header.Add("Authorization", $global:MsoAdminProperties["AuthorizationResult"].CreateAuthorizationHeader())} else{ $header.Add("ACCESS_TOKEN",$global:MsftAccessToken)} $header.Add("TENANT_ID",$TenantId) Write-Host "Sending Schedule Delete Request..." $JsonResult = Invoke-DeleteRequest -Uri ([System.String]::Format("{0}Schedule/{1}",$global:CsiApiBaseUriFormat, $ScheduleUserId)) -Headers $header -Body $serializedJson if($JsonResult.StatusCode -ne $null) { # Error? Write-Warning "Request failed! : $($JsonResult.StatusCode) - Error Message: $($JsonResult)" } else { Waiting-TransactionComplete -TransactionID ($JsonResult.TransactionId) } } catch { Write-Warning -Message:"An error occurred attempting to authenticate with this module" Write-Warning -Message: $_.Exception.Message Write-Host "Press the [enter] key to close this process" Read-Host } } Function New-FastTrackMigrationScheduleFromCsv { <# .SYNOPSIS Creates a new FastTrack schedule from CSV .DESCRIPTION The New-FastTrackMigrationScheduleFromCsv command allows you to upload a full migration schedule in bulk as a CSV file. If you want to upload a single schedule, please use the New-FastTrackMigrationSchedule command. In order to use this command, you must first login using the Login-FastTrackAcount command. .PARAMETER MigrationType This is the type of migration you're wanting to schedule. Mig-ExHybrid Exchange to Exchange hybrid migration Mig-ExSimpleMRS Exchange to Exchange hybrid migration Mig-ExCutover Cutover Migration Mig-ExStaged Staged Migration Mig-IMAP IMAP Migration Mig-GmailCutover Gmail Cutover Migration Mig-GmailStaged Gmail staged Migration Mig-GroupWise GroupWise Migration Mig-GoogleDrive Google drive to OneDrive migration Mig-GoogleSites GoogleSites Migration Mig-Box Box drive to OneDrive migration Mig-FileSharesToOneDrive FileShare to OneDrive migration Mig-FileSharesToTeamSites FileShare to TeamSite migration Mig-Domino-BAM Notes user documents into BAM (Binary Tree Application Manager) migration Mig-Domino-ODME Notes user documents into ODME migration MIG-SPOnPrem Sharepoint Migration .PARAMETER IsCutover Is cutover $true | $false | $null. .PARAMETER Region Name of region. .PARAMETER FilePath Specifies the path to the Schedule CSV file . .EXAMPLE New-FastTrackMigrationScheduleFromCsv -MigrationType "Mig-Box" -Region "US" -FilePath "C:\filename.csv" .INPUTS System.String .OUTPUTS System.Management.Automation.PSObject This cmdlet generates a System.Management.Automation.PSObject object that represents the Transaction ID . .LINK New-FastTrackMigrationSchedule Get-FastTrackMigrationSchedule Set-FastTrackMigrationSchedule Remove-FastTrackMigrationSchedule Get-FastTrackMigrationDeleteTypes #> param( [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [ValidateSet("Mig-ExHybrid","Mig-ExSimpleMRS","Mig-ExCutover","Mig-ExStaged","Mig-IMAP","Mig-GmailCutover","Mig-GmailStaged","Mig-GroupWise","Mig-GoogleDrive","Mig-GoogleSites","Mig-Box","Mig-FileSharesToOneDrive","Mig-FileSharesToTeamSites","Mig-Domino-BAM","Mig-Domino-ODME","MIG-SPOnPrem")] [string] $MigrationType, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $Region, [Parameter(Mandatory=$false,ValueFromPipeline=$true)] [ValidateSet($true, $false, $null)] [Nullable[boolean]] $IsCutover, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $FilePath ) try { if($global:MsoAdminProperties.Count -eq 0) { Write-Warning "Unable to retrieve Office 365 credentials! :: Please call [Login-FastTrackAccount] function." return } $FileContentStr = Get-CsvAsJson -FilePath $FilePath if($FileContentStr -ne "[]") { [string] $TenantId = $global:MsoAdminProperties["MSO-CompanyTenantInfo"] [string] $CompanyName = $global:MsoAdminProperties["MSO-CompanyInfo"].DisplayName [string] $LogOnUserEmail = $global:MsoAdminProperties["MSO-LoggedOnUser"].Account [string] $ApiKey = $global:MsftApiKey $CustomerIdentity = (New-Object PSObject | Add-Member -PassThru NoteProperty TenantId $TenantId | Add-Member -PassThru NoteProperty CompanyName $CompanyName | Add-Member -PassThru NoteProperty LogOnUserEmail $LogOnUserEmail) $FormattedJson = New-Object psobject | Add-Member -PassThru NoteProperty Customer $CustomerIdentity | Add-Member -PassThru NoteProperty ScheduleType $MigrationType | Add-Member -PassThru NoteProperty Schedules $FileContentStr | Add-Member -PassThru NoteProperty Region $Region | Add-Member -PassThru NoteProperty IsCutover $IsCutover | Add-Member -PassThru NoteProperty EnvironmentType $global:MsoComOrGov $Output = $FormattedJson | ConvertTo-Json -Compress: $true $header = @{} if($global:v2FeatureFlag -eq $true){ $header.Add("Authorization", $global:MsoAdminProperties["AuthorizationResult"].CreateAuthorizationHeader())} else{ $header.Add("ACCESS_TOKEN",$global:MsftAccessToken)} $header.Add("TENANT_ID", $TenantId) Write-Host "Sending New Schedule From CSV Request..." $result = Invoke-PostRequest -Uri ([System.String]::Format("{0}Schedule/Create/Batch", $global:CsiApiBaseUriFormat)) -Headers $header -Body $Output if($result.StatusCode -ne $null) { Write-Warning "Request failed! : $($result.StatusCode) - Error Message: $($result)" } else { Waiting-TransactionComplete -TransactionID ($result.TransactionId) } } else { Write-Warning "File ($($FilePath)) is not in valid CSV format." } } catch { Write-Warning -Message:"An error occurred attempting to authenticate with this module" Write-Warning -Message: $_.Exception.Message Write-Host "Press the [enter] key to close this process" Read-Host } } Function Get-FastTrackMigrationScheduleTemplate { <# .SYNOPSIS Get sample template of CSV file which upload in FastTrack schedule. .DESCRIPTION The Get-FastTrackMigrationScheduleTemplate cmdlet invokes the REST API to retrieve the correct CSV file template, based on the input FastTrack migration type. The retrieved template is saved to the directory declared by the Path parameter. In order to use this cmdlet, you must first login using the Login-FastTrackAcount cmdlet. .PARAMETER MigrationType This is the type of migration you're wanting to schedule. Mig-ExHybrid Exchange to Exchange hybrid migration Mig-ExSimpleMRS Exchange to Exchange hybrid migration Mig-ExCutover Cutover Migration Mig-ExStaged Staged Migration Mig-IMAP IMAP Migration Mig-GmailCutover Gmail Cutover Migration Mig-GmailStaged Gmail staged Migration Mig-GroupWise GroupWise Migration Mig-GoogleDrive Google drive to OneDrive migration Mig-GoogleSites GoogleSites Migration Mig-Box Box drive to OneDrive migration Mig-FileSharesToOneDrive FileShare to OneDrive migration Mig-FileSharesToTeamSites FileShare to TeamSite migration Mig-Domino-BAM Notes user documents into BAM (Binary Tree Application Manager) migration Mig-Domino-ODME Notes user documents into ODME migration MIG-SPOnPrem Sharepoint Migration .PARAMETER Path Output path of template file. .EXAMPLE Get-FastTrackMigrationScheduleTemplate -MigrationType "Mig-Box" -Folderpath 'C:/template' .INPUTS System.String .OUTPUTS System.IO This cmdlet generates a File object. .LINK New-FastTrackMigrationScheduleFromCsv #> [cmdletbinding()] param( [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [ValidateSet("Mig-ExHybrid","Mig-ExSimpleMRS","Mig-ExCutover","Mig-ExStaged","Mig-IMAP","Mig-GmailCutover","Mig-GmailStaged","Mig-GroupWise","Mig-GoogleDrive","Mig-GoogleSites","Mig-Box","Mig-FileSharesToOneDrive","Mig-FileSharesToTeamSites","Mig-Domino-BAM","Mig-Domino-ODME","MIG-SPOnPrem")] [string] $MigrationType = $(throw "This migration type is not valid."), [Parameter(Mandatory=$false,ValueFromPipeline=$true)] [string] $FolderPath = $null ) DynamicParam { if($MigrationType -eq "Mig-ExHybrid" -or $MigrationType -eq "Mig-ExSimpleMRS" -or $MigrationType -eq "Mig-ExCutover" -or $MigrationType -eq "Mig-ExStaged") { $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $IscutoverAttribute = New-Object System.Management.Automation.ParameterAttribute -Property @{ Mandatory = $false } $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($IscutoverAttribute) $IsCutover = New-Object System.Management.Automation.RuntimeDefinedParameter('IsCutover', [Nullable[boolean]], $attributeCollection) $paramDictionary.Add('IsCutover', $IsCutover) return $paramDictionary } } Process { try { if($global:MsoAdminProperties.Count -eq 0) { Write-Warning "Unable to retrieve Office 365 credentials! :: Please call [Login-FastTrackAccount] function." return } if($FolderPath) { if((Test-Path -Path $FolderPath -ErrorAction: SilentlyContinue) -ne $true ) { Write-Warning "Unable to find path you entered - $FolderPath" return } $filename = $MigrationType + '_' + ('{0:yyyyMMdd_HHmmss}' -f (Get-Date)) $newFilefullPath = $FolderPath + "\" + $filename + ".csv" } Write-Host "Retrieving template - " -NoNewline; Write-Host $MigrationType -ForegroundColor Yellow; $header = @{} if($global:v2FeatureFlag -eq $true){ $header.Add("Authorization", $global:MsoAdminProperties["AuthorizationResult"].CreateAuthorizationHeader())} else{ $header.Add("ACCESS_TOKEN",$global:MsftAccessToken)} $header.Add("TENANT_ID", $global:MsoAdminProperties["MSO-CompanyTenantInfo"]) if($IsCutover.Value -eq "false") { $IsCutoverOb = "false" } elseif($IsCutover.Value -eq "true") { $IsCutoverOb = "true" } else { $IsCutoverOb = $null } $JsonResult = Invoke-GetRequest -Uri ([System.String]::Format("{0}Schedule/Template?MigrationType={1}&IsCutover={2}&environmentType={3}", $global:CsiApiBaseUriFormat, $MigrationType, $IsCutover.Value, $global:MsoComOrGov)) -Headers $header if($JsonResult.StatusCode -ne $null) { Write-Warning "Request failed! : $($JsonResult.StatusCode) - Error Message: $($JsonResult)" return } else { if(!$FolderPath) { Write-Host "`n" [Regex]::Split($JsonResult.data,"\\r\\n") return } $tempData = ([Regex]::Split($JsonResult.data,"\\r\\n")) | ConvertFrom-Csv $tempData | Export-Csv -NoTypeInformation -Path $newFilefullPath Write-Host "`nCSV Template file successfully generated." Write-Host "File location : " -NoNewline; Write-Host $newFilefullPath -ForegroundColor Yellow Write-Host "`nDo you want to open ?" $input = Read-Host '[F] File [P] Folder Path [S] Suspend (default is "F")' switch(([string]$input).ToUpper()) { "S" { } "P" { ii $FolderPath } default { Invoke-Item $newFilefullPath } } } } catch { Write-Warning -Message:"An error occurred attempting to authenticate with this module" Write-Warning -Message: $_.Exception.Message Write-Host "Press the [enter] key to close this process" Read-Host } } } Function Get-FastTrackMigrationDeleteTypes { <# .SYNOPSIS Get FastTrack delete types. .DESCRIPTION The Get-FastTrackMigrationDeleteTypes cmdlet utilizes the REST API call to retrieve a list of available delete types used to schedule deletion of FastTrack schedule. In order to use this cmdlet, you must first login using the Login-FastTrackAcount cmdlet. .EXAMPLE Get-FastTrackMigrationDeleteTypes .INPUTS System.String .OUTPUTS System.Management.Automation.PSObject This cmdlet generates a System.Management.Automation.PSObject object that represents the list of possible delete types for FastTrack schedule delete. .LINK New-FastTrackMigrationSchedule Set-FastTrackMigrationSchedule Remove-FastTrackMigrationSchedule New-FastTrackMigrationScheduleFromCsv Get-FastTrackMigrationSchedule #> try { if($global:MsoAdminProperties.Count -eq 0) { Write-Warning "Unable to retrieve Office 365 credentials! :: Please call [Login-FastTrackAccount] function." return } [string] $ApiKey = $global:MsftApiKey [string] $TenantId = $global:MsoAdminProperties["MSO-CompanyTenantInfo"] $header = @{} if($global:v2FeatureFlag -eq $true){ $header.Add("Authorization", $global:MsoAdminProperties["AuthorizationResult"].CreateAuthorizationHeader())} else{ $header.Add("ACCESS_TOKEN",$global:MsftAccessToken)} $header.Add("TENANT_ID",$TenantId) Write-Host "Sending Schedule Get Request..." $query += "environmentType=$global:MsoComOrGov" $JsonResult = Invoke-GetRequest -Uri ([System.String]::Format("{0}Schedule/DeleteTypes?$($query)", $global:CsiApiBaseUriFormat)) -Headers $header if($JsonResult.StatusCode -ne $null) { Write-Warning "Request failed! : $($JsonResult.StatusCode) - Error Message: $($JsonResult)" } else { Write-Host "Get request completed" } return $JsonResult } catch { Write-Warning -Message:"An error occurred attempting to authenticate with this module" Write-Warning -Message: $_.Exception.Message Write-Host "Press the [enter] key to close this process" Read-Host } } Function Get-FastTrackMigrationTypes { <# .SYNOPSIS Get FastTrack Migration Types. .DESCRIPTION This cmdlet is used to get all the migration types to execute FastTrack schedules. In order to use this cmdlet, you must first login using the Login-FastTrackAcount cmdlet. .EXAMPLE FastTrackMigrationTypes .INPUTS System.String .OUTPUTS System.Management.Automation.PSObject This cmdlet generates a System.Management.Automation.PSObject object that represents the list of possible migration types for FastTrack schedule operation. .LINK New-FastTrackMigrationSchedule Set-FastTrackMigrationSchedule New-FastTrackMIgrationScheduleFromCsv #> try { if($global:MsoAdminProperties.Count -eq 0) { Write-Warning "Unable to retrieve Office 365 credentials! :: Please call [Login-FastTrackAccount] function." return } [string] $ApiKey = $global:MsftApiKey [string] $TenantId = $global:MsoAdminProperties["MSO-CompanyTenantInfo"] $header = @{} if($global:v2FeatureFlag -eq $true){ $header.Add("Authorization", $global:MsoAdminProperties["AuthorizationResult"].CreateAuthorizationHeader())} else{ $header.Add("ACCESS_TOKEN",$global:MsftAccessToken)} $header.Add("TENANT_ID",$TenantId) Write-Host "Sending Migration type Get Request..." $query += "environmentType=$global:MsoComOrGov" $JsonResult = Invoke-GetRequest -Uri ([System.String]::Format("{0}Schedule/MigrationTypes?$($query)", $global:CsiApiBaseUriFormat)) -Headers $header if($JsonResult.StatusCode -ne $null) { Write-Warning "Request failed! : $($JsonResult.StatusCode) - Error Message: $($JsonResult)" } else { Write-Host "Get request completed" return $JsonResult.MigrationTypes } return $JsonResult } catch { Write-Warning -Message:"An error occurred attempting to authenticate with this module" Write-Warning -Message: $_.Exception.Message Write-Host "Press the [enter] key to close this process" Read-Host } } Function Clear-FastTrackMigrationSchedules { <# .SYNOPSIS Allow for the deletion of multiple schedules .DESCRIPTION This PowerShell is to allow a user to select and delete multiple schedules for a customer #> $scheduleUserId = ( Get-FastTrackMigrationSchedule | Out-GridView -Title "Select schedules to remove (cancel to abort)" -PassThru).ScheduleUserId foreach ($scheduleUser in $scheduleUserId) {Remove-FastTrackMigrationSchedule -ScheduleId $scheduleUser -DeleteType: "ForceDelete" } } Function Update-FastTrackMigrationSchedules { <# .SYNOPSIS Allow for the update of multiple schedules .DESCRIPTION This PowerShell function is to allow a user to select and update multiple schedules for a customer. Only Migration Window, Migration Group and Migration Date can be updated. .PARAMETER MigrationDate Date of migration. .PARAMETER MigrationWindow Migration event window. .PARAMETER MigrationGroup Migration group. #> param( [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $MigrationDate, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $MigrationWindow, [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [string] $MigrationGroup ) # Get the schedules associated to the customer and pipe them into a grid. $selectedSchedules = ( Get-FastTrackMigrationSchedule | Out-GridView -Title "Select a set of schedules to update" -PassThru) foreach ($selectedSchedule in $selectedSchedules) { # Besides updating the base/required schedule parameters certain migration types also have extra paramerters that must also be passed in to the Set-FastTrackMigrationSchedule cmdlet if ($selectedSchedule.MigrationType -eq "Mig-ExHybrid" -or $selectedSchedule.MigrationType -eq "Mig-ExSimpleMRS" -or $selectedSchedule.MigrationType -eq "Mig-ExCutover" -or $selectedSchedule.MigrationType -eq "Mig-ExStaged") { # Update base schedule parameters + MigrationEndpoint and IsCutover parameters Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -MigrationEndpoint $selectedSchedule.MigrationEndpoint -IsCutover $selectedSchedule.IsCutover } elseif ($selectedSchedule.MigrationType -eq "Mig-FileSharesToOneDrive") { # Update base schedule parameters + Office365UPNAccount, TargetDocumentLibrary and FileCount parameters Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -Office365UPNAccount $selectedSchedule.Office365UPNAccount -TargetDocumentLibrary $selectedSchedule.TargetDocumentLibrary -FileCount $selectedSchedule.FileCount } elseif ($selectedSchedule.MigrationType -eq "Mig-FileSharesToTeamSites") { # Update base schedule parameters + TargetSharePointSite, TargetDocumentLibrary and FileCount parameters Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -TargetSharePointSite $selectedSchedule.TargetSharePointSite -TargetDocumentLibrary $selectedSchedule.TargetDocumentLibrary -FileCount $selectedSchedule.FileCount } elseif ($selectedSchedule.MigrationType -eq "Mig-Domino-BAM") { # Update base schedule parameters + O365UsageLocation, O365DisplayName, LicenseSubscriptionID, InPlaceHoldIdentity, HasBlackBerry, VIP, DominoBESServer and SecondPassEmailAddress parameters Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -O365UsageLocation $selectedSchedule.O365UsageLocation -O365DisplayName $selectedSchedule.O365DisplayName -LicenseSubscriptionID $selectedSchedule.LicenseSubscriptionID -InPlaceHoldIdentity $selectedSchedule.InPlaceHoldIdentity -HasBlackBerry $selectedSchedule.HasBlackBerry -VIP $selectedSchedule.VIP -DominoBESServer $selectedSchedule.DominoBESServer -SecondPassEmailAddress $selectedSchedule.SecondPassEmailAddress } elseif ($selectedSchedule.MigrationType -eq "Mig-Box" -or $selectedSchedule.MigrationType -eq "Mig-GoogleDrive") { # Update base schedule parameters + FilesOwned paramerter Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -FilesOwned $selectedSchedule.FilesOwned } elseif ($selectedSchedule.MigrationType -eq "Mig-Domino-ODME") { # Update base schedule parameters + Lotus Notes Name,Location (Site Name),Resource (Room/Equipment),Internet Address,O365 UPN,O365 Display Name and O365 Usage Location parameters Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -O365UsageLocation $selectedSchedule.O365UsageLocation -O365DisplayName $selectedSchedule.O365DisplayName -LotusNotesName $selectedSchedule.LotusNotesName -Location $selectedSchedule.Location -Resource $selectedSchedule.Resource } elseif ($selectedSchedule.MigrationType -eq "Mig-IMAP" ) { # Update base schedule parameters + FilesOwned paramerter Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -Hold $selectedSchedule.Password } elseif ($selectedSchedule.MigrationType -eq "Mig-GroupWise" ) { # Update base schedule parameters + FilesOwned paramerter Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -PoHostingTheMailbox $selectedSchedule.PoHostingTheMailbox -SoapPort $selectedSchedule.SoapPort } elseif ($selectedSchedule.MigrationType -eq "Mig-GoogleSites" ) { # Update base schedule parameters + FilesOwned paramerter Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -Hold $selectedSchedule.Hold } elseif ($selectedSchedule.MigrationType -eq "MIG-SPOnPrem" ) { # Update base schedule parameters + FilesOwned paramerter Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region -Hold $selectedSchedule.Hold } else { # Update base schedule parameters only Set-FastTrackMigrationSchedule -ScheduleId $selectedSchedule.ScheduleUserId -MigrationType $selectedSchedule.MigrationType -Source $selectedSchedule.Source -Target $selectedSchedule.Target -MigrationDate $MigrationDate -MigrationWindow $MigrationWindow -MigrationGroup $MigrationGroup -Size $selectedSchedule.Size -Region $selectedSchedule.Region } } } # SIG # Begin signature block # MIIkWwYJKoZIhvcNAQcCoIIkTDCCJEgCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBT3nWIDVWmApMh # hEcOcm9Ns25P3ClaPGHUhSFZ318KLaCCDYEwggX/MIID56ADAgECAhMzAAABA14l # HJkfox64AAAAAAEDMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMTgwNzEyMjAwODQ4WhcNMTkwNzI2MjAwODQ4WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDRlHY25oarNv5p+UZ8i4hQy5Bwf7BVqSQdfjnnBZ8PrHuXss5zCvvUmyRcFrU5 # 3Rt+M2wR/Dsm85iqXVNrqsPsE7jS789Xf8xly69NLjKxVitONAeJ/mkhvT5E+94S # nYW/fHaGfXKxdpth5opkTEbOttU6jHeTd2chnLZaBl5HhvU80QnKDT3NsumhUHjR # hIjiATwi/K+WCMxdmcDt66VamJL1yEBOanOv3uN0etNfRpe84mcod5mswQ4xFo8A # DwH+S15UD8rEZT8K46NG2/YsAzoZvmgFFpzmfzS/p4eNZTkmyWPU78XdvSX+/Sj0 # NIZ5rCrVXzCRO+QUauuxygQjAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUR77Ay+GmP/1l1jjyA123r3f3QP8w # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDM3OTY1MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAn/XJ # Uw0/DSbsokTYDdGfY5YGSz8eXMUzo6TDbK8fwAG662XsnjMQD6esW9S9kGEX5zHn # wya0rPUn00iThoj+EjWRZCLRay07qCwVlCnSN5bmNf8MzsgGFhaeJLHiOfluDnjY # DBu2KWAndjQkm925l3XLATutghIWIoCJFYS7mFAgsBcmhkmvzn1FFUM0ls+BXBgs # 1JPyZ6vic8g9o838Mh5gHOmwGzD7LLsHLpaEk0UoVFzNlv2g24HYtjDKQ7HzSMCy # RhxdXnYqWJ/U7vL0+khMtWGLsIxB6aq4nZD0/2pCD7k+6Q7slPyNgLt44yOneFuy # bR/5WcF9ttE5yXnggxxgCto9sNHtNr9FB+kbNm7lPTsFA6fUpyUSj+Z2oxOzRVpD # MYLa2ISuubAfdfX2HX1RETcn6LU1hHH3V6qu+olxyZjSnlpkdr6Mw30VapHxFPTy # 2TUxuNty+rR1yIibar+YRcdmstf/zpKQdeTr5obSyBvbJ8BblW9Jb1hdaSreU0v4 # 6Mp79mwV+QMZDxGFqk+av6pX3WDG9XEg9FGomsrp0es0Rz11+iLsVT9qGTlrEOla # P470I3gwsvKmOMs1jaqYWSRAuDpnpAdfoP7YO0kT+wzh7Qttg1DO8H8+4NkI6Iwh # SkHC3uuOW+4Dwx1ubuZUNWZncnwa6lL2IsRyP64wggd6MIIFYqADAgECAgphDpDS # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIWMDCCFiwCAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAQNeJRyZH6MeuAAAAAABAzAN # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgT9nRr7CQ # S4RRcCftKdxVrmxDJZI/qn0iP4fXksiqMeYwQgYKKwYBBAGCNwIBDDE0MDKgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN # BgkqhkiG9w0BAQEFAASCAQAaUbNNUBXyboMjcViLJ4j4/uYizh2rfOrChXO/ZoPz # DoqScYmToUByu418N1m9btzxlZx46sv6chjpaOqdgtMQC0AuDeK6g/nfGD8eYt6R # 3jZG+Ob5qQM+MHIgwLbt318tLw9wxbzY0H0HGHETRuvjxqtK+8bqumemT0I0ioKB # jSpxjfreGDUCfBduGm6oQhCfv91TpyAmffroUYqkH4OYoUgAgU21TzJkweRXNSJb # pN0NN3BCYFI/XgmcPEZd+/1OccYnT/5fYEX/qqr6ItLlGoVtE8uHrM0NK3Q/a0Ee # kErj00jibOseLkSdBwQc7BsmSbsixsYgEIhu7JH//Vp7oYITujCCE7YGCisGAQQB # gjcDAwExghOmMIITogYJKoZIhvcNAQcCoIITkzCCE48CAQMxDzANBglghkgBZQME # AgEFADCCAVgGCyqGSIb3DQEJEAEEoIIBRwSCAUMwggE/AgEBBgorBgEEAYRZCgMB # MDEwDQYJYIZIAWUDBAIBBQAEIAWOQEdtTvnOJk57BBZOEJqH2GwtA+1hAv9kpCVU # ExZdAgZcShKP8UQYEzIwMTkwMjA2MTgzMDU4LjE0M1owBwIBAYACAfSggdSkgdEw # gc4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsT # IE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFs # ZXMgVFNTIEVTTjo3MjhELUM0NUYtRjlFQjElMCMGA1UEAxMcTWljcm9zb2Z0IFRp # bWUtU3RhbXAgU2VydmljZaCCDyIwggT1MIID3aADAgECAhMzAAAA09CUVp0OvYMG # AAAAAADTMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAy # MDEwMB4XDTE4MDgyMzIwMjY0MFoXDTE5MTEyMzIwMjY0MFowgc4xCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP # cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo3 # MjhELUM0NUYtRjlFQjElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy # dmljZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK7ynC6AF22joS/v # TPZsIG82oovZ8kXNQcF6/17dZtRllU6pCGV8zMxSQOXTWD2MZRJ/OqfHUSYCNTPa # knetNsrZhstlFNT09QBjjeVXayDG/aI8JPy91P5riOAFk/gvjnQCdcoV65OBF286 # bs2lgUa6rc2qKHwDVpR1w+2jXrS8Jtz6omUgfB7CMpw1ZwMeQ/+Fb43EAIxeNXB5 # uq/ZYPDA+iMitkdhrjQJgPKKQqhPiYcz3KdrAk34V6y/zUw8FuJ9Zi89actfoS0e # AdSdWYDATi6oIiPAioWYQuwx6ZY+e5U8HcjGiA1bg9pnufqcnVLzInBxr8DVp1im # mAhtkfUCAwEAAaOCARswggEXMB0GA1UdDgQWBBQoUcoPr2oQO5sHaVpYVKDsatRn # eDAfBgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEug # SaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9N # aWNUaW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsG # AQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Rp # bVN0YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG # CCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQA9YvD9FBa0sIj/Q8252GXwW0qQ # aEm/oZXTh4eI6htIKASVxX8y1g4IVeD6O8YyXdBlzQUgr76B70pDgqyynwmJK6KB # pg2bf6KOeHImc4pmofFc9EhYLZgXPXwqHJY1Rgwt4X1kCNNK6PTGeFlJproYry38 # a8AuUm0oLJpf46TLC4wQv89vfyEhBed/Wv95Ro5fqn/tAQc8S/c0eq1CAdkMDzsJ # q7lZmiEAMaVF0vKrcRvtVu7T5BZcTmP6bHNtzcDxnn7rB6TUgSREnWP5Di46Z9P6 # 0XraNff0Ttit5Msy8ivsrcEa2CIxUgscbYDxAaWR8Ghb/rTVIEEWYBAVrF9vMIIG # cTCCBFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UE # BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0 # IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1 # WhcNMjUwNzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu # Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv # cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCC # ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9p # lGt0VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEw # WbEwRA/xYIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeG # MoQedGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJ # UGKxXf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw # 2k4GkbaICDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0C # AwEAAaOCAeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ # 80N7fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8E # BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2U # kFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5j # b20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmww # WgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29m # dC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYD # VR0gAQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6 # Ly93d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYI # KwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0 # AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9 # naOhIW+z66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtR # gkQS+7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzy # mXlKkVIArzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCf # Mkon/VWvL/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3D # nKOiPPp/fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs # 9/S/fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110 # mCIIYdqwUB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL # 2IK0cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffI # rE7aKLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxE # PJdQcdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc # 1bN+NR4Iuto229Nfj950iEkSoYIDsDCCApgCAQEwgf6hgdSkgdEwgc4xCzAJBgNV # BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w # HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29m # dCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVT # Tjo3MjhELUM0NUYtRjlFQjElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg # U2VydmljZaIlCgEBMAkGBSsOAwIaBQADFQBnQlpxrvQi2lklNcOL1G5qmRJdZ6CB # 3jCB26SB2DCB1TELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO # BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEp # MCcGA1UECxMgTWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJzAlBgNV # BAsTHm5DaXBoZXIgTlRTIEVTTjo0REU5LTBDNUUtM0UwOTErMCkGA1UEAxMiTWlj # cm9zb2Z0IFRpbWUgU291cmNlIE1hc3RlciBDbG9jazANBgkqhkiG9w0BAQUFAAIF # AOAE55YwIhgPMjAxOTAyMDYxMjU2NTRaGA8yMDE5MDIwNzEyNTY1NFowdzA9Bgor # BgEEAYRZCgQBMS8wLTAKAgUA4ATnlgIBADAKAgEAAgICjwIB/zAHAgEAAgIZdDAK # AgUA4AY5FgIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMBoAowCAIB # AAIDFuNgoQowCAIBAAIDB6EgMA0GCSqGSIb3DQEBBQUAA4IBAQBqk96DFl4vA/8o # oq9hNatps/sYX2ePe2gsoFkTa5IfnPXc1Yu4TzvfId+d//MqoZuRRPJdWGbyNTRm # T0zIlZQHAWIsa4dF8+6/fxWONYvhtzzIfXkp6ftMmDbo/xKoqpaRbC150PPpvk+R # RFcjbpkEj0Yx1hfM+GR1mGlYEUpx4gmzlQsz2Jf38h1DZVyc9GJHxtXg5m76WDpT # pl56H/xLUlgoSEQiJS/RG1hFD7kryW9XzMQa1lHkGmx1m9HapzN/Pm8ZIzz/jWix # 9aPbPKeOSvKMrwnR2U63Vq8Quz7SvNAergVFJ4Rf4AgII8gSA7BxprDB6QKKK2e+ # g7Ip3N/oMYIC9TCCAvECAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw # MTACEzMAAADT0JRWnQ69gwYAAAAAANMwDQYJYIZIAWUDBAIBBQCgggEyMBoGCSqG # SIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgdJMRswrC6Owb # Sy+CUJADCWcyymrfg1wbiQuJi3xTejEwgeIGCyqGSIb3DQEJEAIMMYHSMIHPMIHM # MIGxBBRnQlpxrvQi2lklNcOL1G5qmRJdZzCBmDCBgKR+MHwxCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1l # LVN0YW1wIFBDQSAyMDEwAhMzAAAA09CUVp0OvYMGAAAAAADTMBYEFIPhy7ept8yk # kI5fPc3VKcb8IW5qMA0GCSqGSIb3DQEBCwUABIIBAKz2/L3hzzEZ9Qz9sr5EwN/o # d98ChTI3Sq60BWiiuhh6MR1Bv2YtwbKsQb1Gg/fmr1R5JpNR11xoe2YaydmieeAx # xG2eR3QnvWGMyz0muEk0ZcU1zBWcvvyRvhQidZuD3TbnWR6oguxKzpwt7HFG119t # p/Ggl2/kZ9vaINVHfHUGm9ZT/nl3NvxUZ47ncOsHsG0kt6lrd4tHGvA6GLUmZfdw # 72WCjU/wKplRfz4eggYwNpy8aekk0OzkEIsWhl+pgK1HavzI6/gPEhPpfue47Mmm # WZCpiG5QOCLbbfF8dWsWYM6y0cuXTCQZ9th6SCxpNRBNSnRh97A7CqS4tuPIDII= # SIG # End signature block |