Windows Azure Powershell将文件复制到VM

时间:2013-08-05 02:18:29

标签: powershell azure azure-virtual-machine

我正在尝试使用Windows Azure PowerShell将zip文件复制到VM中。 我已按照文档设法连接到VM。

但是,我找不到任何教程将zip文件上传/复制/传输到VM Disk,比如说进入C盘。

任何人都可以帮我提供教程的任何链接或任何想法如何复制?

6 个答案:

答案 0 :(得分:6)

这是我记录here的另一种方法。它涉及

  1. 创建并安装空的本地VHD。
  2. 将文件复制到新的VHD并卸载它。
  3. 将VHD复制到azure blob存储
  4. 将该VHD附加到您的VM。
  5. 以下是一个例子:

    #Create and mount a new local VHD
    $volume = new-vhd -Path test.vhd -SizeBytes 50MB | `
      Mount-VHD -PassThru | `
      Initialize-Disk -PartitionStyle mbr -Confirm:$false -PassThru | `
      New-Partition -UseMaximumSize -AssignDriveLetter -MbrType IFS | `
      Format-Volume -NewFileSystemLabel "VHD" -Confirm:$false
    
    #Copy my files  
    Copy-Item C:\dev\boxstarter "$($volume.DriveLetter):\" -Recurse
    Dismount-VHD test.vhd
    
    #upload the Vhd to azure
    Add-AzureVhd -Destination http://mystorageacct.blob.core.windows.net/vhdstore/test.vhd `
      -LocalFilePath test.vhd
    
    #mount the VHD to my VM
    Get-AzureVM MyCloudService MyVMName | `
      Add-AzureDataDisk -ImportFrom `
      -MediaLocation "http://mystorageacct.blob.core.windows.net/vhdstore/test.vhd" `
      -DiskLabel "boxstarter" -LUN 0 | `
      Update-AzureVM
    

答案 1 :(得分:4)

以下是我从一些PowerShell示例中获得并修改过的一些代码。它适用于使用New-PSSession创建的会话。下面还有一个很酷的包装。最后,我需要发送一个整个文件夹,所以也在这里..

将它们捆绑在一起的一些示例用法

# open remote session
$session = Get-Session -uri $uri -credentials $credential 
# copy installer to VM
Write-Verbose "Checking if file $installerDest needs to be uploaded"
Send-File -Source $installerSrc -Destination $installerDest -Session $session -onlyCopyNew $true



<#
.SYNOPSIS
  Returns a session given the URL 
.DESCRIPTION
  http://michaelcollier.wordpress.com/2013/06/23/using-remote-powershell-with-windows-azure-vms/
#>
function Get-Session($uri, $credentials)
{
    for($retry = 0; $retry -le 5; $retry++)
    {
      try
      {
        $session = New-PSSession -ComputerName $uri[0].DnsSafeHost -Credential $credentials -Port $uri[0].Port -UseSSL
        if ($session -ne $null)
        {
            return $session
        }

        Write-Output "Unable to create a PowerShell session . . . sleeping and trying again in 30 seconds."
        Start-Sleep -Seconds 30
      }
      catch
      {
        Write-Output "Unable to create a PowerShell session . . . sleeping and trying again in 30 seconds."
        Start-Sleep -Seconds 30
      }
    }
}

<#
.SYNOPSIS
  Sends a file to a remote session.
  NOTE: will delete the destination before uploading
.EXAMPLE
  $remoteSession = New-PSSession -ConnectionUri $remoteWinRmUri.AbsoluteUri -Credential $credential
  Send-File -Source "c:\temp\myappdata.xml" -Destination "c:\temp\myappdata.xml" $remoteSession

  Copy the required files to the remote server 

    $remoteSession = New-PSSession -ConnectionUri $frontEndwinRmUri.AbsoluteUri -Credential $credential
    $sourcePath = "$PSScriptRoot\$remoteScriptFileName"
    $remoteScriptFilePath = "$remoteScriptsDirectory\$remoteScriptFileName"
    Send-File $sourcePath $remoteScriptFilePath $remoteSession

    $answerFileName = Split-Path -Leaf $WebPIApplicationAnswerFile
    $answerFilePath = "$remoteScriptsDirectory\$answerFileName"
    Send-File $WebPIApplicationAnswerFile $answerFilePath $remoteSession
    Remove-PSSession -InstanceId $remoteSession.InstanceId
