Hey, Scripting Guy! How Can I Use Transactions to Write to the Registry?

ScriptingGuy1

Bookmark and Share

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I am interested in using transactions when writing to the registry, but if something does not work, I want the entire transaction to fail. It does not seem that this actually works in Windows PowerShell. Am I missing something?

— TW

 

Hey, Scripting Guy! AnswerHello TW,

Microsoft Scripting Guy Ed Wilson here. Today has been a great day, and I have spent much of the day in Live Meetings for the MVP program. It has been very informative. The cool thing has also been the “back channel” of tweets that have been flowing from the conference. I have found that all day meetings go great with Dragon Pearl Tea and an ANZAC biscuit.

The MVP meetings are over, TW, so let us get to work on transactions. If you start a transaction by using the Start-Transaction cmdlet, perform an invalid WMI query, and then use the transaction to create a registry key, you might think that the transaction will fail. But the registry key will be created because there is no –usetransaction parameter on the Get-WmiObject cmdlet. The annoying message that is displayed when you use the Start-Transaction cmdlet states that only commands that use the –usetransaction parameter are included in the transaction. In the command sequence seen here, the registry key test is created under test2.

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:> $a = gwmi win32_computerSystem -ComputerName localtoast
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:1 char:10
    + $a = gwmi <<<<  win32_computerSystem -ComputerName localtoast
    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

PS C:> New-ItemProperty -Name memory -Value ($a.totalphysicalmemory).tostring() `
-Path HKCU:SoftwareScriptingGuystest2
You cannot call a method on a null-valued expression.
At line:1 char:71
+ New-ItemProperty -Name memory -Value ($a.totalphysicalmemory).tostring <<<< () -Path HKCU:SoftwareScriptingGuystest2
    + CategoryInfo          : InvalidOperation: (tostring:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

PS C:> New-ItemProperty -Name test -Value rolledback -Path HKCU:SoftwareScriptingGuystest2 -UseTransaction

PSPath       : Microsoft.PowerShell.CoreRegistry::HKEY_CURRENT_USERSoftwareScriptingGuystest2
PSParentPath : Microsoft.PowerShell.CoreRegistry::HKEY_CURRENT_USERSoftwareScriptingGuys
PSChildName  : test2
PSDrive      : HKCU
PSProvider   : Microsoft.PowerShell.CoreRegistry
test         : rolledback

PS C:> Complete-Transaction
PS C:>

The new registry key is seen in the following image:

Image of the new registry key

 

To catch errors from cmdlets that do not directly participate in transactions, such as the Get-WmiObject cmdlet, you can use the Try/Catch/Finally sequence. This is illustrated in the TrapErrorInTransaction.ps1 script. This script requires Windows PowerShell 2.0 because of not only the use of the transaction cmdlets but also the use of the Try/Catch/Finally sequence.

TrapErrorInTransaction.ps1

#requires –version 2.0
Function New-MemoryRegKey ($computer)
{
 $t = {Start-Transaction}
 &($t)
 Try
  {
   $a = Get-WmiObject -Class win32_operatingSystem -ComputerName $computer -ErrorAction silentlyContinue
   Set-ItemProperty -Name FreeMemory -Path HKCU:SoftwareScriptingGuystest2 `
   -Value ($a.FreePhysicalMemory).ToString() -UseTransaction| out-null
   Complete-Transaction
   “registry Key updated”
  }
 Catch [System.Exception]
  {
    Undo-Transaction
    “roll back transaction”
  }
 Finally { “done” }
} #end function New-MemoryReg Key

new-MemoryRegKey localhost

My friend Luis, who is a Microsoft Premier Field Engineer in Lisbon, Portugal, showed me the trick to suppress the transaction message when calling the Start-Transaction cmdlet. To suppress the message, the first thing to do is place the Start-Transaction cmdlet in a script block and assign the results to the $t variable. Then we use the invocation operator to execute the Start-Transaction cmdlet. This provides us with a nice clean output. Here are the two lines of code:

$t = {Start-Transaction}
 &($t)

Next, we perform the WMI query, and attempt to create or update a registry key. When you want to attempt something, use the Try command. To suppress any errors from the WMI operation, set the -erroraction parameter to SilentlyContinue. If the WMI operation completes and the registry update completes without problem, commit the transaction. This is seen here:

Try
  {
   $a = Get-WmiObject -Class win32_operatingSystem -ComputerName $computer -ErrorAction silentlyContinue
   Set-ItemProperty -Name FreeMemory -Path HKCU:SoftwareScriptingGuystest2 `
   -Value ($a.FreePhysicalMemory).ToString() -UseTransaction| out-null
   Complete-Transaction
   “registry Key updated”
  }

If an error occurs in the Try block, we want to roll back the transaction. A system.exception is the most generic error that could occur, and if it occurs, it will invoke the Catch block. This is seen here:

Catch [System.Exception]
  {
    Undo-Transaction
    “roll back transaction”
  }

The Finally block will always execute, whether an error occurs or not. In this example, we simply display a message that states that we are all done:

Finally { “done” }

If the Try block completes successfully, the registry key is updated if it previously existed. If it did not previously exist, it is created. This is seen in the following image.

Image of creating or updating a registry key

 

When the script runs and an error occurs, messages are displayed on the console. If it runs without errors, status updates are still displayed. These are simple strings, and could easily be modified or deleted as required. This is seen in the following image.

Image of status updates being displayed

 

TW that is all there is to using transactions inside a Try/Catch/Finally block. Transaction Week will continue tomorrow.

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

0 comments

Discussion is closed.

Feedback usabilla icon