Invoke-Command: Uzaktan Kod Çalıştırmanın En İyi Yolu
BT uzmanları nadiren yalnızca yerel bilgisayarımızda çalışır. PowerShell Invoke-Command cmdlet'ini kullanmak zorunda değiliz! Bu cmdlet, sanki yerel bilgisayarımızda çalışıyormuşuz gibi sorunsuz bir şekilde kod yazmamızı sağlar.
PowerShell Uzaktan İletişim özelliğini kullanarak Invoke-Command cmdlet'i, kullanıcının bir PSSession içinde kod yürütmesine olanak tanıyan yaygın olarak kullanılan bir PowerShell cmdlet'idir. Bu PSSession, daha önce New-PSSession cmdlet'iyle oluşturulmuş bir PSSession olabilir veya hızlı bir şekilde geçici bir oturum oluşturup kaldırabilir.
İlgili: PowerShell Uzaktan İletişim: Temel Kılavuz
Invoke-Command'ı PowerShell psexec'i olarak düşünün. Farklı şekillerde uygulansalar da konsept aynıdır. Bir bit kodu veya komutu alın ve uzak bilgisayarda “yerel olarak” çalıştırın.
Invoke-Command'ın çalışması için uzak bilgisayarda PowerShell Uzaktan İletişim'in etkin ve kullanılabilir olması gerekir. Varsayılan olarak, tüm Windows Server 2012 R2 veya üzeri makinelerde, uygun güvenlik duvarı istisnalarıyla birlikte bu özellik etkinleştirilmiştir. Hala Server 2008 makinelerine sahip olacak kadar şanssızsanız, Uzaktan İletişim kurmanın birden fazla yolu vardır, ancak kolay bir yol da winrm quickconfig veya Enable-PSRemoting'i çalıştırmaktır. uzak makine.
Invoke-Command'ın, yeni bir PSSession oluşturulmasını gerektirmeyen bir "geçici komut" ile nasıl çalıştığını göstermek için, diyelim ki uzak bir Windows Server 2012 R2 veya sonraki sürüme etki alanına katılmış bir bilgisayarınız var. Çalışma grubu bilgisayarlarında çalışırken işler biraz karışır. PowerShell konsolumu açacağım, Invoke-Command yazıp Enter'a basacağım.
PS> Invoke-Command
cmdlet Invoke-Command at command pipeline position 1
Supply values for the following parameters:
ScriptBlock:Hemen bir komut dosyası bloğu sağlamam isteniyor. Betik bloğu uzaktaki bilgisayarda çalıştıracağımız koddur.
Betik bloğunun içindeki kodun uzaktaki bilgisayarda yürütüldüğünü kanıtlayabilmemiz için ana bilgisayar adı komutunu çalıştıralım. Bu komut, üzerinde çalıştığı bilgisayarın ana bilgisayar adını döndürecektir. Yerel bilgisayarımda ana bilgisayar adı'ı çalıştırmak, bunun sonucunu verir.
PS> hostname
MACWINVMŞimdi bir komut dosyası bloğunun içindeki aynı koda sahip bir komut dosyası bloğunu Invoke-Command'a aktaralım. Ancak bunu yapmadan önce gerekli bir parametreyi unutuyoruz: BilgisayarAdı. Invoke-Command'a bu komutun hangi uzak bilgisayarda çalıştırılacağını söylememiz gerekiyor.
PS> Invoke-Command -ScriptBlock { hostname } -ComputerName WEBSRV1 WEBSRV1ana bilgisayar adı çıktısının artık WEBSRV1 uzak bilgisayarının adı olduğuna dikkat edin. WEBSRV1'de bazı kodlar çalıştırdınız. Basit kodu bir komut dosyası bloğu içinde çalıştırmak ve tek bir uzak makineye aktarmak Invoke-Command'ın en kolay uygulamasıdır ancak çok daha fazlasını yapabilir.
Yerel Değişkenleri Uzak Komut Dosyası Bloklarına Aktarma
Bir betiğin içinde tek bir Invoke-Command referansına sahip olmayacaksınız. Komut dosyanız muhtemelen düzinelerce satır uzunluğunda olacak, değişkenlerin tanımlı yerleri, modüllerde tanımlanmış işlevler vb. olacak. Bazı kodları birkaç süslü parantez içine almak masum görünse de, aslında kodun çalıştığı tüm kapsamı değiştiriyorsunuz. Sonuçta, o kodu uzaktaki bir bilgisayara gönderiyorsunuz. Bu uzaktaki bilgisayarın, komut dosyası bloğundakiler dışında, makinenizdeki tüm yerel kodlar hakkında hiçbir fikri yoktur.
Örneğin, bilgisayar adı ve dosya yolu parametresi olan bir işleviniz olabilir. Bu işlevin amacı uzak bilgisayarda bazı yazılım yükleyicilerini çalıştırmaktır. Bilgisayar adını ve "yerel" dosya yolunu, uzak bilgisayarda zaten bulunan yükleyiciye iletebilirsiniz.
Aşağıdaki işlev makul görünüyor, değil mi? Hadi çalıştıralım.
function Install-Stuff {
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$ComputerName,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$InstallerFilePath
)
Invoke-Command -ComputerName $ComputerName -ScriptBlock { & $InstallerFilePath }
}
PS> Install-Stuff -ComputerName websrv1 -InstallerFilePath 'C:\install.exe'
The expression after '&' in a pipeline element produced an object that was not valid. It must result in a command name, a script block, or a CommandInfo object.
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : BadExpression
+ PSComputerName : websrv1Ve işareti operatörünü kullanmam nedeniyle belirsiz bir hata hata mesajıyla başarısız oluyor. Kod yanlış değildi ancak başarısız oldu çünkü function parametresiyle birlikte bir değer iletmiş olsanız bile $InstallerFilePath boştu. Bunu, ve işaretini Write-Host ile değiştirerek test edebiliriz.
Yeni işlev satırı: Invoke-Command -ComputerName $ComputerName -ScriptBlock { Write-Host "Yükleyici yolu: $InstallerFilePath"
PS> Install-Stuff -ComputerName websrv1 -InstallerFilePath 'C:\install.exe'
Installer path is:
PS>
$InstallerFilePath değerinin hiçbir şey olmadığına dikkat edin. Değişken uzak makineye aktarılmadığından genişletilmedi. Yerel olarak tanımlanmış değişkenleri uzak komut dosyası bloğuna aktarmak için iki seçeneğimiz vardır; değişken adının başına komut bloğunun içinde $using: yazabiliriz veya Invoke-Command parametresi ArgumentList'i kullanabiliriz. İkisine de bakalım.
ArgumentList Parametresi
Yerel değişkenleri uzak bir komut dosyası bloğuna aktarmanın bir yolu, Invoke-Command ArgumentList parametresini kullanmaktır. Bu parametre, yerel değişkenleri parametreye aktarmanıza ve komut dosyası bloğundaki yerel değişken referanslarını yer tutucularla değiştirmenize olanak tanır.
Yerel değişkenleri ArgumentList parametresine aktarmak kolaydır.
Invoke-Command -ComputerName WEBSRV1 -ScriptBlock { & $InstallerFilePath } -ArgumentList $InstallerFilePathBazı insanları şaşırtan kısım, komut dosyası bloğu içindeki değişkenlerin nasıl yapılandırılacağıdır. { & $InstallerPath kullanmak yerine, onu { & $args[0] veya {param($foo) & olacak şekilde değiştirmemiz gerekir. $foo. Her iki yöntem de aynı şekilde çalışır ancak hangisini kullanmalısınız?
ArgumentList parametresi bir nesne koleksiyonudur. Nesne koleksiyonları aynı anda bir veya daha fazla nesneyi aktarmanıza olanak tanır. Bu durumda sadece birini geçiyorum.
Yürütüldüğünde, Invoke-Command cmdlet'i bu koleksiyonu alır ve ardından onu komut dosyası bloğuna enjekte ederek onu esasen $args adlı bir diziye dönüştürür. $args -eq ArgumentList'i unutmayın. Bu noktada, koleksiyonun her dizinine tıpkı bir dizide olduğu gibi referans verirsiniz. Bizim durumumuzda, koleksiyonda yalnızca bir öğemiz vardı ($InstallerFilePath) ve bu öğe, o koleksiyondaki ilk dizin anlamına gelen $args[0]'a "çevrildi". Ancak daha fazlasına sahip olsaydınız, $args[1], $args[2] vb. ile başvuruda bulunurdunuz.
Ek olarak, scriptblock değişkenlerine daha iyi değişken adları atamayı tercih ederseniz, scriptblock'a tıpkı bir fonksiyon gibi parametreler de ekleyebilirsiniz. Sonuçta, bir scriptblock sadece anonim bir fonksiyondur. Komut dosyası bloğu parametreleri oluşturmak için parametrenin adını taşıyan bir param bloğu oluşturun. Oluşturulduktan sonra, aşağıdaki gibi komut dosyası bloğunda bu parametreye referans verin.
Invoke-Command -ComputerName WEBSRV1 -ScriptBlock { param($foo) & $foo } -ArgumentList $InstallerFilePathBu örnekte, ArgumentList koleksiyonundaki öğeler, tanımlanan parametrelerle sırayla "eşlenir". Parametre adlarının önemi yoktur; önemli olan sıradır. Invoke-Command, ArgumentList koleksiyonundaki ilk öğeyi alacak, ilk parametreyi arayacak ve bu değerleri eşleyecek, ikinci, üçüncü ve benzeri için aynısını yapacak.
$Using Yapısı
$using yapısı, yerel değişkenleri uzak bir komut dosyası bloğuna aktarmanın başka bir popüler yoludur. Bu yapı, mevcut yerel değişkenleri yeniden kullanmanıza olanak tanır, ancak yalnızca değişken adının başına $using: ekleyerek gelir. $args koleksiyonu veya parametre bloğu ekleme konusunda endişelenmenize gerek yok.
Invoke-Command -ComputerName WEBSRV1 -ScriptBlock { & $using:InstallerFilePath }PowerShell $using yapısı çok daha basittir ancak Pester'ı öğrenmeye başlarsanız ArgumentList'in arkadaşınız olacağını göreceksiniz.
Invoke-Command ve New-PSSession
Teknik olarak bu yazı sadece Invoke-Command ile ilgili ancak kullanışlılığını göstermek için New-PSSession komutuna da kısaca değinmemiz gerekiyor. Daha önce Invoke-Command'ın "geçici" komutları kullanabileceğinden veya mevcut oturumları kullanabileceğinden bahsettiğimi hatırlayın.
Bu yazı boyunca uzak bilgisayarlarda sadece "geçici" komutlar çalıştırdık. Yeni bir oturum başlatıyoruz, kodu çalıştırıyoruz ve onu yıkıyoruz. Bu, tek seferlik durumlar için iyidir, ancak aynı bilgisayarda düzinelerce komut gerçekleştirdiğiniz bir süre için pek fazla değildir. Bu durumda, önceden New-PSSession ile bir PSSession oluşturarak mevcut bir PSSession'ı yeniden kullanmak daha iyidir.
Herhangi bir komutu çalıştırmadan önce New-PSSession ile bir PSSession oluşturmanız gerekir. Bunu basitçe $session=New-PSSession -ComputerName WEBSRV1 komutunu çalıştırarak yapabiliriz. Bu, sunucuda uzak bir oturumun yanı sıra yerel makinemdeki bu oturuma bir referans oluşturur. Bu noktada, BilgisayarAdı referanslarımı Session ile değiştirebilir ve Session referansımı kayıtlı $session değişkenime yönlendirebilirim.
Invoke-Command -Session $session -ScriptBlock { & $using:InstallerFilePath }Çalıştırıldığında, oturum zaten oluşturulmuş olduğundan performansın daha hızlı olduğunu fark edeceksiniz. Ancak tamamlandığında, açık oturumu Remove-PSSession ile kaldırmak önemlidir.
Özet
Invoke-Command PowerShell cmdlet'i mevcut en yaygın ve güçlü cmdlet'lerden biridir. Neredeyse hepsinden kişisel olarak en çok kullandığım şey bu. Kullanım kolaylığı ve uzaktaki bilgisayarlarda herhangi bir kodu çalıştırma yeteneği son derece güçlüdür ve baştan sona öğrenmenizi tavsiye ettiğim bir komuttur!