I have an issue with a PowerShell script written for SharePoint 2010, it is only working on one site collection http://company/, it lists all the pages using a Content Editor Web Part with Image Maps, once the loop goes to the next site collection it returns nothing.
As the script loops through all the other site collections, it returns nothing to $publishingPages - I can see $publishingWeb loading correctly and returning its data but I get nothing from:
$publishingWeb.GetPublishingPages($publishingWeb)
I've ran the script using different SharePoint accounts (Setup, Farm, Admin, etc), the results are always the same, I have no clue what I could be possibly doing wrong here!
Here's my code:
Start-SPAssignment -Global
$SPWebApp = Get-SPWebApplication "http://company/"
foreach ($site in $sites)
{
foreach ($web in $site.AllWebs)
{
Write-Host `n "-" $web.Url `n -ForegroundColor Green
if ([Microsoft.SharePoint.Publishing.PublishingWeb]::IsPublishingWeb($web))
{
$publishingWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
$publishingPages = $publishingWeb.GetPublishingPages($publishingWeb)
foreach($page in $publishingPages)
{
$manager = $web.GetLimitedWebPartManager($page.Url, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)
$allWebParts = $manager.WebParts
$onlyCEWP = $allWebParts | ? {$_.GetType() -eq [Microsoft.SharePoint.WebPartPages.ContentEditorWebPart]}
$imageMaps = $onlyCEWP | ? {$_.Content.InnerText -match '<map name='}
if ($imageMaps -ne $null)
{
Write-Host `t " - " $page.Url
}
}
}
$web.Dispose()
}
$site.Dispose()
}
Stop-SPAssignment -Global
There was nothing wrong with the script above, it turns our my customer had placed all pages outside the Pages library, therefor a script find pages once a library is empty :)
Related
I am trying to put together a small script that finds all emails in an org box that match a given search term and display the full path to each result.
While what I have works in my personal inbox and recurses through all subfolders, when I try and use it on the Org box it only searches the current directory and does not recurse.
Is there something I am missing that is unique to working with Org boxes?
$OL = New-Object -ComObject Outlook.Application
$NS = $OL.GetNameSpace('MAPI')
$MB = $NS.createRecipient('SomeOrgBox#mail.com')
if ($MB.Resolve) {
$Inbox = $NS.GetSharedDefaultFolder($MB,[Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
} else {
Write-Warning "Unable to access inbox
"
pause
exit
}
Register-ObjectEvent -InputObject $OL -EventName "AdvancedSearchComplete" - Action {
if ($Args.Results) {
Write-Host " - Results -
"
Foreach ($Result in $Args.Results) {
Write-Host $Result.Subject
Write-Host $Result.Parent.FolderPath
}
Write-Host ""
Write-Host " - End of results -"
} else {
Write-Host " - No Results found -"
}
Write-Host ""
}
Function Search-Inbox {
$Search = $OL.AdvancedSearch("'"+$Inbox+"'", "urn:schemas:httpmail:subject like '%"+$Query+"%'", $true)
}
$Query = Read-Host " Enter Search Term "
Search-Inbox
Edit:
To clarify, this will be used on Windows machines and third-party tools are not an option.
Also, after some testing, it seems that how the Org box was added to Outlook plays a role in this issue.
If the account is associated with you through your personal account's advanced options, the search does not recurse.
If the Org box was added as an additional Email account through the 'Add Account' dialog recursion works just fine.
If I was the only one using this, I could just change how I have the account set up, but since other people have to use it as well, it's not the most ideal solution. For now, I'll run with it until a solution can be found for accounts set up the other way.
Found one part of my answer here, Get dbname from multiple web.config files with powershell
But need it to recurse through the IIS Sites and all the Web Apps inside those 'Sites'. I have multiple IIS 'Sites' with multiple Web Apps in each 'Site' need to check each ones web.config file and pull the db used. Cant figure out how to recurse the code in the link above.
#Code from link above.
Import-Module WebAdministration
Get-WebApplication |
ForEach-Object {
$webConfigFile = [xml](Get-Content "$($_.PhysicalPath)\Web.config")
Write-Host "Web Application: $($_.path)"
foreach($connString in $webConfigFile.configuration.connectionStrings.add)
{
Write-Host "Connection String $($connString.name): $($connString.connectionString)"
$dbRegex = "((Initial\sCatalog)|((Database)))\s*=(?<ic>[a-z\s0-9]+?);"
$found = $connString.connectionString -match $dbRegex
if ($found)
{
Write-Host "Database: $($Matches["ic"])"
}
}
Write-Host " "
}
Would like this to output the database name of each web.config file for each IIS Site and for each Web App in the IIS Site. Currently this only looks at the first web app in a IIS Site, and doesnt look at any others in the IIS Site, also doenst look to see if the IIS Site's web.config has a connection string to a DB.
Here is the code for you, from your reference I have changed looping mechanism not the actual logic to get the db name.
Import-Module WebAdministration
Get-Website | % {
$AppList = Get-WebApplication -Site $_.Name
foreach ( $app in $AppList )
{
$app.PhysicalPath
$webConfigFile = [xml](Get-Content "$($app.PhysicalPath)\Web.config")
# NEED TO CHECK WEATHER THE $webConfigFile FILE EXIST OR NOT
Write-Host "Web Application: $($_.path)"
foreach($connString in $webConfigFile.configuration.connectionStrings.add)
{
Write-Host "Connection String $($connString.name): $($connString.connectionString)"
$dbRegex = "((Initial\sCatalog)|((Database)))\s*=(?<ic>[a-z\s0-9]+?);"
$found = $connString.connectionString -match $dbRegex
if ($found)
{
Write-Host "Database: $($Matches["ic"])"
}
}
} # END OF INNER FOR EACH LOOP
} # END OF OUTER FOR EACH LOOP
Here is the basis of my question, I am trying to remove a very large list of users from all site collections in multiple web applications. My overall goal is to remove roughly 50,000 users from almost 10,000 site collections (all site collections in about 15 web applications).
I currently have a way of doing this by having a list of users and a list of sites, and simply looping through the sites and removing each user from each site.
I'm wondering if there is a more efficient way of doing this, and or if there is a way to remove a user from a web application and have that cascade down through each of the site collections.
Below is what I currently have:
$users = get-content $userList
$sites = get-content $siteList
Write-Host "Getting all listed sites"
Write-Host "Getting all listed users"
$siteArray = #()
for ($i=0; $i -lt $sites.length; $i++)
{
try
{
$rmUserCount = 0
$userNotExist = 0
$failedRm = 0
Write-Host "Working on" $sites[$i]"..."
for ($c=0; $c -lt $users.length; $c++)
{
Write-Host "Attempting to remove user" $users[$c] -ForegroundColor Yellow
try
{
write-host $isuser
$isUser = Get-SPUser -Identity $users[$c] -web $sites[$i] -ErrorAction SilentlyContinue
}
catch
{
}
if($isUser)
{
try
{
Remove-SPUser -Identity $users[$c] -Web $sites[$i] -Confirm:$false
Write-Host "The user" $users[$c] "was removed from the site" $sites[$i] -ForegroundColor Green
$rmUserCount++
}
catch
{
Write-Host "The user still exists and was not removed" -ForegroundColor Red
$failedRm++
}
}
else
{
$userNotExist++
Write-Host "user" $users[$c] "does not exist on" $sites[$i]"... moving on"
}
$isuser=$null
}
$addInArrayOut = $rmUserCount.ToString() + " users removed from " + $sites[$i].ToString() + ", " + $userNotExist.ToString() + " users did not exist on the site, " + $failedRm.ToString() + " users failed to be removed"
$siteArray += $addInArrayOut
}
catch
{
Write-Host $_ $Error[0] -ForegroundColor Red
}
}
From my calculations using measure command, I can remove roughly 10 users per second, but this still means that it would take hundreds of days to complete this task, leaving me thinking that there must be a better way of doing this.
I tried adding the web application url as one of the sites in the array and it didn't work like I thought it would, as it didn't remove the user from each of the site collections within it.
If anyone has any idea of how to do this better, or a way of drastically speeding up what I have I would really appreciate it. Thanks!
I'm writing a form which will perform iisreset to remote servers.
The server name I'm getting from the user who needs to select them from a checkbox list.
My problem is that even if the user choses one server, the code processes it like he chose 2.
if ($CBLUKSTG.Visible -Match $true)
{
[array]$chosenServers = $CBLUKSTG.Items
foreach ($item in $chosenServers)
{
Invoke-Command –ComputerName $chosenServers –ScriptBlock { iisreset /noforce }
Invoke-Command –ComputerName $chosenServers –ScriptBlock { iisreset /status }
Write-Host "IIS restarted succefully on $item"
}
What am I doing wrong?
I think your issue is coming from this line: [array]$chosenServers = $CBLUKSTG.Items. Looking at TechNet for .Items you will see that it
Gets the collection of items in this CheckedListBox.
That would return all items from the list. What you need to be doing is only returning [array]$chosenServers = $CBLUKSTG.CheckedItems. So you should be checking CheckedItems.
Collection of checked items in this CheckedListBox.
Exchange Management Shell:
[PS] C:\Windows\system32>$AddressBook = Get-PublicFolderItemStatistics -Identity "\Shared Company Address Book"
[PS] C:\Windows\system32>$AddressBook [0] | format-list
RunspaceId : d8e95055-1f3e-4e7f-a1fc-d5b97ecbcb96
ServerName : MAILMAN
DatabaseName : Public Folder Database 0524088380
Subject : John Q User
PublicFolderName : \Company Address Book
LastModificationTime : 11/12/2012 2:57:49 PM
CreationTime : 11/12/2012 2:56:28 PM
HasAttachments : False
ItemType : IPM.Contact
MessageSize : 6.598 KB (6,756 bytes)
Identity : 000000001A447390AA6611CD9BC800AA002FC45A0900580787449ABF5E4891DD89178938242C0000000250AE00001BE1
A5309D57D5439914FD70BDC745C100000B8942FD0000
MapiIdentity : 000000001A447390AA6611CD9BC800AA002FC45A0900580787449ABF5E4891DD89178938242C0000000250AE00001BE1
A5309D57D5439914FD70BDC745C100000B8942FD0000
OriginatingServer : mailman.company.com
IsValid : True
[PS] C:\Windows\system32>
Okay... I'm trying to export the contacts in an Exchange Server 2010 Contact List. I can not, for the world of me, figure out how to get the "Data" out of this stupid thing.
If I do $AddressBook | Format-List, it lists all the contacts, so I'm know I'm in the right ballpark.
how can I get all of the information out of this list? Last Name, First Name, Email Address, Business Phone, etc.
This is an old post, but I have the same issue for a couple days and was unable to figure it out. So, I opted to use the road #WernerCD used and would like to add my PowerShell script that could help you in the case that you decide to go down this path.
Before starting, allow me to explain my issue. We have multiple folders with contacts in it. These contacts contain User Defined Fields that due to migration issues, were not added to their containing folder. While we use Outlook, we need to be able to see these fields on the current view. However, when we try to add the UDF columns, it only allows us to use the "User-defined fields in folder", which is empty.
Below is the PowerShell script that will check a public folder (and its subfolders) within Outlook, check every contact UserProperties (Equivalent for UDF), put them into an array, then it will check if each contact's UDF exist on its containing folder (UserDefinedProperties), and if it doesn't exist, it will added it as a Text field without a value.
Please keep in mind that all our contact folders are under a folder called Shared Contacts Folder.
Code
# Connection to Outlook
$Outlook = New-Object -com Outlook.Application
$Namespace = $outlook.GetNamespace("MAPI")
# "Location" of public folders (Change me#example.com)
$PublicFolder = $Namespace.Folders.Item("Public Folders - me#example.com")
$PublicFolders = $PublicFolder.Folders.Item("All Public Folders")
# Folder that you would like to check. We will check Shared Contacts under Shared Contacts Folder
$SharedContactsFolder = $PublicFolders.Folders.Item("Shared Contacts Folder")
$SharedContacts = $SharedContactsFolder.Folders.Item("Shared Contacts")
Write-Host ("<----------------------------------------------------------->") -foreground Yellow
function CheckContacts($MyFolder){
# Check if this folder has subfolder
If ( $MyFolder.Folders.Count -gt 0) {
Write-Host ("Folder '" + $MyFolder.Name + "' contains subfolders (" + $MyFolder.Folders.Count + ")") -BackgroundColor Yellow -foreground DarkBlue
Foreach ( $Subfolder in $MyFolder.Folders ) {
CheckContacts($Subfolder)
}
}
Write-Host ("Working on folder: " + $MyFolder.Name) -BackgroundColor White -foreground DarkBlue
$All_UDF = #()
# Check User Defined Fields (UDF) for each contact and add them to array
foreach ( $Contacts in $MyFolder.Items ) {
foreach ( $UDF in $Contacts.UserProperties ) {
# Check if field was previously added to array
If ($All_UDF -notcontains $UDF.Name) {
$All_UDF += $UDF.Name
}
}
}
# Add all UDF to Folder's UDF
Write-Host ("We will add the following UDF into '" + $MyFolder.Name + "': ") -foreground Green
Write-Host ($All_UDF -join "`n") -foreground Green
Foreach ( $UDF in $All_UDF ){
# Only add if UDF does not exist on folder's UDF
if( (CheckFolderUDF $MyFolder $UDF) -eq $false) {
# Add - Always add UDF as Text field (1)
Write-Host ("Adding '" + $UDF + "' to '" + $MyFolder.Name + "'")
$MyFolder.UserDefinedProperties.Add($UDF, 1)
}else{
Write-Host ("Already present: " + $UDF)
}
}
Write-Host ("<----------------------------------------------------------->") -foreground Yellow
}
Function CheckFolderUDF ( $MyFolder, $MyUDFName ) {
$Result = $false
Foreach ( $Folder_UDF in $MyFolder.UserDefinedProperties ){
If ( $Folder_UDF.Name -eq $MyUDFName ) {
$Result = $true
break
}
}
return $Result
}
# Start - Check Shared Contacts
CheckContacts($SharedContacts)
How do I run/test this code?
1) Open Windows PowerShell ISE (within Windows).
2) Copy the code above and paste it into the PowerShell ISE window.
3) Read and understand the code.
4) Modify as needed.
P.S.: I tried to add this a "comment", but I don't have enough points.
After much pain and suffering... and stumbling upon [this post]. This is in Powershell (not Exchange Powershell Console) and from my computer (not server MailMan):
$Outlook = New-Object -com Outlook.Application
$Namespace = $outlook.GetNamespace("MAPI")
$PublicFolder = $Namespace.Folders.Item("Public Folders - me#example.com")
$PublicFolders = $PublicFolder.Folders.Item("All Public Folders")
$AddressBook = $PublicFolders.Folders.Item("Company Address Book")
$Contacts = $AddressBook.Items
$Contacts | Select FullName
This actually pulls the contact information. I'm still looking at how to do it on the server side (Exchange Powershell Console), but this should be a good foundation to select the desired fields and push them into the database as I need.
I figure if I can figure out how to get the "Public Folders - dummy_user#example.com", I should be able to do the same thing on the server.
I also assume there is an easier way to do this (maybe by pull path, instead of one part at a time), but this does work.
Now to find out how to get UserDefinedFields....
Why don't you use Get-Contact instead of Get-PublicFolderItemStatistics?