다음을 통해 공유


PowerShell 및 저장소 공간 직접 성능 기록을 사용한 스크립팅

적용 대상: Windows Server 2022, Windows Server 2019

Windows Server 2019에서 저장소 공간 Direct는 가상 머신, 서버, 드라이브, 볼륨, 네트워크 어댑터 등에 대한 광범위한 성능 기록을 기록하고 저장합니다. 성능 기록은 PowerShell에서 쉽게 쿼리하고 처리할 수 있으므로 원시 데이터에서 실제 답변으로 빠르게 이동할 수 있습니다.

  1. 지난 주에 CPU 스파이크가 있었나요?
  2. 실제 디스크에 비정상적인 대기 시간이 있나요?
  3. 현재 가장 많은 스토리지 IOPS를 사용하는 VM은 무엇입니까?
  4. 네트워크 대역폭이 포화되었나요?
  5. 이 볼륨은 언제 사용 가능한 공간이 부족합니까?
  6. 지난 달에 가장 많은 메모리를 사용한 VM은 무엇입니까?

cmdlet은 Get-ClusterPerf 스크립팅을 위해 빌드됩니다. 연결을 처리하기 위해 파이프라인과 같은 Get-VM cmdlet의 Get-PhysicalDisk 입력을 허용하고, 출력을 유틸리티 cmdlet(예: Sort-ObjectWhere-Object유틸리티 cmdlet)으로 파이프하고 Measure-Object 강력한 쿼리를 신속하게 작성할 수 있습니다.

이 항목에서는 위의 6가지 질문에 답변하는 6개의 샘플 스크립트를 제공하고 설명합니다. 다양한 데이터 및 시간 범위에서 피크를 찾고, 평균을 찾고, 추세선을 표시하고, 이상값 검색을 실행하는 등 적용할 수 있는 패턴을 제공합니다. 복사, 확장 및 다시 사용할 수 있도록 무료 시작 코드로 제공됩니다.

참고 항목

간단히 하기 위해 샘플 스크립트는 고품질 PowerShell 코드에서 예상할 수 있는 오류 처리와 같은 항목을 생략합니다. 주로 생산용이 아닌 영감과 교육을 위한 것입니다.

샘플 1: CPU, 확인해 주세요!

이 샘플에서는 시간 범위의 계열을 LastWeek 사용하여 ClusterNode.Cpu.Usage 클러스터의 모든 서버에 대한 최대("상위 워터 마크"), 최소 및 평균 CPU 사용량을 표시합니다. 또한 간단한 사분위수 분석을 수행하여 지난 8일 동안 CPU 사용량이 25%, 50%, 75%를 초과한 시간을 보여 줍니다.

스크린샷

아래 스크린샷에서는 Server-02지난 주에 설명할 수 없는 급증을 보였습니다.

Screenshot that shows that Server-02 had an unexplained spike last week.

작동 원리

파이프에서 Get-ClusterPerf 기본 제공 Measure-Object cmdlet으로의 출력은 속성을 지정하기 Value 만 하면 됩니다. 플래그-Maximum-Minimum-AverageMeasure-Object 함께 처음 세 개의 열을 거의 무료로 제공합니다. 사분위수 분석을 수행하려면 25, 50 또는 75보다 큰 값 -Gt 수를 파이프 Where-Object 하고 계산할 수 있습니다. 마지막 단계는 도우미 기능을 사용하여 아름답게 하는 Format-HoursFormat-Percent 것입니다. 확실히 선택 사항입니다.

스크립트

스크립트는 다음과 같습니다.

Function Format-Hours {
    Param (
        $RawValue
    )
    # Weekly timeframe has frequency 15 minutes = 4 points per hour
    [Math]::Round($RawValue/4)
}

Function Format-Percent {
    Param (
        $RawValue
    )
    [String][Math]::Round($RawValue) + " " + "%"
}

