Carregar um arquivo para Box.com usando Powershell
-
26-12-2019 - |
Pergunta
Estou trabalhando em uma série de scripts Powershell para minha empresa usar para transferir dados de e para Box.com.A única coisa que não consigo descobrir é o upload de arquivos.A API Box requer uma operação POST multiparte para uploads, e vi algumas respostas aqui no SO indicando que devo ser capaz de fazer isso no Powershell (como Este).Mas não consigo fazê-lo funcionar.
Aqui está o código que tenho agora:
Function Post-File {
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$SourcePath,
[Parameter(Mandatory=$False,Position=2)]
[string]$FolderId = ############
)
#Variables for building URIs
$baseUrl = "https://upload.box.com/api/2.0/files/content"
#Set Authorization for API requests
$headers = @{}
$AccessToken = Refresh-Tokens #A reference to another function that definitely works
$headers.Add("Authorization", "Bearer $AccessToken")
#Set POST content
$body = @{}
$body.Add("filename", [IO.File]::ReadAllBytes($SourcePath))
$body.Add("parent_id", $FolderId)
#Upload the file
Invoke-RestMethod -Uri $baseUrl -Method Post -Headers $headers -ContentType "multipart/form-data" -Body $body
}
Aqui está a resposta que recebo:
{
"type":"error",
"status":400,
"code":"invalid_request_parameters",
"help_url":"http://developers.box.com/docs/#errors",
"message":"Invalid input parameters in request",
"request_id":"1764475572534bcddfe04b7"
}
Também tentei algumas outras permutações que não estão funcionando.Eu tentei usar o -InFile
alternar em Invoke-RestMethod
em vez de -Body
.Eu também tentei usar Get-Content -Raw
no lugar de [IO.File]::ReadAllBytes
.Ambos retornam um erro mais genérico: The server encountered an internal error or misconfiguration and was unable to complete your request.
.
Tenho certeza de que isso tem algo a ver com o meu filename
parâmetro não está correto, mas não sei como corrigi-lo.De acordo com API de caixa, aqui está como deve ficar em curl.Alguém pode me ajudar a traduzir isso corretamente para o Powershell?
https://upload.box.com/api/2.0/files/content \
-H "Authorization: Bearer ACCESS_TOKEN" \
-F filename=@FILE_NAME \
-F parent_id=PARENT_FOLDER_ID
Solução
Há algumas coisas que tornam isso um pouco complicado no PowerShell:
- O
filename
parâmetro especifica o nome do arquivo, não o conteúdo. - Um corpo de solicitação é necessário para especificar o nome e o destino do arquivo.
- Guloseimas do PowerShell
-InFile
e-Body
argumentos como mutuamente exclusivos. - O PowerShell não parece oferecer suporte nativo
multipart/form-data
POSTs, de acordo com o pergunta que você referiu.
Como o corpo da solicitação é necessário (1,2) - e, portanto, -InFile
não pode ser usado (3) - acho que você pode precisar criar o seu próprio multipart/form-data
corpo (4) que contém os metadados e o conteúdo do arquivo necessários. Esta postagem do blog descreve um método para fazer isso.O conteúdo é uma sequência curta (um tweet), mas o princípio é o mesmo.
Abaixo está um rastreamento do Fiddler de um upload que acabei de realizar usando o Box Windows SDK.Isso mostra como a solicitação deve ficar à medida que passa pela rede.O $BOUNDARY
é uma string arbitrária e única - um GUID funciona muito bem.
POST https://upload.box.com/api/2.0/files/content HTTP/1.1
Authorization: Bearer $TOKEN
Content-Type: multipart/form-data; boundary="$BOUNDARY"
Host: upload.box.com
Content-Length: 2118
Accept-Encoding: gzip, deflate
--$BOUNDARY
Content-Disposition: form-data; name="file"; filename="$FILENAME"
<THE CONTENT OF $FILENAME>
--$BOUNDARY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name="metadata"
{"parent":{"id":"$PARENT_FOLDER_ID"},"name":"$FILENAME"}
--$BOUNDARY--
Aqui está a resposta que recebi:
HTTP/1.1 201 Created
Date: Mon, 14 Apr 2014 12:52:33 GMT
Server: Apache
Cache-Control: no-cache, no-store
Content-Length: 364
Connection: close
Content-Type: application/json
{"total_count":1,"entries":[{"type":"file","id":"$ID","name":"$FILENAME", ... }]}
Outras dicas
Posso parecer idiota, mas o que acontece quando você faz isso?
$body.Add("filename", $([IO.File]::ReadAllBytes($SourcePath)))