最后活跃于 1789543730

dartokloning's Avatar dartokloning 修订了这个 Gist 1789543730. 跳至此修订

1 file changed, 807 insertions

dhcp-scope-monitor.ps1(file created)

@@ -0,0 +1,807 @@
1 + #requires -Version 7.0
2 + <#
3 + .SYNOPSIS
4 + Universal DHCP Scope Monitoring Utility
5 +
6 + .DESCRIPTION
7 + Cross-platform DHCP monitoring utility for:
8 + - Windows
9 + - macOS
10 + - Linux (including Debian)
11 +
12 + Execution modes:
13 + 1. LOCAL : On Windows with the DhcpServer module available.
14 + 2. REMOTE : On Windows/macOS/Linux using PowerShell Remoting over SSH
15 + to a Windows DHCP Server.
16 +
17 + Remote DHCP objects are flattened on the Windows server before being
18 + returned to non-Windows clients, avoiding CIM/MI serialization issues
19 + such as libmi errors on macOS/Linux.
20 +
21 + .EXAMPLE
22 + pwsh ./dhcp-monitor-universal.ps1
23 +
24 + On macOS/Linux (or Windows without the local DhcpServer module), the
25 + script asks for the DHCP Server hostname/IP and SSH username.
26 +
27 + .EXAMPLE
28 + pwsh ./dhcp-monitor-universal.ps1 -DhcpServer 192.168.1.10 -UserName "CONTOSO\\administrator"
29 +
30 + Skips the interactive server/username questions.
31 +
32 + .EXAMPLE
33 + pwsh ./dhcp-monitor-universal.ps1 -Mode Local
34 +
35 + Forces Local mode. Requires Windows and the DhcpServer module.
36 +
37 + .NOTES
38 + In Remote mode, the script interactively asks for:
39 + - DHCP Server hostname or IP address
40 + - SSH username
41 + #>
42 +
43 + param (
44 + [string]$DhcpServer,
45 + [string]$UserName,
46 + [ValidateSet("Auto", "Local", "Remote")]
47 + [string]$Mode = "Auto"
48 + )
49 +
50 + $ErrorActionPreference = "Stop"
51 + $script:DhcpSession = $null
52 + $script:ExecutionMode = $null
53 + $script:DhcpServer = $DhcpServer
54 + $script:UserName = $UserName
55 +
56 + # ============================================================
57 + # UI HELPERS
58 + # ============================================================
59 +
60 + function Show-Title {
61 + Clear-Host
62 + Write-Host "===================================================" -ForegroundColor Cyan
63 + Write-Host " Universal DHCP Scope Monitoring Utility" -ForegroundColor Cyan
64 + Write-Host "===================================================" -ForegroundColor Cyan
65 + Write-Host
66 + Write-Host "Client OS : $([System.Runtime.InteropServices.RuntimeInformation]::OSDescription)"
67 + Write-Host "Mode : $script:ExecutionMode"
68 + if ($script:ExecutionMode -eq "Remote") {
69 + Write-Host "DHCP Server : $script:DhcpServer"
70 + Write-Host "SSH User : $script:UserName"
71 + }
72 + Write-Host
73 + }
74 +
75 + function Wait-Enter {
76 + param([string]$Message = "Tekan ENTER untuk melanjutkan")
77 + [void](Read-Host $Message)
78 + }
79 +
80 + function Convert-ToDisplayString {
81 + param($Value)
82 + if ($null -eq $Value) { return "" }
83 + return $Value.ToString()
84 + }
85 +
86 + # ============================================================
87 + # CONNECTION / EXECUTION MODE
88 + # ============================================================
89 +
90 + function Test-LocalDhcpModule {
91 + if (-not $IsWindows) {
92 + return $false
93 + }
94 +
95 + return [bool](Get-Module -ListAvailable -Name DhcpServer)
96 + }
97 +
98 + function Connect-DhcpBackend {
99 + if ($Mode -eq "Local") {
100 + if (-not (Test-LocalDhcpModule)) {
101 + throw "Mode Local dipilih, tetapi module DhcpServer tidak tersedia."
102 + }
103 +
104 + Import-Module DhcpServer -ErrorAction Stop
105 + $script:ExecutionMode = "Local"
106 + return
107 + }
108 +
109 + if ($Mode -eq "Auto" -and (Test-LocalDhcpModule)) {
110 + Import-Module DhcpServer -ErrorAction Stop
111 + $script:ExecutionMode = "Local"
112 + return
113 + }
114 +
115 + $script:ExecutionMode = "Remote"
116 +
117 + Write-Host
118 + Write-Host "Remote DHCP Server Configuration" -ForegroundColor Cyan
119 + Write-Host "---------------------------------------------------"
120 +
121 + while ([string]::IsNullOrWhiteSpace($script:DhcpServer)) {
122 + $script:DhcpServer = Read-Host "DHCP Server hostname / IP"
123 + if ([string]::IsNullOrWhiteSpace($script:DhcpServer)) {
124 + Write-Host "DHCP Server tidak boleh kosong." -ForegroundColor Red
125 + }
126 + }
127 +
128 + while ([string]::IsNullOrWhiteSpace($script:UserName)) {
129 + $script:UserName = Read-Host "SSH username (contoh: DOMAIN\administrator)"
130 + if ([string]::IsNullOrWhiteSpace($script:UserName)) {
131 + Write-Host "Username tidak boleh kosong." -ForegroundColor Red
132 + }
133 + }
134 +
135 + Write-Host
136 + Write-Host "Menghubungkan ke Windows DHCP Server..." -ForegroundColor Cyan
137 + Write-Host "Server : $script:DhcpServer"
138 + Write-Host "User : $script:UserName"
139 + Write-Host
140 +
141 + try {
142 + $script:DhcpSession = New-PSSession `
143 + -HostName $script:DhcpServer `
144 + -UserName $script:UserName `
145 + -ErrorAction Stop
146 +
147 + Write-Host "Koneksi berhasil." -ForegroundColor Green
148 + Start-Sleep -Milliseconds 700
149 + }
150 + catch {
151 + throw "Gagal membuat PowerShell SSH session ke $script:DhcpServer. $($_.Exception.Message)"
152 + }
153 + }
154 +
155 + function Disconnect-DhcpBackend {
156 + if ($null -ne $script:DhcpSession) {
157 + try {
158 + Remove-PSSession -Session $script:DhcpSession -ErrorAction SilentlyContinue
159 + }
160 + catch {}
161 + $script:DhcpSession = $null
162 + }
163 + }
164 +
165 + function Test-DhcpSession {
166 + if ($script:ExecutionMode -ne "Remote") {
167 + return $true
168 + }
169 +
170 + if ($null -eq $script:DhcpSession) {
171 + return $false
172 + }
173 +
174 + return ($script:DhcpSession.State -eq "Opened")
175 + }
176 +
177 + # ============================================================
178 + # DATA ACCESS LAYER
179 + # ============================================================
180 +
181 + function Get-DhcpScopeData {
182 + param (
183 + [Parameter(Mandatory)]
184 + [string]$ScopeId
185 + )
186 +
187 + if ($script:ExecutionMode -eq "Local") {
188 + $s = Get-DhcpServerv4Scope -ScopeId $ScopeId -ErrorAction Stop
189 +
190 + return [PSCustomObject]@{
191 + ScopeId = Convert-ToDisplayString $s.ScopeId
192 + Name = $s.Name
193 + State = Convert-ToDisplayString $s.State
194 + StartRange = Convert-ToDisplayString $s.StartRange
195 + EndRange = Convert-ToDisplayString $s.EndRange
196 + SubnetMask = Convert-ToDisplayString $s.SubnetMask
197 + LeaseDuration = Convert-ToDisplayString $s.LeaseDuration
198 + }
199 + }
200 +
201 + return Invoke-Command -Session $script:DhcpSession -ArgumentList $ScopeId -ScriptBlock {
202 + param($RemoteScopeId)
203 +
204 + $s = Get-DhcpServerv4Scope -ScopeId $RemoteScopeId -ErrorAction Stop
205 +
206 + [PSCustomObject]@{
207 + ScopeId = if ($null -eq $s.ScopeId) { "" } else { $s.ScopeId.ToString() }
208 + Name = $s.Name
209 + State = if ($null -eq $s.State) { "" } else { $s.State.ToString() }
210 + StartRange = if ($null -eq $s.StartRange) { "" } else { $s.StartRange.ToString() }
211 + EndRange = if ($null -eq $s.EndRange) { "" } else { $s.EndRange.ToString() }
212 + SubnetMask = if ($null -eq $s.SubnetMask) { "" } else { $s.SubnetMask.ToString() }
213 + LeaseDuration = if ($null -eq $s.LeaseDuration) { "" } else { $s.LeaseDuration.ToString() }
214 + }
215 + } -ErrorAction Stop
216 + }
217 +
218 + function Get-DhcpStatisticsData {
219 + param (
220 + [Parameter(Mandatory)]
221 + [string]$ScopeId
222 + )
223 +
224 + if ($script:ExecutionMode -eq "Local") {
225 + $s = Get-DhcpServerv4ScopeStatistics -ScopeId $ScopeId -ErrorAction Stop
226 +
227 + return [PSCustomObject]@{
228 + Free = [long]$s.Free
229 + InUse = [long]$s.InUse
230 + PercentageInUse = [double]$s.PercentageInUse
231 + Reserved = [long]$s.Reserved
232 + Pending = [long]$s.Pending
233 + SuperscopeName = Convert-ToDisplayString $s.SuperscopeName
234 + }
235 + }
236 +
237 + return Invoke-Command -Session $script:DhcpSession -ArgumentList $ScopeId -ScriptBlock {
238 + param($RemoteScopeId)
239 +
240 + $s = Get-DhcpServerv4ScopeStatistics -ScopeId $RemoteScopeId -ErrorAction Stop
241 +
242 + [PSCustomObject]@{
243 + Free = [long]$s.Free
244 + InUse = [long]$s.InUse
245 + PercentageInUse = [double]$s.PercentageInUse
246 + Reserved = [long]$s.Reserved
247 + Pending = [long]$s.Pending
248 + SuperscopeName = if ($null -eq $s.SuperscopeName) { "" } else { $s.SuperscopeName.ToString() }
249 + }
250 + } -ErrorAction Stop
251 + }
252 +
253 + function Get-DhcpLeaseData {
254 + param (
255 + [Parameter(Mandatory)]
256 + [string]$ScopeId
257 + )
258 +
259 + if ($script:ExecutionMode -eq "Local") {
260 + $raw = @(Get-DhcpServerv4Lease -ScopeId $ScopeId -ErrorAction Stop)
261 +
262 + return @(
263 + foreach ($lease in $raw) {
264 + [PSCustomObject]@{
265 + IPAddress = Convert-ToDisplayString $lease.IPAddress
266 + HostName = Convert-ToDisplayString $lease.HostName
267 + ClientId = Convert-ToDisplayString $lease.ClientId
268 + AddressState = Convert-ToDisplayString $lease.AddressState
269 + LeaseExpiryTime = $lease.LeaseExpiryTime
270 + }
271 + }
272 + )
273 + }
274 +
275 + # IMPORTANT:
276 + # Materialize the DHCP CIM result first, then flatten every property
277 + # while still executing on Windows. This prevents libmi/CIM objects
278 + # from crossing the SSH remoting boundary.
279 + return @(
280 + Invoke-Command -Session $script:DhcpSession -ArgumentList $ScopeId -ScriptBlock {
281 + param($RemoteScopeId)
282 +
283 + $rawLeases = @(Get-DhcpServerv4Lease -ScopeId $RemoteScopeId -ErrorAction Stop)
284 +
285 + foreach ($lease in $rawLeases) {
286 + $expiry = $null
287 +
288 + if ($null -ne $lease.LeaseExpiryTime) {
289 + try {
290 + $expiry = $lease.LeaseExpiryTime.ToString("o")
291 + }
292 + catch {
293 + $expiry = $lease.LeaseExpiryTime.ToString()
294 + }
295 + }
296 +
297 + [PSCustomObject]@{
298 + IPAddress = if ($null -eq $lease.IPAddress) { "" } else { $lease.IPAddress.ToString() }
299 + HostName = if ($null -eq $lease.HostName) { "" } else { $lease.HostName.ToString() }
300 + ClientId = if ($null -eq $lease.ClientId) { "" } else { $lease.ClientId.ToString() }
301 + AddressState = if ($null -eq $lease.AddressState) { "" } else { $lease.AddressState.ToString() }
302 + LeaseExpiryTime = $expiry
303 + }
304 + }
305 + } -ErrorAction Stop
306 + )
307 + }
308 +
309 + # ============================================================
310 + # NORMALIZATION / SORTING
311 + # ============================================================
312 +
313 + function Convert-LeaseExpiry {
314 + param($Value)
315 +
316 + if ($null -eq $Value -or [string]::IsNullOrWhiteSpace($Value.ToString())) {
317 + return $null
318 + }
319 +
320 + if ($Value -is [datetime]) {
321 + return $Value
322 + }
323 +
324 + $parsed = [datetime]::MinValue
325 +
326 + if ([datetime]::TryParse(
327 + $Value.ToString(),
328 + [System.Globalization.CultureInfo]::InvariantCulture,
329 + [System.Globalization.DateTimeStyles]::RoundtripKind,
330 + [ref]$parsed
331 + )) {
332 + return $parsed
333 + }
334 +
335 + if ([datetime]::TryParse($Value.ToString(), [ref]$parsed)) {
336 + return $parsed
337 + }
338 +
339 + return $null
340 + }
341 +
342 + function Get-IPv4SortKey {
343 + param([string]$IPAddress)
344 +
345 + try {
346 + $bytes = [System.Net.IPAddress]::Parse($IPAddress).GetAddressBytes()
347 + if ($bytes.Count -ne 4) {
348 + return [uint64]::MaxValue
349 + }
350 +
351 + return (
352 + ([uint64]$bytes[0] -shl 24) -bor
353 + ([uint64]$bytes[1] -shl 16) -bor
354 + ([uint64]$bytes[2] -shl 8) -bor
355 + ([uint64]$bytes[3])
356 + )
357 + }
358 + catch {
359 + return [uint64]::MaxValue
360 + }
361 + }
362 +
363 + # ============================================================
364 + # SCOPE FUNCTIONS
365 + # ============================================================
366 +
367 + function Test-DhcpScope {
368 + param (
369 + [Parameter(Mandatory)]
370 + [string]$ScopeId
371 + )
372 +
373 + try {
374 + [void](Get-DhcpScopeData -ScopeId $ScopeId)
375 + return $true
376 + }
377 + catch {
378 + return $false
379 + }
380 + }
381 +
382 + function Show-ScopeSummary {
383 + param (
384 + [Parameter(Mandatory)]
385 + [string]$ScopeId
386 + )
387 +
388 + try {
389 + $scope = Get-DhcpScopeData -ScopeId $ScopeId
390 + $stats = Get-DhcpStatisticsData -ScopeId $ScopeId
391 +
392 + Write-Host
393 + Write-Host "Summary Scope" -ForegroundColor Yellow
394 + Write-Host "---------------------------------------------------"
395 +
396 + [PSCustomObject]@{
397 + ScopeId = $scope.ScopeId
398 + Name = $scope.Name
399 + State = $scope.State
400 + StartRange = $scope.StartRange
401 + EndRange = $scope.EndRange
402 + SubnetMask = $scope.SubnetMask
403 + LeaseDuration = $scope.LeaseDuration
404 + Free = $stats.Free
405 + InUse = $stats.InUse
406 + PercentageInUse = ("{0:N2}%" -f [double]$stats.PercentageInUse)
407 + Reserved = $stats.Reserved
408 + Pending = $stats.Pending
409 + SuperscopeName = $stats.SuperscopeName
410 + } | Format-List | Out-Host
411 +
412 + Write-Host "---------------------------------------------------"
413 +
414 + if ([double]$stats.PercentageInUse -ge 95) {
415 + Write-Host "WARNING: Scope hampir penuh!" -ForegroundColor Red
416 + }
417 + elseif ([double]$stats.PercentageInUse -ge 80) {
418 + Write-Host "WARNING: Pemakaian scope sudah tinggi." -ForegroundColor Yellow
419 + }
420 + else {
421 + Write-Host "Status kapasitas scope masih aman." -ForegroundColor Green
422 + }
423 +
424 + Write-Host
425 + }
426 + catch {
427 + Write-Host
428 + Write-Host "Gagal membaca Scope $ScopeId." -ForegroundColor Red
429 + Write-Host $_.Exception.Message -ForegroundColor DarkRed
430 + Write-Host
431 + }
432 + }
433 +
434 + # ============================================================
435 + # DEVICE / LEASE LIST
436 + # ============================================================
437 +
438 + function Show-ScopeClients {
439 + param (
440 + [Parameter(Mandatory)]
441 + [string]$ScopeId
442 + )
443 +
444 + Clear-Host
445 +
446 + Write-Host "===================================================" -ForegroundColor Cyan
447 + Write-Host " DHCP Lease / Device List" -ForegroundColor Cyan
448 + Write-Host "===================================================" -ForegroundColor Cyan
449 + Write-Host
450 + Write-Host "ScopeId : $ScopeId" -ForegroundColor Yellow
451 + Write-Host
452 +
453 + try {
454 + $leases = @(Get-DhcpLeaseData -ScopeId $ScopeId)
455 +
456 + if ($leases.Count -eq 0) {
457 + Write-Host "Tidak ada lease yang dikembalikan untuk scope ini." -ForegroundColor Yellow
458 + Write-Host
459 + return
460 + }
461 +
462 + $normalized = @(
463 + foreach ($lease in $leases) {
464 + [PSCustomObject]@{
465 + IPAddress = $lease.IPAddress
466 + HostName = $lease.HostName
467 + ClientId = $lease.ClientId
468 + AddressState = $lease.AddressState
469 + LeaseExpiryTime = Convert-LeaseExpiry $lease.LeaseExpiryTime
470 + }
471 + }
472 + )
473 +
474 + $normalized |
475 + Sort-Object @{ Expression = { Get-IPv4SortKey $_.IPAddress } } |
476 + Select-Object IPAddress, HostName, ClientId, AddressState, LeaseExpiryTime |
477 + Format-Table -AutoSize |
478 + Out-Host
479 +
480 + Write-Host
481 + Write-Host "---------------------------------------------------"
482 + Write-Host "Total lease : $($normalized.Count)" -ForegroundColor Cyan
483 +
484 + $activeCount = @(
485 + $normalized | Where-Object { $_.AddressState -match '^Active' }
486 + ).Count
487 +
488 + Write-Host "Active lease: $activeCount" -ForegroundColor Green
489 + Write-Host "---------------------------------------------------"
490 + Write-Host
491 + }
492 + catch {
493 + Write-Host
494 + Write-Host "Gagal membaca daftar lease." -ForegroundColor Red
495 + Write-Host $_.Exception.Message -ForegroundColor DarkRed
496 + Write-Host
497 + }
498 + }
499 +
500 + # ============================================================
501 + # LEASE ANALYSIS
502 + # ============================================================
503 +
504 + function Show-LeaseAnalysis {
505 + param (
506 + [Parameter(Mandatory)]
507 + [string]$ScopeId
508 + )
509 +
510 + Clear-Host
511 +
512 + Write-Host "===================================================" -ForegroundColor Cyan
513 + Write-Host " DHCP Lease Analysis" -ForegroundColor Cyan
514 + Write-Host "===================================================" -ForegroundColor Cyan
515 + Write-Host
516 + Write-Host "ScopeId : $ScopeId" -ForegroundColor Yellow
517 + Write-Host
518 +
519 + try {
520 + $now = Get-Date
521 + $scope = Get-DhcpScopeData -ScopeId $ScopeId
522 + $stats = Get-DhcpStatisticsData -ScopeId $ScopeId
523 + $rawLeases = @(Get-DhcpLeaseData -ScopeId $ScopeId)
524 +
525 + $leases = @(
526 + foreach ($lease in $rawLeases) {
527 + [PSCustomObject]@{
528 + IPAddress = $lease.IPAddress
529 + HostName = $lease.HostName
530 + ClientId = $lease.ClientId
531 + AddressState = $lease.AddressState
532 + LeaseExpiryTime = Convert-LeaseExpiry $lease.LeaseExpiryTime
533 + }
534 + }
535 + )
536 +
537 + $leasesWithExpiry = @(
538 + $leases | Where-Object { $null -ne $_.LeaseExpiryTime }
539 + )
540 +
541 + $expired = @(
542 + $leasesWithExpiry |
543 + Where-Object { $_.LeaseExpiryTime -lt $now }
544 + ).Count
545 +
546 + $expireWithin4Hour = @(
547 + $leasesWithExpiry |
548 + Where-Object {
549 + $_.LeaseExpiryTime -ge $now -and
550 + $_.LeaseExpiryTime -le $now.AddHours(4)
551 + }
552 + ).Count
553 +
554 + $beyond4Hour = @(
555 + $leasesWithExpiry |
556 + Where-Object { $_.LeaseExpiryTime -gt $now.AddHours(4) }
557 + ).Count
558 +
559 + Write-Host "Waktu Pemeriksaan : $now"
560 + Write-Host "Lease Duration : $($scope.LeaseDuration)"
561 + Write-Host
562 +
563 + Write-Host "Pool Statistics" -ForegroundColor Yellow
564 + Write-Host "---------------------------------------------------"
565 +
566 + [PSCustomObject]@{
567 + Free = $stats.Free
568 + InUse = $stats.InUse
569 + PercentageInUse = ("{0:N2}%" -f [double]$stats.PercentageInUse)
570 + Reserved = $stats.Reserved
571 + Pending = $stats.Pending
572 + } | Format-List | Out-Host
573 +
574 + Write-Host
575 + Write-Host "Lease Expiration Analysis" -ForegroundColor Yellow
576 + Write-Host "---------------------------------------------------"
577 +
578 + [PSCustomObject]@{
579 + TotalLease = $leases.Count
580 + WithExpiry = $leasesWithExpiry.Count
581 + Expired = $expired
582 + ExpireWithin4Hour = $expireWithin4Hour
583 + Beyond4Hour = $beyond4Hour
584 + } | Format-Table -AutoSize | Out-Host
585 +
586 + Write-Host
587 + Write-Host "Interpretasi" -ForegroundColor Yellow
588 + Write-Host "---------------------------------------------------"
589 +
590 + if ([double]$stats.PercentageInUse -ge 95) {
591 + Write-Host "Kapasitas scope : KRITIS (>=95%)." -ForegroundColor Red
592 + }
593 + elseif ([double]$stats.PercentageInUse -ge 80) {
594 + Write-Host "Kapasitas scope : TINGGI (>=80%)." -ForegroundColor Yellow
595 + }
596 + else {
597 + Write-Host "Kapasitas scope : AMAN (<80%)." -ForegroundColor Green
598 + }
599 +
600 + if ($leasesWithExpiry.Count -gt 0) {
601 + if ($beyond4Hour -gt ($leasesWithExpiry.Count / 2)) {
602 + Write-Host "Mayoritas lease masih memiliki expiry lebih dari 4 jam." -ForegroundColor Yellow
603 + Write-Host "Kemungkinan masih banyak lease lama dari konfigurasi sebelumnya."
604 + }
605 + else {
606 + Write-Host "Mayoritas lease sudah berada dalam window 4 jam." -ForegroundColor Green
607 + }
608 + }
609 + else {
610 + Write-Host "Tidak ada data expiry lease yang dapat dianalisis." -ForegroundColor Yellow
611 + }
612 +
613 + Write-Host
614 + }
615 + catch {
616 + Write-Host
617 + Write-Host "Gagal melakukan Lease Analysis." -ForegroundColor Red
618 + Write-Host $_.Exception.Message -ForegroundColor DarkRed
619 + Write-Host
620 + }
621 + }
622 +
623 + # ============================================================
624 + # MAIN PROGRAM
625 + # ============================================================
626 +
627 + try {
628 + Connect-DhcpBackend
629 +
630 + while ($true) {
631 + Show-Title
632 +
633 + if (-not (Test-DhcpSession)) {
634 + throw "PowerShell remote session tidak lagi dalam state Opened."
635 + }
636 +
637 + Write-Host "Masukkan ScopeId yang ingin diperiksa." -ForegroundColor Green
638 + Write-Host "Contoh: 10.110.114.0"
639 + Write-Host
640 + Write-Host "Ketik 0 untuk keluar."
641 + Write-Host
642 +
643 + $ScopeId = Read-Host "ScopeId"
644 +
645 + if ($ScopeId -eq "0") {
646 + break
647 + }
648 +
649 + if ([string]::IsNullOrWhiteSpace($ScopeId)) {
650 + Write-Host
651 + Write-Host "ScopeId tidak boleh kosong." -ForegroundColor Red
652 + Write-Host
653 + Wait-Enter
654 + continue
655 + }
656 +
657 + if (-not (Test-DhcpScope -ScopeId $ScopeId)) {
658 + Write-Host
659 + Write-Host "ScopeId '$ScopeId' tidak ditemukan atau tidak dapat dibaca." -ForegroundColor Red
660 + Write-Host
661 + Wait-Enter "Tekan ENTER untuk mencoba lagi"
662 + continue
663 + }
664 +
665 + $changeScope = $false
666 +
667 + while (-not $changeScope) {
668 + Show-Title
669 + Show-ScopeSummary -ScopeId $ScopeId
670 +
671 + Write-Host "Apa yang ingin dilakukan?" -ForegroundColor Green
672 + Write-Host
673 + Write-Host "[1] Tampilkan daftar lease / perangkat"
674 + Write-Host "[2] Lease Analysis"
675 + Write-Host "[3] Cek ScopeId lain"
676 + Write-Host "[4] Refresh summary scope ini"
677 + Write-Host "[0] Keluar"
678 + Write-Host
679 +
680 + $choice = Read-Host "Pilihan"
681 +
682 + switch ($choice) {
683 + "1" {
684 + Show-ScopeClients -ScopeId $ScopeId
685 +
686 + $clientMenu = $true
687 + while ($clientMenu) {
688 + Write-Host "Apa yang ingin dilakukan selanjutnya?" -ForegroundColor Green
689 + Write-Host
690 + Write-Host "[1] Kembali ke summary scope ini"
691 + Write-Host "[2] Lease Analysis"
692 + Write-Host "[3] Cek ScopeId lain"
693 + Write-Host "[4] Refresh daftar lease"
694 + Write-Host "[0] Keluar"
695 + Write-Host
696 +
697 + $subChoice = Read-Host "Pilihan"
698 +
699 + switch ($subChoice) {
700 + "1" {
701 + $clientMenu = $false
702 + }
703 + "2" {
704 + Show-LeaseAnalysis -ScopeId $ScopeId
705 + Write-Host
706 + Wait-Enter "Tekan ENTER untuk kembali"
707 + $clientMenu = $false
708 + }
709 + "3" {
710 + $clientMenu = $false
711 + $changeScope = $true
712 + }
713 + "4" {
714 + Show-ScopeClients -ScopeId $ScopeId
715 + }
716 + "0" {
717 + return
718 + }
719 + default {
720 + Write-Host
721 + Write-Host "Pilihan tidak valid." -ForegroundColor Red
722 + Write-Host
723 + }
724 + }
725 + }
726 + }
727 +
728 + "2" {
729 + Show-LeaseAnalysis -ScopeId $ScopeId
730 +
731 + $analysisMenu = $true
732 + while ($analysisMenu) {
733 + Write-Host "Apa yang ingin dilakukan selanjutnya?" -ForegroundColor Green
734 + Write-Host
735 + Write-Host "[1] Kembali ke summary scope ini"
736 + Write-Host "[2] Tampilkan daftar lease / perangkat"
737 + Write-Host "[3] Cek ScopeId lain"
738 + Write-Host "[4] Refresh Lease Analysis"
739 + Write-Host "[0] Keluar"
740 + Write-Host
741 +
742 + $subChoice = Read-Host "Pilihan"
743 +
744 + switch ($subChoice) {
745 + "1" {
746 + $analysisMenu = $false
747 + }
748 + "2" {
749 + Show-ScopeClients -ScopeId $ScopeId
750 + Write-Host
751 + Wait-Enter "Tekan ENTER untuk kembali"
752 + $analysisMenu = $false
753 + }
754 + "3" {
755 + $analysisMenu = $false
756 + $changeScope = $true
757 + }
758 + "4" {
759 + Show-LeaseAnalysis -ScopeId $ScopeId
760 + }
761 + "0" {
762 + return
763 + }
764 + default {
765 + Write-Host
766 + Write-Host "Pilihan tidak valid." -ForegroundColor Red
767 + Write-Host
768 + }
769 + }
770 + }
771 + }
772 +
773 + "3" {
774 + $changeScope = $true
775 + }
776 +
777 + "4" {
778 + # Loop refreshes summary.
779 + }
780 +
781 + "0" {
782 + return
783 + }
784 +
785 + default {
786 + Write-Host
787 + Write-Host "Pilihan tidak valid." -ForegroundColor Red
788 + Start-Sleep -Seconds 1
789 + }
790 + }
791 + }
792 + }
793 + }
794 + catch {
795 + Write-Host
796 + Write-Host "FATAL ERROR" -ForegroundColor Red
797 + Write-Host "---------------------------------------------------"
798 + Write-Host $_.Exception.Message -ForegroundColor Red
799 + Write-Host
800 + exit 1
801 + }
802 + finally {
803 + Disconnect-DhcpBackend
804 + Write-Host
805 + Write-Host "Keluar dari Universal DHCP Scope Monitoring Utility." -ForegroundColor Cyan
806 + Write-Host
807 + }
更新 更早