
Microsoft 365 OneDrive for Business: Copy File / Folder
Microsoft 365 OneDrive for Business: ファイル / フォルダコピー
This item copies the specified file/folder to the specified folder on OneDrive.
Basic Configs
- Step Name
- Note
Configs for this Auto Step
- conf_OAuth2
- C1: OAuth2 Setting *
- conf_sourceUrl
- C2: Source File / Folder URL *
- conf_destUrl
- C3: Folder URL to store (The same folder as the Source if blank)
- conf_newName
- C4: New File / Folder Name *#{EL}
- conf_dataForUrl
- C5: Data item to save new file / folder URL
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”
Capture

See also
Script (click to open)
- An XML file that contains the code below is available to download
- onedrive-file-copy.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 GRAPH_URI = "https://graph.microsoft.com/v1.0/";
function main() {
//// == Config Retrieving / 工程コンフィグの参照 ==
const oauth2 = configs.get("conf_OAuth2");
const sourceUrl = retrieveSourceUrl();
const destUrl = retrieveDestUrl();
const newName = retrieveNewName();
const saveUrlDataDef = configs.getObject("conf_dataForUrl");
//// == Calculating / 演算 ==
// getting itemInfo for Requesting Copy and Updating Data
const sourceInfo = getItemInfoByUrl(sourceUrl, oauth2);
const destInfo = getItemInfoByUrl(destUrl, oauth2);
// sending Copy Request
const location = sendCopyRequest(sourceInfo, destInfo, newName, oauth2);
const driveId = destInfo.driveId ?? sourceInfo.driveId;
// コピー状況を確認し、未完了なら proceed() に進む
if (checkStatusAndSaveUrl(location, driveId, oauth2, saveUrlDataDef) === false) {
// location と driveId を一時データとして保存
const tempData = {location, driveId};
engine.saveTemporaryData(JSON.stringify(tempData));
return false;
}
}
function proceed() {
//// == Config Retrieving / 工程コンフィグの参照 ==
const oauth2 = configs.get("conf_OAuth2");
const saveUrlDataDef = configs.getObject("conf_dataForUrl");
//// == Restoring Temporary Data / 一時データの読み出し ==
const tempDataStr = engine.restoreTemporaryData();
if (tempDataStr === null) {
throw 'temporary data has not been saved';
}
const { location, driveId } = JSON.parse(tempDataStr);
if (checkStatusAndSaveUrl(location, driveId, oauth2, saveUrlDataDef) === false) {
return false;
}
}
/**
* config からコピー元アイテムの URL を読み出す
* 空の場合はエラー
* @return {String} sourceUrl
*/
function retrieveSourceUrl() {
const sourceUrlDef = configs.getObject("conf_sourceUrl");
let sourceUrl = configs.get("conf_sourceUrl");
if (sourceUrlDef !== null) {
sourceUrl = engine.findData(sourceUrlDef);
}
if (sourceUrl === "" || sourceUrl === null) {
throw `Source file / folder URL is empty.`;
}
return sourceUrl;
}
/**
* config からコピー先フォルダの URL を読み出す
* @return {String} destUrl
*/
function retrieveDestUrl() {
const destUrlDef = configs.getObject("conf_destUrl");
let destUrl = configs.get("conf_destUrl");
if (destUrlDef !== null) {
destUrl = engine.findData(destUrlDef);
}
return destUrl;
}
/**
* config から新しいファイル / フォルダの名前を読み出す
* @return {String} newName
*/
function retrieveNewName() {
const newName = configs.get("conf_newName");
if (newName === "" || newName === null) {
throw `New file / folder name is empty.`;
}
return newName;
}
/**
* ドライブアイテムのURLからアイテム情報(ドライブIDとアイテムID)を取得し、
* オブジェクトで返す(URLが空の場合はドライブIDもアイテムIDも空文字列)
* @param {String} driveItemUrl ドライブアイテム(ファイル、フォルダ)のURL
* @param {String} oauth2 OAuth2 認証設定
* @return {Object} itemInfo ドライブアイテム情報 {driveId, id}
*/
function getItemInfoByUrl(driveItemUrl, oauth2) {
let itemInfo = {};
if (driveItemUrl !== "" && driveItemUrl !== null) {
// 分割代入
const {
id,
parentReference: {
driveId
}
} = getObjBySharingUrl(driveItemUrl, oauth2);
itemInfo = {driveId, id};
}
return itemInfo;
}
/**
* 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);
// API Request
const response = httpClient.begin() // HttpRequestWrapper
.authSetting(oauth2) // Request HEADER (OAuth2 Token)
.get(`${GRAPH_URI}shares/${encodedSharingUrl}/driveItem`); // HttpResponseWrapper
const httpStatus = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (httpStatus >= 300) {
const accessLog = `---GET request--- ${httpStatus}\n${responseStr}\n`;
engine.log(accessLog);
throw `Failed to get drive item. status: ${httpStatus}`;
}
return JSON.parse(response.getResponseAsString());
}
/**
* 共有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}`;
}
/**
* copy リクエストを POST し、コピーステータス確認先 URL を返す
* @param {Object} sourceInfo コピー元アイテム情報 {driveId, id}
* @param {Object} destInfo コピー先フォルダ情報 {driveId, id}
* @param {String} newName 新しいファイル / フォルダの名前
* @param {String} oauth2 OAuth2 認証設定
* @return {String} location コピーステータス確認先 URL
*/
function sendCopyRequest(sourceInfo, destInfo, newName, oauth2) {
// Request PATH
const apiUri = `${GRAPH_URI}drives/${sourceInfo.driveId}/items/${sourceInfo.id}/copy`;
// Request BODY (JSON, Form Parameters, etc)
const requestBody = generateCopyRequestBody(destInfo, newName);
// API Request
const response = httpClient.begin() // HttpRequestWrapper
.authSetting(oauth2) // Request HEADER (OAuth2 Token)
.body(requestBody, "application/json")
.post(apiUri); // HttpResponseWrapper
const httpStatus = response.getStatusCode();
if (httpStatus >= 300) {
const accessLog = `---POST request--- ${httpStatus}\n${response.getResponseAsString()}\n`;
engine.log(accessLog);
throw `Failed to copy. status: ${httpStatus}`;
}
return response.getHeaderValues("Location").get(0);
}
/**
* copyリクエストのBODYを生成し、JSON文字列で返す
* @param {Object} destInfo コピー先フォルダ情報 {driveId, id}
* @param {String} newName 新しいファイル / フォルダの名前
* @return {JSON String} requestBody リクエストBODY
*/
function generateCopyRequestBody(destInfo, newName) {
const requestBodyObj = {};
if (destInfo.driveId !== undefined) {
requestBodyObj.parentReference = destInfo;
}
if (newName !== "" && newName !== null) {
requestBodyObj.name = newName;
}
return JSON.stringify(requestBodyObj);
}
/**
* コピーの完了状態を確認し、完了していれば新しいアイテムの URL を保存する
* コピー未完了の場合は false を返す
* @param {String} location コピーステータス確認用 URL
* @param {String} driveId 新しいアイテムのドライブ ID
* @param {String} oauth2 OAuth2 認証設定
* @param {DataDefinitionView} saveUrlDataDef URL を保存するデータ項目
* @return {boolean}
*/
function checkStatusAndSaveUrl(location, driveId, oauth2, saveUrlDataDef) {
const newItemId = checkStatusAndGetNewItemId(location);
if (newItemId === null) {
return false;
}
const newItemUrl = getItemUrlById(driveId, newItemId, oauth2);
if (saveUrlDataDef !== null) {
engine.setData(saveUrlDataDef, newItemUrl);
}
}
/**
* コピーの完了状態を確認し、新しいドライブアイテムのIDを返す
* コピー未完了の場合は null を返す
* @param {String} location コピーステータス確認用 URL
* @return {String} newItemId 新しいドライブアイテムのID
*/
function checkStatusAndGetNewItemId(location) {
const monitorResponseObj = getMonitorResponseObj(location);
const copyStatus = monitorResponseObj.status;
if (copyStatus === "notStarted" || copyStatus === "inProgress") {
// 未開始または進行中の場合、null を返す
engine.log(`Copy status: ${copyStatus}`);
return null;
}
if (copyStatus === "completed") {
// 完了の場合、ドライブアイテム ID を返す
engine.log(`Copy status: ${copyStatus}`);
return monitorResponseObj.resourceId;
}
// 不明なステータスの場合はエラー
engine.log(`error: ${JSON.stringify(monitorResponseObj.error)}`);
throw `Copy is not in progress nor completed. status: ${copyStatus}`;
}
/**
* copyの完了状態レポートを取得し、JSONオブジェクトを返す
* @param {String} location copy応答のLocationヘッダの値(コピー操作の現在の状況を返すサービスの URL)
* @return {Object} responseObj copy完了状態レポートのJSONオブジェクト
*/
function getMonitorResponseObj(location) {
const response = httpClient.begin() // HttpRequestWrapper
.get(location); // HttpResponseWrapper
const httpStatus = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (httpStatus >= 300) {
const accessLog = `---GET request--- ${httpStatus}\n${responseStr}\n`;
engine.log(accessLog);
throw `Failed to get monitor. status: ${httpStatus}`;
}
return JSON.parse(responseStr);
}
/**
* OneDriveのドライブアイテムのメタデータを取得し、URLを返す
* @param {String} driveId ドライブID
* @param {String} itemId アイテムID
* @param {String} oauth2 OAuth2 認証設定
* @return {String} webUrl ドライブアイテムのURL
*/
function getItemUrlById(driveId, itemId, oauth2) {
const response = httpClient.begin() // HttpRequestWrapper
.authSetting(oauth2) // Request HEADER (OAuth2 Token)
.get(`${GRAPH_URI}drives/${driveId}/items/${itemId}`); // HttpResponseWrapper
const httpStatus = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (httpStatus >= 300) {
const accessLog = `---GET request--- ${httpStatus}\n${responseStr}\n`;
engine.log(accessLog);
throw `Failed to get file. status: ${httpStatus}`;
}
const responseObj = JSON.parse(responseStr);
return responseObj.webUrl;
}
Pingback: Utilising OneDrive from Your Workflow – Questetra Support