Moerwald
Moerwald

Reputation: 11284

Use Begin, Process, End in Scriptblock

Is it possible to use the adavanced function features Begin, Process, End in a script-block?

For example I've the following script block:

$startStopService = {
Param(
    [bool] $startService)    

  if ($startService){
     ...
     Start-Service "My-Service"
  }
  else {
     Stop-Service "My-Service"
  }
}

Since I want to be able to control the verbose output of the scriptblock I want to change the block to:

$startStopService = {
Param(
    [bool] $startService)    

  Begin {
     $oldPreference = $VerbosePreference 
     $VerbosePreference = $Using:VerbosePreference
  }
  Process {
     if ($startService){
        ...
        Start-Service "My-Service"
     }
     else {
        Stop-Service "My-Service"
     }
  }
  End {
     # Restore the old preference
     $VerbosePreference = $oldPreference 
  }
}

Is it possible to use Begin, Process, End here, though the scriptblock isn't a cmdlet? I simply want that the VerbosePreference gets restored to the old value, regardless an error occurred or not. Of course I could use try{}finally{} as an alternative, but I find that Begin, Process, End is more intuitive.

Thx

Upvotes: 2

Views: 2631

Answers (1)

G42
G42

Reputation: 10019

It is possible, as described in about_script_blocks:

Like functions, script blocks can include the DynamicParam, Begin, Process, and End keywords. For more information, see about_Functions and about_Functions_Advanced.


To test this out, I modified your scriptblock and ran this:

$startStopService = {
Param(
    # a bool needs $true or $false passed AFAIK
    # A switch is $true if specified, $false if not included
    [switch] $startService 
 )    

  Begin {
     $oldPreference  = $VerbosePreference 
     Write-Output "Setting VerbosePreference to Continue"

     # $Using:VerbosePreference gave me an error
     $VerbosePreference = "Continue"
  }
  Process {
     if ($startService){
        Write-Verbose "Service was started"
     }
     else {
        Write-Verbose "Service was not started"
     }
  }
  End {
     # Restore the old preference
     Write-Output "Setting VerbosePreference back to $oldPreference"
     $VerbosePreference = $oldPreference 
  }

}

Write-Verbose "This message will not print if VerbosePreference is the default SilentlyContinue"

. $startStopService -startService

Write-Verbose "This message will not print if VerbosePreference is the default SilentlyContinue"

What functionality are you after? If you would to print verbose messages when running a scriptblock but not change the $VerbosePreference in the rest of the script , consider using [CmdletBinding()] and the -Verbose flag:

$startStopService = {
    [CmdLetBinding()]
    Param(
        [switch] $startService
    )

     Write-Verbose "This is a verbose message"

}
Write-Verbose "This message will not print if VerbosePreference is the default SilentlyContinue"

. $startStopService -verbose

Write-Verbose "This message will not print if VerbosePreference is the default SilentlyContinue"

Edit - Invoke-Command

After your comment, I looking into the functionality of Invoke-Command. And found a lot of things that don't work.

The short version that I believe is most useful to you: you can declare $VerbosePreference = "Continue" within a scriptblock and this will be limited to the scope of the scriptblock. No need to change back after.

$startStopService = {
    [CmdLetBinding()]
    Param(
        [parameter(Position=0)]
        [switch]$startStopService,

        [parameter(Position=1)]
        [switch]$Verbose
    )

    if($Verbose){
        $VerbosePreference = "Continue"
    }

    Write-Verbose "This is a verbose message"

}

Write-output "VerbosePreference: $VerbosePreference"
Write-Verbose "This message will not print if VerbosePreference is the default SilentlyContinue"

Invoke-Command -Scriptblock $startStopService -ArgumentList ($true,$true)

Write-output "VerbosePreference: $VerbosePreference"
Write-Verbose "This message will not print if VerbosePreference is the default SilentlyContinue"

Trying to pass the -Verbose switch CommonParameter to Invoke-Command was a no-go. This uses a standard Verbose switch parameter that allows you to pass $true/$false (or omit) to control the verbose output.

Related:
about_Functions
about_Functions_Advanced

Upvotes: 2

Related Questions