functions/invoke-d365lcsupload.ps1


<#
    .SYNOPSIS
        Upload a file to a LCS project
         
    .DESCRIPTION
        Upload a file to a LCS project using the API provided by Microsoft
         
    .PARAMETER ProjectId
        The project id for the Dynamics 365 for Finance & Operations project inside LCS
         
    .PARAMETER ClientId
        The Azure Registered Application Id / Client Id obtained while creating a Registered App inside the Azure Portal
         
    .PARAMETER Username
        The username of the account that you want to impersonate
         
        It can either be your personal account or a service account
         
    .PARAMETER Password
        The password of the account that you want to impersonate
         
    .PARAMETER FilePath
        Path to the file that you want to upload to the Asset Library on LCS
         
    .PARAMETER FileType
        Type of file you want to upload
         
        Valid options:
        "DeployablePackage"
        "DatabaseBackup"
         
    .PARAMETER FileName
        Name to be assigned / shown on LCS
         
    .PARAMETER FileDescription
        Description to be assigned / shown on LCS
         
    .PARAMETER LcsApiUri
        URI / URL to the LCS API you want to use
         
        Depending on whether your LCS project is located in europe or not, there is 2 valid URI's / URL's
         
        Valid options:
        "https://lcsapi.lcs.dynamics.com"
        "https://lcsapi.eu.lcs.dynamics.com"
         
    .EXAMPLE
        PS C:\> Invoke-D365LcsUpload -ProjectId 123456789 -ClientId "9b4f4503-b970-4ade-abc6-2c086e4c4929" -Username claire@contoso.com -Password "pass@word1" -FilePath "C:\temp\d365fo.tools\GOLDEN.bacpac" -FileType "DatabaseBackup" -FileName "ReadyForTesting" -FileDescription "Contains all customers & vendors" -LcsApiUri "https://lcsapi.lcs.dynamics.com"
         
        This will upload the "C:\temp\d365fo.tools\GOLDEN.bacpac" file to the LCS project 123456789.
        It will authenticate against the AAD with the ClientId "9b4f4503-b970-4ade-abc6-2c086e4c4929", the Username Claire@contoso.com and the Password "pass@word1".
        The file will be placed in the sub folder "Database Backup".
        The file will be named "ReadyForTesting" inside the Asset Library in LCS.
        The file is uploaded against the NON-EUROPE LCS API.
         
    .EXAMPLE
        PS C:\> Invoke-D365LcsUpload -FilePath "C:\temp\d365fo.tools\GOLDEN.bacpac" -FileType "DatabaseBackup" -FileName "ReadyForTesting" -FileDescription "Contains all customers & vendors"
         
        This will upload the "C:\temp\d365fo.tools\GOLDEN.bacpac" file.
        The file will be placed in the sub folder "Database Backup".
        The file will be named "ReadyForTesting" inside the Asset Library in LCS.
         
        The ProjectId, ClientId, Username, Password and LcsApiUri parameters are read from the configuration storage, that is configured by the Set-D365LcsUploadConfig cmdlet.
         
    .NOTES
        Tags: Environment, Url, Config, Configuration, LCS, Upload, Api, AAD, Token
         
        Author: Mötz Jensen (@Splaxi)
         
#>


function Invoke-D365LcsUpload {
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "")]
    [CmdletBinding()]
    [OutputType()]
    param(
        [Parameter(Mandatory = $false, Position = 1)]
        [int]$ProjectId = $Script:LcsUploadProjectid,
        
        [Parameter(Mandatory = $false, Position = 2)]
        [string] $ClientId = $Script:LcsUploadClientid,

        [Parameter(Mandatory = $false, Position = 3)]
        [string] $Username = $Script:LcsUploadUsername,

        [Parameter(Mandatory = $false, Position = 4)]
        [string] $Password = $Script:LcsUploadPassword,

        [Parameter(Mandatory = $true, Position = 5)]
        [string]$FilePath,

        [Parameter(Mandatory = $false, Position = 6)]
        [ValidateSet("DeployablePackage", "DatabaseBackup")]
        [string]$FileType = "DatabaseBackup",

        [Parameter(Mandatory = $false, Position = 7)]
        [string]$FileName,

        [Parameter(Mandatory = $false, Position = 8)]
        [string]$FileDescription,

        [Parameter(Mandatory = $false, Position = 9)]
        [ValidateSet("https://lcsapi.lcs.dynamics.com", "https://lcsapi.eu.lcs.dynamics.com")]
        [string]$LcsApiUri = $Script:LcsUploadApiUri
    )

    Invoke-TimeSignal -Start

    $fileNameExtracted = Split-Path $FilePath -Leaf

    if ($FileName -eq "") {
        $FileName = $fileNameExtracted
    }

    $scope = "openid"
    $grantType = "password"

    $authToken = Invoke-AadAuthentication -Resource $LcsApiUri -GrantType $grantType -ClientId $ClientId -Username $Username -Password $Password -Scope $scope

    if (Test-PSFFunctionInterrupt) { return }
    
    Write-PSFMessage -Level Verbose -Message "Auth token" -Target $authToken

    $bearerToken = "Bearer {0}" -f $authToken

    $blobDetails = Start-LcsUpload -Token $bearerToken -ProjectId $ProjectId -FileType $FileType -LcsApiUri $LcsApiUri -Name $FileName -Description $FileDescription

    if (Test-PSFFunctionInterrupt) { return }

    Write-PSFMessage -Level Verbose -Message "Start response" -Target $blobDetails

    $uploadResponse = Copy-FileToLcsBlob -FilePath $FilePath -FullUri $blobDetails.FileLocation

    if (Test-PSFFunctionInterrupt) { return }

    Write-PSFMessage -Level Verbose -Message "Upload response" -Target $uploadResponse

    $ackResponse = Complete-LcsUpload -Token $bearerToken -ProjectId $ProjectId -AssetId $blobDetails.Id -LcsApiUri $LcsApiUri

    if (Test-PSFFunctionInterrupt) { return }

    Write-PSFMessage -Level Verbose -Message "Commit response" -Target $ackResponse

    Invoke-TimeSignal -End

    [PSCustomObject]@{
        AssetId = $blobDetails.Id
        Name = $FileName
    }
}