Set Multi-User Field in Sharepoint using Powershell and TaskManager - powershell

Im using the following to set/update a multi user field in Sharepoint using Powershell:
[Microsoft.SharePoint.SPFieldUserValueCollection]$lotsofpeople = New-Object Microsoft.SharePoint.SPFieldUserValueCollection
$user1 = $w.EnsureUser("domain\user1");
$user1Value = New-Object Microsoft.SharePoint.SPFieldUserValue($w, $user1.Id, $user1.LoginName)
$user2 = $w.EnsureUser("domain\user2");
$user2Value = New-Object Microsoft.SharePoint.SPFieldUserValue($w, $user2.Id, $user2.LoginName);
$lotsofpeople.Add($user1Value);
$lotsofpeople.Add($user2Value);
$i["lotsofpeoplefield"] = $lotsofpeople;
$i.SystemUpdate($false);
This works great in the PS Editor but as soon as I set this up as a repeating task in Win TaskManager, it fails for all items, where SPFieldUserValueCollection contains more than 1 user. Error: "Invalid look-up value. A look-up field contains invalid data. Please check the value and try again."
Any ideas?

Had the same problem today and it took me some time to solve it.
An explicitly cast solved the problem for me:
$i["lotsofpeoplefield"] = [Microsoft.SharePoint.SPFieldUserValueCollection] $lotsofpeople
$i.SystemUpdate($false);

Related

Uploading a Terms of Use PDF via Powershell to Azure using Graph

I've just started trying to use the MgGraph module to try and perform operations on an Office 365 tenant to perform some configuration automation and I'm having a hard time wrapping my head around some of these cmdlets - in particular, the one I'm currently messing around with, New-MgAgreement, in an attempt to automatically upload a terms of use file.
I guess, for starters, is this a viable path to achieving this? Is there some other method I should attempt to be using to try and accomplish this? And if not, I guess how do I go about actually doing this? In short, this is what I've attempted:
I'm utilizing a file picker via Windows Forms to prompt to capture the file I wish to upload
I've created a hash for the File parameter of the cmdlet to satisfy the properties needed (I thought...) as well as filling out the other parameters needed to provide information about the terms of use object being created on the tenant
When I try to run the command, I was initially told that "value cannot be null - parameter name source" which makes sense because I didn't see any parameters specifying source in the documentation for the physical file, so I tried simply adding a "source" parameter to the New-MgAgreement cmdlet thinking I just missed it in the documentation, but upon trying to do that, it tells me "a parameter cannot be found that matches parameter name 'source'.
Just to give an idea of my mindset when trying to achieve this, this is a code snippet hopefully illustrating the direction I'm trying to go about doing this:
Function Main {
Connect-Modules
Set-Tenant-Terms-Of-Use
Get-Tenant-Terms-Of-Use
}
Function Connect-Modules {
Connect-AzureAD
$tenantId = Get-AzureADTenantDetail | Select-Object ObjectId
C:\Windows\System32\cmd.exe /c start shell:AppsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge -private https://microsoft.com/devicelogin
Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All", "Agreement.Read.All", "Agreement.ReadWrite.All" -TenantId $tenantId.ObjectId.ToString()
}
Function Set-Tenant-Terms-Of-Use {
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{
InitialDirectory = [Environment]::GetFolderPath('Desktop')
Filter = 'PDF (*.pdf)|*.pdf'
}
$companyName = Read-Host "Please enter your company name: "
$null = $FileBrowser.ShowDialog()
$fileHash = #{
DisplayName = "All users terms of use";
FileName = $FileBrowser.SafeFileName
IsDefault = $true
IsMajorVersion = $true
Language = "English (Default)"
}
New-MgAgreement -DisplayName "$companyName Terms of Use" -File $fileHash -source $FileBrowser.FileName
}
Function Get-Tenant-Terms-Of-Use {
$termsOfUse = Get-MgAgreement | Select-Object Id, DisplayName
Write-Host $termsOfUse.Id.ToString()
Write-Host $termsOfUse.DisplayName.ToString()
}
Main
Disconnect-MgGraph
I'll admit... I'm kind of completely lost on this one - I haven't really worked with Graph previously and I'm trying to get the hang of it since it seems to have a lot of capabilities that hook into areas of an Azure/O365 tenant that the other modules I'm used to using do not. I appreciate any schooling I can get on the topic! Thank you!
EDIT - So I can get this to work the way I want via Graph Explorer... I realized I needed to convert my file to base64 and put the value under the data property under the FileData parameter from within the File Parameter... but when I try to mirror this in PowerShell using the same parameter values as what is included in Graph Explorer I just get a "New-MgAgreement: Value cannot be null. Parameter name: source"... so it's just that I don't know how to format this using the cmdlet... and I just can't wrap my head around how to use the complex parameters apparently given the documentation.
I was able to reproduce this issue. As an alternative, you can use Invoke-MgGraphRequest passing in the agreements endpoint and upload the agreement - this worked for me see below:
Agreement Resource Sample Data
$data
{
"displayName": "MSGraph Sample",
"isViewingBeforeAcceptanceRequired": true,
"files": [
{
"fileName": "TOU.pdf",
"language": "en",
"isDefault": true,
"fileData": {
"data": "SGVsbG8gd29ybGQ="
}
}
]
}
#Using IGR
Invoke-MgGraphRequest -Uri https://graph.microsoft.com/v1.0/agreements -Method POST -Body $data
Please let me know if this helps and if you have further questions.

