Overvåking av tilgjengeligheten til verter med PowerShell

Hei alle, jeg vil dele en enkel instruksjon om «hvordan man kan slutte å pinge et dusin verter manuelt. Uten registrering og SMS!».

Overvåking av tilgjengeligheten til verter med PowerShellFra internett

Viktig: jeg er ikke programmerer eller systemadministrator, men jeg jobber samtidig med en stor mengde servere tjenester, og dette skriptet har jeg skrevet for min egen bekvemmelighet.

Alle som kan ha nytte av dette, oppfordres til å lese videre.

Hvorfor PowershellJeg har erfaring med å skrive enkle programmer i Python, men det krever enten en installert tolk eller rettigheter til å kjøre .exe-filer, noe som ikke alltid er mulig i mitt arbeid. Men et skript i Powershell finner oftere muligheten til å kjøre.

Ikke alle liker konsollen/terminalen

Jeg tror det ikke er noen motsetning her, ellers ville alle fortsatt brukt konsollebaserte e-postklienter, og GUI ville ikke blitt utviklet i *nix-systemer.

Siden jeg i hverdagen bruker Powershell ganske primitivt, prøvde jeg først å forstå om jeg kunne legge til GUI. Det viste seg at det er mulig, og ganske enkelt:

Overvåking av tilgjengeligheten til verter med PowerShell

Add-Type -assembly System.Windows.Forms #Koble til biblioteket
$main_form = New-Object System.Windows.Forms.Form #Opprett et objekt med vårt "vindu"

#Sett parametrene
$main_form.Text ='Links up' #Navn i toppteksten
$main_form.Width = 300 #Bredde på vinduet
$main_form.Height = 200 #Høyde på vinduet
$main_form.AutoSize = $true #La det endre størrelse selv om nødvendig
$main_form.ShowDialog() #Vis "vinduet"

Legg til et utgangselement, og vi får et elementært Windows-vindu. Tautologi?.

Overvåking av tilgjengeligheten til verter med PowerShell

Add-Type -assembly System.Windows.Forms #Koplete bibliotek

$main_form = New-Object System.Windows.Forms.Form #Oppretter en variabel med vårt "vindu"

#Setter parametere for det
$main_form.Text ='Links up' #Navn i tittelen
$main_form.Width = 300 #Bredde på vinduet
$main_form.Height = 200 #Høyde på vinduet
$main_form.AutoSize = $true #Lar det justere størrelse automatisk ved behov

$Label = New-Object System.Windows.Forms.Label #Alle formelementer vil bli lagret i variabler, men i bunn og grunn er dette objekter, som alle andre variabler i Powershell
$Label.Text = "Hei! Jeg er et enkelt Windows-vindu, hva har du oppnådd?" #Teksten som vises
$Label.Location  = New-Object System.Drawing.Point(10,65) #Plassering av objektet i vinduet (x,y)
$Label.AutoSize = $true 

$main_form.Controls.Add($Label) #Legger det opprettede objektet til vinduet, for å unngå at det blir borte under skriptutførelsen

$main_form.ShowDialog() #Åpner det elementære vinduet

La oss legge til noe dynamikk

Verktøyet jeg brukte til å "pinge Yandex" og montere *.iso har fått sitt eget GUI, men det er ikke nok. På samme måte kan informasjon om tilgjengelighet vises, men for overvåking må skriptet startes på nytt hver gang.

La oss først tegne to ikoner og legge til muligheten til å vise bilder.

Overvåking av tilgjengeligheten til verter med PowerShell

$PictureBox = New-Object system.Windows.Forms.PictureBox #Objektet for å vise bilder heter ganske logisk
$PictureBox.width = 10
$PictureBox.height = 10
$PictureBox.location = New-Object System.Drawing.Point(178,12)

#Her går vi til sak, og binder den viste bildet til resultatet av sjekk for tilgjengelighet av noden ved å bruke cmdleten
#<b>test-connection</b>, hvor:
#-Count - sender antall forespørslser
#-computer - IP eller domenenavn for forespørselen
#-quiet - for at vi kun skal få tilbake en Boolean-verdi
if ((test-connection -Count 1 -computer ya.ru -quiet) -eq $True) {
	$PictureBox.imageLocation = "C:Testyes.png" #Objektet refererer til det tilsvarende bildet 
}
Else {
	$PictureBox.imageLocation = "C:Testno.png" #Objektet refererer til det tilsvarende bildet 
}
$PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom

$main_form.Controls.Add($PictureBox)

Igjen krangler DNS-ene våre...

Overvåking av tilgjengeligheten til verter med PowerShell
Og vi legger til en knapp for å oppdatere visningene.

Overvåking av tilgjengeligheten til verter med PowerShell

$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(100,150) 
$Button.Size = New-Object System.Drawing.Size(80,30)
$Button.Text = "Reload"

# Knytt hendelsen for knappetrykk til hvert PictureBox i henhold til den tidligere beskrevne logikken
$Button.Add_Click({ 
	if ((Test-Connection -Count 1 -computer ya.ru -quiet) -eq $True)
		{$PictureBox.imageLocation	= "C:Testyes.png"}
	Else {$PictureBox.imageLocation	= "C:Testno.png"}
	  
	if ((Test-Connection -Count 1 -computer 8.8.8.8 -quiet) -eq $True)
		{$PictureBox1.imageLocation	= "C:Testyes.png"}
	Else {$PictureBox1.imageLocation	= "C:Testno.png"}
 	})

$main_form.Controls.Add($Button)

Overvåking av tilgjengeligheten til verter med PowerShell

Flott, nå er det produksjon!?

Ved å manuelt skrive inn omtrent et halvt dusin vertsnavn, innså jeg plutselig en ting — dette prosjektet vil ta slutt, vertene vil endres og jeg må redigere skriptet hver gang. På den ene siden er det ikke så farlig, det er jo en løsning for meg selv. På den annen side, se på hva som nå er resultatet:

Et syn ikke for de som er sarte

Add-Type -assembly System.Windows.Forms #Vi knyter til biblioteket

$main_form = New-Object System.Windows.Forms.Form #Vi oppretter en variabel for "vinduet" vårt

#Setter parametere for det via parametere
$main_form.Text ='Links up' #Navn i tittelen
$main_form.Width = 300 #Bredde på vinduet
$main_form.Height = 200 #Høyde på vinduet
$main_form.AutoSize = $true #Vi gir det mulighet til å justere størrelse automatisk ved behov

$Label = New-Object System.Windows.Forms.Label #Alle formelementer vil bli lagret i variabler, men i virkeligheten er dette objekter, som alle andre variabler i Powershell
$Label.Text = "ya.ru		............................" #Tekst som vises 
$Label.Location  = New-Object System.Drawing.Point(15,10) #Plassering av objektet inne i formen horisontalt og vertikalt (x,y)
$Label.AutoSize = $true 

$Label1 = New-Object System.Windows.Forms.Label #Alle formelementer vil bli lagret i variabler, men i virkeligheten er dette objekter, som alle andre variabler i Powershell
$Label1.Text = "8.8.8.8		............................" #Visningstext Googles DNS
$Label1.Location  = New-Object System.Drawing.Point(15,30) #Plassering av objektet inne i formen horisontalt og vertikalt (x,y)
$Label1.AutoSize = $true 

$Label2 = New-Object System.Windows.Forms.Label
$Label2.Text = "192.168.x.x	............................"
$Label2.Location  = New-Object System.Drawing.Point(15,50)
$Label2.AutoSize = $true

$Label3 = New-Object System.Windows.Forms.Label
$Label3.Text = "192.168.x.x	............................"
$Label3.Location  = New-Object System.Drawing.Point(15,70)
$Label3.AutoSize = $true

$Label4 = New-Object System.Windows.Forms.Label
$Label4.Text = "10.0.x.x	 ............................"
$Label4.Location  = New-Object System.Drawing.Point(15,90)
$Label4.AutoSize = $true

$Label5 = New-Object System.Windows.Forms.Label
$Label5.Text = "162.102.x.x	 ............................"
$Label5.Location  = New-Object System.Drawing.Point(15,110)
$Label5.AutoSize = $true

$PictureBox = New-Object system.Windows.Forms.PictureBox #Objektet for å vise bilder er logisk kalt
$PictureBox.width = 10
$PictureBox.height = 10