#>
function Send-File
{
    param (

        ## The path on the local computer
        [Parameter(Mandatory = $true)]
        [string]
        $Source,

        ## The target path on the remote computer
        [Parameter(Mandatory = $true)]
        [string]
        $Destination,

        ## The session that represents the remote computer
        [Parameter(Mandatory = $true)]
        [System.Management.Automation.Runspaces.PSSession] 
        $Session,

        ## should we quit if file already exists?
        [bool]
        $onlyCopyNew = $false

        )

    $remoteScript =
    {
        param ($destination, $bytes)

        # Convert the destination path to a full filesystem path (to supportrelative paths)
        $Destination = $ExecutionContext.SessionState.`
        Path.GetUnresolvedProviderPathFromPSPath($Destination)

        # Write the content to the new file
        $file = [IO.File]::Open($Destination, "OpenOrCreate")
        $null = $file.Seek(0, "End")
        $null = $file.Write($bytes, 0, $bytes.Length)
        $file.Close()
    }

    # Get the source file, and then start reading its content
    $sourceFile = Get-Item $Source

    # Delete the previously-existing file if it exists
    $abort = Invoke-Command -Session $Session {
        param ([String] $dest, [bool]$onlyCopyNew)

        if (Test-Path $dest) 
        { 
            if ($onlyCopyNew -eq $true)
            {
                return $true
            }

            Remove-Item $dest
        }

        $destinationDirectory = Split-Path -Path $dest -Parent
         if (!(Test-Path $destinationDirectory))
        {
            New-Item -ItemType Directory -Force -Path $destinationDirectory 
        }

        return $false
    } -ArgumentList $Destination, $onlyCopyNew

    if ($abort -eq $true)
    {
        Write-Host 'Ignored file transfer - already exists'
        return
    }

    # Now break it into chunks to stream
    Write-Progress -Activity "Sending $Source" -Status "Preparing file"
    $streamSize = 1MB
    $position = 0
    $rawBytes = New-Object byte[] $streamSize
    $file = [IO.File]::OpenRead($sourceFile.FullName)
    while (($read = $file.Read($rawBytes, 0, $streamSize)) -gt 0)
    {
        Write-Progress -Activity "Writing $Destination" -Status "Sending file" `
            -PercentComplete ($position / $sourceFile.Length * 100)

        # Ensure that our array is the same size as what we read from disk
        if ($read -ne $rawBytes.Length)
        {
            [Array]::Resize( [ref] $rawBytes, $read)
        }

        # And send that array to the remote system
        Invoke-Command -Session $session $remoteScript -ArgumentList $destination, $rawBytes

        # Ensure that our array is the same size as what we read from disk
        if ($rawBytes.Length -ne $streamSize)
        {
            [Array]::Resize( [ref] $rawBytes, $streamSize)
        }
        [GC]::Collect()
        $position += $read
    }

    $file.Close()

    # Show the result
    Invoke-Command -Session $session { Get-Item $args[0] } -ArgumentList $Destination
}

<#
.SYNOPSIS
  Sends all files in a folder to a remote session.
  NOTE: will delete any destination files before uploading
.EXAMPLE
  $remoteSession = New-PSSession -ConnectionUri $remoteWinRmUri.AbsoluteUri -Credential $credential
  Send-Folder -Source 'c:\temp\' -Destination 'c:\temp\' $remoteSession
#>
function Send-Folder 
{
    param (
        ## The path on the local computer
        [Parameter(Mandatory = $true)]
        [string]
        $Source,

        ## The target path on the remote computer
        [Parameter(Mandatory = $true)]
        [string]
        $Destination,

        ## The session that represents the remote computer
     #   [Parameter(Mandatory = $true)]
        [System.Management.Automation.Runspaces.PSSession] 
        $Session,

        ## should we quit if files already exist?
        [bool]
        $onlyCopyNew = $false
    )

    foreach ($item in Get-ChildItem $Source)
    {
        if (Test-Path $item.FullName -PathType Container) {
            Send-Folder $item.FullName "$Destination\$item" $Session $onlyCopyNew
        } else {
            Send-File -Source $item.FullName -Destination "$destination\$item" -Session $Session -onlyCopyNew $onlyCopyNew
        }
    }
}

