ForEach Synatax Error? Unexpected token 'in' in expression or statement.

I am trying to create a script to get/change ACLs for folders named Administration. I can get the ACLs from the console with either of these commands:

Get-ChildItem 'D:\data\Company Shared Folders\Operations\Current Jobs' -Recurse -Filter "Administration" | Where-Object {$_.mode -eq "d----"} | Convert-Path | get-acl
Get-ChildItem 'D:\data\Company Shared Folders\Operations\Current Jobs' -Recurse -Filter "Administration" | Where-Object {$_.mode -eq "d----"} | Convert-Path | foreach {get-acl}

But my script gives me the error in the title of this post:

#get permissions for Administration folders
$adminfolders = Get-ChildItem 'D:\data\Company Shared Folders\Operations\Current Jobs' -Recurse -Filter "Administration" | Where-Object {$_.mode -eq "d----"} | Convert-Path
ForEach-Object ($adminfolder in $adminfolders){
        $acl = get-acl $adminfolder
    }

I think I’m missing some concept of the foreach syntax, is $thing in $things correct? Must I define the $thing first?

The type information from the ISE:
$adminfolders | gm
TypeName: System.String

I’m trying to build this up to eventually modify the ACLs using the methods in Set-ACL.

PSversion (SBS 2008)
Major Minor Build Revision


2 0 -1 -1

In the ForEach-Object cmdlet, you use $_ or $PSItem (v3+) to represent the piped-in object.

In the ForEach scripting construct, you use the ($x in $y) syntax.

You’re mixing and matching. In the script, you should be using ForEach, not ForEach-Object.

Thank you that was the concept I was missing. I had thought ForEach was simply an alias for ForEach-Object. When I changed ForEach-Object to ForEach I get the expected result.

Well, that’s the thing. ForEach-Object does have an alias foreach. But neither of them are the foreach scripting construct ;).

Clarification: If ‘Foreach’ is at the beginning of a statement then it is the foreach loop keyword. If it is used after a pipe character it’s interpreted as ‘Foreach-Object’. It was a bit confusing for me at first too. I started a habit of never using the alias of Foreach-Object to prevent this confusion.

So if I understand using foreach in any instance should work, but foreach-object should not be used for a loop in a script. What about the @? Is it simply an alias for foreach? It is not listed by get-alias, but I do see it used often. How (literally) is it interpreted by powershell, both in the shell and in a script?

@ is an array operator, not an alias.

And you can use the cmdlet in a script; it just needs something piped to it, and it’s syntax is different. It has different performance characteristics.

There is no hard and fast rule that says you can’t use Foreach-Object in a script, but it’s generally considered a best practice. I have certainly used it in scripts but if you are processing a ton of data, particularly data that has already been collected and saved in a variable, then using the foreach keyword will generally yield better performance. The performance differences between the two have been hotly debated by people much smarter than me so don’t take my word for it - this is just my preference.

I am not certain what you mean by the ‘@’. Do you mean ‘%’? This is an alias for Foreach-Object and generally aliases should be avoided in scripts just for readability’s sake. They mainly exist to reduce typing in the console. With tab expansion and Intellisense in the ISE I typically use full cmdlet names for scripts and in the console.

Thank you for the clarification, trying to avoid aliases in scripts was why I had used the full foreach-object. I was mixing % for @, since I have seen both used in scripts. And now I know that foreach-object will work in a script if it has pipleline input, but to use only “foreach” for a scriptblock. Is this correct?

Here’s a demonstration that shows how to loop through a collection of files one at a time:

foreach keyword:
$Files = Get-ChildItem c:\data
foreach ($File in $Files)
{
# do something with each file here
}

Foreach-Object cmdlet:
Get-Childitem c:\data | Foreach-Object {# do something with each file here}

Both the Foreach keyword and the Foreach-Object cmdlet take a scriptblock argument and perform that block of code against each item in an array.

Here is a link to an old discussion of foreach vs. foreach-object that I believe is still relevant:

Thank you Don and Matt for your help. Posting my final script for anyone that might find it useful.

#cache the desired permissions for use (this folder was configured correctly using gui) $perms = (get-item "D:\Data\Company Shared Folders\Operations\Administration").getaccesscontrol('Access') #set permissions for folders named Administration $adminfolders = Get-ChildItem 'D:\data\Company Shared Folders\Operations\Current Jobs' -Recurse -Filter "Administration" | Where-Object {$_.psiscontainer} | Convert-Path ForEach ($adminfolder in $adminfolders){ Set-Acl -Path $adminfolder -AclObject $perms }