Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

Here is the scenario. I only need to run this once as business team just decided their contents are confidential. User Group is "Marketing", will use OOTB "Contribute" and all of marketing items are using "2011 Marketing" content type. The library name is "2011Sales". I need to take out current permissions (also remove inheritance) and only add "Marketing" group with "Contribute" right.

Updated Working Code:

$webUrl = "http://inside.national.com/Sales"
$web = Get-SPWeb $webUrl
$list = $web.Lists["2011Sales"]
$ct = "2011 Marketing"
$spgroup = "Custom SP Group"
$rd="Contribute"

foreach ($item in $list.items) {
    If ($item.ContentType.Name -eq $ct)
     {  
        $item.ResetRoleInheritance() # Not sure if this line is needed
        $item.BreakRoleInheritance($false) # I tried $true but did not work, so leave it at $false
        $item.SystemUpdate() # update without changing the modification date

        $group = $web.AllUsers[$spgroup]
        $roledef = $web.RoleDefinitions[$rd]
        $roleass = New-Object Microsoft.SharePoint.SPRoleAssignment($web.SiteGroups[$spgroup])
        $roleass.RoleDefinitionBindings.Add($roledef)
        $item.RoleAssignments.Add($roleass)
        $item.SystemUpdate() # update without changing the modified date
        Write-Host $item.Name " permission applied"
     }
}
$web.dispose()
share|improve this question
    
So what's the question? –  SHug Sep 20 '11 at 14:53
    
Will the code above implement "Recursive" or "RecursiveAll"? –  Monica Lewinski Sep 20 '11 at 15:52
    
The above code is finally working. However, it doesn't apply permissions for items that are in Document Sets and Folders. But I did a Write-Host $item.Name after the last line $item.Update() and i can see the items that are in folders and doc sets. –  Monica Lewinski Sep 20 '11 at 16:47
1  
OMG, so could you finally decide what the question is?! I've already seen three variants. –  Andrey Markeev Sep 20 '11 at 16:51
    
That's because no one is helping me and I would like provide better code for the new reader who is willing to help me. –  Monica Lewinski Sep 20 '11 at 16:55
show 4 more comments

3 Answers 3

up vote 3 down vote accepted

After breaking the inheritance of an item (item,list,web) you have to call update() on that object to make sure the settings are saved to the database. Once these are saved you can start adding/changing the permissions for that item.

BreakRoleInheritance(false) will not copy the permissions of the parent to the new permissionset, supplying true will copy the permissions.

Updates (see also Vedran Rasols answer)

  • Using foreach(item in list.items) is not recommended, use an SPQuery to select the items and properties you really want, otherwise you will fetch all data from the DB. See also this MSDN Best Practices Article!
  • In theory you shouldn't have to call update(), but in some strange way in helped solving this issue.

bonus: Note that when breaking inheritance on lists the AllowUnsafeUpdate property of the parent web reverts to false, which can be annoying.

share|improve this answer
    
Wrong! You don't need to call Update! –  Vedran Rasol Sep 20 '11 at 19:12
    
Strange, it did help +monica. And i've seen it on other locations. But would be the cause of the problems? I don't see any difference in the code (apart of the SPQuery class) –  Dribbel Sep 20 '11 at 19:27
    
On other hand calling Update() cannot hurt (maybe if you have some event handlers in back). If Update() was really needed then it would be necessary to call it twice (after ResetRoleInheritance() and after BreakRoleInheritance()). However biggest problem with code provided in question is foreach loop and lack of recursive scope. I have tested my code and it works without any problems (and I have more then few similar code snippets working in production enviroments). Note about AllowUnsafeUpdate is ok but I doesn't applies to PS scripts (as far as I know). –  Vedran Rasol Sep 20 '11 at 19:48
    
@VedranRasol: Actually, the foreach loop grabs everything so Recursive/RecursiveAll is included. I had 300+ doc sets and 200+ folders and 1,000+ files in the root of doc lib and foreach took care all of the items. –  Monica Lewinski Sep 21 '11 at 13:58
    
Good thing is that you solved your problem. Bad thing is that people are thinking that foreach on SPList.Items is great (and I am not referring on this answer or question). So every time someone uses foreach little red lamp in my head goes on :) –  Vedran Rasol Sep 21 '11 at 19:51
show 1 more comment

You need to take advantage of SPQuery class. Using CAML query is much, much, much more faster then doing foreach.

Here is script you 'really' want:

$webUrl = "http://inside.national.com/Sales"
$listName = "2011Sales"
$ctname = "2011Sales"
$groupname = "Custom SP Group"

# Get web and list
$web = Get-SPWeb -Identity $webUrl
$list = $web.Lists[$listName]

# Build CAML query
$caml="<Where><Eq><FieldRef Name='ContentType'/><Value Type='Text'>{0}</Value></Eq></Where>" -f $ctname
$query = New-Object Microsoft.SharePoint.SPQuery
$query.Query = $caml
# Set scope to Recursive to include all items from folders and Document Sets
$query.ViewAttributes = "Scope='Recursive'"
# Get our data (only items with proper ct name)
$items = $list.GetItems($query)

# Set Role Assignment
$spGroup = $web.SiteGroups[$groupname]
$spRoleAssignment = New-Object Microsoft.SharePoint.SPRoleAssignment($spGroup)
$sproledefinition = $web.RoleDefinitions["Contribute"]
$sproleassignment.RoleDefinitionBindings.Add($sproledefinition)

foreach ($item in $items) {
    # This is the fastest way of deleting all permissions
    # First you restore inheritance
    # And then you break it
    $item.ResetRoleInheritance()
    $item.BreakRoleInheritance($false)

    # Add new permission
    $item.RoleAssignments.Add($spRoleAssignment)
}

This script will update all items of desired Content Type (including items/files in folders and files in Document Sets). However it will not change permissions of parent Folders or Document Sets.

I have tested this on my dev machine. Feel free to ask additional questions.

share|improve this answer
add comment

Here is the working code in case someone needs it.

$webUrl = "http://inside.national.com/Sales"
$web = Get-SPWeb $webUrl
$list = $web.Lists["2011Sales"]
$ct = "2011 Marketing"
$spgroup = "Custom SP Group"
$rd="Contribute"

foreach ($item in $list.items) {
    If ($item.ContentType.Name -eq $ct)
     {  
        $item.ResetRoleInheritance() # Not sure if this line is needed
        $item.BreakRoleInheritance($false) # I tried $true but did not work, so leave it at $false
        $item.SystemUpdate() # Very Important

        $group = $web.AllUsers[$spgroup]
        $roledef = $web.RoleDefinitions[$rd]
        $roleass = New-Object Microsoft.SharePoint.SPRoleAssignment($web.SiteGroups[$spgroup])
        $roleass.RoleDefinitionBindings.Add($roledef)
        $item.RoleAssignments.Add($roleass)
        $item.SystemUpdate() #Update item without changing the updated date
        Write-Host $item.Name " permission applied"
     }
}
$web.dispose()
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.