PowerShell "=" not a recognised cmdlet error

1.5k views Asked by At

Further to the response given here: PowerShell Enter Session find path bug, I've hit another wall in my script that I can't work around. The below script returns the error:

The term '=' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

$sb = [ScriptBlock]::Create(@"
$Acl = (Get-Item -path D:\Websites\$Sitename).GetAccessControl('Access')
$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule('BUILTIN\IIS_IUSRS', 'Modify', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
$Acl.SetAccessRule($Ar)
Set-Acl -path $Path -AclObject $Acl
"@)

Invoke-Command -Session $Session -ScriptBlock $sb

I can create the script block variable ($sb), but when I invoke it, I get the error. I have narrowed it down to the setting of the $Acl variable, and tried rewriting various ways with no luck. What am I missing?

1

There are 1 answers

2
Mathias R. Jessen On BEST ANSWER

When you use a double-quoted here-string, it behaves just like a regular double-quoted string - the parser will evaluate and expand any variable or sub-expression between the quotation marks.

Since the variables in the scriptblock definition doesn't already exist in the defining context, you end up with a scriptblock with the following definition:

 = (Get-Item -path D:\Websites\).GetAccessControl('Access')
 = New-Object System.Security.AccessControl.FileSystemAccessRule('BUILTIN\IIS_IUSRS', 'Modify', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
.SetAccessRule()
Set-Acl -path  -AclObject 

As you can see, the first two statements start out with just a bare = as the first non-whitespace character, and this is the reason for the error you're seeing.

Switch to a single-quoted here-string instead:

$sb = [ScriptBlock]::Create(@'
$Acl = (Get-Item -path D:\Websites\$Sitename).GetAccessControl('Access')
$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule('BUILTIN\IIS_IUSRS', 'Modify', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
$Acl.SetAccessRule($Ar)
Set-Acl -path $Path -AclObject $Acl
'@)

If you need to pass in a variable value from the defining scope, I'd suggest either defining a param block in the scriptblock:

$sb = [ScriptBlock]::Create(@'
param($Sitename)
$Acl = (Get-Item -path D:\Websites\$Sitename).GetAccessControl('Access')
$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule('BUILTIN\IIS_IUSRS', 'Modify', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
$Acl.SetAccessRule($Ar)
Set-Acl -path $Path -AclObject $Acl
'@)
 Invoke-Command -Session $Session -ScriptBlock $sb -ArgumentList $Sitename

or use the -f string format operator to replace it in the string before creating the scriptblock:

$sb = [ScriptBlock]::Create(@'
$Acl = (Get-Item -path D:\Websites\{0}).GetAccessControl('Access')
$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule('BUILTIN\IIS_IUSRS', 'Modify', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
$Acl.SetAccessRule($Ar)
Set-Acl -path $Path -AclObject $Acl
'@ -f $Sitename)

See the about_Quoting_Rules help topic for more information about quoting and variable expansion