# ProgramKurulum.ps1 — v4 # Format sonrası kullanılan programları tek ekrandan kurmak için (WinUtil tarzı, bağımsız script). # Çalıştırma: powershell -ExecutionPolicy Bypass -File .\ProgramKurulum.ps1 # ya da: irm | iex # # v4.3: terminal banner'ı büyük blok harfli, gölgeli ve renk geçişli olarak yeniden tasarlandı. # v4.2: chip/buton köşelerinde kalan taşan beyaz pikseller giderildi (Label'ın kendi metni temizleniyor). # v4.1: yuvarlak köşeler Region yerine GDI+ AntiAlias ile çiziliyor (tırtıklı kenar giderildi). # # v4 notları: # - YERLEŞİM: Kenarlıksız formda pencere boyutu sonradan değiştiği için sağa/alta # sabitlenmiş (Anchor) kontroller ~16px kayıyordu (✕ taşması, buton/log kayması). # Artık ClientSize açıkça ayarlanıyor ve tüm kontroller Yerlesim-Uygula fonksiyonuyla # ClientSize'a göre hesaplanarak yerleştiriliyor. # - BAŞLIK ÇUBUĞU: ⓘ / tema / küçült / kapat simgeleri font yerine GDI+ ile çiziliyor # (emoji/font sorunu yok), eşit boyutlu ve bitişik, hover'da arka plan (kapat = kırmızı). # - ARAMA: yuvarlak köşeli, odakta vurgu rengi alan, çizilmiş büyüteç ikonu. # - KATEGORİ: beyaz ComboBox yerine tema uyumlu "chip" filtreleri. # - İlerleme çubuğu ve günlük kutusu koyu temaya uyduruldu. # - "Güle güle" ekranı: timer'lar fonksiyon-yerel değişken yerine olay parametresi ($s) # kullanıyor (önceki sürümde pencere bu ekranda takılıp kalabiliyordu). # - Arama tr-TR kültüründe "ins" -> "Insights" eşleşmiyordu (I -> ı); artık OrdinalIgnoreCase. # - Tema değişince tüm öğeler (butonlar, satır seçimi, başlık simgeleri...) güncelleniyor. # - Kurulum sırasında liste yenilenirken kaydırma konumu korunuyor. # ---- irm | iex ile çalıştırmak için: script'in barındırıldığı RAW link ---- $ScriptUrl = "https://gist.githubusercontent.com/VegGieg1-dev/fb41e5eb54a28c1d516c98718f85efaf/raw/ProgramKurulum.ps1" # ---- WinForms STA gerektirir; pwsh/powershell MTA modda başlamışsa STA ile yeniden başlat ---- if ([System.Threading.Thread]::CurrentThread.ApartmentState -ne 'STA') { $exe = (Get-Process -Id $PID).Path if ($PSCommandPath) { Start-Process -FilePath $exe -ArgumentList @('-NoProfile', '-STA', '-ExecutionPolicy', 'Bypass', '-File', "`"$PSCommandPath`"") | Out-Null } else { Start-Process -FilePath $exe -ArgumentList @('-NoProfile', '-STA', '-ExecutionPolicy', 'Bypass', '-Command', "irm '$ScriptUrl' | iex") | Out-Null } exit } # ================= TERMİNAL BANNER ================= # Büyük blok harfli (█) "RogeRsen" banner'ı: gölgeli + satır satır renk geçişli. # Blok karakterler [char] koduyla üretilir, böylece dosya kodlamasından etkilenmez. function Show-Banner { $blok = [string][char]0x2588 # █ $golge = [string][char]0x2592 # ▒ # Her harf 9 satır; '#' dolu, '.' boş. Büyük harf 7 satır, küçük harf 5 satır, g'nin kuyruğu 2 satır. $font = @{ 'R' = @('####.', '#...#', '#...#', '####.', '#.#..', '#..#.', '#...#', '.....', '.....') 'o' = @('....', '....', '.##.', '#..#', '#..#', '#..#', '.##.', '....', '....') 'g' = @('....', '....', '.###', '#..#', '#..#', '#..#', '.###', '...#', '.##.') 'e' = @('....', '....', '.##.', '#..#', '####', '#...', '.###', '....', '....') 's' = @('....', '....', '.###', '#...', '.##.', '...#', '###.', '....', '....') 'n' = @('....', '....', '###.', '#..#', '#..#', '#..#', '#..#', '....', '....') } $kelime = "RogeRsen".ToCharArray() $satirSayisi = 9 # Her font pikseli 2 karakter genişliğinde (kare görünsün diye); harfler arası 1 karakter boşluk. $maske = @() for ($sat = 0; $sat -lt $satirSayisi; $sat++) { $parcalar = @() foreach ($harf in $kelime) { $parcalar += (($font[[string]$harf][$sat] -replace '#', '##') -replace '\.', ' ') } $maske += ($parcalar -join ' ') } $genislik = $maske[0].Length # Konsol bu banner için fazla darsa sade bir başlığa düş $konsolGenislik = 120 try { $konsolGenislik = $Host.UI.RawUI.WindowSize.Width } catch {} if ($konsolGenislik -lt ($genislik + 4)) { Write-Host "" Write-Host " R o g e R s e n" -ForegroundColor Cyan Write-Host "" return } # Tuval: 1 satır + 2 sütun gölge payı. 0 = boş, 1 = harf, 2 = gölge $satirToplam = $satirSayisi + 1 $sutunToplam = $genislik + 2 $hucre = [Array]::CreateInstance([int], $satirToplam, $sutunToplam) for ($sat = 0; $sat -lt $satirSayisi; $sat++) { for ($sut = 0; $sut -lt $genislik; $sut++) { if ($maske[$sat][$sut] -eq '#') { $hucre[$sat, $sut] = 1 } } } for ($sat = 0; $sat -lt $satirSayisi; $sat++) { for ($sut = 0; $sut -lt $genislik; $sut++) { if ($maske[$sat][$sut] -eq '#' -and $hucre[($sat + 1), ($sut + 2)] -eq 0) { $hucre[($sat + 1), ($sut + 2)] = 2 } } } $renkler = @('Cyan', 'Cyan', 'Cyan', 'DarkCyan', 'DarkCyan', 'DarkCyan', 'Blue', 'Blue', 'Blue', 'DarkGray') Write-Host "" for ($sat = 0; $sat -lt $satirToplam; $sat++) { Write-Host " " -NoNewline $sut = 0 while ($sut -lt $sutunToplam) { $tur = $hucre[$sat, $sut] $bas = $sut while ($sut -lt $sutunToplam -and $hucre[$sat, $sut] -eq $tur) { $sut++ } $uzun = $sut - $bas if ($tur -eq 1) { Write-Host ($blok * $uzun) -NoNewline -ForegroundColor $renkler[$sat] } elseif ($tur -eq 2) { Write-Host ($golge * $uzun) -NoNewline -ForegroundColor DarkGray } else { Write-Host (' ' * $uzun) -NoNewline } } Write-Host "" } # Alt başlıklar, banner genişliğine göre ortalanır $ortala = { param($metin) $bosluk = [Math]::Max(0, [int](($sutunToplam - $metin.Length) / 2)) return (" " + (' ' * $bosluk) + $metin) } Write-Host "" Write-Host (& $ortala "===== Format Sonrasi Program Kurulumu =====") -ForegroundColor DarkGray Write-Host (& $ortala "bit.ly/RogeRsen") -ForegroundColor Cyan Write-Host "" } Clear-Host Show-Banner Write-Host " GUI aciliyor, bekleyin..." -ForegroundColor DarkGray Write-Host "" Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing # İlerleme çubuğunun görsel temasını kapatmak için (koyu temada renkler uygulansın diye) try { Add-Type -Namespace RogeRsen -Name Native -MemberDefinition @' [System.Runtime.InteropServices.DllImport("uxtheme.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] public static extern int SetWindowTheme(System.IntPtr hWnd, string appName, string idList); [System.Runtime.InteropServices.DllImport("dwmapi.dll")] public static extern int DwmSetWindowAttribute(System.IntPtr hwnd, int attr, ref int attrValue, int attrSize); '@ } catch {} # ================= TEMA PALETLERİ ================= $temaKoyu = @{ Arkaplan = [System.Drawing.Color]::FromArgb(24, 24, 27) Panel = [System.Drawing.Color]::FromArgb(32, 32, 36) PanelKoyu = [System.Drawing.Color]::FromArgb(26, 26, 29) Vurgu = [System.Drawing.Color]::FromArgb(88, 145, 255) VurguKoyu = [System.Drawing.Color]::FromArgb(64, 112, 210) Yazi = [System.Drawing.Color]::FromArgb(235, 235, 240) YaziSoluk = [System.Drawing.Color]::FromArgb(150, 150, 160) YaziPasif = [System.Drawing.Color]::FromArgb(90, 90, 98) Log = [System.Drawing.Color]::FromArgb(14, 14, 16) LogYazi = [System.Drawing.Color]::FromArgb(120, 220, 140) Kenar = [System.Drawing.Color]::FromArgb(46, 46, 52) ButonAlt = [System.Drawing.Color]::FromArgb(52, 52, 58) ButonAltHover = [System.Drawing.Color]::FromArgb(68, 68, 76) } $temaAcik = @{ Arkaplan = [System.Drawing.Color]::FromArgb(246, 246, 249) Panel = [System.Drawing.Color]::FromArgb(255, 255, 255) PanelKoyu = [System.Drawing.Color]::FromArgb(237, 237, 242) Vurgu = [System.Drawing.Color]::FromArgb(64, 112, 220) VurguKoyu = [System.Drawing.Color]::FromArgb(46, 90, 190) Yazi = [System.Drawing.Color]::FromArgb(28, 28, 32) YaziSoluk = [System.Drawing.Color]::FromArgb(100, 100, 110) YaziPasif = [System.Drawing.Color]::FromArgb(170, 170, 178) Log = [System.Drawing.Color]::FromArgb(250, 250, 250) LogYazi = [System.Drawing.Color]::FromArgb(30, 130, 60) Kenar = [System.Drawing.Color]::FromArgb(222, 222, 230) ButonAlt = [System.Drawing.Color]::FromArgb(228, 228, 236) ButonAltHover = [System.Drawing.Color]::FromArgb(212, 212, 224) } $script:temaAdi = "Koyu" $script:tema = $temaKoyu $fontNormal = New-Object System.Drawing.Font("Segoe UI", 9.5) $fontBaslik = New-Object System.Drawing.Font("Segoe UI Semibold", 12.5) $fontAltBaslik = New-Object System.Drawing.Font("Segoe UI", 8.5) $fontButon = New-Object System.Drawing.Font("Segoe UI Semibold", 9) $fontLog = New-Object System.Drawing.Font("Consolas", 9) # Durum sütunu (✓ ✗ ⏳) için sembol fontu; güle güle ekranındaki 👋 için emoji fontu $fontDurum = New-Object System.Drawing.Font("Segoe UI Symbol", 10) $fontEmojiBuyuk = New-Object System.Drawing.Font("Segoe UI Emoji", 20) # ================= YARDIMCI FONKSİYONLAR ================= function New-YuvarlakYol([int]$w, [int]$h, [int]$r) { $yol = New-Object System.Drawing.Drawing2D.GraphicsPath $d = $r * 2 $yol.AddArc(0, 0, $d, $d, 180, 90) $yol.AddArc($w - $d, 0, $d, $d, 270, 90) $yol.AddArc($w - $d, $h - $d, $d, $d, 0, 90) $yol.AddArc(0, $h - $d, $d, $d, 90, 90) $yol.CloseFigure() return $yol } function Set-YuvarlakBolge($ctrl, $yaricap) { if ($ctrl.Width -le 0 -or $ctrl.Height -le 0) { return } $yol = New-YuvarlakYol $ctrl.Width $ctrl.Height $yaricap $ctrl.Region = New-Object System.Drawing.Region($yol) } # Çift tamponlama (titremeyi azaltır). DoubleBuffered korumalı bir özellik: reflection ile açılır. function Set-DoubleBuffer($ctrl) { try { $ctrl.GetType().GetProperty("DoubleBuffered", [System.Reflection.BindingFlags]"Instance,NonPublic").SetValue($ctrl, $true, $null) } catch {} } # Yuvarlak köşeli dolgulu buton/chip boyayıcısı. # Region KULLANILMAZ (Region kenarları antialias'sız, tırtıklı görünür); şekil GDI+ AntiAlias ile # çizilir, kontrolün BackColor'ı form zemini rengi olduğu için köşeler pürüzsüzce karışır. $yuvarlakBoya = { param($s, $e) $g = $e.Graphics # Label kendi metnini sol üst köşeye çizip sonra bu olayı tetikler; o metnin köşelerde # taşan (beyaz) pikselleri kalmasın diye önce tüm alan zemin renginle temizlenir. $g.Clear($s.BackColor) $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias $g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality $dolgu = $s.Dolgu if (-not $s.Enabled) { $dolgu = $script:tema.Kenar } $yol = New-YuvarlakYol $s.Width $s.Height $s.Yaricap $fir = New-Object System.Drawing.SolidBrush($dolgu) $g.FillPath($fir, $yol) $fir.Dispose(); $yol.Dispose() $renk = $s.ForeColor if (-not $s.Enabled) { $renk = $script:tema.YaziPasif } $rect = New-Object System.Drawing.Rectangle(0, 0, $s.Width, $s.Height) $bayrak = [System.Windows.Forms.TextFormatFlags]::HorizontalCenter -bor [System.Windows.Forms.TextFormatFlags]::VerticalCenter -bor [System.Windows.Forms.TextFormatFlags]::SingleLine -bor [System.Windows.Forms.TextFormatFlags]::NoPadding -bor [System.Windows.Forms.TextFormatFlags]::EndEllipsis [System.Windows.Forms.TextRenderer]::DrawText($g, $s.Text, $s.Font, $rect, $renk, $bayrak) } function New-YuvarlakLabel([string]$metin, $font, [int]$yaricap, $dolgu) { $l = New-Object System.Windows.Forms.Label $l.AutoSize = $false $l.UseMnemonic = $false $l.Text = $metin $l.Font = $font $l.Cursor = [System.Windows.Forms.Cursors]::Hand $l.BackColor = $script:tema.Arkaplan Add-Member -InputObject $l -NotePropertyName Dolgu -NotePropertyValue $dolgu Add-Member -InputObject $l -NotePropertyName Yaricap -NotePropertyValue $yaricap Set-DoubleBuffer $l $l.Add_Paint($yuvarlakBoya) return $l } # Butona yumuşak (lerp) hover animasyonu ekler; animasyon $buton.Dolgu rengi üzerinde çalışır. # Renkler $durum nesnesinde tutulur ki tema değişince güncellenebilsin ($buton.Tag). # Yalnızca yerel değişken yakaladığı için burada .GetNewClosure() doğru ve gerekli. function Animate-Buton($buton, $renkNormal, $renkHover) { $buton.Dolgu = $renkNormal $buton.ForeColor = [System.Drawing.Color]::White $buton.Font = $fontButon $durum = [PSCustomObject]@{ Hedef = $renkNormal; Normal = $renkNormal; Hover = $renkHover } $buton.Tag = $durum $timer = New-Object System.Windows.Forms.Timer $timer.Interval = 15 $timer.Add_Tick({ $simdi = $buton.Dolgu $hedef = $durum.Hedef $r = $simdi.R + ([Math]::Sign($hedef.R - $simdi.R) * [Math]::Min(22, [Math]::Abs($hedef.R - $simdi.R))) $g = $simdi.G + ([Math]::Sign($hedef.G - $simdi.G) * [Math]::Min(22, [Math]::Abs($hedef.G - $simdi.G))) $b = $simdi.B + ([Math]::Sign($hedef.B - $simdi.B) * [Math]::Min(22, [Math]::Abs($hedef.B - $simdi.B))) $buton.Dolgu = [System.Drawing.Color]::FromArgb($r, $g, $b) $buton.Invalidate() if ($r -eq $hedef.R -and $g -eq $hedef.G -and $b -eq $hedef.B) { $timer.Stop() } }.GetNewClosure()) $buton.Add_MouseEnter({ $durum.Hedef = $durum.Hover; $timer.Start() }.GetNewClosure()) $buton.Add_MouseLeave({ $durum.Hedef = $durum.Normal; $timer.Start() }.GetNewClosure()) } # Basit bir uygulama ikonu üretir (yuvarlak + "R" harfi). function New-UygulamaIkonu($renkVurgu) { $bmp = New-Object System.Drawing.Bitmap(32, 32) $g = [System.Drawing.Graphics]::FromImage($bmp) $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias $g.Clear([System.Drawing.Color]::Transparent) $frenBrush = New-Object System.Drawing.SolidBrush($renkVurgu) $g.FillEllipse($frenBrush, 1, 1, 30, 30) $sf = New-Object System.Drawing.StringFormat $sf.Alignment = [System.Drawing.StringAlignment]::Center $sf.LineAlignment = [System.Drawing.StringAlignment]::Center $g.DrawString("R", $fontBaslik, [System.Drawing.Brushes]::White, (New-Object System.Drawing.RectangleF(0, 0, 32, 32)), $sf) $g.Dispose() $hIcon = $bmp.GetHicon() return [System.Drawing.Icon]::FromHandle($hIcon) } # Büyük/kalın/gölgeli banner metni üretir (splash ekranındaki "RogeRsen" için). function New-BuyukBanner([string]$metin, [int]$genislik, [int]$yukseklik, $renkMetin) { $bmp = New-Object System.Drawing.Bitmap($genislik, $yukseklik) $g = [System.Drawing.Graphics]::FromImage($bmp) $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias # Şeffaf zemin üzerinde GridFit kenarlarda tırtık bırakır; düz AntiAlias kullanılıyor. $g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::AntiAlias $g.Clear([System.Drawing.Color]::Transparent) # GDI+ olmayan fontta hata vermez, sessizce başka fonta düşer; bu yüzden önce kurulu mu diye bak. $kurulu = (New-Object System.Drawing.Text.InstalledFontCollection).Families.Name $aile = if ($kurulu -contains "Segoe UI Black") { "Segoe UI Black" } else { "Segoe UI" } $font = New-Object System.Drawing.Font($aile, 34, [System.Drawing.FontStyle]::Bold) $sf = New-Object System.Drawing.StringFormat $sf.Alignment = [System.Drawing.StringAlignment]::Center $sf.LineAlignment = [System.Drawing.StringAlignment]::Center $rectGolge = New-Object System.Drawing.RectangleF(3, 4, $genislik, $yukseklik) $rectAsil = New-Object System.Drawing.RectangleF(0, 0, $genislik, $yukseklik) $golgeBrush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(110, 0, 0, 0)) $g.DrawString($metin, $font, $golgeBrush, $rectGolge, $sf) $anaBrush = New-Object System.Drawing.SolidBrush($renkMetin) $g.DrawString($metin, $font, $anaBrush, $rectAsil, $sf) $g.Dispose() return $bmp } $script:uygulamaIkonu = New-UygulamaIkonu $script:tema.Vurgu # ---- Splash ekranı: kısa süreli logo/başlık ekranı, fade-in/fade-out ---- function Goster-SplashEkrani { $splash = New-Object System.Windows.Forms.Form $splash.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None $splash.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen $splash.ClientSize = New-Object System.Drawing.Size(460, 260) $splash.BackColor = $script:tema.Arkaplan $splash.Opacity = 0 $splash.TopMost = $true $splash.ShowInTaskbar = $false Set-YuvarlakBolge $splash 18 $picIkon = New-Object System.Windows.Forms.PictureBox $picIkon.Image = $script:uygulamaIkonu.ToBitmap() $picIkon.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom $picIkon.Width = 48; $picIkon.Height = 48 $picIkon.Left = [int](($splash.Width - $picIkon.Width) / 2) $picIkon.Top = 24 $splash.Controls.Add($picIkon) $picBanner = New-Object System.Windows.Forms.PictureBox $picBanner.Image = New-BuyukBanner "RogeRsen" 400 70 $script:tema.Vurgu $picBanner.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::CenterImage $picBanner.Width = 400; $picBanner.Height = 70 $picBanner.Left = [int](($splash.Width - $picBanner.Width) / 2) $picBanner.Top = 78 $picBanner.BackColor = [System.Drawing.Color]::Transparent $splash.Controls.Add($picBanner) $altCizgi = New-Object System.Windows.Forms.Panel $altCizgi.BackColor = $script:tema.Vurgu $altCizgi.Width = 140; $altCizgi.Height = 3 $altCizgi.Left = [int](($splash.Width - $altCizgi.Width) / 2) $altCizgi.Top = 150 $splash.Controls.Add($altCizgi) $altyazi = New-Object System.Windows.Forms.Label $altyazi.Text = "Format sonrası program kurulumu yükleniyor..." $altyazi.Font = $fontAltBaslik $altyazi.ForeColor = $script:tema.YaziSoluk $altyazi.AutoSize = $true $splash.Controls.Add($altyazi) $splash.Show() $altyazi.Left = [int](($splash.Width - $altyazi.PreferredWidth) / 2) $altyazi.Top = 168 for ($o = 0.0; $o -le 1.0; $o += 0.09) { $splash.Opacity = [Math]::Min(1.0, $o) Start-Sleep -Milliseconds 12 [System.Windows.Forms.Application]::DoEvents() } $splash.Opacity = 1 Start-Sleep -Milliseconds 950 [System.Windows.Forms.Application]::DoEvents() for ($o = 1.0; $o -ge 0.0; $o -= 0.09) { $splash.Opacity = [Math]::Max(0.0, $o) Start-Sleep -Milliseconds 10 [System.Windows.Forms.Application]::DoEvents() } $splash.Close() $splash.Dispose() } Goster-SplashEkrani # ---- Program listesi ---- $programlar = @( [PSCustomObject]@{ Ad = "NVIDIA App (sürücü + performans/optimizasyon)"; WingetId = "XP8CLZL93F5Z4P"; Kaynak = "msstore"; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "NVIDIA Control Panel (renk/3D/çoklu monitör ayarları)"; WingetId = "9NF8H0H7WMLT"; Kaynak = "msstore"; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Bulk Crap Uninstaller"; WingetId = "Klocman.BulkCrapUninstaller"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Brave Browser"; WingetId = "Brave.Brave"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "CapCut"; WingetId = "ByteDance.CapCut"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Discord"; WingetId = "Discord.Discord"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "EarTrumpet"; WingetId = "File-New-Project.EarTrumpet"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Epic Games Launcher"; WingetId = "EpicGames.EpicGamesLauncher"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Everything"; WingetId = "voidtools.Everything"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Flow Launcher"; WingetId = "Flow-Launcher.Flow-Launcher"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "HyperX NGENUITY"; WingetId = "9P1TBXR6QDCX"; Kaynak = "msstore"; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "OBS Studio"; WingetId = "OBSProject.OBSStudio"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Overwolf (platform - Tracker ve Insights Capture için gerekli)"; WingetId = $null; Kaynak = $null; DirectUrl = "https://download.overwolf.com/install/Download?utm_content=new-light&utm_source=web_app_store"; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Insights Capture"; WingetId = $null; Kaynak = $null; DirectUrl = "https://download.overwolf.com/install/Download?Name=Insights_Capture&ExtensionId=fljbachcphmmjflapcokloinfikfpdhepkobcbco&Channel=web_dl_btn"; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Riot Client / VALORANT (EU sunucusu)"; WingetId = $null; Kaynak = $null; DirectUrl = "https://valorant.secure.dyn.riotcdn.net/channels/public/x/installer/current/live.live.eu.exe"; ManuelUrl = $null } [PSCustomObject]@{ Ad = "LocalSend"; WingetId = "LocalSend.LocalSend"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "MicMute (mikrofonu kısayolla sessize al)"; WingetId = $null; Kaynak = $null; DirectUrl = "https://github.com/Anc813/MicMute/releases/download/0.0.8/MicMute.exe"; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Microsoft PowerToys"; WingetId = "Microsoft.PowerToys"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Mullvad Browser"; WingetId = "MullvadVPN.MullvadBrowser"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Notepad++"; WingetId = "Notepad++.Notepad++"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Pinokio"; WingetId = "pinokiocomputer.pinokio"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "ProtonVPN"; WingetId = "Proton.ProtonVPN"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Lightshot"; WingetId = "Skillbrains.Lightshot"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Steam"; WingetId = "Valve.Steam"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Valorant Tracker"; WingetId = $null; Kaynak = $null; DirectUrl = "https://download.overwolf.com/install/Download?PartnerId=3973&ExtentionId=ipmlnnogholfmdmenfijjifldcpjoecappfccceh"; ManuelUrl = $null } [PSCustomObject]@{ Ad = "Visual Studio 2022 Community"; WingetId = "Microsoft.VisualStudio.2022.Community"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "VLC"; WingetId = "VideoLAN.VLC"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "WhatsApp"; WingetId = "9NKSQGP7F2NH"; Kaynak = "msstore"; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "WinDirStat"; WingetId = "WinDirStat.WinDirStat"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } [PSCustomObject]@{ Ad = "WinRAR"; WingetId = "RARLab.WinRAR"; Kaynak = $null; DirectUrl = $null; ManuelUrl = $null } ) # Taşınabilir programlar (indirilip kalıcı klasöre konur, başlangıca eklenir) foreach ($p in $programlar) { $p | Add-Member -NotePropertyName PortableExe -NotePropertyValue $false } foreach ($p in $programlar) { $p | Add-Member -NotePropertyName PortableKlasor -NotePropertyValue $null } ($programlar | Where-Object { $_.Ad -like "MicMute*" }) | ForEach-Object { $_.PortableExe = $true; $_.PortableKlasor = "MicMute" } foreach ($p in $programlar) { if ($p.WingetId) { $p | Add-Member -NotePropertyName Etiket -NotePropertyValue $p.Ad } elseif ($p.DirectUrl -and $p.PortableExe) { $p | Add-Member -NotePropertyName Etiket -NotePropertyValue ($p.Ad + " · indir + çalıştır · başlangıç uygulamalarına eklenir") } elseif ($p.DirectUrl) { $p | Add-Member -NotePropertyName Etiket -NotePropertyValue ($p.Ad + " · indir + çalıştır") } else { $p | Add-Member -NotePropertyName Etiket -NotePropertyValue ($p.Ad + " · manuel link açılır") } } # Kurulum önceliği (Overwolf önce, ona bağlı programlar sonra) foreach ($p in $programlar) { $p | Add-Member -NotePropertyName Oncelik -NotePropertyValue 1 } foreach ($p in $programlar) { $p | Add-Member -NotePropertyName Secili -NotePropertyValue $true } foreach ($p in $programlar) { $p | Add-Member -NotePropertyName Etkilesimli -NotePropertyValue $false } ($programlar | Where-Object { $_.Ad -like "Overwolf*" }) | ForEach-Object { $_.Oncelik = 0 } ($programlar | Where-Object { $_.Ad -eq "Insights Capture" -or $_.Ad -eq "Valorant Tracker" }) | ForEach-Object { $_.Oncelik = 2 } # ---- Kategori ataması ---- $kategoriHaritasi = @{ "Tarayıcı" = @("Brave*", "Mullvad*") "Oyun" = @("Epic*", "Overwolf*", "Insights*", "Riot*", "Steam*", "Valorant*") "İletişim" = @("Discord*", "WhatsApp*") "Multimedya" = @("CapCut*", "OBS*", "VLC*") "Geliştirme" = @("Notepad++*", "Pinokio*", "Visual Studio*") "Sistem Araçları" = @("NVIDIA*", "Bulk*", "EarTrumpet*", "Everything*", "Flow*", "HyperX*", "LocalSend*", "MicMute*", "Microsoft PowerToys*", "ProtonVPN*", "Lightshot*", "WinDirStat*", "WinRAR*") } foreach ($p in $programlar) { $p | Add-Member -NotePropertyName Kategori -NotePropertyValue "Diğer" } foreach ($p in $programlar) { foreach ($kat in $kategoriHaritasi.Keys) { foreach ($desen in $kategoriHaritasi[$kat]) { if ($p.Ad -like $desen) { $p.Kategori = $kat } } } } $programlar = $programlar | Sort-Object Ad $script:DurumMap = [Hashtable]::Synchronized(@{}) # ================= ANA PENCERE ================= $FORM_GENISLIK = 780 $calisma = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea $FORM_YUKSEKLIK = [Math]::Min(760, $calisma.Height - 20) $form = New-Object System.Windows.Forms.Form $form.Text = "Format Sonrası Program Kurulumu" $form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen $form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None # ÖNEMLİ: boyutu FormBorderStyle'dan SONRA ve ClientSize olarak ver (kayma sorununun çözümü) $form.ClientSize = New-Object System.Drawing.Size($FORM_GENISLIK, $FORM_YUKSEKLIK) $form.BackColor = $script:tema.Arkaplan $form.Font = $fontNormal $form.ForeColor = $script:tema.Yazi $form.Icon = $script:uygulamaIkonu $form.Opacity = 0 # ---- Özel başlık çubuğu ---- $BASLIK_YUKSEKLIK = 56 $headerPanel = New-Object System.Windows.Forms.Panel $headerPanel.Dock = [System.Windows.Forms.DockStyle]::Top $headerPanel.Height = $BASLIK_YUKSEKLIK $headerPanel.BackColor = $script:tema.Panel $form.Controls.Add($headerPanel) $picIkonBaslik = New-Object System.Windows.Forms.PictureBox $picIkonBaslik.Image = $script:uygulamaIkonu.ToBitmap() $picIkonBaslik.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom $picIkonBaslik.Width = 28; $picIkonBaslik.Height = 28 $picIkonBaslik.Left = 18; $picIkonBaslik.Top = 14 $headerPanel.Controls.Add($picIkonBaslik) $baslikLbl = New-Object System.Windows.Forms.Label $baslikLbl.Text = "Format Sonrası Program Kurulumu" $baslikLbl.Font = $fontBaslik $baslikLbl.ForeColor = $script:tema.Yazi $baslikLbl.AutoSize = $true $baslikLbl.Left = 56 $baslikLbl.Top = 8 $headerPanel.Controls.Add($baslikLbl) $altBaslikLbl = New-Object System.Windows.Forms.Label $altBaslikLbl.Text = "bit.ly/RogeRsen" $altBaslikLbl.Font = $fontAltBaslik $altBaslikLbl.ForeColor = $script:tema.YaziSoluk $altBaslikLbl.AutoSize = $true $altBaslikLbl.Left = 57 $altBaslikLbl.Top = 32 $headerPanel.Controls.Add($altBaslikLbl) # ---- Pencereyi başlık çubuğundan sürükleme ---- # NOT: .GetNewClosure() KULLANILMIYOR; $script:surukleBaslangic üç olay arasında ortak canlı değişken. $script:surukleBaslangic = $null $surukleMouseDown = { $script:surukleBaslangic = New-Object System.Drawing.Point($_.X, $_.Y) } $surukleMouseMove = { if ($_.Button -eq [System.Windows.Forms.MouseButtons]::Left -and $script:surukleBaslangic) { $form.Left += ($_.X - $script:surukleBaslangic.X) $form.Top += ($_.Y - $script:surukleBaslangic.Y) } } $surukleMouseUp = { $script:surukleBaslangic = $null } foreach ($ctrl in @($headerPanel, $baslikLbl, $altBaslikLbl, $picIkonBaslik)) { $ctrl.Add_MouseDown($surukleMouseDown) $ctrl.Add_MouseMove($surukleMouseMove) $ctrl.Add_MouseUp($surukleMouseUp) } # ---- Başlık çubuğu düğmeleri: font yerine GDI+ ile çizilir (emoji/font sorunu yok) ---- function New-BaslikButonu([string]$tur) { $lbl = New-Object System.Windows.Forms.Label $lbl.Text = "" $lbl.Tag = $tur $lbl.AutoSize = $false $lbl.Width = 46 $lbl.Height = $BASLIK_YUKSEKLIK $lbl.Cursor = [System.Windows.Forms.Cursors]::Hand $lbl.BackColor = $script:tema.Panel Add-Member -InputObject $lbl -NotePropertyName Hover -NotePropertyValue $false $lbl.Add_Paint({ param($s, $e) $g = $e.Graphics $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias if ($s.Hover) { if ($s.Tag -eq "kapat") { $renk = [System.Drawing.Color]::White } else { $renk = $script:tema.Yazi } } else { $renk = $script:tema.YaziSoluk } $kalem = New-Object System.Drawing.Pen($renk, 1.5) $fir = New-Object System.Drawing.SolidBrush($renk) $cx = $s.Width / 2.0 $cy = $s.Height / 2.0 switch ($s.Tag) { "kapat" { $g.DrawLine($kalem, $cx - 5, $cy - 5, $cx + 5, $cy + 5) $g.DrawLine($kalem, $cx - 5, $cy + 5, $cx + 5, $cy - 5) } "kucult" { $g.DrawLine($kalem, $cx - 5, $cy, $cx + 5, $cy) } "hakkinda" { $g.DrawEllipse($kalem, $cx - 8, $cy - 8, 16, 16) $g.DrawLine($kalem, $cx, $cy - 1, $cx, $cy + 4) $g.FillEllipse($fir, $cx - 1.3, $cy - 4.8, 2.6, 2.6) } "tema" { if ($script:temaAdi -eq "Koyu") { # ay: dolu daire + arka plan renginde kaydırılmış daire $g.FillEllipse($fir, $cx - 7, $cy - 7, 14, 14) $arka = New-Object System.Drawing.SolidBrush($s.BackColor) $g.FillEllipse($arka, $cx - 2, $cy - 9, 13, 13) $arka.Dispose() } else { # güneş: daire + 8 ışın $g.DrawEllipse($kalem, $cx - 4, $cy - 4, 8, 8) for ($i = 0; $i -lt 8; $i++) { $a = $i * [Math]::PI / 4 $g.DrawLine($kalem, $cx + [Math]::Cos($a) * 7, $cy + [Math]::Sin($a) * 7, $cx + [Math]::Cos($a) * 9.5, $cy + [Math]::Sin($a) * 9.5) } } } } $kalem.Dispose(); $fir.Dispose() }) $lbl.Add_MouseEnter({ $this.Hover = $true if ($this.Tag -eq "kapat") { $this.BackColor = [System.Drawing.Color]::FromArgb(232, 17, 35) } else { $this.BackColor = $script:tema.Kenar } $this.Invalidate() }) $lbl.Add_MouseLeave({ $this.Hover = $false $this.BackColor = $script:tema.Panel $this.Invalidate() }) return $lbl } $simgeGenislik = 46 $lblKapat = New-BaslikButonu "kapat" $lblKucult = New-BaslikButonu "kucult" $lblTema = New-BaslikButonu "tema" $lblHakkinda = New-BaslikButonu "hakkinda" foreach ($b in @($lblKapat, $lblKucult, $lblTema, $lblHakkinda)) { $headerPanel.Controls.Add($b) } $lblHakkinda.Add_Click({ [System.Windows.Forms.MessageBox]::Show( "RogeRsen - Format Sonrası Program Kurulumu`nsürüm 4.2`nbit.ly/RogeRsen", "Hakkında") | Out-Null }) # ---- Sistem tray simgesi ---- $trayIcon = New-Object System.Windows.Forms.NotifyIcon $trayIcon.Icon = $script:uygulamaIkonu $trayIcon.Text = "RogeRsen - Program Kurulumu" $trayIcon.Visible = $false $trayMenu = New-Object System.Windows.Forms.ContextMenuStrip [void]$trayMenu.Items.Add("Göster", $null, { $form.Show(); $form.WindowState = [System.Windows.Forms.FormWindowState]::Normal; $form.Activate() $trayIcon.Visible = $false }) [void]$trayMenu.Items.Add("Çıkış", $null, { $trayIcon.Visible = $false $script:kapatOnaylandi = $true $form.Close() }) $trayIcon.ContextMenuStrip = $trayMenu $trayIcon.Add_MouseDoubleClick({ $form.Show(); $form.WindowState = [System.Windows.Forms.FormWindowState]::Normal; $form.Activate() $trayIcon.Visible = $false }) $lblKucult.Add_Click({ $form.Hide() $trayIcon.Visible = $true $trayIcon.ShowBalloonTip(1500, "RogeRsen", "Kurulum arka planda devam ediyor. Geri açmak için çift tıkla.", [System.Windows.Forms.ToolTipIcon]::Info) }) # ---- Kapatma: "Güle güle" fade-out animasyonu ---- $script:kapatOnaylandi = $false $script:kapaniyor = $false function Show-GuleGule { $overlay = New-Object System.Windows.Forms.Panel $overlay.Dock = [System.Windows.Forms.DockStyle]::Fill $overlay.BackColor = $script:tema.Arkaplan $form.Controls.Add($overlay) $overlay.BringToFront() $lblMetin = New-Object System.Windows.Forms.Label $lblMetin.Text = "Güle güle!" $lblMetin.Font = New-Object System.Drawing.Font("Segoe UI Semibold", 24) $lblMetin.ForeColor = $script:tema.Vurgu $lblMetin.AutoSize = $true $overlay.Controls.Add($lblMetin) $lblEl = New-Object System.Windows.Forms.Label $lblEl.Text = "👋" $lblEl.Font = $fontEmojiBuyuk $lblEl.ForeColor = $script:tema.Vurgu $lblEl.AutoSize = $true $overlay.Controls.Add($lblEl) $toplamGenislik = $lblMetin.PreferredWidth + 10 + $lblEl.PreferredWidth $solBaslangic = [int](($overlay.Width - $toplamGenislik) / 2) $lblMetin.Left = $solBaslangic $lblMetin.Top = [int](($overlay.Height - $lblMetin.PreferredHeight) / 2) $lblEl.Left = $lblMetin.Left + $lblMetin.PreferredWidth + 10 $lblEl.Top = $lblMetin.Top - 4 # Timer olayları fonksiyon bittikten sonra çalışır; fonksiyon-yerel değişkenler artık # görünmez. Bu yüzden olayın kendi $s parametresi + $script: değişkenleri kullanılıyor. $script:bekleTimer = New-Object System.Windows.Forms.Timer $script:bekleTimer.Interval = 850 $script:bekleTimer.Add_Tick({ param($s, $e) $s.Stop(); $s.Dispose() $script:fadeTimer = New-Object System.Windows.Forms.Timer $script:fadeTimer.Interval = 25 $script:fadeTimer.Add_Tick({ param($s2, $e2) $form.Opacity = [Math]::Max(0, $form.Opacity - 0.09) if ($form.Opacity -le 0.02) { $s2.Stop(); $s2.Dispose() $script:kapatOnaylandi = $true $form.Close() } }) $script:fadeTimer.Start() }) $script:bekleTimer.Start() } $form.Add_FormClosing({ param($s, $e) if (-not $script:kapatOnaylandi) { $e.Cancel = $true if (-not $script:kapaniyor) { $script:kapaniyor = $true; Show-GuleGule } } else { $trayIcon.Visible = $false $trayIcon.Dispose() } }) $lblKapat.Add_Click({ $form.Close() }) # ---- Yuvarlak panel çizimi (arama kutusu, tablo ve günlük kutusu ortak kullanır) ---- # Dolgu + kenar GDI+ AntiAlias ile çizilir; panelin BackColor'ı form zemini rengidir. $script:aramaOdak = $false $panelBoya = { param($s, $e) $g = $e.Graphics $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias $g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality if ($s.Name -eq "log") { $dolgu = $script:tema.Log } else { $dolgu = $script:tema.Panel } $yolD = New-YuvarlakYol $s.Width $s.Height 8 $fir = New-Object System.Drawing.SolidBrush($dolgu) $g.FillPath($fir, $yolD) $fir.Dispose(); $yolD.Dispose() if ($s.Name -eq "arama" -and $script:aramaOdak) { $renkB = $script:tema.Vurgu } else { $renkB = $script:tema.Kenar } $kalemB = New-Object System.Drawing.Pen($renkB, 1) $yol = New-YuvarlakYol ($s.Width - 1) ($s.Height - 1) 8 $g.DrawPath($kalemB, $yol) $kalemB.Dispose(); $yol.Dispose() if ($s.Name -eq "arama") { $kalemI = New-Object System.Drawing.Pen($script:tema.YaziSoluk, 1.6) $g.DrawEllipse($kalemI, 11, 9, 10, 10) $g.DrawLine($kalemI, 19, 17, 23, 21) $kalemI.Dispose() } } # ---- Arama kutusu ---- $txtAramaPlaceholder = "Ara... (örn: ins)" $aramaPanel = New-Object System.Windows.Forms.Panel $aramaPanel.Name = "arama" $aramaPanel.BackColor = $script:tema.Arkaplan Set-DoubleBuffer $aramaPanel $aramaPanel.Add_Paint($panelBoya) $form.Controls.Add($aramaPanel) $txtArama = New-Object System.Windows.Forms.TextBox $txtArama.BorderStyle = [System.Windows.Forms.BorderStyle]::None $txtArama.BackColor = $script:tema.Panel $txtArama.ForeColor = $script:tema.YaziSoluk $txtArama.Font = $fontNormal $txtArama.Text = $txtAramaPlaceholder $aramaPanel.Controls.Add($txtArama) # ---- Kategori filtresi: tema uyumlu "chip"ler ---- $script:secilenKategori = "Tümü" $script:chipler = @() function Chipleri-Boya { foreach ($c in $script:chipler) { $c.BackColor = $script:tema.Arkaplan if ($c.Text -eq $script:secilenKategori) { $c.Dolgu = $script:tema.Vurgu $c.ForeColor = [System.Drawing.Color]::White } else { $c.Dolgu = $script:tema.Panel $c.ForeColor = $script:tema.YaziSoluk } $c.Invalidate() } } $kategoriler = @("Tümü") + @($programlar | Select-Object -ExpandProperty Kategori -Unique | Sort-Object) foreach ($k in $kategoriler) { $chip = New-YuvarlakLabel $k $fontButon 13 $script:tema.Panel $chip.Width = [System.Windows.Forms.TextRenderer]::MeasureText($k, $fontButon).Width + 22 $chip.Height = 26 $chip.Add_Click({ $script:secilenKategori = $this.Text Chipleri-Boya & $script:mevcutFiltreOku }) $chip.Add_MouseEnter({ if ($this.Text -ne $script:secilenKategori) { $this.Dolgu = $script:tema.Kenar; $this.Invalidate() } }) $chip.Add_MouseLeave({ Chipleri-Boya }) $form.Controls.Add($chip) $script:chipler += $chip } # ---- Program tablosu (yuvarlak kenarlı panelin içinde) ---- $tabloPanel = New-Object System.Windows.Forms.Panel $tabloPanel.Name = "tablo" $tabloPanel.BackColor = $script:tema.Arkaplan $tabloPanel.Padding = New-Object System.Windows.Forms.Padding(4) Set-DoubleBuffer $tabloPanel $tabloPanel.Add_Paint($panelBoya) $form.Controls.Add($tabloPanel) $dgv = New-Object System.Windows.Forms.DataGridView $dgv.Dock = [System.Windows.Forms.DockStyle]::Fill Set-DoubleBuffer $dgv $dgv.BackgroundColor = $script:tema.Panel $dgv.BorderStyle = [System.Windows.Forms.BorderStyle]::None $dgv.GridColor = $script:tema.PanelKoyu $dgv.Font = $fontNormal $dgv.AutoGenerateColumns = $false $dgv.AllowUserToAddRows = $false $dgv.AllowUserToDeleteRows = $false $dgv.AllowUserToResizeRows = $false $dgv.AllowUserToResizeColumns = $false $dgv.RowHeadersVisible = $false $dgv.MultiSelect = $false $dgv.SelectionMode = [System.Windows.Forms.DataGridViewSelectionMode]::CellSelect $dgv.EditMode = [System.Windows.Forms.DataGridViewEditMode]::EditOnEnter $dgv.EnableHeadersVisualStyles = $false $dgv.RowTemplate.Height = 26 $dgv.ColumnHeadersHeight = 28 $dgv.ColumnHeadersHeightSizeMode = [System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode]::DisableResizing $dgv.ColumnHeadersDefaultCellStyle.BackColor = $script:tema.Panel $dgv.ColumnHeadersDefaultCellStyle.ForeColor = $script:tema.YaziSoluk $dgv.ColumnHeadersDefaultCellStyle.SelectionBackColor = $script:tema.Panel $dgv.ColumnHeadersDefaultCellStyle.Font = $fontAltBaslik $dgv.ColumnHeadersBorderStyle = [System.Windows.Forms.DataGridViewHeaderBorderStyle]::None $dgv.CellBorderStyle = [System.Windows.Forms.DataGridViewCellBorderStyle]::None $dgv.DefaultCellStyle.BackColor = $script:tema.Panel $dgv.DefaultCellStyle.ForeColor = $script:tema.Yazi $dgv.DefaultCellStyle.SelectionBackColor = $script:tema.Kenar $dgv.DefaultCellStyle.SelectionForeColor = $script:tema.Yazi $dgv.RowsDefaultCellStyle.BackColor = $script:tema.Panel $dgv.AlternatingRowsDefaultCellStyle.BackColor = $script:tema.Panel $colKur = New-Object System.Windows.Forms.DataGridViewCheckBoxColumn $colKur.Name = "Kur"; $colKur.HeaderText = "Kur"; $colKur.Width = 44 $colKur.Resizable = [System.Windows.Forms.DataGridViewTriState]::False [void]$dgv.Columns.Add($colKur) $colProgram = New-Object System.Windows.Forms.DataGridViewTextBoxColumn $colProgram.Name = "Program"; $colProgram.HeaderText = "Program"; $colProgram.ReadOnly = $true $colProgram.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::Fill [void]$dgv.Columns.Add($colProgram) $colKategori = New-Object System.Windows.Forms.DataGridViewTextBoxColumn $colKategori.Name = "Kategori"; $colKategori.HeaderText = "Kategori"; $colKategori.ReadOnly = $true $colKategori.Width = 120 [void]$dgv.Columns.Add($colKategori) $colEtkilesimli = New-Object System.Windows.Forms.DataGridViewCheckBoxColumn $colEtkilesimli.Name = "Etkilesimli"; $colEtkilesimli.HeaderText = "Etkileşimli"; $colEtkilesimli.Width = 86 $colEtkilesimli.Resizable = [System.Windows.Forms.DataGridViewTriState]::False [void]$dgv.Columns.Add($colEtkilesimli) $colDurum = New-Object System.Windows.Forms.DataGridViewTextBoxColumn $colDurum.Name = "Durum"; $colDurum.HeaderText = "Durum"; $colDurum.ReadOnly = $true $colDurum.Width = 60 $colDurum.DefaultCellStyle.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleCenter $colDurum.DefaultCellStyle.Font = $fontDurum [void]$dgv.Columns.Add($colDurum) $tabloPanel.Controls.Add($dgv) $ipucuLbl = New-Object System.Windows.Forms.Label $ipucuLbl.Text = "İpucu: bir programın kurulum ekranını kendin tamamlamak istersen ""Etkileşimli""yi işaretle." $ipucuLbl.Font = $fontAltBaslik $ipucuLbl.ForeColor = $script:tema.YaziSoluk $ipucuLbl.AutoSize = $false $form.Controls.Add($ipucuLbl) $script:goruntulenenler = @() $script:tabloDolduruluyor = $false function Listeyi-Guncelle([string]$filtre, [string]$kategoriFiltre, [bool]$scrollKoru = $false) { $script:tabloDolduruluyor = $true $ilkSatir = -1 if ($scrollKoru -and $dgv.RowCount -gt 0) { try { $ilkSatir = $dgv.FirstDisplayedScrollingRowIndex } catch { $ilkSatir = -1 } } $dgv.Rows.Clear() $yeni = @() $f = $filtre.Trim() foreach ($p in $programlar) { # tr-TR kültüründe ToLower() "I" -> "ı" yaptığı için "ins" -> "Insights" eşleşmiyordu. $metinUyuyor = [string]::IsNullOrWhiteSpace($f) -or ($p.Ad.IndexOf($f, [System.StringComparison]::OrdinalIgnoreCase) -ge 0) $katUyuyor = ([string]::IsNullOrWhiteSpace($kategoriFiltre) -or $kategoriFiltre -eq "Tümü" -or $p.Kategori -eq $kategoriFiltre) if ($metinUyuyor -and $katUyuyor) { $durumSimge = "" if ($script:DurumMap.ContainsKey($p.Ad)) { $durumSimge = $script:DurumMap[$p.Ad] } $rowIndex = $dgv.Rows.Add($p.Secili, $p.Etiket, $p.Kategori, $p.Etkilesimli, $durumSimge) $row = $dgv.Rows[$rowIndex] if (-not $p.WingetId) { $row.Cells["Etkilesimli"].Value = $false $row.Cells["Etkilesimli"].ReadOnly = $true $row.Cells["Etkilesimli"].Style.ForeColor = $script:tema.YaziPasif $row.Cells["Etkilesimli"].ToolTipText = "Bu program winget ile kurulmuyor, etkileşimli/sessiz ayrımı yok." } switch ($durumSimge) { "✓" { $row.Cells["Durum"].Style.ForeColor = [System.Drawing.Color]::FromArgb(80, 200, 120) } "✗" { $row.Cells["Durum"].Style.ForeColor = [System.Drawing.Color]::FromArgb(235, 90, 90) } "⏳" { $row.Cells["Durum"].Style.ForeColor = [System.Drawing.Color]::FromArgb(240, 180, 60) } } $row.Cells["Program"].ToolTipText = $p.Kategori + " · " + $(if ($p.WingetId) { "winget: " + $p.WingetId } else { "doğrudan indirme" }) $yeni += $p } } $script:goruntulenenler = $yeni if ($ilkSatir -ge 0 -and $ilkSatir -lt $dgv.RowCount) { try { $dgv.FirstDisplayedScrollingRowIndex = $ilkSatir } catch {} } try { $dgv.ClearSelection(); $dgv.CurrentCell = $null } catch {} $script:tabloDolduruluyor = $false } $script:mevcutFiltreOku = { param([bool]$koru = $false) $f = if ($txtArama.Text -eq $txtAramaPlaceholder) { "" } else { $txtArama.Text } Listeyi-Guncelle $f $script:secilenKategori $koru } $txtArama.Add_GotFocus({ if ($txtArama.Text -eq $txtAramaPlaceholder) { $txtArama.Text = ""; $txtArama.ForeColor = $script:tema.Yazi } $script:aramaOdak = $true; $aramaPanel.Invalidate() }) $txtArama.Add_LostFocus({ if ([string]::IsNullOrWhiteSpace($txtArama.Text)) { $txtArama.Text = $txtAramaPlaceholder; $txtArama.ForeColor = $script:tema.YaziSoluk } $script:aramaOdak = $false; $aramaPanel.Invalidate() }) $txtArama.Add_TextChanged({ & $script:mevcutFiltreOku }) # Panelin boş kısmına tıklayınca da kutuya odaklan $aramaPanel.Add_Click({ $txtArama.Focus() }) $dgv.Add_CurrentCellDirtyStateChanged({ if ($dgv.IsCurrentCellDirty) { $dgv.CommitEdit([System.Windows.Forms.DataGridViewDataErrorContexts]::Commit) } }) $dgv.Add_CellValueChanged({ param($s, $e) if ($script:tabloDolduruluyor) { return } if ($e.RowIndex -lt 0 -or $e.RowIndex -ge $script:goruntulenenler.Count) { return } $p = $script:goruntulenenler[$e.RowIndex] $colAdi = $dgv.Columns[$e.ColumnIndex].Name if ($colAdi -eq "Kur") { $p.Secili = [bool]$dgv.Rows[$e.RowIndex].Cells["Kur"].Value } elseif ($colAdi -eq "Etkilesimli" -and $p.WingetId) { $p.Etkilesimli = [bool]$dgv.Rows[$e.RowIndex].Cells["Etkilesimli"].Value } }) # ---- Butonlar ---- $btnTumunuSec = New-YuvarlakLabel "Tümünü Seç" $fontButon 8 $script:tema.ButonAlt Animate-Buton $btnTumunuSec $script:tema.ButonAlt $script:tema.ButonAltHover $btnTumunuSec.ForeColor = $script:tema.Yazi $btnTumunuSec.Add_Click({ foreach ($p in $programlar) { $p.Secili = $true } & $script:mevcutFiltreOku }) $form.Controls.Add($btnTumunuSec) $btnTumunuKaldir = New-YuvarlakLabel "Tümünü Kaldır" $fontButon 8 $script:tema.ButonAlt Animate-Buton $btnTumunuKaldir $script:tema.ButonAlt $script:tema.ButonAltHover $btnTumunuKaldir.ForeColor = $script:tema.Yazi $btnTumunuKaldir.Add_Click({ foreach ($p in $programlar) { $p.Secili = $false } & $script:mevcutFiltreOku }) $form.Controls.Add($btnTumunuKaldir) $btnKur = New-YuvarlakLabel "Seçilenleri Kur" $fontButon 8 $script:tema.Vurgu Animate-Buton $btnKur $script:tema.Vurgu $script:tema.VurguKoyu $form.Controls.Add($btnKur) # ---- Genel ilerleme çubuğu ---- $progressBar = New-Object System.Windows.Forms.ProgressBar $progressBar.Style = [System.Windows.Forms.ProgressBarStyle]::Continuous $progressBar.Minimum = 0; $progressBar.Maximum = 100; $progressBar.Value = 0 $progressBar.ForeColor = $script:tema.Vurgu $progressBar.BackColor = $script:tema.Kenar $form.Controls.Add($progressBar) $lblProgress = New-Object System.Windows.Forms.Label $lblProgress.Text = "Hazır" $lblProgress.Font = $fontAltBaslik $lblProgress.ForeColor = $script:tema.YaziSoluk $lblProgress.AutoSize = $true $form.Controls.Add($lblProgress) # ---- Log kutusu ---- $logBaslikLbl = New-Object System.Windows.Forms.Label $logBaslikLbl.Text = "GÜNLÜK" $logBaslikLbl.Font = $fontAltBaslik $logBaslikLbl.ForeColor = $script:tema.YaziSoluk $logBaslikLbl.AutoSize = $true $form.Controls.Add($logBaslikLbl) $logPanel = New-Object System.Windows.Forms.Panel $logPanel.Name = "log" $logPanel.BackColor = $script:tema.Arkaplan $logPanel.Padding = New-Object System.Windows.Forms.Padding(10, 8, 8, 8) Set-DoubleBuffer $logPanel $logPanel.Add_Paint($panelBoya) $form.Controls.Add($logPanel) $log = New-Object System.Windows.Forms.TextBox $log.Dock = [System.Windows.Forms.DockStyle]::Fill $log.Multiline = $true $log.ScrollBars = [System.Windows.Forms.ScrollBars]::Vertical $log.ReadOnly = $true $log.BackColor = $script:tema.Log $log.ForeColor = $script:tema.LogYazi $log.BorderStyle = [System.Windows.Forms.BorderStyle]::None $log.Font = $fontLog $logPanel.Controls.Add($log) # ---- Yerleşim: tüm kontroller ClientSize'a göre hesaplanır (kayma/taşma olmaz) ---- function Yerlesim-Uygula { $W = $form.ClientSize.Width $H = $form.ClientSize.Height $M = 20 $CW = $W - 2 * $M # Başlık düğmeleri: sağdan sola, bitişik, tam başlık yüksekliğinde $x = $W foreach ($b in @($lblKapat, $lblKucult, $lblTema, $lblHakkinda)) { $x -= $simgeGenislik $b.SetBounds($x, 0, $simgeGenislik, $BASLIK_YUKSEKLIK) } # Arama kutusu $aramaPanel.SetBounds($M, 72, $CW, 32) $txtArama.Left = 38 $txtArama.Width = $CW - 38 - 12 $txtArama.Top = [int]((32 - $txtArama.Height) / 2) # Kategori chip'leri $cx = $M foreach ($c in $script:chipler) { $c.SetBounds($cx, 112, $c.Width, 26) $cx += $c.Width + 8 } # Alttan yukarı doğru yığın $logH = 140 $logTop = $H - 16 - $logH $logBaslikTop = $logTop - 20 $lblProgTop = $logBaslikTop - 22 $barTop = $lblProgTop - 16 $btnTop = $barTop - 14 - 36 $ipTop = $btnTop - 24 $dgvTop = 150 $dgvH = ($ipTop - 4) - $dgvTop $tabloPanel.SetBounds($M, $dgvTop, $CW, $dgvH) $ipucuLbl.SetBounds($M, $ipTop, $CW, 18) $btnTumunuSec.SetBounds($M, $btnTop, 130, 36) $btnTumunuKaldir.SetBounds($M + 138, $btnTop, 130, 36) $btnKur.SetBounds($W - $M - 170, $btnTop, 170, 36) $progressBar.SetBounds($M, $barTop, $CW, 10) $lblProgress.Left = $M; $lblProgress.Top = $lblProgTop $logBaslikLbl.Left = $M; $logBaslikLbl.Top = $logBaslikTop $logPanel.SetBounds($M, $logTop, $CW, $logH) } # ---- Tema uygulama ---- function Uygula-Tema { $t = $script:tema $form.BackColor = $t.Arkaplan $headerPanel.BackColor = $t.Panel $baslikLbl.ForeColor = $t.Yazi $altBaslikLbl.ForeColor = $t.YaziSoluk foreach ($b in @($lblKapat, $lblKucult, $lblTema, $lblHakkinda)) { $b.BackColor = $t.Panel; $b.Hover = $false; $b.Invalidate() } $aramaPanel.BackColor = $t.Arkaplan $txtArama.BackColor = $t.Panel if ($txtArama.Text -ne $txtAramaPlaceholder) { $txtArama.ForeColor = $t.Yazi } else { $txtArama.ForeColor = $t.YaziSoluk } $aramaPanel.Invalidate() Chipleri-Boya $dgv.BackgroundColor = $t.Panel $dgv.GridColor = $t.PanelKoyu $dgv.ColumnHeadersDefaultCellStyle.BackColor = $t.Panel $dgv.ColumnHeadersDefaultCellStyle.ForeColor = $t.YaziSoluk $dgv.ColumnHeadersDefaultCellStyle.SelectionBackColor = $t.Panel $dgv.DefaultCellStyle.BackColor = $t.Panel $dgv.DefaultCellStyle.ForeColor = $t.Yazi $dgv.DefaultCellStyle.SelectionBackColor = $t.Kenar $dgv.DefaultCellStyle.SelectionForeColor = $t.Yazi $dgv.RowsDefaultCellStyle.BackColor = $t.Panel $dgv.AlternatingRowsDefaultCellStyle.BackColor = $t.Panel foreach ($b in @($btnTumunuSec, $btnTumunuKaldir)) { $b.Tag.Normal = $t.ButonAlt; $b.Tag.Hover = $t.ButonAltHover; $b.Tag.Hedef = $t.ButonAlt $b.BackColor = $t.Arkaplan; $b.Dolgu = $t.ButonAlt; $b.ForeColor = $t.Yazi; $b.Invalidate() } $btnKur.Tag.Normal = $t.Vurgu; $btnKur.Tag.Hover = $t.VurguKoyu; $btnKur.Tag.Hedef = $t.Vurgu $btnKur.BackColor = $t.Arkaplan; $btnKur.Dolgu = $t.Vurgu; $btnKur.Invalidate() $tabloPanel.BackColor = $t.Arkaplan; $tabloPanel.Invalidate() $ipucuLbl.ForeColor = $t.YaziSoluk $lblProgress.ForeColor = $t.YaziSoluk $progressBar.ForeColor = $t.Vurgu $progressBar.BackColor = $t.Kenar $logBaslikLbl.ForeColor = $t.YaziSoluk $logPanel.BackColor = $t.Arkaplan $logPanel.Invalidate() $log.BackColor = $t.Log $log.ForeColor = $t.LogYazi & $script:mevcutFiltreOku $true # satırları yeni temayla yeniden oluştur } $lblTema.Add_Click({ if ($script:temaAdi -eq "Koyu") { $script:tema = $temaAcik; $script:temaAdi = "Acik" } else { $script:tema = $temaKoyu; $script:temaAdi = "Koyu" } Uygula-Tema $lblTema.Invalidate() }) # ---- Pencere yüklenirken: yuvarlak köşe, ilerleme çubuğu teması, yerleşim ---- $form.Add_Load({ # Win11: DWM ile yerel (antialias'lı) yuvarlak köşe. Olmazsa Region'a düş (Win10). $dwmTamam = $false try { if ([Environment]::OSVersion.Version.Build -ge 22000) { $v = 2 $dwmTamam = ([RogeRsen.Native]::DwmSetWindowAttribute($form.Handle, 33, [ref]$v, 4) -eq 0) } } catch {} if (-not $dwmTamam) { Set-YuvarlakBolge $form 16 } try { [void][RogeRsen.Native]::SetWindowTheme($progressBar.Handle, "", "") } catch {} $progressBar.ForeColor = $script:tema.Vurgu $progressBar.BackColor = $script:tema.Kenar Yerlesim-Uygula }) # ---- Pencere açılışında yumuşak fade-in ---- $form.Add_Shown({ $script:fadeInTimer = New-Object System.Windows.Forms.Timer $script:fadeInTimer.Interval = 15 $script:fadeInTimer.Add_Tick({ param($s, $e) $form.Opacity = [Math]::Min(1.0, $form.Opacity + 0.08) if ($form.Opacity -ge 1.0) { $s.Stop(); $s.Dispose() } }) $script:fadeInTimer.Start() $dgv.Focus() }) Yerlesim-Uygula Chipleri-Boya Listeyi-Guncelle "" "Tümü" # ---- Kurulum işini arka planda (ayrı runspace) çalıştır ---- $syncHash = [Hashtable]::Synchronized(@{ Log = $log ProgressBar = $progressBar ProgressLabel = $lblProgress DurumMap = $script:DurumMap Yenile = $script:mevcutFiltreOku Bitti = $false }) $installWorker = { param($syncHash, $secilenler) function LogYaz([string]$satir) { $syncHash.Log.Invoke([Action]{ $syncHash.Log.AppendText("[" + (Get-Date -Format "HH:mm:ss") + "] " + $satir + [Environment]::NewLine) }) | Out-Null } function Durum-Guncelle($p, [string]$simge) { $syncHash.DurumMap[$p.Ad] = $simge # $true: liste yenilenirken kaydırma konumunu koru $syncHash.Log.Invoke([Action]{ & $syncHash.Yenile $true }) | Out-Null } function Ilerleme-Artir { $syncHash.Log.Invoke([Action]{ $syncHash.ProgressBar.Value = [Math]::Min($syncHash.ProgressBar.Maximum, $syncHash.ProgressBar.Value + 1) $yuzde = [Math]::Round((100.0 * $syncHash.ProgressBar.Value) / [Math]::Max(1, $syncHash.ProgressBar.Maximum)) $syncHash.ProgressLabel.Text = "$($syncHash.ProgressBar.Value) / $($syncHash.ProgressBar.Maximum) (%$yuzde)" }) | Out-Null } function Kisalt([string]$s) { if ([string]::IsNullOrEmpty($s)) { return "" } if ($s.Length -gt 200) { return $s.Substring(0, 200) + "..." } else { return $s } } $syncHash.Log.Invoke([Action]{ $syncHash.ProgressBar.Value = 0 $syncHash.ProgressBar.Maximum = [Math]::Max(1, $secilenler.Count) $syncHash.ProgressLabel.Text = "0 / $($secilenler.Count) (%0)" }) | Out-Null $wingetGerekli = $secilenler | Where-Object { $_.WingetId } | Select-Object -First 1 if ($wingetGerekli -and -not (Get-Command winget -ErrorAction SilentlyContinue)) { LogYaz "HATA: 'winget' bulunamadı. Microsoft Store'dan 'App Installer'ı güncelleyin ya da winget'i kurun." $syncHash.Bitti = $true return } foreach ($p in $secilenler) { Durum-Guncelle $p "⏳" if ($p.WingetId) { $kaynakMetni = if ($p.Kaynak) { ", kaynak: " + $p.Kaynak } else { "" } $etkilesimli = [bool]$p.Etkilesimli $modMetni = if ($etkilesimli) { " (kurulum ekranı açılacak, sen tamamla)" } else { "" } LogYaz ($p.Ad + " kuruluyor (winget: " + $p.WingetId + $kaynakMetni + ")..." + $modMetni) if ($etkilesimli) { $wArgs = @("install", "--id", $p.WingetId, "-e", "--interactive", "--accept-package-agreements", "--accept-source-agreements") } else { $wArgs = @("install", "--id", $p.WingetId, "-e", "--silent", "--accept-package-agreements", "--accept-source-agreements") } if ($p.Kaynak) { $wArgs += @("--source", $p.Kaynak) } try { $errLog = Join-Path $env:TEMP ("we_" + [guid]::NewGuid().ToString("N") + ".log") $outLog = [System.IO.Path]::GetTempFileName() $proc = Start-Process -FilePath "winget" -ArgumentList $wArgs -NoNewWindow -Wait -PassThru -RedirectStandardError $errLog -RedirectStandardOutput $outLog $basarili = $proc.ExitCode -eq 0 $cikti = "" if (-not $basarili) { $errText = ""; $outText = "" if (Test-Path $errLog) { $errText = Get-Content $errLog -Raw -ErrorAction SilentlyContinue } if (Test-Path $outLog) { $outText = Get-Content $outLog -Raw -ErrorAction SilentlyContinue } $cikti = ($outText + " " + $errText).Trim() } Remove-Item $errLog -Force -ErrorAction SilentlyContinue Remove-Item $outLog -Force -ErrorAction SilentlyContinue if ($basarili) { LogYaz ("OK " + $p.Ad + " kuruldu.") Durum-Guncelle $p "✓" } elseif ($cikti -match '(?i)already installed|zaten y[uü]kl|no newer package|no available upgrade|up to date') { LogYaz ("= " + $p.Ad + " zaten kurulu, atlandı.") Durum-Guncelle $p "✓" } else { LogYaz ("HATA " + $p.Ad + " kurulamadı: " + (Kisalt $cikti)) Durum-Guncelle $p "✗" } } catch { LogYaz ("HATA " + $p.Ad + " kurulamadı: " + (Kisalt $_.Exception.Message)) Durum-Guncelle $p "✗" } } elseif ($p.PortableExe -and $p.DirectUrl) { LogYaz ($p.Ad + " indiriliyor: " + $p.DirectUrl) try { $dosyaAdi = [System.IO.Path]::GetFileName($p.DirectUrl) $klasorAdi = if ($p.PortableKlasor) { $p.PortableKlasor } else { "Portable" } $hedefKlasor = Join-Path $env:LOCALAPPDATA ("Programs\" + $klasorAdi) $hedefYol = Join-Path $hedefKlasor $dosyaAdi New-Item -ItemType Directory -Path $hedefKlasor -Force | Out-Null Invoke-WebRequest -Uri $p.DirectUrl -OutFile $hedefYol -UseBasicParsing Start-Process -FilePath $hedefYol | Out-Null try { $startupKlasor = [Environment]::GetFolderPath("Startup") $kisayolYolu = Join-Path $startupKlasor ($klasorAdi + ".lnk") $wsh = New-Object -ComObject WScript.Shell $kisayol = $wsh.CreateShortcut($kisayolYolu) $kisayol.TargetPath = $hedefYol $kisayol.WorkingDirectory = $hedefKlasor $kisayol.Save() [void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($wsh) } catch {} LogYaz ("OK " + $p.Ad + " kuruldu ve çalıştırıldı: " + $hedefYol + " (başlangıca eklendi)") Durum-Guncelle $p "✓" } catch { LogYaz ("HATA " + $p.Ad + " başarısız: " + (Kisalt $_.Exception.Message)) Durum-Guncelle $p "✗" } } elseif ($p.DirectUrl) { LogYaz ($p.Ad + " indiriliyor ve çalıştırılıyor: " + $p.DirectUrl) $temp = $null try { $temp = Join-Path $env:TEMP ("kurulum_" + [guid]::NewGuid().ToString("N") + ".exe") Invoke-WebRequest -Uri $p.DirectUrl -OutFile $temp -UseBasicParsing $proc = Start-Process -FilePath $temp -PassThru $proc.WaitForExit(5 * 60 * 1000) | Out-Null LogYaz ("OK " + $p.Ad + " installer çalıştırıldı.") Durum-Guncelle $p "✓" } catch { LogYaz ("HATA " + $p.Ad + " başarısız: " + (Kisalt $_.Exception.Message)) Durum-Guncelle $p "✗" } finally { if ($temp -and (Test-Path $temp)) { Remove-Item $temp -Force -ErrorAction SilentlyContinue } } } elseif ($p.ManuelUrl) { LogYaz ($p.Ad + " için resmi sayfa tarayıcıda açılıyor: " + $p.ManuelUrl) try { Start-Process $p.ManuelUrl; Durum-Guncelle $p "✓" } catch { LogYaz ("HATA Tarayıcı açılamadı: " + $_.Exception.Message); Durum-Guncelle $p "✗" } Start-Sleep -Milliseconds 400 } else { LogYaz ("UYARI " + $p.Ad + " için kurulum bilgisi tanımlı değil, atlandı.") Durum-Guncelle $p "✗" } Ilerleme-Artir } LogYaz "Tamamlandı." $syncHash.Bitti = $true } $btnKur.Add_Click({ if ($dgv.IsCurrentCellDirty -or $dgv.IsCurrentRowDirty) { $dgv.EndEdit() } $btnKur.Enabled = $false $log.Clear() $syncHash.Bitti = $false $script:DurumMap.Clear() $secilenler = @($programlar | Where-Object { $_.Secili }) $secilenler = @($secilenler | Sort-Object Oncelik, Ad) if ($secilenler.Count -eq 0) { [System.Windows.Forms.MessageBox]::Show("Hiç program seçilmedi.", "Uyarı") | Out-Null $btnKur.Enabled = $true return } $runspace = [runspacefactory]::CreateRunspace() $runspace.ApartmentState = "STA" $runspace.ThreadOptions = "ReuseThread" $runspace.Open() $ps = [powershell]::Create() $ps.Runspace = $runspace [void]$ps.AddScript($installWorker).AddArgument($syncHash).AddArgument($secilenler) $handle = $ps.BeginInvoke() # Burada .GetNewClosure() GEREKLİ: $timer/$ps/$runspace/$handle her tıklamada # yeniden oluşturuluyor, Tick olayı doğru (o tıklamaya ait) kopyayı görmeli. $timer = New-Object System.Windows.Forms.Timer $timer.Interval = 300 $timer.Add_Tick({ if ($syncHash.Bitti) { try { $timer.Stop() } catch {} try { $timer.Dispose() } catch {} try { $ps.EndInvoke($handle) } catch {} try { $ps.Dispose() } catch {} try { $runspace.Close() } catch {} try { $runspace.Dispose() } catch {} $btnKur.Enabled = $true } }.GetNewClosure()) $timer.Start() }) [void]$form.ShowDialog()