,

Powershell: Convert String to Scriptblock

1–2 minutes
19 comments on Powershell: Convert String to Scriptblock

If you use PowerShell remoting in some scripts, you will ses you cannot use a string to send it with the Invoke-Command cmdlet.

So you can simple convert a String to a Scriptblock

 $scriptBlock = [Scriptblock]::Create($string) 

Now here an example

$remoteCommand =
@"
Import-Module ActiveDirectory
New-ADOrganizationalUnit -name
"@

$scriptBlock = [Scriptblock]::Create($remoteCommand)

Invoke-Command -ComputerName AD01 -ScriptBlock $scriptBlock

Basically you could create a function for that.

function ConvertTo-Scriptblock {
<# Function to Convert a String into a Script Block #>
Param(
[Parameter(
Mandatory = $true,
ParameterSetName = '',
ValueFromPipeline = $true)]
[string]$string
)
$scriptBlock = [scriptblock]::Create($string)
return $scriptBlock
}

19 responses

  1. Jared Bratu Avatar

    Thanks, this was exactly what I needed.

  2. James Robison Avatar
    James Robison

    Thanks much!

  3. Nicolas Melay Avatar
    Nicolas Melay

    Nice. Just what I was looking for.

    1. Thomas Maurer Avatar

      great it helped you

  4. CHrisN Avatar

    Why couldn’t you make me google this 18hours ago??? :-)
    Thanks Thomas

  5. Danny Nilsson Avatar
    Danny Nilsson

    this one really saved my, i was trying all kinds of Invoke-Expression they needed to implement something like [scriptblock]$string

    before i put a full powershell string into a variable and used invoke-expression

  6. Michael M Avatar
    Michael M

    Used this for a project where I build a string of properties and values stored in a hashtable to be passed to Where-Object:

    # Filter Hash
    $filterItems = @{
    #”Property Value” = “Property Name”
    ‘ODB’ = ‘Folder’
    ‘NetApp’ = ‘Folder’
    ‘cl_Prod’ = ‘Cluster’
    }

    # Bulid Filter String for Where-Object
    $filterItems.Keys | ForEach-Object{
    $pValue = $_
    $pName = $($filterItems[$_])
    if (! $fString) { $fString = “`$_.$pName -ne `”$pValue`”” } else { $fString += ” -And `$_.$pName -ne `”$pValue`”” }
    }

    # Convert Filter String to a Scriptblock
    $scriptBlock = [ScriptBlock]::Create($fString)

    # Extract the filtered VMs
    $filteredVMs = $allVMs | where-object $scriptBlock

  7. Sandor Teglasy Avatar
    Sandor Teglasy

    This has been a lifesaver to a project of mine, where I store a set of commands in two variables (base command + path parameter tacked onto it), which I wanted to then wanted to combine and finally pass on to Invoke-Command. This didn’t work before you’ve shown how to convert a string to scriptblock.

    Also the error message from PowerShell is quite straightforward:
    “Invoke-Command : Cannot bind parameter ‘ScriptBlock’. Cannot convert the “asfewfasd” value of type “System.String” to
    type “System.Management.Automation.ScriptBlock”.”

    Nonetheless, I have expected PowerShell to be more “intelligent” and do the conversion automatically.

    In any case, to contribute back to the community, I’m providing the function back that I’ve put togethe on top of your solution, to address my issue. I know I could have used a string array instead of two strings as the function’s parameters, but for my purposes I wanted to have EXACTLY 2 strings and not more:

    function CombineTo-Scriptblock ()
    {
    [CmdletBinding()]
    param(
    [Parameter(Mandatory=$True,Position=1)]
    [string]$command1,
    [Parameter(Mandatory=$True,Position=2)]
    [string]$command2
    )

    $newscriptblock = [scriptblock]::Criceate($($command1+$command2))

    return $newscriptblock
    }

    1. Thomas Maurer Avatar

      thanks for sharing :)

  8. Wamiq Ansari Avatar
    Wamiq Ansari

    Thank you, great help!

  9. johndoe Avatar
    johndoe

    Love you. 2 Hours of searching.

  10. couli Avatar
    couli

    Works like a charm!

    Only problem I’m having is when I have a $variable in the command which is defined locally but not remotely. When converted to a scriptblock and executed through Invoke-Command in a remote session, it would need a $using:variable.

    For instance a command string like = “Test-Path -LiteralPath $Folder -PathType Container” will work when executed locally, but throws an error when in Invoke-Command:
    Invoke-Command -Session $session -ScriptBlock $CommandAsScriptBlock
    Invoke-Command : Missing an argument for parameter ‘Session’. Specify a parameter of type ‘System.Management.Automation.Runspaces.PSSession[]’ and try again.
    Cannot bind argument to parameter ‘LiteralPath’ because it is null.
    + CategoryInfo : InvalidData: (:) [Test-Path], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.TestPathCommand
    + PSComputerName : Windows Server 2016 – test

    Is there a way to force the substitution of variables in a string or scriptblock before respectively the conversion to scriptblock or the execution of the scriptblock?

  11. couli Avatar
    couli

    Apologies for error in previous post: posted too much error message which is unrelated. The correct error message is below:

    Cannot bind argument to parameter ‘LiteralPath’ because it is null.
    + CategoryInfo : InvalidData: (:) [Test-Path], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.TestPathCommand
    + PSComputerName : Windows Server 2016 – test

  12. Kirt Carson Avatar
    Kirt Carson

    I had something like Couli had. A local variable that was not passed to the remote scriptBlock. Also my $string had single quotes and ampersands which is not permitted in my older powershell [scriptblock]::Create($string) method; So I had to use invoke-expression in combo with invoke-command for remote server execution.

    get-acl C:\MyShare | select -expand access | select IdentityReference | where IdentityReference -match ‘My Media group’ | foreach
    {
    $samid=[regex]::matches($_.IdentityReference,'(?i)(?<=^MyDomain\\).*').value;
    $SB="get-adgroup '$samid' -Properties * -ErrorAction SilentlyContinue";
    $exp = ("Invoke-Command -ComputerName myDC -Credential "+'$cred'+" -EnableNetworkAccess -ScriptBlock {"+$SB+"}") ;
    Invoke-Expression $exp
    }

  13. Yawar Avatar

    Hello Thomas,
    Thanks for writing this. I have a situation where I have to pass Credential to a method using string script block.

    the method call and other params are build as string then that string is used to create scriptBlock using ScriptBlock::Ceate(string) method.

    when i pass in the credetials I get this error:

    Exception : System.Management.Automation.MethodInvocationException: Exception calling “Invoke” with “1” argument(s): “Cannot process argument transformation on parame
    ter ‘Credential’. A command that prompts the user failed because the host program or the command type does not support user interaction.

    I have tried to invoke this scripBlock like this

    & $scriptBlock

    and

    Invoke-Command $ScriptBlock -Credentail $Credential

    both dont work.

    Thanks in advace.

  14. Andrew Avatar

    I was trying to pass a string containing a script block to the Filter parameter of Where-Object.
    Why oh why couldn’t it convert it and why couldn’t I just do
    [scriptblock]$filter
    or
    $filter -as [scriptblock]

    Thanks for this article!

  15. Eyup Dogan Okkir Avatar
    Eyup Dogan Okkir

    Year 2022 :) Thanks for the saver. Nowherelse.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.