Chapter 30. Transactions

Introduction

Transactions describe a system’s ability to support tentative or multistep changes. When you make changes within the context of a transaction, the system provides four main guarantees:

Isolation

To observers not participating in the transaction, the commands inside the transaction have not impacted the system.

Atomicity

Once you decide to finalize (commit) a transaction, either all of the changes take effect or none of them do.

Consistency

Errors caused during a transaction that would cause an inconsistent system state are dealt with in order to bring the system back to a consistent state.

Durability

Once the system has informed you of the transaction’s successful completion, you can be certain that the changes are permanent.

As a real-world example of a transaction, consider a money transfer between two bank accounts. This might happen in two stages: subtract the money from the first account, and then add the money to the second account. In this situation, you have the exact same goals for robustness and correctness:

Isolation

While the money transfer is taking place (but has not yet completed), the balance of both bank accounts appears unchanged.

Atomicity

At some point in the process, it’s possible that we’ve subtracted the money from the first account but haven’t added it yet to the second account. When we process the money transfer, it’s critical that the system never show this intermediate state. Either all of the changes take effect or none of them do.

Consistency

If an error occurs during the money transfer, the system takes corrective action to ensure that it is not left in an intermediate state. Perhaps it accounts for a lack of funds by adding an overdraft charge or by abandoning the money transfer altogether. It should not, for example, take the funds from one account without depositing them into the second account.

Durability

Once the money transfer completes, you don’t have to worry about a system error undoing all or part of it.

Although transactions are normally a developer topic, PowerShell exposes transactions as an end-user concept, opening a great deal of potential for consistent system management.

To start a transaction, call the Start-Transaction cmdlet. To use a cmdlet that supports transactions, specify the -UseTransaction parameter. Being explicit about this parameter is crucial, as many cmdlets that support transactions can work equally well without one. Because of that, PowerShell lets the cmdlet participate in the transaction only when you supply this parameter.

In Windows Vista and later, PowerShell’s registry provider supports transactions as a first-class concept. You can see this in action in Safely Combine Related Registry Modifications.

PS > Set-Location HKCU:
PS > Start-Transaction

PS > mkdir TempKey -UseTransaction

    Hive: HKEY_CURRENT_USER

SKC  VC Name                           Property
---  -- ----                           --------
  0   0 TempKey                        {}

PS > New-Item TempKeyTempKey2 -UseTransaction


    Hive: HKEY_CURRENT_USERTempKey

SKC  VC Name                           Property
---  -- ----                           --------
  0   0 TempKey2                       {}

PS > Get-ChildItem TempKey
Get-ChildItem : Cannot find path 'HKEY_CURRENT_USERTempKey' because it 
does not exist.

PS > Complete-Transaction
PS > Get-ChildItem TempKey

    Hive: HKEY_CURRENT_USERTempKey

SKC  VC Name                           Property
---  -- ----                           --------
  0   0 TempKey2                       {}

Once you have completed the transactional work, call either the Complete-Transaction cmdlet to make it final or the Undo-Transaction cmdlet to discard the changes. While you may now be tempted to experiment with transactions on other providers (for example, the filesystem), be aware that only the registry provider currently supports them.

Safely Experiment with Transactions

Problem

You want to experiment with PowerShell’s transactions support but don’t want to use the Registry Provider as your playground.

Solution

Use PowerShell’s System.Management.Automation.TransactedString object along with the Use-Transaction cmdlet to experiment with a string, rather than registry keys:

PS > 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 > 
PS > $transactedString = New-Object Microsoft.PowerShell.Commands.Management.
TransactedString
PS > $transactedString.Append("Hello ")
PS > 
PS > Use-Transaction -UseTransaction { $transactedString.Append("World") }

Suggestion [2,Transactions]: The Use-Transaction cmdlet is intended for 
scripting of transaction-enabled .NET objects. Its ScriptBlock should contain 
nothing else.
PS > 
PS > $transactedString.ToString()
Hello
PS > 
PS > Complete-Transaction
PS > 
PS > $transactedString.ToString()
Hello World
PS > 

Discussion

PowerShell’s transaction support builds on four core cmdlets: Start-Transaction, Use-Transaction, Complete-Transaction, and Undo-Transaction.

The Start-Transaction begins a transaction, creating a context where changes are visible to commands within the transaction, but not outside of it. For the most part, after starting a transaction, you’ll apply commands to that transaction by adding the -UseTransaction parameter to a cmdlet that supports it. For example, when a PowerShell provider supports transactions, all of PowerShell’s core cmdlets (Get-ChildItem, Remove-Item, etc.) let you specify the -UseTransaction parameter for actions against that provider.

