28.12.2017

Powershell ile belirtilen zamanda bir komut çalıştırma

Şöyle bir ihtiyacım var; sunucularımdan birinin bu gece yarısından sonra saat 03:00'te tekrar başlamasını istiyorum. Bunu zamanlanmış görevlerle yapabilirim. Ama powershell ile yapmak istiyorum. Açık bir powershell penceresi bırakarak şu komutları yazarsam bu mümkün:

PS> Start-Sleep -Seconds (New-Timespan -End '2099-12-29 03:00').TotalSeconds; Restart-Computer

Burada Start-Sleep cmdlet'i belli bir süre beklemeyi sağlayacak. Ne kadar bekleyeceğini New-Timespan cmdlet'i ona söyleyecek. New-Timespan cmdlet'i şu andan itibaren 29.12.2017 saat 03:00'e kadar ne kadar zaman beklemesi gerektiğini hesaplayacak. TotalSeconds ile de bu süreyi saniye cinsinden Start-Sleep cmdlet'ine verecek [1]. Bu kadar süre beklendikten sonra da Restart-Computer cmdlet'i ile sistemin tekrar başlaması sağlanacak.

Ancak bu komut dizisi, kopyala ve yapıştır amaçları için biraz tehlikeli. Yukarıdaki komutu kopyalayıp doğrudan powershell penceresine yapıştırıp orada tarih ve saati düzenleyeyim dersek doğrudan işletebilir. Daha önce orada yıl olarak 2099 yerine 2017 yazdığı ve o tarih de geçmişte kaldığı için makineyi doğrudan yeniden başlatmaya geçiyordu. Bunun için oraya yıl olarak uzak bir tarih girdim. Bir metin düzenleyicide (ör. Notepad) tarihi değiştirmeyi seçebilir, ya da kabaca kaç saat ve dakika sonra başlatılacağını hesaplayarak Start-Sleep cmdlet'ine bir elle hesaplanmış saniye miktarı verebiliriz. Örneğin 3 saat 45 dakika sonra komut çalıştırmak için

PS> Start-Sleep -Seconds ((3*60+45)*60); Restart-Computer

Hatta belki de bir zamanlanmış işler (Scheduled Jobs) nesnesi kullanabiliriz. Örneğin bugün 22:30'da çalışacak bir işlem için

PS> $baslat = New-JobTrigger -Once -At 22:30

PS> Register-ScheduledJob -Trigger $baslat -Name "Restart" -ScriptBlock {Restart-Computer -Force}

-Force parametresi olmadan olmadı.

[1] http://www.madwithpowershell.com/2013/08/sleep-until-certain-time-with-powershell.html

26.12.2017

sort komutu

Powershell'deki sort (aslında Sort-Object'in alias'ı) ile ilgilendikten komut satırındaki sort baştan biraz daha yavan gelmişti. Ama yine de çok güçlü. Temel amacı bir metin dosyasındaki verileri sıralamak. Örnek sabit uzunluklu alanlara sahip metin veriler.txt dosyamızda aşağıdaki gibi bir veri olsun:

2014-09-12 Cihan  1993
2017-10-01 Zeynep 1992
2013-05-02 Mutlu  1991


3 sütun veri var. İlk sütun bir tarih alanı. Ama tarihler metin sıralaması yapılabilmesi için yıl-ay-gün şeklinde yazılmış. Aksi takdirde gün-ay-yıl şeklinde olan bir alanda metin sıralaması yapabilmek için tarih veri tipinden anlayan, hatta varklı formatlardaki tarihleri algılayabilen bir algoritma gerekli, ama bu sort ile imkansız. İkinci sütunumuz düz metin tabanlı isimlerden oluşuyor. Üçüncü sütun ise tamsayılardan oluşan yıl bilgisi.

Görüldüğü gibi bi veriler metin dosyasında sıralanmamış şekilde yer alıyor. Bu verileri örneğin tarihe göre sıralamak için
sort veriler.txt
demek yeterli. Tarih ilk sütunda yer aldığı için sonuç aşağıdaki gibi olacaktır

2013-05-02 Mutlu  1991
2014-09-12 Cihan  1993
2017-10-01 Zeynep 1992


İkinci sütundaki isimlere göre sıralamak için
sort veriler.txt /+12
komutu işimizi görür. İsimler sütununun ilk karakteri 12'den başladığı için /+12 anahtarı ile sıralamada dikkate alınacak bölümün 12. karakterden sonrası olduğunu belirttik. Burada önemli olan şu; sort aslında sadece isimlere göre sıralamıyor, isim+yıla göre sıralıyor. Önceki örnekte de bu geçerliydi. Sort tarih+isim+yıla göre sıraladı. /+12 anahtarı ile alınan (isim+yıla göre sıralama) sonuç şöyle:

2014-09-12 Cihan  1993
2013-05-02 Mutlu  1991
2017-10-01 Zeynep 1992


Üçüncü sütundaki yıl bilgisine göre sıralamak istersek, 199x'ların 1'i 19. karakterden başladığı için
sort veriler.txt /+19
Burada yıl sütununun sağında başka sütun olmadığı için doğal olarak sıralamaya sadece yıl bilgisi dahil edildi.

2013-05-02 Mutlu  1991
2017-10-01 Zeynep 1992
2014-09-12 Cihan  1993


Sıralama varsayılan olarak küçükten büyüğe (1'den 9'a, a'dan z'ye) yapılır. Sıralamayı ters çevirmek için /R anahtarı kullanılabilir.

sort veriler.txt /+19 /R
sonuç:

