2.04.2025

Powershell ve emojiler

Promptu renklendirmek için emojiler işe yarayabilir. Windows Terminal'in de gelişiyle emoji desteği de zenginleşti.

Herhangi bir nedenle bir emoji buldum ve bunu script ile ekrana basmak istiyorum. Örneğin https://emojidb.org veya https://home.unicode.org adreslerinden ⚡ emojisini buldum. Bu emoji siteden kopyalandı ve panoda (clipboard) var. Bunu istediğim yere, Windows Terminal dahil, yapıştırabiliyorum. Ama elimde bunun bir kodu yok. Koduna nasıl ulaşabilirim?

[char]::ConvertToUtf32("⚡", 0).ToString("X")

komutu bana

26A1

döndü. Şimdi bu kodu kullanarak her an

[char]::ConvertFromUtf32(0x26A1)

ile ⚡ emojisini kullanabilirim. Veya U+1f91e igi U ile başlayan kodlara sahipsek (örneğin home.unicode.org sitesinde bu şekilde veriliyor) U+'dan sonra gelen kodu doğrudan kullanabiliriz.

[char]::ConvertFromUtf32(0x1f91e)

Vereceği sonuç

🤞

olur.

Değer 65536'dan küçükse sadece [char] ile görüntüleyebiliriz.

[char]36000
負 

Benzer şekilde 65536'dan küçük kodlara karşılık gelen unicode karakterler için şu daha basit bir şekilde kodları bulunabilir.

[int][char]'負'
36000 

Powershell core 7 ile bunun yerine

