Stejně jako Mistr Skriptík, i já jsem nedávno dostal dotaz na transakce v PowerShellu. Že prý kdysi v PowerShellu byly, ale teď tam nejsou a proč byly odebrány.
Transakce v PowerShellu pořád jsou, jenom se o nich nemluví, protože jejich implementace není taková, jakou bychom si ji všichni představovali. Zatím je dostupná pouze pro registr. Nicméně pojďme se podívat, jak taková implementace vypadá.
V první řadě si řekneme, co si pod pojmem transakce představit. Jedná se o operaci, při které nám systém zajistí několik základních vlastností: Izolace (prováděné příkazy neovlivní systém – dokud to nepovolíme), Atomicita (když se rozhodneme změny uložit, uloží se buď všechny, nebo žádná), Konzistence (pokus se v průběhu operace objeví chyby, které mohou vést ke stavu, který nechceme, můžeme operaci zrušit a vrátit provedené kroky), Odolnost (pokud je operace dokončená, provedené změny jsou trvalé). I když zní předchozí pokus o popis transakčního zpracování příliš „vědecky“, žádná věda to není. Pojďme si vše ukázat na příkladu.
Nejprve zjistíme, kde můžeme transakce provádět. Jistě víte, že v PowerShellu existuje systém tzv. Providerů. Jedná se například o FileSystem Provider pro práci se souborovým systém, dále máme např. Registry Provider, atd. Jejich seznam si můžeme zobrazit pomocí cmdletu Get-PSProvider.
PS C:\> Get-PSProvider
Name Capabilities Drives
---- ------------ ------
Alias ShouldProcess {Alias}
Environment ShouldProcess {Env}
FileSystem Filter, ShouldProcess, Credentials {C, Dropbox, Download, E}
Function ShouldProcess {Function}
Registry ShouldProcess, Transactions {HKLM, HKCU, HKU, HKCR...}
Variable ShouldProcess {Variable}
Certificate ShouldProcess {Cert}
ActiveDirectory Include, Exclude, Filter, ShouldProcess, Crede... {}
Pokud se chceme podívat jenom na providery podporující transakce, můžeme si výstup filtrovat:
PS C:\> Get-PSProvider |? Capabilities -m 'Transactions' | ft -auto
Name Capabilities Drives
---- ------------ ------
Registry ShouldProcess, Transactions {HKLM, HKCU, HKU, HKCR...}
Opravdu, jediným providerem je zatím ten pro registr.
Ukážeme si nějakou operaci a zkusíme ji provést transakčně. Nejprve se přepneme do registru:
PS C:\> cd HKCU:\Software\Makovec\Tran
A poté odstartujeme transakci pomocí cmdletu Start-Transaction.
PS C:\> Start-Transaction
Suggestion [1,Transactions]: Once a transaction is started, only commands that get called with the -UseTransaction flag become part of that transaction.
PowerShell nám rovnou oznamuje, že všechny operace, které chceme provést jako součást transakce, musíme volat i s parametrem UseTransaction. Můžeme si zobrazit všechny cmdlety, které transakce podporují:
PS C:\> gcm -ParameterName UseTransaction | fw -c 3
mkdir Add-Content Clear-Content
Clear-Item Clear-ItemProperty Convert-Path
Copy-Item Copy-ItemProperty Get-Acl
Get-Content Get-ChildItem Get-Item
Get-ItemProperty Get-Location Get-PSDrive
Invoke-Item Join-Path Move-Item
Move-ItemProperty New-Item New-ItemProperty
New-PSDrive Pop-Location Push-Location
Remove-Item Remove-ItemProperty Remove-PSDrive
Rename-Item Rename-ItemProperty Resolve-Path
Set-Acl Set-Content Set-Item
Set-ItemProperty Set-Location Split-Path
Test-Path Use-Transaction
A nyní si vytvoříme strukturu, do které budeme zapisovat data:
PS C:\> mkdir MyKey -UseTransaction
Hive: HKEY_CURRENT_USER\Software\Makovec\Tran
Name Property
---- --------
MyKey
Pro kontrolu si můžeme zobrazit výpis aktuálního stavu. Transakce by ještě neměla být zapsána.
PS C:\> ls
PS C:\> New-Item MyKey\Datum -UseTransaction
Hive: HKEY_CURRENT_USER\Software\Makovec\Tran\MyKey
Name Property
---- --------
Datum
A celou transakci uložíme.
PS C:\> Complete-Transaction
PS C:\> ls
Hive: HKEY_CURRENT_USER\Software\Makovec\Tran
Name Property
---- --------
MyKey
Nyní už máme vše zapsáno tak, jak jsme si představovali. Ještě zapíšeme aktuální datum a čas do nově vytvořené struktury.
PS C:\> Start-Transaction
Suggestion [1,Transactions]: Once a transaction is started, only commands that get called with the -UseTransaction flag become part of that transaction.
PS C:\> New-ItemProperty -Path .\MyKey\Datum –Name Datum -Value $(date)
Datum : 5. 11. 2013 7:48:38
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Makovec\Tran\MyKey\Datum
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Makovec\Tran\MyKey
PSChildName : Datum
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
PS C:\> Complete-Transaction
A výsledek si můžeme zobrazit pomocí regeditu:
Transakce mají výhodu v tom, že pokud dojde k chybě, výsledná operace se neprovede. Pojďme si to demonstrovat na příkladu.
PS C:\> Start-Transaction
Suggestion [1,Transactions]: Once a transaction is started, only commands that get called with the -UseTransaction flag become part of that transaction.
PS C:\> New-ItemProperty -Path . -Name Datum2 -Value (get-date) -UseTransaction
Datum2 : 5. 11. 2013 8:01:48
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Makovec\Tran\MyKey\Datum
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Makovec\Tran\MyKey
PSChildName : Datum
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
PS C:\> New-ItemProperty -Path .\asdfg -Name Datum3 -Value (get-date) -UseTransaction
New-ItemProperty : Cannot find path 'HKCU:\Software\Makovec\Tran\MyKey\Datum\asdfg' because it does not exist.
At line:1 char:1
+ New-ItemProperty -Path .\asdfg -Name Datum3 -Value (get-date) -UseTransaction
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (HKCU:\Software\...Key\Datum\asdfg:String) [New-ItemProperty], ItemNotFo
undException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.NewItemPropertyCommand
PS C:\> Complete-Transaction
Complete-Transaction : Cannot commit transaction. The transaction has been rolled back or has timed out.
At line:1 char:1
+ Complete-Transaction
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Complete-Transaction], TransactionAbortedException
+ FullyQualifiedErrorId : System.Transactions.TransactionAbortedException,Microsoft.PowerShell.Commands.CompleteTr
ansactionCommand
PS C:\> Get-ItemProperty .
Datum : 5. 11. 2013 7:48:38
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Makovec\Tran\MyKey\Datum
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Makovec\Tran\MyKey
PSChildName : Datum
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
Všimněte si, že při snaze o vložení aktuálního data do neexistující cesty PowerShell zahlásil chybu a při snaze o zapsání celé transakce nás informoval, že nemůže provést celou transakci. Kontrolou na konci jsme si ověřili, že nová položka skutečně nebyla vytvořena.
Transakce jsou velice zajímavou součástí práce s PowerShellem, ale doufám, že se dočkáme doby, kdy budou implementovány minimálně ještě pro souborový systém. Do té doby doporučuji při vaší práci s registrem myslet na to, že je můžete využít. Za ten pocit jistoty to určitě stojí.