9

I've had some significant difficulties figuring out how exactly to download a file with PowerShell under Nano Server.

The challenge is the following:

  • There is no Invoke-WebRequest

  • There is no System.Net.WebClient

  • There is no Start-BitsTransfer

  • There is no bitsadmin

Does anyone know how to do this (seemingly simple) task?

4 Answers4

4

There is an example here of downloading a zip file using PowerShell on Nano, you might have to modify it a bit for your purposes;

(from here: https://docs.asp.net/en/latest/tutorials/nano-server.html#installing-the-asp-net-core-module-ancm)

$SourcePath = "https://dotnetcli.blob.core.windows.net/dotnet/beta/Binaries/Latest/dotnet-win-x64.latest.zip"
$DestinationPath = "C:\dotnet"

$EditionId = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'EditionID').EditionId

if (($EditionId -eq "ServerStandardNano") -or
    ($EditionId -eq "ServerDataCenterNano") -or
    ($EditionId -eq "NanoServer") -or
    ($EditionId -eq "ServerTuva")) {

    $TempPath = [System.IO.Path]::GetTempFileName()
    if (($SourcePath -as [System.URI]).AbsoluteURI -ne $null)
    {
        $handler = New-Object System.Net.Http.HttpClientHandler
        $client = New-Object System.Net.Http.HttpClient($handler)
        $client.Timeout = New-Object System.TimeSpan(0, 30, 0)
        $cancelTokenSource = [System.Threading.CancellationTokenSource]::new()
        $responseMsg = $client.GetAsync([System.Uri]::new($SourcePath), $cancelTokenSource.Token)
        $responseMsg.Wait()
        if (!$responseMsg.IsCanceled)
        {
            $response = $responseMsg.Result
            if ($response.IsSuccessStatusCode)
            {
                $downloadedFileStream = [System.IO.FileStream]::new($TempPath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write)
                $copyStreamOp = $response.Content.CopyToAsync($downloadedFileStream)
                $copyStreamOp.Wait()
                $downloadedFileStream.Close()
                if ($copyStreamOp.Exception -ne $null)
                {
                    throw $copyStreamOp.Exception
                }
            }
        }
    }
    else
    {
        throw "Cannot copy from $SourcePath"
    }
    [System.IO.Compression.ZipFile]::ExtractToDirectory($TempPath, $DestinationPath)
    Remove-Item $TempPath
}
Tom
  • 10,886
  • 5
  • 39
  • 62
4

Invoke-WebRequest was added to nanoserver as part of the September 26, 2016 Cumulative Update for Windows Server 2016.

mikebridge
  • 195
  • 1
  • 2
  • 11
  • I believe those powershell code samples you're referring to are meant to be run on client machine, not the Nano docker host (it says "On the remote system where you will be working, download the Docker client.: `Invoke-WebRequest ...`") – qbik Jun 14 '17 at 03:46
  • I could be wrong but I assumed @yet-another-user wanted to use it from within the docker client during a build. – mikebridge Jun 14 '17 at 04:03
2

It's crazy that a server OS designed to power cloud workloads doesn't have in-built convenient method for a simple REST/Web request :O

Anyway, you can try this powershell script wget.ps1 which is a modification of the one from Microsoft. Copy-pasting here for convenience

<#
.SYNOPSIS
    Downloads a file
.DESCRIPTION
    Downloads a file
.PARAMETER Url
    URL to file/resource to download
.PARAMETER Filename
    file to save it as locally
.EXAMPLE
    C:\PS> .\wget.ps1 https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
#>

Param(
  [Parameter(Position=0,mandatory=$true)]
  [string]$Url,
  [string]$Filename = ''
)

# Get filename
if (!$Filename) {
    $Filename = [System.IO.Path]::GetFileName($Url)    
}

Write-Host "Download: $Url to $Filename"

# Make absolute local path
if (![System.IO.Path]::IsPathRooted($Filename)) {
    $FilePath = Join-Path (Get-Item -Path ".\" -Verbose).FullName $Filename
}

if (($Url -as [System.URI]).AbsoluteURI -ne $null)
{
    # Download the bits
    $handler = New-Object System.Net.Http.HttpClientHandler
    $client = New-Object System.Net.Http.HttpClient($handler)
    $client.Timeout = New-Object System.TimeSpan(0, 30, 0)
    $cancelTokenSource = [System.Threading.CancellationTokenSource]::new()
    $responseMsg = $client.GetAsync([System.Uri]::new($Url), $cancelTokenSource.Token)
    $responseMsg.Wait()
    if (!$responseMsg.IsCanceled)
    {
        $response = $responseMsg.Result
        if ($response.IsSuccessStatusCode)
        {
            $downloadedFileStream = [System.IO.FileStream]::new($FilePath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write)

            $copyStreamOp = $response.Content.CopyToAsync($downloadedFileStream)
            # TODO: Progress bar? Total size?
            Write-Host "Downloading ..."
            $copyStreamOp.Wait()

            $downloadedFileStream.Close()
            if ($copyStreamOp.Exception -ne $null)
            {
                throw $copyStreamOp.Exception
            }
        }
    }
}
else
{
    throw "Cannot download from $Url"
}
DeepSpace101
  • 698
  • 5
  • 12
  • 25
0

Ever Since Microsoft released the new Windows Nano Server 1709 Container Image downloading and extracting files without PowerShell has been challenging.

Recently, The Microsoft Virtualization announced that two command-line tools will be added to Windows 10 and Windows Nano Server.

The tools are:

  • Tar.exe – Allows us to extract files and create archives without PowerShell which means you can use it from the command -line.

  • Curl .exe– allows us to download files from Internet sources and Servers located on our network.

     curl.exe -o node.zip https://nodejs.org/dist/v9.2.0/node-v9.2.0-win-x64.zip
    

Reference: https://www.ntweekly.com/2019/10/27/tar-and-curl-come-to-windows-nano-server-insider-image/