PnP New Site_dorago01

<#
Windows PowerShell 5.1 / PnP.PowerShell 1.12.0向け修正版。接続済みセッションで実行: .\New-KumePortal.ps1
通常実行は対象サイトのテーマを変更し、新しい下書きとバナーを作成します。
-ThemeOnly は配色のみ変更。テーマは対象サイトの既存ページにも反映されます。
ナビ・権限・Power Apps本体は変更しません。-SkipTheme で配色変更を省略できます。
編集箇所: 冒頭の設定欄(param)と $cards。独自バナーは -BannerPath でPNG/JPEGを指定。
標準テーマ対応箇所に黒紺・シアン・白を適用します。任意CSSは使用しません。
UTF-8(BOM付き)で保存してください。実テナントでは未実行。
会社側のキャンバスアプリのWebリンクを使用。アプリの公開・共有・データ接続は別途必要です。
標準の埋め込みWebパーツを使用します。埋め込み制限がある場合は起動リンクを利用できます。
#>
[CmdletBinding()]
param(
 # ===== 設定欄:引用符の中を書き換えてください =====
 # 【必須】対象サイトのURL。/SitePages/...aspx は含めません。
 # 例: https://yourtenant.sharepoint.com/sites/your-site
 [string]$SiteUrl='ここを対象サイトのURLに置き換えてください',
 # 表示名(ページタイトルと自動生成バナーに反映)
 [string]$PageTitle='dorago01',
 # 配色だけを既存サイトへ適用する場合: .\New-KumePortal.ps1 -ThemeOnly
 [switch]$ThemeOnly,
 # ページだけ作成し、配色を変更しない場合: -SkipTheme
 [switch]$SkipTheme,
 # 会社側のキャンバスアプリの「詳細」→「Webリンク」を貼り付けます。
 # 空欄なら掲示板の埋め込みを省略します。編集画面のURLは指定しません。
 [string]$PowerAppUrl='',
 # おみくじPower AppsのWebリンク(未設定でも紹介文は表示します)
 [string]$OmikujiAppUrl='',
 # おみくじをページ内にも表示する場合は -EmbedOmikuji を付けて実行
 [switch]$EmbedOmikuji,
 [ValidateRange(300,2000)]
 [int]$PowerAppHeight=720,
 # ===== 以下は通常、変更不要です =====
 [ValidatePattern('^[A-Za-z0-9_-]+$')]
 [string]$PageName=('Portal-Draft-'+(Get-Date -Format 'yyyyMMdd-HHmmss')),
 [string]$BannerPath,
 [switch]$SkipPowerApps
)
$ErrorActionPreference='Stop'
if ($ThemeOnly -and $SkipTheme) { throw '-ThemeOnly と -SkipTheme は同時に指定できません。' }
$SiteUrl=$SiteUrl.Trim().TrimEnd('/')
$targetUri=$null
if (-not [Uri]::TryCreate($SiteUrl,[UriKind]::Absolute,[ref]$targetUri) -or
    $targetUri.Scheme -ne 'https' -or $targetUri.AbsolutePath -match '/SitePages/' -or
    $targetUri.Query -or $targetUri.Fragment) {
 throw '冒頭の $SiteUrl に対象サイトのHTTPS URLを設定してください。ページURLではなく、/sites/サイト名 までのURLを指定します。'
}
$PowerAppUrl=$PowerAppUrl.Trim()
$OmikujiAppUrl=$OmikujiAppUrl.Trim()
foreach ($appSetting in @(@{Name='PowerAppUrl'; Url=$PowerAppUrl},@{Name='OmikujiAppUrl'; Url=$OmikujiAppUrl})) {
 if ($appSetting.Url) {
  $appUri=$null
  if (-not [Uri]::TryCreate($appSetting.Url,[UriKind]::Absolute,[ref]$appUri) -or
      $appUri.Scheme -ne 'https' -or $appUri.Host -notin @('apps.powerapps.com','web.powerapps.com') -or
      $appUri.AbsolutePath -notmatch '^/(play|apps)(/|$)') {
   throw "$($appSetting.Name) にキャンバスアプリのWebリンクを貼り付けてください(apps.powerapps.com/play/...)。"
  }
 }
}
# ===== 自己紹介:自由に書き換えられます =====
$AboutText='こんにちは、dorago01です。普段はセキュリティクラウドを担当しています。仕事の外でもWebサイトを作ったり、自宅でサーバーを動かしたりしています。「これ、作れそう」と思うと、つい試してみたくなるタイプです。'
$WorkText='セキュリティクラウドに関わる業務に取り組んでいます。日々の気づきや学びを整理し、わかりやすく共有できる形にしていきたいと思っています。ネットワークやセキュリティに加えて、手作業を減らす仕組みづくりにも関心があります。'
$MakingText='個人でもいろいろなWebサイトを作っています。見た目を考えるのも、裏側の仕組みを動かすのも好きです。最近はPower AppsやSharePointも触りながら、掲示板やおみくじなど、実際に使ってもらえるものを作っています。'
$PersonalText='思い立ったら、まずやってみる。そんな勢いで、気になった技術や創作を少しずつ試しています。うまく動いたときはもちろん、つまずいて原因がわかったときも楽しいです。このページでは、仕事の担当だけでは伝わらない普段の自分も紹介していきます。'
$Notes=@(
 @{Title='自宅も、ちょっとした検証場所'; Body='自宅ではサーバーやネットワーク機器を触っています。仮想環境を作ったり、Webサービスを動かしたり。仕組みを読んで終わりにせず、自分の手元で試してみるのが好きです。'},
 @{Title='技術のほかに、物語も作ります'; Body='小説を書いたり、AIを使った音楽づくりを試したりしています。システムを作るときとはまた違う難しさがありますが、頭の中にあったものが形になるところは共通していて、どちらも楽しんでいます。'},
 @{Title='AIと一緒に、試行錯誤'; Body='AIには文章やコードの相談をしながら、アイデアを実際に動く形にしています。最近はPower Appsもコードから組み立てられることを知り、できることが増える面白さを感じています。'},
 @{Title='ちょっとした遊び心も'; Body='便利なツールだけでなく、気軽に楽しめるものも作ってみたくて、Power Appsでおみくじを作りました。作ったものをきっかけに、会話が生まれたらうれしいです。'},
 @{Title='気軽に話しかけてください'; Body='サイト制作、サーバー、ネットワーク、AI、創作など、気になる話題があればぜひ。掲示板への感想や「こんなものを作ってみたい」という話も歓迎です。'}
)
$OmikujiText='Power Appsで、おみくじアプリを作りました。仕事の合間の気分転換に、気軽にのぞいてもらえたらうれしいです。使ってみた感想も、ぜひ掲示板で教えてください。'
# 接続済みの旧版を使い、PowerShell 7専用の新版を自動選択しないよう固定します。
Import-Module PnP.PowerShell -RequiredVersion 1.12.0 -ErrorAction Stop
# 作成前に、読み込まれたPnPのコマンド・パラメーターを確認します。
$requiredCommands = @{
 'Get-PnPConnection' = @()
 'Get-PnPWeb' = @('Includes','Connection')
 'Add-PnPPage' = @('Name','LayoutType','Connection')
 'Set-PnPPage' = @('Identity','Title','Connection')
 'Add-PnPFile' = @('Path','Folder','NewFileName','Connection')
 'Add-PnPPageSection' = @('Page','SectionTemplate','Order','ZoneEmphasis','Connection')
 'Add-PnPPageTextPart' = @('Page','Section','Column','Order','Text','Connection')
 'Add-PnPPageWebPart' = @('Page','DefaultWebPartType','WebPartProperties','Section','Column','Order','Connection')
 'Get-PnPPage' = @('Identity','Connection')
}
foreach ($entry in $requiredCommands.GetEnumerator()) {
 $cmd = Get-Command $entry.Key -ErrorAction Stop
 foreach ($parameterName in $entry.Value) {
  if (-not $cmd.Parameters.ContainsKey($parameterName)) {
   throw "$($entry.Key) に -$parameterName がありません。ページはまだ作成していません。このエラーを共有してください。"
  }
 }
}
$imageCommand = Get-Command Add-PnPPageImageWebPart -ErrorAction SilentlyContinue
$canUseImageCommand = $null -ne $imageCommand
if ($canUseImageCommand) {
 foreach ($parameterName in @('Page','Section','Column','Order','ImageUrl','ImageWidth','ImageHeight','AlternativeText','Connection')) {
  if (-not $imageCommand.Parameters.ContainsKey($parameterName)) { $canUseImageCommand = $false }
 }
}

