Microsoft 365 OneDrive for Business: ファイル / フォルダコピー (Microsoft 365 OneDrive for Business: Copy File / Folder)
この工程は、OneDrive 上のファイル / フォルダを複製し、指定フォルダに新規保存します。
Configs:共通設定
  • 工程名
  • メモ
Configs
  • C1: OAuth2 設定 *
  • C2: コピー元ファイル / フォルダの URL *
  • C3: 保存先フォルダの URL (空白の場合、元ファイル / フォルダと同じ場所にコピーされます)
  • C4: 新しいファイル / フォルダの名前 *#{EL}
  • C5: 新しいファイル / フォルダの URL を保存するデータ項目

Notes

  • Microsoft 365 の OneDrive for Business で使用できる自動工程です。個人用の OneDrive では使用できません。
  • ファイルやフォルダの URL は、OneDrive でファイルやフォルダの詳細ウィンドウ(右上のiのアイコン)から「その他の詳細」へ進み、「パス」の隣のアイコンから取得します。(上部メニューの「共有」や「リンクのコピー」から取得した URL も使用できます)
    ファイル、フォルダURLの取得方法
  • OneDrive 側でのコピー処理の進捗状況によっては、「新しいファイル/フォルダのURL を保存するデータ項目」が空となる場合があります
    • 「新しいファイル/フォルダの URL を保存するデータ項目」が空の場合であっても、一定時間経過後には OneDrive 側でコピー処理が完了している見込みです

Capture

See also

