2023-04-26

Powershell'de çıkışa satır numarası eklemek

Domain'de bir grubun üyelerini listelemek için şöyle bir komut kullanıyorum:

Get-ADGroupMember -Identity "Grup Adi"

Bunun sonucunda kullanıcı nesneleri listelenir. Nesne ile bütün verilere ihtiyacım yok, sadece isimler yeterli. Bu durumda select-object ile sadece Name alanı süzülebilir:

Get-ADGroupMember -Identity "Grup Adi" | select name

Gelen listeye bir de kullanıcıların grup bilgisini eklemek istiyorum. Benim durumumda bu bilgi Organizational Unit adında var.

Get-ADGroupMember -Identity "Grup Adi" | select Name,@{N="Bolum";E={$_.DistinguishedName.split(",")[1].Split("=")[1]}}

Nihayet, bir de bu listeyi 1'den başlayıp her satırda artan şekilde satır numaralarıyla görüntülemek istiyorum. Bunun için bir $satir değişkeni yaratıp şu şekilde sürece ilave ettim:

$satir=0;  Get-ADGroupMember -Identity "Grup Adi" | select Name,@{N="Bolum";E={$_.DistinguishedName.split(",")[1].Split("=")[1]}} | % {$satir++;"$satir `t$($_.Name)`t$($_.Bolum)}

Daha kolay bir örnek üzeriden satır numaraları konusunu tekrarlayayım. Bir metin dosyasına satır numaraları eklemek için

$satir=0; gc dosya.txt | % {$satir++;"$satir`t$_"}

Takıntılı davranış bozukluğu olanlar tire "-" karakterinin kaymasından hoşnut olmayabilir:

$satir=0; gc dosya.txt | % {$satir++;"{0,3} - {1}" -f $satir,$_}

2023-04-24

Powershell ile ekran çözünürlüğünü değiştirmek

Maalesef Powershell ile varsayılan olarak çözüürlüğü değiştirecek bir cmdlet gelmiyor. Ama Powershell-Gallery'de güzel bir modül var. Kurmak için terminali yönetici yetkileriyle açtıktan sonra

PS> Install-Module DisplaySettings

kullanmak ve sonrasında kaynağa güvendiğimizi belirtmek gerek. Bu adımlardan sonra

PS> Set-DisplayResolution -Width 1440 -Height 900

ile çözünürlüğü ayarlamak mümkün. Var olan çözünürlüğü öğrenmek için ise

PS> Get-DisplayResolution

var. Modüldeki yegane iki cmdlet bunlar. Modül bugün itibarı ile 0.0.2 sürümde.

Server Core için böyle bir modül var ama PSGallery'deki modülün Microsoft ile bir ilişkisini göremedim.

2023-04-10

Powershell'de tür dönüşümü (casting)

Birçok programlama ortamında tür dönüşümü eşittir işaretinin sağında yapılır. Ama powershell'de bu iş eşittirin solunda da yapılıyor. Bunun sebebiyle ilgili bulduğum çok güzel bir açıklamayı[1] paylaşmak istiyorum.

Varsayalım bir xml dosyamız var, diskte kayıtlı (dosya.xml). Bu xml dosyamızı okuyup bir değişkene atmak istiyoruz. Ama değişkenimizin de xml tipinde bir değişken olmasını istiyoruz. Diğer programlama ortamlarından alışık olduğumuz durum şu olabilir:

PS> $x = [xml]Get-Content -Path dosya.xml

Bu yanlış bir ifade olurdu. [xml] tür dönüşümü yapmak istediğimiz veri, dosya.xml dosyası okunduktan sonra Get-Content cmdlet'inin döndüğü tüm veri olduğundan burada bir parantez kullanmalıyız. Yani;

PS> $x = [xml](Get-Content -Path dosya.xml)

Bu şekilde x değişkenine atanan verinin xml türünde olması sağlanabilir. Ama powershell'de bu iş şu şekilde yapılıyor:

PS> [xml]$x = Get-Content -Path dosya.xml

Bu şekilde x değişkenimizin türü xml olarak oluşturulmuş. Sonrasında bu değişkene yapılacak atamaların da otomatik xml'e dönüştürülmesi sağlanmış.

---

[1] https://stackoverflow.com/questions/11685265/casting-in-powershell-weird-syntax

2023-04-07

Olay günlüğü (eventlog) boyutlarını değiştirme

Get-WinEvent ile güvenlik olay kayıtlarını incelerken bazen hiç kayıt dönmüyor. Bunun sebebi de varsayılan olarak 20 MB olarak ayarlanan güvenlik olay günlüğünün bir süre sonra eski olayları siliyor olması. Yerel bilgisayarda mevcut durumu kontrol etmek için

PS> Get-Evenlog -List

kullanabiliriz. Güvenlik olay günlüğü (security) için bunu yönetici yetkileriyle açılmış bir pencereden çalıştırmamız gerek. Uygulama ve sistem için buna gerek yok. Bu komutun ürettiği çıktıda Max(K) sütununa bakarak istediğimiz olay günlüğünün azami boyutunu öğrenebiliriz. Bunu Get-WinEvent ile de yapabiliriz. Örneğin uzak bir bilgisayarın uygulama, sistem ve güvenlik olay kayıtlarını (yetkilerimiz dahilinde) incelemek için

PS> Get-WinEvent -Computername uzakpc -Listlog Application, System, Security

Yerel bilgisayarda olay herhangi bir günlüğüne ayrılmış alanı değiştirmek için

PS> Limit-Eventlog -LogName Security -MaximumSize 128MB

kullanabiliriz. Yeni boyutun 64KB'ın katları olması gerektiği söylenmiş. Bunu sağlamak için en iyi yöntem MB birimlerini kullanarak 1MB'ın katlarını belirtmek olabilir.

Limit-Eventlog cmdlet'inin -Computer parametresi ile ya da Invoke-Command kullanarak bu işlemi uzak bilgisayarlarda da uygulayabiliriz.

Sadece yerel bilgisayarda çalışan Get-LogProperties cmdlet'ini uzak bilgisayarda kullanmak için Invoke-Command ile birlikte çalıştırabiliriz. Hatta alias'larla birlikte şöyle bir çıktı üretir:

PS> icm -cn uzakpc {Get-LogProperties Security}

PSComputerName : uzakpc
RunspaceId     : <...>
Name           : Security
Enabled        : True
Type           : Admin
Retention      : False
AutoBackup     : False
MaxLogSize     : 524288000

2023-11-24 Ek: Bu harika yöntem, Application and Services Logs (Uygulama ve Hizmet Günlükleri) altındaki günlüklerin boyutlarını değiştiremiyor. Örneğin

PS> Get-WinEvent -LogName "Microsoft-Windows-TaskScheduler/Operational"

ile "Microsoft-Windows-TaskScheduler/Operational" günlüğünü bulmasına rağmen

PS> Limit-Eventlog "Microsoft-Windows-TaskScheduler/Operational" -MaximumSize 512MB

hata dönüyor. İki yöntem buldum. Birincisi Get-WinEvent kullanmak:

PS> $log1 = Get-WinEvent -ListLog "Microsoft-Windows-TaskScheduler/Operational"
PS> $log1.MaximumSizeInBytes = 128MB
PS> $log1.SaveChanges()

İkinci yöntem ise Kayıt defteri düzenleyicisini kullanmak. Regedit.exe ile açtıktan sonra HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT\Channels\Microsoft-Windows-TaskScheduler/Operational yoluna giderek buradaki MaxSize byte cinsinden değerini değiştirebiliriz. 128MB için bu 0x8000000 veya 134217728 olabilir.

2023-03-26

Powershell'in dahili fonksiyonları

Powershell'de New-Item cmdlet'ini yeni dosya oluşturmak veya yeni klasör oluşturmak için kullanabiliriz. Bu farkı belirtmek için -ItemType var. Dökümantasyona göre varsayılan bir değeri yok:


Ama garip bir şekilde özellikle belirtmezsek dosya sistemi modunda "dosya" oluşturuyor. Bu varsayılan değer demek değil mi?

Neyse, bu cmdlet'in "ni" alias'ı da var. Gerek tam cmdlet adı, gerek alias'ı ni ile klasör oluşturmak için -ItemType'a Directory değerini vermek yeterli. Hatta ItemType parametresinin yukarıdaki resimde görüldüğü gibi Type alias'ı da var.

PS> New-Item -ItemType Directory -Name YeniKlasor

PS> ni -type directory YeniKlasor

Ama ilginç bir şekilde mkdir veya md komutları da Powershell'de çalışıyor. Önceleri bunları New-Item alias'ları olduğunu sanmıştım ama öyle değilmiş (olsaydı alias için varsayılan parametre değeri nasıl değiltirilir, merak ederdim). Get-Command ile baktığımda şöyle bir sonuç aldım:

PS> Get-Command mkdir

CommandType     Name                      Version    Source
-----------     ----                      -------    ------
Function        mkdir

Meğer mkdir bir Powershell dahili (built-in) komutuymuş. md ise mkdir için bir alias'mış. Diğer dahili komutlar şunlar:

cd..
cd\
ImportSystemModules
pause
help
prompt
Clear-Host
TabExpansion2
Get-Verb
oss

Bunların hepsi için Get-Command ile baktığımızda CommandType sütununda Function yazıyor. Örneğin Write-Host'a Get-Command ile baktığımızda ise CommanType'ı Cmdlet ve Source sütununda modül adı ve Version sütununda da sürüm numarası yazar. Ama Get-Help mkdir'a baktığımda gözüken yardım girdisi, New-Item'in.

PS> Get-Help mkdir

NAME
    New-Item

SYNOPSIS
    Creates a new item.

SYNTAX
    New-Item [[-Path] <System.String[]>] [-Credential <System.Management.Automation.PSCredential>] [-Force] [-ItemType
    <System.String>]
-Name <System.String> [-UseTransaction] [-Value <System.Object>] [-Confirm] [-WhatIf] [<CommonPara
    meters>]

    New-Item [[-Path] <System.String[]>] [-Credential <System.Management.Automation.PSCredential>] [-Force] [-ItemType
    <System.String>]
[-UseTransaction] [-Value <System.Object>] [-Confirm] [-WhatIf] [<CommonParameters>]

Her ne kadar bu yardım girdisinde -ItemType parametresi verilmiş olsa da mkdir ile -ItemType'ı kullanmak aşağıdaki gibi bir hataya sebep oluyor:

PS> mkdir -ItemType file -Name qwer
mkdir : A parameter cannot be found that matches parameter name 'ItemType'.
At line:1 char:7
+ mkdir -ItemType file -Name qwer
+       ~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [mkdir], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,mkdir

Bu arada help'in de bir alias değil de bir dahili komut olması da ilginç.

2023-03-17

Windows Terminal'de 2 farklı powershell profili

Windows Terminal'e birden fazla profil eklemek mümkün. Ama aynı powershell sürümü için birden fazla profil dosyası (powershell oturumu başladığında çalıştırılacak, tek profil durumunda Belgelerim\WindowsPowershell konumunda bulunan *.ps1 uzantılı dosya) nasıl yapılır sorusunun cevabı şu adreste var. Çözüm, için Windows Terminal'in settings.json dosyasını ($env:LOCALAPPDATA\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState konumunda) açıp, yeni yaratılan profilin içine 

"commandline": "powershell.exe -noprofile -noexit -command \"invoke-expression '. ''C:/PsProfile.ps1''' \"",

gibi bir satır eklemek. Burada yeni oturum çalıştırılıdığında C:\PsProfile.ps1 gibi bir dosyanın "dot sourcing" yöntemi ile çalıştırılması sağlanmış (noktaya dikkat!). Bu şekilde farklı prompt'lar, farklı diğer şeyler yaratılabilir. Bundan sonra Windows Terminal ile diğer görünüm ayarları yapılabilir. Örneğin Exhange Management Shell'e bağlanmak için PsProfile.ps1 içine

$cred = Get-Credential -Username "<domain\user>" -Message "Credential to connect to Exchange server"
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://<exchange_url>/PowerShell/ -Credential $cred -Authentication Kerberos
Import-PSSession $Session -Verbose

yazarak Exhange'e özgü bir tema oluşturabiliriz. Her profilin kendine özgü bazı alias'ları, değişkenleri profil dosyasına yazılabilir.

2023-03-15

Manjaro duvar kağıtları, Simon Stalenhag, Sven Dahlstrand, bash ve Powershell

Manjaro KDE'de duvar kağıtları konusunda değişik seçenekler var. Her açılışta zevkinize göre değişik duvar kağıtlarından birini (kdeplasma-addons paketi ile geliyor) sizin için ayarlayabiliyor.

 

Seçeneklerden biri çok hoşuma gitti. İsmine bakınca koleksiyonun adının Simon Stalenhag olduğunu gördüm. Aratınca bir sürü benzer duvar kağıdının sanal alemde bulunabildiğini farkettim. Hemen Windows'a uyarlamak geldi aklıma. Önce wallpaperflare.com sitesini buldum. Ama buradaki tam boyuttaki resimler maalesef base64 formatında. Bunları powershell ile kaydetmenin  bir yolunu bulamadım. Browser ile statik olarak yüklenmiyorlar, Invoke-WebRequest ile yaptığım işlemde sayfada yer almıyor, muhtemelen bir Javascript ile yerine konuyor. Daha fazla seçenek ararken benzer zevke sahip bir sanal alem bireyi Sven Dahlstrand'ın çalışmasına denk geldim:

ROOT_URL="http://simonstalenhag.se"
MAX_PROCESSES=30
curl -s "${ROOT_URL}" |
grep -Eio "bilderbig[^\"]+\.jpg" |
sort | uniq |
xargs -P "${MAX_PROCESSES}" -n 1 basename |
xargs -P "${MAX_PROCESSES}" -n 1 -I {} curl -z {} -f -O "${ROOT_URL}/bilderbig/{}"

Bunu anlamak bile uzun sürdü. Anladıklarımı özetleyeyim.

- İlk 2 satırda sanatçının çalışmalarının yer aldığı web sayfasının adresi ile xargs komutu ile aynı anda çalıştırılacak süreç sayısı değişkenlere atanmış.

- 3. satırda web sayfasının içeriği alınmış ve 4. satırda içinde bilderbig geçen ve uzantısı .jpg olan adresleri regular expressions ile ayırmış

- 5. satırda bunları sıralayıp içinden tekrarlayan kayıtları silmiş (uniq komutunun önkoşulu girişin sıralı -alfabetik veya değil- olması)

- basename, http://simonstalenhag.se/bilderbig/image.jpg gibi bir adresin içinden sadece image.jpg bilgisini ayırıyor.

- En son satır ise 30 paralel süreçte dosyalar indirilerek her biri aynı isimle mevcut klasöre kaydediliyor.

Bunu powershell ile yapmanın yollarından biri:

$root_url = "http://simonstalenhag.se"
$content = iwr $root_url
$content.Links.href | where {$_ -like "bilderbig*"} | sort | gu | 
% { iwr -uri ($root_url+"/"+$_) -OutFile (Split-Path $_ -Leaf) } 

olabilir. Birebir aynısı değil. 30 paralel işlem yok. curl komutunun -f parametresi, dosyaların olup olmadığını da kontrol ediyor, ben etmedim. Invoke-WebRequest her seferinde üzerine yazar. Bu davranışı değiştirecek bir yol bulamadım ama -OutFile parametresini terk edip, çıkış Out-File cmdlet'ine yönlendirmek (pipe) gibi yöntemlere geçilebilir.

Paralel işlem yapabilmek için de Powershell Core kullanılabilir. Son satırda Foreach-Object'in alias'ı olarak kullanılan "%" sonrasında -Parallel ve hatta -ThrottleLimit eklenebilir:

% -Parallel -ThrottleLimit 30 { ... }

Sonrasında indirilen resimlerden birini duvar kağıdı olarak ayarlamak için daha önce bulduğum Set-Wallpaper fonksiyonu kullanılabilir.