2026-09-04

Kayıt defterine powershell ile erişim

Windows kayıt defteri (registry) erişimi grafik arayüzle yapılabildiği gibi reg.exe aracı ile de yapılabiliyor. reg.exe'nin query, add, delete, import, export (bunlarla sınırlı değil) gibi komutları var. Örneğin bir anahtarı bir dosyaya yedeklemek için

reg export HKLM\Software\Microsoft\Windows\CurrentVersion\Run reg_export.reg

gibi bir komut, bir bozulma durumunda da bu anahtarı dosyadan geri yüklemek için

reg import reg_export.reg

yeterli. Benzer şekilde Run anahtarı altındaki değerleri sorgulamak için

reg query HKLM\Software\Microsoft\Windows\CurrentVersion\Run

kullanılabilir. Bu anahtar altına yeni bir değer eklemek için

reg add HKLM\Software\Microsoft\Windows\CurrentVersion\Run /v YeniDeger /t REG_DWORD /d 9876

Ya da var olanı silmek için

reg delete HKLM\Software\Microsoft\Windows\CurrentVersion\Run /v YeniDeger

Bunlar güzel, ama nesne çıktıları veren, daha yetenekli Powershell cmdlet'lerimiz de var. Bu cmdlet'ler kayıt defterine özel değil, tüm PSDrive nesneleri üzerinde kullanılabilen cmdlet'ler.

Kayıt defterindeki verileri 2 ana kategoride değerlendirelim. Anahtarlar ve bu anahtarların altındaki özellikler. Örneğin

HKLM\Software\Microsoft\Windows\CurrentVersion\Run

bir anahtar, ve bu anahtarın altında oluşturduğum

YeniDeger = (REG_DWORD) 9876

verisi de özellik.

Bir anahtarı üzerinde işlem yaparken *-Item ile biten cmdlet'leri kullanıyoruz. Özellikler için ise *-ItemProperty cmdlet'lerini. Örneğin hedefimiz HKLM\Software\Microsoft\Windows\CurrentVersion\Run anahtarını bir değişkene atmak için Get-Item'ı şu şekilde kullanabiliriz

$anahtar = Get-Item -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run"

Powershell'de HKLM bir PSDrive olduğu için bundan sonra iki nokta üst üste ":" işareti koyarak bir sürücü yolu oluşturdum.

Bu anahtarın altındaki özellikleri (değişken ve değerlerini) dönmek için Get-ItemProperty cmdlet'ini ve -Name parametresini kullanabiliriz.

Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "Program1"

Sadece bu özelliğin değerini göstermek için 

(Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run").Program1

yapmak yeterli.

Aslında bu iki cmdlet'i sadece kayıt defteri erişiminde değil, diğer konularda da kullanabiliyoruz. Örneğin Get-Item'ı ortam değişkeni ProgramData'yı okumak için

Get-Item -Path env:ProgramData

şeklinde kullanabiliriz.

Get-ItemProperty bir öğenin özelliklerini okumak için kullanılır. Bu özellikleri ayarlamak için ise Set-ItemProperty cmdlet'i var. Bir dosyayı read-only (sadece okunbilir) duruma getirmek için şu şekilde kullanım mümkün

Set-ItemProperty -Path "C:\klasor\dosya.txt" -Name IsReadOnly -Value $true

Bir bilgisayara takılmış tüm USB cihazların listesinin tutulduğu HKLM\SYSTEM\CurrentVersion\ENUM\USB altındaki tüm HardwareID değerlerini özyinelemeli olarak listelemek için, kısaltmalarla:

dir "HKLM:\SYSTEM\CurrentControlSet\ENUM\USB" -rec -ea sil | gp | ? {$_.HardwareID} | select HardwareID

 

2026-09-02

Windows ISO dosyalarının indirilmesi

Windows update hep yavaştı. Windows ISO dosyası indirme de öyle. Üstelik de düz HTTP üzerinden gerçekleşiyor. Bütün Linux dağıtımları güncellemelerini bile yüksek hızlı HTTPS bağlantıları üzerinden yaparken, Microsoft gibi bir firma bunu ~40 Mbps hızında, güvenli olmayan sunucular üzerinden yapıyor.

Bir Windows ISO dosyası indirmek için

https://www.microsoft.com/en-in/software-download/windows11

sayfasına gidip önce MediaCreationTool.exe'yi indirdikten sonra onu çalıştırıp ISO dosyası indirme süreci başladığında sorumluluk BITS'e bırakılıyor. Arka planda bu işlemi BITS yapıyor.

Get-BitsTransfer -AllUsers
JobId                                DisplayName               TransferType JobState     OwnerAccount
-----                                -----------               ------------ --------     ------------
acb23d6d-f557-4793-a84d-661a0499e879 Windows Dlp Manager       Download     Transferring metin

Kaynak izleyicisinde "Ağ" sekmesine geçip "Al" sütununu azalan şekilde sıraladıktan sonra en üstte svchost süreçlerinden biri en yüksek trafiği yapıyor gözüktü. Bu süreç kimliğini aradığımda BITS'ı buldum.

gcim win32_service | where ProcessId -eq 17730

Sonrasında da Get-BitsTransfer ile işin "Windows Dlp Manager" adı altında gerçekleştiğini buldum. En son olarak Get-NetTCPConnection ile bu sürecin hangi bağlantılarını listelediğimde 80/tcp bağlantısını gördüm.

Get-NetTCPConnection -OwningProcess 17730 | ft RemoteAddress, RemotePort, State -AutoSize
RemoteAddress          RemotePort       State
-------------          ----------       -----
92.223.40.60           80               Established

2026-08-27

Powershell'de EFS altyapısını kullanarak dosya şifreleme

EFS (encrypting file system), Windows işletim sisteminin sadece NTFS dosya sistemi üzerinde bir dosya şifreleme yöntemi.

Bilgisayarımızda 2 kullanıcımız var, user1 ve user2. İkisinin de ortak erişiminin olduğu bir klasör olsun. C:\klasor gibi. Bu klasör içinde dosya.txt adında bir dosya var. Bu dosyaya da 2 kullanıcımızın erişimi var. user1 kullanıcısı bu dosyayı aşağıdaki gibi şifrelesin.

(Get-Item -Path "C:\klasor\dosya.txt").encrypt()

Bu işlem sonunda dosya user1 tarafından erişilmeye devam eder. Açılırken bir şifre falan sormaz, ama dosyanın simgesine sarı bir asma kilit sembolü eklenir. Aşağıda biri henüz şifrelenmemiş, diğeri şifrelenmiş 2 dosyanın simgeleri var.

Bu dosyayı sistemdeki başka bir kullanıcı açamaz. Dosya sadece NTFS biriminde şifrelenmeye devam edebileceği için dosya FAT veya desteklemeyen başka bir dosya sistemi üzerine taşınamaz. Dosya gezgini üzerinde dosya özelliklerinden "Gelişmiş" tıklandığında aşağıdaki gibi "Encrypt contents to secure data" veya Türkçe olarak "Veriyi korumak için içeriği şifrele" kutusu işaretli gözükür.


Powerhshell ile dosyanın öznitelikleri arasında Encrypted bulunur:

(Get-Item -Path "C:\klasor\dosya.txt").Attributes

Archive, Encrypted

Dosyayı şifrelemek için PKI (public key infrastructure) yapısı gereği bir "sertifikaya" ihtiyaç duyulur. Yetkili bir sertifika otoritesinin bulunduğu bir Active Directory ortamında değilsek, bilgisayarda da EFS amaçlı kullanılabilecek başka bir sertifika da yoksa, bilgisayar kendi kendine bir sertifika üretecektir. Bu işlem kullanıcı müdahalesine gerek kalmadan arka planda yapılır. Böyle bir sertifikanın varlığı

cipher /y

veya Powershell ile sertifika PSDrive içeriği sorgulanarak görülebilir.

Get-ChildItem Cert:\CurrentUser\My | 
	Where-Object { $_.EnhancedKeyUsageList.FriendlyName -contains 'Encrypting File System' }

Dosyayı tekrar şifrelenmemiş haline getirmek için 

(Get-Item -Path "C:\klasor\dosya.txt").decrypt()

kullanmak gerekir. Dosyayı şifrelenmemiş hale getirmek sertifikayı silmez.

2026-08-18

Powershell'de "cannot validate argument on parameter" hatası

Uzak bir bilgisayara Powershell'in Copy-Item cmdlet'i ile, uzak oturumlar (PS remote sessions) kullanarak veri kopyalıyordum. Her zamanki gibi oturumu oluşturdum:

$oturum = New-PSSession -Computername 192.168.11.27

Var olduğunu bildiğim bir uzak klasöre, yerel bilgisayarımda var olduğunu doğruladığım bir exe dosyayı atmaya başladım.

Copy-Item -Path "C:\klasor\dosya.exe" -ToSession $oturum -Destination "C:\klasor"

Ama şu hata ile karşılaştım:

Copy-Item : Cannot validate argument on parameter 'b64Fragment'. The argument is null or empty. Provide an argument that is not n
ull or empty, and then try the command again.
Copy-Item : Failed to copy file C:\klasor\dosya.exe to remote target destination.
At line:1 char:1

Kullandığım komut tam olarak yukarıda yazdığım gibiydi, b46Fragment gibi bir parametre kullanmadım.

Aradım, ama bu hataya benzer bir hata ile karşılaşan birini bulamadım. Ama dosya karşı tarafa kopyalanmıştı. Yerel ve uzak dosya hash'lerini karşılaştırdım, fark bulamadım.

Get-FileHash -Path "C:\klasor\dosya.exe"
Invoke-Comand -Session $oturum -Script {Get-FileHash -Path "C:\klasor\dosya.exe")

Bu da böyle bir durum olarak kaldı. 

2026-08-17

Linux'ta süreçler ve PID'ler

Bash ile çalışırken mevcut bash prosesinin ID'sini öğrenmek için

echo $$

Mevcut shell bilgisini verecek olan ifade

echo $SHELL

Peki şu an hangi terminal'i kullanıyoruz dersek

echo $PPID

bash'in parent proces ID'sini verir ki o da aslında terminal'imiz olacak. Emin olmak için pstree ile işlem ağacını görebiliriz.

pstree -sp $$

Burada

-s : seçili sürecin (ki burada $$ mevcut bash ID'sini dönecek) tüm parent zincirini döner

-p : PID'leri gösterir

İsmi bilinen bir prosesin ID'sini öğrenmek için

pidof gedit

2026-08-16

Bir süreci başlatan süreç ve hizmetler ilişkileri

Daha önce kısmen bu konuyla ilgilenmiştim ama yeterli olmamıştı.

Komut satırından bir süreci başlatan süreci bulmak istiyourm. Örneğin bir notepad süreci var. Bunu başlatan süreci Get-Process ile bulmak mümkün değil. Bir WMI/CIM sorgusu lazım. Bunu da hem PID, hem de süreç ismi ile çalışacak şekilde yapmam gerek. Ben şöyle bir parent.ps1 dosyası oluşturarak yaptım:

param(
    [Parameter(Position=0,Mandatory=$true,ParameterSetName="ProcessName")]
    [string]$ProcessName,
    [Parameter(Position=0,Mandatory=$true,ParameterSetName="ProcessId")]
    [int]$ProcessId
)

switch ($PSCmdlet.ParameterSetName) {
    "ProcessName" {
        Get-CimInstance Win32_Process |
            Where-Object Name -match ${ProcessName}  |
                Format-Table -Property ProcessId, ParentProcessId, Name, CommandLine -AutoSize -Wrap
    }
    "ProcessId" {
        Get-CimInstance Win32_Process -Filter "ProcessId='$ProcessId'"  |
            Format-Table -Property ProcessId, ParentProcessId, Name, CommandLine -AutoSize -Wrap
    }
}

bunuda

.\parent.ps1 -ProcessName notepad

şeklinde çalıştırınca şöyle bir çıktı verdi:

ProcessId ParentProcessId Name        CommandLine
--------- --------------- ----        -----------
    12216            3708 Notepad.exe "C:\Windows\System32\notepad.exe" 

Buradan 3708'i sorguladığımda bana svchost döndü.

ps -id 3708
Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    450      21     7576      51272              3708   0 svchost 

Bu noktada da win32_service sınıfını sogrulamak gerek, 3708'in içinde hangi hizmetler çalışıyor diye:

param(
    [Parameter(Mandatory,ParameterSetName="SearchID")][int]$Id,
    [Parameter(Mandatory,ParameterSetName="SearchName")][string]$Name,
    [Parameter(Mandatory,ParameterSetName="SearchDisplayName")][string]$DisplayName
)

if ($PSCmdlet.ParameterSetName -eq "SearchID") {
    gcim win32_service | where {$_.ProcessId -eq $Id}
}
elseif ($PSCmdlet.ParameterSetName -eq "SearchName") {
    gcim win32_service | where {$_.Name -like "*${Name}*"}
}
elseif ($PSCmdlet.ParameterSetName -eq "SearchDisplayName") {
    gcim win32_service | where {$_.Name -like "*${DisplayName}*"}
}

Bunu da serv.ps1 diye kaydedip

.\serv1.ps1 -Id 3708

şeklinde çalıştırınca

ProcessId Name     StartMode State   Status ExitCode
--------- ----     --------- -----   ------ --------
3708      Schedule Auto      Running OK     0

Notepad'i çalıştıran hizmetin görev zamanlayıcısı olduğunu buldum. 

2026-08-15

Mevcut bir zamanlanmış görevin tekrarlama sıklığını değiştirmek

Bir zamanlanmış görevim var. Her 5 dakikada bir çalışıyor. Powershell kullanarak bunun süresini değiştirmek istiyorum. İsmini kullanarak görev nesnesini bir değişkene atıyorum.

$gorev = Get-ScheduledTask -TaskName "Temizlik"

Bu görevin birden fazla tetiklemesi olabilir. Mevcut durumu görelim:

$gorev.Triggers

Triggers dizisinin içindeki 1 numaralı tetiklemenin tekrarlama sıklığını görelim:

$gorev.Triggers[1].Repetition.Interval
PT5M

Bu dönen değer ISO 8601 standardına göre bir süre ifadesi:

P: Periyot
T: Time (zaman)
M: Zaman ifadesi olduğu için 1 dakika (Minute)

P1M olsaydı 1 ay (Month) olacaktı. P1M2DT3M gibi bir ifade de 1 ay 2 gün 3 saat yapar. Windows görev zamanlayıcısı bu ifadelerin tümünü desteklemiyor. Basit ifadeler kullanmak lazım.

Bu 5 dakikayı 1 dakika olarak değiştirmek istiyorum. Önce $gorev nesnesini değiştirelim.

$gorev.Triggers[1].Repetition.Interval = "PT1M"

2 tetikleyiciden biri periyodik tekrarlayan, diğeri oturum açma/event tabanlı ise bunu aşağıdaki gibi ayırt edebilirim:

$gorev.Triggers | % {
   if ($_.CimClass.CimClassName -eq 'MSFT_TaskTimeTrigger') {
        $_.Triggers.Repetition.Interval = "PT1M"
     }
}

Bu nesne henüz sadece RAM'de. Bunu bir de görev zamanlayıcı nesnesi olarak yazalım.

Set-TaskScheduler -InputObject $gorev

Sonrasında bir de kontrol edelim, uygulanmış mı:

(Get-TaskScheduler -TaskName "Temizlik").Triggers[1].Repetition.Interval
PT1M 

Olduğunu görmek güzel.