Add RoleAssignment Member to SPItem Using PowerShell - powershell

I will be executing a script to remove permissions from a SPitem. However, a rollback plan is required and I am required to create a separate script which will add the permission of the user back to the SPitem if required.
Below is my code snippet which removes a user from the SPitem:
ForEach ($RDfolderId in $RDfolderSplit)
{
$query = New-Object Microsoft.SharePoint.SPQuery
$query.ViewXml = "#<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='Title' /><Value Type='Text'>$RDfolderId</Value></Eq></Where></Query></View>"
$RDfolder = $RDlist.GetItems($query)
foreach($role in $RDfolder.RoleAssignments)
{
if ($role.Member.Name.Equals($userToAction))
{
#$RDitem.BreakRoleInheritance($true)
#$RDitem.RoleAssignments.RemoveById($roleAssignment.Member.ID)
#$RDitem.Update()
}
}
}
I have seen code samples online on adding roles back to the SPitem. However, there is an additional field RoleDefinitions declared.
Is it compulsary to have the value declared when adding a user to a SPitem?
Below is the code sample for adding:
$web = Get-SPWeb http://sp-2010
$account = $web.EnsureUser("SHAREPOINT\mray")
$role = $web.RoleDefinitions["Contribute"] #is this value compulsory?
$list = $web.Lists["Shared Documents"]
$list.BreakRoleInheritance($true)
$assignment = New-Object Microsoft.SharePoint.SPRoleAssignment($account)
$assignment.RoleDefinitionBindings.Add($role)
$list.RoleAssignments.Add($assignment)
$list.Update()
$web.Dispose()
source

Short answer - Yes.
Let's break this sample up and explain each part:
$web = Get-SPWeb http://sp-2010
$web - SharePoint Web object aka. Site we are working on.
$account = $web.EnsureUser("SHAREPOINT\mray")
$account - User account we are working with.
$role = $web.RoleDefinitions["Contribute"] #is this value compulsory?
$role - This is the Role Definition aka permissions like Contribute/Read/Approve. Yes. This is mandatory as it is the permissions you are going to add back.
$list = $web.Lists["Shared Documents"]
$list - The List we are working with.
$list.BreakRoleInheritance($true)
BreakRoleInheritance - This is if we need unique permissions on the List and to turn inheritance off. We don't have to do this every time, and likely in this example, you don't have to break inheritance.
Now, we are onto the permissions pieces.
$assignment = New-Object Microsoft.SharePoint.SPRoleAssignment($account)
$assignment - First, we need to get all the SharePoint roles currently assigned to our user.
$assignment.RoleDefinitionBindings.Add($role)
Add($role) - Add the Role Definition i.e. "Contribute" to the user object. This does nothing to the list on SharePoint.
$list.RoleAssignments.Add($assignment)
Add($assignment) - Add user with the new permissions to the List object. This does nothing to the list on SharePoint. We are manipulating the end state of the list that we want.
$list.Update()
Update - Now do something on SharePoint. Actually apply the changes we have made to the List object to SharePoint.
$web.Dispose()
Dispose - cleanup our objects.
Now. Saying all of that. This is a good script for setting permissions. You also have a script for removing permissions. The point of a rollback script is that you need to record what those permissions originally were before you remove them. i.e. once you remove them, there isn't a magic undo button. ;-)

Related

How to replace/update the Value of an Attribute in LDAP Directory using PowerShell?