2014-09-12 Cihan  1993
2017-10-01 Zeynep 1992
2013-05-02 Mutlu  1991


İlk örnekten beri vurguladığım "sıralamaya dahil edilen alan uzunluğu"nu kısıtlamak için /REC anahtarı kullanılabilir. Örneğin sıralamayı sadece ayın gününe göre yapmak için sıralmaya dahil edilecek veriyi 9'dan başlatıp 2 karakter uzunluğunda tutmalıyız:
sort veriler.txt /+9 /REC 2
Bu şekilde şu sonucu elde ederiz:

2017-10-01 Zeynep 1992
2013-05-02 Mutlu  1991
2014-09-12 Cihan  1993


Bir de bu sıralanmış çıktıyı başka bir dosyaya yazmak istersek /O anahtarını şu şekilde kullanabiliriz:
sort veriler /+9 /REC 2 /O sirali.txt
Eğer bu dosyayı Powershell'de sadece tarihe göre sıralamak (aslında tüm satıra göre) istersek şu olabilir:
PS C:\>Get-Content veriler.txt | Sort-Object
Ama bu verileri isim veya yıla göre sıralamak isteyince bunun şaşırtıcı bir şekilde daha zor olduğunu gördüm. Çünkü PowerShell'in sabit uzunluklu verileri import edecek varsayılan bir yöntem yok. Eğer dosya tipi CSV (virgülle ayrılmış değerler) olsaydı

tarih,isim,yıl
2014-09-12,Cihan,1993
2017-10-01,Zeynep,1992
2013-05-02,Mutlu,1991


bu dosyayı Import-CSV ile import edebilirdik. Dikkat, bu dosyada bir farklılık daha var: sütun başlıkları.

PS C:\> Import-Csv .\veriler.txt
tarih                      isim                          yıl
-----                      ----                          ---
2014-09-12                 Cihan                         1993
2017-10-01                 Zeynep                        1992
2013-05-02                 Mutlu                         1991


Burada boru ( | ) operatörü ile çıkışı doğrudan Sort-Object cmdlet'ine gönderebiliriz (kısaca sort).

PS C:\> Import-Csv .\veriler.txt | sort

Bu varsayılan olarak tarih alanına göre sıralar

tarih                      isim                          yıl
-----                      ----                          ---
2013-05-02                 Mutlu                         1991
2017-10-01                 Zeynep                        1992
2014-09-12                 Cihan                         1993


İstediğimiz alana göre sıralamak için tırnak içinde alan adını yazıp, sıralamayı büyükten küçüğe yapmak için ise -Descending anahtarını kullanabiliriz.

İlle de powershell ve sabit uzunluklu alanlar diyorsak önce metin dosyasını okuyup bir değişkene atmak gerek:
PS C:\> $metin = Get-Content .\veriler.txt
Daha sonra da bu içeriği CSV'ye uygun şekle çevirmek gerek. veriler.txt dosyasında sütunlar arasında birden fazla boşluk olabildiği için doğrudan boşluğu virgülle değiştirmek işe yaramaz. Bunun için önce her sütunun sadece 1 boşluk ile ayrılmasını sağlamak gerek. Yeterli sayıda şu komutu ard arda kullanmak ilk adım:
PS C:\> $metin = $metin -replace "  "," "
yukarıda -replace'ten sonra çift tırnakların arasında 2 boşluk karakteri, ikinci çift tırnakların arasında ise 1 boşluk karakteri var. Sonrasında her boşluğu virgülle değiştirmek gerek:
PS C:\> $metin = $metin -replace " ",","
Daha sonra da bu verilere bir başlık satırı eklemek gerek. Önce bir $csv değişkeni oluşturalım:
PS C:\> $csv =  @() 
Başlık satırını ekleyelim:
PS C:\> $csv += "Tarih,Isim,Yil"
Sonra buna verilerimizi ekleyelim
PS C:\> $csv += $metin
Nihayetinde de bunu ConvertFrom-CSV ile çevirelim
PS C:\> $csv = $csv | ConvertFrom-Csv
Bu noktada $csv değişkenimiz aynen bir CSV dosyasından aktarılmış gibi uygun formatta olacaktır.

Not: Türkçe karakterler (yıl başlığındaki ı harfi) her zamanki gibi sorun. Güzel gözüksün diye  düzelttim.

28.11.2017

ffmpeg kullanımı

Komut satırından video dönüştürme, kırpma ve ses ekleme/çıkartma işlemleri için ideal bir araç. Birkaç kullanıma örnek vermek istiyorum.

En basit örnek olarak avi dosyasını mp4'e dönüştürmeyi deneyelim.
ffmpeg -i input.avi output.mp4
Burada -i anahtarı giriş videosunu gösterir. Çıkış dosyası için bir anahtarı kullanılmaz. Yukarıdaki örnekte ayrıca kodek, bit oranı, kare sayısı vs. gibi parametreleri belirtmedik, çünkü ffmpeg varsayılanları kullanarak dönüşüm yaptı. Eğer varsayılanların haricinde değerler kullanmak istiyorsak şöyle bir komut işimizi görürdü:
ffmpeg -i input.avi -vframes 24 -aspect 4:3 -b:a 128k -b:v 2000k -c:a mp3 -c:v libx264 - output.mp4
Burada kullanılan ve kullanılmayan anahtarlar şöyle:

