Windows Azure Powershell копирование файла в виртуальную машину
Я пытаюсь использовать Windows Azure PowerShell для копирования zip-файла в виртуальную машину. Мне удалось подключиться к VM после документации.
но я не могу найти учебник для загрузки / копирования / передачи zip-файла на диск VM, скажем, на диск C.
может ли кто-нибудь помочь мне дать любую ссылку на учебник или любую идею, как я могу это скопировать?
5 ответов
PowerShell нельзя использовать для копирования файла непосредственно на диск ОС виртуальной машины (или даже на один из подключенных дисков). Нет API для прямой связи с внутренностями виртуальной машины (для этого вам нужно создать собственную пользовательскую службу.
вы can используйте PowerShell для загрузки файла в Blob с помощью Set-AzureStorageBlobContent
.
В этот момент Вы можете уведомить свое запущенное приложение (возможно, с сообщением очереди?) на вашей виртуальной машине, которую ждет файл его обработать. И обработка может быть такой же простой, как копирование файла на локальный диск виртуальной машины.
вот такой подход, который я задокументировал здесь. Это включает
- создание и установка пустого локального VHD.
- копирование файлов на новый VHD и его демонтаж.
- скопируйте VHD в хранилище Azure blob
- прикрепите этот VHD к вашей виртуальной машине.
вот пример:
#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
вот код, который я получил из некоторых примеров 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
}
}
}
- установить AzCopy из http://aka.ms/downloadazcopy
- чтение документов из:https://docs.microsoft.com/en-us/azure/storage/storage-use-azcopy
- cd "C:\Program файлы (x86)\Microsoft SDKs\Azure\AzCopy"
- Получить Blob-Хранилище (Вторичный) Ключ
Powershell: Blob загрузить один файл
.\AzCopy /Source:C:\myfolder /Dest:https://myaccount.blob.core.windows.net/mycontainer/myfolder/ /DestKey:key /Pattern:abc.txt
вход для дистанционного VM
Powershell: Blob скачать один файл
.\AzCopy /Source:https://myaccount.file.core.windows.net/myfileshare/myfolder/ /Dest:C:\myfolder /SourceKey:key /Pattern:abc.txt
другое решение-использовать Пользовательский Сценарий Расширения.
Использование пользовательского сценария расширения позволяет копировать файл на виртуальную машину, даже если у нее нет общедоступного ip-адреса (частной сети). Поэтому вам не нужно настраивать winRm или что-то еще.
в прошлом я использовал пользовательские скрипты расширения для пост-развертывания, такие как установка приложения на виртуальной машине или в масштабе. В основном вы загружаете файлы в хранилище blob, и пользовательский скрипт расширения загружает этот файл на виртуальной машине.
Я создал test-container
на моей учетной записи хранения blob и загрузил два файла:
-
deploy.ps1
: скрипт, выполняемый на виртуальной машине. -
test.txt
: текстовый файл с надписью "Hello world from VM"
здесь код :
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), которые добавляют расширение пользовательского скрипта, а затем удаляют его.