Kontode muutmine domeenis

Vahel on vaja korraga paljusid domeenikontosid muuta.  Näiteks vahetus osakonna juht ja nüüd oleks vaja kõikide osakonna töötajate kontodel juhi atribuut ära muuta:

#Requires -Version 3.0
#Requires -Modules ActiveDirectory

$vana = Get-ADUser "Mihkel Metsik"
$uus = Get-ADUser "Leila Liblikas"

Get-ADUser -Filter {Manager -eq $vana.DistinguishedName} |
  Set-ADUser -Manager $uus

Tasub tähele panna, et kasutajate otsimisel tuleb ette anda konto atribuut DistingushedName, aga uue juhi määramisel on vaja juhi kasutajakontot.

Natuke keerulisemaks läheb asi siis, kui muutmise käigus tuleb igale kontol midagi unikaalset muuta.  Näiteks võib juhtuda, et meil tuleb muuta ära kasutaja atibuut DisplayName.  Kui seni oli see kujul “eesnimi perenimi”, siis nüüd tahaks seda kujul “perenimi, eesnimi”.  Ja teeme seda ainult Hiina töötajatega.  Antud juhul ei saa enam nii lihtsalt läbi kui eelmisel korral:

Get-ADUser -Filter {country -eq "cn"} |
  ForEach-Object {
    Set-ADUser -Identity $_.sid -DisplayName (
      "{1}, {0}" -f $_.GivenName, $_.SurName
    )
  }

Natuke rohkem tööd on ka siis, kui me peaksime muutma kasutajakontode logon nimesid.  Koostame logon nime nii, et võtame eesnimest 5 tähte ja perenimest 2.  Ning võtame seekord ainult ühe grupi liikmed.

Grupi liikmed võivad olla nii kasutajad, arvutid, kui ka teised grupid.  Meie aga tahame vaid kasutajaid.  Lisaks on veel probleem sellega, et Get-ADGroupMember tagastab vale tüüpi objekti, millel pole ees- ja perenime küljes:

Get-ADGroupMember "meie" |
  Where-Object {$_.objectClass -eq "user"} |
  Get-ADUser |
  ForEach-Object {
    $uusnimi = (
      "{0}{1}" -f $_.GivenName.Substring(0,5), $_.SurName.Substring(0,2)
    )
    if (-not (Get-ADUser $uusnimi)) {
      Set-ADUser -Identity $_.sid -SamAccountName $uusnimi
    }
  }

Kontonimede muutmisel tuleb arvestada, et atribuudil SamAccountName on peal 20 märgi piirang ja pikema teksti sisestamiskatsel saame veateate. Samuti tuleks arvestada, et mainitud atribuut peab olema domeeni piires unikaalne ja seetõttu kontrollime, et sellise nimega kasutajat juba olemas ei oleks. Jääb veel võimalus, et sama nime kannab mõni arvuti või grupp, aga seda me siin ei kontrolli. Samuti jääb juba sellise nimega kasutaja olemasolu korral kasutaja logon nimi muutmata.

Juhul kui iga muudetud väärtus on ette teada ja seda ei saa välja arvutada, siis aitab hädast välja juba varem kirjeldatud CSV faili import.  Vaja vaid, et CSV failis olesid õigete nimedega veerud:

Import-Csv c:\modify.csv |
  ForEach-Object {
    Set-ADUser -Identity $_.id -MobilePhone $_.mobile
  }

Ühe liigutuse võiks veel teha.  Nimelt kui meil on rühmapoliitika korralikult juurutatud, siis ei ole kasutajatel enam vaja personaalseid logon skripte.  Korjame need ära:

Get-ADUser -Filter * |
  Set-ADUser -Clear ScriptPath

Kui ülaltoodud näidetest jääb väheks, siis TechNetis on näiteid veel.  Need on küll pärit Server 2008 R2 ajast, aga töötavad ka uuemate ActiveDirectory moodulitega.