-frames:v number    çıkışa verilecek -toplam- kare sayısı
-ar rate            kare hızı (Hz değeri, ondalık veya kısaltma)
-s size             kare boyutu (Gen x Yük veya kısaltma)
-aspect oran        resim oranı (4:3, 16:9 or 1.3333, 1.7777)
-bits_per_raw_sample oran  ham örnek için bit oranı
-vn                 videoyu akışını görmezden gel (sil)
-c:v codec          video kodeği

-c:a codec          ses kodeği
-timecode hh:mm:ss[:;.]ff  başlangıç zamanını belirtmek için
-pass n             geçiş sayısı (iteratif, 1'den 3'e)
-filter:v filter    video filtresi ayarlamak için
-b:a bitrate        ses bit oranı
-b:v bitrate        video bit oranı
-dn                 verileri görmezden gel


Videonun içinden bir kısmı kesip çıkartmak için:
ffmpeg -i input.avi -ss 00:01:05 -t 00:00:55 output.avi
Örneğin yukarıdaki komut 1. dakika 5. saniyede başlayıp 55 saniye sürecek (yani tam 2. dakikada bitecek) şekilde parçayı kesip çıkartır. Yukarıdaki komut kesme işleminden sonra avi tipi için varsayılanları kullanarak yeniden kodlama yapar. Yeniden kodlamadan kaydetmek için ses ve video kodekleri anahtarlarına "copy" yazmak gerekir. Örneğin
ffmpeg -i input.avi -ss 00:01:05 -t 00:00:05 -c:v copy -c:a copy output.avi
Bir video dosyasından sadece sesi alıp onu da mp3 formatında kaydetmek için
ffmpeg -i input.avi -vn output.mp3
Elbette yine sesle ilgili şu anahtarları kullanabiliriz:

-frames:a sayı      çıkışa verilecek ses "frame"i sayısı
-aq kalite          ses kalitesi (kodeğe özel)
-ar oran            Hertz cinsinden ses örneği sayısı
-ac kanal           ses kanalı sayısı
-an                 sesi görmezden gel (sil)
-c:a codec          Ses kodeğini belirt (değişiklik yapmadan 'copy')

-b:a oran           ses bit oranı
-vol volume         ses seviyesi (0 en az, 256 en yüksek)
-filter:a filter    ses filtresi

-c:a pcm_s16le      örnek başına 16 bit kodlama, signed, little-endian (tam liste)
-f s16le            ham veri, signed, little-endian 16-bit

Ayrı ayrı dosyalarda bulunan ses ve videoyu birleştirmek için (formata hiç dokunmadan):
ffmpeg -i input_video.mp4 -i input_audio.mp3 -c:v copy -c:a copy output.mp4
Buna göre örneğin elimizde kayıpsız flac dosyası varsa ve bundan 256k 44kHz 2 kanal kodlanmış mp3 yaratmak istiyorsak:
ffmpeg -i input.flac -b:a 256k -ar 44100 -ac 2 output.mp3
Kullanılabilir kodek listesini görmek için
ffmpeg -codecs
 kullanabilirz. Benzer şekilde -formats, -muxers, -demuxers, -encoders, -decoders, -filters anahtarları da mevcut.

Video kalitesini belirtmek için görüntü kodlamasında kullanılacak bit oranını belirtebiliriz:
-b:v 128k
video kodeğinin saniyede 128 kilobit veri üretmesini sağlar. -qscale veya -vbr gibi değişken bit oranlı (kalite bazlı) parametreler de kullanmak mümkün. Ama bunların değerleri kodeğe bağlı.

Bir videonun her karesini resim olarak kaydetmek için
ffmpeg -i input.mp4 resim-%03.jpg
diyebiliriz. Burada %03, 3 haneli, başında sıfırlar bulunan sayıları ifade eder. Yani 000, 001, 002,... 999 dizisi. Eğer 1000 taneden fazla resim varsa ilk çıkarılanların üzerine yazılır. Tam tersi durumda resim dizizinden video yapmak için ise
ffmpeg -i resim-%03.jpg output.mp4
kullanılabilir. Burada -f image2 ile format gizli bir şekilde ima ediliyor. Ama ffmpeg çıkış formatlarını akıllı bir şekilde anlayabildiği için bu anahtara gerek kalmıyor. Eğer resimlerin başlangıcı 000 değilse bu durumda örneğin 138'den başlayan resimleri belirtmek için
ffmpeg -start_number 138 -i resim-%03.jpg output.mp4
yazılmalı. Varsayılan olarak saniyede 25 resim gösterilir. Bu oranı değiştirmek için -framerate (veya yeni sürümlerde -r) ile bir kare oranı belirtebiliriz. Bir sunum tarzı video hazırlıyorsak ve her karenin 5 saniye görünmesini istiyorsak yapılacak
ffmpeg -r 1/5 -i resim-%03 output.mp4
şeklinde 1/5 kare oranı seçmeliyiz. Resimlerin arasında silinen bir geçiş olmasını istiyorsak bunu aşağıdaki şekilde yapabiliriz:
ffmpeg -i resim-%03d.jpg -vf zoompan=d=(A+B)/B:fps=1/B,framerate=25:interp_start=0:interp_end=255:scene=100 -c:v mpeg4 -maxrate 5M -q:v 2 output.mp4
Burada A her resmin saniye cinsinden geçişsiz gösterilme süresini, B ise geçişteki silinme etkili gösterilme süresini belirtir.

Saniyede 1 resim çıkartmak için
ffmpeg -i video.webm -vf fps=1 resim-%03d.png
ya da seçilen dakika ve saniyedeki görünen resmi çıkartmak için ise

ffmpeg -i video.webm -ss 00:00:10 -vframes 1 thumbnail.png
kullanılabilir.

