5

I'm pretty new to Powershell, but I have lots of experience in VBScript and Python. I'm trying to be a good Windows admin and get into Powershell more. So, here is what I'm trying to do: A parent folder contains dozens of sub-folders that are named as AD usernames (ex. Users\username1, Users\username2, where Users is the parent folder). I want to loop through each folder name, parse out the sub-folder name, and pass that to icacls to apply permissions based on the username. I did a multi-liner because I was running into issues piping. This is what I have after trying several different approaches:

$root_folder = "c:\temp\test"
$cmd1 = "icacls "
$cmd2 = " /grant cm\"
$cmd3 = ":`(OI`)`(CI`)F"
$paths_collection = get-childitem $root_folder | foreach-object -process {$_.FullName}
foreach ($path in $paths_collection)
{$string = $path.split("\");$last = $string[-1];$command = $cmd1 + $path +$cmd2 +$last +$cmd3;invoke-expression $command}

It wasn't originally this rough, but I started breaking it apart when I was running into issues.

THE PROBLEM - in $cmd3, the (OI)(CI) is not coming in cleanly to the invoke-expression. If I change $cmd3 to just ":F" it works, but I have to set inheritance using the offending parameters. PLEASE HELP. I've been racking my brain all day on this one. Couldn't really find anything that dealt with this issue specifically (tried backticks, referencing the $command as '$command', etc.)

ERROR: The term 'OI' 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. At line:1 char:56 + icacls C:\temp\test\garthwaitm /grant domain\user1:(OI <<<< )(IO)F + CategoryInfo : ObjectNotFound: (OI:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException

Matt G.
  • 51
  • 1
  • 1
  • 2
  • For what it's worth, string concatenation is a lot easier than you are making it here. You could also do:`$command = "$cmd1$path$cmd2$last$cmd3` and then print it to see what it's running. What's the output if you just write out that variable? – JNK Dec 20 '11 at 20:33
  • I did that and it prints out the string correctly. However, it's when the Invoke-Expression gets called that it doesn't parse correctly (I believe). I think bobbymcr got it below. Thanks though! – Matt G. Dec 20 '11 at 20:42

3 Answers3

8

Just to add to this old question, in PowerShell 3.0 you can now use --% to tell PowerShell to stop processing anything else on the line, so you can use something like this:

icacls.exe $path --% /grant "Everyone:(OI)(CI)(F)"

Daniel Morritt
  • 1,787
  • 17
  • 25
  • 2
    This worked for me. As an example, `icacls "\\foo\doo\who" /GRANT c123123:(OI)(CI)(M)` did not run but the following did: `icacls "\\foo\doo\who" /GRANT "c123123:(OI)(CI)(M)"` – nate Mar 22 '22 at 21:07
2

I think you are unnecessarily complicating it.

Get the echoargs.exe from Powershell Community Extensions.

See if something like below is what you wanted:

PS >.\EchoArgs.exe /grant $path "cm\$last" ":(OI)(CI)F"
Arg 0 is </grant>
Arg 1 is <c:\test>
Arg 2 is <cm\user>
Arg 3 is <:(OI)(CI)F>

Then call it with the command you want:

&icacls /grant $path "cm\$last" ":(OI)(CI)F"

BTW, you can use Split-Path to get the $last. And use select -expand fullname instead of the foreach-object -process {$_.FullName}

manojlds
  • 290,304
  • 63
  • 469
  • 417
  • Wow, this is all great information. Thanks manojlds! Like I said, really trying to get familiar with Powershell. Never even heard of EchoArgs.exe, looks great! – Matt G. Dec 20 '11 at 21:39
  • @MattG. if you don't want to download an external app you could simply write a console application that prints the 'args' elements. – mjsr Dec 20 '11 at 23:13
0

Have you tried using quotes around $command, e.g. Invoke-Expression "$command"? Other techniques for preventing parentheses from being processed are discussed here: http://msdn.microsoft.com/en-us/library/cc281841.aspx

bobbymcr
  • 23,769
  • 3
  • 56
  • 67