#Her går vi til sak og binder bildet som vises til resultatet av tilgjengelighetssjekken ved å bruke cmdlet
#<b>test-connection</b>, hvor:
#-Count - sender antallet af anmodninger
#-computer - IP eller domænenavn for anmodningen
#-quiet - for at returnere kun Boolean-værdien
$PictureBox.location = New-Object System.Drawing.Point(235,12)
if ((test-connection -Count 1 -computer ya.ru -quiet) -eq $True) {
	$PictureBox.imageLocation = "C:Testyes.png" #Objektet refererer til det tilsvarende billede 
}
Else {
	$PictureBox.imageLocation = "C:Testno.png" #Objektet refererer til det tilsvarende billede 
}
$PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom

$PictureBox1 = New-Object system.Windows.Forms.PictureBox #Objektet til at vise billedernavnet giver mening
$PictureBox1.width = 10
$PictureBox1.height = 10
$PictureBox1.location = New-Object System.Drawing.Point(235,32)
if ((test-connection -Count 1 -computer 8.8.8.8 -quiet) -eq $True) {
	$PictureBox1.imageLocation = "C:Testyes.png" #Objektet refererer til det tilsvarende billede 
}
Else {
	$PictureBox1.imageLocation = "C:Testno.png" #Objektet refererer til det tilsvarende billede 
}
$PictureBox1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom

$PictureBox2 = New-Object system.Windows.Forms.PictureBox #Objektet til at vise billedernavnet giver mening
$PictureBox2.width = 10
$PictureBox2.height = 10
$PictureBox2.location = New-Object System.Drawing.Point(235,52)
if ((test-connection -Count 1 -computer 192.168.x.x -quiet) -eq $True) {
	$PictureBox2.imageLocation = "C:Testyes.png" #Objektet refererer til det tilsvarende billede 
}
Else {
	$PictureBox2.imageLocation = "C:Testno.png" #Objektet refererer til det tilsvarende billede 
}
$PictureBox2.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom

$PictureBox3 = New-Object system.Windows.Forms.PictureBox #Objektet til at vise billedernavnet giver mening
$PictureBox3.width = 10
$PictureBox3.height = 10
$PictureBox3.location = New-Object System.Drawing.Point(235,72)
if ((test-connection -Count 1 -computer 192.168.x.x -quiet) -eq $True) {
	$PictureBox3.imageLocation = "C:Testyes.png" #Objektet refererer til det tilsvarende billede 
}
Else {
	$PictureBox3.imageLocation = "C:Testno.png" #Objektet refererer til det tilsvarende billede 
}
$PictureBox3.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom

$PictureBox4 = New-Object system.Windows.Forms.PictureBox #Objektet til at vise billedernavnet giver mening
$PictureBox4.width = 10
$PictureBox4.height = 10
$PictureBox4.location = New-Object System.Drawing.Point(235,92)
if ((test-connection -Count 1 -computer 10.0.x.x -quiet) -eq $True) {
	$PictureBox4.imageLocation = "C:Testyes.png" #Objektet refererer til det tilsvarende billede 
}
Else {
	$PictureBox4.imageLocation = "C:Testno.png" #Objektet refererer til det tilsvarende billede 
}
$PictureBox1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom

$PictureBox5 = New-Object system.Windows.Forms.PictureBox #Objektet til at vise billedernavnet giver mening
$PictureBox5.width = 10
$PictureBox5.height = 10
$PictureBox5.location = New-Object System.Drawing.Point(235,112)
if ((test-connection -Count 1 -computer 162.102.x.x -quiet) -eq $True) {
	$PictureBox5.imageLocation = "C:Testyes.png" #Objektet refererer til det tilsvarende billede 
	}
Else {
	$PictureBox5.imageLocation = "C:Testno.png" #Objektet refererer til det tilsvarende billede 
	}
$PictureBox5.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom

$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(100,150) 
$Button.Size = New-Object System.Drawing.Size(80,30)
$Button.Text = "Genindlæs"

