
Azure Screenshot Mask
- 4 installs
- 23 repo stars
- Updated August 4, 2026
- aktsmm/agent-skills
azure-screenshot-mask is a Claude skill that mosaics environment-sensitive areas on Azure Portal screenshots before public publishing.
About
Mosaics environment-sensitive areas on Azure Portal screenshots before they are published to blogs, Qiita, Medium, slides or demos. A developer runs the bundled Pillow-based CLI to redact tenant names, subscription names and IDs, resource groups, internal hostnames and IPs, either as a default top-right strip or via explicit region coordinates. It also supports an OCR fallback and red-box highlight annotations.
- Batch-masks tenant, subscription and resource-group info on Azure Portal captures
- Ships a Pillow CLI with default top-right strip, --region coords and --backup
- OCR (Surya) fallback masks text bounding boxes when fixed coordinates miss
Azure Screenshot Mask by the numbers
- 4 all-time installs (skills.sh)
- Ranked #1,780 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
azure-screenshot-mask capabilities & compatibility
Free; requires local Python and Pillow (pip install pillow)
- Capabilities
- packet capture analysis · humanize writing · image redaction
- Works with
- azure
- Use cases
- image generation
- Pricing
- Free
What azure-screenshot-mask says it does
このスキルには CLI スクリプト [scripts/mosaic-azure-screenshots.py](scripts/mosaic-azure-screenshots.py) を同梱している。Pillow ベースで pixel mosaic をかける。
本文を伏せても画像内に残れば公開情報になる
npx skills add https://github.com/aktsmm/agent-skills --skill azure-screenshot-maskAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4 |
|---|---|
| repo stars | ★ 23 |
| Last updated | August 4, 2026 |
| Repository | aktsmm/agent-skills ↗ |
What it does
Redact tenant, subscription and resource-group details from Azure Portal screenshots before publishing them to a blog or slides.
Who is it for?
Sanitizing Azure Portal screenshots in bulk before publishing articles, slides or demos
Skip if: Masking pcap captures (that is packet-capture-analysis) or general prose sanitization (humanize-writing)
When should I use this skill?
Preparing Azure Portal captures for a public blog, Qiita, Medium or a demo video
What you get
Screenshots with environment-sensitive regions mosaicked and visually verified
- Mosaicked screenshots
- Optional .bak.png backups
- Red-box annotated captures
By the numbers
- 9-item what-to-mask checklist
- default 320x44 top-right strip
Files
Azure Screenshot Mask
Azure Portal のスクリーンショットに残る環境固有情報を、公開前にまとめてモザイクで消すための skill。
When To Use
- Azure Portal のスクリーンショットをブログ、Qiita、Medium、note、社外スライド、デモ動画に載せる前
- 同じテナントや顧客環境で連続して撮ったキャプチャを、一気にサニタイズしたいとき
- 「本文では伏せたのに画像内に名前が残っていた」を防ぎたいとき
Core Principles
- 本文を伏せても画像内に残れば公開情報になる。画像を別レビューで必ず目視する
- 右上のテナント表示はほぼ常に対象。viewport 1912 px の Azure Portal なら右端
(W-320, 0, W, 44)のストリップで覆える - 本文中の subscription 名 / ID / RG 名は座標が画面ごとに違う。事前に値の有無を見て、必要な領域だけ追加で渡す
- モザイクは元データを破壊する。再撮りや再生成に備えて
.bak.pngを残せる手段を用意する - 資源名そのものもマスク対象になりうる。ラボ用に作った短命リソース名でも、ユニークな文字列は特定可能。本文で明示していても、画像内では先頭数文字だけ残してマスクするのが安全
What To Mask (Checklist)
公開前に最低限見るリスト。残っていればモザイクをかけるか撮り直す。
- 右上のテナント表示 (
HINOKUNI (...)など organization 名、user の頭文字アバター) - サブスクリプション名 (例:
*-sub、顧客名入りの命名) - サブスクリプション ID (GUID。Portal の "リソース ID" や "サブスクリプション ID" 欄に出る)
- テナント ID (GUID。Entra ID 関連画面で見える)
- リソースグループ名 (内部コードや顧客プロジェクト名を含む場合)
- 個人ユーザーの UPN / メールアドレス
- 内部ホスト名 / FQDN / Private IP / Public IP
- アカウント表示の onmicrosoft ドメイン
- リソース名(Storage Account 名、task 名、assignment 名など)ユニークな文字列は先頭数文字だけ残してマスクする
逆に、汎用の lab 用に作った storage account 名や resource 名でも、ユニークな文字列は特定可能なのでマスク推奨。
Default Workflow
1. 対象画像を 1 フォルダにまとめる
- 記事に貼る画像を
images/<platform>/<article>/配下に集約しておく - 同じ Portal 解像度 (viewport 幅) で揃っていると、領域指定を使い回せる
2. 右上テナント帯だけでよいか確認する
- フォルダ内の代表 1 枚を開き、右上の組織表示・アバターだけが env-sensitive か確認する
- 本文側に subscription 名 / ID / RG 名が見えていれば、その行も対象にする
3. モザイクをかける
# フォルダ内の PNG 全部に対し、右上テナント帯だけ覆う
python <skill-path>/scripts/mosaic-azure-screenshots.py images/qiita/<article>
# 単一画像 + 追加領域(例: 概要画面のサブスクリプション名 / ID 行)
python <skill-path>/scripts/mosaic-azure-screenshots.py images/qiita/<article>/overview.png `
--region 450,277,740,304 `
--region 450,308,920,335
# 元画像を保険として残したい
python <skill-path>/scripts/mosaic-azure-screenshots.py images/qiita/<article> --backup4. 目視で検証する
- 上記チェックリスト項目が読めなくなっているか、画像ビューアで確認する
- 1 枚でも残っていれば、その画面だけ
--regionを足して再実行する
5. 記事側のテキストも合わせて整える
- 本文に
hinokuni-subのような subscription 名や顧客固有名が出ていたら削除する - 「環境固有情報はスクリーンショット上でマスクしています」のような 1 行を入れておくと、読者が画像のモザイクを誤読しない
Script
このスキルには CLI スクリプト scripts/mosaic-azure-screenshots.py を同梱している。Pillow ベースで pixel mosaic をかける。
主な引数:
| 引数 | 説明 |
|---|---|
path | PNG ファイル、または PNG を含むディレクトリ |
--region L,T,R,B | 追加でマスクする領域 (px 座標)。繰り返し指定可 |
--topright-width / --topright-height | 右上テナント帯のサイズ調整 (既定 320 × 44) |
--no-topright | 既定の右上ストリップを無効化 |
--block | モザイクのブロックサイズ (既定 14 px) |
--backup | <name>.bak.png を残してから上書きする |
依存: Pillow。pip install pillow で導入できる。
OCR Fallback
--region 座標指定でテーブル行や詳細ペイン内のテキストに当たらない場合は、OCR(Surya)でテキスト bbox を取得してから Pillow で直接モザイクをかける。
手順:
1. ocr-super-surya skill で画像を OCR し、各テキスト行の text と bbox [x1, y1, x2, y2] を取得する 2. マスク対象のキーワード(例: stmock, hinokuni)を含む行をフィルタする 3. bbox の先頭数ピクセルを残し、残りを Pillow の resize (NEAREST) でピクセル化する
MASK_PATTERNS = ["stmock", "hinokuni"] # マスク対象キーワード
KEEP_PX = 30 # 先頭何 px を残すか
for line in page.text_lines:
text = line.text.strip()
if any(pat in text.lower() for pat in MASK_PATTERNS):
x1, y1, x2, y2 = [int(v) for v in line.bbox]
mask_x1 = x1 + KEEP_PX # 先頭を残す
region = img.crop((mask_x1, y1, x2, y2))
block = 8
small = region.resize((max(1, (x2-mask_x1)//block), max(1, (y2-y1)//block)), Image.NEAREST)
img.paste(small.resize((x2-mask_x1, y2-y1), Image.NEAREST), (mask_x1, y1))依存: surya-ocr, Pillow。ocr-super-surya skill の環境を使う。
OCR-guided Highlight(赤枠注釈)
before / after 比較や検証記事で「この行を見てほしい」と伝えたいとき、OCR で bbox を取得してから ImageDraw.rectangle で赤枠を入れる。座標を手入力するより確実に当たる。
from PIL import Image, ImageDraw
# OCR で取得済みの bbox を使って赤枠を描画
img = Image.open("screenshot.png")
draw = ImageDraw.Draw(img)
# 行全体をハイライト(太い赤枠)
draw.rectangle([x1, y1, x2, y2], outline="red", width=3)
img.save("screenshot.png")ポイント:
- モザイクと違い、元テキストを隠さず「ここを見て」と指すための注釈
- 記事本文で「(赤枠の行)」と書いて、画像と本文をリンクさせる
- 1 画像に 2〜3 箇所程度に絞る。多すぎると逆に見づらい
Tips
- viewport を毎回 1912 px 前後に揃えると、
--topright-*を毎回触らずに済む - 座標は 1 枚で決めて使い回す。ある記事の overview 画面で
(450,277,740,304)が subscription 行に当たれば、同じ Portal レイアウトの別キャプチャでも流用しやすい - モザイクの代わりに塗りつぶしで十分な場合は、Snipping Tool / Snagit / Greenshot などの注釈機能を使い、本 skill のスクリプトは一括処理が必要な時だけに絞ってよい
- Public IP の判別が必要な場合は、
subscription/tenant/IPを一気にマスクするより、IP は別途 RDAP で意味付けしてから判断する(公開可否は所有者で変わる)
Related Skills
humanize-writing: 本文のサニタイズや AI 感の除去。同じ「公開前の最終チェック」フローで一緒に走らせると効率がよいpacket-capture-analysis: pcap の中身を画像化する際の env-sensitive 領域マスクは別 skill。本スキルは Azure Portal キャプチャに特化
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
## English
Copyright (c) 2025-2026 yamapan (aktsmm)
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0
International License.
You are free to:
- **Share** — copy and redistribute the material in any medium or format
- **Adapt** — remix, transform, and build upon the material
Under the following terms:
- **Attribution** — You must give appropriate credit, provide a link to the
license, and indicate if changes were made. You may do so in any reasonable manner,
but not in any way that suggests the licensor endorses you or your use.
- **NonCommercial** — You may not use the material for commercial purposes.
*(Please contact the author if you wish to use this material for commercial purposes.)*
- **ShareAlike** — If you remix, transform, or build upon the material, you must
distribute your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological
measures that legally restrict others from doing anything the license permits.
**AI/ML Training Restriction** — Use of this content for AI/ML training, data
mining, or other analytical purposes is prohibited without explicit permission.
Full license text: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
---
## 日本語
Copyright (c) 2025-2026 yamapan (aktsmm)
この作品はクリエイティブ・コモンズ 表示-非営利-継承 4.0 国際ライセンスの下に提供されています。
あなたは以下の条件に従う限り、自由に:
- **共有** — どのようなメディアやフォーマットでも資料を複製・再配布できます
- **翻案** — 資料をリミックス、変形、および加工することができます
以下の条件に従ってください:
- **表示** — あなたは適切なクレジットを表示し、ライセンスへのリンクを提供し、
変更があったらその旨を示さなければなりません。これらは合理的であればどのような方法で
行っても構いませんが、許諾者があなたやあなたの利用行為を支持していると示唆するような
方法は除きます。
- **非営利** — あなたは営利目的でこの資料を利用してはなりません。
(※商用利用をご希望の場合は、別途ご連絡ください。)
- **継承** — もしあなたがこの資料をリミックス、変形、または加工した場合、
あなたはあなたの貢献部分を元の作品と同じライセンスの下で配布しなければなりません。
追加的な制約は課せません — あなたは、このライセンスが他の者に許諾することを法的に
制限するような法的条項や技術的手段を適用してはなりません。
**AI/MLトレーニング制限** — 本コンテンツをAI/MLモデルのトレーニング、データマイニング、
その他の解析目的での使用は明示的な許可なく禁止されています。
ライセンス全文: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.ja
---
## Special Permission for Microsoft Employees / Microsoft 社員向け特別許諾
### English
Microsoft Corporation employees are granted permission to use, copy, modify, and
distribute this material for any purpose within the scope of their employment
duties at Microsoft, including internal business use and customer-facing
activities, without the NonCommercial restriction of this license.
This special permission applies only to work performed as part of official
Microsoft business activities.
### 日本語
Microsoft Corporation の社員は、Microsoft での業務の範疇において、本資料を社内業務
および顧客対応を含むあらゆる目的で使用、複製、改変、配布することが許諾されます。
この場合、本ライセンスの「非営利」制限は適用されません。
この特別許諾は、Microsoft の公式な業務活動の一環として行われる作業にのみ適用されます。
---
## Disclaimer / 免責事項
### English
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR
A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
### 日本語
本ソフトウェアは「現状のまま」で提供され、明示または黙示を問わず、商品性、
特定目的への適合性、および権利非侵害についての保証を含むがこれに限定されない、
いかなる種類の保証も伴いません。作者または著作権者は、契約行為、不法行為、
またはそれ以外であろうと、ソフトウェアに起因または関連し、あるいはソフトウェアの
使用またはその他の扱いによって生じる一切の請求、損害、その他の責任について
責任を負いません。"""Pixel-style mosaic for Azure Portal (or any) screenshots.
Use when publishing screenshots that contain environment-sensitive info such as:
- Top-right tenant name / user avatar strip (Azure Portal header)
- Subscription name or subscription ID values shown inside the page
By default, the script applies a pixel mosaic to the **top-right tenant strip**,
which has roughly the same shape across Azure Portal screenshots taken at the
standard 1912 px-wide viewport (last 320 px wide, top 44 px tall).
Additional regions can be specified with `--region L,T,R,B` (in pixels) and
the flag is repeatable.
Examples
--------
# Mask only the top-right tenant strip on every PNG in a folder (overwrite in place):
python scripts/mosaic-azure-screenshots.py images/qiita/some-article
# Single file, plus an extra region (e.g. subscription name row):
python scripts/mosaic-azure-screenshots.py images/qiita/.../overview.png --region 450,277,740,304
# Custom top-right strip size, or skip the default strip entirely:
python scripts/mosaic-azure-screenshots.py images/foo.png --topright-width 280 --topright-height 40
python scripts/mosaic-azure-screenshots.py images/foo.png --no-topright --region 100,200,500,240
Notes
-----
- Files are overwritten in place. Use `--backup` to keep `<name>.bak.png` copies.
- Body-content region coordinates depend on the page layout, so they stay
article-specific. Capture them once per page and pass via `--region` flags.
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
from PIL import Image
def pixelate(img: Image.Image, box: tuple[int, int, int, int], block: int = 14) -> None:
"""Mosaic the given (l, t, r, b) box in place by downscaling then upscaling."""
l, t, r, b = box
iw, ih = img.size
l, t = max(0, l), max(0, t)
r, b = min(iw, r), min(ih, b)
if r - l <= 0 or b - t <= 0:
return
region = img.crop((l, t, r, b))
sw = max(1, (r - l) // block)
sh = max(1, (b - t) // block)
small = region.resize((sw, sh), Image.NEAREST)
region = small.resize((r - l, b - t), Image.NEAREST)
img.paste(region, (l, t))
def parse_region(spec: str) -> tuple[int, int, int, int]:
parts = [int(p.strip()) for p in spec.split(",")]
if len(parts) != 4:
raise argparse.ArgumentTypeError(f"--region expects L,T,R,B (got: {spec!r})")
return tuple(parts) # type: ignore[return-value]
def iter_targets(path: Path) -> list[Path]:
if path.is_file():
return [path]
if path.is_dir():
return sorted(path.glob("*.png"))
raise FileNotFoundError(path)
def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser(description="Mosaic env-sensitive areas of screenshots.")
ap.add_argument("path", type=Path, help="PNG file or directory of PNGs.")
ap.add_argument(
"--region",
action="append",
type=parse_region,
default=[],
help="Extra mosaic region as L,T,R,B (pixel coords). Repeatable.",
)
ap.add_argument("--topright-width", type=int, default=320, help="Top-right strip width.")
ap.add_argument("--topright-height", type=int, default=44, help="Top-right strip height.")
ap.add_argument("--no-topright", action="store_true", help="Skip default top-right strip.")
ap.add_argument("--block", type=int, default=14, help="Mosaic block size (px).")
ap.add_argument("--backup", action="store_true", help="Write <name>.bak.png before overwrite.")
args = ap.parse_args(argv)
targets = iter_targets(args.path)
if not targets:
print(f"no PNG found at: {args.path}", file=sys.stderr)
return 1
for p in targets:
with Image.open(p) as src:
img = src.convert("RGB")
W, H = img.size
regions = list(args.region)
if not args.no_topright:
regions.append((W - args.topright_width, 0, W, args.topright_height))
if not regions:
print(f"skip (no regions): {p.name}")
continue
if args.backup:
bak = p.with_suffix(".bak.png")
if not bak.exists():
img.save(bak)
for region in regions:
pixelate(img, region, block=args.block)
img.save(p)
print(f"masked: {p.name} ({W}x{H}) regions={len(regions)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Related skills
FAQ
What does it mask by default?
The top-right tenant strip; the default region is roughly (W-320, 0, W, 44) on a 1912px viewport, with additional --region coordinates for subscription/RG rows.
Can I keep the original image?
Yes, the --backup flag writes a .bak.png before overwriting so you can re-capture or re-generate.