The entries in our companys Non-AD LDAP Server look like this:
uid = e145871
sn = Smith
givenName = John
department = Research & Development
department = Human Resource
And so on...
I've developed a PowerShell script to add specific attributes and values which is working just fine. Now I need to replace specific values but the issue is the identical attribute name. (In this case it's "department")
My goal is to replace "Research & Development" with "Something Else". If I run the following script it gets replaced but Human Resource is deleted as well. Is it possible to replace only one value without touching/deleting the other?
$r = New-Object -TypeName System.DirectoryServices.Protocols.ModifyRequest
$r.DistinguishedName = "uid=e145871,ou=identities,ou=users,o=items,dc=company,dc=domain,dc=com"
$DirectoryRequest_value = New-Object "System.DirectoryServices.Protocols.DirectoryAttributeModification"
$DirectoryRequest_value.Name = "department"
$DirectoryRequest_value.Contains("Research & Development")
$DirectoryRequest_value.Operation = [System.DirectoryServices.Protocols.DirectoryAttributeOperation]::Replace
$DirectoryRequest_value.Add("SomethingElse")
$r.Modifications.Add($DirectoryRequest_value)
$result = $connection.SendRequest($r)
Thanks!
The LDAP Replace operation replaces (or overwrites) the entire value of the attribute, including any existing values that might exist as part of a multi-valued attribute.
From RFC4511 §4.6 - "Modify Operation":
- operation: Used to specify the type of modification being
performed. Each operation type acts on the following
modification. The values of this field have the following
semantics, respectively:
[...]
replace: replace all existing values of the modification
attribute with the new values listed, creating the attribute
if it did not already exist. A replace with no value will
delete the entire attribute if it exists, and it is ignored
if the attribute does not exist.
Instead, add two separate modifications to the request - one to add "SomethingElse" and one to remove "Research & Development":
$targetObject = 'uid=e145871,ou=identities,ou=users,o=items,dc=company,dc=domain,dc=com'
$attributeName = 'department'
$oldValue = 'Research & Development'
$newValue = 'SomethingElse'
$request = [System.DirectoryServices.Protocols.ModifyRequest]::new()
$request.DistinguishedName = $targetObject
# This modification will add the new value "SomethingElse"
$addNewDepartment = #{
Name = $attributeName
Operation = 'Add'
} -as [System.DirectoryServices.Protocols.DirectoryAttributeModification]
$addNewDepartment.Add($newValue) |Out-Null
$request.Modifications.Add($addNewDepartment) |Out-Null
# This modification will remove the old value "Research & Development"
$removeOldDepartment = #{
Name = $attributeName
Operation = 'Delete'
} -as [System.DirectoryServices.Protocols.DirectoryAttributeModification]
$removeOldDepartment.Add($oldValue) |Out-Null
$request.Modifications.Add($removeOldDepartment) |Out-Null
$result = $connection.SendRequest($request)

Outlook Distribution Lists (DistListItem) are not updated after a referenced contact (ContactItem) is changed

I've gathered some code from around the web to create Contacts and then Contact groups. However, if I update the contact after creation, the "relation" between the contact object inside the Contact group and the Contact is gone. The Contact group is not updated with the changes to the Contact.
If I manually create a Contact and Contact group, the relationship is just maintained as expected. Any ideas on what I could have missed?
Code for the Contact:
$olContactItem = 2
$o = new-object -comobject outlook.application
$c = $o.CreateItem($olContactItem)
$c.FullName = "Dummy Account"
$c.Email1Address = "aa#bb.com"
$a = $c.Save()
Code for the Contact group:
$outlook = new-object -com Outlook.Application
$contacts = $outlook.Session.GetDefaultFolder(10)
$session = $outlook.Session
$session.Logon("Outlook")
$namespace = $outlook.GetNamespace("MAPI")
$DL = $contacts.Items.Add("IPM.DistList")
$DL.DLName = "dummy2"
$recipient = $namespace.CreateRecipient("Dummy Account")
$recipient.Resolve()
$DL.AddMember($recipient)
$DL.Save()
Looks pretty straight forward to me. I checked the API, but that didn't get me much further.
https://msdn.microsoft.com/en-us/vba/outlook-vba/articles/recipients-object-outlook
Thanks in advance!
You add $recipient before it is initialized.
UPDATE: DistListItem.AddMember in OOM only adds one-off recipients, there is no way to add contacts. If using Redemption (I am its author) is an option, it exposes RDODistListItem.AddContact method that allows to pass either Outlook's ContactItem object or RDOContactItem object from Redemption. RDODistListItem also exposes AddMembers / AddMember / AddMemberEx methods.

