Microsoft Windows
- Komendy CLI
- Sprawdzenie samej listy IPv4 kart sieciowych
- Reguły w firewallu dla ECHO / PING / ICMP
- Czyszczenie kosza wszystkich userów
- Sprawdzenie, kto wykonał restart OS
- Czyszczenie starych komponentów WinSxS
- Manualne wymuszenie synchronizacji AD on premis z EntraID
- Podłączanie się do WinRM - Powershell
- Instalacja Telnet poprzez powershell
- Zaszyfrowanie hasła dla secure-string w Powershell
- Zdalne uruchamianie skryptów PS
- Zarządzanie RemoteApps w Remote Desktop Services (RDS)
- Rebuild performance counter oraz resynchronizacja z WMI
- Rozszerzenie StorageTier (wymagane do powiększenia wolumenów przy S2D)
- Zmiana nazwy dla ClusterSharedVolume
- Wgranie danych poprzez WinRM (Powershell Remoting)
- Skrypty powershell
- Audyt grup z zagnieżdzoną grupą z innej domeny
- Skrypt wykonujący audyt wszystkich wpisów w DNS
- Skrypt do wysłania wiadomości e-mail
- Sprawdzenie otwartych / nasłuchujących portów wraz z aktywnym procesem
- Skrypt do odrzucenia starych paczek i czyszczenia bazy WSUS
- Skrypt dodający aliasy SMTP użytkownikom w parametrach AD
- Wyszukiwania zadania w Task Scheduler o odpowiedniej nazwie
- Wyszukiwanie frazy we wszystkich GPO.
- Pobieranie klucza BitLocker z AD
- Diagnostyka systemu
- Konfiguracja oprogramowania
Komendy CLI
Sprawdzenie samej listy IPv4 kart sieciowych
Wszystkie komendy uruchamiamy w powershell.
Komenda ipconfig:
ipconfig /all | findstr /I "Adapter | Descripton | IPv4"
Komenda Get-NetAdapter, z ładniejszym formatowaniem)
Get-NetAdapter | ForEach-Object {
$adapterName = $_.InterfaceAlias
$ipv4 = (Get-NetIPAddress -InterfaceAlias $adapterName -AddressFamily IPv4).IPAddress
[PSCustomObject]@{
"Karta sieciowa" = $adapterName
"Adres IPv4" = $ipv4 -join ", "
}
} | Format-Table -AutoSize
Reguły w firewallu dla ECHO / PING / ICMP
Dodanie reguł
New-NetFirewallRule -DisplayName "PING / ECHO / ICMP v4" -Direction Inbound -Protocol ICMPv4 -IcmpType 8 -Action Allow
New-NetFirewallRule -DisplayName "PING / ECHO / ICMP v6" -Direction Inbound -Protocol ICMPv6 -IcmpType 8 -Action Allow
Usunięcie reguł:
Remove-NetFirewallRule -DisplayName "PING / ECHO / ICMP v4"
Remove-NetFirewallRule -DisplayName "PING / ECHO / ICMP v6"
Sprawdzenie czy reguły o danej nazwie występują:
Get-NetFirewallRule | Where-Object DisplayName -like "*PING*"
Czyszczenie kosza wszystkich userów
Komendę uruchamiamy jako Administrator w cmd / powershell.
rd /s /q C:/$Recycle.bin
- /s oznacza usunięcie podfolderów
- /q oznacza quiet mode - nie będzie pytał o potwierdzenie
Docelowy dysk z C:/ można zmienić na odpowiedni
Sprawdzenie, kto wykonał restart OS
Komendę uruchamiamy jako Administrator w powershell.
Get-WinEvent -FilterHashtable @{logname = 'System'; id = 1074} | Format-Table -Property * -Wrap
Przykładowy wynik:
Czyszczenie starych komponentów WinSxS
Komendę uruchamiamy jako Administrator w cmd / powershell.
Dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase
Manualne wymuszenie synchronizacji AD on premis z EntraID
Komendę uruchamiamy jako Administrator w powershell na kontrolerze domeny ze skonfigurowanymi odpowiednimi połączeniami do Entra ID.
Start-ADSyncSyncCycle -PolicyType Delta
Podłączanie się do WinRM - Powershell
Uruchamiamy z poziomu powershell, po uruchomieniu usługi WinRM
Enter-PSSession -ComputerName "NazwaKomputera" -Credential (Get-Credential)
Instalacja Telnet poprzez powershell
Komendę uruchamiamy jako Administrator w powershell.
pkgmgr /iu:"TelnetClient"
Zaszyfrowanie hasła dla secure-string w Powershell
Komendę uruchamiamy jako użytkownik który będzie z tego hasła korzystał. Hasło wygenerowane będzie działać poprawnie tylko i wyłącznie użytkownikiem z którego wykonamy komendę.
Jeżeli powershell uruchomimy jako Administrator, to kontem wykonawczym np. w harmonogramie zadań musi być administrator.
'HasloDoZaszyfrowania' | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString
Przykładowy wynik:
Zdalne uruchamianie skryptów PS
Wykonujemy z poziomu Powershell jako użytkownik z uprawnieniami administracyjnymi na komputerze docelowym:
Invoke-Command -ComputerName <computer_name> -scriptblock {PowerShell.exe -ExecutionPolicy Bypass -File "/local/path/to/script.ps1"}
Zarządzanie RemoteApps w Remote Desktop Services (RDS)
RemoteApp to funkcja Remote Desktop Services (RDS), która pozwala na publikowanie aplikacji zdalnych, tak aby wyglądały i działały jak lokalne programy na komputerze użytkownika. Dzięki temu użytkownicy mogą uruchamiać aplikacje z serwera RDS bez potrzeby pełnego dostępu do pulpitu zdalnego.
Komendy uruchamiamy z poziomu powershell, z zainstalowanym modułem RemoteDesktop, najlepiej od razu na serwerze z zainstalowaną rolą Remote Desktop Services
Wylistowanie wszystkich aplikacji w kolekcji
# Wskazanie nazwy kolekcji z której pobieramy aplikacje
$collectionName = "Nazwa Kolekcji"
# Zaimportowanie modułu RemoteDesktop
Import-Module RemoteDesktop
# Pobieranie wszystkich RemoteApp z kolekcji
$remoteApps = Get-RDRemoteApp -CollectionName $collectionName
# Wyświetlanie pobranych aplikacji RemoteApp
$remoteApps | Select-Object Alias, DisplayName, FilePath
Dodanie nowej aplikacji do kolekcji
# Pobieranie nazwy kolekcji do której chcemy dodać aplikację
$collectionName = "Nazwa Kolekcji"
# Pobieranie parametrów nowej aplikacji
$lnkFilePath = "C:\Ścieżka\do\aplikacji\Skrót.lnk"
$iconFilePath = "C:\Ścieżka\do\pliku\ikony.ico"
$appAlias = "Alias aplikacji w RDS"
$appDisplayName = "Nazwa aplikacji w RDS wyświetlana dla użytkowników"
# Importowanie potrzebnego modułu powershell
Import-Module RemoteDesktop
# Dodanie nowej aplikacji
New-RDRemoteApp -CollectionName $collectionName -Alias $appAlias -DisplayName $appDisplayName -FilePath $lnkFilePath -IconPath $iconFilePath
Zmiana nazwy aplikacji w kolekcji
# Pobieranie nazwy kolekcji i aplikacji do zmiany
$collectionName = "Nazwa Kolekcji"
$alias = "Stara nazwa aplikacji"
# Pobieranie parametrów do zmiany
$newDisplayName = "Nowa nazwa aplikacji"
$newProgramPath = "C:\Ścieżka\do\aplikacji.lnk" #Bądź do skrótu
# Importowanie odpowieniego modułu powershell
Import-Module RemoteDesktop
# Zmiana nazwy aplikacji
Set-RDRemoteApp -CollectionName $collectionName -Alias $alias -DisplayName $newDisplayName -FilePath $newProgramPath
Usunięcie aplikacji z kolekcji
# Pobieranie nazwy kolekcji i aplikacji do usunięcia
$collectionName = "Nazwa Kolekcji"
$alias = "Aplikacja do usunięcia"
# Importowanie odpowieniego modułu powershell
Import-Module RemoteDesktop
# Usunięcie aplikacji z kolekcji
Remove-RDRemoteApp -CollectionName $collectionName -Alias $alias
Rebuild performance counter oraz resynchronizacja z WMI
Komendy uruchamiamy w CMD jako administrator
cd C:\Windows\system32
lodctr /R
cd C:\Windows\SysWOW64
lodctr /R
Resynchronizacja performance counterów z WMI
WINMGMT.EXE /RESYNCPERF
Rozszerzenie StorageTier (wymagane do powiększenia wolumenów przy S2D)
Powiększanie StoregeTier:
Pobieranie wszystkich VirtualDisks:
Get-VirtualDisk
Pobieranie nazwy StorageTier
Get-VirtualDisk "NazwaDyskuJeżeliZnamy" | Get-StorageTier | Select FriendlyName
Sprawdzenie parametrów konkretnego StorageTier
Get-StorageTier -FriendlyName "NazwaStorageTier"
Rozszerzanie odpowiedniego StorageTier do dedykowanej wielkości (MB/GB/TB itd)
Get-StorageTier -FriendlyName "NazwaStorageTier" | Resize-StorageTier -Size (10TB)
Powiększenie wolumenu :
Sprawdzenie nazwy dysku wirtualnego:
Get-VirtualDisk
Samo powiększanie wolumenu:
$VirtualDisk = Get-VirtualDisk "NazwaDysku"
$Partition = $VirtualDisk | Get-Disk | Get-Partition | Where PartitionNumber -Eq 2
$Partition | Resize-Partition -Size ($Partition | Get-PartitionSupportedSize).SizeMax
Wynik Get-VirtualDisk po powiększeniu:
Zmiana nazwy dla ClusterSharedVolume
Polecenia wykonujemy na hoście Hyper-V, z poziomu powershell, uruchomionego z uprawnieniami administratora
Pobieranie nazwy do zmiany:
Get-ClusterSharedVolume
(Get-ClusterSharedVolume -Name "NazwaDoZmiany").Name = "NowaNazwa"
Wgranie danych poprzez WinRM (Powershell Remoting)
Wcześniej musi być uruchomiona usługa WinRM, oraz musimy mieć włączony dostęp sieciowy do danego komputera
$cred = Get-Credential
$session = New-PSSession -ComputerName Nazwa-Komputera -Credential $cred
Copy-Item "C:\Temp\Plik Źródłowy.plik" `
-Destination "C:\Temp\Plik docelowy.plik" `
-ToSession $session
Skrypty powershell
Audyt grup z zagnieżdzoną grupą z innej domeny
Komendę uruchamiamy jako Administrator w powershell na systemie z zainstalowanymi przystawkami RSAT.
# Pytaj użytkownika o nazwę grupy, kontroler domeny (DC) i poświadczenia
$Group = Read-Host -Prompt "Podaj nazwę grupy"
$DC = Read-Host -Prompt "Podaj kontroler domeny badź jej nazwę (dc.example.local / example.local)"
$Credential = Get-Credential -Message "Podaj poświadczenia użytkownika do dostępu do domeny $DC"
# Pobierz członków grupy z określonego kontrolera domeny
$membership = Get-ADGroup $Group -Properties Member -Server $DC -Credential $Credential
$membership.Member | Group-Object { ($_ -split '(?=DC=)',2)[1] } |
ForEach-Object {
[adsi] $ldap = 'LDAP://{0}' -f $_.Name
[string] $domain = $ldap.Name
foreach($member in $_.Group) {
$obj = Get-ADObject $member -Server $domain -Credential $Credential
[pscustomobject]@{
MemberOf = $membership.Name
Domain = $domain
Name = $obj.Name
DSN = $obj.DistinguishedName
SamAccountName = $obj.SamAccountName
ObjectClass = $obj.ObjectClass
}
}
}
Wersja z zapisem pliku do CSV
# Pytaj użytkownika o nazwę grupy, kontroler domeny (DC) i poświadczenia
$Group = Read-Host -Prompt "Podaj nazwę grupy"
$DC = Read-Host -Prompt "Podaj kontroler domeny badź jej nazwę (dc.example.local / example.local)"
$Credential = Get-Credential -Message "Podaj poświadczenia użytkownika do dostępu do domeny $DC"
# Pobierz członków grupy z określonego kontrolera domeny
$membership = Get-ADGroup $Group -Properties Member -Server $DC -Credential $Credential
# Zbieramy obiekty członków grupy
$results = foreach ($domainGroup in $membership.Member | Group-Object { ($_ -split '(?=DC=)',2)[1] }) {
[adsi] $ldap = "LDAP://$($domainGroup.Name)"
[string] $domain = $ldap.Name
foreach ($member in $domainGroup.Group) {
$obj = Get-ADObject $member -Server $domain -Credential $Credential
[pscustomobject]@{
MemberOf = $membership.Name
Domain = $domain
Name = $obj.Name
DSN = $obj.DistinguishedName
SamAccountName = $obj.SamAccountName
ObjectClass = $obj.ObjectClass
}
}
}
# Pytanie do użytkownika czy zapisać wynik
$saveCsv = Read-Host -Prompt "Czy chcesz zapisać wynik do pliku CSV? (t/n)"
if ($saveCsv -eq 't') {
$path = Read-Host -Prompt "Podaj pełną ścieżkę do pliku CSV"
try {
$results | Export-Csv -Path $path -NoTypeInformation -Encoding UTF8
Write-Host "Wynik zapisano do pliku: $path" -ForegroundColor Green
}
catch {
Write-Host "Wystąpił błąd podczas zapisywania pliku:" -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
}
}
else {
Write-Host "Wynik nie został zapisany do pliku." -ForegroundColor Yellow
}
# Możesz też wyświetlić wyniki na ekranie jeśli chcesz
$results
Skrypt wykonujący audyt wszystkich wpisów w DNS
Skrypt uruchamiamy jako Administrator w powershell, z zainstalowanymi przystawkami RSAT - DNS.
Skrypt zapisujący wyniki do pliku:
### Pobieranie argumentu adresu serwera DNS ###
if ($args.Count -eq 2) {
$DnsServer = $args[0]
$SavePath = $args[1]
} else {
# Jeśli uruchomiono w ISE lub bez argumentów, prosi o wpisanie ręcznie
Write-Host "Uruchom skrypt poprzez ./NazwaSkryptu.ps1 AdresSerweraDNS ŚcieżkaDoPliku.txt bądź podaj je teraz: "
$DnsServer = Read-Host "Podaj adres serwera DNS"
$SavePath = Read-Host "Podaj ścieżkę do zapisu"
}
# Sprawdzenie czy podano ścieżkę do zapisu
if (-not $SavePath) {
Write-Host "Nie podano ścieżki do zapisu. Skrypt zostanie przerwany." -ForegroundColor Red
exit
}
# Pobranie stref DNS z serwera
$Zones = @(Get-DnsServerZone -ComputerName $DnsServer)
ForEach ($Zone in $Zones) {
# Wypisywanie strefy do konsoli i pliku
Write-Host "`n$($Zone.ZoneName)" -ForegroundColor "Green"
"`n$($Zone.ZoneName)" | Out-File -Append -FilePath $SavePath
# Pobranie rekordów DNS w strefie i zapis do pliku
Get-DnsServerResourceRecord -ComputerName $DnsServer -ZoneName $Zone.ZoneName | Out-File -Append -FilePath $SavePath
}
Write-Host "Zapis zakończony. Dane znajdują się w: $SavePath" -ForegroundColor Cyan
Przykładowe uruchomienie :
Skrypt który każdą zone pokazuje w osobnym, interaktywnym oknie
Uwaga! Przy większej ilości zone w DNS może zająć dużo czasu przez przeklikanie się przez wszystkie okna
Okna otwierają się dopiero po zamknięciu poprzedniego
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class WinAPI {
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"@ -Language CSharp
# Tworzenie formularza i ustawienie go na aktywne okno
[System.Windows.Forms.Application]::EnableVisualStyles()
$null = [System.Windows.Forms.Form]::new()
# Wyświetlenie okna dialogowego do wpisania adresu serwera DNS z instrukcją
$DnsServer = [Microsoft.VisualBasic.Interaction]::InputBox(
"Podaj adres serwera DNS w formacie: serwer.domena.local`n`n⚠ UWAGA: Skrypt musi być uruchomiony na komputerze z zainstalowaną przystawką RSAT: DNS!`n`n ⚠ UWAGA: Skrypt otwiera nowe interaktywne okno dla każdej zony!",
"Wprowadź adres DNS",
"serwer.domena.local"
)
# Ustawienie okna na pierwszym planie po zamknięciu InputBox
$process = Get-Process | Where-Object { $_.MainWindowTitle -match "Wprowadź adres DNS" }
if ($process) {
[WinAPI]::SetForegroundWindow($process.MainWindowHandle)
}
# Jeśli użytkownik nic nie wpisał i kliknął "Anuluj", skrypt się zatrzyma
if (-not $DnsServer) {
Write-Host "Nie podano adresu serwera DNS. Skrypt zostanie zakończony." -ForegroundColor Red
exit
}
# Pobranie stref DNS z serwera
$Zones = @(Get-DnsServerZone -ComputerName $DnsServer)
ForEach ($Zone in $Zones) {
Write-Host "`n$($Zone.ZoneName)" -ForegroundColor "Green"
# Pobranie rekordów DNS w strefie
$records = Get-DnsServerResourceRecord -ComputerName $DnsServer -ZoneName $Zone.ZoneName
if ($records) {
# Wymuszenie oczekiwania na zamknięcie Out-GridView przed otwarciem kolejnego
$records | Out-GridView -Title "Rekordy DNS - $($Zone.ZoneName)" -PassThru | Out-Null
} else {
Write-Host "Brak rekordów w strefie $($Zone.ZoneName)" -ForegroundColor Yellow
}
}
Write-Host "Koniec działania skryptu." -ForegroundColor Cyan
Przykładowe użycie:
Pytanie o serwer DNS
Interaktywne okno z wynikami
Skrypt do wysłania wiadomości e-mail
Uruchamiamy skrypt z poziomu Powershell ISE
$EmailFrom = "AdresNadawcy@domena.com"
$EmailTo = "AdresOdbiorcy@domena.com"
$SMTPServer = "smtp.domena.com" ## Adres serwera SMTP
$SMTPPort = 587 ## Port serwera
$SMTPUsername = "no-reply@domena.com"
$SMTPPassword = "SilneHasłoDoSkrzynki"
$Subject = "Temat Wiadomości"
$Body = "Treść wiadomości"
$SMTPPassword = ConvertTo-SecureString $SMTPPassword -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ($SMTPUsername, $SMTPPassword)
Send-MailMessage -From $EmailFrom -To $EmailTo -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Port $SMTPPort -Credential $Credential -UseSsl
Sprawdzenie otwartych / nasłuchujących portów wraz z aktywnym procesem
Skrypty uruchamiamy w powershell.
Samo pobranie danych bez parsowania wyników:
Get-NetTCPConnection | Sort-Object -Property LocalPort | Select-Object -Property LocalPort, RemoteAddress, RemotePort, State, OwningProcess | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name ProcessName -Value (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ProcessName)
$_
} | Format-Table -Property LocalPort, RemoteAddress, RemotePort, State, ProcessName
Przykładowy wynik:
Pobieranie danych z filtrowaniem po IP:
$ipFilter = "Szukanie danego IP"
Get-NetTCPConnection | Where-Object {
$_.RemoteAddress -eq $ipFilter -or $_.LocalAddress -eq $ipFilter
} | Sort-Object -Property LocalPort | Select-Object -Property LocalPort, RemoteAddress, RemotePort, State, OwningProcess | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name ProcessName -Value (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ProcessName)
$_
} | Format-Table -Property LocalPort, RemoteAddress, RemotePort, State, ProcessName
Przykładowy wynik:
Pobieranie danych i zapisanie wyników do pliku
# Definiowanie ścieżki do pliku CSV
$csvPath = "C:\LokalizacjaDoPliku\NazwaPliku.csv"
# Pobranie wszystkich połączeń TCP i dodanie informacji o procesie
Get-NetTCPConnection | Sort-Object -Property LocalPort | Select-Object -Property LocalPort, RemoteAddress, RemotePort, State, OwningProcess | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name ProcessName -Value (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ProcessName)
$_
} | Export-Csv -Path $csvPath -NoTypeInformation
Write-Host "Zapisano połączenia do pliku CSV: $csvPath"
Pobieranie danych za pomocą netstat -ano z parsowaniem wyników w CLI:
$netstatOutput = netstat -ano
$connections = @()
foreach ($line in $netstatOutput) {
if ($line -match '^\s*(TCP|UDP)') {
$parts = $line -split '\s+'
# Przypisanie wartości do odpowiednich zmiennych
$protocol = $parts[1]
$localAddress = $parts[2]
$remoteAddress = $parts[3]
$processID = ""
$state = ""
if ($protocol -eq 'TCP') {
$state = $parts[4]
$processID = $parts[5]
} elseif ($protocol -eq 'UDP') {
$state = "N/A"
$processID = $parts[4]
}
# Funkcja do dzielenia adresu i portu, zachowująca nawiasy IPv6
function Split-AddressPort ($address) {
if ($address -match '^\[(.+)\]:(\d+)$') {
# IPv6 z nawiasami np. [::1]:443
return @("[{0}]" -f $matches[1], $matches[2])
} elseif ($address -match '^(.+):(\d+)$') {
# IPv4 i inne adresy z portem np. 192.168.1.1:80
return @($matches[1], $matches[2])
} else {
# Adresy bez portów np. *:*
return @($address, "N/A")
}
}
$localIP, $localPort = Split-AddressPort $localAddress
$remoteIP, $remotePort = Split-AddressPort $remoteAddress
# Pobranie nazwy procesu lub ustawienie komunikatu
$processName = "Unknown"
if ($processID -eq "0") {
$processName = "Process terminated | PID = 0"
} elseif ($processID -match '^\d+$') {
try {
$processName = (Get-Process -Id $processID -ErrorAction SilentlyContinue).Name
} catch {
# Proces może już nie istnieć lub być niedostępny
}
}
$connections += [PSCustomObject]@{
Protocol = $protocol
LocalIP = $localIP
LocalPort = $localPort
RemoteIP = $remoteIP
RemotePort = $remotePort
ProcessId = $processID
State = $state
ProcessName = $processName
}
}
}
$connections | Sort-Object -Property LocalIP | Format-Table -AutoSize -Property Protocol, LocalIP, LocalPort, RemoteIP, RemotePort, ProcessId, State, ProcessName
Przykładowy wynik:
Pobieranie danych za pomocą netstat -ano z interaktywną tabelą
$netstatOutput = netstat -ano
$connections = @()
foreach ($line in $netstatOutput) {
if ($line -match '^\s*(TCP|UDP)') {
$parts = $line -split '\s+'
# Przypisanie wartości do odpowiednich zmiennych
$protocol = $parts[1]
$localAddress = $parts[2]
$remoteAddress = $parts[3]
$processID = ""
$state = ""
if ($protocol -eq 'TCP') {
$state = $parts[4]
$processID = $parts[5]
} elseif ($protocol -eq 'UDP') {
$state = "N/A"
$processID = $parts[4]
}
# Funkcja do dzielenia adresu i portu, zachowująca nawiasy IPv6
function Split-AddressPort ($address) {
if ($address -match '^\[(.+)\]:(\d+)$') {
# IPv6 z nawiasami np. [::1]:443
return @("[{0}]" -f $matches[1], $matches[2])
} elseif ($address -match '^(.+):(\d+)$') {
# IPv4 i inne adresy z portem np. 192.168.1.1:80
return @($matches[1], $matches[2])
} else {
# Adresy bez portów np. *:*
return @($address, "N/A")
}
}
$localIP, $localPort = Split-AddressPort $localAddress
$remoteIP, $remotePort = Split-AddressPort $remoteAddress
# Pobranie nazwy procesu lub ustawienie komunikatu
$processName = "Unknown"
if ($processID -eq "0") {
$processName = "Process terminated | PID = 0"
} elseif ($processID -match '^\d+$') {
try {
$processName = (Get-Process -Id $processID -ErrorAction SilentlyContinue).Name
} catch {
# Proces może już nie istnieć lub być niedostępny
}
}
$connections += [PSCustomObject]@{
Protocol = $protocol
LocalIP = $localIP
LocalPort = $localPort
RemoteIP = $remoteIP
RemotePort = $remotePort
ProcessId = $processID
State = $state
ProcessName = $processName
}
}
}
$connections | Sort-Object -Property LocalIP | Out-GridView
Przykładowy wynik:
Skrypt do odrzucenia starych paczek i czyszczenia bazy WSUS
Skrypt służy do automatycznego odrzucania przestarzałych aktualizacji w WSUS oraz uruchamiania procesu czyszczenia WSUS, jeśli dokonano jakichkolwiek zmian.
Wymagania:
- Uprawnienia administracyjne do serwera WSUS.
- Zainstalowany moduł PowerShell dla WSUS.
- Połączenie z serwerem WSUS.
Zakres działania:
Skrypt odrzuca aktualizacje, jeśli spełniają one którykolwiek z poniższych warunków:
- Są zastąpione przez nowsze aktualizacje (superseded).
- Są oznaczone jako wygasłe (expired) według definicji Microsoft.
- Dotyczą systemów operacyjnych x86 lub Itanium.
- Są przeznaczone dla systemu Windows XP.
- Są pakietami językowymi.
- Dotyczą starszych wersji przeglądarki Internet Explorer (wersje 7, 8, 9).
- Są aktualizacjami specyficznymi dla regionów (zawierają nazwy krajów).
- Są aktualizacjami beta.
- Są przeznaczone dla systemów wbudowanych (embedded).
Jeśli aktualizacja obejmuje wiele systemów operacyjnych i spełnia jeden lub więcej powyższych warunków, wersje aktualizacji, które nie spełniają tych kryteriów, nie zostaną odrzucone przez ten skrypt.
Przykład użycia:
Aby uruchomić skrypt, użyj poniższej komendy w PowerShell:
.\Decline-Updates -WSUSServer WSUSServer.Company.com -WSUSPort 8530
Gdzie:
- WSUSServer.Company.com - to adres Twojego serwera WSUS
- 8530 - to numer portu WSUS (domyślnie 8530 dla HTTP, 8531 dla HTTPS).
Efekty działania:
- Skrypt analizuje listę dostępnych aktualizacji.
- Odrzuca aktualizacje zgodnie z podanymi kryteriami.
- Jeśli odrzucono jakiekolwiek aktualizacje, skrypt uruchamia czyszczenie WSUS w celu zwolnienia miejsca na serwerze.
Treść skryptu
Param(
[Parameter(Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$false,
Position=0)]
[string]$WSUSServer = "Localhost", #default to localhost
[int]$WSUSPort=8530,
[switch]$reportonly
)
Function Decline-Updates{
Param(
[string]$WsusServer,
[int]$WSUSPort,
[switch]$ReportOnly
)
write-host "Connecting to WSUS Server $WSUSServer and getting list of updates"
$Wsus = Get-WSUSserver -Name $WSUSServer -PortNumber $WSUSPort
if($WSUS -eq $Null){
write-error "unable to contact WSUSServer $WSUSServer"
}else{
$Updates = $wsus.GetUpdates()
write-host "$(($Updates | where {$_.IsDeclined -eq $false} | measure).Count) Updates before cleanup"
$updatesToDecline = $updates | where {$_.IsDeclined -eq $false -and (
$_.IsSuperseded -eq $true -or #remove superseded updates
$_.PublicationState -eq "Expired" -or #remove updates that have been pulled by Microsoft
$_.LegacyName -imatch "ia64" -or #remove updates for itanium computers (1/2)
$_.LegacyName -imatch "x86" -or #remove updates for 32-bit computers
$_.LegacyName -match "XP" -or #remove Windows XP updates (1/2)
$_.producttitles -match "XP" -or #remove Windows XP updates (1/2)
$_.Title -match "Itanium" -or #remove updates for itanium computers (2/2)
$_.Title -match "ARM64" -or #remove updates for itanium computers (2/2)
($_.Title -imatch "language" -and $_.Title -notmatch "(PL|ENG)") -or #remove langauge packs
$_.Title -match "Sprachpaket" -or
$_.title -match "Internet Explorer 7" -or #remove updates for old versions of IE
$_.title -match "Internet Explorer 8" -or
$_.title -match "Internet Explorer 9" -or
$_.title -match "Japanese" -or #some non-english updates are not filtered by WSUS language filtering
$_.title -match "Korean" -or
$_.title -match "Taiwan" -or
$_.Title -match "Beta" -or #Beta products and beta updates
$_.title -match "Embedded" #Embedded version of Windows
)}
write-host "$(($updatesToDecline | measure).Count) Updates to decline"
$changemade = $false
if($reportonly){
write-host "ReportOnly was set to true, so not making any changes"
}else{
$changemade = $true
$updatesToDecline | %{$_.Decline()}
}
#Decline updates released more then 3 months prior to the release of an included service pack
# - service packs updates don't appear to contain the supersedance information.
Foreach($SP in $($updates | where title -match "^Windows Server \d{4} .* Service Pack \d")){
if(($SP.ProductTitles |measure ).count -eq 1){
$updatesToDecline = $updates | where {$_.IsDeclined -eq $false -and $_.ProductTitles -contains $SP.ProductTitles -and $_.CreationDate -lt $SP.CreationDate.Addmonths(-3)}
if($updatesToDecline -ne $null){
write-host "$(($updatesToDecline | measure).Count) Updates to decline (superseded by $($SP.Title))"
if(-not $reportonly){
$changemade = $true
$updatesToDecline | %{$_.Decline()}
}
}
}
}
#if changes were made, run a WSUS cleanup to recover disk space
if($changemade -eq $true -and $reportonly -eq $false){
$Updates = $wsus.GetUpdates()
write-host "$(($Updates | where {$_.IsDeclined -eq $false} | measure).Count) Updates remaining, running WSUS cleanup"
Invoke-WsusServerCleanup -updateServer $WSUS -CleanupObsoleteComputers -CleanupUnneededContentFiles -CleanupObsoleteUpdates -CompressUpdates -DeclineExpiredUpdates -DeclineSupersededUpdates
}
}
}
Decline-Updates -WSUSServer $WSUSServer -WSUSPort $WSUSPort -reportonly:$reportonly
Skrypt dodający aliasy SMTP użytkownikom w parametrach AD
Skrypt wykonujemy z poziomu PowerShell ISE po zmianie odpowiednich parametrów. Skrypt musi być uruchomiony na serwerze z zainstalowanym funkcją RSAT, z dostępem do domeny w której chcemy go uruchomić
# Importowanie modułu Active Directory
Import-Module ActiveDirectory
# Definicja zmiennych dla domen
$oldDomain = "staradomena.pl"
$newDomain = "nowadomena.pl"
# Określenie wyróżnionej nazwy (DN) docelowej jednostki organizacyjnej (OU)
$ou = "OU=Użytkownicy_Firma,OU=Kontakty,OU=Organizacja,DC=domena,DC=local"
# Pobranie wszystkich użytkowników (aktywnych i nieaktywnych) w określonym OU wraz z ich UserPrincipalName i ProxyAddresses
$users = Get-ADUser -Filter * -SearchBase $ou -Properties UserPrincipalName, ProxyAddresses, SamAccountName
# Iteracja przez każdego użytkownika (zarówno aktywnego, jak i nieaktywnego) i dodanie aliasu
foreach ($user in $users) {
# Upewnienie się, że użytkownik ma ustawiony UserPrincipalName
if ($user.UserPrincipalName -match "@$oldDomain$") {
# Wyodrębnienie nazwy użytkownika poprzez usunięcie starej domeny z UserPrincipalName
$username = $user.UserPrincipalName -replace "@$oldDomain", ""
# Utworzenie aliasu w formacie username@newDomain
$alias = "smtp:$username@$newDomain"
# Pobranie aktualnych ProxyAddresses (aliasów e-mail)
$proxyAddresses = $user.ProxyAddresses
# Upewnienie się, że ProxyAddresses jest zainicjalizowane
if (-not $proxyAddresses) {
$proxyAddresses = @()
}
# Sprawdzenie, czy alias już istnieje
if ($proxyAddresses -notcontains $alias) {
try {
# Dodanie nowego aliasu
Set-ADUser -Identity $user -Add @{ProxyAddresses=$alias}
Write-Host "Dodano alias $alias dla użytkownika $username"
} catch {
Write-Host "Błąd podczas dodawania aliasu $alias dla użytkownika $username: $_" -ForegroundColor Red
}
} else {
Write-Host "Alias $alias już istnieje dla użytkownika $username"
}
} else {
Write-Host "Pomijanie użytkownika $($user.SamAccountName), ponieważ nie ma poprawnego UserPrincipalName kończącego się na @$oldDomain" -ForegroundColor Yellow
}
}
Wyszukiwania zadania w Task Scheduler o odpowiedniej nazwie
Skrypt zapisuje pliki w aktualnie używanym folderze. Należy przejść w PWSH do katalogu docelowego
Skrypt uruchamiamy w PowerShell z uprawnieniami Administratora
# Definiujemy nazwę zadania do wyszukania
$taskName = 'NazwaTasku'
# Pobierz nazwę hosta i skonstruuj nazwę pliku
$hostname = $env:COMPUTERNAME
$filepath = "tasks_$hostname.txt"
# Wypisz wszystkie zadania wraz z nazwami i ścieżkami, zapisz do pliku
Get-ScheduledTask | Select-Object TaskName, TaskPath | Out-File -FilePath $filepath -Encoding UTF8
# Oddziel sekcje w pliku
Add-Content -Path $filepath "`nWeryfikacja czy istnieje task o określonej nazwie:`n"
# Sprawdź, czy zadanie o podanej nazwie istnieje, dopisz wynik na końcu pliku lub stosowny komunikat
$task = Get-ScheduledTask | Where-Object { $_.TaskName -eq $taskName }
if ($task) {
$task | Out-File -FilePath $filepath -Append -Encoding UTF8
} else {
Add-Content -Path $filepath "Brak zadania o nazwie $taskName"
}
Wyszukiwanie frazy we wszystkich GPO.
Skrypt tworzy katalog gdzie eksportuje pliki xml GPO po czym przeszukuje w nich ustawioną frazę. Katalog oraz pliki utworzą się w aktywnym katalogu PWSH
Skrypt uruchamiamy w PWSH z uprawnieniami administratora, na kontrolerze domeny
# Definiujemy wzorzec wyszukiwania na samej górze
$searchPattern = "SvcUpddate"
Write-Host "`nTworzę folder na raporty GPO w bieżącym katalogu..."
# Próba pobrania ścieżki skryptu, jeśli brak to używamy bieżącego katalogu
if ($MyInvocation.MyCommand.Path) {
$scriptFolder = Split-Path -Parent $MyInvocation.MyCommand.Path
} else {
Write-Host "Nie wykryto ścieżki skryptu, używam bieżącego katalogu."
$scriptFolder = (Get-Location).Path
}
$folder = Join-Path $scriptFolder "GPOReports"
New-Item -Path $folder -ItemType Directory -Force | Out-Null
Write-Host "Pobieram wszystkie obiekty GPO z domeny..."
$allgpos = Get-GPO -All
# Plik do zapisania raportu z listą i wynikiem w folderze skryptu
$reportFile = Join-Path $scriptFolder "GPO_export_and_scan_report.txt"
# Czyszczenie pliku jeśli istnieje
if (Test-Path $reportFile) {
Remove-Item $reportFile
}
Write-Host "Eksportuję wszystkie GPO do osobnych plików XML oraz zapisuję listę do pliku raportu..."
Add-Content -Path $reportFile "Lista wyeksportowanych GPO:`n"
$allgpos | ForEach-Object {
$path = Join-Path $folder ("{0}_{1}.xml" -f $_.DisplayName, $_.Id)
Write-Host ("Eksportuję GPO: {0}" -f $_.DisplayName)
Get-GPOReport -Guid $_.Id -ReportType Xml -Path $path
Add-Content -Path $reportFile $_.DisplayName
}
# Dodaj pustą linię do rozdzielenia sekcji
Add-Content -Path $reportFile "`nWyniki wyszukiwania wzorca '$searchPattern':`n"
Write-Host "Szukam wzorca '$searchPattern' we wszystkich wyeksportowanych raportach..."
$patternMatches = Select-String -Path (Join-Path $folder "*.xml") -Pattern $searchPattern
if ($patternMatches -and $patternMatches.Count -gt 0) {
$patternMatches | ForEach-Object { Add-Content -Path $reportFile $_.ToString() }
} else {
Add-Content -Path $reportFile "Brak wzorca '$searchPattern' w żadnym z raportów GPO."
}
Write-Host "`nGotowe! Pełny raport w pliku: $reportFile"
Pobieranie klucza BitLocker z AD
Należy uruchomić powershell jako user z uprawnieniami do odczytu atrybutów
$objComputer = Get-ADComputer NAZWAKOMPUTERA
$Bitlocker_Objects = Get-ADObject -Filter {objectclass -eq 'msFVE-RecoveryInformation'} -SearchBase $objComputer.DistinguishedName -Properties 'msFVE-RecoveryPassword'
$Bitlocker_Objects
Wynik:
Bardziej skomplikowana wersja - z pytaniem o nazwę komputera oraz poświadczenia domenowe:
# Pobieranie nazwy komputera
$ComputerName = Read-Host "Nazwa komputera [$env:COMPUTERNAME]"
if ([string]::IsNullOrWhiteSpace($ComputerName)) {
$ComputerName = $env:COMPUTERNAME
}
# Pobieranie poświadczeń domenowych
$Credentials = Get-Credential -Message "Poświadczenia do domeny AD"
# Wyszukanie odpowiedniego komputera
$objComputer = Get-ADComputer $ComputerName -Credential $Credentials
# Pobranie kluczy BitLocker z dodatkowymi polami
$Bitlocker_Object = Get-ADObject `
-Filter {objectclass -eq 'msFVE-RecoveryInformation'} `
-SearchBase $objComputer.DistinguishedName `
-Properties 'msFVE-RecoveryPassword','msFVE-RecoveryGuid','msFVE-VolumeGuid','whenCreated' `
-Credential $Credentials |
Sort-Object whenCreated -Descending |
Select-Object `
@{Name='CN'; Expression={ $ComputerName }},
@{Name='Bitlocker Password'; Expression={ $_.'msFVE-RecoveryPassword' }},
@{Name='Volume GUID'; Expression={ $_.'msFVE-VolumeGuid' }},
@{Name='Recovery GUID'; Expression={ $_.'msFVE-RecoveryGuid' }},
@{Name='Created'; Expression={ $_.whenCreated }}
# Wypisanie danych
$Bitlocker_Object | Format-Table -AutoSize
Wynik:
Diagnostyka systemu
Sprawdzenie SCSI dysku z poziomu GUI w OS dla zmian vCenter
Dokumentacja: Match Windows Disks to VMWare VMDK Files | Windows OS Hub (woshub.com)
Jak odróżnić identyczne dyski w vCenter z poziomu Windows:
Otwieramy konsolę Zarządzania Dyskami (diskmgmt.msc) w systemie Windows.
Nazwa kontrolera SCSI oraz numer urządzenia SCSI nie jest wyświetlana bezpośrednio na liście dysków.
Aby uzyskać numer urządzenia SCSI, klikamy prawym przyciskiem na dysk i wybieramy Właściwości. Informacja o porcie urządzenia dla dysku wirtualnego VMWare SCSI Disk Device znajduje się w polu Lokalizacja na zakładce Ogólne.
- Lokalizacja 160 = Kontroler SCSI Bus 0
- Lokalizacja 224 = Kontroler SCSI Bus 1
- Target ID 1 = ID urządzenia SCSI to 1
Łączymy te dane, aby uzyskać adres dysku SCSI, na przykład na podstawie poniższych zrzutów ekranu dysk jest w lokalizacji: SCSI(0:6).
Następnie otwieramy właściwości maszyny wirtualnej w kliencie VMWare vSphere. Znajdujemy dysk, który ma taki sam numer Virtual Device Node, jak ID, które uzyskano. W naszym przykładzie jest to SCSI(0:6).
Konfiguracja oprogramowania
Konfiguracja kont MSA / gMSA
Na kontrolerze domeny:
Logujemy się na konto w domenie w której chcemy użyć kont gMSA,
Używamy aplikację PowerShell by sprawdzić wersję domeny:
(Get-ADDomain).ForestMode
(Get-ADDomain).DomainMode

Dodajmy główny klucz KDS - Ustawiamy -10 godzin by automatycznie zresetować jego długość życia:
Add-KdsRootKey -EffectiveTime (Get-Date).AddHours(-10)

Testujemy poprawność klucza:
Test-KdsRootKey -KeyId (Get-KdsRootKey).KeyId

Dodajemy odpowiednie konto:
Ważne Częstotliwość automatycznej zmiany haseł można podać tylko przy tworzeniu konta, domyślnie jest 30dni
New-ADServiceAccount -Name NazwaKonta -DNSHostName NazwaKonta.AktualnaDomena -ManagedPasswordIntervalInDays LiczbaDni
![]()
Dla przykładu:
![]()

Dodajemy grupę która może zarządzać danym kontem i do niej konto komputera które może skorzystać z naszego konta gMSA

Set-ADServiceAccount -Identity "NazwaKonta" -PrincipalsAllowedToRetrieveManagedPassword "NazwaGrupy"
![]()
![]()
Na serwerze docelowym:
Najpierw musimy zainstalować przystawki powershell do zarządzania AD:
Add-WindowsFeature RSAT-AD-PowerShell

Resetujemy ticket autentykacji Kerberos:
klist purge -li 0x3e7

I instalujemy konto:
Install-ADServiceAccount -Identity "NazwaKonta"
![]()
Przykładowy wynik:

I weryfikujemy instalację:
Test-ADServiceAccount -Identity NazwaKonta

Po tych akcjach konto jest dostępne:


Na podstawie:
Secure group managed service accounts - Microsoft Entra | Microsoft Learn
Konfiguracja WinRM - Zarządzanie zdalne systemem operacyjnym
Sprawdzenie działania usług
Do zdalnego zarządzania systemem operacyjnym muszą być uruchomione usługi:
WinRM
Przepuszczenie ruchu sieciowego:
By można było się połączyć do danej maszyny, musimy przepuścić ruch po porcie 445 + 139 oraz warto też od razu dodać ping:
New-NetFirewallRule -DisplayName "Allow ICMPv4-In" -Protocol ICMPv4 -IcmpType 8 -Direction Inbound -Action Allow -Profile Any
netsh advfirewall firewall add rule name="Open Port 139 - SMB over NetBIOS" dir=in action=allow protocol=TCP localport=139
netsh advfirewall firewall add rule name="Open Port 445 - SMB" dir=in action=allow protocol=TCP localport=445
Problem "Access Denied (5)"
Dodatkwo, w razie problemów z "Access Denied (5)", należy zweryfikować wpis w rejestrze:
$newItemPropertySplat = @{
Name = 'LocalAccountTokenFilterPolicy'
Path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
PropertyType = 'DWord'
Value = 1
}
New-ItemProperty @newItemPropertySplat