private/New-odscShortcutItem.ps1

function New-odscShortcutItem {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string] $User,

        [Parameter(Mandatory = $true)]
        [hashtable] $RemoteItem,

        [Parameter(Mandatory = $true)]
        [string] $ShortcutName,

        [Parameter(Mandatory = $false)]
        [AllowNull()]
        [AllowEmptyString()]
        [string] $RelativePath
    )

    # Resolve (and create) the destination folder first so a failure there does not leave a shortcut behind.
    $DestinationFolder = $null
    if (-not [string]::IsNullOrWhiteSpace($RelativePath)) {
        $DestinationFolder = Resolve-odscDriveFolderPath -User $User -RelativePath $RelativePath -Create
    }

    # Shortcuts are created at the OneDrive root, moved to the destination folder and then renamed,
    # because the root may already hold an item with the same name as the one in the destination.
    $CreateRequest = @{
        Resource = "users/${User}/drive/root/children"
        Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Post
        Body = @{
            name = $ShortcutName
            remoteItem = $RemoteItem
            '@microsoft.graph.conflictBehavior' = 'rename'
        }
    }

    try {
        $ShortcutResponse = Invoke-odscApiRequest @CreateRequest -ErrorAction Stop
    } catch {
        # Name clashes are renamed by Graph, so a conflict here means OneDrive already has a shortcut to this target.
        if ((Get-odscGraphStatusCode -ErrorRecord $_) -eq 409) {
            Write-Error "${User}'s OneDrive already has a shortcut to this target, possibly with another name or in another folder. OneDrive allows only one shortcut per target. $($_.Exception.Message)" -ErrorAction Stop
        }

        throw
    }

    if (!($ShortcutResponse) -or [string]::IsNullOrWhiteSpace($ShortcutResponse.id)) {
        Write-Error "Error creating OneDrive shortcut '$ShortcutName' for ${User}. Microsoft Graph did not return an item id." -ErrorAction Stop
    }

    $ItemResource = Join-odscDriveItemResource -User $User -ItemId $ShortcutResponse.id

    # From here on the shortcut exists. Graph may have given it another name (on a clash, '<site> - <name>').
    # If it cannot be moved or renamed it is kept, so the user keeps access, and the error names it so an
    # administrator can sort it out. Callers can recognise this error by its id and read the shortcut from TargetObject.
    if ($DestinationFolder) {
        $MoveRequest = @{
            Resource = $ItemResource
            Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Patch
            DoNotUsePrefer = $true
            Body = @{
                parentReference = @{
                    id = $DestinationFolder.id
                }
            }
        }

        try {
            Invoke-odscApiRequest @MoveRequest -ErrorAction Stop | Out-Null
        } catch {
            Write-Error -ErrorId 'odscShortcutNotRenamed' -TargetObject $ShortcutResponse -ErrorAction Stop -Message (
                "The shortcut was created as '$($ShortcutResponse.name)' at the root of ${User}'s OneDrive but could not be moved to '$RelativePath'. " +
                "Move and rename it to '$ShortcutName' by hand. $($_.Exception.Message)")
        }
    }

    $RenameRequest = @{
        Resource = $ItemResource
        Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Patch
        Body = @{
            name = $ShortcutName
        }
    }

    try {
        return Invoke-odscApiRequest @RenameRequest -ErrorAction Stop
    } catch {
        $Location = if ($DestinationFolder) { "'$RelativePath'" } else { 'the root' }
        $Reason = if ((Get-odscGraphStatusCode -ErrorRecord $_) -eq 409) {
            "because the name '$ShortcutName' is already used by another item there. Rename that item, then rename the shortcut to '$ShortcutName'."
        } else {
            "because it could not be renamed to '$ShortcutName'."
        }

        Write-Error -ErrorId 'odscShortcutNotRenamed' -TargetObject $ShortcutResponse -ErrorAction Stop -Message (
            "The shortcut was created as '$($ShortcutResponse.name)' in $Location of ${User}'s OneDrive $Reason $($_.Exception.Message)")
    }
}