$Output = Get-ClusterNode | ForEach-Object {
    $Data = $_ | Get-ClusterPerf -ClusterNodeSeriesName "ClusterNode.Cpu.Usage" -TimeFrame "LastWeek"

    $Measure = $Data | Measure-Object -Property Value -Minimum -Maximum -Average
    $Min = $Measure.Minimum
    $Max = $Measure.Maximum
    $Avg = $Measure.Average

    [PsCustomObject]@{
        "ClusterNode"    = $_.Name
        "MinCpuObserved" = Format-Percent $Min
        "MaxCpuObserved" = Format-Percent $Max
        "AvgCpuObserved" = Format-Percent $Avg
        "HrsOver25%"     = Format-Hours ($Data | Where-Object Value -Gt 25).Length
        "HrsOver50%"     = Format-Hours ($Data | Where-Object Value -Gt 50).Length
        "HrsOver75%"     = Format-Hours ($Data | Where-Object Value -Gt 75).Length
    }
}

$Output | Sort-Object ClusterNode | Format-Table

샘플 2: 화재, 화재, 대기 시간 이상값

이 샘플에서는 시간 범위의 PhysicalDisk.Latency.AverageLastHour 계열을 사용하여 시간당 평균 대기 시간이 모집단 평균보다 +3σ(3개의 표준 편차)를 초과하는 드라이브로 정의된 통계 이상값을 찾습니다.

Important

간단히 하기 위해 이 스크립트는 낮은 분산에 대한 보호 장치를 구현하지 않고, 부분 누락된 데이터를 처리하지 않으며, 모델 또는 펌웨어 등을 구분하지 않습니다. 적절한 판단을 수행하고 하드 디스크를 교체할지 여부를 결정하기 위해 이 스크립트에만 의존하지 마세요. 교육용으로만 제공됩니다.

스크린샷

아래 스크린샷에는 이상값이 없습니다.

Screenshot that shows there are no outliers.

작동 원리

먼저 일관되게 검사 유휴 또는 거의 유휴 드라이브를 제외합니다 PhysicalDisk.Iops.Total-Gt 1. 모든 활성 HDD의 경우 10초 간격으로 360개의 측정으로 구성된 시간 프레임을 파이프 LastHour 하여 Measure-Object -Average 지난 1시간 동안의 평균 대기 시간을 확보합니다. 이것은 우리의 인구를 설정합니다.

모집단의 평균 μ 및 표준 편차 σ 를 찾기 위해 널리 알려진 수식을 구현합니다. 모든 활성 HDD의 경우 평균 대기 시간을 모집단 평균과 비교하고 표준 편차로 나눕니다. 원시 값을 유지하므로 결과를 사용할 수 Sort-Object 있지만 도우미 함수를 Format-StandardDeviation 사용하여 Format-Latency 표시할 내용을 아름답게 만들 수 있습니다( 확실히 선택 사항).

드라이브가 +3σ를 초과하는 경우 빨간색으로 표시되고 Write-Host , 그렇지 않으면 녹색으로 표시됩니다.

스크립트

스크립트는 다음과 같습니다.

Function Format-Latency {
    Param (
        $RawValue
    )
    $i = 0 ; $Labels = ("s", "ms", "μs", "ns") # Petabits, just in case!
    Do { $RawValue *= 1000 ; $i++ } While ( $RawValue -Lt 1 )
    # Return
    [String][Math]::Round($RawValue, 2) + " " + $Labels[$i]
}

Function Format-StandardDeviation {
    Param (
        $RawValue
    )
    If ($RawValue -Gt 0) {
        $Sign = "+"
    }
    Else {
        $Sign = "-"
    }
    # Return
    $Sign + [String][Math]::Round([Math]::Abs($RawValue), 2) + "σ"
}

$HDD = Get-StorageSubSystem Cluster* | Get-PhysicalDisk | Where-Object MediaType -Eq HDD

$Output = $HDD | ForEach-Object {

    $Iops = $_ | Get-ClusterPerf -PhysicalDiskSeriesName "PhysicalDisk.Iops.Total" -TimeFrame "LastHour"
    $AvgIops = ($Iops | Measure-Object -Property Value -Average).Average

    If ($AvgIops -Gt 1) { # Exclude idle or nearly idle drives

        $Latency = $_ | Get-ClusterPerf -PhysicalDiskSeriesName "PhysicalDisk.Latency.Average" -TimeFrame "LastHour"
        $AvgLatency = ($Latency | Measure-Object -Property Value -Average).Average

        [PsCustomObject]@{
            "FriendlyName"  = $_.FriendlyName
            "SerialNumber"  = $_.SerialNumber
            "MediaType"     = $_.MediaType
            "AvgLatencyPopulation" = $null # Set below
            "AvgLatencyThisHDD"    = Format-Latency $AvgLatency
            "RawAvgLatencyThisHDD" = $AvgLatency
            "Deviation"            = $null # Set below
            "RawDeviation"         = $null # Set below
        }
    }
}

