
Microsoft 365 OneDrive for Business: Upload File
Microsoft 365 OneDrive for Business: ファイルアップロード
This item uploads files to the specified folder on OneDrive.
Configs for All Step
- Step Name
- Note
Configs for this Auto Step
- conf_OAuth2
- C1: OAuth2 Setting *
- conf_uploadedFile
- C2: Data item whose attached files will be uploaded *
- conf_folderUrl
- C3: Folder URL files will be uploaded (Root folder if blank)
- conf_shouldReplace
- C4: Replace if the file with the same name already exists
- conf_fileUrl
- C5: Data item to save uploaded file URLs
Notes
- This Auto Step is for OneDrive for Business of Microsoft 365
- It does not work for OneDrive personal
- To get the URL of a file/folder on OneDrive, open the Details window of the file/folder by clicking the Information icon, proceed to “More details”, and click the icon next to “Path”
- Files over 4MB will be divided into 10MB parts
- In this case, number of sending requests is expressed by the expression (file size ÷ 10MB) + 1 (you should round up the result of calculation in parenthesis)
- 1MB = 1,048,576 (1024 * 1024) byte
Capture

See also
Script (click to open)
- An XML file that contains the code below is available to download
- onedrive-file-upload.xml (C) Questetra, Inc. (MIT License)
- If you are using Professional, you can modify the contents of this file and use it as your own add-on auto step
// OAuth2 config sample at [OAuth 2.0 Setting]
// - Authorization Endpoint URL: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
// - Token Endpoint URL: https://login.microsoftonline.com/common/oauth2/v2.0/token
// - Scope: https://graph.microsoft.com/Files.ReadWrite.All offline_access
// - Consumer Key: (Get by Microsoft Azure Active Directory)
// - Consumer Secret: (Get by Microsoft Azure Active Directory)
const LIMIT_SIZE = 4194304; //File size border of Microsoft Graph
const PACKET_MAX_SIZE = 10485760; //size of each packet,must be a multiple of 327680(320KiB): 10485760=10MiB
const GRAPH_URI = "https://graph.microsoft.com/v1.0/";
main();
function main() {
//// == 工程コンフィグの参照 / Config Retrieving ==
const oauth2 = configs.get("conf_OAuth2");
const folderUrl = retrieveFolderUrl();
const urlDataDef = configs.getObject("conf_fileUrl");
const shouldReplace = configs.getObject("conf_shouldReplace");
//// == ワークフローデータの参照 / Data Retrieving ==
const files = engine.findData(configs.getObject("conf_uploadedFile"));
if (files === null) {
setData(urlDataDef, [""]);
return;
}
//// == 演算 / Calculating ==
fileCheck(files, urlDataDef, folderUrl);
const folderInfo = getFolderInfoByUrl(folderUrl, oauth2);
const uploadedFileUrl = [];
files.forEach(file => {
engine.log(`Uploading: ${file.getName()}`);
if (file.getLength() > LIMIT_SIZE) {
//over 4MB
processLargeFile(oauth2, file, folderInfo, shouldReplace, uploadedFileUrl);
} else {
//under 4MB
upload(oauth2, file, folderInfo, shouldReplace, uploadedFileUrl);
}
});
//// == ワークフローデータへの代入 / Data Updating ==
setData(urlDataDef, uploadedFileUrl);
}
/**
* configからフォルダURLの値を読み出す
* @return {String} configの値
*/
function retrieveFolderUrl() {
const folderUrlDef = configs.getObject("conf_folderUrl");
let folderUrl = "";
if (folderUrlDef === null) {
folderUrl = configs.get("conf_folderUrl");
} else {
folderUrl = engine.findData(folderUrlDef);
}
return folderUrl;
}
/**
* アップロードしようとするファイルの名前・数・サイズが適切かどうかチェックする
* ファイル数、通信制限をチェック
* 通信数=4MB以下のファイルの数 + <4MBを超えるファイルそれぞれについて>(ceil(ファイルサイズ/パケットの最大サイズ) + 1)
* その後ファイル名をチェック
* @param {Array<File>} files アップロードしようとするファイル
* @param {ProcessDataDefinitionView} urlDataDef URL を保存するデータ項目の ProcessDataDefinitionView
* @param {String} folderUrl アップロード先フォルダの URL
*/
function fileCheck(files, urlDataDef, folderUrl) {
fileNumCheck(urlDataDef, files.size());
let requestNum = 0;
files.forEach(file => {
const size = file.getLength();
if (size > LIMIT_SIZE) {
requestNum += (Math.ceil(size / PACKET_MAX_SIZE) + 1);
} else {
requestNum++;
}
});
if (folderUrl !== "" && folderUrl !== null) {
requestNum++;
}
if (requestNum > httpClient.getRequestingLimit()) {
throw "Necessary HTTP requests exceeds the limit.";
}
checkFileNameOverlap(files);
}
/**
* アップロードするデータが複数で URL 出力先のデータ項目が単一行ならエラーにする
* @param {ProcessDataDefinitionView} dataDef データ項目の ProcessDataDefinitionView
* @param {Number} fileNum アップロードしようとしているファイルの個数
*/
function fileNumCheck(dataDef, fileNum) {
if (dataDef !== null) {
//Multiple Judge
if (dataDef.matchDataType("STRING_TEXTFIELD") && fileNum > 1) {
throw "Multiple files are set though the Data Item to save the output is Single-line String."
}
}
}
/**
* アップロードするファイルの中に同じファイル名のものが2つ以上あればエラー
* @param {Array<File>} アップロードしようとするファイルの配列
*/
function checkFileNameOverlap(files) {
const fileNames = new Set();
files.forEach(file => {
if (fileNames.has(file.getName())) {
throw "Two or more files to upload have the same name.";
}
fileNames.add(file.getName());
});
}
/**
* フォルダのURLからフォルダ情報(ドライブIDとフォルダID)を取得し、
* オブジェクトで返す(URLが空の場合はドライブIDをme/drive、フォルダIDをrootにする)
* @param {String} folderUrl フォルダのURL
* @param {String} oauth2 OAuth2 設定情報
* @return {Object} folderInfo フォルダ情報 {driveId, folderId}
*/
function getFolderInfoByUrl(folderUrl, oauth2) {
let folderInfo = { driveId: "me/drive", folderId: "root" };
if (folderUrl !== "" && folderUrl !== null) {
// 分割代入
const {
id,
parentReference: {
driveId
}
} = getObjBySharingUrl(folderUrl, oauth2);
folderInfo = { driveId: `drives/${driveId}`, folderId: id };
}
return folderInfo;
}
/**
* OneDriveのドライブアイテム(ファイル、フォルダ)のメタデータを取得し、JSONオブジェクトを返す
* APIの仕様: https://docs.microsoft.com/ja-jp/onedrive/developer/rest-api/api/shares_get?view=odsp-graph-online
* @param {String} sharingUrl ファイルの共有URL
* @param {String} oauth2 OAuth2 設定情報
* @return {Object} responseObj ドライブアイテムのメタデータのJSONオブジェクト
*/
function getObjBySharingUrl(sharingUrl, oauth2) {
if (sharingUrl === "" || sharingUrl === null) {
throw "Sharing URL is empty.";
}
// encoding sharing URL
const encodedSharingUrl = encodeSharingUrl(sharingUrl);
// preparing for API Request
const response = httpClient.begin()
.authSetting(oauth2)
.get(`${GRAPH_URI}shares/${encodedSharingUrl}/driveItem`);
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status >= 300) {
engine.log(`status: ${status}`);
engine.log(responseStr);
throw "Failed to get drive item.";
}
return JSON.parse(responseStr);
}
/**
* 共有URLをunpadded base64url 形式にエンコードする
* @param {String} sharingUrl 共有URL
* @return {String} encodedSharingUrl エンコードされた共有URL
*/
function encodeSharingUrl(sharingUrl) {
let encodedSharingUrl = base64.encodeToUrlSafeString(sharingUrl);
while (encodedSharingUrl.slice(-1) === '=') {
encodedSharingUrl = encodedSharingUrl.slice(0, -1);
}
return `u!${encodedSharingUrl}`;
}
/**
* ファイルをアップロードする。一回につき一つのみ。
* @param {String} oauth2 OAuth2 設定情報
* @param {File} file アップロードするファイル
* @param {String,String} driveId,folderId アップロード先ドライブ、フォルダのID
* @param {boolean} shouldReplace 上書きするかどうか
* @param {Array<String>} uploadedFileUrl アップロードしたファイルのURLを格納する配列
*/
function upload(oauth2, file, {
driveId,
folderId
}, shouldReplace, uploadedFileUrl) {
const url = `${GRAPH_URI}${driveId}/items/${folderId}:/${encodeURIComponent(file.getName())}:/content`;
let request = httpClient.begin()
.authSetting(oauth2)
.body(file, "application/octet-stream");
if (!shouldReplace) { // デフォルトは replace
request = request.queryParam("@microsoft.graph.conflictBehavior", "fail");
}
const response = request.put(url);
const responseStr = response.getResponseAsString();
const status = response.getStatusCode();
if (status >= 300) {
//when error thrown
engine.log(`Status: ${status}`);
engine.log(responseStr);
throw "Failed to upload";
}
engine.log("Succeeded to upload.");
outputDataSet(responseStr, uploadedFileUrl);
}
/**
* 4MBを超えるファイルのアップロード処理を行う
* @param {String} oauth2 OAuth2 設定情報
* @param {File} file アップロードするファイル
* @param {String,String} driveId,folderId アップロード先ドライブ、フォルダのID
* @param {boolean} shouldReplace 上書きするかどうか
* @param {Array<String>} uploadedFileUrl アップロードしたファイルのURLを格納する配列
*/
function processLargeFile(oauth2, file, {
driveId,
folderId
}, shouldReplace, uploadedFileUrl) {
const upUrl = createSession(oauth2, file.getName(), {
driveId,
folderId
}, shouldReplace);
let range = 0;
const fileSize = file.getLength();
fileRepository.readFile(file, PACKET_MAX_SIZE, function (packet) {
//upload each fragment of file
range = uploadLarge(upUrl, range, packet, fileSize, uploadedFileUrl);
});
}
/**
* アップロード用のセッションを作成する
* @param {String} oauth2 OAuth2 設定情報
* @param {String} fileName アップロードするファイルのファイル名
* @param {String,String} driveId,folderId アップロード先ドライブ、フォルダのID
* @param {boolean} shouldReplace 上書きするかどうか
* @return {String} アップロード先 URL
*/
function createSession(oauth2, fileName, {
driveId,
folderId
}, shouldReplace) {
const url = `${GRAPH_URI}${driveId}/items/${folderId}:/${encodeURIComponent(fileName)}:/createUploadSession`;
let request = httpClient.begin()
.authSetting(oauth2);
if (!shouldReplace) { // デフォルトは replace
const body = {
"item": {
"@microsoft.graph.conflictBehavior": "fail"
}
}
request = request.body(JSON.stringify(body), "application/json; charset=UTF-8");
}
const response = request.post(url);
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status >= 300) {
engine.log(`Status: ${status}`);
engine.log(responseStr);
throw "Failed to create upload session";
}
return JSON.parse(responseStr).uploadUrl;
}
/**
* 4MBを超えるファイルについて、各部分のアップロードを実行する
* @param {String} upUrl アップロード先 URL
* @param {Number} range これまでにアップロードしたサイズ
* @param {ByteArrayWrapper} packet アップロードするバイナリ
* @param {Number} fileSize アップロードするファイルのサイズ
* @param {Array<String>} uploadedFileUrl アップロードしたファイルのURLを格納する配列
* @return {Number} 新しい range
*/
function uploadLarge(upUrl, range, packet, fileSize, uploadedFileUrl) {
const packetSize = packet.getLength();
const rangetxt = `bytes ${range}-${range + packetSize - 1}/${fileSize}`;
const response = httpClient.begin()
.header("Content-Range", rangetxt)
.body(packet, "application/octet-stream")
.put(upUrl);
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status >= 300) {
engine.log(`Status: ${status}`);
engine.log(responseStr);
throw "Failed to upload";
} else if (status === 202) {
range += packetSize;
return range;
} else {
engine.log("Succeeded to upload.");
outputDataSet(responseStr, uploadedFileUrl);
return range;
}
}
/**
* アップロードしたデータのURLを配列にセットする。
* @param {String} responseStr 送信時のレスポンスをテキスト出力したもの
* @param {Array<String>} uploadedFileUrl アップロードしたファイルのURLを格納する配列
*/
function outputDataSet(responseStr, uploadedFileUrl) {
const json = JSON.parse(responseStr);
uploadedFileUrl.push(json.webUrl);
}
/**
* アップロードしたデータのURLをデータ項目に出力する。
* @param {ProcessDataDefinitionView} dataDef データ項目の ProcessDataDefinitionView
* @param {Array<String>} uploadedFileUrl アップロードしたファイルのURLを格納する配列
*/
function setData(dataDef, uploadedFileUrl) {
if (dataDef !== null) {
engine.setData(dataDef, uploadedFileUrl.join('\n'));
}
}
Pingback: Utilising OneDrive from Your Workflow – Questetra Support