Seriál Windows PowerShell – Transakce (část 40.)

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:

image

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í.