Author Posts

February 8, 2016 at 6:53 am

I am trying to use Don John's Famous Enhanced HTML Report Script to pull some data out of Exchange 2013 Servers, I have created two functions to pull some basic data to test and i got this error message below. When i run the functions by itself they are working fine. I know the HTML requires string, does not like Arrays, Out-string does that but i still get the error below.

Error Message;
ConvertTo-EnhancedHTML : Cannot bind argument to parameter 'HTMLFragments' because it is an empty string.
At C:\Scripts\ExchReport.ps1:144 char:32
+ ConvertTo-EnhancedHTML @params |
+ ~~~~~~~
+ CategoryInfo : InvalidData: (:) [ConvertTo-EnhancedHTML], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,ConvertTo-EnhancedHTML

ConvertTo-EnhancedHTML : Cannot bind argument to parameter 'HTMLFragments' because it is an empty string.
At C:\Scripts\ExchReport.ps1:144 char:32
+ ConvertTo-EnhancedHTML @params |
+ ~~~~~~~
+ CategoryInfo : InvalidData: (:) [ConvertTo-EnhancedHTML], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,ConvertTo-EnhancedHTML

Script;

#requires -module EnhancedHTML2

[CmdletBinding()]
param(
[Parameter(Mandatory=$True,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True)]
[string[]]$ComputerName,

[Parameter(Mandatory=$True)]
[string]$Path
)
BEGIN {
Remove-Module EnhancedHTML2
Import-Module EnhancedHTML2
}
PROCESS {

$CSS = @"

body {
color:#333333;
font-family:Calibri,Tahoma;
font-size: 10pt;
}
h1 {
text-align:center;
}
h2 {
border-top:1px solid #666666;
}

th {
font-weight:bold;
color:#eeeeee;
background-color:#333333;
cursor:pointer;
}
.odd { background-color:#ffffff; }
.even { background-color:#dddddd; }
.paginate_enabled_next, .paginate_enabled_previous {
cursor:pointer;
border:1px solid #222222;
background-color:#dddddd;
padding:2px;
margin:4px;
border-radius:2px;
}
.paginate_disabled_previous, .paginate_disabled_next {
color:#666666;
cursor:pointer;
background-color:#dddddd;
padding:2px;
margin:4px;
border-radius:2px;
}
.dataTables_info { margin-bottom:4px; }
.sectionheader { cursor:pointer; }
.sectionheader:hover { color:red; }
.grid { width:100% }
.red {
color:red;
font-weight:bold;
}

"@

function Get-BootInfo {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string]$ComputerName
)
$BootInfo = Get-CimInstance -ClassName win32_operatingsystem -ComputerName $ComputerName
$props = @{'Server'=$bootInfo.CSName;
'LastBootTime'=$bootInfo.LastBootUpTime}

New-Object -TypeName PSObject -Property $props
}

function Get-LargeEmail {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string]$ComputerName
)
$email = Get-MailboxStatistics -server $computerName |
sort-object -Property totalitemsize -des |
select-object Displayname, ItemCount, totalItemSize -first 10

$props = @{'User'=$email.Displayname;
'ItemCount'=$email.ItemCount;
'Mailbox Size'=$email.totalItemSize;
}

New-Object -TypeName PSObject -Property $props
}

foreach ($computer in $computername) {
try {
$everything_ok = $true
Write-Verbose "Checking connectivity to $computer"
Get-WmiObject -class Win32_BIOS -ComputerName $Computer -EA Stop | Out-Null
} catch {
Write-Warning "$computer failed"
$everything_ok = $false
}

if ($everything_ok) {
$filepath = Join-Path -Path $Path -ChildPath "$computer.html"

$params = @{'As'='Table';
'PreContent'='Server UP Time'}
$html_BootInfo = Get-BootInfo -ComputerName $computer |
Out-String |
ConvertTo-EnhancedHTMLFragment @params

$params = @{'As'='Table';
'PreContent'='Largest Email Users'}
$html_email = Get-LargeEmail -ComputerName $computer |
Out-String |
ConvertTo-EnhancedHTMLFragment @params

$params = @{'CssStyleSheet'=$style;
'Title'="System Report for $computer";
'PreContent'="System Report for $computer";
'HTMLFragments'=@($html_BootInf,$html_email);
'jQueryDataTableUri'='http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.3/jquery.dataTables.min.js';
'jQueryUri'='http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.2.min.js'}
ConvertTo-EnhancedHTML @params |
Out-File -FilePath $filepath

}
}

}

