DSCResources/ArcGIS_RemoteFile/ArcGIS_RemoteFile.psm1
<#
.SYNOPSIS Makes a request to the download a file from remote file storage server. .PARAMETER Url Fully qualified url of the remote file to be downloaded. .PARAMETER DestinationPath File path on the Local machine where the image will be downloaded too. .PARAMETER FileSourceType Remote file storage Authentication type. Supported values - AzureFiles, AzureBlobsManagedIdentity, Default .PARAMETER AFSCredential Credential to use when Azure Files if being used as remote file storage server .PARAMETER AFSEndpoint End point of Azure Files if being used as remote file storage server .PARAMETER Ensure Ensure makes sure that a remote file exists on the local machine. Take the values Present or Absent. - "Present" ensures that a remote file exists on the local machine. - "Absent" ensures that a remote file doesn't exists on the local machine. #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $true)] [System.String] $Url, [Parameter(Mandatory=$true)] [ValidateSet("AzureFiles","AzureBlobsManagedIdentity","Default")] [System.String] $FileSourceType ) $null } function Set-TargetResource { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [System.String] $Url, [System.String] $DestinationPath, [Parameter(Mandatory=$true)] [ValidateSet("AzureFiles","AzureBlobsManagedIdentity","Default")] [System.String] $FileSourceType, [Parameter(Mandatory=$False)] [System.Management.Automation.PSCredential] $AFSCredential, [Parameter(Mandatory=$false)] [System.String] $AFSEndpoint, [ValidateSet("Present","Absent")] [System.String] $Ensure ) if(-not($DestinationPath)) { throw 'Destination Path not provided' } if($Ensure -ieq 'Present') { $DestinationFolder = Split-Path $DestinationPath -Parent if(-not(Test-Path $DestinationFolder)){ Write-Verbose "Creating Directory $DestinationFolder" New-Item $DestinationFolder -ItemType directory } if($FileSourceType -ieq "AzureFiles"){ $AvailableDriveLetter = AvailableDriveLetter New-PSDrive -Name $AvailableDriveLetter -PSProvider FileSystem -Root $AFSEndpoint -Credential $AFSCredential -Persist $FileSharePath = "$($AvailableDriveLetter):\\$($url)" Write-Verbose "Copying file $FileSharePath to $DestinationPath" Copy-Item -Path $FileSharePath -Destination $DestinationPath -Force Remove-PSDrive -Name $AvailableDriveLetter }else{ if($url.StartsWith('http', [System.StringComparison]::InvariantCultureIgnoreCase)) { Write-Verbose "Downloading file $url to $DestinationPath" Invoke-DownloadFile -RemoteFileUrl $url -DestinationFilePath $DestinationPath ` -IsUsingAzureBlobManagedIndentity ($FileSourceType -ieq "AzureBlobsManagedIdentity") -Verbose }else{ Write-Verbose "Copying file $url to $DestinationPath" Copy-Item -Path $url -Destination $DestinationPath -Force } } } elseif($Ensure -ieq 'Absent') { if($DestinationPath -and (Test-Path $DestinationPath)) { Remove-Item -Path $DestinationPath -Force } } } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $true)] [System.String] $Url, [System.String] $DestinationPath, [Parameter(Mandatory=$true)] [ValidateSet("AzureFiles","AzureBlobsManagedIdentity","Default")] [System.String] $FileSourceType, [Parameter(Mandatory=$False)] [System.Management.Automation.PSCredential] $AFSCredential, [Parameter(Mandatory=$false)] [System.String] $AFSEndpoint, [ValidateSet("Present","Absent")] [System.String] $Ensure ) $result = $false if($DestinationPath -and (Test-Path $DestinationPath)) { $result = $true } if($Ensure -ieq 'Present') { if($result) { if($url.StartsWith('http', [System.StringComparison]::InvariantCultureIgnoreCase)) { # File Exists locally. Check the remote location Write-Verbose 'File Exists locally. Check if the remote URL has Changed using Last-Modified Header' $HasRemoteFileChanged = $true $response = $null try { if($FileSourceType -ieq "AzureBlobsManagedIdentity"){ $ManagedIdentityAccessToken = Get-ManagedIdentityAccessToken -Verbose $Headers = @{ Authorization = "Bearer $ManagedIdentityAccessToken" "x-ms-version" = "2017-11-09" } $response = Invoke-WebRequest -Uri $Url -UseBasicParsing -Headers $Headers -TimeoutSec 15 -Method Head -ErrorAction Ignore }else{ $response = Invoke-WebRequest -Uri $Url -UseBasicParsing -UseDefaultCredentials -TimeoutSec 15 -Method Head -ErrorAction Ignore } } catch{ $HasRemoteFileChanged = $false } if($response) { [DateTime]$RemoteFileLastModTime = $response.Headers['Last-Modified'] if($RemoteFileLastModTime -le (Get-Item -Path $DestinationPath).CreationTime) { $HasRemoteFileChanged = $false } } if($HasRemoteFileChanged) { # File has changed - needs to be downloaded again $result = $false } } else { if($FileSourceType -eq "Default"){ if((Get-Item -Path $Url).LastWriteTime -gt (Get-Item -Path $DestinationPath).CreationTime) { # File has changed - needs to be copied again $result = $false } }else{ $result = $false } } } $result } elseif($Ensure -ieq 'Absent') { (-not($result)) } } function AvailableDriveLetter { param ( [char] $ExcludedLetter ) $Letter = [int][char]'C' $i = @() #getting all the used Drive letters reported by the Operating System $(Get-PSDrive -PSProvider filesystem) | ForEach-Object{$i += $_.name} #Adding the excluded letter $i+=$ExcludedLetter while($i -contains $([char]$Letter)){$Letter++} return $([char]$Letter) } function Get-ManagedIdentityAccessToken { $response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fstorage.azure.com%2F' -UseBasicParsing -Method GET -Headers @{Metadata="true"} $content = $response.Content | ConvertFrom-Json $ArmToken = $content.access_token return $ArmToken } function Invoke-DownloadFile { param ( [System.String] $RemoteFileUrl, [System.String] $DestinationFilePath, [System.Boolean] $IsUsingAzureBlobManagedIndentity ) try { $wc = New-Object System.Net.WebClient; if($IsUsingAzureBlobManagedIndentity){ $ManagedIdentityAccessToken = Get-ManagedIdentityAccessToken -Verbose $wc.Headers.Add('Authorization', "Bearer $ManagedIdentityAccessToken") $wc.Headers.Add("x-ms-version", "2017-11-09") } $wc.DownloadFile($RemoteFileUrl, $DestinationFilePath) } catch { throw "Error downloading remote file. Error - $_" } } Export-ModuleMember -Function *-TargetResource |