$connection=Get-PnPConnection -ErrorAction Stop
if (-not $connection) { throw 'Connect-PnPOnlineで接続してください。' }
$web=Get-PnPWeb -Includes Url -Connection $connection
if ($web.Url.TrimEnd('/') -ine $SiteUrl.TrimEnd('/')) { throw "接続先が違います: $($web.Url)" }
$SiteUrl=$web.Url.TrimEnd('/')
# Microsoft公開のApplyTheme APIで、接続済みの対象サイトだけに適用します。
# https://learn.microsoft.com/sharepoint/dev/declarative-customization/site-theming/sharepoint-site-theming-rest-api
# テナント共通テーマの登録や権限設定の変更は行いません。
$themeApplied=$false
if (-not $SkipTheme) {
 $themeCommand=Get-Command Invoke-PnPSPRestMethod -ErrorAction Stop
 foreach ($parameterName in @('Url','Method','Content','ContentType','Connection','Raw')) {
  if (-not $themeCommand.Parameters.ContainsKey($parameterName)) {
   throw "Invoke-PnPSPRestMethod に -$parameterName がありません。テーマとページはまだ変更していません。"
  }
 }
 # ダークテーマでは white が背景、neutralPrimary が本文色になります。
 $palette=@{
  themePrimary='#28DCDC'; themeLighterAlt='#0D1D22'; themeLighter='#103438'
  themeLight='#155257'; themeTertiary='#208F94'; themeSecondary='#25C2C6'
  themeDarkAlt='#42E0E0'; themeDark='#69E8E8'; themeDarker='#9BF0F0'
  neutralLighterAlt='#101820'; neutralLighter='#142029'; neutralLight='#1B2D35'
  neutralQuaternaryAlt='#29404A'; neutralQuaternary='#38515C'; neutralTertiaryAlt='#53717D'
  neutralTertiary='#92A8B2'; neutralSecondaryAlt='#AEC1C9'; neutralSecondary='#C6D7DE'
  neutralPrimaryAlt='#D9E7EC'; neutralPrimary='#EBF5F8'; neutralDark='#F4FAFC'
  black='#FFFFFF'; white='#0C1218'; primaryBackground='#0C1218'; primaryText='#EBF5F8'
  bodyBackground='#0C1218'; bodyText='#EBF5F8'; disabledBackground='#142029'; disabledText='#92A8B2'
  error='#FF8A8A'; accent='#28DCDC'
 }
 $themeJson=@{isInverted=$true; palette=$palette} | ConvertTo-Json -Depth 5 -Compress
 $themeBody=@{name='dorago01 Dark Cyan'; themeJson=$themeJson} | ConvertTo-Json -Depth 6 -Compress
 # PnP 1.12.0 のオブジェクト変換を避けるため、新しい.NET文字列として渡します。
 $themeBody=[string]::Concat('', [string]$themeBody)
 # 送信前にJSONの形式と二重構造を検証します。
 $themePayloadCheck=ConvertFrom-Json -InputObject $themeBody -ErrorAction Stop
 $null=ConvertFrom-Json -InputObject $themePayloadCheck.themeJson -ErrorAction Stop
 Write-Host "サイト配色を適用中: $SiteUrl(既存ページにも反映)" -ForegroundColor Cyan
 try {
  $themeRaw=Invoke-PnPSPRestMethod -Url "$SiteUrl/_api/thememanager/ApplyTheme" -Method Post -Content ($themeBody.ToString()) -ContentType 'application/json; charset=utf-8' -Raw -Connection $connection -ErrorAction Stop
  # 応答もPnP内蔵のオブジェクト変換を使わず、PowerShell標準で解析します。
  $themeResponse=$null
  if (-not [string]::IsNullOrWhiteSpace([string]$themeRaw)) {
   $themeResponse=ConvertFrom-Json -InputObject ([string]$themeRaw) -ErrorAction Stop
  }
  if ($themeResponse -and $themeResponse.PSObject.Properties['error']) {
   throw ($themeResponse.error | ConvertTo-Json -Depth 5 -Compress)
  }
  if (($themeResponse -is [bool] -and -not $themeResponse) -or
      ($themeResponse -and $themeResponse.PSObject.Properties['value'] -and $themeResponse.value -eq $false)) {
   throw 'ApplyTheme が失敗を返しました。'
  }
  $themeApplied=$true
  Write-Host '配色の適用要求が完了しました。ブラウザを再読み込みして確認してください。' -ForegroundColor Green
 } catch {
  throw "テーマの適用に失敗しました。ページ作成は開始していません。テーマが反映済みかはブラウザでもご確認ください。詳細: $($_.Exception.Message)"
 }
}
if ($ThemeOnly) {
 [pscustomobject]@{SiteUrl=$SiteUrl; Theme='dorago01 Dark Cyan'; ThemeApplied=$themeApplied; PageCreated=$false}
 return
}

