Iterating multiple Outlook COM Object fails - powershell

We're having a very strange problem. When iterating through multiple elements in an array of public folder names, PowerShell sometimes throws an error. But not always.
When running the code below with as input only one element it works fine but when multiple elements are defined the second iteration throws an error.
According to this Microsoft article one should Release the COM-Object, but this doesn't work either.
Code
Param (
[String]$Mail = 'User#donain.com',
[String]$ImportFile = 'C:\Scripts\Import.txt'
)
$Import = Get-Content $ImportFile
$Start = "\\Public Folders - $Mail"
Add-Type -AssemblyName 'Microsoft.Office.Interop.Outlook'
foreach ($L in $Import) {
$PSTFile = "$ExportFolder\$($L -replace '[^A-Za-z0-9-_ \.\[\]]', ' ').pst"
$Outlook = New-Object -ComObject Outlook.Application -Verbose:$false
$Namespace = $Outlook.GetNameSpace('MAPI')
$AllPublicFolders = $Namespace.Folders | where FolderPath -EQ $Start | ForEach-Object {
$Start = $Start + '\All Public Folders'
$_.Folders | where FolderPath -EQ $Start
}
$Split = $L.Split('\')
$Folder = Switch ($Split.Count) {
1 {$AllPublicFolders.Folders.Item($Split[0])}
2 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1])}
3 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2])}
4 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3])}
5 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4])}
6 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4]).Folders.Item($Split[5])}
7 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4]).Folders.Item($Split[5]).Folders.Item($Split[6])}
8 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4]).Folders.Item($Split[5]).Folders.Item($Split[6]).Folders.Item($Split[7])}
9 {$AllPublicFolders.Folders.Item($Split[0]).Folders.Item($Split[1]).Folders.Item($Split[2]).Folders.Item($Split[3]).Folders.Item($Split[4]).Folders.Item($Split[5]).Folders.Item($Split[6]).Folders.Item($Split[7]).Folders.Item($Split[8])}
}
Write-Verbose "Folder '$($Folder.FolderPath.TrimStart($Start))'"
Write-Verbose "Add PST"
$NameSpace.AddStore($PSTFile)
$PSTStore = $NameSpace.Stores | where {$_.FilePath -eq $PSTFile}
Write-Verbose "Copy content to PST"
$Folder.CopyTo($PSTStore) | Out-Null
Write-Verbose "Remove PST"
$PST = $NameSpace.Stores | where {$_.FilePath -eq $PSTFile}
$PSTRoot= $PST.GetRootFolder()
$PSTFolder= $NameSpace.Folders.Item($PSTRoot.Name)
$NameSpace.GetType().InvokeMember('RemoveStore',[System.Reflection.BindingFlags]::InvokeMethod,$null,$Namespace,($PSTFolder))
$Outlook.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook)
Remove-Variable Outlook
Start-Sleep -Seconds 5
}
ImportFile
WEUR - COMPANY\DAF\Tableau de bord IB\Année 2002\07 juillet
WEUR - COMPANY\DAF\Tableau de bord IB\Année 2002\08 Août
Error
Failed for path 'WEUR - DOMAIM\DAF\Tableau de bord IB\Année 2002\08 Août': You cannot call a method on a null-va
lued expression.

Found the problem:
$AllPublicFolders = $Namespace.Folders | where FolderPath -EQ "\\Public Folders - $Mail" | ForEach-Object {
$_.Folders | where FolderPath -EQ "\\Public Folders - $Mail\All Public Folders"
}

Related

Powershell - Make a menu out of text file