PowerShell SetAccessRule for ACL failing

The script I've done creates a folder and security groups that is later added to the folder in question with special permissions. The problem is that the script fails on "$acl.SetAccessRule($rule_modify)" and complains about the identity.
Error:
"Exception calling "SetAccessRule" with "1" argument(s): "Some or all identity references could not be translated."
If I run the script row by row by simply using copy/paste from ISE into a regular PowerShell window everything goes through without errors using the same location and user.
This is the important bit that isn't working.
#Get ACL list
$acl = Get-Acl -Path $Path
$acl.SetAccessRuleProtection($false,$false)
#Add permission for modify
$set_modify = "INTRA\FIL_$($Department)_$($Group)_Modify", 'DeleteSubdirectoriesAndFiles, Write, ReadAndExecute, Synchronize', 'ContainerInherit, ObjectInherit', 'None', 'Allow'
$rule_modify = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $set_modify
$acl.SetAccessRule($rule_modify)
$acl | Set-Acl $path
I had basicly the same issue but with "AddAccessRule".
$Acl.AddAccessRule($Ar)
My Script failed with the above mentioned error.
Just as Patrik Persson mentioned, in my case it was also because AD was slow on showing new groups and the Ar could not be added until the security group showed up in my AD.
So i added a try/catch with a do/until loop to my script which i want to share:
do {
$check = 'ok'
try {
$Acl.AddAccessRule($Ar)
} catch [System.Management.Automation.RuntimeException] {
$_.Exception.Message
$check = 'error'
Start-Sleep -Seconds 2
}
} until (
$check -eq 'ok'
)
So the loop continues until AD registers the security group correctly. After that the Ar is added to the acl and my script continues as expected.
I have found the solution and it fails because ActiveDirectory is too slow to recognize that the security group is created propery before adding it to the ACL.
Solution I went with was to add a 10 second sleep after groups and folder was created and it now works as intended.
You might want to expand all the strings you're using to build your security group name into a clean variable - I find that can be touchy. Make sure that $secgroup contains the right string value when you've constructed it.
You can create the rule together with the object type on one line as well.
$secgroup = "INTRA\FIL_$($Department)_$($Group)_Modify"
$modifyRule = New-Object System.Security.AccessControl.FileSystemAccessRule($secgroup,'DeleteSubdirectoriesAndFiles, Write, ReadAndExecute, Synchronize','ContainerInherit, ObjectInherit','None','Allow')
By the way, if essentially you want your users to have Modify rights on the contents without being able to delete the parent folder, it should work if you set the InheritOnly flag (I haven't tested it).
$modifyRule = New-Object System.Security.AccessControl.FileSystemAccessRule($secgroup,'Modify, Synchronize', 'ContainerInherit, ObjectInherit','InheritOnly','Allow')
Had a similar issue while creating shares on remote file servers.
At first, I'd used the proposed solution (start-sleep), but it was not good enough as it significantly increased the time consumed while processing a lot of shares.
It turns out that you may use SID while defining your ACE and operation is instant:
$TempSID = (Get-ADGroup "FIL_$($Department)_$($Group)_Modify").SID
$PermissionModify = "Write, Read, ListDirectory, ReadAndexecute, DeleteSubdirectoriesAndFiles"
$Inherit = [system.security.accesscontrol.InheritanceFlags]"ContainerInherit, ObjectInherit"
$Propagation = [system.security.accesscontrol.PropagationFlags]"None"
$Type = "Allow"
$modifyRule = New-Object System.Security.AccessControl.FileSystemAccessRule($TempSID, $PermissionModify, $Inherit, $Propagation, $Type)
Seems that Active Directory needs some time (in my case 2 seconds) to translate SID to the group name (in DOMAIN\groupName format).
Another case: I have got the error Exception calling SetAccessRule... because I have set the account without the domain, so - with the question's example - I have put .\FIL_$($Department)_$($Group)_Modify instead of INTRA\FIL_$($Department)_$($Group)_Modify.

InternetExplorer.Application COM object's getElementById method not working

I am very new to powershell, and I am trying to automate a login to website, I have browsed many examples but NONE is working without errors.
For example with this very simple script:
$ie = New-Object -comobject InternetExplorer.Application
$ie.Visible = $true
$ie.Navigate($URL)
$ie.Navigate("www.facebook.com")
$ie.document.getElementById("pass")
$ie.document.getElementById("pass").value = "Hi"
I am supposed to get "Hi" in the password field but I get instead this
I am getting this error in ALL the examples I found, what's going on? Is this something no longer supported in Powershell?
I have windows 10.
Don't use getElementById. Use IHTMLDocument3_getElementById, e.g.:
$ie.Document.IHTMLDocument3_getElementById("email").value = "asd123"
You can do this for other methods as well, such as IHTMLDocument3_getElementsByName.
I should add that I don't know why this works - I just used the following query to find any useful looking members on the Document object and played around with them
$ie.Document | Get-Member | where Name -like '*get*'

POWERSHELL - The member's SID could not be resolved

Hello im working with Active Directory Group and Users and i wanna check and set proper Users/Groups from AD to machines. Problem is when i iterate over Local Users/Groups on some machine and there is old Users/Group that no longer exists in AD POWERSHELL will stop working and will throw exception.
An error (1332) occurred while enumerating the group membership. The member's SID could not be resolved.
I know what causes this problem but i dont know how to work around it. The main issue here is that its not even possible to iterate over whole array of users if one is no longer valid. Only solution to this is manualy delete those invalid users.
I even saw some reports to Microsoft that this behaviour is wrong and should be fixed but nothing was done about it.
Anyone here encountered this issue?
Thank you for your help.
$ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
$computer = "PC name"
$groupName = "Administrators"
$context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype, $computer
$idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
$groupData = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, $idtype, $groupName)
$groupData.Members | select #{N='Server'; E={$computer}}, #{N='Domain'; E={$_.Context.Name}},#{N='Group'; E={$groupName}} , #{N='Account Name/Group'; E={$_.SamAccountName}}
Here is example of code that im using for iterating over Local users/groups on some PC.
Can You post the code that you are using, and the full error. Im guessing there is a workaround, but without seeing your code I can't see what could be wrong. If a terminating error is thrown it will stop the script or function from running further (with some gotchas, and exceptions), there are many ways of working around this
Also could you post the full error.
You will probably need to set the $erroractionpreference to silentlycontinue. And then review the $error variable to check the errors, but again I am only speculating.

How to query for members of an LDAP group using Powershell not in MS Active Directory

All I am trying to accomplish is to return if an LDAP group has any members in it. So, I have a list of groups, and I want to query each one for a list of members to ensure there is at least 1 member in every group.
I am using powershell and this is NOT Active Directory.
This is currently what I am trying
$user = "username"
$pwd = "password"
$de = "LDAP://[SERVERNAME]/cn=user,ou=people,o=company"
$deObject = New-Object -TypeName System.DirectoryServices.DirectoryEntry($de,$user,$pwd,'FastBind')
This returns a DirectoryEntry object (at least as far as I can tell). I can't really see any attributes or anything except for if I do the following:
$deObject.Name
This returns the cn of "user" and that's it. Any suggestions?
I've tried:
$deObject.Properties
$deObject.Properties['member']
$deObject.Properties.Values['member']
Thanks in advance!
This will show you all the properties there are:
$deObject | Format-List * -force
And this will return you the number of members in a group:
$deObject.member.Count