February 8, 2016 at 9:13 am

The problem is here:

'HTMLFragments'=@($html_BootInf,$html_email);

Neither of those variables appears to contain anything, according to the error message. Because you didn't format your script as code, or paste it from Gist, it's a little hard to follow, and I'm not able to run your code on my environment.

But you appear to have a problem here:

$html_BootInfo = Get-BootInfo -ComputerName $computer |
Out-String |
ConvertTo-EnhancedHTMLFragment @params

That won't work. ConvertTo-EnhancedHTMLFragment wants objects as input, not a string. If you debug your code, I imagine you'll find $html_BootInfo to be empty. You probably meant for Out-String to come after ConvertTo-EnhancedHTMLFragment, as in the examples in the book.

February 8, 2016 at 11:27 am

Yes you are right, I have moved the Out-String to the end and it worked. Now, i have eveything on the same line instead of Table or List;

ItemCount

16565 18306 58478 29877 17408 477289 9941 15478 19461 7913 15.43 GB (16,571,992,221 bytes) 14.92 GB (16,019,366,454 bytes) 10.26 GB (11,020,001,935 bytes) 8.761 GB (9,406,653,181 bytes) 8.465 GB (9,089,731,166 bytes) 7.724 GB (8,293,210,131 bytes) 7.577 GB (8,136,272,688 bytes) 6.931 GB (7,442,630,099 bytes) 6.272 GB (6,735,010,952 bytes) 5.911 GB (6,346,656,429 bytes)

Names
Meza, Juan DeBoer, Carol Schmitt, Klaus Theise, Mike Koetje, Chris Snow, Steve Couturier, Dorothy Bahr, Joe Westveld, Belinda Johnson, Tony

February 8, 2016 at 11:38 am

Well, look at what you're doing:

function Get-LargeEmail {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string]$ComputerName
)
$email = Get-MailboxStatistics -server $computerName |
sort-object -Property totalitemsize -des |
select-object Displayname, ItemCount, totalItemSize -first 10

$props = @{'User'=$email.Displayname;
'ItemCount'=$email.ItemCount;
'Mailbox Size'=$email.totalItemSize;
}

You're retrieving ALL the mailbox statistics from a single server, right? So $email doesn't represent ONE mailbox, it represents them ALL. So $email.ItemCount isn't a single mailbox item count, it is the item counts for ALL mailboxes. So that's what you're showing in your output.

February 8, 2016 at 11:58 am

So the script is doing exactly what it is told 🙂 how do i change it to show the each one of the items in a table like this;
Name ItemCount MailboxSize
Mr Funny Guy 222554 25GB
MS Funny Girl 665464654 54GB

February 8, 2016 at 12:28 pm

You need to get all the mailboxes, but then enumerate (ForEach) through each one. For each one, output a unique object with whatever properties you want. Each object then becomes a table row, and each property is a table column.

February 8, 2016 at 2:43 pm

I have added the ForEach inside the function but now i got this error;

MyFunction

function Get-LargeEmail {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string]$ComputerName
)
$Mailboxes = Get-MailboxStatistics -server $computerName |
sort-object -Property totalitemsize -des |
select-object Displayname, ItemCount, totalItemSize -first 10

foreach($Mailbox in $Mailboxes){

$props = @{n="Total Items";exp={$Mailbox.ItemCount}},
@{n="Total Mailbox Size (MB)";exp={$Mailbox.totalitemsize.value.ToMb()}}

New-Object -TypeName PSObject -Property $props

ERROR'
New-Object : Cannot convert 'System.Object[]' to the type 'System.Collections.IDictionary' required by parameter 'Property'. Specified method is not supported.
At C:\Scripts\ExchReport.ps1:109 char:45
+ New-Object -TypeName PSObject -Property $props
+ ~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-Object], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.NewObjectCommand

February 8, 2016 at 3:48 pm

That's because your New-Object is outside the ForEach loop, I believe. However, because you're still not formatting your code here, it's difficult to be certain.

February 8, 2016 at 5:11 pm

I got it to work finally, thank you for all your help. No i can add more functions and prepare a complete Exchange 2013 report.

