PowerShell Core Out-Gridview Çözümü
Çoğunuzun bildiği gibi bu yıl "günlük sürücüm" olarak PowerShell Core'a geçiş yaptım. Önemli bir itici faktör sınırlamaları keşfetmekti. Platformlar arası bir dünyaya geçiş yaparken kesinlikle pek çok avantajımız var. Ancak PowerShell Core, tam Windows masaüstünde alışık olduğumuz her şeyi içermeyen .NET Core tabanlıdır. Birçok insanı ilgilendiren en büyük sınırlamalardan biri grafiksel araçlara yönelik desteğin kaybıdır. PowerShell Core'da Windows Forms veya WPF desteği yoktur. Belki de duyduğum en büyük ağıt Out-Gridview'in kaybıdır. Anladım. Komut yararlı bir araç olabilir. Şimdi size PowerShell Core'da bir komut çalıştırabileceğinizi ve sonuçları yine de bildiğiniz ve sevdiğiniz Out-Gridview komutuna gönderebileceğinizi söylesem ne olur?
Gereksinimler
Aslında geçici bir çözümden pek fazlası olmayan çözümüm, Windows 10 gibi bir Windows masaüstü çalıştırdığınızı varsayar; bu, Windows PowerShell'e erişiminiz olduğu anlamına gelir. Çözümümün arkasındaki fikir oldukça basit: Bir PowerShell Core komutunun çıktısını alın ve bunu Out-Gridview çalıştıran bir Windows PowerShell örneğine gönderin. Out-Gridview'i bir Windows PowerShell oturumunda kullanabildiğiniz sürece ve neden bunu yapamadığınızı anlayamıyorum, o zaman hazırsınız demektir.
PowerShell Core için Out-Gridview Alternatifi
Çözümümün temel kısmı yeni bir örnek başlatmak için PowerShell.exe komutunu çalıştırmaktır. Bir istemde powershell /? yazarsanız söz dizimini görürsünüz. Başlangıçta PowerShell Core çıktısını scriptblock için bir argüman olarak göndermeye çalışıyordum. Ancak komut dosyası bloğunun boyutunda sınırlamalar vardır. Bu yüzden aklıma gelen bir sonraki en iyi adımı attım. PowerShell core komutunun çıktısını alıp Export-Clixml kullanarak bir dosyaya serileştiriyorum. PowerShell.exe komut dosyası bloğunda, Import-Clixml'i kullanarak onu geri dönüştürüyorum ve sonuçları Out-Gridview'e aktarıyorum.
Out-Gridview'in işlevselliğini mümkün olduğu kadar çoğaltmak istedim. Sonuçları görüntüleyebilmek veya görüntüleyip seçebilmek istedim. Karşılaştığım zorluk, Out-Gridview'i basitçe görüntülerken, Windows PowerShell penceresinin siz hiçbir şey göremeden açılıp kapanmasıydı. -Passthru'yu kullanmak beklediğiniz deneyimi sağlar. Benim çözümüm en sonuna bir Pause ifadesi eklemekti. Bu, siz Enter tuşuna basana kadar Windows PowerShell penceresini açık tutar. Ayrıca nesneleri PowerShell Core'a geri göndermeye devam edebilirsiniz.
Bu büyünün kodu Github'da.
Send-ToPSGridview.ps1:
#requires -version 6.1
Function Send-ToPSGridView {
<#
.SYNOPSIS
Send objects to Out-Gridview in Windows PowerShell
.DESCRIPTION
This command is intended as a workaround for PowerShell Core running on a Windows platform, presumably Windows 10. PowerShell Core does not support all of the .NET Framework which means some commands like Out-Gridview are not supported. However, on a Windows desktop you are most likely running Windows PowerShell side by side with PowerShell Core. This command is designed to take objects from a PowerShell expression and send it to an instance of Windows PowerShell running Out-Gridview. You can specify a title and pass objects back to your PowerShell Core session. Note that passed objects will be deserialized versions of the original objects.
.PARAMETER Title
Specify a Title for the Out-Gridview window
.PARAMETER Passthru
Pass selected objects from Out-Gridview back to your PowerShell Core session.
.EXAMPLE
PS C:\> get-childitem c:\scripts\*.ps1 | Send-ToPSGridview -title "My Scripts"
Press Enter to continue...:
Display all ps1 files in Out-Gridview. You must press Enter to continue.
.EXAMPLE
PS C:\> get-service | where status -eq 'running' | Send-ToPSGridView -Passthru | Restart-service -PassThru
Press Enter to continue...:
Status Name DisplayName
------ ---- -----------
Running BluetoothUserSe... Bluetooth User Support Service_17b710
Running Audiosrv Windows Audio
Get all running services and pipe to Out-Gridview where you can select services which will be restarted.
.EXAMPLE
PS C:\> $val = 1..10 | Send-ToPSGridView -Title "Select some numbers" -Passthru
Press Enter to continue...:
PS C:\> $val
4
8
6
PS C:\> $val | Measure-Object -sum
Count : 3
Average :
Sum : 18
Maximum :
Minimum :
StandardDeviation :
Property :
Send the numbers 1 to 10 to Out-Gridview where you can select a few. The results are saved to a variable in the PowerShell Core session where you can use them.
.INPUTS
System.Object
.OUTPUTS
None, Deserialized.System.Object[]
.NOTES
Learn more about PowerShell: http://jdhitsolutions.com/blog/essential-powershell-resources/
#>
[cmdletbinding()]
[alias("ogv")]
[OutputType("None", "Deserialized.System.Object[]")]
Param(
[Parameter(Position = 0, ValueFromPipeline, Mandatory)]
[ValidateNotNullOrEmpty()]
[object[]]$InputObject,
[ValidateNotNullOrEmpty()]
[string]$Title = "Out-GridView",
[switch]$Passthru
)
Begin {
Write-Verbose "[$((Get-Date).TimeofDay) BEGIN ] Starting $($myinvocation.mycommand)"
#validate running on a Windows platform`
if ($PSVersionTable.Platform -ne 'Win32NT') {
Throw "This command requires a Windows platform with a graphical operating system like Windows 10."
}
#initialize an array to hold pipelined objects
$data = @()
#save foreground color
$fg = $host.ui.RawUI.ForegroundColor
} #begin
Process {
Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Adding object"
$data += $InputObject
} #process
End {
Write-Verbose "[$((Get-Date).TimeofDay) END ] Creating a temporary xml file with the data"
$tempFile = Join-Path -path $env:temp -ChildPath ogvTemp.xml
$data | Export-Clixml -Path $tempFile
Write-Verbose "[$((Get-Date).TimeofDay) END ] Starting up a PowerShell.exe instance"
PowerShell.exe -nologo -noprofile -command {
param([string]$Path, [string]$Title = "Out-Gridview", [bool]$Passthru)
Import-Clixml -Path $path | Out-Gridview -title $Title -passthru:$Passthru
#a pause is required because if you don't use -Passthru the command will automatically complete and close
$host.ui.RawUI.ForegroundColor = "yellow"
Pause
} -args $tempFile, $Title, ($passthru -as [bool])
if (Test-Path -Path $tempFile) {
Write-Verbose "[$((Get-Date).TimeofDay) END ] Removing $tempFile"
Remove-Item -Path $tempFile
}
#restore foreground color
$host.ui.RawUI.ForegroundColor = $fg
Write-Verbose "[$((Get-Date).TimeofDay) END ] Ending $($myinvocation.mycommand)"
} #end
} #close Send-ToPSGridView
Hatta ogv takma adını da ekledim.
PowerShell Core'u bir Windows platformunda çalıştırdığımı görebilirsiniz. Get-Process'in sonuçlarını Out-Gridview'e, bir pencere başlığı belirterek ve -Passthru'yu kullanarak aktarıyorum. Bu aynı Out-Gridview komutudur.
Öğeleri seçip Tamam'ı tıklayabilirim. Sonuçlar PowerShell Core hattına geri yazılır ve $P'de depolanır. Duraklatma mesajını göreceksiniz. İşlevde, öne çıkması için ana bilgisayarın ön plan rengini geçici olarak değiştiriyorum. Pek çok kişinin sarı bir arka plan çalıştırdığından şüpheliyim, ancak öyleyse, işlevi değiştirmeniz gerekecek.
Sınırlamalar
Benim çözümümün birkaç dezavantajı yok değil. Clixml cmdlet'lerini kullandığım için serileştirme ve seri durumdan çıkarmada biraz ek yük var. Disk süresini ve Windows PowerShell işlemini başlatma zamanını ekleyin ve tüm bu ek yükler toplanır. Bu mutlaka katlanılamaz bir durum değildir ancak ödenmesi gereken bir bedel olduğunu kabul etmeniz gerekir. Out-Gridview'e 10.000 dosya nesnesi göndermeye çalışmadığınız sürece pek şikayet edeceğinizi düşünmüyorum. Ve elbette her zaman seçici olabilirsiniz.
Umarım birkaçınız fonksiyonun bir kopyasını alır ve ne düşündüğünüzü bana bildirir. Herhangi bir sorunu, soruyu veya isteği bildirmek için lütfen Github özetinin yorum bölümünü kullanın. Eğer bu sizi PowerShell Core'dan alıkoyuyorsa umarım şimdi yeniden düşünüp benimle birlikte adım atarsınız.