Filtreler özellikle çok faydalı olabilir. Örneğin ses için fade-in ve/veya fade-out eklemek için şu şekilde bir kullanım uygun:
ffmpeg -i audio.mp3 -filter:a 'fade=in:0:30,fade=out:9650:30' audio_fade.mp3
Bu şekilde fade-in için 0 ile 30. kareler arasında, fade-out için ise 9650 ile 9580 arasındaki kareler verilmiş.

ffmpeg bazı video filtrelerine de sahip. Örneğin bir videoyu ters çevirmek için reverse filtresi kullanılır:
ffmpeg -i input.mp4 -filter:v reverse output.mp4
Bu işlem, girişteki dosyanın büyüklüğüne göre videoyu tek parçada veya parça parça tersine çevirip sonra bunları ekleyerek nihai videoyu oluşturmasını sağlayabilir.

Ekleme 2020-07-28: Resim dosyaları üzerinde de benzer işlemler yapılabilir. Örneğin bir resmi 640x480'e ölçeklendirmek için

ffmpeg -i resim.jpg -vf "scale=640:480" resim_olcekli.jpg

Ya da resmin içinden x=100 ve y=120 konumundan (resmin sol üst köşesi x=0 ve y=0 olmak üzere) başlayıp x=300 ve y=250'ye kadar olan dikdörtgen alanı kırpmak için (genişlik : 300-100 = 200, yükseklik: 250-120 = 130)

ffmpeg -i resim.jpg -vf "crop=200:130:100:120 resim_kirpilmis.jpg

yazılabilir.

Ekleme 2022-07-13: Ayrıca streaming videoları indirmek için de, eğer m3u8 uzantılı bir dosyamız varsa, şöyle bir komut kullanabiliriz:

ffmpeg -i "http://example.com/video_url.m3u8" -c copy -bsf:a aac_adtstoasc "output.mp4"


25.10.2017

nmap

1 Eylül 2017 itibariyle nmap 20 yaşını dolduran proje. Her türlü çok faydalı.

Karışımızda tek bir bilgisayar (genel anlamda herhangi bir ağ cihazı olabilir, ama kısaca bilgisayar veya cihaz diyelim) var, IP adresi 192.168.1.1 olsun ve bu bilgisayarın sık kullanılan portlar üzerinden bir taramasını yapmak istiyoruz. Kullanacağımız komut:

nmap 192.168.1.1