答案 2 :(得分:2)

您无法使用PowerShell将文件直接复制到虚拟机的操作系统磁盘(甚至是其中一个连接的磁盘)。没有用于直接与虚拟机内部通信的API(您需要为此创建自己的自定义服务。

可以使用PowerShell将文件上传到带有Set-AzureStorageBlobContent的Blob。 此时,您可以在虚拟机上通知正在运行的应用程序(可能带有队列消息?),这是一个等待处理的文件。处理可以像将文件复制到VM的本地磁盘一样简单。

答案 3 :(得分:1)

  1. http://aka.ms/downloadazcopy
  2. 安装AzCopy
  3. 阅读以下文档:https://docs.microsoft.com/en-us/azure/storage/storage-use-azcopy
  4. cd&#34; C:\ Program Files(x86)\ Microsoft SDKs \ Azure \ AzCopy&#34;
  5. 获取Blob存储(辅助)密钥
  6. Powershell:Blob上传单个文件

  7.     .\AzCopy /Source:C:\myfolder /Dest:https://myaccount.blob.core.windows.net/mycontainer/myfolder/ /DestKey:key /Pattern:abc.txt

    1. 登录远程VM

    2. Powershell:Blob下载单个文件

    3.     .\AzCopy /Source:https://myaccount.file.core.windows.net/myfileshare/myfolder/ /Dest:C:\myfolder /SourceKey:key /Pattern:abc.txt

答案 4 :(得分:0)

另一种解决方案是使用Custom Extension Script 即使VM没有公共IP(专用网络),使用自定义扩展脚本也可以将文件复制到VM。所以你不需要配置winRm或任何东西。

我过去曾使用自定义扩展脚本进行部署后,例如在VM或Scale Set上安装应用。基本上,您将文件上传到blob存储,自定义扩展脚本将在VM上下载这些文件。

我在blob存储帐户上创建了test-container并上传了两个文件:

  • deploy.ps1:在VM上执行的脚本。
  • test.txt:一个带有&#34;来自VM&#34;
  • 的Hello world的文本文件

以下是deploy.ps1文件的代码:

Param(
    [string] [Parameter(Mandatory=$true)] $filename,
    [string] [Parameter(Mandatory=$true)] $destinationPath
)

# Getting the full path of the downloaded file
$filePath = $PSScriptRoot + "\" + $filename

Write-Host "Checking the destination folder..." -Verbose
if(!(Test-Path $destinationPath -Verbose)){
    Write-Host "Creating the destination folder..." -Verbose
    New-Item -ItemType directory -Path $destinationPath -Force -Verbose
}

Copy-Item $filePath -Destination $destinationPath -Force -Verbose

以下是将自定义脚本扩展添加到虚拟机的代码。

Login-AzureRMAccount

$resourceGroupName = "resourcegroupname"
$storageAccountName = "storageaccountname"
$containerName = "test-container"
$location = "Australia East"
$vmName = "TestVM"
$extensionName = "copy-file-to-vm"
$filename = "test.txt"
$deploymentScript = "deploy.ps1"
$destintionPath = "C:\MyTempFolder\"

$storageAccountKeys = (Get-AzureRmStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName).Value
$storageAccountKey = $storageAccountKeys[0]

Set-AzureRmVMCustomScriptExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name $extensionName -Location $location -TypeHandlerVersion "1.9" -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey -ContainerName $containerName -FileName $deploymentScript, $filename -Run $deploymentScript -Argument "$filename $destintionPath" -ForceRerun "1"

您可以在复制文件后删除扩展程序:

Remove-AzureRmVMCustomScriptExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name $extensionName -Force

在我的场景中,我有一个逻辑应用程序,每次将新文件添加到容器时都会触发该应用程序。逻辑应用程序调用一个Runbook(需要azure automation account),添加自定义脚本扩展,然后删除它。

答案 5 :(得分:0)

我能够在目标服务器上复制二进制文件,但无法安装,我在底部的deploy.ps1中使用以下语法

powershell.exe Start-Process -Wait  -PassThru msiexec -ArgumentList '/qn /i "c:\MyTempFolder\ddagent.msi" APIKEY="8532473174"'