2016-08-12 40 views
-1

質問はありません。ちょうど共有。これが間違った会場や方法の場合は申し訳ありませんが、私はこれらのフォーラムから多くを得て、PSを学び、PSで基本的に役立つものをやろうとしている人のためにちょっと戻ってみたいです。謝罪しましたが、私は編集者を通してスクリプトを実行しなければなりませんでした。とにかくここにある:DFSRバックログを監視するPowershellスクリプト

本当に「具体的な質問」ではありませんので、私はこれがCodeReview.StackExchangeが代わりにしたかのように行動するつもりです
################################################################################################### 
# File: DFSR-check-3-show-backlog.ps1 
# Desc: Simple monitor of DFSR backlog. 
# 
# Vers Date  Who Description 
# ---- ----  --- ----------- 
# v0.01 11-Aug-2016 sdo Initial draft, based on commands from BM. 
# v0.02 12-Aug-2016 sdo Use "Out-String" to trim the blank lines of the table. 
# v0.03 12-Aug-2016 sdo Extract count from verbose output if "100" items are returned. 
# v0.04 12-Aug-2016 sdo Write to a log file. 
# v0.05 12-Aug-2016 sdo Only display when different or every 100 entries. 
# v0.06 12-Aug-2016 sdo Same layout and counter as other two scripts. 
# v0.07 12-Aug-2016 sdo If the return backlog value is "", make it "0". 
# v0.08 12-Aug-2016 sdo If display is "0,0", make it "-", which is easier to see activity. 
# v0.09 12-Aug-2016 sdo Round anything > 100 to units of 100. 
# v0.10 12-Aug-2016 sdo Use a function so that display updates less often. 
################################################################################################### 


################################################################################################### 
# Functions... 

Function fn_count($p1) { 
    $return = [string]$p1 
    if ($return -eq "") {Return "0"} 
    if (fn_is_numeric($return)) { 
    $number = [int]$return 
    switch ($number) { 
    {$_ -ge 100} {$return = $(([math]::Round($_/100)) * 100) ; $return=[string]$return+"+" ; Return $return } 
    {$_ -ge 1} {Return "<100" } 
    {$_ -eq 0} {Return "0" } 
    } 
    } 
    Return $return 
} 

Function fn_display_header { 
    "" 
    "   Disp Cnt AppAxx   AppBxxxWorking AppCxxxx  AppKxx   AppTxxxFiles" 
    "   ===== ===== ======   ============== ========  ======   ============" 
} 

Function fn_is_numeric($p1) { 
    Return ($($p1.Trim()) -Match "^[-+]?([0-9]*\.[0-9]+|[0-9]+\.?)$") 
} 


################################################################################################### 
# Main code... 

$script_spec = $PSCommandPath 
$script_path = [System.IO.Path]::GetDirectoryName(   $script_spec  ) 
$script_name = [System.IO.Path]::GetFileNameWithoutExtension($script_spec  ) 
$script_log = [System.IO.Path]::ChangeExtension(   $script_spec, ".log") 

$Host.UI.RawUI.WindowTitle = $script_name 

$line = "" 
$z_count = 0 
$z_lines = 0 


fn_display_header 
fn_display_header | Out-File $script_log -Append 