Starting Nmap 7.31 ( https://nmap.org ) at 2017-10-24 09:05 Turkey Standard Time
Nmap scan report for 192.168.1.1
Host is up (0.027s latency).
Not shown: 997 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
23/tcp open  telnet
80/tcp open  http
MAC Address: XX:YY:ZZ:WW:QQ:AA (üretici)

Nmap done: 1 IP address (1 host up) scanned in 2.16 seconds


gibi bir sonuç döner. Bir çok güzel bilgi var. 1000 tane port taramış, 997 tanesinin kapalı olduğunu, 3 tanesinin ise açık olduğunu söylüyor: 22, 23 ve 80. En altta gizlediğim MAC adresi var, yanında parantez içinde de üretici bilgisi yer alıyor. Birden fazla cihazı isim veya IP adreslerini boşlukla ayrılmış bir şekilde aynı satıra yazarak da taratabiliriz. IP aralığı vermek için 192.168.1.1-10 veya tüm oktet yerine * karakterini kullanarak 192.168.1.* veya CIDR notasyonu ile 192.168.1.1/24 de yazabiliriz.

Genel olarak taramanın iki aşaması var; ilk aşama cihaz keşfi (host discovery). Bu aşamada verilen IP aralığındaki açık ve taranabilir cihaz listesi çıkartılıyor, açık olduğuna dair hiçbir iz olmayan IP adreslerinin portlarını tarayarak vakit kaybetmemek için. İkinci aşama port taraması (port scanning). Bu aşamada da hedef bilgisayarların açık olan portlarını bulmaya çalışıyor. Sadece cihaz keşfi yapıp, port taraması yapmamak için -sn anahtarını, tam tersi durumda cihaz keşfi yapmadan doğrudan verilen tüm IP adreslerini port taramasına sokmak için -Pn anahtarını kullanabiliriz.

Cihaz Keşfi

Port taramasını tamamen atlayıp sadece ping taraması gerçekleştirmek için:

nmap -sn 192.168.1.*

Sadece belli bir aralıktaki cihazların ters DNS sorgularını yapıp toplam sayıyı almak için (bilgisayarlara hiçbir paket gönderilmeden)

nmap -sL 192.168.1.*

SYN flag set edilmiş TCP paketi ile ping yapmak için (port taramasız):

nmap -sn -PS 192.168.1.*

SYN biti 1 olan bir paket alındığında, eğer o portu dinleyen bir hizmet yoksa RST biti 1 olan bir paket ile cevap verilir. Eğer dinleyen bir hizmet varsa da hedef makine bir sonraki aşamaya geçerek SYN/ACK bitleri 1 olan bir paket ile cevar verir. Bu da yine karşıdaki cihazın açık olduğunu anlamamıza yarar.

ACK flag set edilmiş TCP paketi ile ping yapmak için (port taramasız):

nmap -sn -PA 192.168.1.*

ACK biti 1 olan bir pakette ise var olan bir TCP bağlantısında alınan veriye ait alındı cevabı gönderiliyormuş gibi yapılır. Bu cevabı alan hedef makine ise RST biti 1 olan bir paket ile cevap verir ki bu da aynı şekilde hedef makinenin açık olduğunu gösterir.

Yukarıdaki iki yöntem varsayılan olarak TCP 80 portunu kullanır. Bu durumu değiştirmek için komut satırında -p20 gibi bir port belirtebiliriz.

UDP taraması yapmak için (port taramasız):

nmap -sn -PU 192.168.1.*

varsayılan olarak UDP taramasında 40125 portu kullanılır, kullanılan bir porta denk gelmesi için. Kullanmayan bir porta UDP paketi gönderildiğinde ICMP port erişilemiyor cevabının gönderilir. Bu da karşıdaki bilgisayarın açık olduğunu gösterir. Kullanımda bir UDP portuna denk gelirsek hiçbir cevap dönülmez. Bu sebeple varsayılan olarak 40125 gibi kullanılma ihtimali az olan bir port seçilmiş.

Bir de SCTP kullanarak yukarıdaki denemenin yapılması var:

nmap -sn -SY 192.168.1.*

Denemeleri yaparken dikkat edilecek bir konu; yerel ağdaki bir hedefi tarıyorken bir de WireShark'ta gönderilen paketleri inceliyorsanız sadece ARP protokolünün kullanıldığını, ne TCP SYN ne de ACK kullanıldığını görünce şaşırabilirsiniz. Bu durum yerel ağdaki cihazların açık olduğunu ARP ile anlamanın daha kolay olmasından kaynaklanıyor. nmap bu kolay yöntemi kullanıyor. ARP'yi kapatmak için komut satırından --disable-arp-ping 'i kullanabilirsiniz, şöyle:

nmap -sn -PS 192.168.1.* --disable-arp-ping

Tam tersine, yerel ağdaki cihazları sadece ARP sorgularıyla tespit etmek istiyorsak ARP ping kullanmalıyız:

nmap -sn -PR 192.168.1.*

ARP protokolü düşük TCP stack'inde düşük seviyede çalışan bir protokoldür. İşletim sisteminin güvenlik duvarı ile "genelde" engellenmezler. Basit olarak gönderilen "Kim 192.168.1.5 adresine sahip?" sorgusuna, bu adrese sahip cihaz tarafından cevap verilir. Bunu aslında 192.168.1.5 adresine ping atıp daha sonra ARP cache'ine bakarak da bulabiliriz. Ama nmap'in bu işi işletim sisteminin algoritmalarına kıyasla, çok sayıda hedef cihaz üzerinde daha optimize bir şekilde yaptığı belirtilmiş.

Port Taraması

nmap'in -P ile başlayan anahtarları cihaz keşfi ile ilgili olanlardı. Port taraması ile ilgili olanlar ise -s ile başlar.

Yine SYN biti 1 olan bir paket ile port taraması yapmak için

nmap -sS -p80 192.168.1.1

SYN paketi gönderip gerisini getirmeden bağlantıyı sonlandırmak için işletim sistemi tarafından sunulan standart ağ rutinlerinin dışında özel paketler göndermek gerekir. Bu da root/administrator yetkisi ister çoğu durumda. Bu duruma alternatif işletim sisteminin standart rutinleri ile işi gerçekleştirmek için TCP Connect taraması tercih edilebilir.

nmap -sT -p80 192.168.1.1

SYN taraması çoğu durumda loglara girmez, dikkat uyandırmaz. Ama çok sayıda TCP Connect taraması loglara girer ve dikkat uyandırır. Dahası yavaştır ve aynı bilgiyi elde etmek için daha fazla paket gönerilmesini gerektirir. Ama mecbur kalınınca kullanılabilir.

UDP kullanan portlar üzerinden tarama yapmak için ise

nmap -sU 192.168.1.1

Cihaz keşfini atlayıp sadece 53 UDP portunu kontrol etmek istersek

nmap -Pn -sU -p53 192.168.1.1

SCTP ile port taraması yapmak için -sY kullanılablir. Şu sayfada çok faydalı bir yöntem olarak vurgulanmış.

nmap -sY 192.168.1.1

Cihaz keşfinde kullanılan ACK bitini port taramasında da kullanabiliyoruz. Ama burada durum biraz daha farklı. -sA ile TCP ACK scan yapmak mümkün. Ama bu taramayla portların tam durum bilgisini edinmek mümkün değil. Daha çok firewall kurallarını tahmin etme, stateful mu değil mi öğrenmek için kullanılabilir.

Bunun dışında TCP Null (-sN), TCP FIN (-sF) ve Xmas (-sX) taramaları var, ama kullanım alanları biraz daha kısıtlı.

Hedef bilgisayarın verdiği cevaplara göre hangi işletim sistemine sahip olduğunu tahmin edebiliriz:

nmap -O 192.168.1.1

Hedef bilgisayarın bir güvenlik duvarı ile korunup korunmadığını bulmak için

nmap -sA 192.168.1.1

Son olarak port bazında dönülen open, closed ve filtered durumlarına açıklama getireyim. Bir port açıksa ve gönderilen örneğin SYN paketine SYN veya SYN/ACK ile cevap veriyorsa port open olarak listelenir. Bağlantıya karşılık RST ile cevap veriyorsa port kapalı olarak listelenir. Gönderilen pakete hiç cevap gelmiyorsa filtered olarak görülür.

Şu sayfada verilen cheat-sheet faydalı olabilir:


Scripting Engine

smb-os-discovery

Tüm yetenekleri bunlar değil elbette. Çok faydalı bulduğum özelliklerinden biri de hazır gelen, veya genişletilebilen scriptler ile ileri seviye bazı taramalar yapabiliyor olması. Örneğin SMB protokolü üzerinde işletim sistemi ve diğer bazı özellikleri edinebileceğimiz aşağıdaki tarama çok faydalı bilgiler içeriyor. Bu bilgilerin edinilebilmesi için cihazın SMB (veya linux SAMBA) protokolünü destekliyor olması gerek.

nmap -p 445 --script smb-os-discovery 192.168.1.0/24

Nmap scan report for pc1.domain (192.168.1.1)
Host is up (0.066s latency).
PORT    STATE SERVICE
445/tcp open  microsoft-ds
MAC Address: xx:xx:xx:xx:xx:xx (Manufacturer)

Host script results:
| smb-os-discovery:
|   OS: Windows 7 Professional 7601 Service Pack 1 (Windows 7 Professional 6.1)
|   OS CPE: cpe:/o:microsoft:windows_7::sp1:professional
|   Computer name: pc1
|   NetBIOS computer name: pc1\x00
|   Domain name: domain
|   Forest name: domain
|   FQDN: pc1.domain
|_  System time: 2017-11-29T10:51:37+03:00


ssl-enum-ciphers

HTTPS üzerinden hizmet veren bir web sunucunun hangi protokolleri desteklediğini bulmak için bu da çok faydalı. SSLv1 ve SSLv2 kullanan "riskli" sunucuların tespit edilebilmesi için kullanılabilir.



nmap --script ssl-enum-ciphers -p 443 www.example.com

Starting Nmap 7.31 ( https://nmap.org ) at 2017-11-29 11:10 Turkey Standard Time
Nmap scan report for
www.example.com (192.168.1.9)
Host is up (0.00013s latency).
Other addresses for
www.example.com (not scanned):
192.168.1.9rDNS record for www.example.com: bosbdata.bosb.lc
PORT    STATE SERVICE
443/tcp open  https
| ssl-enum-ciphers:
|   SSLv3:
|     ciphers:
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - C
|     compressors:
|       NULL
|     cipher preference: server
|     warnings:
|       64-bit block cipher 3DES vulnerable to SWEET32 attack
|       Broken cipher RC4 is deprecated by RFC 7465
|       CBC-mode cipher in SSLv3 (CVE-2014-3566)
|       Ciphersuite uses MD5 for message integrity
|   TLSv1.0:
|     ciphers:
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 1024) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 1024) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - C
|     compressors:
|       NULL
|     cipher preference: server
|     warnings:
|       64-bit block cipher 3DES vulnerable to SWEET32 attack
|       Broken cipher RC4 is deprecated by RFC 7465
|       Ciphersuite uses MD5 for message integrity
|       Key exchange (dh 1024) of lower strength than certificate key
|_  least strength: C
MAC Address:
xx:xx:xx:xx:xx:xx (Manufacturer)