# Binder til knapens klik-begivenhed angiver hver PictureBox i henhold til den tidligere beskrevne logik
$Button.Add_Click({ 
	if ((Test-Connection -Count 1 -computer ya.ru -quiet) -eq $True)
		{$PictureBox.imageLocation	= "C:Testyes.png"}
	Else {$PictureBox.imageLocation	= "C:Testno.png"}
	  
	if ((Test-Connection -Count 1 -computer 8.8.8.8 -quiet) -eq $True)
		{$PictureBox1.imageLocation	= "C:Testyes.png"}
	Else {$PictureBox1.imageLocation	= "C:Testno.png"}

	if ((Test-Connection -Count 1 -computer 192.168.x.x -quiet) -eq $True)
		{$PictureBox2.imageLocation	= "C:Testyes.png"}
	Else {$PictureBox2.imageLocation	= "C:Testno.png"}

	if ((Test-Connection -Count 1 -computer 192.168.x.x -quiet) -eq $True)
		{$PictureBox3.imageLocation	= "C:Testyes.png"}
	Else {$PictureBox3.imageLocation	= "C:Testno.png"}

	if ((Test-Connection -Count 1 -computer 10.0.x.x -quiet) -eq $True)
		{$PictureBox4.imageLocation	= "C:Testyes.png"}
	Else {$PictureBox4.imageLocation	= "C:Testno.png"}

	if ((Test-Connection -Count 1 -computer 162.102.x.x -quiet) -eq $True)
		{$PictureBox5.imageLocation	= "C:Testyes.png"}
	Else {$PictureBox5.imageLocation	= "C:Testno.png"}
	})

$main_form.Controls.Add($Label) #tilføjer det oprettede objekt til formularen, så det ikke går tabt under udførelsen af scriptet
$main_form.Controls.Add($Label1)
$main_form.Controls.Add($Label2)
$main_form.Controls.Add($Label3)
$main_form.Controls.Add($Label4)
$main_form.Controls.Add($Label5)
$main_form.Controls.Add($PictureBox)
$main_form.Controls.Add($PictureBox1)
$main_form.Controls.Add($PictureBox2)
$main_form.Controls.Add($PictureBox3)
$main_form.Controls.Add($PictureBox4)
$main_form.Controls.Add($PictureBox5)
$main_form.Controls.Add($Button)

$main_form.ShowDialog() #Kalder det meget enkle vindue

Selv om jeg holder det rent og følger strukturen, vil periodisk redigering føre til ikke de mest behagelige opplevelsene.

Først flytter vi tilgjengelighetssjekken til en egen funksjon, og stien til katalogen til en egen variabel:

$script_path	= "C:TestPS ping"

# Vi flytter den opprettede PictureBox-objektet og IP-adressen som skal sjekkes, til en funksjon.
# Resultatet endrer det lastede bildet.
function get_status($PictureBox,$path_ip) {
	if ((Test-Connection -Count 1 -computer $path_ip -quiet) -eq $True)
		{$PictureBox.imageLocation	= $script_path + "yes.png"}
	Else {$PictureBox.imageLocation	= $script_path + "no.png"} 
	}

Vi tar ut dataene om verten til en ekstern fil path.txt, og skriver dem i formatet «ip/host-funksjonsnavn/», mens vi tar dem inn i dokumentet som matriser. Vi vil også gjøre Y-posisjonsberegningen mer automatisert. Alt dette gir oss muligheten til å opprette Label-er og avmerkingsbokser ved å kalle funksjonen:

Overvåking av tilgjengeligheten til verter med PowerShell

#создаем описательную линию, на вход идут: объект Label, IP-адресс, описание и позиция по оси Y
Function Create_line($label,$path_ip,$caption, $top){ 
	$label.Location = New-Object System.Drawing.Point(1, $top)
	$label.text = $path_ip+$caption
	$label.font = $font
	$Label.AutoSize = $true
	}
#создаем индикатор для описательной линию, на вход идут: объект PictureBox, IP-адресс и позиция по оси Y
Function Create_link($PictureBox,$path_ip, $top){ 
	$PictureBox.width	= 10
	$PictureBox.height	= 10
	$PictureBox.location	= New-Object System.Drawing.Point(210,$top)
	get_status -PictureBox $PictureBox -path_ip $path_ip
	$PictureBox.SizeMode	= [System.Windows.Forms.PictureBoxSizeMode]::zoom
	}