function Get-LargeEmail {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string]$ComputerName
)
$Mailboxes = Get-MailboxStatistics -server $computerName |
Sort-Object -Property totalitemsize -des |
Select-Object Displayname,Database, TotalDeletedItemSize, ItemCount, TotalItemSize, ID -first 10

foreach($Mailbox in $Mailboxes){

$props = @{'Deleted Item Size'=$Mailbox.TotalDeletedItemSize
'Database'=$Mailbox.Database;
'User Name ' =$Mailbox.DisplayName;
'Total Items'=$Mailbox.ItemCount;
'Total Mailbox Size'=$Mailbox.totalitemsize}

New-Object -TypeName PSCustomObject -Property $props

February 11, 2016 at 12:43 pm

Me again 🙂
I have 8 Exchange Server, i got all the information I need , i prepared the functions. I want to be able to put all the information on the same page and send it out as email, instead of making 8 attachments.When i run the functions individually they generate the result by Server Name, When I put it in the Script, i only get one server info. I checked the module did not see any parameter for it, what am i missing ?

Here is the whole Code;

#requires -module EnhancedHTML2

[CmdletBinding()]
param(
[Parameter(Mandatory=$True,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True)]
[string[]]$ComputerName,

[Parameter(Mandatory=$True)]
[string]$Path
)
BEGIN {
Remove-Module EnhancedHTML2
Import-Module EnhancedHTML2
}
PROCESS {

$CSS = @"

body {
color:#333333;
font-family:Calibri,Tahoma,Arial;
font-size: 10pt;
}
h1 {
text-align:center;
}
h2 {
border-top:1px solid #666666;
}

th {
font-weight:bold;
color:#eeeeee;
background-color:#333333;
cursor:pointer;
}
.odd { background-color:#ffffff; }
.even { background-color:#dddddd; }
.paginate_enabled_next, .paginate_enabled_previous {
cursor:pointer;
border:1px solid #222222;
background-color:#dddddd;
padding:2px;
margin:4px;
border-radius:2px;
}
.paginate_disabled_previous, .paginate_disabled_next {
color:#666666;
cursor:pointer;
background-color:#dddddd;
padding:2px;
margin:4px;
border-radius:2px;
}
.dataTables_info { margin-bottom:4px; }
.sectionheader { cursor:pointer; }
.sectionheader:hover { color:red; }
.grid { width:100% }
.red {
color:red;
font-weight:bold;
}

"@

function Get-BootInfo {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string[]]$ComputerName
)
$BootInfo = Get-CimInstance -ClassName win32_operatingsystem -ComputerName $ComputerName

foreach($B in $BootInfo){
$props = @{'Server'=$B.CSName;
'LastBootTime'=$B.LastBootUpTime}

New-Object -TypeName PSObject -Property $props
}
}

function Get-InfoDisk {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string[]]$ComputerName
)
$drives = Get-WmiObject -class Win32_LogicalDisk -ComputerName $ComputerName `
-Filter "DriveType=3"

foreach ($drive in $drives) {
$props = @{'Server'=$drive.SystemName
'Drive'=$drive.DeviceID
'Size'=$drive.size / 1GB -as [int]
'Free'="{0:N2}" -f ($drive.freespace / 1GB)
'FreePct'=$drive.freespace / $drive.size * 100 -as [int]
}
New-Object -TypeName PSObject -Property $props
}
}

function Get-LargeEmail {
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string]$ComputerName
)
$Mailboxes = Get-MailboxStatistics -server $computerName |
Sort-Object -Property totalitemsize -des |
Select-Object Displayname,Database, TotalDeletedItemSize, ItemCount, TotalItemSize, ID -first 30

foreach($Mailbox in $Mailboxes){

$props = @{'Deleted Item Size'=$Mailbox.TotalDeletedItemSize
'Database'=$Mailbox.Database;
'User Name ' =$Mailbox.DisplayName;
'Total Items'=$Mailbox.ItemCount;
'Total Mailbox Size'=$Mailbox.totalitemsize}

New-Object -TypeName PSCustomObject -Property $props

}
}

function Get-DatabaseStatistics {
[CmdletBinding()]

$Databases = Get-MailboxDatabase -Status

foreach($Database in $Databases) {
$DBSize = $Database.DatabaseSize
$MBCount = @(Get-MailboxStatistics -Database $Database.Name).Count

$MBAvg = Get-MailboxStatistics -Database $Database.Name |
%{$_.TotalItemSize.value.ToGB()} |
Measure-Object -Average

New-Object PSObject -Property @{
Server = $Database.Server.Name
'Database Name' = $Database.Name
'Mailbox Count' = $MBCount
"DatabaseSize (GB)" = $DBSize.ToGB()
"AverageMailboxSize (MB)" = $MBAvg.Average
"WhiteSpace (MB)" = $Database.AvailableNewMailboxSpace.ToMb()
}
}
}

function Get-TransportQ {
[CmdletBinding()]

$Queues = Get-TransportService DETMSEX* | Get-Queue -Filter {MessageCount -gt 10} |
Sort-Object -Property MessageCount -Des |
Select-Object Identity,MessageCount,Status,NextHopDomain

foreach($Queue in $Queues){

$props = @{'Queue Name'=$Queue.Identity;
'Status'=$Queue.Status;
'Mail in Queue'=$Queue.MessageCount;
'Destination'=$Queue.NextHopDomain;
}

New-Object -TypeName PSCustomObject -Property $props

}
}

# Each object is a table row, each property is a table column.

foreach ($computer in $computername) {
try {
$everything_ok = $true
Write-Verbose "Checking connectivity to $computer"
Get-WmiObject -class Win32_BIOS -ComputerName $Computer -EA Stop | Out-Null
} catch {
Write-Warning "$computer failed"
$everything_ok = $false
}

if ($everything_ok) {
$filepath = Join-Path -Path $Path -ChildPath "$computer.html"

$params = @{'As'='Table';
'PreContent'='Server UP Time';
'EvenRowCssClass'='even';
'OddRowCssClass'='odd';
'MakeHiddenSection'=$False;
'TableCssClass'='grid'}
$html_BootInfo = Get-BootInfo -ComputerName $computer |
ConvertTo-EnhancedHTMLFragment @params
$params = @{'As'='Table';
'PreContent'='♦ Local Disks';
'EvenRowCssClass'='even';
'OddRowCssClass'='odd';
'MakeHiddenSection'=$false;
'TableCssClass'='grid';
'Properties'='Drive',
@{n='Size(GB)';e={$_.Size}},
@{n='Free(GB)';e={$_.Free};css={if ($_.FreePct -lt 80) { 'red' }}},
@{n='Free(%)';e={$_.FreePct};css={if ($_.FreeePct -lt 80) { 'red' }}}}
$html_dr = Get-InfoDisk -ComputerName $computer |
ConvertTo-EnhancedHTMLFragment @params

$params = @{'As'='Table';
'PreContent'='Largest Email Users'
'EvenRowCssClass'='even';
'OddRowCssClass'='odd';
'MakeHiddenSection'=$True;
'MakeTableDynamic'=$true;
'TableCssClass'='grid'}

$html_email = Get-LargeEmail -ComputerName $computer |
ConvertTo-EnhancedHTMLFragment @params

$params = @{'As'='Table';
'PreContent'='Mailbox Database Info'
'EvenRowCssClass'='even';
'OddRowCssClass'='odd';
'MakeHiddenSection'=$True;
'MakeTableDynamic'=$true;
'TableCssClass'='grid'}

$Databases = Get-DatabaseStatistics $ComputerName|
ConvertTo-EnhancedHTMLFragment @params

$params = @{'As'='Table';
'PreContent'='Transport Queues'
'EvenRowCssClass'='even';
'OddRowCssClass'='odd';
'MakeHiddenSection'=$True;
'MakeTableDynamic'=$true;
'TableCssClass'='grid'}

$Queues = Get-TransportQ |
ConvertTo-EnhancedHTMLFragment @params

$params = @{'CssStyleSheet'=$style;
'Title'="Exchange Server $computer";
'PreContent'="EXCHANGE ENVIRONMENT REPORT for $computer";
'HTMLFragments'=@($html_BootInfo,$html_dr,$html_email,$Databases,$Queues);
'jQueryDataTableUri'='http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.3/jquery.dataTables.min.js';
'jQueryUri'='http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.2.min.js'}
ConvertTo-EnhancedHTML @params |
Out-File -FilePath $filepath

}
}

}