Nmap done: 1 IP address (1 host up) scanned in 3.38 seconds


En altta yazdığı gibi en düşük güvenlik seviyesi C. Yukarıda da kırmızı ile bu güvenlik seviyesindeki protokoller var. Bunların kapatılması gerekebilir.

[1] https://nmap.org/book/man
[2] https://nmap.org/book/man-host-discovery.html
[3] https://nmap.org/book/man-port-scanning-techniques.html
[4] https://hackertarget.com/7-nmap-nse-scripts-recon/
[5] https://nmap.org/nsedoc/
[6] https://www.computerhope.com/unix/nmap.htm
[7] https://www.tecmint.com/use-nmap-script-engine-nse-scripts-in-linux/
[8] https://bencane.com/2013/02/25/10-nmap-commands-every-sysadmin-should-know/

23.10.2017

Wayland mi X mi kullanıyoruz nasıl anlarız?

Linux veya benzeri işletim sistemlerinin grafik arayüz için kullandıkları X Windowing System'in günlük ihtiyaçları karşılayamaması sebebiyle Waylan adında bir projeye başlandı. Bazı dağıtımlar hala X kullanırken bazıları Wayland'a geçiş yaptı.

Kullandığımız dağıtımın hangisini kullandığını nasıl anlarız sorusuna bulduğum yanıtlar şöyle:

1. Yöntem:
Terminalden önce mevcut oturum kimliğimizi (session ID) bulalım:

$ loginctl
    SESSION       UID    User       SEAT
          1      1000    metin      seat0

Dikkat edilecek yer, SESSION başlığının altında kalan sayı. Bizi durumumuzda 1. İkinci adımda bu sayıyı kullanarak şu satırı yazalım (küçük büyük harf duyarlı):

$ loginctl show-session 1 -p Type
Type=X11

Hala X11 kullanıyormuşuz.

2. Yöntem
$ echo $XDG_SESSION_TYPE
x11

sonuç x11 veya wayland olarak belirtilir. Benim X kullandığım çıktı.

3. Yöntem
Gnome için:

$ ps aux | grep gnome-shell

ya da KDE Plasma için

$ ps aux | grep plasma

Eğer sonuçların arasında --wayland görünüyorsa Wayland kullanıyoruz. Gnome üzerinde şöyle birşey çıkıyorsa

metin 1877 0.0 0.0  118520   976  pts/0  S+  08:09  0:00 --color=auto  gnome-shell

veya KDE plasma üzerinde

root 1071 0.0 0.1 62740 16988 ? S 16:55 0:00 /usr/lib/sddm/sddm-helper --socket /tmp/sdd
m-authf3607558-f925-4db1-b685-3431073f8948 --id 1 --start /usr/bin/startplasma-x11 --user metin


gibi birşey çıktığı için X kullanıyorum.