Advertisements

Powershell Remoting ja TrustedHosts

Powershelliga teises masinas toimetamine on süsteemiülema jaoks väga mugav.  Ent ilma erilise vaevata töötab see vaid domeeni keskkonnas.  Niipea, kui masin(ad) ei kuulu domeeni või kuuluvad domeenidesse, mis teineteist ei usalda, ei ole see enam nii lihtne.

Põhjus peitub selles, et kaugühenduse loomisel kontrollitakse nii kasutajat (et see tohib üldse kaugsessiooni luua) kui ka masinat (ühenduse looja kontrollib, et sihtmasin on ikka õige).  Ja kui masinad saavad autentimiseks oma domeenikontosid kasutada, ongi asi korras.

Kui aga domeenikontod ei sobi, siis saab asja siiski tööle.  Selleks tuleb ühendust loovas masinas kuidagi korraldada sihtmasina usaldusväärsus.  Üks võimalus oleks kasutada serte, aga see muudaks asja enamasti veelgi keerulisemaks.  Natuke lihtsam oleks sihtmasina lisamine usaldusväärsete masinate nimekirja.  Sinna nimekirja lisamine tähendab sisuliselt seda, et sihtmasina identiteeti enam ei kontrollita.

Nimetatud tegevust saab teostada ainult süsteemiülema õigustes kasutaja.  Ning teha saab seda näiteks järgnevalt:

#Requires -RunAsAdministrator
#Requires -Version 2

$NewList = "uusmasin, 192.168.2.3"

# salvestame praeguse listi
$OldHosts = (Get-Item WSMan:\localhost\Client\TrustedHosts).Value

# salvestame listi
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $NewList -Concatenate

Viimases reas lisatud käsurea parameeter korraldab selle, et uus väärtus lisatakse olemasolevale, mitte ei kirjutata üle. Tänud Kaidole, kes sellele parameetrile peale sattus 🙂

Nüüd tasuks sihtmasinas üle vaadata, kas ja kes kaugsessioonide kaudu üldse sisse saavad.  Vaikimisi saavad kaugsessioone kasutada vaid süsteemiülemad.  Alates Windows 8/Server 2012 keskkonnast on ligipääs lubatud veel lokaalse grupi Remote Management Users liikmetele.  Varasemate OS-versioonide puhul sellist gruppi pole ning seetõttu tuleks ligipääsuõigusi täiendada.  Lihtsaim viis oleks vastava dialoogiakna avamine:

#Requires -RunAsAdministrator
#Requires -Version 2
Set-PSSessionConfiguration Microsoft.PowerShell –ShowSecurityDescriptorUI

#Requires -Version 3
Set-PSSessionConfiguration microsoft.powershell.workflow –ShowSecurityDescriptorUI

Kui sihtmasin on Windows Server 2012 või kui sihtvõrgus on selline OS kättesaadav, siis saab kaugsessiooni häälestust mõnevõrra lihtsustada.  Nimelt on Server 2012-s olemas komponent Windows PowerShell Web Access (PSWA).  Ja see on sisuliselt veebisait, mis vahendab Powershelli käsurida veebilehitsejasse.  Jääb muidugi veel probleem, et Server 2012 (PSWA) masinast tuleb edasi sihtmasinasse saada ikkagi WinRM sessiooni kaudu ning kogu ülaltoodud jutt võib olla oluline.

Gruppi kuulumise kontroll

Domeeni keskkonnas on sageli vaja tuvastada, kas kasutaja kuulub mingisse gruppi või kes on mingi grupi liikmed.  PowerShelli abil on seda lihtne kontrollida:

#Requires –Modules ActiveDirectory

Get-ADGroup "minu grupp" | Get-ADGroupMember
#või siis
Get-ADGroupMember "minu grupp"

Get-ADUser mina | Get-ADPrincipalMembership