$pageFile="$PageName.aspx"
$pageUrl="$SiteUrl/SitePages/$pageFile"
# 個人サイトの紹介文は、それぞれの用途に合わせて編集してください。
$cards=@(
 @{Heading='01 / PERSONAL SITE'; Title='dorago01.xyz'; Description='個人で制作しているサイト。'; Url='https://dorago01.xyz'; Label='サイトを開く'},
 @{Heading='02 / PERSONAL SITE'; Title='dorago01.net'; Description='個人で制作しているサイト。'; Url='https://dorago01.net'; Label='サイトを開く'},
 @{Heading='03 / PERSONAL SITE'; Title='dorago01.com'; Description='個人で制作しているサイト。'; Url='https://dorago01.com'; Label='サイトを開く'}
)
function Encode-Html([string]$Value) { [System.Net.WebUtility]::HtmlEncode($Value) }
function New-TextBlock([string]$Heading,[string]$Body) {
 '<h2>'+(Encode-Html $Heading)+'</h2><p>'+((Encode-Html $Body) -replace '\r?\n','<br>')+'</p>'
}
# 同名ページがある場合、Add-PnPPageは上書きせず停止します。
Add-PnPPage -Name $PageName -LayoutType Home -Connection $connection | Out-Null
Write-Host "作成中: $pageUrl" -ForegroundColor Cyan
try {
 Set-PnPPage -Identity $pageFile -Title $PageTitle -Connection $connection | Out-Null
 $tempBanner=$null
 try {
  if ($BannerPath) {
   $imagePath=(Resolve-Path -LiteralPath $BannerPath).Path
   if ([IO.Path]::GetExtension($imagePath) -notmatch '^\.(png|jpg|jpeg)$') { throw 'PNG/JPEGを指定してください。' }
  } else {
    # バナーをコードで生成。表示名を変えると画像内の文字も変わります。
    Add-Type -AssemblyName System.Drawing
    $tempBanner=Join-Path ([IO.Path]::GetTempPath()) ('dorago01-'+[guid]::NewGuid().ToString('N')+'.png')
    $bitmap=[System.Drawing.Bitmap]::new(1600,440)
    $graphics=$null; $gridPen=$null; $accent=$null; $white=$null; $font=$null; $smallFont=$null
    try {
     $graphics=[System.Drawing.Graphics]::FromImage($bitmap)
     $graphics.Clear([System.Drawing.Color]::FromArgb(12,18,24))
     $graphics.TextRenderingHint=[System.Drawing.Text.TextRenderingHint]::AntiAliasGridFit
     $gridPen=[System.Drawing.Pen]::new([System.Drawing.Color]::FromArgb(27,45,53))
     for ($x=0; $x -lt 1600; $x+=48) { $graphics.DrawLine($gridPen,$x,0,$x,440) }
     for ($y=0; $y -lt 440; $y+=48) { $graphics.DrawLine($gridPen,0,$y,1600,$y) }
     $accent=[System.Drawing.SolidBrush]::new([System.Drawing.Color]::FromArgb(40,220,220))
     $white=[System.Drawing.SolidBrush]::new([System.Drawing.Color]::FromArgb(235,245,248))
     $font=[System.Drawing.Font]::new('Segoe UI',64,[System.Drawing.FontStyle]::Bold)
     $smallFont=[System.Drawing.Font]::new('Segoe UI',22)
     $graphics.FillRectangle($accent,80,86,8,258)
     $graphics.DrawString($PageTitle,$font,$white,[single]120,[single]110)
     $graphics.DrawString('CONNECT. SHARE. CREATE.',$smallFont,$accent,[single]126,[single]260)
     $bitmap.Save($tempBanner,[System.Drawing.Imaging.ImageFormat]::Png)
    } finally {
     foreach ($resource in @($smallFont,$font,$white,$accent,$gridPen,$graphics,$bitmap)) {
      if ($null -ne $resource) { $resource.Dispose() }
     }
    }
    $imagePath=$tempBanner
   }
  $assetName=$PageName+'-'+[guid]::NewGuid().ToString('N').Substring(0,8)+[IO.Path]::GetExtension($imagePath)
  $asset=Add-PnPFile -Path $imagePath -Folder 'SiteAssets/PortalDraft' -NewFileName $assetName -Connection $connection
  $imageUrl=$asset.ServerRelativeUrl
  if (-not $imageUrl) { throw '画像URLを取得できませんでした。' }
 } finally {
  if ($tempBanner -and (Test-Path -LiteralPath $tempBanner)) { Remove-Item -LiteralPath $tempBanner }
 }
 Add-PnPPageSection -Page $pageFile -SectionTemplate OneColumn -Order 1 -Connection $connection | Out-Null
 if ($canUseImageCommand) {
  Add-PnPPageImageWebPart -Page $pageFile -Section 1 -Column 1 -Order 1 -ImageUrl $imageUrl -ImageWidth 1600 -ImageHeight 440 -AlternativeText ($PageTitle+': CONNECT. SHARE. CREATE.') -Connection $connection | Out-Null
 } else {
  $imageProperties=@{imageSource=$imageUrl; altText=($PageTitle+': CONNECT. SHARE. CREATE.'); imgWidth=1600; imgHeight=440}
  Add-PnPPageWebPart -Page $pageFile -DefaultWebPartType Image -WebPartProperties $imageProperties -Section 1 -Column 1 -Order 1 -Connection $connection | Out-Null
 }
 Add-PnPPageTextPart -Page $pageFile -Section 1 -Column 1 -Order 2 -Text (New-TextBlock 'ABOUT / 自己紹介' $AboutText) -Connection $connection | Out-Null
 Add-PnPPageSection -Page $pageFile -SectionTemplate TwoColumn -Order 2 -ZoneEmphasis 1 -Connection $connection | Out-Null
 Add-PnPPageTextPart -Page $pageFile -Section 2 -Column 1 -Order 1 -Text (New-TextBlock 'WORK / 普段の担当' $WorkText) -Connection $connection | Out-Null
 Add-PnPPageTextPart -Page $pageFile -Section 2 -Column 2 -Order 1 -Text (New-TextBlock 'MAKING / サイトを作る' $MakingText) -Connection $connection | Out-Null
 Add-PnPPageSection -Page $pageFile -SectionTemplate ThreeColumn -Order 3 -Connection $connection | Out-Null
 for ($i=0; $i -lt $cards.Count; $i++) {
  $card=$cards[$i]
  $html='<p><strong>'+(Encode-Html $card.Heading)+'</strong></p><h2>'+(Encode-Html $card.Title)+'</h2><p>'+(Encode-Html $card.Description)+'</p><p><a href="'+(Encode-Html $card.Url)+'" target="_blank" rel="noopener noreferrer">'+(Encode-Html $card.Label)+' →</a></p>'
  Add-PnPPageTextPart -Page $pageFile -Section 3 -Column ($i+1) -Order 1 -Text $html -Connection $connection | Out-Null
 }
 Add-PnPPageSection -Page $pageFile -SectionTemplate OneColumn -Order 4 -ZoneEmphasis 1 -Connection $connection | Out-Null
 Add-PnPPageTextPart -Page $pageFile -Section 4 -Column 1 -Order 1 -Text (New-TextBlock 'PERSONAL / ひとこと' $PersonalText) -Connection $connection | Out-Null
 $noteOrder=2
 foreach ($note in $Notes) {
  Add-PnPPageTextPart -Page $pageFile -Section 4 -Column 1 -Order $noteOrder -Text (New-TextBlock $note.Title $note.Body) -Connection $connection | Out-Null
  $noteOrder++
 }
 Add-PnPPageSection -Page $pageFile -SectionTemplate OneColumn -Order 5 -Connection $connection | Out-Null
 $heading='<h2>COMMUNITY / 掲示板</h2><p>質問や雑談、サイトへの感想など、気軽にどうぞ。</p>'
 if ($PowerAppUrl) {
  $heading+='<p><a href="'+(Encode-Html $PowerAppUrl)+'" target="_blank" rel="noopener noreferrer">掲示板を別画面で開く →</a></p>'
 } else {
  $heading+='<p>掲示板は準備中です。</p>'
 }
 Add-PnPPageTextPart -Page $pageFile -Section 5 -Column 1 -Order 1 -Text $heading -Connection $connection | Out-Null
 $embedded=$false
 if ($PowerAppUrl -and -not $SkipPowerApps) {
  try {
   # 標準「埋め込み」Webパーツを使用。元ページの設定コピーは不要です。
   # サイトの埋め込み許可設定は変更しません。ブラウザで表示確認してください。
   $iframe='<iframe src="'+(Encode-Html $PowerAppUrl)+'" width="1200" height="'+$PowerAppHeight+'" frameborder="0" title="掲示板"></iframe>'
   $properties=@{embedCode=$iframe; cachedEmbedCode=$iframe; shouldScaleWidth=$true}
   Add-PnPPageWebPart -Page $pageFile -DefaultWebPartType ContentEmbed -WebPartProperties $properties -Section 5 -Column 1 -Order 2 -Connection $connection | Out-Null
   $embedded=$true
  } catch { Write-Warning "埋め込みパーツを追加できませんでした。別画面で開くリンクを利用できます: $($_.Exception.Message)" }
 }

 Add-PnPPageSection -Page $pageFile -SectionTemplate OneColumn -Order 6 -ZoneEmphasis 1 -Connection $connection | Out-Null
 $fortuneHtml=New-TextBlock 'PLAY / おみくじアプリ' $OmikujiText
 if ($OmikujiAppUrl) {
  $fortuneHtml+='<p><a href="'+(Encode-Html $OmikujiAppUrl)+'" target="_blank" rel="noopener noreferrer">おみくじを開く →</a></p>'
 } else {
  $fortuneHtml+='<p>アプリのリンクは準備中です。</p>'
 }
 Add-PnPPageTextPart -Page $pageFile -Section 6 -Column 1 -Order 1 -Text $fortuneHtml -Connection $connection | Out-Null
 $omikujiEmbedded=$false
 if ($OmikujiAppUrl -and $EmbedOmikuji -and -not $SkipPowerApps) {
  try {
   $fortuneFrame='<iframe src="'+(Encode-Html $OmikujiAppUrl)+'" width="1200" height="'+$PowerAppHeight+'" frameborder="0" title="おみくじアプリ"></iframe>'
   $fortuneProperties=@{embedCode=$fortuneFrame; cachedEmbedCode=$fortuneFrame; shouldScaleWidth=$true}
   Add-PnPPageWebPart -Page $pageFile -DefaultWebPartType ContentEmbed -WebPartProperties $fortuneProperties -Section 6 -Column 1 -Order 2 -Connection $connection | Out-Null
   $omikujiEmbedded=$true
  } catch { Write-Warning "おみくじの埋め込みを追加できませんでした。起動リンクを利用できます: $($_.Exception.Message)" }
 }

 $result=Get-PnPPage -Identity $pageFile -Connection $connection
 Write-Host "下書き作成完了: $pageUrl" -ForegroundColor Green
 Write-Host "埋め込みパーツ追加: $embedded / パーツ数: $($result.Controls.Count)"
 Write-Host '追加成功はアプリの表示成功を保証しません。ブラウザでサインインと表示を確認してください。'
 Write-Host 'ブラウザで確認して編集してください。公開とホーム切替は行っていません。'
 [pscustomobject]@{PageUrl=$pageUrl; PageName=$pageFile; PowerAppsEmbedAdded=$embedded; OmikujiEmbedAdded=$omikujiEmbedded; ThemeApplied=$themeApplied; Published=$false}
} catch {
 Write-Warning "途中まで作成された下書き: $pageUrl"
 if ($themeApplied) { Write-Warning 'サイトの配色は適用済みです。ページ作成の失敗では元に戻りません。' }
 Write-Warning '再実行すると別名の下書きが作られます。不要な下書きは確認後に削除してください。'
 throw
}

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

日記

前の記事

表示する列を設定
日記

次の記事

PnP実行用