while ($true) { 
    $prev = $line 

    $z_count++ 
    if (($z_count % 100) -eq 0) {$prev = ""} 


################################################################################################### 
# Establish whether DFSR is up/enabled/available, or unknown... 

    $set = $(DFSRDiag backlog /rgname:AppAxx   /rfname:AppAxx   /sendingmember:ZZZPAAACSFT001 /receivingmember:ZZZPAAACSFT002) 
    if ($LastExitCode -eq 0) {$AppAxx_Diag = "ok"} else {$AppAxx_Diag = "UNKNOWN"} 

    $set = $(DFSRDiag backlog /rgname:AppBxxxWorking /rfname:AppBxxxWorking /sendingmember:ZZZPAAACSFT001 /receivingmember:ZZZPAAACSFT002) 
    if ($LastExitCode -eq 0) {$AppBxxxWorking_Diag = "ok"} else {$AppBxxxWorking_Diag = "UNKNOWN"} 

    $set = $(DFSRDiag backlog /rgname:AppCxxxx  /rfname:AppCxxxx  /sendingmember:ZZZPAAACSFT001 /receivingmember:ZZZPAAACSFT002) 
    if ($LastExitCode -eq 0) {$AppCxxxx_Diag = "ok"} else {$AppCxxxx_Diag = "UNKNOWN"} 

    $set = $(DFSRDiag backlog /rgname:AppKxx   /rfname:AppKxx   /sendingmember:ZZZPAAACSFT001 /receivingmember:ZZZPAAACSFT002) 
    if ($LastExitCode -eq 0) {$AppKxx_Diag = "ok"} else {$AppKxx_Diag = "UNKNOWN"} 

    $set = $(DFSRDiag backlog /rgname:AppTxxxFiles /rfname:AppTxxxFiles /sendingmember:ZZZPAAACSTA003 /receivingmember:ZZZPAAACSTA004) 
    if ($LastExitCode -eq 0) {$AppTxxxFiles_Diag = "ok"} else {$AppTxxxFiles_Diag = "UNKNOWN"} 


################################################################################################### 
# Get DFSR back-log counts, from both sides... or report the "unknown" from the diagnostics... 

    if ($AppAxx_Diag -eq "ok") { 
    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT001 -DestinationComputerName ZZZPAAACSFT002 -GroupName AppAxx -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppAxx_Display = $count 

    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT002 -DestinationComputerName ZZZPAAACSFT001 -GroupName AppAxx -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppAxx_Display = $AppAxx_Display + "," + $count 
    } else { 
    $AppAxx_Display = $AppAxx_Diag 
    } 


    if ($AppBxxxWorking_Diag -eq "ok") { 
    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT001 -DestinationComputerName ZZZPAAACSFT002 -GroupName AppBxxxWorking -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppBxxxWorking_Display = $count 

    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT002 -DestinationComputerName ZZZPAAACSFT001 -GroupName AppBxxxWorking -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppBxxxWorking_Display = $AppBxxxWorking_Display + "," + $count 
    } else { 
    $AppBxxxWorking_Display = $AppBxxxWorking_Diag 
    } 


    if ($AppCxxxx_Diag -eq "ok") { 
    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT001 -DestinationComputerName ZZZPAAACSFT002 -GroupName AppCxxxx -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppCxxxx_Display = $count 

    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT002 -DestinationComputerName ZZZPAAACSFT001 -GroupName AppCxxxx -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppCxxxx_Display = $AppCxxxx_Display + "," + $count 
    } else { 
    $AppCxxxx_Display = $AppCxxxx_Diag 
    } 


    if ($AppKxx_Diag -eq "ok") { 
    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT001 -DestinationComputerName ZZZPAAACSFT002 -GroupName AppKxx -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppKxx_Display = $count 

    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT002 -DestinationComputerName ZZZPAAACSFT001 -GroupName AppKxx -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppKxx_Display = $AppKxx_Display + "," + $count 
    } else { 
    $AppKxx_Display = $AppKxx_Diag 
    } 


    if ($AppTxxxFiles_Diag -eq "ok") { 
    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSTA003 -DestinationComputerName ZZZPAAACSTA004 -GroupName AppTxxxFiles -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppTxxxFiles_Display = $count 

    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSTA004 -DestinationComputerName ZZZPAAACSTA003 -GroupName AppTxxxFiles -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
    if ($count -ne "ERROR") { 
     if ($count -ne "100") { $count = fn_count($count) } else { 
     $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
    $AppTxxxFiles_Display = $AppTxxxFiles_Display + "," + $count 
    } else { 
    $AppTxxxFiles_Display = $AppTxxxFiles_Diag 
    } 


################################################################################################### 
# Build the table for display... 

    if ($AppAxx_Display   -eq "0,0") {$AppAxx_Display   = "-"} 
    if ($AppBxxxWorking_Display -eq "0,0") {$AppBxxxWorking_Display = "-"} 
    if ($AppCxxxx_Display  -eq "0,0") {$AppCxxxx_Display  = "-"} 
    if ($AppKxx_Display   -eq "0,0") {$AppKxx_Display   = "-"} 
    if ($AppTxxxFiles_Display -eq "0,0") {$AppTxxxFiles_Display = "-"} 

    $table = @() 
    $table = New-Object PSObject -Property @{ 
    AppAxx   = $AppAxx_Display 
    AppBxxxWorking = $AppBxxxWorking_Display 
    AppCxxxx  = $AppCxxxx_Display 
    AppKxx   = $AppKxx_Display 
    AppTxxxFiles = $AppTxxxFiles_Display 
    } 

    $line = ($table | Format-Table -HideTableHeaders ` 
    @{ expression = { $_.AppAxx   } ; width = 15 } ` 
    ,@{ expression = { $_.AppBxxxWorking } ; width = 15 } ` 
    ,@{ expression = { $_.AppCxxxx  } ; width = 15 } ` 
    ,@{ expression = { $_.AppKxx   } ; width = 15 } ` 
    ,@{ expression = { $_.AppTxxxFiles } ; width = 15 } ` 
    | Out-String).Trim() 


    if ($line -ne $prev) { 
    $z_lines++ 

    if (($z_lines % 10) -eq 0) { 
     fn_display_header 
     fn_display_header | Out-File $script_log -Append 
    } 

    $display = $(Get-Date -Format T) + " " + $("{0:F0}" -f $z_lines).PadLeft(5) + " " + $("{0:F0}" -f $z_count).PadLeft(5) + " " + $line 

    $display 
    $display | Out-File $script_log -Append 
    } 

    Start-Sleep -Seconds 10 
} 

exit 
+0

5つの異なるDFSRクラスターペアと5つの異なるDFSR名前空間については、DFSR(つまり複製)が有効/無効/構成されているかどうかを確認し、そうであれば、 DFSR関係を定義し、バックログカウンタを表示します。私は表示/レポート/リスト/スクリーン/更新レートを表示するために削減しようとする機能を使用しました。つまり、バックログカウントのマイナーな変更には関心がありませんが、基本的なアクティビティと大きなバックログ、 DFSRが実際に動作していることを示します。 HTH。 – sdo

+0

あなたが書いたコードを紹介したい場合は、ブログやフォーラムを利用してください。あなたがそれをSOに掲示しなければならない場合:あなたのスクリプトが解決した問題についての質問を投稿し、あなた自身の答えとしてあなたのスクリプト(何らかの説明を含む)を投稿するだけで、 - )質問は明らかに話題外です。 –

+0

ok - 理解されました - 再び起こりません。 – sdo

答えて

0

  • $count = fn_count($count) - あなたは、パラメータとして配列を渡す場合を除き - - 彼らは、コマンドレットのように動作する機能が()を使用していないPowerShellで呼び出します。 $count = fn_count $count
  • fn_is_numeric($p1) - [int]::TryParse()を使用するか、[int]にキャストしてエラーをキャッチします。
  • fn_count($p1) - 疑わしいVisual Basicスタイルの冗長な名前付けスタイル、古いスタイルのパラメーター宣言、役に立たないパラメーター名
  • fn_count - 何ですか。この関数は、11行に14回、returnという単語があります。これは文字列にキャストします。これはコール時にも行います。最後の2桁を00にするか、< 100または0と言うだけで十分です。それはバグです.170インチで200 +。
  • [System.IO.Path]::GetDirectoryName()や友人 - >コピー・貼り付けコードの[IO.FileInfo].Directory
  • ミサ - 代わりに、個別に名前付き変数
  • $("{0:F0}" -f $z_lines).PadLeft(5)が表示されますがたくさんのリピートデータについて>セットアップの5行とForEachループ
  • 使用のHashtable "$z_lines".PadLeft(5)
  • DFSRDiagは、10行のコピー貼り付けと5つのカスタム変数名を持ち、スクリプトの次の部分に「OK」または「UNKNOWN」のテキストを入れるだけの呼び出しです。それを捨てて、次のコピーパンクチャンクとマージします。彼らはすでに肥大化しているが、

これ...ので、それをクリーンアップすることができます。これは私がするつもりです、私のコピー・貼り付けコード」の感触が長くなってきてい

if ($?) {$count = [string]$set.Count} else {$count = "ERROR"} 
if ($count -ne "ERROR") { 
    if ($count -ne "100") { $count = fn_count($count) } else { 
    $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } } 
$AppAxx_Display = $count 

REALLYCRAMMINGEVERYTHINGUPUNREADABLYで短縮します; fn_countはすでに$ p1を文字列にキャストしていますのでここでスキップしてください。fn_countは数字以外の文字列をそのまま通過させるので、 "ERROR"の場合はスキップして何でも入力してください。 (どうやって1つにすることができないのでしょうか?)読みにくいアライメントでネストされたたくさんのネストされたif/elseを忘れて、$ countをすべて実際には、1つまたは他のものをfn_countにスローし、その結果をAppAxxに一度に割り当てます。

  • $表/フォーマットテーブルshennanigansは:IDKのが、foreachループのためのセットアップコードの5行で、私はそれがほとんどぺしゃんこにすることができると思います。

  • この$Verbose = $($set = $(Get-DFSRBackLog ... | Select FullPathname)) 4>&1はコメントを外しています。私はそれに触れたくない。

はとにかく、私はセットアップ、5台のサーバーとそれらの複製メンバーのハッシュテーブルをfn_is_numericを落とし、1つのループにコピー&ペーストの二つの大きな塊になって、関数に二重には、Get-DFSRBacklogコールを引き抜きますfn_countをマージして"0,0"テストをそのソースに移動し、先ほどと同じハッシュテーブルの設定を再利用して$tableのものを整え、()のヒープを削除し、奇妙な数値の書式設定を行いました。それをオフにして、170-> 200+バグを修正しました:

################################################################################################### 
# File: DFSR-check-3-show-backlog.ps1 
# Desc: Simple monitor of DFSR backlog. 
# 
# Vers Date  Who Description 
# ---- ----  --- ----------- 
# v0.01 11-Aug-2016 sdo Initial draft, based on commands from BM. 
# v0.02 12-Aug-2016 sdo Use "Out-String" to trim the blank lines of the table. 
# v0.03 12-Aug-2016 sdo Extract count from verbose output if "100" items are returned. 
# v0.04 12-Aug-2016 sdo Write to a log file. 
# v0.05 12-Aug-2016 sdo Only display when different or every 100 entries. 
# v0.06 12-Aug-2016 sdo Same layout and counter as other two scripts. 
# v0.07 12-Aug-2016 sdo If the return backlog value is "", make it "0". 
# v0.08 12-Aug-2016 sdo If display is "0,0", make it "-", which is easier to see activity. 
# v0.09 12-Aug-2016 sdo Round anything > 100 to units of 100. 
# v0.10 12-Aug-2016 sdo Use a function so that display updates less often. 
################################################################################################### 


# Functions... ################################################################################### 


Function Test-DFSRAtoB { 
    Param($ComputerA, $ComputerB, $GroupName) 

    # Get the backlog count, either directly or from the verbose log 
    $verbose = $($set = $(Get-DFSRBackLog -Verbose -SourceComputerName $ComputerA -DestinationComputerName $ComputerB -GroupName $GroupName -ErrorAction SilentlyContinue | Select FullPathname)) 4>&1 
    if (!$?) { return "ERROR" } 
    $Count = if ("100" -ne $set.Count) { $set.Count } else { "$verbose".Split(" ")[-1] } 

    # Round the backlog count to (0, <100, nn00+), or return it unchanged if that fails 
    try { 

     if  (100 -le $Count) { $Count -replace '..$', '00+' } 
     elseif ( 1 -le $Count) { "<100" } 
     elseif ( 0 -eq $Count) { "0" } 

    } catch { $Count } 

} 

Function Show-Header { 
    "" 
    "   Disp Cnt AppAxx   AppBxxxWorking AppCxxxx  AppKxx   AppTxxxFiles" 
    "   ===== ===== ======   ============== ========  ======   ============" 
} 


################################################################################################### 
# Main code... 

$ScriptFileName = [System.IO.FileInfo]$PSCommandPath 
$ScriptLog = Join-Path $ScriptFileName.Directory "$($ScriptFileName.BaseName).log" 

$Host.UI.RawUI.WindowTitle = $ScriptFileName.Name 

$line = "" 
$z_count = 0 
$z_lines = 0 


Show-Header 
Show-Header| Out-File $ScriptLog -Append 

$Replications = @(
    @{Name='AppAxx';   Member1='ZZZPAAACSFT001'; Member2='ZZZPAAACSFT002'}, 
    @{Name='AppBxxxWorking'; Member1='ZZZPAAACSFT001'; Member2='ZZZPAAACSFT002'}, 
    @{Name='AppCxxxx';  Member1='ZZZPAAACSFT001'; Member2='ZZZPAAACSFT002'}, 
    @{Name='AppKxx';   Member1='ZZZPAAACSFT001'; Member2='ZZZPAAACSFT002'}, 
    @{Name='AppTxxxFiles'; Member1='ZZZPAAACSTA003'; Member2='ZZZPAAACSTA004'} 
) 

while ($true) { 

################################################################################################### 
# Establish whether DFSR is up/enabled/available, or unknown... 
# Get DFSR back-log counts, from both sides... or report the "unknown" from the diagnostics... 

    $DisplayData = @{} 

    $Replications | ForEach { 

    $set = $(DFSRDiag backlog /rgname:$_.Name /rfname:$_.Name /sendingmember:$_.Member1 /receivingmember:$_.Member2) 
    if ($LastExitCode -eq 0) 
    { 
     $AtoBResult = Test-DFSRAtoB $_.Member1 $_.Member2 $_.Name 
     $BtoAResult = Test-DFSRAtoB $_.Member2 $_.Member1 $_.Name 

     $Display = "$AtoBResult, $BtoAResult" 
     $DisplayData[$_.Name] = if ($Display -eq "0,0") { "-" } else { $Display } 
    } 
    else 
    { 
     $DisplayData[$_.Name] = "UNKNOWN" 
    } 

    } 

################################################################################################### 
# Build the table for display... 

    $prev = if (++$z_count % 100) { $line } else { "" } 

    $line = ([PSCustomObject]$DisplayData | Format-Table -HideTableHeaders ` 
    @{ expression = { $_.AppAxx   } ; width = 15 } ` 
    ,@{ expression = { $_.AppBxxxWorking } ; width = 15 } ` 
    ,@{ expression = { $_.AppCxxxx  } ; width = 15 } ` 
    ,@{ expression = { $_.AppKxx   } ; width = 15 } ` 
    ,@{ expression = { $_.AppTxxxFiles } ; width = 15 } ` 
    | Out-String).Trim() 


    if ($line -ne $prev) { 

    if ((++$z_lines % 10) -eq 0) { 
     Show-Header 
     Show-Header | Out-File $ScriptLog -Append 
    } 

    ($display = "$(Get-Date -Format T) $("$z_lines".PadLeft(5)) $("$z_count".PadLeft(5)) $line") 
    $display | Out-File $ScriptLog -Append 
    } 

    Start-Sleep -Seconds 10 
} 

exit 

私がしなかったことはそれをテストすることなので、そのまま動作するのではないかと疑います。うまくいけばそれは概念的には健全です。

+1

すごい!私の貧しいコードを徹底的に解読する時間を取ってくれてありがとう。はい、結果は概念的には健全です。 noobの最初のスクリプトとそれが本当にどうやって行われるべきかの違いの素晴らしい例です。どのような素晴らしい学習の練習。 – sdo

+1

私はDFSRdiagの呼び出しで '$ _。Name'(およびその他の)エンティティをカプセル化しました。つまり、 '/switch:$($_.Name)'を使用しなければなりませんでした。 )返されるカウントが空の文字列 ""なので、2つのif文を追加して "" 0に変更することは、あなたには明らかではありませんでした。これらの2つのマイナーな点を除けば、それは完璧な書き換えでした。私はそれをもう一度言います、あなたよりもはっきりしたレッスンです。非常に高く評価。 – sdo

+0

re point ii)実際にmain関数でGet-DSFRBackLogからの戻り値は$ Nullなので、これをテストして$ Countをゼロに変更します。 – sdo

関連する問題