The Use-Transaction cmdlet is slightly different. Although it still requires the -UseTransaction parameter to apply its script block to the current transaction, its sole purpose is to let you script against .NET objects that support transactions themselves. Since they have no way to supply a -UseTransaction parameter, PowerShell offers this generic cmdlet for any type of transactional .NET scripting.

Note

Other transaction-enabled cmdlets should not be called within the Use-Transaction script block. You still need to provide the -UseTransaction parameter to the cmdlet being called, and there’s a chance that they might cause instability with your PowerShell-wide transactions.

To give users an opportunity to play with something a little less risky than the Windows Registry, PowerShell includes the Microsoft.PowerShell.Commands.Management.TransactedString class. This class acts like you’d expect any transacted command to act and lets you become familiar with how the rest of PowerShell’s transaction cmdlets work together. Since this is a .NET object, it must be called from within the script block of the Use-Transaction cmdlet.

Finally, when you are finished performing tasks for the current transaction, call either the Complete-Transaction or the Undo-Transaction cmdlet. As compared to the solution, here’s an example session where the Undo-Transaction cmdlet lets you discard changes made during the transaction:

PS > 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 > 
PS > $transactedString = New-Object Microsoft.PowerShell.Commands.Management.Tra
nsactedString
PS > $transactedString.Append("Hello ")
PS > 
PS > Use-Transaction -UseTransaction { $transactedString.Append("World") }

Suggestion [2,Transactions]: The Use-Transaction cmdlet is intended for 
scripting of transaction-enabled .NET objects. Its ScriptBlock should contain 
nothing else.
PS > 
PS > $transactedString.ToString()
Hello
PS > 
PS > Undo-Transaction
PS > 
PS > $transactedString.ToString()
Hello

For more information about transactions in the Windows Registry, see Safely Combine Related Registry Modifications.

Change Error Recovery Behavior in Transactions

Problem

You want to change how PowerShell responds to errors during the execution of a transacted cmdlet.

Solution

Use the -RollbackPreference parameter of the Start-Transaction cmdlet to control what type of error will cause PowerShell to automatically undo your transaction:

HKCU: >Start-Transaction
HKCU: >New-Item Foo -UseTransaction

    Hive: HKEY_CURRENT_USER

SKC  VC Name                           Property
---  -- ----                           --------
  0   0 Foo                            {}

HKCU: >Copy IDoNotExist Foo -UseTransaction
Copy-Item : Cannot find path 'HKCU:IDoNotExist' because it does not exist.

HKCU: >Complete-Transaction
Complete-Transaction : Cannot commit transaction. The transaction has been 
rolled back or has timed out.

HKCU: >Start-Transaction -RollbackPreference TerminatingError

    Hive: HKEY_CURRENT_USER

SKC  VC Name                           Property
---  -- ----                           --------
  0   0 Foo                            {}

HKCU: >Copy IDoNotExist Foo -UseTransaction
Copy-Item : Cannot find path 'HKCU:IDoNotExist' because it does not exist.

HKCU: >Complete-Transaction
HKCU: >Get-Item Foo

    Hive: HKEY_CURRENT_USER

SKC  VC Name                           Property
---  -- ----                           --------
  0   0 Foo                            {}

Discussion

Errors in scripts are an extremely frequent cause of system inconsistency. If a script incorrectly assumes the existence of a registry key or other system state, this type of error tends to waterfall through the entire script. As the script continues, some of the operations succeed while others fail. When the script completes, you’re in the difficult situation of not knowing exactly what portions of the script worked correctly.

Sometimes running the script again will magically make the problems go away. Unfortunately, it’s just as common to face a painstaking manual cleanup effort.

Addressing these consistency issues is one of the primary goals of system transactions.

When PowerShell creates a new transaction, it undoes (rolls back) your transaction for any error it encounters that is operating in the context of that transaction. When PowerShell rolls back your transaction, the system impact is clear: no part of your transaction was made permanent, so your system is still entirely consistent.

Some situations are simply too volatile to depend on this rigid interpretation of consistency, though, so PowerShell offers the -RollbackPreference parameter on the Start-Transaction to let you configure how it should respond to errors:

Error

PowerShell rolls back your transaction when any error occurs.

TerminatingError

PowerShell rolls back your transaction only when a terminating error occurs.

Never

PowerShell never automatically rolls back your transaction in response to errors.

For more information about PowerShell’s error handling and error levels, see Chapter 15.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.85.181