If ($Output.Length -Ge 3) { # Minimum population requirement

    # Find mean μ and standard deviation σ
    $μ = ($Output | Measure-Object -Property RawAvgLatencyThisHDD -Average).Average
    $d = $Output | ForEach-Object { ($_.RawAvgLatencyThisHDD - $μ) * ($_.RawAvgLatencyThisHDD - $μ) }
    $σ = [Math]::Sqrt(($d | Measure-Object -Sum).Sum / $Output.Length)

    $FoundOutlier = $False

    $Output | ForEach-Object {
        $Deviation = ($_.RawAvgLatencyThisHDD - $μ) / $σ
        $_.AvgLatencyPopulation = Format-Latency $μ
        $_.Deviation = Format-StandardDeviation $Deviation
        $_.RawDeviation = $Deviation
        # If distribution is Normal, expect >99% within 3σ
        If ($Deviation -Gt 3) {
            $FoundOutlier = $True
        }
    }

    If ($FoundOutlier) {
        Write-Host -BackgroundColor Black -ForegroundColor Red "Oh no! There's an HDD significantly slower than the others."
    }
    Else {
        Write-Host -BackgroundColor Black -ForegroundColor Green "Good news! No outlier found."
    }

    $Output | Sort-Object RawDeviation -Descending | Format-Table FriendlyName, SerialNumber, MediaType, AvgLatencyPopulation, AvgLatencyThisHDD, Deviation

}
Else {
    Write-Warning "There aren't enough active drives to look for outliers right now."
}

샘플 3: 시끄러운 이웃? 즉, 쓰기입니다!

성능 기록도 지금 당장에 대한 질문에 답할 수 있습니다. 새로운 측정값은 10초마다 실시간으로 사용할 수 있습니다. 이 샘플에서는 시간 범위의 VHD.Iops.TotalMostRecent 시리즈를 사용하여 클러스터의 모든 호스트에서 가장 많은 스토리지 IOPS를 사용하는 가장 바쁜 가상 머신(일부는 "가장 시끄럽다"라고도 함)을 식별하고 해당 활동의 읽기/쓰기 분석을 표시합니다.

스크린샷

아래 스크린샷에는 스토리지 작업별 상위 10개 가상 머신이 표시됩니다.

Screenshot that shows the Top 10 virtual machines by storage activity.

작동 원리

cmdlet Get-PhysicalDiskGet-VM 클러스터를 인식하지 않으므로 로컬 서버에서만 VM을 반환합니다. 모든 서버에서 병렬로 쿼리하기 위해 호출을 래핑합니다 Invoke-Command (Get-ClusterNode).Name { ... }. 모든 VM에 대해 측정VHD.Iops.Read값을 VHD.Iops.TotalVHD.Iops.Write 가져옵니다. 매개 변수를 -TimeFrame 지정하지 않으면 각각에 MostRecent 대한 단일 데이터 포인트를 가져옵니다.

이러한 시리즈는 이 VM의 활동의 합계를 모든 VHD/VHDX 파일에 반영합니다. 성능 기록이 자동으로 집계되는 예제입니다. VHD/VHDX별 분석을 가져오기 위해 VM 대신 개인 Get-VHD 을 파이프할 Get-ClusterPerf 수 있습니다.

모든 서버의 결과는 다음과 같이 $OutputSort-ObjectSelect-Object -First 10함께 제공됩니다. 결과를 VM이 Invoke-Command 실행되는 위치를 알기 위해 인쇄할 수 있는 원본을 나타내는 속성으로 데 PsComputerName 코레이팅합니다.

스크립트

스크립트는 다음과 같습니다.

