PowerShell okiem programisty .NET
Artykuł ten tworzę z dość prostego powodu. Wraz z mijającym czasem w każdym programiście rośnie opór oraz lenistwo wobec powtarzalnych czynności wykonywanych codziennie w pracy. Stąd też szukamy sposobów na zautomatyzowanie choć części z tych zadań. PowerShell może być jednym ze sposobów na osiągnięcie tego celu. Z tego powodu warto lepiej się z nim zapoznać.
Zanim zacznę, chcę zaznaczyć, że nie jestem mistrzem PS. Postanowiłem jednak podzielić się swoimi doświadczeniami z punktu widzenia typowego programisty .NET i w miarę zwięźle pokazać, w jaki sposób przenieść niektóre z najpopularniejszych operacji występujących w tym świecie na ich odpowiedniki w PowerShellu. Zaczynajmy.
Rzecz, którą nieraz warto zrobić przed rozpoczęciem właściwej pracy, to uruchomienie PowerShella w trybie administratora. Możemy to zrobić bezpośrednio z poziomu cmd.exe za pomocą komendy:powershell “Start-Process powershell -Verb runAs”
.
Wypisanie textu na konsolę
C#:
System.Console.WriteLine("Hello world!");
PowerShell:
Write-Host "Hello world!"
# lub krócej
"Hello world!"
Zmienne
C#:
int a = 1, b = 2;
var a = 1; var b = 2;
PowerShell:
$a = 1
$b = 2
$a, $b = 1, 2 # Python-like
Tablice
C#:
var array = new object[] { 1, "text", 3.14 };
var a = array[0];
var iter = Enumerable.Range(1, 10);
PowerShell:
$array = 1, "text", 3.14
$array = @(1, "text", 3.14) # jawny zapis
$a = $array[0]
$iter = (1..10)
Słowniki
C#:
var dictionary = new Dictionary<string,string>
{
{"key 1", "value 1"},
{"key 2", "value 2"}
};
dictionary["key 1"]
PowerShell:
$dictionary = @{"key 1" = "value 1"; "key 2" = "value 2"}
$dictionary["key 1"]
Operatory logiczne, warunkowe i binarne
C#:
true == true // równy
true != false // różny
1 > 0 // większy
0 < 1 // mniejszy
1 >= 0 // większy lub równy
0 <= 1 // mniejszy lub równy
!true // negacja
true && true // koniunkcja (logiczny)
true || false // alternatywa (logiczny)
1 ^ 1 // alternatywa wykluczająca
1 | 1 // alternatywa (binarny)
1 & 1 // koniunkcja (binarny)
PowerShell:
$True -eq $True # równy
$True -ne $False # różny
1 -gt 0 # większy
0 -lt 1 # mniejszy
1 -ge 0 # większy lub równy
0 -le 1 # mniejszy lub równy
-not $True # negacja
$True -and $True # koniunkcja (logiczny)
$True -or $False # alternatywa (logiczny)
$True -xor $False # alternatywa wykluczająca (logiczny)
1 -bxor 2 # alternatywa wykluczająca (binarny)
1 -bor 1 # alternatywa (binarny)
1 -band 1 # koniunkcja (binarny)
Instrukcje warunkowe
C#:
if($a == true)
{
Console.WriteLine("Statement 1");
}
else if($b == true)
{
Console.WriteLine("Statement 2");
}
else
{
Console.WriteLine("Statement 3");
}
PowerShell:
If($a -eq $True) {
"Statement 1"
} ElseIf($b -eq $True) {
"Statement 2"
} Else {
"Statement 3"
}
Pętle
C#:
for(int i=0; i < 10; i++)
Console.WriteLine(i);
foreach(var element in array)
Console.WriteLine(element);
while(i < 10)
Console.WriteLine(i++);
do {
Console.WriteLine(i++);
} while(i < 10);
PowerShell:
for($i=1; $i -lt 10; $i++) {
Write-Host $i
}
foreach($i in (1..10)) {
Write-Host $i
}
while($i -lt 10) {
Write-Host $i
$i++
}
do {
Write-Host $i
$i++
} while($i -lt 10)
do {
Write-Host $i
$i++
} until($i -eq 10) # odpowiednik: do {} while(-not ($i -ne 10))
Definicje własnych metod/funkcji
C#:
// C# wymaga "opakowania funkcji" w klasę
class A
{
public int Fib(int n = 1)
{
if(n < 2) return n;
return Fib(n - 2) + Fib(n - 1);
}
}
(new A()).Fib(10); // wynik: 55
PowerShell:
Function Fib($n = 1) {
if($n -lt 2) {
return $n
}
return ((Fib($n - 2)) + (Fib($n - 1)))
}
Fib(10) # wynik: 55
Wywołania statycznych klas .NET
C#:
System.DateTime.Parse("10-01-2012"); // 1 Października 2012
PowerShell:
[System.DateTime]::Parse("10-01-2012"); # 1 Października 2012
Tworzenie nowych obiektów za pomocą konstruktorów
C#:
var date = new DateTime(2012, 10, 1); // 1 Października 2012
PowerShell (przestrzeń nazw System jest domyślnie zaimportowana):
$date = New-Object DateTime(2012, 10, 1) # 1 Października 2012
Kilka przydatnych cmdletów
Na koniec chciałbym pokazać kilka cmdletów, które nieraz ułatwiają pracę. Warto zauważyć, że nieraz cmdlet dostępny jest również poprzez alias (przeważnie więcej niż jeden). Niektóre z nich zostały tutaj przedstawione.
"A = {0} hours {1} minutes" -f 10, 20 # odpowiednik string.Format
#tworzenie nowego pliku/katalogu
New-Item c:\files\new_file.txt -Type File
New-Item "c:\directories" -Type Directory
ni c:\files\new.txt -type file # skrótowy zapis
# kopiujemy wszystkie pliki z c:\files do c:\directories
Copy-Item c:\files\* c\directories
copy c:\files\* c\directories # skrótowy zapis
cp c:\files\* c\directories # skrótowy zapis
# usunięcie pliku lub katalogu
Remove-Item c:\files\new.txt
rm c:\files\new.txt # alternatywa
# przenoszenie plików lub folderów
Move-Item c:\files\old.txt c:\files2\
move c:\files\old.txt c:\files2\ # skrótowy zapis
mv c:\files\old.txt c:\files2\ # skrótowy zapis
# pobranie zawartości pliku
Get-Content c:\files\file.txt
# wpisanie tekstu do pliku
Set-Content file.txt "file content"
"file content" | Out-File file.txt
# sprawdzenie istnienia pliku lub folderu pasującego do podanego wzorca
Test-Path c:\files\*.txt
# wyszukanie linijki z pliku źródłowego, zawierającego szukaną frazę
Get-Content file.txt | Select-String "fraza"
# zwaraca True, jeżeli znaleziono dopasowanie
Get-Content file.txt | Select-String "fraza" -quiet
# rozróżnienie wielkości liter
Get-Content file.txt | Select-String "fraza" -casesensitive
Get-Date # pobieramy bierzącą datę z zegara systemowego: DateTime.Now
Get-Date -displayhint date # jak powyżej, ale pobieramy samą datę: DateTime.Today
Get-Date -displayhist time # analogicznie dla czasu
# ustawia zegar systemowy na hh:mm:ss do przodu (w przykładzie 1h10m)
Set-Date -adjust 1:10:00
# informacje o procesie
Get-Process process1, process2 # jawne wyliczenie szukanych nazw
Get-Process proc* # szukanie wg. wzorca
ps proc* # skrótowy zapis
# zakończ process(-y)
Stop-Process -processname process* # zakończ procesy o nazwie zgodnej z wzorcem
kill 3888 # skrótowy zapis, zakończ process o Id równym 3888
PS: W niektórych z powyższych komend wykorzystałem jeden z feature’ów PowerShella, którego wcześniej nie opisałem – pipeline operator. Jest on reprezentowany przez symbol |
i służy do przekazywania wyniku jednej funkcji/polecenia jako wejścia do następnej.