$line = Get-content -LiteralPath $script_path"path.txt" #вытаскиваем данные о необходимых хостах
$len = $line.Length	#вычисляем длину, а точнее массив длин каждой строки

$i = 0

#далее объявляем массивы которые понадобятся дальше
$ip = @()	#массив ip
$capt = @()	#массив описания
$Labels =@()	#массив Label
$PictureBoxs =@()	#массив PictureBox

while($i -lt $len){
	$f = $line[$i].IndexOf("/") #вычисляем позицию начала описания
	$l = $line[$i].LastIndexOf("/")	#вычисляем позицию конца описания
	$ip += $line[$i].Substring(0,$f)	#вытаскиваем ip
	$capt += $line[$i].Substring($f+1,$l-$f-1)	#вытаскиваем описание

	#создаем поле Label
	Create_line -label ($label_obj = New-Object System.Windows.Forms.Label) -path_ip $ip[$i] -caption $capt[$i] -top $label_from_top
	#создаем поле PictureBox
	Create_link -PictureBox ($PictureBox_obj = New-Object system.Windows.Forms.PictureBox) -path_ip $ip[$i] -top $label_from_top

	$label_from_top += 15	#делаем "шаг" по оси Y

	$Labels	+= $label_obj	#вносим созданный Label в общий массив
	$PictureBoxs	+= $PictureBox_obj	#вносим созданный PictureBox в общий массив
	$main_form.Controls.Add($Labels[$i])
	$main_form.Controls.Add($PictureBoxs[$i])
	$i	+=1
	}

Vi legger til et sted for å vise tidspunktet for den siste sjekken, fordi det er praktisk, og vi vil også supplere handlingen når knappen trykkes.

Overvåking av tilgjengeligheten til verter med PowerShell

$Label0	= New-Object System.Windows.Forms.Label
$Label0.Text	= Get-Date
$Label0.Location	= New-Object System.Drawing.Point(80,180)
$Label0.AutoSize	= $true
$main_form.Controls.Add($Label0)
$Button.Add_Click({ 
	while($i -lt $len){
		get_status -PictureBox $PictureBoxs[$i] -path_ip $ip[$i]
		$i +=1
		}
	$Label0.Text	= Get-Date 
	})

Og jeg har også lagt til en liten funksjon som, ved oppdagelse av en utilgjengelig vert, ikke bare informerer om det med indikatorendring, men også skriker fra høyttalerne.

Add-Type -AssemblyName System.Speech
$voice	= New-Object System.Speech.Synthesis.SpeechSynthesizer
$voice.Rate	= 5
$voice.Speak("Advarsel! Advarsel! Base er under angrep!")

Så etter noen dekorasjoner og tilpasninger til et lesbart og praktisk format, ble det slik:

Den fullstendige koden for skriptet

Add-Type -AssemblyName System.Speech
Add-Type -assembly System.Windows.Forms

$script_path	= "C:PS ping"
$label_from_top	= 10
$voice	= New-Object System.Speech.Synthesis.SpeechSynthesizer
$voice.Rate	= 5

#Flytt til funksjonen allerede opprettet objekt PictureBox og IP-adressen som må kontrolleres.
#Det endrer bildet som lastes inn.
function get_status($PictureBox,$path_ip) {
	if ((Test-Connection -Count 1 -computer $path_ip -quiet) -eq $True) {
		$PictureBox.imageLocation	= $script_path + "yes.png"
		}
	Else {
		$PictureBox.imageLocation	= $script_path + "no.png"
		$voice.Speak("Feil! Vert " + $path_ip + ", utilgjengelig!")
		}
	}

#lager en beskrivende linje, inngangene er: Label-objekt, IP-adresse, beskrivelse og Y-posisjon
Function Create_line($label,$path_ip,$caption, $top){ 
	$label.Location	= New-Object System.Drawing.Point(1, $top)
	$label.text	= $path_ip+$caption
	$label.font	= $font
	$Label.AutoSize	= $true
	}