$Output = Invoke-Command (Get-ClusterNode).Name {
    Function Format-Iops {
        Param (
            $RawValue
        )
        $i = 0 ; $Labels = (" ", "K", "M", "B", "T") # Thousands, millions, billions, trillions...
        Do { if($RawValue -Gt 1000){$RawValue /= 1000 ; $i++ } } While ( $RawValue -Gt 1000 )
        # Return
        [String][Math]::Round($RawValue) + " " + $Labels[$i]
    }

    Get-VM | ForEach-Object {
        $IopsTotal = $_ | Get-ClusterPerf -VMSeriesName "VHD.Iops.Total"
        $IopsRead  = $_ | Get-ClusterPerf -VMSeriesName "VHD.Iops.Read"
        $IopsWrite = $_ | Get-ClusterPerf -VMSeriesName "VHD.Iops.Write"
        [PsCustomObject]@{
            "VM" = $_.Name
            "IopsTotal" = Format-Iops $IopsTotal.Value
            "IopsRead"  = Format-Iops $IopsRead.Value
            "IopsWrite" = Format-Iops $IopsWrite.Value
            "RawIopsTotal" = $IopsTotal.Value # For sorting...
        }
    }
}

$Output | Sort-Object RawIopsTotal -Descending | Select-Object -First 10 | Format-Table PsComputerName, VM, IopsTotal, IopsRead, IopsWrite

샘플 4: 그들이 말했듯이, "25 공연은 새로운 10 공연입니다"

이 샘플에서는 시간 범위의 계열을 LastDay 사용하여 NetAdapter.Bandwidth.Total 이론적 최대 대역폭의 90%로 정의된 >네트워크 포화의 징후를 찾습니다. 클러스터의 모든 네트워크 어댑터에 대해 마지막 날에 관찰된 가장 높은 대역폭 사용량을 명시된 링크 속도와 비교합니다.

스크린샷

아래 스크린샷에서는 마지막 날에 Fabrikam NX-4 Pro #2 하나가 최고조에 달했음을 알 수 있습니다.

Screenshot that shows that Fabrikam NX-4 Pro #2 peaked in the last day.

작동 원리

위에서부터 모든 서버로의 트릭을 Get-NetAdapter 반복 Invoke-Command 하고 Get-ClusterPerf. 그 과정에서 "10Gbps"와 같은 문자열과 10000000000과 같은 원시 Speed 정수라는 두 가지 관련 속성을 LinkSpeed 가져옵니다. Measure-Object 마지막 날(미리 알림: 시간 범위의 각 측정 LastDay 값은 5분을 나타낸다)에서 평균 및 피크를 가져오고 바이트당 8비트를 곱하여 사과 대 사과 비교를 얻습니다.

참고 항목

Chelsio와 같은 일부 공급업체는 네트워크 어댑터 성능 카운터에 RDMA(원격 직접 메모리 액세스) 작업을 포함하므로 시리즈에 포함 NetAdapter.Bandwidth.Total 됩니다. 멜라녹스와 같은 다른 사람들은 그렇지 않을 수 있습니다. 공급업체가 그렇지 않은 경우 이 스크립트의 버전에 계열을 추가 NetAdapter.Bandwidth.RDMA.Total 하기만 하면 됩니다.

스크립트

스크립트는 다음과 같습니다.

$Output = Invoke-Command (Get-ClusterNode).Name {

    Function Format-BitsPerSec {
        Param (
            $RawValue
        )
        $i = 0 ; $Labels = ("bps", "kbps", "Mbps", "Gbps", "Tbps", "Pbps") # Petabits, just in case!
        Do { $RawValue /= 1000 ; $i++ } While ( $RawValue -Gt 1000 )
        # Return
        [String][Math]::Round($RawValue) + " " + $Labels[$i]
    }

    Get-NetAdapter | ForEach-Object {

        $Inbound = $_ | Get-ClusterPerf -NetAdapterSeriesName "NetAdapter.Bandwidth.Inbound" -TimeFrame "LastDay"
        $Outbound = $_ | Get-ClusterPerf -NetAdapterSeriesName "NetAdapter.Bandwidth.Outbound" -TimeFrame "LastDay"

        If ($Inbound -Or $Outbound) {

            $InterfaceDescription = $_.InterfaceDescription
            $LinkSpeed = $_.LinkSpeed

            $MeasureInbound = $Inbound | Measure-Object -Property Value -Maximum
            $MaxInbound = $MeasureInbound.Maximum * 8 # Multiply to bits/sec

            $MeasureOutbound = $Outbound | Measure-Object -Property Value -Maximum
            $MaxOutbound = $MeasureOutbound.Maximum * 8 # Multiply to bits/sec

            $Saturated = $False

            # Speed property is Int, e.g. 10000000000
            If (($MaxInbound -Gt (0.90 * $_.Speed)) -Or ($MaxOutbound -Gt (0.90 * $_.Speed))) {
                $Saturated = $True
                Write-Warning "In the last day, adapter '$InterfaceDescription' on server '$Env:ComputerName' exceeded 90% of its '$LinkSpeed' theoretical maximum bandwidth. In general, network saturation leads to higher latency and diminished reliability. Not good!"
            }

            [PsCustomObject]@{
                "NetAdapter"  = $InterfaceDescription
                "LinkSpeed"   = $LinkSpeed
                "MaxInbound"  = Format-BitsPerSec $MaxInbound
                "MaxOutbound" = Format-BitsPerSec $MaxOutbound
                "Saturated"   = $Saturated
            }
        }
    }
}

