PowerShell Bloglama Haftası: WhatIf'i Destekleme ve Onaylama


Topluluk bloglarındaki bu deneyden keyif alacağınızı umuyoruz. Bugünkü katkımda, gelişmiş PowerShell işlevlerinize WhatIf ve Confirm için nasıl destek ekleyebileceğinizi göstermek istiyorum. Özellikle işleviniz zaten -Whatif ve -Confirm'i destekleyen diğer PowerShell komutlarını çağırıyorsa, bu aslında oldukça kolaydır. Önerilen en iyi uygulama, eğer fonksiyonunuz bir şeyi değiştirecek herhangi bir şey yapacaksa bu parametreleri desteklemesidir. İşte nasıl yapılacağı.

İşlevinizde cmdletbinding niteliğini kullanmanız ve SupportsShouldProcess'i belirtmeniz gerekecektir.

[cmdletbinding(SupportsShouldProcess)]

PowerShell 3.0'dan başlayarak ihtiyacınız olan tek şey budur ancak komut dosyalarının bunu açıkça $True olarak ayarladığını göreceksiniz.

[cmdletbinding(SupportsShouldProcess=$True)]

Bu iyi, ancak şahsen ben bunu gereksiz buluyorum. SupportsShouldProcess listeleniyorsa varsayılan olarak True'dur. Bunu açıkça $False olarak ayarlamanıza gerek yoktur. Basitçe ihmal edin. Bu özelliği eklediğinizde otomatik olarak -WhatIf ve -Confirm parametrelerini alırsınız. En iyi yanı, işleviniz zaten -WhatIf'i destekleyen PowerShell cmdlet'lerini çağırıyorsa, bu ayarı otomatik olarak devralacaklardır. İşte örnek bir fonksiyon.

#requires -version 4.0