Script (click to open)
  • 下記のスクリプトを記述した XML ファイルをダウンロードできます
    • onedrive-file-copy.xml (C) Questetra, Inc. (MIT License)
    • Professional をご利用であればファイルの内容を改変することでオリジナルのアドオンとして活用できます

  // 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/";

  main();
  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 / 演算 ==
    // checking the HTTP requesting limit
    checkHttpRequestingLimit( destUrl );
    // getting itemInfo for Requesting Copy and Updating Data
    const sourceInfo = getItemInfoByUrl( sourceUrl, oauth2 );
    const destInfo = getItemInfoByUrl( destUrl, oauth2 );
    // sending Copy Request
    const copyResponse = sendCopyRequest( sourceInfo, destInfo, newName, oauth2 );

    // コピー状況を確認し、ドライブアイテム ID を取得
    const newItemId = getNewItemId( copyResponse );

    // ワークフローデータへの代入データの作成
    const newItemUrl = getNewItemUrl( sourceInfo.driveId, destInfo.driveId, newItemId, oauth2 );

    //// == Data Updating / ワークフローデータへの代入 ==
    if ( saveUrlDataDef !== null ){
      engine.setData( saveUrlDataDef, newItemUrl );
    }
  }

  /**
    * configから値を読み出し、必要に応じて値チェックを行った後、値を返す
    * @return {String} configの値
    */
  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;
  }

  function retrieveDestUrl() {
    const destUrlDef = configs.getObject( "conf_destUrl" );
    let destUrl = configs.get( "conf_destUrl" );
    if ( destUrlDef !== null ) {
      destUrl = engine.findData( destUrlDef );
    }
    return destUrl;
  }

  function retrieveNewName() {
    const newName = configs.get( "conf_newName" );
    if ( newName === "" || newName === null ) {
      throw `New file / folder name is empty.`;
    }
    return newName;
  }

  /**
    * HTTPリクエストの上限を超えないか確認する
    * @param {String} destUrl  コピー先フォルダのURL
    */
  function checkHttpRequestingLimit( destUrl ) {
    const reqLimit = httpClient.getRequestingLimit();
    if ( destUrl !== "" && destUrl !== null ) {
      if ( reqLimit < 5 ) {
        throw `HTTP requesting limit is fewer than necessary requests.`;
      }
    } else if ( reqLimit < 4 ) {
      throw `HTTP requesting limit is fewer than neceessary requests.`;
    }
  }

  /**
    * ドライブアイテムの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 = {driveId: "", id: ""};
    if ( driveItemUrl !== "" && driveItemUrl !== null ) {
      // 分割代入
      const {
        id: id,
        parentReference: {
          driveId: driveId
        }
      } = getObjBySharingUrl( driveItemUrl, oauth2 );
      itemInfo = {driveId: driveId, id: 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し、レスポンスを返す
    * @param {String} sourceInfo  コピー元アイテム情報 {driveId, id}
    * @param {String} destInfo  コピー先フォルダ情報 {driveId, id}
    * @param {String} newName  新しいファイル / フォルダの名前
    * @param {String} oauth2  OAuth2 認証設定
    * @return {HttpResponseWrapper} response  レスポンス
    */
  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;
  }

  /**
    * copyリクエストのBODYを生成し、JSON文字列で返す
    * @param {Object} destInfo  コピー先フォルダ情報 {driveId, id}
    * @param {String} newName  新しいファイル / フォルダの名前
    * @return {JSON String} requestBody  リクエストBODY
    */
  function generateCopyRequestBody( destInfo, newName ) {
    let requestBodyObj = {};
    if ( destInfo.driveId !== "" ) {
      requestBodyObj.parentReference = {
        driveId: destInfo.driveId,
        id: destInfo.id
      };
    }
    if ( newName !== "" && newName !== null ) {
      requestBodyObj.name = newName;
    }
    return JSON.stringify( requestBodyObj );
  }

  /**
    * コピーAPIのレスポンスからコピーの完了状態を確認し、新しいドライブアイテムのIDを返す
    * @param {HttpResponseWrapper} copyResponse  コピーAPIのレスポンス
    * @return {String} newItemId  新しいドライブアイテムのID
    */
  function getNewItemId( copyResponse ) {
    const location = copyResponse.getHeaderValues("Location").get(0);
    const monitorResponseObj = getMonitorResponseObj( location );
    const copyStatus = monitorResponseObj.status;
    let newItemId = "";
    if ( copyStatus === "notStarted" || copyStatus === "inProgress" ) {
      // 未開始または進行中の場合、newItemId は空文字列のまま
      engine.log(`Copy status: ${copyStatus}\nTo retrieve copy status, GET ${location}\n`);
    } else if ( copyStatus === "completed" ) {
      // 完了の場合、ドライブアイテムIDを取得
      engine.log(`Copy status: ${copyStatus}\n`);
      newItemId = monitorResponseObj.resourceId;
    } else {
      // 不明なステータスの場合はエラー
      engine.log(`error: ${JSON.stringify( monitorResponseObj.error )}\n`);
      throw `Copy is not in progress nor completed. status: ${copyStatus}`;
    }
    return newItemId;
  }

  /**
    * copyの完了状態レポートを取得し、JSONオブジェクトを返す
    * @param {String} location  copy応答のLocationヘッダの値(コピー操作の現在の状況を返すサービスの URL)
    * @return {Object} responseObj  copy完了状態レポートのJSONオブジェクト
    */
  function getMonitorResponseObj( location ) {
    // API Request
    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 );
  }

  /**
    * 新しいファイル / フォルダのURLを返す
    * @param {String} driveIdOfSource  コピー元アイテムのドライブのID(フォルダのドライブIDが空文字列の場合に使用)
    * @param {String} driveIdOfDest  コピー先フォルダのドライブID
    * @param {String} newItemId  新しいファイル/ フォルダのID
    * @param {String} oauth2  OAuth2 認証設定
    * @return {String} newItemUrl  新しいファイル / フォルダのURL
    */
  function getNewItemUrl( driveIdOfSource, driveIdOfDest, newItemId, oauth2 ) {
    let newItemUrl = "";
    // ドライブIDを決める(コピー先フォルダのドライブIDが空文字列でなければフォルダのドライブID)
    let driveId = driveIdOfSource;
    if ( driveIdOfDest !== "" ) {
      driveId = driveIdOfDest;
    }
    if ( newItemId !== "" ) {
      newItemUrl = getItemUrlById( driveId, newItemId, oauth2 );
    }
    return newItemUrl;
  }

  /**
    * OneDriveのドライブアイテムのメタデータを取得し、URLを返す
    * @param {String} driveId  ドライブID
    * @param {String} itemId  アイテムID
    * @param {String} oauth2  OAuth2 認証設定
    * @return {String} webUrl  ドライブアイテムのURL
    */
  function getItemUrlById( driveId, itemId, oauth2 ) {
    if (itemId === "" || itemId === null) {
      throw `DriveItem ID is empty.`;
    }
    if (driveId === "" || driveId === null) {
      throw `Drive ID is empty.`;
    }

    // API Request
    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;
  }

「Microsoft 365 OneDrive for Business: ファイル / フォルダコピー」への1件のフィードバック

  1. ピンバック: ワークフローから OneDrive を活用する – Questetra Support

コメントは受け付けていません。

%d人のブロガーが「いいね」をつけました。