12.10.2017

Günlük ihtiyaçlar için Powershell

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.

C:\> dir
PS C:\> Get-ChildItem

C:\> cd 
PS C:\> Set-Location

C:\> del
PS C:\> Remove-Item

C:\> mkdir
PS C:\> New-Item -ItemType Directory

Bunlara ek olarak örneğin tüm alt klasörlerde bulunan ve isminde fatura geçen dosyaları bulmak için

C:\> dir *fatura* /s
eşdeğeri
PS C:\> 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

PS C:\> 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:

C:\> findstr /s /i "admin" *.log

Bunun eşdeğeri de Select-String cmdlet'i. Alias'ı ise sls:

PS C:\> 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:

PS C:\> 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.

PS C:\>New-Item -Path D:\klasor1 -ItemType file -Name dosya1.txt

Dosya veya klasör ismini değiştirmek için Rename-Item kullanılabilir.

PS C:\>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:

PS C:\>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.

PS C:\>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.

C:\> 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         


PS C:\> 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

PS C:\> 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.

Bilgisayarda hangi ağ aygıtları var görmek istersek:

PS C:\> 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.

PS C:\> 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.

PS C:\> Get-NetTCPConnection -RemotePort 443

arp -a alternatifi olarak Get-NetNeighbor kullanılabilir, hatta IPAddress alanında '*' wildcard olarak kabul edilir:

PS> 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:
 
PS> Get-NetRoute -InterfaceIndex 2 

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:

PS> Get-NetIPInterface -AddressFamily IPv4 -ConnectionState Connected

Hizmetler

Yerel bilgisayardaki hizmetlerin bir listesini almak için komut:

PS C:\> Get-Service

veya kısaca

PS C:\> gsv

yeterli. Ama hayat her zaman bu kadar kolay olmuyor. İlgilendiğimiz sadece DHCP client hizmeti ise şu şekilde bir komut ile durumunu sorgulayabiliriz:

PS C:\> 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.

PS C:\> gsv dhcp | Restart-Service

Bazen de adını tam bilmediğimiz bir hizmetin durumunu öğrenmek isteriz. Örneğin "Bit Locker Drive Encryption Service"in kısa servis adını bulmak için şunu yapabiliriz:

PS C:\> gsv | select DisplayName, Name, Status | sls "bit"

@{DisplayName=BitLocker Drive Encryption Service; Name=BDESVC; Status=Stopped}
@{DisplayName=VMware USB Arbitration Service; Name=VMUSBArbService; Status=Running}


2 tane hizmet döndü, bunların ilki bizim aradığımız (daha temiz bir çıktı için gsv | out-string -stream | sls "bit" kullanılabilir). Kırmızı ile belirttiğim kısa hizmet adının hemen devamında da Status = Stopped olarak gözüküyor. Bunu tekrar başlatmak istersek

PS C:\> Start-Service BDESVC

dememiz yeterli.

(04.01.2018 düzeltme: daha da kısa olarak aynı şeyi gsv -Disp *bit* ile de yapabiliriz)

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:

PS C:\> 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.

PS C:\> 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:

PS C:\> get-eventlog -LogName system

Tabi bu binlerce kayıt dönebilir. Bunun yerine en yeni 10 olaya

PS C:\> get-eventlog system -Newest 10

ya da son 1 saatte meydana gelen olaylara bakmak isteyebiliriz:

PS C:\> 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.

PS C:\> 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:

PS C:\> 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-EventLog cmdlet'i yerine Get-WinEvent cmdlet'i kullanılabilir. 7040 olay kimliği için son 10 olayı aşağıdaki şekilde çekebilriz:

PS C:\> 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

PS C:\> 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.

PS C:\> 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

PS C:\> 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

PS C:\> 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:

PS C:\> cd HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\run
PS C:\> 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

PS C:\> 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

PS C:\> New-Item Adobe

ve bu alt anahtarın altında kayıt defteri değerleri yaratmak için ise

PS C:\> 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

PS C:\> cd ENV:                                                   
PS C:\> dir Path                                                  
Name                        Value                                 
----                        -----                                 
Path                        C:\ProgramData\Oracle\Java\javapath...


kullanmak mümkün. Ayrıca

PS C:\> $ENV:Path

de aynı işi yapar. Daha okunaklı bir liste için