#lager en indikator for beskrivende linjer, inngangene er: PictureBox-objekt, IP-adresse og Y-posisjon
Function Create_link($PictureBox,$path_ip, $top){ 
	$PictureBox.width	= 10
	$PictureBox.height	= 10
	$PictureBox.location	= New-Object System.Drawing.Point(210,$top)
	get_status -PictureBox $PictureBox -path_ip $path_ip
	$PictureBox.SizeMode	= [System.Windows.Forms.PictureBoxSizeMode]::zoom
	}

$main_form	= New-Object System.Windows.Forms.Form
$main_form.Text ='Lenker aktivert' #Navn i tittelen
$main_form.Width = 300 #Bredde på vinduet
$main_form.Height = 200 #Høyde på vinduet
$main_form.AutoSize = $true #Lar det endre størrelse automatisk, om nødvendig
$main_form.TopMost	= $true #Dette er veldig viktig, det lar vinduet forbli foran andre

$line = Get-content -LiteralPath $script_path"path.txt" #henter data om nødvendige vertsnavn
$len = $line.Length	#beregner lengden, nærmere bestemt array-lengden til hver linje

$i = 0

#deklarerer videre arrayene som vil være nødvendige
$ip	= @()	#ip-array
$capt	= @()	#beskrivelse array
$Labels	=@()	#Label array
$PictureBoxs	=@()	#PictureBox array

while($i -lt $len){
	$f	= $line[$i].IndexOf("/") #beregner posisjonen til starten av beskrivelsen
	$l	= $line[$i].LastIndexOf("/")	#beregner posisjonen til slutten av beskrivelsen
	$ip	+= $line[$i].Substring(0,$f)	#henter ut ip
	$capt	+= $line[$i].Substring($f+1,$l-$f-1)	#henter ut beskrivelsen

	#lager et Label-felt
	Create_line -label ($label_obj = New-Object System.Windows.Forms.Label) -path_ip $ip[$i] -caption $capt[$i] -top $label_from_top
	#lager et PictureBox-felt
	Create_link -PictureBox ($PictureBox_obj = New-Object system.Windows.Forms.PictureBox) -path_ip $ip[$i] -top $label_from_top

	$label_from_top	+= 15	#øker "trinnet" på Y-aksen

	$Labels	+= $label_obj	#legger til den opprettede Label i den samlede arrayen
	$PictureBoxs	+= $PictureBox_obj	#legger til den opprettede PictureBox i den samlede arrayen
	$main_form.Controls.Add($Labels[$i])
	$main_form.Controls.Add($PictureBoxs[$i])
	$i	+=1
}

#det feltet med siste sjekketid
$Label0	= New-Object System.Windows.Forms.Label
$Label0.Text	= Get-Date
$Label0.Location	= New-Object System.Drawing.Point(80,180)
$Label0.AutoSize	= $true


#Fester klikkhendelsen på alle PictureBox-ene i henhold til den tidligere beskrevne logikken
$Button	= New-Object System.Windows.Forms.Button
$Button.Location	= New-Object System.Drawing.Size(100,200)
$Button.Size	= New-Object System.Drawing.Size(80,30)
$Button.Text	= "Last inn på nytt"

$Button.Add_Click({ 
	while($i -lt $len){
		get_status -PictureBox $PictureBoxs[$i] -path_ip $ip[$i]
		$i	+=1
		}
	$i	= 0
	$Label0.Text	= Get-Date 
})

$main_form.Controls.Add($Button)
$main_form.Controls.Add($Label0)

$main_form.ShowDialog()

Etterord

Jeg håper denne veiledningen vil være nyttig for noen. Hvis du har gjort dette siden du var liten, gratulerer, jeg har ikke gjort det. Men jeg er klar til å høre dine kommentarer og forslag.

For meg selv var det hyggelig å grave litt og samle en liten, men nyttig verktøy for hverdagen. Jeg planlegger å implementere tillegg og fjerning av noder fra GUI, samt gjøre det som burde vært implementert først — automatisk oppdatering av statuser uten behov for å «klikke» på knappen, slik at det ikke henger opp «powershell.exe».

Den nyeste versjonen av skriptet er på GitHub

Kilde: habr.com

Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere 🔥 Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere | ProHoster