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

David Moravec, MVP
Mainstream Technologies