Set audience on specific node in SharePoint quick launch with powershell - powershell

I'm using a script for setting an audience group for a navigation node in SharePoint. When I set the group It's no problem, or it sets the group but the settings is never pushed through. But If I edit the node in the GUI and just press OK (on both the node settings and navigation settings) the changes goes through.
Script:
$FindString = "Custom link"
Get-SPSite "http://dev:18792/sites/devsite/" | Get-SPWeb -Limit ALL | ForEach-Object {
$web = $_
$_.Navigation.QuickLaunch | ForEach-Object {
$_.Children | ForEach-Object {
if($_.title -eq $FindString){
$node = $_
$node.Properties["Audience"] = "Custom group"
$node.Update()
}
}
}
$web.Update()
}
Am I using the Updates in the wrong place?
EDIT: "SharePoint Server Publishing Infrastructure" feature is activated on the site collection.

Solved it by adding ;;;; before the group name.
$node.Properties["Audience"] = ";;;;Custom group"

Related

If else statement inside foreach results in overwrite each time it loops

I apologize for the unclear title. I'm finding it hard to articulate my problem. I'm writing a script in powershell for the first time. I primarily use python for short scripts but for this task I'm forced to use powershell because of some limitations where I need to use powercli cmdlets. Let me quickly explain the problem. This is to create and/or assign tags to vms in vsphere.
I read the list of VMs into a variable $vms2tag. These are the ones that need to be tagged.
I read a json file into a variable and create tag name and description variables based on the data in the json (there's key value pairs that i can directly plug into the names and descriptions) This file also has a 'Server' key which has a value of the VM name exactly as it would appear in "Output-VM.csv" file. This file has data about every single VM that exists. Only ones that need tagged the ones in $vms2tag
Based on some if else conditions like if tag category exists, or if tag exists, it will either create one or use/assign one.
Basically the following code "works" in the sense it will create these tags BUT, it will quickly get overwritten by the next $vm until it keeps overwriting each time and the only tag that sticks around on all the $vms is the one created for the last VM in the list.
$myJson = Get-Content 'C:\For-Powershell.json'| Out-String | ConvertFrom-Json
$vms2tag = Get-Content 'C:\Output-VM.txt'
foreach ($vm in $vms2tag) {
For ($j=0; $j -lt $myJson.Length; $j++) {
if ($vm -eq $myJson.Server[$j]) {
Write-Output "Match!"
# Variables for Application Owner
$nameAO = [string]$myJson.Application_Owner[$j]
$descriptionAO = [string]$myJson.Application_Owner[$j]
# check if Tag Category and/or Tag exist
if ((Get-TagCategory -Name "app_owner") -eq $null) {
New-TagCategory -Name "app_owner" -Cardinality "Multiple"
}
if ((Get-Tag -Category "app_owner" | Set-Tag -Name $nameAO -Description $descriptionAO) -eq $null) {
$myTagAO = Get-TagCategory -Name "app_owner" | New-Tag -Name $nameAO -Description $descriptionAO
New-TagAssignment -Tag $myTagAO -Entity $myJson.Server[$j]
}
else {
$myTagAO = Get-Tag -Category "app_owner" | Set-Tag -Name $nameAO -Description $descriptionAO
New-TagAssignment -Tag $myTagAO -Entity $myJson.Server[$j]
}
}
}
}
I tested while the script runs and the tag is properly applied to the VM based on its data but when I refresh it after the script completes, all the tags on each VM exist but they are incorrect as they contain the information that's valid only for the last VM in the $vms2tag list. It seems pretty simple but I just don't see where I'm messing up. My guess is something with if else statements is nested incorrectly? It took me a while (~6 hours) to get this to work as I had other issues with the script but when I finally got the tags to correctly set based on the other conditions, I ended up with this problem so it's possible I'm just burnt out and not seeing it.
The problem is with the Tag logic. The following line is overwriting existing tags every loop:
if ((Get-Tag -Category "app_owner" | Set-Tag -Name $nameAO -Description $descriptionAO) -eq $null) {
The Set-Tag cmdlet should never be used in a test to find existing tags.
I would write the test and assignment block like the following:
$myTagAO = Get-Tag -Category "app_owner" -Name $nameAO -ErrorAction SilentlyContinue
if ($myTagAO -eq $null) {
$myTagAO = Get-TagCategory -Name "app_owner" | New-Tag -Name $nameAO -Description $descriptionAO
}
New-TagAssignment -Tag $myTagAO -Entity $myJson.Server[$j]
This ensures that each tag is only created once, with the appropriate description.

How do I change the permissions of a user for 600+ folders in Outlook via PowerShell?

I'm trying to give an assistant access to part of someone's O365 mailbox. She currently has foldervisible permissions on his inbox. And there is about 607 folders under the inbox that she needs access to without having anymore permissions to the inbox itself.
Below is the code I've tried to run. I've removed the domain name but otherwise the code is exact. I've run the code twice and gotten no errors and it runs for a quite a while. But once it's complete, there is no change in the permissions.
ForEach($f in (Get-EXOMailboxFolderStatistics -identity jjo | Where { $_.FolderPath.Contains("jjo:/Inbox/Case Files") -eq $True } ) ) {
$fname = "jjo:" + $f.FolderPath.Replace("/","\");
Add-MailboxFolderPermission $fname -User gka -AccessRights Owner
}
Try to narrow down what's working and not;
Get-EXOMailboxFolderStatistics -identity jjo -ErrorAction Stop | Where-Object { $_.FolderPath.Contains("jjo:/Inbox/Case Files") } | ForEach-Object {
Try {
$fname = "jjo:" + $_.FolderPath.Replace("/","\")
Write-Host "Amending: $fname ..."
Add-MailboxFolderPermission $fname -User gka -AccessRights Owner -ErrorAction Stop
Write-Host "Done"
}
Catch {
$_
}
}
Write-Host "Complete"
On the client side, Extended MAPI (C++ or Delphi) can be used modify the ACL table on the folder level. If using Redemption (I am its author) is an option (any language), you can use RDOFolder.ACL collection to modify the permissions. Something along the lines (VBA, off the op of my head):
ROLE_PUBLISH_EDITOR = &H4FB
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set AddressEntry = Session.AddressBook.GAL.ResolveName("The Other User Name")
set Folder = Session.GetDefaultFolder(olFolderInbox)
for each subFolder in Folder.Folders
set ACE = subFolder.ACL.Add(AddressEntry)
ACE.Rights = ROLE_PUBLISH_EDITOR
next

Find IIS Application Pool not linked to an application via Powershell

I would like to write a powershell script that will find all Application Pool on a server that are not link to an application and then delete the application pool that are not used.
One way I can think of doing this is to retrieve all the Application pool, retrieve all the IIS applications and then cross check the two list. Is there a better way of doing this?
For those interested, here's the code I've written:
$UsedAppPoolList = get-item "IIS:\Sites\*" | foreach { $_.applicationPool; Get-WebApplication -Site $_.Name | foreach { $_.applicationPool } }
$AppPoolExistList = get-item 'IIS:\AppPools\*' | foreach { $_.Name }
foreach ( $AppPool in $AppPoolExistList ){
if ($UsedAppPoolList -notcontains $AppPool){
Remove-WebAppPool $AppPool
write-host "Delete Application Pool $AppPool"
}
}

Powershell - Checking Security Group Members against another list

A bit of context, I am trying to get a list of users from a security group, then check if any of those users do not have an assigned XenDesktop.
Please forgive me, I only started using Powershell yesterday so my formatting is off. It first grabs the users from the AD group then checks if that user has an assigned desktop, which works but I what I can't seem to get working is that if the user is found in that list, I want it to move onto the next username, instead it continues to check against every machine and then onto the final bits of code.
$checkusernames = Get-ADGroupMember "***AD security Group***" | Select SamAccountName
$desktops = get-brokerdesktop -DesktopGroupName Personal_WIN8 | Select MachineName, #{Name='AssociatedUserNames';Expression={[string]::join(“;”, ($_.AssociatedUserNames))}}
foreach ($username in $checkusernames.SamAccountName) {
foreach ($desktop in $desktops) {
If ($desktop.AssociatedUserNames -like "*$username*") {
write-host $username "is assigned to" $desktop.machinename
}
write-host $username "is not assigned to a desktop"
}
Write-host $username "is not assigned to anything"
pause
}
If you want to exit from a ForEach loop early you can do so with the Break keyword. For example:
$checkusernames = Get-ADGroupMember "***AD security Group***" | Select SamAccountName
$desktops = get-brokerdesktop -DesktopGroupName Personal_WIN8 | Select MachineName, #{Name='AssociatedUserNames';Expression={[string]::join(“;”, ($_.AssociatedUserNames))}}
foreach ($username in $checkusernames.SamAccountName) {
$machine = ''
foreach ($desktop in $desktops) {
If ($desktop.AssociatedUserNames -like "*$username*") {
$machine = $desktop.machinename
break
}
}
If ($machine) {
write-host $username "is assigned to" $desktop.machinename
} Else {
write-host $username "is not assigned to a desktop"
pause
}
}
This will stop the current cycle of the inner ForEach loop (once it has completed in it's entirety) without interrupting the ongoing cycle of the outer one.
Per the dicussion in the comments, i've also reorganised the code so that you only get a single output dependent on whether a desktop is matched to a user or not and it only pauses if it does not find a match.

Create Libraries and Permissions with SharePoint Powershell

I'm trying to make a script to help automate this process a bit but am fairly new to using PowerShell with SharePoint and don't really know the route to take.
I have a list of 40 items and I need to make a library for each one. Each library then needs to have unique permissions with 3 default groups(Owners, Members, Visitors). The groups should be named the same as the List.Title + Owners/Members/Visitors.
So far I create a site group as follows:
# Owner Group
$web.SiteGroups.Add(“$web Owners”, $web.Site.Owner, $web.Site.Owner, “Use this group to grant people full control permissions to the $web site”)
$ownerGroup = $web.SiteGroups["$web Owners"]
$ownerGroup.AllowMembersEditMembership = $true
$ownerGroup.Update()
The naming of my groups needs to be the list title and not the web name as I have above.
I create a new library like this:
PS > $spWeb = Get-SPWeb -Identity http://SPServer
PS > $listTemplate = [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary
PS > $spWeb.Lists.Add("My Documents","My Doc Library",$listTemplate)
Clearly this is not automated at all and no faster than just using the GUI to make each new library and adding in the site groups. Can anyone help get me started on a script that would iterate through a list of names create a library and create 3 groups on the site for each new library?
Thanks!!
This should get you on the right track I believe.
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
$Lists = #("My Documents", "My Docs", "Testing")
$Groups = #("Owners", "Members", "Visitors")
$listTemplate = [Microsoft.SharePoint.SPListTemplateType]::DocumentLibrary
$Web = Get-SPWeb "Your_URL"
$Lists | ForEach-Object {
$ListName = $_
$Description = "$_ Description"
$Web.Lists.Add($ListName, $Description, $listTemplate)
$Groups | % {
$GroupName = "$ListName $_"
$Web.SiteGroups.Add($GroupName, $Web.Site.Owner, $Web.Site.Owner, "Group $GroupName created by automatic process")
$group = $Web.SiteGroups["$GroupName"]
if ( !$GroupName -contains "Visitors")
{
$group.AllowMembersEditMembership = $true
} else
{
$group.AllowMembersEditMembership = $false
}
$group.Update()
}
}