functions/Invoke-DownloadAndExpand.ps1

function Invoke-DownloadAndExpand {
    param(
        [string]$Uri,
        [string]$DestinationPath
    )

    $mutexName = "DownloadAndExpand"
    $mutex = New-Object System.Threading.Mutex($false, $mutexName)

    try {
        try { 
            $mutex.WaitOne() | Out-Null
        }
        catch {}

        $tempName = Join-Path -Path $env:TEMP -ChildPath ([Guid]::NewGuid().ToString())

        Write-Host "Downloading $Uri"
        (New-Object System.Net.WebClient).DownloadFile($Uri, "$tempName.zip")

        Expand-Archive -Path "$tempName.zip" -DestinationPath $tempName

        $archiveContent = (Get-Item -Path (Join-Path -Path $tempName -ChildPath '*')).FullName

        if (Test-Path -Path $DestinationPath) {
            Remove-Item -Path $DestinationPath -Force -Recurse
            New-Item -ItemType Directory -Path $DestinationPath | Out-Null
        }
        
        Move-Item -Path $archiveContent -Destination $DestinationPath -Force

        Remove-Item -Path "$tempName.zip" -Force
        Remove-Item -Path $tempName -Force -Recurse
    }
    finally {
        $mutex.ReleaseMutex()
    }
}