`u{26A1}

ile de aynı şeyi yapabiliyorum.

21.03.2025

The package provider requires 'PackageManagement' and 'Provider' tags hatası

Bir makinede powershell ile PowershellGallery.com'dan bir modül kurmak istediğimde

Install-Module -Name PSWritePDF

şöyle bir hata alıyordum:

PackageManagement\Install-PackageProvider : No match was found for the specified search criteria for the

provider 'NuGet'. The package provider requires 'PackageManagement' and 'Provider' tags. Please check if the

specified package has the tags.

At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:7468 char:21

+ ...     $null = PackageManagement\Install-PackageProvider -Name $script:N ...

+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidArgument: (Microsoft.Power...PackageProvider:InstallPackageProvider) [I

   nstall-PackageProvider], Exception

    + FullyQualifiedErrorId : NoMatchFoundForProvider,Microsoft.PowerShell.PackageManagement.Cmdlets.Install

   PackageProvider


PackageManagement\Import-PackageProvider : No match was found for the specified search criteria and provider

name 'NuGet'. Try 'Get-PackageProvider -ListAvailable' to see if the provider exists on the system.

At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:7474 char:21

+ ...     $null = PackageManagement\Import-PackageProvider -Name $script:Nu ...

+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidData: (NuGet:String) [Import-PackageProvider], Exception

    + FullyQualifiedErrorId : NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.ImportP

   ackageProvider


WARNING: Network connectivity may not be available, unable to reach remote sources.

WARNING: Unable to bootstrap the required package provider due to problems with network connectivity. Please

fix your network connection. If this is not possible, refer to 'Get-Help Install-PackageProvider' or

https:/go.microsoft.com/fwlink/?LinkId=626941 for guidance on installing the package provider manually.

WARNING: Unable to download from URI 'https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409' to ''.      WARNING: Unable to download the list of available providers. Check your internet connection.                  PackageManagement\Get-PackageProvider : Unable to find package provider 'NuGet'. It may not be imported yet.  Try 'Get-PackageProvider -ListAvailable'.                                                                     At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:7478 char:30                + ... tProvider = PackageManagement\Get-PackageProvider -Name $script:NuGet ...

+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : ObjectNotFound: (Microsoft.Power...PackageProvider:GetPackageProvider) [Get-Pa

   ckageProvider], Exception

    + FullyQualifiedErrorId : UnknownProviderFromActivatedList,Microsoft.PowerShell.PackageManagement.Cmdlet

   s.GetPackageProvider


Install-Module : NuGet provider is required to interact with NuGet-based repositories. Please ensure that

'2.8.5.201' or newer version of NuGet provider is installed.                                                  At line:1 char:1                                                                                              + Install-Module -Name PSWritePDF                                                                             + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                                 + CategoryInfo          : InvalidOperation: (:) [Install-Module], InvalidOperationException                   + FullyQualifiedErrorId : CouldNotInstallNuGetProvider,Install-Module

Çözüm olarak şu sitede gösterildiği gibi

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

ile TLS 1.2'yi Service Point Manager olarak ayarladıktan sonra asıl kurmak istediğim PSWritePDF'i kurmayı başardım.

19.03.2025

Timeout özelliği olan bir powershell ping fonksiyonu

Powershell'de Test-Connection cmlet'i ping yerine kullanılabilir. Ping'e benzer şekilde 4 adet ICMP paketi gönderir ve cevabını bekler. Bazen betiklerin içinde hedef cihazın canlı olup olmadığını anlamak için

Test-Connection -Computername hedef -Quiet -Count 1

gibi bir komut kullanırım, sadece True veya False dönen. Hedef cihaz açıksa ve ping'e cevap veriyorsa hemen True döner. Ama hedef cihaz kapalıysa False dönmesi uzun sürer. Powershell 5.1'de Test-Connection'ın bir timeout parametresi de yok. Onun için şöyle bir fonksiyon işimi görüyor:

function Test-ICMP {
    param (
        [string]$Computername = "8.8.8.8",
        [int]$Timeout = 1000  # Milisaniye
    )

    $ping = New-Object System.Net.NetworkInformation.Ping
    $task = $ping.SendPingAsync($Computername, $Timeout)

    $completed = [System.Threading.Tasks.Task]::WaitAny(@($task), $Timeout)

    if ($completed -eq 0) {
        # Ping işlemi tamamlandı, sonucu al
        $reply = $task.Result
        if ($reply.Status -eq "Success") {
            $True
        } else {
            $False
        }
    } else {
        # Timeout süresinden uzun sürdü
        $False
    }
}

Hiç bir parametre kullanmazsam varsayılan hedef olarak Google'ın birincil DNS sunucusu 8.8.8.8'e 1 adet ICMP request paketi gönderir ve 1000 ms bekler. Ama yerel ağdaki bir makinenin açık mı kapalı mı olduğunu anlamak için

Test-Connection -Computername hedef -Timeout 100

yazabilirim. 100 ms içinde açıksa True, kapalı (veya cevap dönmüyorsa) False cevabını alırım.

12.03.2025

Uzun powershell komutları tamamlanınca sesli uyarı versin

Powershell'de bazı komutların tamamlanması uzun sürebiliyor. Uzun sürsün, sorun değil. Ama bitince haberim olsa keşke diye düşünürken aklıma bir yöntem geldi.

Zaten profil dosyamın içinde en son komutun ne kadar sürdüğünü hesapladığım bir bölüm vardı.

    if ((Get-History).Length -gt 0)
    {
        $LastExecutionTime = [long]((Get-History)[-1].EndExecutionTime - (Get-History)[-1].StartExecutionTime).TotalMilliSeconds
    }

Her komut tamamlandığında bir sesli uyarı almak da istemiyorum. Ne zaman almak isterim diye kendime sordum, aldığım cevap 5 saniye oldu. Bana da mantıklı geldi. Bu if bloğunu şöyle güncelledim:

    if ((Get-History).Length -gt 0)
    {
        $LastExecutionTime = [long]((Get-History)[-1].EndExecutionTime - (Get-History)[-1].StartExecutionTime).TotalMilliSeconds
        if ($LastExecutionTime -gt 5000) {
            Play-Sound -Play "C:\Windows\Media\Windows Proximity Notification.wav"
        }
    }

Zaten Play-Sound diye bir fonksiyonum vardı. Yoksa onu da şu şekilde oluşturabilirdim:

function Play-Sound
{
    param
    (
        [string]$Play = "C:\Windows\Media\Alarm01.wav"
    
    $sound = New-Object System.Media.SoundPlayer;
    $sound.SoundLocation="$Play";
    $sound.Play()
}

Tabi bunların hepsi $profile dosyamın içindeki

  function profile {
  ...
  }

fonksiyonu içinde oluyor.

22.02.2025

bash prompt'a en son komut çalışma süresini eklemek

bash promptumda en son çalışan komutun ne kadar süre ile çalıştığını gösteren bir alan olmasını istiyorum. Bu işi doğrudan yapmanın bir yönteminin olmadığını öğrendim. Ama dolaylı olarak yapmanın yolları var. trap ve PROMPT_COMMAND gibi yönergeler işe yarıyor. Yazdığımız komutu çalıştırmadan hemen önce çalışacak fonkisyonu trap ile bildiriyoruz. Promptu oluşturacak fonksiyonu işe PROMPT_COMMAND yönergesi ile belirliyoruz. Örneğin preexec adında bir fonksiyon oluşturup içeriğini şöyle belirledim.

function preexec() {
    export TIMER_START=(date +%s%3N)
}

Bu fonksiyon, TIMER_START adında bir değişken oluşturup, içeriğini 01.01.1970'ten bu yana geçen milisaniyelere eşiytleyecek. Sonra da precmd adında bir fonksiyon oluşturup içeriğini aşağıdaki gibi belirledim.

function precmd() {
local TIMER_END=(date +%s%3N)
local TIME_DIFF=$((TIMER_END-TIMER_START))
if (( TIME_DIFF > 1000 )); then
local DURATION="$((TIME_DIFF / 1000)) s"
else
local DURATION="$TIME_DIFF ms"
fi
export PS1="($DURATION) $ "
}

Bundan sonra preexec'i trap ile, precmd'yi de PROMPT_COMMAND ile belirliyorum.

trap 'preexec' DEBUG 
PROMPT_COMMAND=precmd

Ancak bundan sonra farkettim ki preexec fonksiyonu birden fazla işliyor. Benim tespit ettiğim bir kez komutu çalıştırmadan önce, bir kez de komutu çalıştırdıktan sonra. Bu ilginç bir konu ama derinlerine dalmak istemedim. Basit bir şekilde bir komut için sadece 1 kez çalıştırılmasını bir değişkenle denetledim.

preexec_active=0
function preexec() {
    if [[ $preexec_active -eq 0 ]]; then
    export TIMER_START=(date +%s%3N)
    preexec_active=1
    fi
}

Benzer şekilde precmd fonksiyonunun içine de bu değişkeni eski haline döndürecek bir satır ekledim.

function precmd() {
    local TIMER_END=(date +%s%3N)
   local TIME_DIFF=$((TIMER_END-TIMER_START))
    if (( TIME_DIFF > 1000 )); then
        local DURATION="$TIME_DIFF s"
   else
        local DURATION="$TIME_DIFF ms"
   fi
   export PS1="($DURATION) $ "
    preexec_active=0
}

Bu şekilde herşey istediğim gibi oldu.

14.02.2025

Bir web sayfasının yüklenme süresini ölçmek

İlk defa bir web sayfasının yüklenme süresini ölçmem gerektiğinde şöyle birşey düşünmüştüm:

(1..5) | % {$a=(measure-command {iwr "http://www.ozmener.net"}).TotalMilliseconds; "$_ - $a"}

Daha sonra farkettim ki bu şekilde sadece varsayılan html, asp veya php sayfasını almaktan başka birşey yapmıyorum. Sayfadaki resimler, script'ler veya başka sitelerden alınan iframe'ler hesaba katılmıyor. Bunu powershell ile nasıl yapacağımı bilemedim. Her konuda bilgili arkadaşım ChatGPT bana

nmp install playwright

önerdi. Tabi bunun için önce nodejs'i kurmam gerek. Kurduktan sonra  karşılaştığım hata sonrası bir de

npx playwright install

komutunu verdikten sonra bir measure.js dosyasının içine

const { chromium } = require('playwright');
(async () => {
const url = process.argv[2] || 'https://example.com';

// Launch a headless browser with SSL verification disabled
const browser = await chromium.launch({
headless: true, // Optional: Set to false if you want to see the browser
});
const context = await browser.newContext({
ignoreHTTPSErrors: true // Ignore SSL certificate errors
});
const page = await context.newPage();

// Measure page load time
const start = Date.now();
await page.goto(url, { waitUntil: 'networkidle' });
const loadTime = Date.now() - start;

console.log(`Page loading time for ${url}: ${loadTime} ms`);

// Close the browser
await browser.close();
})();

yazıp komut satırından

node measure.js "http://www.ozmener.net"

yazınca

Page loading time for http://www.ozmener.net: 811 ms

sonucunu aldım. Bir siteye Chromium ile girmek ile Firefox ile girmek arasında bir fark vardır elbet, milisaniyeler seviyesinde. Bu ölçümün hassasiyeti farklı tarayıcıların sayfayı oluşturma performanslarını ölçecek hassasiyette değil. Safi sayfa öğelerinin uzaktan indirilmesi, önemsediğimiz.

12.02.2025

SSL sertifikası talep ve kurulum

IIS üzerinde bir web sunucum var. Bu sunucumun trafiğinin güvenli kanaldan gerçekleşmesini istiyorum. İlk iş bir sertifika talebinde (Certificate Signing Request, ya da kısaca CSR) bulunmak. Bu adımda hangi alan adına ait bir sertifika talep ettiğimiz, kendimizi nasıl tanımladığımız, sertifikanın anahtar uzunluğunu belirteceğiz. Dahası IIS (veya başka web sunucular) bir özel anahtar oluşturacak. IIS üzerinde CSR oluşturmak için sol taraftaki ağaç yapısından sunucu adını tıkladıktan sonra orta menüde IIS başlığı altında kalan Server Certificates nesnesini çift tıklayarak içine girmeli ve sağ menüde çıkan "Create Certificate Request..." bağlantısını tıklamalıyız.

ozmener.net sitem için bir sertifika istediğim için common name alanına bunu yazmalıyım. Ben wildcard sertifikası istediğim için *.ozmener.net yazdım. Wildcard sertifikalar aynı alan adına ait alt alan adlarını da kapsayan tipte sertifikalardır. Sadece www.ozmener.net için sertifika isteseydim www.ozmener.net yazabilirdim. Diğer veriler güvenli bir bağlantı ile bize ulaşan kullanıcıların beni nasıl tanımalarını istiyorsam öyle yazdığım veriler. EV (extended validation) gibi bir sertifika istemiyorsak işlem bundan ibaret. EV sertifika için burada yazanların doğru olduğunu belgelememiz gerekir.

Bir sonraki sayfada sertifikanın anahtar uzunluğunu seçiyoruz. Bu, kriptografik işlemlerin ne kadar karmaşık olacağına dair bir bilgi.

Bu adımdan sonra CSR dosyamıza bir isim vererek kaydedeceğiz. Sonra bu CSR dosyasını  sertifika hizmet sağlayıcıya göndermemiz gerekecek. Sertifika üretme süreci tamamlandıktan sonra bizim elimize geçen "sertifika paketi" üreticiden üreticiye değişiklik gösterebilir ama genellikle sertifika sağlayıcının tüm zincirine ait sertifikalar gönderilir. Güncel bir işletim sistemine sahipsek ve hizmet aldığımız sertifika sağlayıcıya ait kök sertifika bilgisayarımızda yüklü ise bunlara ihtiyacımız kalmayabilir. Güncel bir bilgisayara kurulum yaptığımızı varsayarak bu adımı atlıyorum.

Sertifika geldikten sonra yine IIS'in aynı bölümünden bu sefer sağ menüden "Complete Certificate Request..." bağlantısını tıklayarak bizim için üretilen sertifika dosyasını göstermemiz gerek. Friendly name alanına ozmener.net falan yazmaya gerek yok. Burası sadece site yöneticisinin göreceği bir alan. Ben genelde WC_Comodo_2025 falan gibi sertifika tipini (wildcard), sağlayıcı adını ve yıl gibi bilgileri içeren bir etiket kullanıyorum. SSL sertifikaları Computer Certificates>Personal>Certificates altına kuruluyor. Kurulum tamamlandıktan sonra ilgili web sunucuya gelerek sağ menüden "Bindings..." bağlantısını tıklamalıyım.

Burada hedefimiz 443 portu üzerinden gerçekleşecek trafik olduğu için bu satırı çift tıklayarak açılan "Edit Site Binding" penceresinde altta "SSL Certificate" altıdaki açılan menüden yeni kurduğumuz, adı da muhtemelen WC_Comodo_2025 gibi birşey olan sertifikayı seçerek devam ediyoruz. Bundan sonra hizmetlerden birini yeniden başlatmaya falan gerek yok ama istemci bilgisayarlarda sertifikanın yerel bellekte kalmış olması ihtimaline karşı (firefox için) Ctrl+F5 yapmak gerekebilir.

Standart SSL sertifikası kurulumu buraya kadar. Wildcard sertifikamız varsa ve bu sertifikayı başka sunuculara kurmak istiyorsak ek bazı işlemler yapmamız gerekecek. Sertifika sağlayıcımızın bize ilettiği sertifikayı "CSR üretmeyen bir bilgisayara" kurmak istediğimizde hiçbir sorun çıkmadan kurabiliriz. Ancak bu sertifika en son aşamada "Edit Site Binding" penceresinde listelenmeyecektir. Bunun sebebi de eksik özel anahtarımız. Hatırlayalm, özel anahtar CSR talebinin üretildiği bilgisayarda saklanır ve sertifika sağlayıcımızın bize ilettiği sertifikanın içinde yer almaz. Bunu yapmak istiyorsak CSR dosyasını üreten bilgisayarda yeni kurduğumuz sertifikayı "Export private key" diyerek dışarıya aktarmamız ve daha sonra bunu diğer sunucuya da kurmamız gerekir.


Özel anahtarımız (private key) kritik bir bilgi. Bu bilgiyi başkalarıyla paylaşmamamız gerek. Bu amaçla dışa aktarılan dosyaya bir şifre verebiliriz.

Bu adıma dikkat. Encryption seçeneklerinde SHA1 ile biten seçim eski ve güvenli olmayan yöntem. Bir süredir bu yöntemin kullanılmaması öneriliyor. SHA256 ile biten seçenek ile devam ettim.

Ancak kurulum yaptığım bilgisayar biraz daha eski bir sunucu olduğundan şifre ile korunan sertifika dosyasını kurarken şifremin yanlış olduğuna dair bir hata ile karşılaştım. Şifremin kesinlikle doğru olduğunu biliyorum. Sonra anladım ki sebep bu sunucunun SHA256'yı desteklememsiymiş. Geri dönüp CSR'ı oluşturan bilgisayardan sertifikayı tekrar dışarı aktarıp, aktarırken de SHA1 ile şifreemeyi seçerek devam etmek zorunda kaldım.

CSR'ı oluşturan sunucudan başka bir sunucuya wildcard sertifikamı kurmanın birkaç yolu var. IIS>Server Certificates bölümünden Import etmek bunlardan biri. Ancak burada ben sertifikanın tekrar dışarı aktarılabilmesini istemediğim için alttaki kutuyu işaretlememeyi seçtim.

Bunun sonucunda da "Edit Site Binding" penceresinde yeni kurduğum ve içinde özel anahtarımın olduğu sertifikayı içermesine rağmen sertifikayı seçip OK'e bastığımda aşağıdaki gibi bir hata ekranıyla karşılaştım.

Bu hataya System olay günlüğündeki 36870 kimlik numaralı olay da eşlik eder. Burada der ki; 

"TLS sunucu özel anahtarına erişirken hata oldu. Kriptografik modülden dönen hata kodu 0x8009030D, iç hata kodu da 10001. SSPI istemci süreci de System (PID:4)"

Bunun çözümünü şu adreste buldum. Dışarıya aktarılan sertifikanın anahtar yapısında bir bozulma olduğu belirtilmiş. Ya sertifikayı yüklerken "Allow this certificate to be exported" kutusunun işaretli bir şekilde içeriye aktarılması, ya da mmc > certificates kullanılarak içeriye aktarılması gerek. İkinci yöntemi seçtim.

11.02.2025

Powershell, WMI, CIM ve wmic

Windows Instrumentation Model (WMI) yerine artık Common Information Model (CIM) kullanılıyor. WMI'ın yapabildiği (sanıyorum) herşeyi CIM ile de yapabiliyoruz. Daha hızlı ve daha güvenli. Bunun için Powershell'de gwmi (Get-WmiObject) yerine gcim (Get-CimInstance) kullanmak gerek.

Bir kurulumda hangi sınıflar (class) var nasıl görürüz? Harici araçlar var ama kurmak istemiyorum.

Get-CimClass -Namespace 'root/cimv2'

Burada root/cimv2 varsayılan namespace'imiz. Bu şekilde varsayılan namespace'imiz içindeki bütün sınıfları listeleyebiliyoruz. Eski cmdlet gwmi (Get-WmiObject) ile -List parametresi de mümkün:

gwmi -list

wmic komut satırı aracıyla powershell cmdlet'i arasında bir benzerik var. Powershell'de uzun uzadıya yazdığımı sınıf isimleri (Win32_OperatingSystem) gibi yerine wmic'te kısa parametreler var. Örneğin Powershell'de işletim sistemimizi sorgulamak için

gcim win32_operatingsystem | select name

yazarken wmic ile

wmic os get name

yazabiliyoruz.

Alt bilgi isimleri (name gibi) belirtmeden bir sınıftaki bütün verileri görmek için Powershell'de

gcim win32_operatingsystem | fl *

yazarken wmic eşdeğeri şöyle

wmic os get * /format:list

Uzak bilgisayarda bir sorgu çalıştırmak için (örneğin schedule hizmetine ait süreç kimliğini alalım)

wmic /node:UZAKPC service where "name='schedule'" get processid
gcim -cn UZAKPC | where name -eq schedule | select processid

wmic /filter parametresi aracılığıyla list, table, csv, xml, hform, htable gibi biçimlerde çıkıtı üretebilir. Bu bir dosyaya aktarılabildiği gibi

wmic computersystem get ChassisSKUNumber,Description,DNSHostName,Domain,Manufacturer,Model,PartOfDomain,PrimaryOwnerName /format:csv > computerinfo.csv

powershell ile birleştirilip tablo da yapılabilir

wmic computersystem get ChassisSKUNumber,Description,DNSHostName,Domain,Manufacturer,Model,PartOfDomain,PrimaryOwnerName /format:csv | ConvertFrom-Csv | Out-GridView

Windows 10 21H1 güncellemesinden sonra wmic artık aramızda değil. Kurmak için

DISM /Online /Add-Capability /CapabilityName:WMIC.Client~~~~0.0.1.0

yapılabilir.

---

https://www.pearsonitcertification.com/articles/article.aspx?p=1700427&seqNum=4
https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmic

10.02.2025

Powershell'de komut satırı komutlarını kullanmak

Komut satırı ilginç bir terim. İngilizcesi de command prompt, bu da çok mantıklı değil. Ama ne kastedildiği anlaşılıyordur, umarım.

Powershell kullanırken iki dosyayı karşılaştırmak istiyorum.

Compare-Object -ReferrenceObject D:\klasor1\dosya1.txt -DifferenceObject D:\klasor2\dosya2.txt

gibi yazınca doğrudan dosya içeriğini karşılaştırmıyor. İçeriği karşılaştırmak için en basit yöntem her bir dosyanın ayrı ayrı hash'lerini hesaplatmak

Compare-Object -ReferrenceObject (Get-FileHash D:\klasor1\dosya1.txt) -DifferenceObject (Get-FileHash D:\klasor2\dosya2.txt)

 ya da düz metin dosyasıylsa içeriklerini okuyup 

Compare-Object -ReferrenceObject (Get-Content D:\klasor1\dosya1.txt) -DifferenceObject (Get-Content D:\klasor2\dosya2.txt)

karşılaştırmak gerek. Böyle uzun uzadıya yazmak yerine eski güzel günlerdeki basit fc komutunu kullanmak istiyorum.

fc D:\klasor1\dosya1.txt D:\klasor2\dosya2.txt

yazınca maalesef fc komutunu Format-Custom cmdlet'inin alias'ı olarak algılıyor. Ne yapmak gerek? Powershell'i bırakıp yeni bir komut satırı penceresi/sekmesi açıp komutu tekrar yazmak bir seçenek. Ama onun yerine cmd.exe'nin /C anahtarı daha kolay. Mevcut pencerenin komut geçmişinden dosya adlarını da bir daha yazmaya gerek kalmaz. Kısaca powershell'in içinden

cmd /c fc D:\klasor1\dosya1.txt D:\klasor2\dosya2.txt

yazınca sonuca ulaşabiliryorum.

7.02.2025

Fortigate Firewall CLI

Fortigate güvenlik duvarı üzerinde bazı CLI işlemleri.

Firewall kullanıcısı için 2FA amaçlı eposta adresi eklemek için

config user local
edit metin
show
set two-factor email
set email-to metin@ozmener.net
end

Kullanıcılarda belli sayıda yanlış parola sonrası lockout uygulamak için (5 yanlış denemeden sonra 2 saat (120dk, 7200 sn lockout) uygulamak için:

config user setting
set auth-lockout-threshold 5 set auth-lockout-duration 7200 end

VPN bağlantılarında lockout devreye almak için (3 yanlış şifre ve 3600 sn süreyle - geçmiş 600 saniye içinde yapılan yanlışları sayarak)

config vpn ssl setting
set login-attempt-limit 3
set login-block-time 3600
set login-attempt-timeout 600
end

VPN üzerinden yapılan 3 yanlış giriş sonrası engellenen IP adreslerinin listesini görmek için

diagnose vpn ssl blocklist list
|id|addr|status|first-attempt|last-attempt/fail-count|vfid|
|1|10.1.1.2|locked|2024-08-09 08:32:46|2024-08-09 08:33:16|5|0|

Bu liseden bir IP adresini kaldırmak için

diagnose vpn ssl blocklist del 10.1.1.2

Hepsini silmek için IP adresi all yerine all kullanılabiir. Veya en sondaki vfid de IP adresi yerine kullanılabilir. Toplam engellenen sayıyı görmek için:

diagnose vpn ssl blocklist count

Engellenen kullanıcı listesini almak için

diag user banned-ip list

list List banned IPs.
add Add banned IP address.
delete Delete banned IP address.
clear Clear all banned IP addresses.
stat stat

Bilgilendirme mesajları ile ilgili ayarlamalar için

config alertemail setting
show
set username DoNotReply@notification.fortinet.net
set mailto1 alici@firma.com
set firewall-authentication enable
end

Deneme mesajı göndermek için

diagnose log alertmail test

Bütün bağlantıların listesini almak için

get system session list

Belli bir IP adresine/adresinden yapılan bağlantı ile ilgileniyorsak

get system session list | grep 10.1.1.2

Bir IP adresinin coğrafi konumunu sorgulamak için

diagnose geoip geoip-query 195.175.39.39
diagnose geoip ip2country 195.175.39.39
     diagnose firewall ipgeo ip2country 195.175.39.39
diagnose geoip iprange TR
     diagnose firewall ipgeo ip-list TR

Bir IP adresine ait konum bilgisinin üzerine yazmak için

config system geoip-override
edit India
config ip-range
edit 1
set start-ip 208.91.112.52
set end-ip 208.91.112.52
next
end
next
end

Yerel geoIP veritabanını güncellemek için

execute update-geo-ip

4.02.2025

KDE'de 3 parmak kaydırma hareketi algılama

Touchpad'in fareye göre biraz zor olduğu doğru. Ama avantajları da var. Örneğin bir süredir standart olan iki parmak kaydırma ile sayfada gezinme güzel birşey. Son zamanlarda 3 parmak ile kaydırma işlevlerinin de Windows ve Gnome'da çok kullanışlı olmasının ardından x11 ile birlikte kullandığım KDE'ye de bu özellikleri kazandırmak için ne yapabilirim diye bakınca touchegg touche paketlerinin varlığından haberdar oldum.

sudo pacman -S touchegg touche

komutuyla kurdum. Kurduktan sonra touchegg hizmetini etkinleştirdim.

sudo systemctl enable touchegg.service --now

Sonra da bir kez yeniden başlattım, --now'a rağmen -gerekiyormuş. Açıldıntan sonra başlat menüme eklenen Touche simgesine tıklayınca Touche penceresi açıldı:

 

Buradan 3 parmak hatta 4 parmak kaydırma hareketleri için istediğim atamaları yapabildim.

3.02.2025

Manjaro'da gerek duyulmayan paketleri silmek

Manjaro linux'umdaki root partition'ım doldu. Biraz yer açmam lazım. En büyük yer kaplayan klasör de pacman cache'i.

pacman -Qdtq

komutu ile bir sürü pakete artık ihtiacımın olmadığnı görüyorum. Ama bir ara Linus Sebastian'ın başına geldiği gibi birşeyin benim başıma da gelmemesi için öncelikle bütün paketlerin gerçekten ihtiyaç duyulmadığını görmek, hatta şüphe ettiklerimi kapsam dışında bırakmak istiyorum. Öncelikle -Qdtq ile listelenen paket listesini bir dosyaya atıyorum.

pacman -Qdtq > gereksizler.txt

Belki ilk iş olarak bu listeye bakabilir, tereddüt ettiklerimi çıkarabilirim. Sonra bu listedeki her paketin -Qi ile listelenen bilgilerine bakmak istiyorum. Örneğin electron paketi gereksiz olarak listelenmiş. -Qi ile baktığımda şöyle bir çıkış alıyorum:

pacman -Qi electron
İsim                   : electron
Sürüm                  : 1:33-1
Açıklama               : Meta package providing the latest available stable Electron
                         build
Mimari                 : any
URL                    : https://electronjs.org
Lisanslar              : MIT
Gruplar                : Hiçbiri
Sağlananlar            : Hiçbiri
Bağımlılıkları         : electron33
Tercihli Bağımlılıklar : Hiçbiri
İhtiyaç Duyulanlar     : Hiçbiri
İsteğe Bağlı           : Hiçbiri
Çakışıyor              : Hiçbiri
Değiştirilenler        : Hiçbiri
Kurulum Boyutu         : 0,00 B
Paketçi                : Caleb Maclennan <alerque@archlinux.org>
İnşa Tarihi            : Sal 15 Eki 2024 23:10:40
Yükleme Tarihi         : Paz 01 Ara 2024 09:31:58
Yükleme Sebebi         : Başka bir paketin bağımlılığı olarak kurulmuş
Kurulum Betiği         : Hayır
Doğrulayan             : İmza

Burada İhityaç Duyulanlar alanı, bu pakete ihtiyaç duyan diğer paketleri, İsteğe Bağlı alanı ise çalışmak temel işlevleri için değil de bazı ek işlevler için bu pakete ihtiyaç duyabilecek paketleri listeliyor. Görüldüğü gibi electron için bu liste boş. Dolayısıyla silinebilir. Bu listedeki 92 paket için bunu elle yapmak istemiyorum. Otomatize etmek için

xargs -r pacman -Qi < gereksizler.txt | grep -E "İhtiyaç Duyulanlar|İsteğe Bağlı"

gibi bir komutla her paket için ekrana "İhtiyaç Duyulanlar" ve "İsteğe Bağlı" alanlarını yazdırıp gerçekten gereksiz olup olmadığını görmek istiyorum.

Bu adım gereksiz, evet. Ama emin olmak istedim. Nihayet, her paket için hem ihtiyaç duyulan hem de isteğe bağlı satırda "Hiçbiri" yazdığını görünce tümünü birden silme komutunu verdim.

sudo pacman -Rsn $(pacman -Qdtq)

2.02.2025

Dizüstü bilgisayarın bataryasının durumunu kontrol etme

Dizüstü bilgisayarların bataryaları zamanla ilk günkü kapasitelerini kaybederler. Bataryamızın fabrika çıkışındaki kapasitesi ile bugünkü kapasitesini karşılaştırmak istersek Windows'da powercfg komutunu kullanabiliriz.

powercfg /batteryreport

Bu bir htm formatında rapor dosyası üretecek, bulunduğumuz klasörde.  Tarayıcımızla açıp inceleyebiliriz. Bu dosyada "DESIGN CAPACITY" bölümünde gözüken bataryamızın fabrika çıkışındaki kapasitesi. "FULL CHARGE CAPACITY" bölümünde gözüken ise bugünkü kapasitesi.

Linux'ta ise bunu upower komutu ile yapabiliriz. Linux'ta bu iki aşamada oluyor. Önce upower ile mevcut cihazları listelemek gerek.

upower -e

Burada muhtemelen battery_BAT0 gibi bir şekilde isimlendirilen kaynağı kopyalayıp bir sonraki adımda upower'a -i parametresi ile birlikte yapıştırmak gerek:

upower -i /org/freedesktop/UPower/devices/battery_BAT0

Bu komutun çıktısında da energy-full-design bataryanın tasarlanan kapasitesini, energy-full ile bugünkü kapasitesini gösteriyor.

bugünkü kapasite / tasarlanan kapasite 'nin 0,8'den küçük olması bataryanın kapasitesinin ciddi düştüğü anlamına geliyor.

1.02.2025

Gnome'da batarya düşük ve kritik seviyelerini belirlemek

Gnome masaüstü kullanan bir bilgisayardayım. Varsayılan düşük batarya seviyesi %20. Yani bu seviyeden sonra düşük güç harcama kipi etkinleştiriliyor. Kritik batarya seviyesi %5 ve askıya alma seviyesi de %2. Batarya yeniyken sorun yok ama batarya bir süre (~2 yıl?) kullanıldıktan sonra bu seviyeleri değiştirmek gerekebilir. Benim bilgisayarımda seviye %10'a geldikten sonra çok hızlı bir şekilde %2'ye düşüyor ve askıya alma işlemi gerçekleşiyor. Bu sebeple bu seviyeleri biraz yükseltmek gerek. Ama grafik arayüzde bunu değiştirecek bir yer bulamadım. Şu sayfada bulduğum bilgi işimi yarar. Önce uygun bir editör ile /etc/UPower/UPower.conf dosyasını (sudo ile) açıp şu satırlara geledim:

PercentageLow=10.0
PercentageCritical=5.0
PercentageAction=2.0

Bu satırları aşağıdaki gibi değiştirdim.

PercentageLow=30.0
PercentageCritical=10.0
PercentageAction=5.0

Sonra da upower hizmetini tekrar başlattım.

sudo systemctl restart upower.service

20.01.2025

uBlock Origin Lite

Bu geçişi kaçırmışım. Bir ara Google'ın Chrome tarayıcısının eklentileri için oluşturduğu Manivest v3 vardı. uBlock Origin'in v3 uyumlu olmadığından bahsediliyordu ve Chromium tabanlı tarayıcılarda artık güvenilir bir reklam engelleyicinin kalmayacağı düşünülüyordu. Bu dönemde uBlock Origin'in v3'e uyumlu sürümü Lite çıkmış. Chrome Web Mağazası'nda artık uBlock Origin Lite var.

İkinci sırada gözüken uBlock, Raymond Hill'in geliştirdiği eklenti değil.

Madem ortada bir "Lite" sürüm var, merak ettim neleri yapabiliyor, neleri yapamıyordur. Benimle birlikte merak edenler de varmış. Örneğin ssg'nin ekşi sözlük'teki 28.09.2022 tarihli entry'si:

Temel olarak olay bundan ibaret. Firefox'ta hala manifest v2 uyumlu tam sürüm bir uBlock origin kullanılmaya devam ediyor. Ama Chrome Web Store'da artık bu yok, onun yerine v3 uyumlusu var. Daha kısıtlı özellikleri var.

  • Youtube reklamları artık engellenmiyor.
  • Filtreler otomatik olarak güncellenmiyor, sadece yeni sürüm çıktığında o yüklenirken güncelleniyor.Merak ettim, m
  • Bazı durumlarda regex tabanlı filtrelemeler çalışmıyor.

Ayrıntılar için aşağıdaki bağlantılara bakılabilir. Ama ilk bağlantıda da dediği gibi, uBlock en iyi Firefox'ta çalışıyor.



---

https://github.com/gorhill/uBlock/wiki/uBlock-Origin-works-best-on-Firefox
https://github.com/uBlockOrigin/uBOL-home/wiki/Frequently-asked-questions-(FAQ)
https://github.com/uBlockOrigin/uBlock-issues/issues/338#issuecomment-1332300191
https://github.com/uBlockOrigin/uBlock-issues/issues/338#issuecomment-1507539114
https://www.aboutcookies.org.uk/ad-blockers/ublock-review

11.01.2025

Hafta numaraları

Türkiye'de çok kullandığımız birşey olmasa da yılın içinde kaçıncı hafta olduğumuz bilgisi bazen faydalı olabiliyor. Powershell'de bu işi doğrudan Get-Date'i formatlayarak yapabiliriz:

Get-Date -UFormat %V

İlk haftanın hangisi olacağı ölçütü var. Bazı kültürlerde yılın ilk haftası olarak ilk tam hafta (FirstFullWeek), diğerlerinde yılın ilk gününün olduğu hafta (FirstDay) ötekilerde ise ilk 4 veya daha günlük hafta (FirstFourDayWeek) olarak kabul edilir [1].

Türkçe Windows'da bunu öğrenmenin yolu:

$kultur = Get-Culture
$kultur.DateTimeFormat.CalendarWeekRule

FirstDay

Yani yılın ilk gününün olduğu hafta bizde yılın ilk haftası kabul ediliyor. 1 Ocak Pazar bile olsa ertesi gün 2 Ocak bizim için yılın ikinci haftası. Değiştirmek mi istiyoruz? Olur [2, 3]:

$kulturBilgisi = [System.Globalization.CultureInfo]::InvariantCulture
$takvim = $kulturBilgisi.calendar
$takvimYilinIlkHaftasi = [System.Globalization.CalendarWeekRule]::FirstFourDayWeek
$haftaninIlkGunu = [System.DayOfWeek]::Sunday
$suAn = Get-Date
$haftaNo = $takvim.GetWeekOfYear($suAn, $takvimYilinIlkHaftasi, $haftaninIlkGunu)
"ISO 8601 standardına göre hafta numarası: $weekNumber"

Bu satırlar da yılın ilk haftasının en az 4 günü olan bir hafta olması ve haftanın ilk günün Pazar olması kuralına göre hesaplar.

Eski günlerden kalma güzel bir çalışma da Scripting Guy'a ait.