Asi läheb natuke keerulisemaks, kui grupid kuuluvad gruppide sisse.  Ülaltoodud näited annavad vaid grupi vahetud liikmed (või grupid, kuhu kasutaja vahetult kuulub) ning välja jäävad grupid, mis kuuluvad teiste gruppide sisse.

Teoreetiliselt on ka see situatsioon lihtne.  Vaja vaid võtta saadud nimekiri ning ka nende liikmelisus tuvastada:

Get-ADUser mina |
  Get-ADPrincipalGroupMembership |
  Get-ADPrincipalGroupMembership

aga nii läheb kaotsi esimene kiht liikmelisust.  Ka seda annab parandada:

Get-ADUser mina |
  Get-ADPrincipalGroupMembership |
  Foreach-Object {
    $_
    Get-ADPrincipalGroupMembership $_
  } | Sort-Object –Unique

Jääb vaid probleem, et kui liikmelisuse kihte on rohkem, siis tuleks sama tegevust korrata mitu korda.  Kordade arv võib sõltuda vajadusest ning sellist ühte rida on tüütu kirjutada.  Seega võiks luua rekursiivse funktsiooni, mis vajadusel iseennast välja kutsub:

#Requires -Modules ActiveDirectory

Function Get-GroupMembership {
  Param(
    $level = 1
  )
  PROCESS {
    $_
    if ($level –ne 0) {
      Get-ADPrincipalGroupMembership $_ |
        Get-GroupMembership –level ($level-1) |
        Sort-Object -Unique
    }
  }
}

Ja nüüd jääb üle vaid seda funktsiooni kasutada:

Get-ADUser mina | Get-GroupMembership –level 2

Get-ADGroup miskigrupp | Get-GroupMembership –level 4

# kui vaja saada liikmelisus ilma algse objektita:
Get-ADUser mina | Get-GroupMembership –level 3 | Select-Object -skip 1

if (
    Get-ADUser mina |
      Get-GroupMembership –level 3 |
      Where {$_.name –like "grupp1"}
  ) {
    Write-Host "Kasutaja mina kuulub gruppi grupp1"
}

Grupi liikmete lahtiharutamise korral on asi palju lihtsam. Nimelt on käsul Get-ADGroupMemeber olemas käsurea võti -Recursive.  Ainsaks puuduseks on see et nii saame teada vaid kasutajad, kes gruppide hierarhiasse kuuluvad. Küll aga on see piisav, et kontrollida, kas kasutaja kuulub (kaudselt) gruppi:

if (
  Get-ADGroupMember grupp1 -Recursive |
    Where-Object {$_.name –like "*mina*"}
) {
  write-host "Kasutaja 'mina' kuulub gruppi 'grupp1'"
}

Veelgi mugavam on ülaltoodud kood vormistada funktsiooniks ja siis seda kasutada:

Function Test-IsGroupMember {
  Param(
      [parameter(Mandatory=$true)]
      [Microsoft.ActiveDirectory.Management.ADGroup]
    $group,
      [parameter(ValueFromPipeline=$true)]
      [Microsoft.ActiveDirectory.Management.ADUser]
    $user
  )
  PROCESS {
    [bool](
      Get-ADGroupMember $group -Recursive |
        Where-Object {$_.SID –eq $user.SID}
      )
  }
}