$Output | Sort-Object PsComputerName, InterfaceDescription | Format-Table PsComputerName, NetAdapter, LinkSpeed, MaxInbound, MaxOutbound, Saturated

샘플 5: 스토리지를 다시 트렌디하게 만드세요!

매크로 추세를 살펴보기 위해 성능 기록은 최대 1년 동안 유지됩니다. 이 샘플에서는 기간의 Volume.Size.Available 계열을 LastYear 사용하여 스토리지가 채워지는 속도를 결정하고 가득 찼을 때를 예측합니다.

스크린샷

아래 스크린샷에서는 백업 볼륨이 하루에 약 15GB를 추가하는 것을 볼 수 있습니다.

Screenshot that shows that the Backup volume is adding about 15 GB per day.

이 속도로 42일 후에 용량에 도달합니다.

작동 원리

기간에는 LastYear 하루에 하나의 데이터 포인트가 있습니다. 추세선에 맞게 두 점만 엄격하게 필요하지만 실제로는 14일과 같이 더 많은 것을 요구하는 것이 좋습니다. 범위 [1, 14]의 x에 대해 (x, y) 점의 배열을 설정하는 데 사용합니다Select-Object -Last 14. 이러한 점을 사용하여 찾을 $A 수 있는 간단한 선형 최소 제곱 알고리즘을 구현하고 $B 가장 적합한 y = ax + b의 줄을 매개 변수화합니다. 고등학교에 다시 오신 것을 환영합니다.

볼륨의 SizeRemaining 속성을 추세(기울기 $A)로 나누면 볼륨이 가득 찼을 때까지 스토리지 증가율의 현재 속도로 며칠을 조잡하게 예측할 수 있습니다. Format-Bytes, Format-TrendFormat-Days 도우미 함수는 출력을 아름답게 합니다.

Important

이 추정치는 선형이며 가장 최근의 14일 단위만을 기반으로 합니다. 더 정교하고 정확한 기술이 존재합니다. 적절한 판단을 수행하고 스토리지 확장에 투자할지 여부를 결정하기 위해 이 스크립트에만 의존하지 마세요. 교육용으로만 제공됩니다.

스크립트

스크립트는 다음과 같습니다.


Function Format-Bytes {
    Param (
        $RawValue
    )
    $i = 0 ; $Labels = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
    Do { $RawValue /= 1024 ; $i++ } While ( $RawValue -Gt 1024 )
    # Return
    [String][Math]::Round($RawValue) + " " + $Labels[$i]
}

Function Format-Trend {
    Param (
        $RawValue
    )
    If ($RawValue -Eq 0) {
        "0"
    }
    Else {
        If ($RawValue -Gt 0) {
            $Sign = "+"
        }
        Else {
            $Sign = "-"
        }
        # Return
        $Sign + $(Format-Bytes ([Math]::Abs($RawValue))) + "/day"
    }
}

Function Format-Days {
    Param (
        $RawValue
    )
    [Math]::Round($RawValue)
}

$CSV = Get-Volume | Where-Object FileSystem -Like "*CSV*"

