はじめに
【Excel VBA】別ブックからデータを抜き出す処理(その1)では、「取得セル設定」シート上に置いたマーカー文字列(#1、#2…)をCells.Findで検索し、見つかったセル番地を別シートに記録する処理を解説しました。この番地は、続く「その2」で別ブックを開いてデータをピンポイントで抜き出す際の「地図」として使われます。
今回はこのその1にあたる処理を生成AIでOffice Scriptsに変換し、実際にExcel on the webで動かして検証します。まだ別ブックを開く処理は登場しないため、PAD(Power Automate for Desktop)は使わず、Office Scripts単体での検証です。
なお、本記事では検証用のサンプルファイルは提供していません(次回その2で提供予定です)。同じシート構成(「Main」シート・「取得セル設定」シート)で試したい場合は、元記事「別ブックからデータを抜き出す処理(その1)」内でダウンロードできるVBA版のサンプルファイルをご利用ください。
注意: 本記事は実際にExcel on the webで手を動かして検証しています。AIが最初に出したコードはそのままでは動かず、2回のエラーを経て修正しています。つまずいた点もそのまま掲載します。
今回の検証結果(先に結論)
| 項目 | 結果 |
|---|---|
VBAのCells.Findに相当するメソッド | ❌ WorksheetにもRangeにも直接のFind系メソッドは存在しなかった(詳細は後述) |
| マーカー文字列からのセル番地取得 | ✅ Find系APIを使わず、値の配列を自前でスキャンする方式で実現できた |
| セル番地の表記形式 | ⚠️ getAddressLocal()はシート名付きで返るため、文字列処理での加工が必要だった |
| スクリプトのボタン割り当て | ✅ 「挿入」→「ボタン」から可能。VBAと同様の操作感で実行できる |
要点: VBAのFindメソッドは非常によく使われますが、Office Scriptsには同名・同用途のAPIがそのまま存在しません。AIが生成したコードも実在しないメソッドを使っていたため、値配列を自前でスキャンする方式に置き換えることで解決しました。
元になるVBAコードのおさらい
その1のVBAコードは、以下のように「Main」シートの設定(マーカー記号・設定シート名)を読み取り、設定シート内をマーカー記号で検索してセル番地を記録します。
'ターゲットのセル番地を取得する処理
'同じ符号を複数付けた場合最初に見つかった1個だけになります
Sub GetTargetCells()
Dim strTarget As String
Dim strMark As String
Dim i As Long, m As Long
Dim FCell As Range
Dim strFind As String
Dim shSeting As String
With WorkSheets("Main")
shSeting = .Range("F2") 'Target設定用シート名
.Range("C:D").Clear 'Targetセル番地保存エリアをクリア
strMark = .Range("B2") 'Targetの設定用符号をセット
Sheets(shSeting).Activate 'Target設定用シートをアクティブに
m = Application.CountIf(Cells, strMark & "*") 'Targetの数を調べる
For i = 1 To m
strTarget = strMark & i '符号+番号
Set FCell = Cells.Find(What:=strTarget) 'Findメソッド
If FCell Is Nothing Then
strFind = "見つかりません"
Else
strFind = FCell.Address 'Targetのアドレス代入
End If
.Cells(i, 3) = strTarget
.Cells(i, 4).Formula = strFind
Next
.Activate
End With
End Subポイントは3つです。
Application.CountIf(Cells, strMark & "*"):ワイルドカードで「マーカー記号から始まるセル」の数を数える- 符号+番号で順番にFindメソッドでセル番地を取得し、シートに「符号+番号」と「セル番地」を書き込んでいく
Cells.Find(What:=strTarget):見つからなければNothingが返る。この分岐でエラーを防いでいる
生成AIにOffice Scripts変換を依頼する
第4回で得た知見(AIは「動きそうなコード」を出すが、Office Scripts特有のAPI差異を把握していないことがある)を踏まえ、以下を明示してAIに変換を依頼しました。
- 対象VBAコードと処理の目的(マーカー符号をFindで検索し、セル番地を記録する)
- Office Scripts(TypeScript/ExcelScript API)への変換であること
Cells.Findが見つからない場合Nothingを返す挙動を、Office Scripts側でどう置き換えるか
1回目:AIの変換結果でエラー
AIはWorksheetに対してfindOrNullObjectを呼び出すコードを生成しましたが、実行するとエラーになりました。

Property 'findOrNullObject' does not exist on type 'Worksheet'.
findOrNullObjectはWorksheetではなくRangeのメソッドだったため、getUsedRange()で取得したRangeに対して呼び出す形にAIがコードを修正しました。
2回目:正しい作法で呼び出しても別のエラー
findOrNullObjectは本来Rangeに対して呼び出すのが正しい作法です(Microsoft Learn: Excel アドイン用 JavaScript APIのドキュメントにも記載があります)。そこでgetUsedRange()で取得したRangeに対して呼び出すよう修正しましたが、今度は次のエラーになりました。

Property 'findOrNullObject' does not exist on type 'Range'.
ここで気づいたのは、上記のMicrosoft Learnのドキュメントは「Excel アドイン用 JavaScript API」(Excel名前空間)のものであり、今回使っているOffice Scripts(ExcelScript名前空間)とは別のAPIセットだという点です。両者は似ていますが同一ではなく、アドイン用APIのメソッドがすべてOffice Scriptsに移植されているわけではありません。正しい作法(Rangeに対して呼び出す)で試しても存在しないエラーになったことから、少なくとも今回の検証環境では、Office Scriptsの型定義にfindOrNullObject自体が含まれていないと判断しました。
3回目:Find系APIを使わない方式に変更して成功
方針を変え、Find系のメソッドを一切使わず、getValues()で取得済みの値配列を自前でスキャンしてマーカー文字列とセル番地の対応表(Map)を作る方式にしたところ、正常に動作しました。
function main(workbook: ExcelScript.Workbook) {
const mainSheet = workbook.getWorksheet("Main");
const settingSheetName = mainSheet.getRange("F2").getValue() as string;
// Target番地保存エリア(C:D列)をクリア
mainSheet.getRange("C:D").clear(ExcelScript.ClearApplyTo.contents);
const mark = mainSheet.getRange("B2").getValue() as string;
const settingSheet = workbook.getWorksheet(settingSheetName);
settingSheet.activate();
const usedRange = settingSheet.getUsedRange();
const values = usedRange.getValues();
// マーカー文字列 → セル番地 のマップを、値配列を自前でスキャンして作る
const addressMap = new Map<string, string>();
for (let r = 0; r < values.length; r++) {
for (let c = 0; c < values[r].length; c++) {
const cellValue = values[r][c];
if (typeof cellValue === "string" && cellValue.indexOf(mark) === 0) {
const fullAddress: string = usedRange.getCell(r, c).getAddressLocal();
// "取得セル設定!A1" のようにシート名が付くため、"!"より後ろだけを取り出す
const address: string = fullAddress.includes("!") ? fullAddress.split("!")[1] : fullAddress;
addressMap.set(cellValue, address);
}
}
}
const m = addressMap.size;
for (let i = 1; i <= m; i++) {
const target = `${mark}${i}`;
const address: string = addressMap.has(target) ? addressMap.get(target) : "見つかりません";
mainSheet.getRange("C" + i).setValue(target);
mainSheet.getRange("D" + i).setValue(address);
}
}実際に動かして検証する
「Main」シートにマーカー記号(★)と設定シート名(取得セル設定)を設定し、「取得セル設定」シートに★1〜★12をバラバラに配置した状態で実行しました。
1回目・2回目の実行:上記の通りエラーで停止
3回目(自前スキャン方式)の実行:「スクリプトが正常に実行されました。」と表示され、C列・D列に★1〜★12とそれぞれの取得セル番地のペアが正しく書き出されました。
ただし、D列の値が取得セル設定!A1のようにシート名付きで書き出されていました。VBA版の.Addressはシート名を含まないA1形式だったため、"!"で文字列を分割してシート名部分を取り除く処理を追加し、最終的にA1・C2のようなシート名なしの番地で記録できることを確認しました。

さらに2つの課題が見つかった
エラーなく動作するようになった後、実機であらためて確認したところ、VBA版との挙動の違いが2つ見つかりました。
課題1:「Main」シートで実行したのに「取得セル設定」シートが開いたままになる
VBAの元コードを見直すと、Sheets(shSeting).Activateで設定シートに切り替えた後、処理の最後に.Activate(With WorkSheets("Main")ブロック内なので実質WorkSheets("Main").Activate)でMainシートに戻す処理が入っていました。Office Scripts版はこの「戻す」部分が抜けており、実行後に「取得セル設定」シートが開いたままになっていました。
課題2:セル番地が相対参照(A1)になっている
VBA版のFCell.Addressは既定で絶対参照形式($A$1)を返しますが、Office ScriptsのgetAddressLocal()は相対参照形式(A1)で返ってきます。
一度目の修正:処理の最後にMainシートへ戻す
VBAと同じく、処理の最後にmainSheet.activate()を追加し、絶対参照への変換も加えて再検証しました。動作上は問題ありませんでしたが、ここで実機ならではの気づきがありました。VBAはシート切り替えが一瞬で終わるため気にならなかったのに対し、Office Scriptsはシート遷移が画面上ではっきり見えてしまい、体感的に気になるという点です。
最終的な修正:そもそもシートを切り替えない
Office ScriptsはWorksheet・Rangeオブジェクトに対して直接値の読み書きができるため、画面上でどのシートが表示されているかに関わらず処理が可能です。VBAのように処理対象のシートをActivate/Selectする必要はありません。この点を踏まえ、settingSheet.activate()も含めてシート切り替えの処理自体を撤去し、画面がMainシートから一切動かないまま処理が完了する形に修正しました。
function main(workbook: ExcelScript.Workbook) {
const mainSheet = workbook.getWorksheet("Main");
const settingSheetName = mainSheet.getRange("F2").getValue() as string;
// Target番地保存エリア(C:D列)をクリア
mainSheet.getRange("C:D").clear(ExcelScript.ClearApplyTo.contents);
const mark = mainSheet.getRange("B2").getValue() as string;
const settingSheet = workbook.getWorksheet(settingSheetName);
const usedRange = settingSheet.getUsedRange();
const values = usedRange.getValues();
// マーカー文字列 → セル番地(絶対参照形式)のマップを、値配列を自前でスキャンして作る
const addressMap = new Map<string, string>();
for (let r = 0; r < values.length; r++) {
for (let c = 0; c < values[r].length; c++) {
const cellValue = values[r][c];
if (typeof cellValue === "string" && cellValue.indexOf(mark) === 0) {
const fullAddress: string = usedRange.getCell(r, c).getAddressLocal();
// "取得セル設定!A1" のようにシート名が付くため、"!"より後ろだけを取り出す
const localAddress = fullAddress.includes("!") ? fullAddress.split("!")[1] : fullAddress;
// VBAの.Addressと同じ絶対参照形式($A$1)にする
const address: string = localAddress.replace(/([A-Z]+)(\d+)/, "$$$1$$$2");
addressMap.set(cellValue, address);
}
}
}
const m = addressMap.size;
for (let i = 1; i <= m; i++) {
const target = `${mark}${i}`;
const address: string = addressMap.has(target) ? addressMap.get(target) : "見つかりません";
mainSheet.getRange("C" + i).setValue(target);
mainSheet.getRange("D" + i).setValue(address);
}
}再検証の結果、画面はMainシートから動かないまま、D列には$A$1・$C$2のような絶対参照形式で番地が記録されることを確認できました。
「見つかりません」の分岐(マーカーが存在しない場合の挙動)は、今回のテストデータでは★1〜★12すべてが見つかったため未検証です。

スクリプトをボタンに紐付ける
Office Scriptsもシート上のボタンにスクリプトを割り当てて、ワンクリックで実行できます。ただし「挿入」タブからボタンを配置する方法ではありません(現在のExcel on the webでは、この方法でOffice Scripts用のボタンを追加することはできません)。正しくは、スクリプト側の共有設定からボタンを追加します。
- 「自動化」タブで、ボタンに割り当てたいスクリプトを選択して開く
- スクリプトの詳細画面で「このスクリプトを共有する」セクションまでスクロール
- 「ブックに関連付ける」トグルが無効になっている場合は有効にする
- 「ワークシートに追加」ボタンを選択する
これでシート上にボタンが追加され、そのブックを編集できる全ユーザーとスクリプトが共有された状態になります。
| 項目 | VBA | Office Scripts |
|---|---|---|
| ボタンの設置 | 挿入 → フォームコントロール → ボタン | 自動化タブ → スクリプトの共有設定 → 「ワークシートに追加」 |
| 割り当て方法 | 右クリック → マクロの登録 | スクリプト作成時点でボタンと1対1に紐付く |
| 実行環境 | デスクトップExcel | Excel on the web |
| 共有範囲 | ブック内(マクロ有効ブックとして配布) | ブックを編集できる全ユーザーと自動共有 |
コードエディターで未保存のスクリプトを複数回実行すると、「スクリプトは正常に複数回実行されました。ブックに追加しますか?」という確認が表示されることがあります。これはエラーではなく、まだブックに保存されていないスクリプトを保存するかどうかの確認です。ボタンに割り当てて再利用する場合は、ここで保存しておく必要があります。
VBAとOffice Scriptsの差分まとめ
| 項目 | VBA | Office Scripts |
|---|---|---|
| セル検索 | Cells.Find | 直接の代替メソッドなし。値配列を自前でスキャン |
| 見つからない場合の判定 | Nothingかどうかで判定 | Mapに存在するかどうかで判定 |
| ワイルドカード集計 | Application.CountIf(Cells, "★*") | 前方一致(indexOf(mark) === 0)でループ集計 |
| セル番地の取得 | Range.Address(シート名なし・既定で絶対参照) | Range.getAddressLocal()(シート名付き・相対参照。文字列処理で加工) |
| 他シートの値を読む際の操作 | Sheets(...).Activateが必要な場面が多い | Worksheet/Rangeオブジェクトに直接アクセスでき、Activateは不要 |
よくある質問・エラー対処
Q. Property 'findOrNullObject' does not exist というエラーが出る
→ findOrNullObjectはWorksheetではなくRangeに対して呼び出すのが正しい作法ですが、正しくRangeに対して呼び出してもOffice Scriptsではエラーになりました。Find系のAPIに頼らず、getValues()で取得した値配列を自前でループしてセル番地を特定する方式に切り替えてください(本記事の「実際に動かして検証する」参照)。
Q. Microsoft公式ドキュメントにはRange.findOrNullObjectが載っているのに、Office Scriptsでエラーになる
→ 公式ドキュメントの多くはExcel JavaScript API(Excelアドイン用、Excel名前空間)のものです。Office Scripts(ExcelScript名前空間)はこれと似ていますが別のAPIセットで、すべてのメソッドが移植されているわけではありません。今回の検証では、Worksheet・Rangeどちらに対して呼び出してもOffice Scriptsの型定義上findOrNullObjectは存在せず、Find系のメソッドに頼らない自前実装への切り替えが必要でした。
Q. セル番地を取得するとシート名!A1のようにシート名が付いてくる
→ getAddressLocal()の仕様です。VBAの.Addressと同じくシート名なしの番地が欲しい場合は、"!"で文字列を分割し、後半部分だけを取り出してください。
Q. セル番地がA1のような相対参照になり、VBAの$A$1と形式が違う
→ getAddressLocal()は既定で相対参照形式を返します。VBAの.Addressと同じ絶対参照形式にするには、localAddress.replace(/([A-Z]+)(\d+)/, "$$$1$$$2")のように正規表現で$を付与してください。
Q. スクリプト実行後、別のシートが開いたままになってしまう
→ VBAではSheets(...).Activateで処理対象のシートに切り替えるのが一般的ですが、Office ScriptsはWorksheet・Rangeオブジェクトに直接アクセスできるため、そもそもActivateする必要がありません。Activateの呼び出しを削除すれば、画面のシートを切り替えずに処理できます。
Q. コードエディターで「ブックに追加しますか?」と表示される
→ エラーではありません。まだブックに保存されていないスクリプトを、複数回実行したタイミングで保存するかどうかの確認です。ボタンに割り当てて再利用したい場合は保存しておくことをおすすめします。
まとめ
- VBAの
Cells.Findに相当する検索専用メソッドは、Office ScriptsのWorksheetにもRangeにも存在しない - AIが生成したコードも実在しないAPI(
findOrNullObject)を使っており、2回のエラーを経て自前実装に切り替えた getValues()で取得した値配列を自前でスキャンし、マーカー文字列とセル番地の対応表(Map)を作る方式で代替できたgetAddressLocal()はシート名付き・相対参照で返るため、VBAの.Addressと同じ形式にするには文字列処理が必要- Office Scriptsは
Worksheet・Rangeオブジェクトに直接アクセスできるため、VBAで多用するActivate/Selectは不要。むしろ画面のシート遷移が目立つ分、削除した方が体感的にも自然 - スクリプトのボタン割り当てはVBAと同様の操作感で行える
次回予告
次回は、いよいよ「その2」にあたる別ブックを実際に開いてデータを抜き出す本編です。今回記録したセル番地を使い、複数の別ブックを順番に開いてデータを集計する処理をOffice Scriptsで実現します。Office Scriptsはサーバーサイド実行のためVBAのWorkbooks.Openをそのまま使えず、PAD(Power Automate for Desktop)との連携が本格的に必要になる見込みです。
関連記事
- 【Web版Excel】VBAをOffice Scriptsに移行する方法
- 【保存版】VBA→Office Scripts 書換チートシート
- 生成AIでVBAをOffice Scriptsに変換できるか?
- 【検証】生成AIはVBAをOffice Scriptsに変換できるか?
- 【Office Scripts×Power Automate】UserFormの代替で完了通知を自動化する
- 【Office Scripts】UserForm代替パターン:進捗表示はセルで、キャンセルは実行ボタンで実装する
- 【Office Scripts×PAD】Power Automate for Desktopのブラウザ操作でExcel on the webのスクリプトを起動する
- 【Excel VBA】別ブックからデータを抜き出す処理(その1)
当サイトの記事で使用したVBAなどのサンプルをDLできます
この記事のサンプルはありません!
ダウンロードページへは下のカードをクリックすればジャンプできます。
よろしければご利用ください!

