PowerShellでChatworkにファイルをPOSTする


http://developer.chatwork.com/ja/endpoint_rooms.html#POST-rooms-room_id-files
このAPIを使って単にmultipart/form-dataでpostするだけ!
と思いきや成功が返ってくるのにアップロードされなかったので四苦八苦。
Content-Dispositionの内容やmessageにContent-Typeがあるとアップロードされないようです。

Invoke-RestMethod版

リクエストボディを気合いで作ります。一時的にファイルに書き出して使います。

# params
$filePath = "your/file/path.hoge"
$message = 'メッセージです'
$roomId = 'your chatwork room id'
$token = 'your chatwork token'


# body
$fileName = [System.IO.Path]::GetFileName($filePath)
$UTF8woBOM = New-Object "System.Text.UTF8Encoding" -ArgumentList @($false)
$boundary = '--------------------------n4nd3m011k3d0y0'
$tempFile = './tempfile'
$sw = New-Object System.IO.StreamWriter($tempFile, $false, $UTF8woBOM)
$sw.Write("$boundary`nContent-Disposition: form-data; name=`"message`"`n`n$message`n$boundary`nContent-Disposition: form-data; name=`"file`"; filename=`"$fileName`"`n`n")
$sw.Close()
$fs = New-Object System.IO.FileStream($tempFile, [System.IO.FileMode]::Append)
$bw = New-Object System.IO.BinaryWriter($fs)
$fileBinary = [System.IO.File]::ReadAllBytes($filePath)
$bw.Write($fileBinary)
$bw.Close()
$sw = New-Object System.IO.StreamWriter($tempFile, $true, $UTF8woBOM)
$sw.Write("`n$boundary--`n")
$sw.Close()

# post
Invoke-RestMethod -Method POST -Uri "https://api.chatwork.com/v2/rooms/$roomId/files" -Headers @{"X-ChatWorkToken" = $token} -ContentType "multipart/form-data; boundary=$boundary" -InFile $tempFile

HttpClient版

比較的スマート。日本語ファイル名は文字化けしてしまうのですがどうしても解決せず…。

# params
$filePath = "your/file/path.hoge"
$message = 'メッセージです'
$roomId = 'your chatwork room id'
$token = 'your chatwork token'


#
Add-Type -AssemblyName 'System.Net.Http'
$content = New-Object System.Net.Http.MultipartFormDataContent

# file
$fileStream = [System.IO.File]::OpenRead($filePath)
$fileContent = New-Object System.Net.Http.StreamContent($fileStream)
$fileName = [System.IO.Path]::GetFileName($filePath)

$fileContent.Headers.Add('Content-Disposition', "form-data; name=`"file`"; filename=`"$fileName`"");
$content.Add($fileContent)

# message
$StringContent = New-Object System.Net.Http.StringContent($message)
$StringContent.Headers.Add('Content-Disposition', 'form-data; name="message"');
$StringContent.Headers.Remove('Content-Type');
$content.Add($StringContent)

echo $content.ReadAsStringAsync()

# header
$content.Headers.Add('X-ChatWorkToken', $token)

# post
$url = "https://api.chatwork.com/v2/rooms/$roomId/files"
$client = New-Object System.Net.Http.HttpClient
$result = $client.PostAsync($url, $content).Result
$result.EnsureSuccessStatusCode()
echo $result.Content.ReadAsStringAsync()

参考:
https://sue445.hatenablog.com/entry/2018/08/02/111403
https://stackoverflow.com/questions/22491129/how-to-send-multipart-form-data-with-powershell-invoke-restmethod
https://get-powershellblog.blogspot.com/2017/09/multipartform-data-support-for-invoke.html
https://qiita.com/sin_tanaka/items/d57ea67351efc1994c48
https://ufcpp.net/study/csharp/lib_file.html
https://blog.shibata.tech/entry/2016/10/02/154329