PS C:\> ($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:

PS C:\> $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.

PS C:\> 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:

PS C:\> 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:

PS C:\> 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ş. Bir array döndüğü için array'in ilk elemanının tüm özelliklerini (property) yazalım:

PS C:\> (dir Alias:)[0] | fl *         
                                       
DisplayName       : % -> ForEach-Object
CommandType       : Alias              
Definition        : ForEach-Object     
ReferencedCommand : ForEach-Object     
ResolvedCommand   : ForEach-Object     


Burada çok şaşırtıcı olmayan "DisplayName" adında bir alan var. Bu alanın tipini kontrol edelim:

PS C:\> (dir Alias:)[0].DisplayName | Get-Member 
                                                 
   TypeName: System.String                       

String'i bulduk. Demek ki Select-String'in girişi bu alan olmalı.

PS C:\> (dir Alias:).DisplayName | sls "service"
                                                
gsv -> Get-Service                              
sasv -> Start-Service                           
spsv -> Stop-Service                            


Sonuçta 3 alias olduğunu gördük. İlla ki powershell saysın dersek:

PS C:\> (dir Alias:).DisplayName | sls "service" | Measure
                                                          
Count    : 3                                              
Average  :                                                
Sum      :                                                
Maximum  :                                                
Minimum  :                                                
Property :                                                

Powershell'e giriş

Windows'da komut satırının yeteneklerinin günümüz beklentilerinin altında kalmasına çözüm olarak ortaya çıkan Powershell faydalı ve kullanışlı bir framework haline geldi. .Net altyapısı üzerine inşa edilen sistem her yeni sürümde daha faydalı işlevler sunuyor

Powershell komutlarına cmdlet deniyor. Bir fiil ve ismin tire işareti ile birleşiminden oluşuyorlar. Örneğin çalışan süreçlerin listesini almak için kullanılacak komut (cmdlet):

Get-Process
Ama her seferinde bu kadar uzun komutlar girmemek için kısaltma amaçlı "alias"lar eklenmiş. Her seferinde Get-Process yazmak elbette mümkün, ama kısaltmak isterseniz

gps
veya
ps
de aynı işi yapıyor. Bu alias elbette linuxtaki eşdeğeri ps komutundan geliyor. Ama linux eşdeğerinden farklı olarak tamamen nesne yönelimli (object oriented). Tüm çalışan süreçlerin listesini değil de sadece svc ile başlayan süreçlerin listesini görmek istersek yapılacak
ps svc*
yazmak. Bunun sonucunda aşağıdaki gibi bir çıktı üretecek:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    844      30    19016      21172    90             232 svchost
   1005      37   112316     114080   190             396 svchost
   2163      71    72416      72612   349             412 svchost
    652      34    12444      20520   145             452 svchost
    527      19     8504      14744    82             756 svchost
    547      18     6752      10376    71             796 svchost
   1250     183    24952      28980  1309            1240 svchost
    325      19     3396       8688    54            1508 svchost
    489      38    27524      28188   116            1532 svchost
    108      10     3316       3040    42            1844 svchost
     55       6      712       1224    21            2036 svchost
    369      17     5584      10000    91            2044 svchost
     53       6      712       1280    21            2088 svchost
    100       8     1312       2224    24            2136 svchost
    165      14     4176       5092    48            2568 svchost
    145      11     2148       5920    43            5968 svchost


Buradaki sütünların açıklamaları [1] ve [2] de var.
Örneğin handle sayısı 1000'den fazla olan ve svc ile başlayan süreçleri listelemek için

ps svc* | ? {$_.Handles -gt 1000}

yazmak yeterli. Bu komutun kısaltılmış hali. Uzun uzun alias kullanmadan yazmak istersek komut şöyle olurdu:
Get-Process -Process svc* | Where-Object {$_.Handles -gt 1000}
Soru işareti (?) Where-Object cmdlet'inin bir alias'ı. Get-Process cmdlet'inin varsayılan parametresi de Process olduğu için ayrıca -Process yazmaya gerek yok. Önemli olan kısmı boru karakterinden (|) sonrası. Komut satırında olduğu gibi burada da boru karakteri bir komutun çıktısını diğer komuta giriş olarak veriyor. svc ile başlayan süreçlerlerin listesini al, Where-Object komuduna ver. O da bunları bir döngüye soksun (küme parantezleri sanal bir for döngüsü gibi), sadece Handles değeri 1000'den büyük olanları çıkış olarak üretsin. Burada $_ sanal for döngüsündeki döngü değişkeninin yerine geçiyor. Döngünün her adımında nesnenin Handles özelliğini alıp -gt ile "büyüktür" (greater than) işlemine tabi tutuyor. Sonucunda da şu çıkıyor:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
   1008      38   114932     113968   193             396 svchost
   2226      71    75344      73328   347             412 svchost
   1245     182    24888      28940  1308            1240 svchost


Tam da istenen bu. Powershell bunun için güzel :)

Hatta bunları da Working Set değerine göre azalan şekilde sıralamak istersek yazılması gereken bir boru karakteri daha var:
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc
Bu komutu da uzun uzadıya yazmak istersek
Get-Process -ProcessName svc* | Where-Object {$_.Handles -gt 1000} | Sort-Object -Property WS -Descending
olurdu. Tabloyu çok karmaşık bulursanız, sadece Handles ve Working Set değerlerni süreç isim ve ID'leriyle görmek isterseniz bu alanlardan sadece bazılarını select ile seçmeniz gerekir:
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc | select Id, ProcessName, WS, Handles

Bu noktadan sonra uzunlarını yazmaya gerek yok bence.

Hala eklenebilecek şeyler var. Working Set sütununun sayısal biçimlendirmesini beğenmeyenler binlik ayraç kullanmak isteyebilir. Bu durumda
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc | select Id, ProcessName, @{N="WorkingSet";E={"{0,13:N0}" -f $_.WS}}, Handles

yazılabilir. Sonuç şu şekilde olur:

 Id  ProcessName       WorkingSet                          Handles
 --  -----------       ----------                          -------
 396 svchost           114.790.400                           1005
 412 svchost            72.474.624                           2173
1240 svchost            29.532.160                           1245


Çıkışı buraya sığdırmak için boşlukları sildiğimi itiraf etmeliyim. Ama bunu gerek kalmadan sonuç üretmek için de Format-Table * -Autosize ekleyebilirdim. Yani:
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc | select Id, ProcessName, @{N="WorkingSet";E={"{0,13:N0}" -f $_.WS}}, Handles | ft -AutoSize
Sonuç şöyle olurdu:

  Id ProcessName WorkingSet    Handles
  -- ----------- ----------    -------
 396 svchost       114.221.056    1005
 412 svchost        72.462.336    2173
1240 svchost        29.532.160    1247


Temiz ve güzel.