Powershell - Outlook Mark all mails as read then delete

having some problems trying to figure this one out.
For some reason my script is not working as it should.
It should mark all mails in inbox folder as read and then delete them.
However, when the script runs it only delete's half of the .count $emails show...
How to solve this, am I doing something wrong?
$outlook = new-object -comobject outlook.application
#Define folders
$namespace = $outlook.GetNameSpace("MAPI")
$pst = $namespace.Stores
$pstRoot = $pst.GetRootFolder()
$pstFolders = $pstRoot.Folders
#$personal = $pstFolders.Items("ARCHIVE") ##Not working, sadly.
$DefaultFolder = $namespace.GetDefaultFolder(6)
$InboxFolders = $DefaultFolder.Folders
$DeletedItems = $namespace.GetDefaultFolder(3)
$Emails = $DefaultFolder.Items
Foreach ($Email in $Emails) {
#Define folders
$Email.UnRead = $false
$Email.Move($DeletedItems) | out-null
continue
}
I would suggest using the MailItem.Delete() method instead of moving things to the Deleted Items folder. From the Delete() method page:
The Delete method deletes a single item in a collection. To delete all
items in the Items collection of a folder, you must delete each item
starting with the last item in the folder. For example, in the items
collection of a folder, AllItems, if there are n number of items in
the folder, start deleting the item at AllItems.Item(n), decrementing
the index each time until you delete AllItems.Item(1).
The Delete method moves the item from the containing folder to the
Deleted Items folder. If the containing folder is the Deleted Items
folder, the Delete method removes the item permanently.
With that knowledge I would suggest replacing your ForEach loop with the following:
For($i=($emails.count-1);$i -ge 0;$i--){
$($emails)[$i].Unread = $false
$($emails)[$i].delete()
}
I don't understand why you have to sub-expression the collection in order to enumerate it, but I've never been able to specify a record without doing that.
Do not use "foreach" loop since you are modifying the number of items in the collection. Use a loop from Items.Count down to 1.

Powershell, retrieve users manager

I'm creating a csv type org chart and was just wondering what would be the preferred to retrieve a users manager, manager's manager, ... etc up to the highest position. Currently i'm using:
[string]$man = $userEntry.manager
[array]$manName = $man.split('=,')
$manager = $manName[1]
$item.Cells.Item($i,1) = $userEntry.name.value
$item.Cells.Item($i,2) = $userEntry.description.value
$item.Cells.Item($i,3) = $manager.ToString()
then running get-QADobject to find the next manager by their DN.
but there must be a much cleaner way!
Thanks
If I'm understanding you correctly, you want to follow the chain of command all the way up to the very top (where presumably that person has no manager?). In that case, you need to recursively walk up the tree.
Untested pseudocode as I don't have a domain handy at the moment to test with:
Function Get-Manager {
params(
[string]$username
)
$userEntry = get-qaduser $username
[string]$man = $userEntry.manager
if (-not ($man -eq $null)) {
[array]$manName = $man.split('=,')
$manager = $manName[1]
"$manager is the manager of $username";
Get-Manager $manager
}
}
This will come to a halt once a user has no manager. In my organization's case, our CEO is listed as his own manager, so I'd change the above code to look for the manager to be non-null or equal to the user, so that either of those conditions being true broke the loop.

PowerShell - SCOM PropertyBag, How to check if already added?

I want to add values to a PropertyBag.
How is it possible to check if the value is already in the PropertyBag?
I know one can use an array, list, etc. But how can I use the $bag/$api object to do this check?
$api = New-Object -comObject “MOM.ScriptAPI”
$bag = $api.CreatePropertyBag()
$bag.AddValue("TestValue1","1234")
I'm searching for something like this:
if($bag -match "TestValue1")
{"In the Bag!"}
But, unfortunately, it's not working.
I do not have SCOM on a server I can access, but could you do the following to get the bag contents and check against it?
$api = New-Object -comObject “MOM.ScriptAPI”
$bag = $api.CreatePropertyBag()
$bagContents = $api.Return($bag)