$mina = Get-ADUser (whoami).split("\")[1]
$mina | Test-IsGroupMember (Get-ADGroup grupp1)

Kasutajakontode loomine domeenis

Tahan tuua mõned näited, kuidas domeenis objekte hallata skriptide abil.  Tasub vist mainida, et minu näidete töötamise eelduseks on Windows Server 2008 R2 (või 2012) haldusvahenditega kaasatuleva Powershelli mooduli ActiveDirectory olemasolu.

Alustame kasutajakonto loomisest:

#Requires –Version 2.0
#Requires –Modules ActiveDirectory

# laeme vajadusel AD mooduli
if ($Host.Version.Major -eq 2) {
  Import-Module ActiveDirectory
}

New-ADUser –Name Mari

Kogu töö teeb ära käsk New-ADUser ning uue konto loomiseks rohkem polegi vaja.  Tuleb lihtsalt tähele panna, et kuna kontole ei määratud parooli, siis on konto välja lülitatud ja seda ei saa sisse lülitada enne, kui kontole on määratud parool.  Lisaks on nii logon nimi (sAMAccountName) kui ka konto nimi mõlemad samad.  Ning ees- ja perenime pole üldse.  Selle vea saab kohe parandada:

$userParams = @{
  Name = "Kati Kallike"
  SamAccountName = "Kati"
  GivenName = "Kati"
  SurName = "Kallike"
}

New-ADUser @userParams

Kui me juba skripte teeme, siis tõenäoliselt on meil korraga rohkem kasutajaid, keda luua ning üks lihtsamaid viise kasutajaid sedasi teha on CSV faili import.  Teeme näiteks järgmise CSV faili:

GivenName,Surname,Department,SamAccountName
Mati,Maasikas,Müük,mati
Juhan,Juurikas,Juhatus,juhan

ja impordime selle:

Import-Csv c:\users.csv -Encoding Default |
  select *,
    @{name="Name"; e={"{0} {1}" –f $_.GivenName, $_.SurName }},
    @{name="DisplayName"; e={"{0} {1}" –f $_.GivenName, $_.SurName }} |
  New-ADUser

Töö on lihtne selle tõttu, et CSV failis on veergude nimed viidud kooskõlla käsu New-ADUser parameetritega (ja tuletatud pikk nimi).

Teine võimalus uuele kontole atribuute ette anda on kasutada valmis kontot kui malli.  Selleks tuleb käsule New-ADUser anda ette kasutajakonto, mille küljest olemasolevad atribuudid võtta:

$template = Get-ADUser _usertemplate -Properties City, ProfilePath, MemberOf

Import-Csv c:\users.csv |
  New-ADUser -Instance $template

Nii täidetakse atribuudid, mis sageli on erinevatel kontodel ühised.  Muuhulgas ka gruppidesse kuulumised.  Ent kuna kasutajale pole antud parooli, siis on kasutajakontod ikka veel välja lülitatud.  Parooli lisamiseks on mitu võimalust.

Parooli saab skripti käivitaja käest küsida:

#Requires –Version 2.0
Read-Host -AsSecureString -Prompt "Ütle üks ilus parool"

(Get-Credential -Message "Ütle üks ilus parool" -UserName kasutaja).Password

Samas saab parooli ka näiteks tekstifailist (või parooligeneraatorist) lugeda:

ConvertTo-SecureString -String (Get-Content c:\parool.txt) -AsPlainText -Force

Paneme parooli lisamise eelnevale skriptile otsa:

#Requires –Modules ActiveDirectory

Import-Csv c:\users.csv |
  New-ADUser -AccountPassword (Get-Credential -UserName kasutaja).Password -Enabled $true

Nii saab kasutajakontod ka kohe sisse lülitada.  Samas on võib-olla hea mõte enne kasutajale parooli määramist välja mõtelda, kuidas parool kasutajani toimetada.  Ja las ta niikaua olla välja lülitatud ning ilma paroolita.

Loome nüüd uued kasutajad kindlasse OU-sse ning paneme nad ka gruppi :

#Requires –Modules ActiveDirectory
$rootdn = (Get-ADDomain).DistinguishedName

Import-Csv c:\users.csv |
  New-ADUser -PassThru -Path "ou=uued,ou=kasutajad,$rootdn" |
  Add-ADPrincipalGroupMembership -MemberOf "kõik töötajad"

Kui me nüüd mõne aja pärast avastame, et mõned atribuudid jäid kohe paika panemata, siis tuleb seda teha hiljem. Ja käsk Set-ADUser ei ole enam nii vastutulelik ning ei ole nõus otse torust muudetavaid väärtusi lugema.  Lisaks ei ole kõikide kasutajakonto atribuutide jaoks ka eraldi käsureavõtit. Siin tuleb natuke kavaldada. Loome kõigepealt sobiva CSV faili:

id, email, parool
mati,"mati@firma.ee",Par0ol33
"cn=Juhan Juurikas,ou=kasutajad,dc=firma,dc=ee","juhan@firma.ee",pAro0like

ja siis anname selle käsule ette. Tasub tähele panna, et parameeter -Add lubab lisada mistahes konto atribuute – tuleb vaid teada nende atribuutide LDAP-nimesid (need erinevad graafilise kasutajaliideses ja Powershellis kasutatavastest nimedest):

Import-Csv c:\modify.csv | ForEach-Object {
  Set-ADUser -Identity $_.id -Add @{mail=$_.email}
}

Sama lugu on parooli tagantjärele muutmise ja kontode avamisega:

Import-Csv c:\modify.csv | ForEach-Object {
  Set-ADAccountPassword -Identity $_.id `
                        -Reset `
                        -NewPassword (ConvertTo-SecureString -AsPlainText -Force $_.parool) `
                        -PassThru |
  Enable-ADAccount
}

Käsurea atribuudi -Reset kasutamine eeldab, et skripti käivitaval kasutajakontol on õigus muuta teiste kasutajate paroole. Kui skriptiga tahetakse muuta kasutaja enda õigustes tema parooli, siis tuleb see asendada atribuudiga -OldPassword (ja lisada kehtiv parool).

Vanad kontod domeenis

Aeg-ajalt on domeenist vaja üles leida kasutajakontod, kes pole tükk aega ennast näole andnud.  On nad siis ettevõttest lahkunud või on nende projekt lõppenud ja neil pole enam ligipääsu vaja.  Tavaliselt unustatakse mõlemal juhul süsteemiülemale teatada, et konto võib kinni panna.

Sarnane probleem tekib ka arvutikontodega.  Kui arvutid maha kantakse ning ära müüakse, siis ununeb sageli masina domeenist väljavõtmine.  Aga ConfigMgr’i jaoks tähendab see terve hulk zombisid, mida ei ole enam vaja.

Alates Windows Server 2003-st on haldusvahendite hulgas ka hunnik käsurea utiliite, mis antud juhul abiks on:

dsquery user "ou=kasutajad,ou=firma,dc=firma,dc=ee" –inactive 13

dsquery user –stalepwd 90

Ülaltoodud näites esimene rida otsib välja kasutajakontod, mis pole viimase 13 nädala jooksul sisse loginud ning teine rida otsib välja kasutajad, mis viimase kolme kuu (90 päeva) jooksul pole parooli muutnud.  Sama saab teha ka arvutikontodega.

tuleb vaid tähele panna, et kui inimesele on tehtud konto ja sellega pole kunagi sisse logitud, siis ei leia –inactive võtmega otsimisel seda kontot üles.  Nimetatud võti kasutab domeenikonto atribuuti lastLogonTimestamp, kus on kirjas et millal konto viimati sisse logis.  Ja kui ta pole kunagi loginud, on see atribuut tühi.

Masinakontodega on natuke lihtsam, kuna masinad käivad regulaarselt iga 30 päeva tagant oma parooli muutmas.  Kui nad pole seda teinud, siis pole nad viimase kuu jooksul domeenikontrollerit näinud.

Kui nüüd kontod üles leitud, siis peaks need välja lülitama.  Siis on kindel, et need ei saa enam domeeni sisse ja ühtlasi tuleb sageli ka välja, et kui konto(d) on tegelikult vajalikud, siis võetakse meiega varsti ühendust:

dsquery user –inactive 16 | dsmod user –disabled yes

dsquery computer –stalepwd 90 | dsmove –newparent "ou=teadmata kadunud"

Sellisel viisil võib muidugi juhtuda, et osa leitud kontosid juba on välja lülitatud.  Seega oleks vaja natuke võimsamat vahendit.

Windows Server 2008 R2 ja tema kaughaldusvahendid sisaldavad Powershelli moodulit ActiveDirectory.  Antud juhul on see väga abiks.  Vaja vaid, et vähemalt üks domeenikontroller oleks Windows Server 2008 R2 või siis et vähemalt ühele domeenikontrollerile oleks paigaldatud Active Directory Gateway Management Service.  Ja siis saame teha järgmist:

#Requires -Modules ActiveDirectory

Search-ADAccount -AccountInactive -TimeSpan 90.00:00:00 -UsersOnly

$ammu = (Get-Date).AddDays(-90)

Get-ADUser -Filter {logonCount -ge 1 -and LastLogonDate -le $ammu} |
  Move-ADObject -TargetPath "ou=kadunud hinged"

Get-ADUser -Filter {Enabled -eq $true -and PasswordLastSet -le $ammu} `
  -SearchBase "ou=IT,ou=kasutajad,dc=firma,dc=ee"

Get-ADComputer -Filter {PasswordLastSet -le $ammu} | Disable-ADAccount

Ülaltoodud näites leiab 7. rida kasutajakontod, kes on vähemalt korra sisse loginud ja viimane sisselogimine on toimunud 90 päeva tagasi või varem.  Leitud kontod tõstetakse eraldi OU-sse.

10. rida leiab kasutajakontod kindlast OU-st, kes ei ole välja lülitatud ja kelle parool on viimati vahetatud 90 päeva tagasi või varem.

Viimane rida leiab arvutikontod mis ei ole viimase 90 päeva jooksul domeenikontrollerit näinud (kui oleks, siis oleks ka parool juba muudetud) ning lülitab need välja.

Loomulikult tekib küsimus, et milliseid atribuute veel on, mida kasutada saaks.  Küsime seda Powershelli käest:

#Requires -Modules ActiveDirectory

Get-ADUser -Identity mina -Properties *

Siin tuleb tähele panna, et üks tagastatud atribuut on selline, mis arvutatakse atribuudi nTSecurityDescriptor pealt: see on CannotChangePassword.  Seda atribuuti ei saa filtris kasutada, küll aga saab seda kontrollida mööda toru järgmises käsus:

Get-ADUser -Filter * -Properties CannotChangePassword |
  Where-Object {$_.CannotChangePassword}

Tulemuseks on kasutajate nimekiri, kes ei saa ise oma parooli muuta.

Täpsemalt infot filtri võimalustest ja atribuutidest, mida võib Active Directory objektide küljest leida, saab järgmistest Powershelli spikri teemadest (või veebist):

Powershell ja käsurea argumendid

Aeg-ajalt on vaja mõnele PowerShelli käsule või skriptile kombineerida käsurea argumentide komplekt.  Võtame näiteks käsu Send-MailMessage:

#requires –Version 2.0
Send-MailMessage -To "meelis@koolitus.ee" -Subject "Powershell saadab meili" -Priority Low –DeliveryNotificationOption Never

Käsurida on küllalt pikk ja siia peaks teatud tingimustel lisama veel hulga argumente.  Seda on lihtne teha luues muutuja, mille sisuks saab käsurea argumentide komplekt.  Näiteks:

#requires –Version 2.0

$mailFrom = "keegi@mees.ee"
$mailSettings = @{
    Subject = "Tähtis teade";
    From = $mailFrom;
    SmtpServer = "mail.mees.ee";
    Encoding = [System.Text.Encoding]::UTF8;
    To = "teine@mees.ee";
    UseSSL = $false
}

Send-MailMessage @mailSettings

Nii on juba mõnevõrra parem.  Käsk ise on lühem ja loetavam ning lisaks saab boonusena käsurea argumentide komplekti käigult muuta (või uusi argumente lisada):

$mailBody = "This is e-mail sent by Powershell"
$mailSettings.To = $userMail
$mailSettings.Add("Body",$mailBody)
if ((get-date).year -eq 2012) {
    $mailSettings.Add("DeliveryNotificationOption", [System.Net.Mail.DeliveryNotificationOptions]::OnSuccess)
}

Send-MailMessage @mailSettings

Nii saab näiteks kogu meilisaatmise panna tsüklisse, mille tulemusel tekib järjekordne masspostituse mootor. Järgneva näite jaoks eeldame, et meil on failis mailusers.csv inimesed, kellele tahame meili saata, nii et iga inimese kohta on olemas tema nimi (veerg Name) ja e-maili aadress (veerg Mail):

$users = import-csv .\mailusers.csv
foreach ($user in $users) {
    $mailSettings.Body = ("Kallis {0}, `n Meil on Sulle superpakkumine" –f $user.Name)
    $mailSettings.To = $user.Mail
    Send-MailMessage @mailSettings
}

Positiivne on see, et sama meetodit saab kasutada kõigi Powershelli käskude ja isekirjutatud skriptide korral:

function minu ($a, $b) {
  $a
  $b
}

$argList = @{
  a = "üks";
  b = 2
}

minu @argList

Õnnetuseks ei saa sama meetodit kasutada muude programmide väljakutsumise juures.  Seal aitab välja vana hea Start-Process:

#requires –Version 2.0
$argList = "www.ee", "-n 3"
$argList += "-l 100"
Start-Process "ping" -ArgumentList $argList -Wait

Väikesed asjad võrgus

Vahel on just väikesed asjad need, mis teevad elu mugavaks. Serverite peal on mul sageli läinud vaja kahte asja:

  • vahel on vaja võrgust otsida seadmeid ilma et teaks, millisel IP aadressil nad vastavad
  • serveris on sageli vaja vaadata, mitmel kasutajal on lahti sessioon serveri teenusega.

Esimese asja puhul tuleb seadmeid otsida pimesi.  Ehk siis lihtsaim viis on IP-vahemik läbi pingida ja vaadata, mis IP-d vastavad.  Nendest tuleb siis välja filtreerida kõik, mille kohta on teada, et mis asi seda IP-d kasutab.  Seda filtreerimist tuleb ise ja käsitsi teha, aga vahemiku läbipingimist on võimalik automatiseerida ja lihtsutada. Nimelt saame siin kasutada Powershelli oskust võtta mingist hulgast ükshaaval elemendid ning seejärel igaühega neist midagi teha.  Näiteks:

1..10 | foreach-object { ping 192.168.3.$_}

Nüüd võiks veel teha seda, et pingitakse üks, mitte neli korda ja siis võiks välja tuua ainult need read, kus on näha vaid need IP-d, mis pingimisele vastavad:

90..100 | % { ping /n 1 192.168.3.$_ | Select-String "TTL"}

#requires -Version 2.0
Test-Connection -ComputerName (1..10 | % {"192.168.3.$_"}) -Count 1 -ea SilentlyContinue

#Requires -Modules NetTCPIP
192..203 | ForEach-Object { Test-NetConnection 192.168.3.$_ } |
  Where-Object {$_.PingSucceeded} |
  Select-Object -ExpandProperty ComputerName

Meeldival kombel jäävad ekraanile vaid need read, kus seade on vastanud.  Lisaks on kogu skript võimalik soovi korral kirjutada ühele reale ja on piisavalt lühike.  Samuti saab tulemust kohe edasi anda mingile järgmisele korraldusele …

Kui sihtmärke on palju, siis saab neid taustal paralleelselt pingida:

$myJob = Test-Connection (1..254 | foreach {"192.168.1.$_"}) -Count 1 -AsJob

Wait-Job $myJob |
  Receive-Job | 
  Where-Object {$_.StatusCode -eq 0} |
  Select-Object -ExpandProperty Address

Vajadus teise tegevuse järele tuleb serverites enamasti siis, kui oleks vaja teenus ajutiselt seisma panna või uuesti käivitada, aga kasutajad on veel serveris sees.  Võtame näiteks meiliserveri ja vaatame, kas seal on palju IMAP-SSL ühendusi:

netstat –n | select-string ":993 "

Kui pole vaja teada, et kust täpselt ühendused tulevad, on vaja teada vaid ühenduste arvu, siis loeme tagastatud read üle:

netstat –n | select-string ":993 " | measure-object

Või näiteks oleks vaja teada, et kas server ikka kuulab ettenähtud pordi peal:

netstat –an | select-string "listening" | select-string ":993 "

Windows Server 2012 (tegelikult ka Windows 8) peal on asi natuke lihtsam ja teksti seest asju otsima ei pea:

#Requires -Version 3
#Requires -Modules NetTCPIP

Get-NetTCPConnection -LocalPort 993
Get-NetTCPConnection -LocalPort 993 | Measure-Object
Get-NetTCPConnection -LocalPort 993 -State Listen

Kui on võimalik kasutada Powershell 5.0 võimalusi, siis saab samuti lihtsamalt. Nimelt võib teksti konvertida massiiviks, kasutades käsku ConvertFrom-String:

#Requires -Version 5
netstat -n |
  Select-Object -Skip 4 |
  ConvertFrom-String -PropertyNames Empty, Protocol, LocalAddress, RemoteAddress, State |
  Where-Object RemoteAddress -like "*:443"

Ent kujutame ette, et meil on serveris mitu erinevat veebiserveri rakendust ja me tahame teada, et kes täpselt kuulab parajasti konkreetsel pordil. Siin Server 2012 käsud ja Powershell 5 ei aita, kuna see ei näita porti kasutavat protsessi:

netstat –abon | Select-String -Pattern ":8080 " –Context 0,1

Ülaltoodud näide võtab programmi Netstat poolt väljastatud ridadest kaasa kõik, millel on tekst “:8080 ” ja lisab sellele leitud reale järgneva rea.  Sellelt leiame vastava protsessi nime, mis porti kasutab (selle eest hoolitses programmi Netstat käsurea võti “-b”, mis muuhulgas vajab süsteemiülema õigusi).  Eelduseks on see, et samal ajal ei ole kliendid nimetatud porti veel ühendust teinud.  Kui on, siis saame ülearustest ridadest lahti järgmiselt:

netstat –abon |
  select-string ":8080 " –context 0,1 |
  where-object {$_.line -like "*listening*"}

Jällegi on positiivne, et kõik mahub vajadusel ühele käsureale või sagedasemal kasutamisel võib ülaltoodu vormistada funktsiooniks (või paariks). Ülaltoodud näites vajaminevatest süsteemiülema õigustest saaks lahti (nagu ka käsu Select-String atribuudist -Context), kui jätta programmil Netstat ära käsureavõti “-b”.  Ainult et siis saame pordil kuulava protsessi tuvastada vaid “Process ID” järgi, mis tuleks omakorda sööta ette käsule Get-Process:

Get-Process -Id 3927

Ja selleks et nimetatud number leitud realt kätte saada, tuleb natuke tegeleda tekstitöötlusega, mida otse käsurealt on natuke ebamugav teha:

$protsess = netstat –aon |
  select-string ":8080 " |
  select-string "listening" |
  select-object -first 1
get-process -Id ($protsess.tostring().split(" ")[-1])

Ülaltoodud näites me muudame käsu select-string poolt leitud info objekti tekstiks, lõikame selle tühikute kohalt eraldi tükkideks ning tekkivast hulgast valime viimase teksti, mis juhtumisi ongi protsessi number. Juhuks kui sama protsess kuulab mitme IP peal, jätab neljas rida (üleval näites) neist järgi vaid ühe (esimese, mille Netstat raporteerib).