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

David Moravec, MVP
Mainstream Technologies