$Output = $CSV | ForEach-Object {

    $N = 14 # Require 14 days of history

    $Data = $_ | Get-ClusterPerf -VolumeSeriesName "Volume.Size.Available" -TimeFrame "LastYear" | Sort-Object Time | Select-Object -Last $N

    If ($Data.Length -Ge $N) {

        # Last N days as (x, y) points
        $PointsXY = @()
        1..$N | ForEach-Object {
            $PointsXY += [PsCustomObject]@{ "X" = $_ ; "Y" = $Data[$_-1].Value }
        }

        # Linear (y = ax + b) least squares algorithm
        $MeanX = ($PointsXY | Measure-Object -Property X -Average).Average
        $MeanY = ($PointsXY | Measure-Object -Property Y -Average).Average
        $XX = $PointsXY | ForEach-Object { $_.X * $_.X }
        $XY = $PointsXY | ForEach-Object { $_.X * $_.Y }
        $SSXX = ($XX | Measure-Object -Sum).Sum - $N * $MeanX * $MeanX
        $SSXY = ($XY | Measure-Object -Sum).Sum - $N * $MeanX * $MeanY
        $A = ($SSXY / $SSXX)
        $B = ($MeanY - $A * $MeanX)
        $RawTrend = -$A # Flip to get daily increase in Used (vs decrease in Remaining)
        $Trend = Format-Trend $RawTrend

        If ($RawTrend -Gt 0) {
            $DaysToFull = Format-Days ($_.SizeRemaining / $RawTrend)
        }
        Else {
            $DaysToFull = "-"
        }
    }
    Else {
        $Trend = "InsufficientHistory"
        $DaysToFull = "-"
    }

    [PsCustomObject]@{
        "Volume"     = $_.FileSystemLabel
        "Size"       = Format-Bytes ($_.Size)
        "Used"       = Format-Bytes ($_.Size - $_.SizeRemaining)
        "Trend"      = $Trend
        "DaysToFull" = $DaysToFull
    }
}

$Output | Format-Table

샘플 6: 메모리 돼지, 실행할 수 있지만 숨길 수 없습니다.

성능 기록은 전체 클러스터에 대해 중앙에서 수집되고 저장되므로 VM이 호스트 간에 이동하는 횟수에 관계없이 서로 다른 컴퓨터의 데이터를 함께 연결할 필요가 없습니다. 이 샘플은 기간의 VM.Memory.AssignedLastMonth 시리즈를 사용하여 지난 35일 동안 가장 많은 메모리를 소비하는 가상 머신을 식별합니다.

스크린샷

아래 스크린샷에는 지난 달 메모리 사용량별 상위 10개 가상 머신이 표시됩니다.

Screenshot of PowerShell

작동 원리

위에서 소개한 트릭을 모든 서버에 반복 Invoke-Command 합니다 Get-VM . 모든 VM의 월평균을 구한 Select-Object -First 10 다음 Sort-Object 순위표를 얻는 데 사용합니다Measure-Object -Average. (아니면 우리의 것일 수도 있습니다. 대부분의 구함 목록?)

스크립트

스크립트는 다음과 같습니다.

$Output = Invoke-Command (Get-ClusterNode).Name {
    Function Format-Bytes {
        Param (
            $RawValue
        )
        $i = 0 ; $Labels = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
        Do { if( $RawValue -Gt 1024 ){ $RawValue /= 1024 ; $i++ } } While ( $RawValue -Gt 1024 )
        # Return
        [String][Math]::Round($RawValue) + " " + $Labels[$i]
    }

    Get-VM | ForEach-Object {
        $Data = $_ | Get-ClusterPerf -VMSeriesName "VM.Memory.Assigned" -TimeFrame "LastMonth"
        If ($Data) {
            $AvgMemoryUsage = ($Data | Measure-Object -Property Value -Average).Average
            [PsCustomObject]@{
                "VM" = $_.Name
                "AvgMemoryUsage" = Format-Bytes $AvgMemoryUsage.Value
                "RawAvgMemoryUsage" = $AvgMemoryUsage.Value # For sorting...
            }
        }
    }
}

$Output | Sort-Object RawAvgMemoryUsage -Descending | Select-Object -First 10 | Format-Table PsComputerName, VM, AvgMemoryUsage

이것으로 끝입니다. 이러한 샘플이 영감을 주고 시작하는 데 도움이 되기를 바랍니다. 저장소 공간 직접 성능 기록과 강력하고 스크립팅에 친숙한 Get-ClusterPerf cmdlet을 사용하면 질문하고 대답할 수 있습니다. – Windows Server 2019 인프라를 관리하고 모니터링할 때 복잡한 질문입니다.

추가 참조