Fixing via another CloudM Migrate pass is likely still the best option. Test on a single account first (be mindful of Drive sharing, the test account should have minimal permissions to other folders to limit the impact of the test). You can fix via GAM, but it is going to be a lot of work and carries a greater risk of mistakes.
Excel is probably going to be the easiest, and it gives you a chance to spot check things to make sure everything will be updated as you expect it to. Since you have a filelist of the destination with originid's already, you can map the migrated folders to the source folders via these origin ID's. This will be more reliable than folder path.
I had to create shortcuts for a customer as we used Google Workspace Migrate, which (at least at the time) did not not support migrating shortcuts. The script I created won't apply directly in this case, but since I needed to create shortcuts in the correct destination folders, a subset of my code did roughly what you're trying to do. I've tried to adapt it here for you, but mainly "on paper" and untested, so this script likely won't work as-is. Hopefully it can help you get most of the way though.
Import-Csv $usersfile | ForEach-Object -ThrottleLimit 2 -Parallel {
Set-Alias "gam" ~/bin/gamadv-xtd3/gam
$sourcedomain = $using:sourcedomain
$destdomain = $using:destdomain
$sourceuser = $_.source
$destuser = $_.dest
Write-Host "Starting to process $destuser..."
$alldestfiles = "query","'me' in owners","not 'me' in owners" | # this worked around an issue with obtaining all items located within a users Drive
gam select $destdomain config cache_discovery_only true show_gettings false csv_output_header_filter JSON redirect csv - multiprocess noheader csv - gam user $destuser print filelist fullquery ~query fields name,id,parents,owners,mimetype,shortcutdetails.targetid,properties formatjson quotechar "'" 2>$null | % {
$_.TrimStart("'").TrimEnd("'") | ConvertFrom-Json | Group-Object -Property {
if ($_.Properties.key -eq 'CloudMigrator-OriginId') {
($_.Properties).where({ $_.key -eq 'CloudMigrator-OriginId' }).value
} elseif ($_.shortcutDetails.targetId) {
$_.shortcutDetails.targetId
} else {
$_.id
}
} -AsHashTable
}
$allsourcefiles = "query","'me' in owners","not 'me' in owners" |
gam select $sourcedomain config cache_discovery_only true show_gettings false csv_output_header_filter JSON redirect csv - multiprocess noheader csv - gam user $sourceuser print filelist fullquery ~query excludetrashed fields name,id,parents,owners,mimetype,shortcutdetails.targetid formatjson quotechar "'" 2>$null | % {
$_.TrimStart("'").TrimEnd("'") | ConvertFrom-Json | Group-Object id -AsHashTable
}
# Everything below here is more theory-crafted, and so is much less likely to work as-is than the lines above
$incorrectdestparents = $alldestfiles.where({ $_.parents -neq $allsourcefiles.$($_.id).parents })
if ($incorrectdestparents.count -gt 0) {
[Array]$parentstoupdate = foreach ($item in $incorrectdestparents.where({ $_.Values.ownedByMe -eq $true -and ($_.Values.parents) }).values) {
if ($alldestfiles.$($item.id).trashed -eq $true) {
continue
}
$parentId = $null
if ($item.parents.isRoot -eq $true) {
$parentId = $null
} else {
if (-not $item.parents.id) {
continue
}
$destparent = $alldestfiles.$($item.parents.id)
if ($destparent) {
$parentId = $destparent.id
} else {
$parentId = $item.parents.id
}
}
[PSCustomObject]@{
User = $destuser
id = $id
parentId = $parentId
originFileId = $item.id
}
}if ($parentstoupdate.Length -gt 0) {
[Array]$parentsUpdated = $parentstoupdate.Where({$_.parentId.count -eq 1}) | ConvertTo-Csv | gam select $destdomain config cache_discovery_only true show_gettings false csv_input_row_filter "parentId:regex:^.+$" redirect csv - multiprocess csv - gam user ~User update drivefile ~id parentid ~parentId csv 2>$null | ConvertFrom-Csv
}
#Optionally, if you want to keep an indicator on the updated files that you have updated them, you can do the below. You can also modify this (or add new properties) that store the original parent id (from the source or the destination), or anything else that you may find helpful
$parentsUpdated | ConvertTo-Csv | gam select $destdomain config cache_discovery_only true show_gettings false csv - gam user ~User update drivefile ~id returnidonly publicproperty MovedToNewParent True | Out-Null
$parentsUpdated
} #End of the "Import-Csv $usersfile | ForEach-Object -ThrottleLimit 2 -Parallel {" loop
The script outputs an object that you can watch directly on the screen, or more helpfully pipe out to a csv (via | Export-Csv) so you have a record of the actions taken.
You also may need to factor in that it is no longer possible for files to have multiple parents, while in your source domain you may have some that do have multiple parents. You'll have to decide which folder to locate the primary item in, and which folder (or if) to create a shortcut in; the above script does not handle creating shortcuts for multi-parented items. If you're going to take the route of fixing this via GAM, you'll need a more comprehensive test account to validate the scripting with than you will with taking the route of fixing via CloudM, as there are more variables that you'll need to account for.