functions/Get-UdeDeveloperFile.ps1
|
<# .SYNOPSIS Gets UDE developer files for a specified environment. .DESCRIPTION This function retrieves UDE developer files for a specified environment. .PARAMETER EnvironmentId The ID of the environment to retrieve. Supports wildcard patterns. Can be either the environment name or the environment GUID. .PARAMETER Path The path to the directory where the developer files will be saved. Defaults to "C:\Temp\d365bap.tools\UdeDeveloperFiles". .PARAMETER Files The types of developer files to retrieve. Can be one or more of the following values: "All", "SystemMetadata", "FinOpsVsix22", "TraceParser", "CrossReference". Defaults to "All". .PARAMETER Download Instructs the function to download the developer files to the specified path. .EXAMPLE PS C:\> Get-UdeDeveloperFile -EnvironmentId "env-123" This will retrieve the UDE developer files for the specified environment ID without downloading them. .EXAMPLE PS C:\> Get-UdeDeveloperFile -EnvironmentId "env-123" -Download This will download the UDE developer files for the specified environment ID to the default path. .NOTES Author: Mötz Jensen (@Splaxi) #> function Get-UdeDeveloperFile { [CmdletBinding()] [OutputType('System.Object[]')] param ( [Parameter (mandatory = $true)] [string] $EnvironmentId, [string] $Path = "C:\Temp\d365bap.tools\UdeDeveloperFiles", [ValidateSet('All', 'SystemMetadata', 'FinOpsVsix22', 'TraceParser', 'CrossReference')] [string[]] $Files = 'All', [switch] $Download ) begin { Add-Type -AssemblyName System.IO.Compression.FileSystem $envObj = Get-UdeEnvironment -EnvironmentId $EnvironmentId | Select-Object -First 1 if ($null -eq $envObj) { $messageString = "Could not find environment with Id <c='em'>$EnvironmentId</c>. Please verify the Id and try again, or list available environments using <c='em'>Get-UdeEnvironment</c>. Consider using wildcards if needed." Write-PSFMessage -Level Host -Message $messageString -Target Host Stop-PSFFunction -Message "Stopping because environment was NOT found based on the id." ` -Exception $([System.Exception]::new($($messageString -replace '<[^>]+>', ''))) return } $build = $envObj.PpacProvApp if ($Download) { $downloadDir = "$Path\$($envObj.PpacProvApp)" New-Item -Path $downloadDir ` -ItemType Directory ` -Force ` -WarningAction SilentlyContinue > $null } $executable = Get-PSFConfigValue -FullName "d365bap.tools.path.azcopy" $endpoints = @("SystemMetadata", "FinOpsVsix22", "TraceParser", "CrossReference") $colFileTypes = @() if ($Files -eq 'All') { $colFileTypes = $endpoints } else { $colFileTypes = $Files } } process { if (Test-PSFFunctionInterrupt) { return } $baseUri = $envObj.PpacEnvUri + "/" #! Very important to have the trailing slash $secureToken = (Get-AzAccessToken -ResourceUrl $baseUri -AsSecureString).Token $tokenWebApiValue = ConvertFrom-SecureString -AsPlainText -SecureString $secureToken $headers = @{ "Correlationid" = [guid]::NewGuid().ToString() "Dataverseenvironmenturi" = $envObj.PpacEnvUri "Authorization" = "Bearer $($tokenWebApiValue)" "Odata-Maxversion" = "4.0" "Odata-Version" = "4.0" "Accept" = "application/json" } $colFiles = @( foreach ($endpoint in $endpoints) { # Skip if not in requested file types if ($endpoint -notin $colFileTypes) { continue } $localUri = "https://developertools.powerplatform.microsoft.com/api/clientmetadata/$($endpoint.ToLower())?version=$($envObj.PpacProvApp.Replace(".", "-"))" [PsCustomObject][Ordered]@{ "Type" = $endpoint "Build" = $envObj.PpacProvApp "Uri" = $(Invoke-RestMethod -Method Get ` -Uri $localUri ` -Headers $headers) } | Select-PSFObject -TypeName "D365Bap.Tools.UdeDeveloperFile" ` -Property * } ) if (-not $Download) { $colFiles return } Write-PSFMessage -Level Host -Message "Will start the download of the files. It will open a separate PowerShell window for each:" $processes = @() # Start a new PowerShell window for each download to allow parallel downloads # Each window will remain open after download to allow user to validate the download foreach ($fileObj in $colFiles) { $uriQuery = Split-Path $fileObj.Uri -Leaf $fileName = $uriQuery.Split("?")[0] $outputPath = Join-Path $downloadDir $fileName $fileObj | Add-Member -NotePropertyName "Path" -NotePropertyValue $outputPath if ([System.IO.Path]::Exists($outputPath)) { Write-PSFMessage -Level Host -Message " - Skipping <c='em'>$fileName</c> as it already <c='em'>exists</c>" continue } Write-PSFMessage -Level Host -Message " - <c='em'>$fileName</c>" # Command to run in new window: azcopy copy, then pause for validation $command = @" $executable copy '$($fileObj.Uri)' '$outputPath'; if(-not [System.IO.Path]::Exists('$outputPath')){ Write-Host 'Download failed. Review the logs for more information.' -ForegroundColor Red }; "@ $process = Start-Process -FilePath "powershell.exe" -ArgumentList "-Command", $command -WindowStyle Normal -PassThru $processes += $process } Write-PSFMessage -Level Host -Message "Will await the completion of <c='em'>all</c> file downloads." if ($processes.Count -gt 0 ) { Wait-Process -Id $processes.Id > $null } # Output the details to the user $colFiles # If we downloaded the SystemMetadata, we extract it - otherwise it is useless $zipPackages = $colFiles | Where-Object type -eq 'SystemMetadata' | Select-Object -First 1 -ExpandProperty Path $pathPackages = "$env:LOCALAPPDATA\Microsoft\Dynamics365\$build" if (-not [System.IO.Path]::Exists("$pathPackages\PackagesLocalDirectory")) { New-Item -Path "$pathPackages" ` -ItemType Directory ` -Force ` -WarningAction SilentlyContinue > $null Write-PSFMessage -Level Host -Message "Will extract the <c='em'>PackagesLocalDirectory.zip</c> file. It will take some minutes..." [IO.Compression.ZipFile]::ExtractToDirectory($zipPackages, "$pathPackages\PackagesLocalDirectory") Write-PSFMessage -Level Host -Message "Extraction completed..." } } end { } } |