In my adventure trying to learn Powershell, I am working on an extension on a script I have made. The idea is to make script there by adding ".iso" files into a folder. It will use that content in a menu so that I later can use it to select an iso file for a WM in Hyper-V
This is my version of how it will get the content in the first place
Get-ChildItem -Path C:\iso/*.iso -Name > C:\iso/nummer-temp.txt
Add-Content -Path C:\iso/nummer.txt ""
Get-Content -Path C:\iso/nummer-temp.txt | Add-Content -Path C:\iso/nummer.txt
When this code is run it will send an output like what i want. But my question is how do I use this output in a menu?
This is the best practice way to do so in powershell :
#lets say your .txt files gets this list after running get-content
$my_isos = $('win7.iso','win8.iso','win10.iso')
$user_choice = $my_isos | Out-GridView -Title 'Select the ISO File you want' -PassThru
#waiting till you choose the item you want from the grid view
Write-Host "$user_choice is going to be the VM"
I wouldn't try to make it with System.windows.forms utilities as i mentioned in my comment, unless you want to present the form more "good looking".
If you don't want to go for a graphical menu, but rather a console menu, you could use this function below:
function Show-Menu {
Param(
[Parameter(Position=0, Mandatory=$True)]
[string[]]$MenuItems,
[string] $Title
)
$header = $null
if (![string]::IsNullOrWhiteSpace($Title)) {
$len = [math]::Max(($MenuItems | Measure-Object -Maximum -Property Length).Maximum, $Title.Length)
$header = '{0}{1}{2}' -f $Title, [Environment]::NewLine, ('-' * $len)
}
# possible choices: digits 1 to 9, characters A to Z
$choices = (49..57) + (65..90) | ForEach-Object { [char]$_ }
$i = 0
$items = ($MenuItems | ForEach-Object { '{0} {1}' -f $choices[$i++], $_ }) -join [Environment]::NewLine
# display the menu and return the chosen option
while ($true) {
cls
if ($header) { Write-Host $header -ForegroundColor Yellow }
Write-Host $items
Write-Host
$answer = (Read-Host -Prompt 'Please make your choice').ToUpper()
$index = $choices.IndexOf($answer[0])
if ($index -ge 0 -and $index -lt $MenuItems.Count) {
return $MenuItems[$index]
}
else {
Write-Warning "Invalid choice.. Please try again."
Start-Sleep -Seconds 2
}
}
}
Having that in place, you call it like:
# get a list if iso files (file names for the menu and full path names for later handling)
$isoFiles = Get-ChildItem -Path 'D:\IsoFiles' -Filter '*.iso' -File | Select-Object Name, FullName
$selected = Show-Menu -MenuItems $isoFiles.Name -Title 'Please select the ISO file to use'
# get the full path name for the chosen file from the $isoFiles array
$isoToUse = ($isoFiles | Where-Object { $_.Name -eq $selected }).FullName
Write-Host "`r`nYou have selected file '$isoToUse'"
Example:
Please select the ISO file to use
---------------------------------
1 Win10.iso
2 Win7.iso
3 Win8.iso
Please make your choice: 3
You have selected file 'D:\IsoFiles\Win8.iso'

Fix moving files into year folder if exist a matching in .txt file

I have files like this
Taxi driver.torrent
Tabu - Gohatto.txt
Troll 2 (1990)..zip
Inside my filelist.txt file I have files named like so
Troll 2 (1990) [BDrip 1080p - H264 - Ita Ac3] Horror, Commedia
Troll 2 (1990) [XviD - Ita Mp3]
Taxi Driver (1976) Mastered..
Tabù - Gohatto (N. Oshima, 1999)
I have just folders like
1976
1990
1999
I want to move files into correct year folder in this way
1976
|__ Taxi driver.torrent
1990
|__ Troll 2 (1990)..zip
1999
|__ Tabu - Gohatto.txt
I use this path, folders
C:\Path
Test4.txt
script_powershell.ps1
I actually test with powershell 5 to move
$movies = #()
(get-content C:\Path\Test4.txt) | foreach($_){
$properties = #{
date = $_.substring($_.IndexOf("(")+1,4)
name = $_.substring(0,$_.IndexOf("("))
}
write-host $date
write-host $name
$movies += New-Object PSObject -Property $properties
}
$torrentFiles = dir $torrentPath
foreach($movie in $movies){
$datePath = "C:\Path\$($movie.date)"
if(-not(test-path $datePath)) {
new-item $datePath -ItemType "directory"
}
$words = ($movie.name -split '\s') | ?{ $_.Length -gt 1}
$significant = $words.Count
foreach($torrentFile in $torrentFiles){
$matchingWords = 0
foreach($word in $words){
if($torrentFile.BaseName -match $word){
$matchingWords += 1
}
}
if($matchingWords -ge $significant){
Move-Item -path $torrentfile -Destination $datePath
}
}
}
EDIT:
This poweshell has many problems. For examples
Caccia al delitto
is moved in 1990 folder...but..Caccia al delitto is 1986..
Inside file text I have
Caccia a Ottobre Rosso (1990) [DivX - Ita Mp3] Guerra [CURA] Russia
Caccia a Ottobre Rosso (1990) [VP9 - Ita Eng Opus] Thriller
I have not a text string for Caccia al delitto (I remove it for test)
$movies = #()
$movieLocation = 'C:\Path'
$torrentPath = '.'
(get-content "$movieLocation\Test4.txt") | foreach($_) {
# Check for braces.
if (-not($_ -match ".*\(.*\).*")) {return}
$properties = #{
date = ($_ -replace ".+?\(.*?(\d{4}).*?\).*", '$1')
name = $_.substring(0, $_.IndexOf("(")).Trim()
}
# Add items that have a 4 digit date.
if ($properties.date -match "^\d{4}$") {
'Name: "' + $properties.name + '" Date: "' + $properties.date + '"'
$movies += New-Object PSObject -Property $properties
}
}
$torrentFiles = dir $torrentPath
foreach ($movie in $movies) {
$datePath = "$movieLocation\$($movie.date)"
if (-not(test-path "$datePath")) {
new-item "$datePath" -ItemType "directory"
}
foreach ($torrentFile in $torrentFiles) {
# Get percentage based on length.
$pc = [int]($movie.name.length / $torrentFile.basename.length * 100)
# Only between 80% and 100% in length.
if ($pc -gt 100) {continue}
if ($pc -lt 80) {continue}
if ($torrentFile.basename -match $movie.name) {
# Items that match.
'Torrent: {0,-40} Date: {1,-5} Match: {2}' -f $torrentFile.basename, $movie.date, $movie.name
if (-not(test-path "$datePath\$torrentfile")) {
Move-Item -LiteralPath "$torrentPath\$torrentfile" -Destination "$datePath"
}
}
}
}
A modest fix with the date using regex.
The name required a trim to remove trailing space.
I added a test-path before move-item in case the file is not found.
Long time since last used Powershell so could be perhaps improved more.
I tested in path . so hope C:\Path works just as well.

Powershell Script for 500 errors

I want power shell script to fetch all 500 entries from IIS logs from multiple servers. I have written a script that fetches 500 from single servers for previous hours. Could someone check and help me how I can go for fetching multiple servers. Script that I have:
#Set Time Variable -60
$time = (Get-Date -Format "HH:mm:ss"(Get-Date).addminutes(-60))
# Location of IIS LogFile
#$servers = get-content C:\Users\servers.txt
$File = "\\server\D$\Logs\W3SVC89\"+"u_ex"+(get-date).ToString("yyMMddHH")+".log"
# Get-Content gets the file, pipe to Where-Object and skip the first 3 lines.
$Log = Get-Content $File | where {$_ -notLike "#[D,S-V]*" }
# Replace unwanted text in the line containing the columns.
$Columns = (($Log[0].TrimEnd()) -replace "#Fields: ", "" -replace "-","" -replace "\(","" -replace "\)","").Split(" ")
# Count available Columns, used later
$Count = $Columns.Length
# Strip out the other rows that contain the header (happens on iisreset)
$Rows = $Log | where {$_ -like "*500 0 0*"}
# Create an instance of a System.Data.DataTable
#Set-Variable -Name IISLog -Scope Global
$IISLog = New-Object System.Data.DataTable "IISLog"
# Loop through each Column, create a new column through Data.DataColumn and add it to the DataTable
foreach ($Column in $Columns) {
$NewColumn = New-Object System.Data.DataColumn $Column, ([string])
$IISLog.Columns.Add($NewColumn)
}
# Loop Through each Row and add the Rows.
foreach ($Row in $Rows) {
$Row = $Row.Split(" ")
$AddRow = $IISLog.newrow()
for($i=0;$i -lt $Count; $i++) {
$ColumnName = $Columns[$i]
$AddRow.$ColumnName = $Row[$i]
}
$IISLog.Rows.Add($AddRow)
}
$IISLog | select #{n="DateTime"; e={Get-Date ("$($_.date) $($_.time)")}},sip,csuristem,scstatus | ? { $_.DateTime -ge $time } |Out-File C:\Users\Servers\results.csv
Assuming your logfile is always on the same path, and that servers.txt contains you server list,
you can read the server list then execute your code against each one using a foreach loop :
something like that ( a result file is create for each server) :
#Set Time Variable -60
$time = (Get-Date -Format "HH:mm:ss"(Get-Date).addminutes(-60))
# Location of IIS LogFile
$servers = get-content C:\Users\servers.txt
$servers| foreach{
#inside the foreach loop $_ will represent the current server
$File = "\\$_\D$\Logs\W3SVC89\"+"u_ex"+(get-date).ToString("yyMMddHH")+".log"
# Get-Content gets the file, pipe to Where-Object and skip the first 3 lines.
$Log = Get-Content $File | where {$_ -notLike "#[D,S-V]*" }
# Replace unwanted text in the line containing the columns.
$Columns = (($Log[0].TrimEnd()) -replace "#Fields: ", "" -replace "-","" -replace "\(","" -replace "\)","").Split(" ")
# Count available Columns, used later
$Count = $Columns.Length
# Strip out the other rows that contain the header (happens on iisreset)
$Rows = $Log | where {$_ -like "*500 0 0*"}
# Create an instance of a System.Data.DataTable
#Set-Variable -Name IISLog -Scope Global
$IISLog = New-Object System.Data.DataTable "IISLog"
# Loop through each Column, create a new column through Data.DataColumn and add it to the DataTable
foreach ($Column in $Columns) {
$NewColumn = New-Object System.Data.DataColumn $Column, ([string])
$IISLog.Columns.Add($NewColumn)
}
# Loop Through each Row and add the Rows.
foreach ($Row in $Rows) {
$Row = $Row.Split(" ")
$AddRow = $IISLog.newrow()
for($i=0;$i -lt $Count; $i++) {
$ColumnName = $Columns[$i]
$AddRow.$ColumnName = $Row[$i]
}
$IISLog.Rows.Add($AddRow)
}
$IISLog | select #{n="DateTime"; e={Get-Date ("$($_.date) $($_.time)")}},sip,csuristem,scstatus | ? { $_.DateTime -ge $time } |Out-File C:\Users\Servers\$_results.csv
}
Note that this will run your code sequentially on each of your server wich can be time consumming. If you are facing duration issue, you can try to use invoke-command and the -asjob parameter in order to launch you code asynchronoulsy

Script to export to excel

I Have below script:-- looking for help to convert the output to excel format
$servers = get-content “c:\list.txt”
foreach ($server in $servers)
{
$server
$command = “quser /server:” + $server
invoke-expression $command
}
when executed getting in below format the output.
server1
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
Vdw231 ica-tcp#8 7 Active . 11/5/2012 10:40 AM
Vdw232 ica-tcp#60 16 Active 16:18 11/5/2012 2:22 PM
Vdw233 ica-tcp#71 3 Active . 11/6/2012 6:10 AM
Vdw234 ica-tcp#72 1 Active 3 11/6/2012 6:59 AM
Vdw235 ica-tcp#73 5 Active . 11/6/2012 6:59 AM
Vdw236 rdp-tcp#74 2 Active . 11/6/2012 7:07 AM
server2
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
Vdw210 ica-tcp#44 14 Active 13:50 11/5/2012 9:03 AM
Vdw211 ica-tcp#67 6 Active . 11/6/2012 1:56 AM
Vdw212 ica-tcp#70 1 Active 45 11/6/2012 6:34 AM
Vdw213 ica-tcp#72 9 Active 25 11/6/2012 6:53 AM
Vdw214
server3
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
Vdw215 rdp-tcp#131 1 Active 19 11/5/2012 1:42 AM
Vdw216 rdp-tcp#132 4 Active 17 11/5/2012 2:06 AM
Vdw217 rdp-tcp#143 6 Active . 11/6/2012 3:31 AM
My requirement is i wanted to convert this output to excel format for submitting to management. Below is the excel format that i am thinking...to have from above script...
I've rewritten this, but I didn't test the full script and it's not optimized. If you encounter any
problems, feel free to contact me.
$statuses = #()
$servers = get-content "c:\list.txt"
$splitter = [regex]"\s+"
foreach ($server in $servers)
{
$command = "quser /server:$server"
$lines = #((invoke-expression $command | Out-String) -split "`n")
#remove header
$lines = $lines[1..$lines.count]
foreach ($line in $lines)
{
$attrs = #($splitter.Split($line.Trim(),6))
if ( $attrs -eq 6 )
{
$status = New-Object PSCustomObject -Property #{
"SERVER"=$server;
"USERNAME"=$attrs[0];
"SESSIONNAME"=$attrs[1];
"ID"=$attrs[2];
"STATE"=$attrs[3];
"IDLE_TIME"=$attrs[4];
"LOGON_TIME"=[datetime]$attrs[5]}
$statuses += $status
}
}
}
#your filter here
#$statuses = $statuses | where{ XXXXX }
$statuses | Export-Csv G:/test.csv -NoTypeInformation
You need to convert PSObject to an excel compatible Array and after you can write this array in excel sheet
include this code in your *.PS1 script, and use like this : get-process | Export-Excel
#=============================================================================
# Convert powershell Object to Array for Excel
#=============================================================================
function ConvertTo-MultiArray {
<#
.Notes
NAME: ConvertTo-MultiArray
AUTHOR: Tome Tanasovski
Website: http://powertoe.wordpress.com
Twitter: http://twitter.com/toenuff
Version: 1.2
.Synopsis
Converts a collection of PowerShell objects into a multi-dimensional array
.Description
Converts a collection of PowerShell objects into a multi-dimensional array. The first row of the array contains the property names. Each additional row contains the values for each object.
This cmdlet was created to act as an intermediary to importing PowerShell objects into a range of cells in Exchange. By using a multi-dimensional array you can greatly speed up the process of adding data to Excel through the Excel COM objects.
.Parameter InputObject
Specifies the objects to export into the multi dimensional array. Enter a variable that contains the objects or type a command or expression that gets the objects. You can also pipe objects to ConvertTo-MultiArray.
.Inputs
System.Management.Automation.PSObject
You can pipe any .NET Framework object to ConvertTo-MultiArray
.Outputs
[ref]
The cmdlet will return a reference to the multi-dimensional array. To access the array itself you will need to use the Value property of the reference
.Example
$arrayref = get-process |Convertto-MultiArray
.Example
$dir = Get-ChildItem c:\
$arrayref = Convertto-MultiArray -InputObject $dir
.Example
$range.value2 = (ConvertTo-MultiArray (get-process)).value
.LINK
http://powertoe.wordpress.com
#>
param(
[Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)]
[PSObject[]]$InputObject
)
BEGIN {
$objects = #()
[ref]$array = [ref]$null
}
Process {
$objects += $InputObject
}
END {
$properties = $objects[0].psobject.properties |%{$_.name}
$array.Value = New-Object 'object[,]' ($objects.Count+1),$properties.count
# i = row and j = column
$j = 0
$properties |%{
$array.Value[0,$j] = $_.tostring()
$j++
}
$i = 1
$objects |% {
$item = $_
$j = 0
$properties | % {
if ($item.($_) -eq $null) {
$array.value[$i,$j] = ""
}
else {
$array.value[$i,$j] = $item.($_).tostring()
}
$j++
}
$i++
}
$array
}
}
#=============================================================================
# Export pipe in Excel file
#=============================================================================
function Export-Excel {
[cmdletBinding()]
Param(
[Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)]
[PSObject[]]$InputObject
)
begin{
$header=$null
$row=1
$xl=New-Object -ComObject Excel.Application
$wb=$xl.WorkBooks.add(1)
$ws=$wb.WorkSheets.item(1)
$xl.Visible=$false
$xl.DisplayAlerts = $false
$xl.ScreenUpdating = $False
$objects = #()
}
process{
$objects += $InputObject
}
end{
$array4XL = ($objects | ConvertTo-MultiArray).value
$starta = [int][char]'a' - 1
if ($array4XL.GetLength(1) -gt 26) {
$col = [char]([int][math]::Floor($array4XL.GetLength(1)/26) + $starta) + [char](($array4XL.GetLength(1)%26) + $Starta)
} else {
$col = [char]($array4XL.GetLength(1) + $starta)
}
$ws.Range("a1","$col$($array4XL.GetLength(0))").value2=$array4XL
$wb.SaveAs("$([Environment]::GetFolderPath('desktop'))\Export-Excel ($(Get-Date -Format u)).xlsx")
$xl.Quit()
Remove-Variable xl
}
}
you get

IIS 7.5 Application Pools / IIS Manager GUI column: Applications

When looking in the IIS 7.5 manager > application pools, The last column lists "Applications". This column shows the number of application pools / websites this appPool is associated with.
I am trying to figure out how to query this column / information using Powershell. The end goal here is to have a script that I could run that would tell me if any applicaiton pool is being used for more than 1 website or app.
I am unable to find how to query this information, when running:
get-itemproperty IIS:\AppPools\(AppPoolName) | format-list *
I dont see this property. Im not sure that this column is a property, if not, is there a best way to check if AppPools are being used for more than 1 website / applicaiton?
The Applications property is defined in the format file, its code reside in the iisprovider.format.ps1xml file (in the webadmin module folder).
<TableColumnItem>
<ScriptBlock>
$pn = $_.Name
$sites = get-webconfigurationproperty "/system.applicationHost/sites/site/application[#applicationPool=`'$pn`'and #path='/']/parent::*" machine/webroot/apphost -name name
$apps = get-webconfigurationproperty "/system.applicationHost/sites/site/application[#applicationPool=`'$pn`'and #path!='/']" machine/webroot/apphost -name path
$arr = #()
if ($sites -ne $null) {$arr += $sites}
if ($apps -ne $null) {$arr += $apps}
if ($arr.Length -gt 0) {
$out = ""
foreach ($s in $arr) {$out += $s.Value + "`n"}
$out.Substring(0, $out.Length - 1)
}
</ScriptBlock>
</TableColumnItem>
You can take the code out and use it outside the format file, just assign $pn the apppool name you want to query. Here's a simplified version of the code:
$pn = 'pool1'
$sites = get-webconfigurationproperty "/system.applicationHost/sites/site/application[#applicationPool='$pn' and #path='/']/parent::*" machine/webroot/apphost -name name
$apps = get-webconfigurationproperty "/system.applicationHost/sites/site/application[#applicationPool='$pn' and #path!='/']" machine/webroot/apphost -name path
$sites,$apps | foreach {$_.value}
I went with this:
Import-Module WebAdministration
function Get-WebAppPoolApplications($webAppPoolName) {
$result = #()
$webAppPool = Get-Item ( Join-Path 'IIS:\AppPools' $webAppPoolName )
if ( $webAppPool -ne $null ) {
$webSites = Get-ChildItem 'IIS:\Sites'
$webSites | % {
$webApplications = Get-ChildItem ( Join-Path 'IIS:\Sites' $_.Name ) |
where { $_.NodeType -eq 'application' }
$result += $webApplications |
where { $_.applicationPool -eq $webAppPoolName }
}
}
$result
}
Wish I would have seen your post earlier, this is what I eventually came up with:
$SiteApps = get-item IIS:\Sites* $arraySize = ($SiteApps.count -1)
$i = 0
$t = 0
for ($i=0; $i -le $arraySize; $i ++) # start at the beg of the array
{
for ($t=($i+1); $t -le $arraySize; $t++)
{
if ($siteApps[$i].applicationpool -eq $siteApps[$t].applicationpool)
{
$web1 = $siteApps[$i].name
$webappPool = $siteApps[$i].applicationpool
$web2 = $siteApps[$t].name $answer = $answer + "The website "$web1" is sharing the AppPool "webAppPool" with website "$web2". "
}
}
}