Bu yazı, standart komut satırı araçlarının Powershell eşdeğerlerini listelemeyi amaçlıyor. Aşağıda önce komut satırı çözümünü, sonrasında da Powershell eşdeğerini yazacağım.
Dosya sistemi işleri
Dosya sistemi temel komutları olan cd, dir, del, mkdir gibi komutları aynen Powershell'de de kullanabiliyoruz. Bunlar alias'lar aracılığıyla oluyor. Ama aslında arka tarafta komut satırı penceresinin iç komutlarından başka komutlar çalışıyor.
dir
Get-ChildItem
cd
Set-Location
del
Remove-Item
mkdir
New-Item -ItemType Directory
Bunlara ek olarak örneğin tüm alt klasörlerde bulunan ve isminde fatura geçen dosyaları bulmak için
dir *fatura* /s
eşdeğeri
dir -Include *fatura* -Recurse
Hatta daha da fazlasını yapıp içinde fatura geçen dosyaların son 1 ayda oluşturulanlarını bulmak için ise
dir -Include *fatura* -Recurse | ? {$_.CreationTime -gt (Get-Date).AddMonths(-1)} | select CreationTime, LastWriteTime, Fullname
kullanılabilir. -Include anahtarı bazen garip bir şekilde istediğim gibi sonuç vermiyor. Bu durumda -Filter anahtarı faydalı olabiliyor. Tek yapılacak -Include'u silip yerine -Filter eklemek. Duruma göre tırnak içine almak gerekebilir.
En çok ihtiyaç duyduğum başka bir şey ise içinde belli bir kelime veya karakter kümesi geçen belli tipte uzantıya sahip dosyaları bulmak. Bunu klasik komut satırında şu şekilde yapıyordum:
findstr /s /i "admin" *.log
Bunun eşdeğeri de Select-String cmdlet'i. Alias'ı ise sls:
dir *.log -Recurse | sls -Pattern "admin"
findstr.exe alt klasörleri de kapsama alabilecek /s anahtarına sahip. Select-String (sls) cmdlet'inin böyle bir yeteneği yok ama Get-ChildItem (dir) cmdlet'inin çıktısını ona yönlendirerek bu ihtiyacı karşılayabiliyoruz. Eğer alt klasörler değil de sadece mevcut klasördeki bazı dosyalar içinde arama yapacaksak dir (Get-ChildItem) komtuna ihtiyaç yok. Doğrudan sls (Select-String) kullanabiliriz:
sls -Path C:\*.log -Pattern "admin"
Select-String cmdlet'i varsayılan olarak küçük/büyük ayrımı yapmaz (case insensitive). Özellikle küçük/büyük harf ayrımı olmasını isterseniz -CaseSensitive parametresini kullanmalısınız.
Komut satırından yeni dosya oluşturmak için New-Item cmdlet'i kullanılabilir. New-Item hem dosya, hem klasör, hem de başka sağlayıcıların yeni öğelerini yaratmak için kullanılabilir. Varsayılan değeri File (dosya)dır.
New-Item -Path D:\klasor1 -ItemType file -Name dosya1.txt
Dosya veya klasör ismini değiştirmek için Rename-Item kullanılabilir.
Rename-Item -Name dosya.log -NewName dosya.txt
Ancak Path parametresi wildcard desteklemez. Bunun için toplu dosya isim değiştirme işlemlerini şunun gibi yapmak gerekir:
Get-ChildItem *.log | Rename-Item -NewName {$_.Name -replace ".log", ".txt"}
Linux'ta olduğu gibi New-Item cmdlet'i taşımayı deskeklemez. Yani NewName parametresi sadece dosya adı olmalıdır. Bu alanda dosya yolu verisi olamaz. Taşıma işlemleri için Move-Item kullanılmalıdır ve Path parametresi wildcard'ları destekler.
Move-Item -Path .\file*.txt -Destination D:\klasor1
Ağ sorun giderme
Komut satırının meşhur ping komutu harici bir komut olduğu için Powershell'de ping çalışıyor. Ama bunun yerine başka bir alternatif komut daha var.
ping 192.168.1.1
Pinging 192.168.1.1 with 32 bytes of data:
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128
Ping statistics for 192.168.1.1:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
Test-Connection -Computarname 192.168.1.1
Source Destination IPV4Address IPV6Address Bytes Time(ms)
------ ----------- ----------- ----------- ----- --------
MET8 192.168.1.1 192.168.1.1 32 0
MET8 192.168.1.1 192.168.1.1 32 0
MET8 192.168.1.1 192.168.1.1 32 0
MET8 192.168.1.1 192.168.1.1 32 0
Bu bildiğimiz ICMP ping.exe'nin karşılığı. Aynı ping.exe'de olduğu gibi varsayılan olarak 32 byte'lık paketler gönderiyor. Varsayılan olarak 1 saniye bekliyor, varsayılan olarak 4 paket gönderip duruyor. Sırasıyla bu parametreleri değiştirmek için -BufferSize, -Delay ve -Count kullanmak gerek.
Ayrıca ICMP ile değil de, TCP ile herhangi bir portu denemek istersek de
Test-NetConnection -ComputarName server01 -Port 21
kullanabiliriz. Bunun eşdeğeri klasik komut satırında yoktu. Bunun yerine psping veya benzer uygulamaları kullanıyorduk. tracert komutunun eşdeğeri olarak Test-NetConnection'ı -TraceRoute parametresi ile birlikte kullanabilirizi
Test-NetConnection -TraceRoute google.com
Bilgisayarda hangi ağ aygıtları var görmek istersek:
Get-NetAdapter
Name InterfaceDescription ifIndex Status MacAddress LinkSpeed
---- -------------------- ------- ------ ---------- ---------
Ethernet Broadcom NetXtreme... 4 Up XX-XX-XX-XX-XX-XX 1 Gbps
Wi-Fi Intel(R) Centrino ... 3 Discon. XX-XX-XX-XX-XX-XX 0 bps
Buradan bir arayüzün IP adresini bulmak istersek (örneğin Ethernet cihazı) ifIndex sütunundaki arayüz endeksini alıp aşağıdaki komuta yazarak IP adresini öğrenebiliriz.
Get-NetIPAddress -InterfaceIndex 4
IPAddress : 192.168.1.5
InterfaceIndex : 4
InterfaceAlias : Ethernet
AddressFamily : IPv4
Type : Unicast
PrefixLength : 16
PrefixOrigin : Manual
SuffixOrigin : Manual
AddressState : Preferred
ValidLifetime : Infinite ([TimeSpan]::MaxValue)
PreferredLifetime : Infinite ([TimeSpan]::MaxValue)
SkipAsSource : False
PolicyStore : ActiveStore
2022-08-26 Ek: netstat alternatifi olarak da Get-NetTCPConnection kullanılabilir.
Get-NetTCPConnection -RemotePort 443
arp -a alternatifi olarak Get-NetNeighbor kullanılabilir, hatta IPAddress alanında '*' wildcard olarak kabul edilir:
Get-NetNeighbor -IPAddress 192.168*
route print yerine Get-NetRoute kullanılabilir, hatta belli bir ağ arayüzü için interface index verilerek çıkış daraltılabilir:
Get-NetRoute -InterfaceIndex 2
İsim çözümlemesi denemeleri için nslookup yerine Resolve-DNSName cmdlet'i var:
Resolve-DNSName -Name mail.google.com
Ağ arayüzü ve IP adresi eşleşmesi için Get-NetIPInterface komutu faydalı olabilir, IP sürümü ve bağlantı durumu kısıtlamasıyla:
Get-NetIPInterface -AddressFamily IPv4 -ConnectionState Connected
Hizmetler
Yerel bilgisayardaki hizmetlerin bir listesini almak için komut:
Get-Service
veya kısaca
gsv
yeterli. Ama hayat her zaman bu kadar kolay olmuyor. İlgilendiğimiz sadece DHCP client hizmeti ise şu şekilde bir komut ile durumunu sorgulayabiliriz:
gsv dhcp
Status Name DisplayName
------ ---- -----------
Running Dhcp DHCP Client
Bu hizmeti tekrar başlatmak için boru karakteri ile Get-Service cmdletinin yukarıdaki çıktısını Restart-Service cmdlet'ine yönlendirebiliriz.
gsv dhcp | Restart-Service
Sadece çalışan servisleri başlatmak için kullanabileceğimiz bir parametresi yok Get-Service cmdlet'inin. Bunun yerine Get-Service'in çıktısını Where-Object cmdlet'ine yönlendirerek sadece çalışanları süzebiliriz:
gsv | ? {$_.Status -eq "Running"}
Eğer bu işi yerel makinede değil de uzaktaki bir makinede yapmak istiyorsak Get-Service cmdlet'ine -ComputerName parametresi ile uzak makine adını belirmek gerek.
gsv -Computername server01| ?{$_.Status -eq "Running"}
Windows Olayları
En sık kullanılan araçlardan biri de Windows Olaylarıdır. Örneğin sistem olay günlüğüne bakmak için şu cmdlet'i kullanabiliriz:
get-eventlog -LogName system
Tabi bu binlerce kayıt dönebilir. Bunun yerine en yeni 10 olaya
get-eventlog system -Newest 10
ya da son 1 saatte meydana gelen olaylara bakmak isteyebiliriz:
get-eventlog system -After (Get-Date).AddHours(-1)
Eğer belli bir Event ID'ye sahip olayları süzmek isterseniz bu noktada yine Where-Object'e başvurmak gerek.
Get-Eventlog -LogName system -Newest 10 | Where-Object {$_.EventID -eq 7040}
Where-Object'e başvurmadan doğrudan Get-Eventlog tarafından süzme işleminin yapılabiliyor olması güzel olurdu, ama olmamış. Bunun ne dezavantajı var? Yukarıdaki örnekte öncelikle son 10 olayı görmek istiyor, sonrasında da bu olayların içinde Event ID'si 7040 olanları seçiyoruz. Bu durumda dönen olay sayısı 10 da olabilir, 0 da olabilir. Yani Event ID'si 7040 olan son 10 olayı almak istersek bu sefer olayın sırasını değiştirmek lazım:
Get-EventLog -LogName system | Where-Object {$_.EventID -eq 7040} | Select-Object -First 10
Ancak bu da nispeten ilk duruma göre çok daha fazla uzun sürecek. Çünkü Get-Eventlog çalışmaya başlayınca en yeni olaylardan başlayarak olayları getirir. Belli bir ölçüt belirtilmişse o ölçüte göre (son 5 olay, son 1 saatte olan olaylar, belli bir kaynaktan gelenler vs.) göre işlem yapar. Ancak son örnekteki gibi bir ölçüt yoksa tüm olayları tarar, ve sonrasında bunların içinden süzme işlemi yapar. Bu da hem daha fazla işlemci hem de daha fazla bellek kullanımını gerektirir.
Alternatif olarak Get-WinEvent cmdlet'i kullanılabilir. 7040 olay kimliği için son 10 olayı aşağıdaki şekilde çekebilriz:
Get-WinEvent -FilterHashTable @{LogName=System;ID=7040} -MaxEvents 10
Veya son 1 saat içinde gerçekleşen tüm 7040 olaylarını görmek için
Get-WinEvent -FilterHashTable @{LogName=System;ID=7040;StartTime=(Get-Date).AddHours(-1)}
Birden fazla ID'yi virgüllerle ayırarak yazabiliriz. StarTime gibi EndTime gibi bir son tarih-saat bilgisi de verilebilir. FilterHashTable ile kullanılabilecek bazı alanlar
Key name Value data type Accepts wildcard characters?
LogName <String[]> Yes
ProviderName <String[]> Yes
Path <String[]> No
Keywords <Long[]> No
ID <Int32[]> No
Level <Int32[]> No
StartTime <DateTime> No
EndTime <DataTime> No
UserID <SID> No
Data <String[]> No
* <String[]> No
Görüleceği gibi wildcard'lar sadece LogName ve ProviderName için kullanılabiliyor. Keyword gibi alanlar olayın ayrıntısında anahtar kelime araması yapmak için değil. Bu alan için veri tipinin Long[] olduğuna dikkat etmek gerek. Sadece hataları listelemek için Level=2, uyarılar için Level=3 ve nihayet bilgi seviyesindeki olaylar için Information=4 kullanılabilir.
Kayıt Defteri
Windows Kayıt defteri ile uğraşmak nispeten komut satırına göre daha kolaydır. Yolunu bildiğiniz bir kayıt defteri konumunu sanki dosya sisteminde bir konumda çalışıyormuş gibi cd (Get-ChildItem) cmdlet'iyle görebilirsiniz.
dir HKLM:\Software\Microsoft\Windows\CurrentVersion\Run
Üstelik de her adımda tab ile tamamlama imkanıyla.
Get-ChildItem ile gezilebilecek yerler dosya sistemi ile kayıt defterinden ibaret değil. Bu tip nesnelere PowerShell Drive deniyor. Tüm PSDrive sürücülerinin listesi için
Get-PSDrive
Name Used (GB) Free (GB) Provider Root
---- --------- --------- -------- ----
Alias Alias
C FileSystem C:\
Cert Certificate \
D FileSystem D:\
Env Environment
Function Function
S FileSystem \\server\paylasim
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
WSMan WSMan
gibi bir sonuç elde ederiz. Bu da demektir ki örneğin alias'lar hakkında bilgi için Get-Alias ve Get-Help'in dışında doğrudan
cd Alias:
komutunu kullanıp dir ile tüm alias listesini alabiliriz.
Kayıt defteri konusuna gelelim. HKLM\Software\Microsoft\CurrentVersion\Run altındaki değerleri sorgulayalım:
cd HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\run
dir
Burada bazı değerler olmasına rağmen içerik gözükmedi. dir (Get-ChildItem) sadece alt anahtarları listeler. Değerleri görmek için
Get-ItemProperty .
Apoint : C:\Program Files\DellTPad\Apoint.exe
PSPath : Microsoft.PShell.Core\Registry::HKEY_LOCAL_MACHINE\...
PSParentPath: Microsoft.PShell.Core\Registry::HKEY_LOCAL_MACHINE\...
PSChildName : run
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
kullanabiliriz (ekrana sığsın diye kısalttım). Burada Run anahtarı altında yer alan değer Apoint'ti.
Yeni Registry değeri yaratmak için
New-Item Adobe
ve bu alt anahtarın altında kayıt defteri değerleri yaratmak için ise
New-ItemProperty -Path . -Name "Disable" -Type DWord -Value 1
kullanabiliriz. Aynı şekilde alt anahtarları silmek için Remove-Item, değerleri silmek için ise Remove-ItemProperty kullanılmalı.
Ortam Değişkenleri
Ortam değişkenleri de bir sistemin işleyişinde önemli yere sahip. Önceki başlıkta Get-PSDrive ile gezinmeye uygun nesneleri listelerken Env de çıkmıştı. Yani ortam değişkenlerinden PATH'i görmek için
cd ENV:
dir Path
Name Value
---- -----
Path C:\ProgramData\Oracle\Java\javapath...
kullanmak mümkün. Ayrıca
$ENV:Path
de aynı işi yapar. Daha okunaklı bir liste için
($Env:Path).Split(";")
yapabiliriz. Bu listeye örneğin C:\Scripts klasörünü eklemek istersek yapmamız gereken
$Env:Path += ";C:\Scripts"
Veya bunu tekrar silmek için
$Env:Path = $Env:Path.Replace(";C:\Script","")
yapabiliriz. Ama bu ortam değişkenini kalıcı olarak değiştirmez. Kalıcı yapmak için
[Environment]::SetEnvironmentVariable( "Path", $env:Path, [System.EnvironmentVariableTarget]::Machine )
şeklinde sistem genelinde değişiklik yapan yordam çağrılmalı.
Son olarak bazı durumlarda uyumsuz veri tiplerinin gizemini çözmek için kullanılabilecek cmdlet Get-Member'a örnek vereyim:
$Env:Path | Get-Member
Uzun bir liste verecek. İlk sırada yer alacak
TypeName: System.String
bizim için anahtar. Örnek bir kullanım için tüm alias'lar içinde hizmetlerin yönetimi için kaç alias yaratıldığını bulmak isteyelim.
dir Alias:
komutu ile tüm alias'ları listeleyebiliriz. Ama acaba bunların kaçının içinde "service" geçiyor. Select-String (sls) cmdlet'iyle içinde service geçenleri bulmaya çalışalım:
dir Alias: | sls "service"
Hiçbir şey dönmedi. Neden? Çünkü adından da anlaşılacağı gibi Select-String cmdlet'i sadece string veri tipi üzerinde çalışır. Sebebi dir Alias: komutunun string veri tipi dönmemesi olabilir mi? Bakalım:
dir Alias: | Get-Member
TypeName: System.Management.Automation.AliasInfo
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
diye uzayan bir çıktı üretir. İlk satırda yazan
TypeName: System.Management.Automation.AliasInfo
bizim için önemli. Yani string veri tipi dönmemiş.