Function Remove-TempFile {
[cmdletbinding(SupportsShouldProcess)]

Param(
[Parameter(Position=0)]
[ValidateScript({Test-Path $_})]
[string]$Path = $env:temp
)

#get last bootup time
$LastBoot = (Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUptime
Write-Verbose "Finding all files in $path modified before $lastboot"

(Get-Childitem -path $path -File).Where({$_.lastWriteTime -le $lastboot}) | Remove-Item

} #end function

İşlev, %TEMP% klasöründeki, son değiştirilme tarihi son başlatma zamanından daha eski olan tüm dosyaları siler. Yardımda görebileceğiniz gibi PowerShell gerekli parametreleri ekledi.

Fonksiyonu -Whatif ile çalıştırdığımda Remove-Item'a aktarılıyor.

Gerçekten bu kadar kolay. Ayrıca -Confirm için otomatik olarak destek alıyorum.

Komutlarınızın doğal olarak SupportsShouldProcess'i tanımadığı bir işlev için WhatIf'i desteklemek istediğinizde işler biraz daha karmaşıklaşıyor. Birkaç örnek vermek gerekirse bu, herhangi bir .NET statik yöntemi veya hatta çalıştırıyor olabileceğiniz bir komut satırı aracı için geçerli olabilir. Kendi desteğinizi eklemek için yerleşik $PSCmdlet nesnesini ve onun ShouldProcess() yöntemini çağırmanız gerekir. İşte basit bir örnek.

Function Set-Folder {
[cmdletbinding(SupportsShouldProcess)]

Param(
[Parameter(Position=0,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias("pspath")]
[ValidateScript({Test-Path $_})]
[string]$Path=".")

Process {
$Path = (Resolve-Path -Path $Path).ProviderPath
if ($PSCmdlet.ShouldProcess($Path)) {
#do the action
$Path.ToUpper()
}
} #Process

} #end function

Bu işlev varsayımsal olarak bir klasör üzerinde bazı eylemler gerçekleştirecek ve ben yalnızca klasör adını büyük harfle görüntülüyorum. Önemli olan If ifadesidir. Bu ihtiyacınız olan minimum miktardır. -WhatIf belirtirseniz sizden istenecektir.

İşlem, betiğinizin veya işlevinizin adı olacaktır. Hedef, benim örneğimde yol olan ShouldProcess parametre değeridir. Ancak hedef ve eylem için ShouldProcess parametrelerini belirterek daha spesifik bilgiler sağlayabilirsiniz. İşte gözden geçirilmiş bir fonksiyon.

Function Set-Folder2 {
[cmdletbinding(SupportsShouldProcess)]

Param(
[Parameter(Position=0,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias("pspath")]
[ValidateScript({Test-Path $_})]
[string]$Path=".")

Process {
$Path = (Resolve-Path -Path $Path).ProviderPath
if ($PSCmdlet.ShouldProcess($Path,"Updating")) {
#do the action
$Path.ToUpper()
}
} #Process

} #end function

ShouldProcess koduna sahip olmanız gerekir, aksi takdirde cmdletbinding özelliğini ayarlasanız bile PowerShell hangi komutların WhatIf'e ihtiyacı olduğunu bilemez. Ayrıca ihtiyaç duyduğunuz sayıda ShouldProcess ifadesine de sahip olabilirsiniz.

Onay söz konusu olduğunda işler biraz daha karmaşık hale gelir ve bu, gerçekten neye ihtiyacınız olduğuna bağlı olabilir. Yukarıda gördüğünüz gibi -Confirm'i destekleyen herhangi bir cmdlet, ayarı otomatik olarak devralmalıdır. Bunun nedeni, varsayılan değeri Medium olan ConfirmImpact adında başka bir cmdletbinding özelliğinin bulunmasıdır. Diğer seçenekler Düşük ve Yüksek'tir. İlk fonksiyonum şu şekilde de yazılabilirdi:

[cmdletbinding(SupportsShouldProcess,ConfirmImpact="medium ")]

Onaylama, ConfirmImpact değerinin varsayılan değeri Yüksek olan yerleşik $ConfirmPreference değişkeniyle karşılaştırılmasıyla gerçekleşir. $ConfirmPreference değeri ConfirmImpact'a eşit veya ondan büyükse PowerShell onay isteyecektir. Bunu test edelim.

Function Set-Folder6 {
[cmdletbinding(SupportsShouldProcess,ConfirmImpact="High")]

Param(
[Parameter(Position=0,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias("pspath")]
[ValidateScript({Test-Path $_})]
[string]$Path="."
)
Begin {
Write-Verbose "Starting $($MyInvocation.Mycommand)"
} #begin

Process {
$Path = (Resolve-Path -Path $Path).ProviderPath
Write-Verbose "Processing $path"
if ($PSCmdlet.ShouldProcess($Path,"Updating")) {
#do the action
$Path.ToUpper()
} #ShouldProcess
} #Process

End {
Write-Verbose "Ending $($MyInvocation.Mycommand)"
} #end

} #end function

Ayrıca WhatIf için de kullandığıma dikkat edin. Bu işlevde ConfirmImpact yüksek olarak ayarlanmıştır; bu, PowerShell'in her zaman istemde bulunacağı anlamına gelir.

İşlevi düzenler ve ConfirmImpact'ı Orta veya Düşük olarak değiştirirsem, PowerShell yalnızca ben sorduğumda onaylayacaktır.

Cmdletbinding için herhangi bir şey belirtmeniz gerekmez. Her zaman onay almak istediğinizi biliyorsanız şöyle bir şey yapabilirsiniz:

Function Set-Folder4 {
[cmdletbinding()]

Param(
[Parameter(Position=0,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[Alias("pspath")]
[ValidateScript({Test-Path $_})]
[string]$Path=".",
[switch]$Force
)

Process {
$Path = (Resolve-Path -Path $Path).ProviderPath
Write-Verbose "Processing $path"
if ($Force -OR $PSCmdlet.ShouldContinue("Do you want to continue modifying folder?",$path)) {
#do the action
$Path.ToUpper()
}
} #Process

} #end function

ShouldContinue yönteminin kullanımına dikkat edin. Bu işlevi çalıştırdığımda PowerShell her zaman onay isteyecek.

Ayrıca Force adında bir switch parametresi de ekledim, böylece belirtilirse kullanıcıdan onay istenmez.

Bu yaklaşımın dezavantajı, yardımın hiçbir şey göstermemesidir.

Belki özel durumlarda istediğiniz budur. Şahsen, Set-Folder6 örneğimde yaptığım gibi cmdletbinding niteliklerini kullanmanın daha iyi olacağını düşünüyorum.

WhatIf ve Confirm için destek eklemek fazla çaba gerektirmez ve gelişmiş işlevinizi bir sonraki seviyeye taşıyacaktır.

Bu gönderi, belirli bir konunun kapsamlı bir görünümünü sağlamak için tasarlanmış bir dizi koordineli gönderi olan Windows PowerShell Gelişmiş İşlevleri hakkındaki PowerShell Bloglama Haftası serisinin bir parçasıdır.

Bu serideki diğer makaleler:

  • Standart ve Gelişmiş İşlevler, François-Xavier Cat
  • PowerShell Gelişmiş İşlevleri: Bunları daha iyi oluşturabilir miyiz? Yazan: Mike F. Robbins
  • Dinamik Parametreler ve Parametre Doğrulaması, Adam Bertram
  • June Blender'dan Yardım ve Yorumlar Oluşturma
  • Boe Prox'tan Dene/Yakala ve Temel Hata İşleme

Umarız çalışmalarımızı zaman ayırmaya değer bulmuşsunuzdur.

İlgili makaleler