Exchange Get-MailboxFolderStatistics FolderSize to MB - powershell

Morning folks, and what a sad day it is to be British.
Anyway, I'm trying to get MailboxFolderStatistics's FolderSize to MB.
The following line:
Get-MailboxFolderStatistics Joe.Bloggs |
Where-Object { $_.FolderPath -ne "/Deletions" } |
Select-Object FolderPath, #{ N = "FolderSize (MB)"; E = { $_.FolderSize.ToMB() } }
works fine when I'm using Exchange Management Shell.
But if I'm using a remote PS session into one of my Exchange boxes, I don't get anything for FolderSize.
Any ideas?

It's because the Exchange Management Shell you run on the server includes a type named Microsoft.Exchange.Data.ByteQuantifiedSize that gets converted to a System.String through remoting. The former exposes a ToMB() method, the latter does not.
I have written a workaround, but maybe there is a simpler and/or prettier method :
Get-MailboxFolderStatistics Joe.Bloggs |
Where-Object { $_.FolderPath -ne "/Deletions" } |
Select-Object FolderPath, #{
N = "FolderSize (MB)";
E = {
"{0:N2}" -f ((($_.FolderSize -replace "[0-9\.]+ [A-Z]* \(([0-9,]+) bytes\)","`$1") -replace ",","") / 1MB)
}
}
This uses a regular expression to turn the ugly string (example : 3.712 KB (3,801 bytes)) into a usable number. On my system , is not a valid digit grouping symbol so I had to remove it from the string, too.

You can use the following lines to get the $_.FolderSize represented in [decimals]
Select-Object #{
N = "FS_MB";
E = {
[math]::round( ([decimal](($_.FolderSize -replace "[0-9\.]+ [A-Z]* \(([0-9,]+) bytes\)","`$1") -replace ",","") / 1MB),2)
}
}

Typically when looking at folder sizes there is desire to sort them by size descending. To achieve this we need to know the FolderAndSubfolderSize in Bytes and store that in a bigint property as opposed to System.String. It's not rocket science to convert Bytes to Kb,Mb,Gb so I won't go into that here.
In-line syntax for dynamically adding a new property FolderAndSubfolderSizeBytes (I've used backticks to split over several lines for legibility only)
Get-EXOMailbox -Identity user.name#domain.com`
| Get-EXOMailboxFolderStatistics `
| Select Name,FolderAndSubfolderSize,#{`
name="FolderAndSubfolderSizeBytes";`
expression={((($_.FolderAndSubfolderSize -replace '^(.*\()(.*)(\sbytes\))$','$2').Replace(',','')) -as [bigint])}} `
| Sort-Object -Property FolderAndSubfolderSizeBytes -Descending | ft
Long-hand add new properties to variable object for later re-use
$mb = Get-EXOMailbox -Identity user.name#domain.com | Get-EXOMailboxFolderStatistics
foreach ($folder in $mb) {
$folder | Add-Member -NotePropertyName FolderSizeBytes -NotePropertyValue ((($folder.FolderSize -replace '^(.*\()(.*)(\sbytes\))$','$2').Replace(',','')) -as [bigint])
$folder | Add-Member -NotePropertyName FolderAndSubfolderSizeBytes -NotePropertyValue ((($folder.FolderAndSubfolderSize -replace '^(.*\()(.*)(\sbytes\))$','$2').Replace(',','')) -as [bigint])
}
$mb | Select Name,FolderPath,FolderAndSubfolderSize,FolderAndSubfolderSizeBytes | Sort-Object -Property FolderAndSubfolderSizeBytes -Descending | ft

Related

How to format piped output in powershell to a line

I have a script powershell to get PercentProcessorTime of processes.
$Processes = (get-wmiobject Win32_PerfFormattedData_PerfProc_Process)
$Processes | %{ New-Object psobject -Property `
#{ Time = $_.PercentProcessorTime;
Name = ($_.name -replace "#\d+", "" )}}`
| ?{ $_.Name -notmatch "_Total|Idle" } `
| Group-Object Name `
| %{ New-Object psobject -Property `
#{ Name = $_.Name;
Sum = ($_.Group | Measure-Object Time -Sum ).Sum }} `
| Format-Table
Format of result as below:
But I want to format result as below to insert to database:
OK |Idle=100 System=6 smss=0 csrss=0 wininit=0 services=0 lsass=0 lsm=0 svchost=18 ICTrigger=0 nvvsvc=0 ICDCMGR64=0 svchost#2=0 winlogon=0 svchost#3=0 svchost#4=0 svchost#5=0 igfxCUIService=0 svchost#6=0 spoolsv=0 svchost#7=0 armsvc=0 ShieldStart=0 svchost#8=0 GateMan=0 HeciServer=0 Jhi_service=0 NHCAAgent=0 nvxdsync=0 nvvsvc#1=0 nscp=0 PaSvc=0 pcdrmsvc=0 NSCHIM=0 ASDSvc=0 secugate64=0 WindowsSecuService=0 WinFil32=0 WmiPrvSE=0 svchost#9=0 papersrv64=0 WUDFHost=0 svchost#10=0 svchost#11=0 WmiP rvSE#1=0 PaTray=0 unsecapp=0 WmiPrvSE#2=0 LMS=0 SWMAgent=0
Please help me to solve it.
Thanks very much ^^
I don't think there is an "easy", builtin command for it, but it doesn't take much to update the function to do what you want:
$Processes = (get-wmiobject Win32_PerfFormattedData_PerfProc_Process)
$procStrings = #()
$Processes | %{ New-Object psobject -Property `
#{ Time = $_.PercentProcessorTime;
Name = ($_.name -replace "#\d+", "" )}}`
| ?{ $_.Name -notmatch "_Total|Idle" } `
| Group-Object Name `
| %{
$procStrings += "$($_.Name)=$(($_.Group | Measure-Object Time -Sum ).Sum)"}
$procStrings -join " "
Basically, I added an array to hold the string key/value paris and replaced the final New-Object with code to create the desired string. Finally it is joined with spaces to create the final string.
You could absolutely skip the array part and just build up the string directly, instead of creating an array, I just like that approach :)
It doesn't include the "OK |" in the beginning, i don't know what you constitutes an OK, but I'm sure you can add yourself to get what you want :)

Split property value in Powershell

I am currently trying to do an Out-GridView to get a simple overview about our group policy objects. To do so, I am using the Get-GPO cmdlet, like so:
Get-GPO -all |
Select-Object -Property DisplayName, Description |
Sort-Object -Property DisplayName |
Out-GridView
In our company we use the first line of the description field to store the name of the admin who created the policy, and all following lines hold a short description.
I would want to be able to grab the first line of the the Description field with the column header Responsability and all other lines of the field in a separate column. So assuming my current code would give me a table like this:
DisplayName | Description
-------------------------
GPO1 | Username
| stuff
| stuff
I would want it to look like this:
DisplayName | Responsability | Description
------------------------------------------
GPO1 | Username | stuff
| | stuff
How can I achieve this?
As #Matt suggested, you can use a calculated property.
Then since Description is a string, rather than an array of strings, you will need to split the line at the line breaks. This can be done by using -split and since it's information from a GPO we can assume Windows line endings `r`n (Otherwise you could use [environment]::newline)
The first property, use array element [0] will be the first line. For the second property, we'll need to save the array in a variable. Then we can use the length of that variable to get first element through the last.
Get-GPO -all |
Select-Object -Property DisplayName, #{
Name = "Responsibility"
Expression = {($_.Description -split "`r`n")[0]}
}, #{
Name = "Description"
Expression = {
$linearray = ($_.Description -split "`r`n")
$linearray[1..($linearray.length - 1)] | Out-String
}
} |
Sort-Object -Property DisplayName |
Out-GridView
Alternatively, you could create a new object rather than using the calculated property.
Get-GPO -all |
ForEach-Object {
$linearray = ($_.Description -split "`r`n")
[pscustomobject]#{
"DisplayName" = $_.DisplayName
"Responsibility"= $linearray[0]
"Description" = $linearray[1..($linearray.length - 1)] | Out-String
}
} |
Sort-Object -Property DisplayName |
Out-GridView
The first thing to understand is what Get-GPO is returning: an array of objects, each of which has a set of properties.
What is displayed in your table is a series of rows (one per object), with the columns being the values of the properties for that object.
Therefore if you want a new column, you need a new property.
There are two ways you can do this: create a calculated property with Select-Object or add a property to the objects via Add-Member.
Calculated
You may provide a hashtable as a property to Select-Object, and the hashtable must have two keys:
Name (the name of the property)
Expression (a scriptblock that will be executed to determine the value, where $_ refers to the object itself)
Get-GPO -all |
Select-Object -Property DisplayName, Description, #{
Name = 'Responsibility'
Expression = {
($_.Description -split '\r?\n')[0] # First line
}
} |
Sort-Object -Property DisplayName |
Out-GridView
New Member
You can use a ScriptProperty that will execute a scriptblock each time the property is called on the object. Use $this to refer to the object in this context.
Get-GPO -all |
Add-Member -MemberType ScriptProperty -Name Responsibility -Value {
($this.Description -split '\r?\n')[0] # First line
} -Force -PassThru |
Select-Object -Property DisplayName, Responsibility, Description |
Sort-Object -Property DisplayName |
Out-GridView
I would probably use something like this:
Get-GPO -All | ForEach-Object {
$info = $_.Description
$pos = $info.IndexOf([Environment]::NewLine)
if ( $pos -gt 0 ) {
$responsibility = $info.Substring(0,$pos)
$description = $info.Substring($pos + [Environment]::NewLine.Length)
}
else {
$responsibility = ""
$description = $info
}
[PSCustomObject] #{
"DisplayName" = $_.DisplayName
"Responsibility" = $responsibility
"Description" = $description
}
}
This way you can preserve formatting.

combine get-user get-mailboxstatistics exchange 2010

I need to create a report for exchange server 2010.
Where I need the users Display name, lastlogontime and account status ie enabled or disable.
get-mailbox statistics shows lastlogon and get-user can show account control status.
So I tried this not working anyhow.
Get-User -ResultSize Unlimited | Where { $_.RecipientType -eq ‘UserMailbox’ } | ForEach { $Users = #{} } { $Users[$_.SamAccountName] = $_ }
get-mailboxstatistics -server 00-exchbx01 |
ForEach {
New-Object psobject |
Add-Member -PassThru NoteProperty name $_.name |
Add-Member -PassThru NoteProperty lastlogontime $_.lastlogontime |
Add-Member -PassThru NoteProperty UserAccountControl $Users[$_.SamAccountName].UserAccountControl
} |select name,lastlogontime,useraccountcontrol |sort-lastlogontime -descending | export-csv c:\ussersxx.csv -nti
also tried No luck Yet any Help?
Get-User -ResultSize Unlimited | Where { $_.RecipientType -eq ‘UserMailbox’ } | ForEach { $Users = #{} } { $Users[$_.SamAccountName] = $_ } | get-mailboxstatistics -server 00-exchbx01 | select Name,useraccountcontrol, lastlogontime|sort-lastlogontime -descending | Export-csv c:\report.csv
`
This should do it.
$outtbl = #()
$users = Get-User -ResultSize Unlimited | Where { $_.RecipientType -eq ‘UserMailbox’ }
$users | % {
$x = Get-MailboxStatistics $_ | Select LastLogonTime
$t = New-Object PSObject -Property #{
Name = $_.Name
LastLogonTime = $x.LastLogontime
UserAccountControl = $_.UserAccountControl
}
$outtbl += $t
}
This is the way I've always done these "combining results of different commands" type scenarios.
You can then do $outtbl | Sort LastLogonTime -Descending | Export-Csv c:\ussersxx.csv -nti to export the data
There's a couple of things here, most of that looks fine except for your last line:
||sort-lastlogontime -descending |
This should become:
| sort -property lastlogontime -descending |
What you'll also run into is that you might end up with things coming down the pipeline from Get-MailboxStatistics that aren't in your $Users hash table. This will results in getting errors when using your hash table to fill out a property the psobject.
You could adjust this to iterate through the hash table, passing the SamAccountName as the value for the Identity property (but this will likely be slower), or add in some error handling so that you just end up with an empty property rather than it completely erroring out.

Script output that will work on the console as well as with Export-Csv

I'm working on a basic PowerShell script that inputs a pair of dates then gets all accounts with passwords expiring between those times. I'd like to output the data to the console in a way that is compatible with Export-Csv. That way the person running the script can either just view in the console, or get a file.
Here is my script:
[CmdletBinding()]
param(
[string]$StartDate = $(throw "Enter beginning date as MM/DD/YY"),
[string]$EndDate = $(throw "Enter end date as MM/DD/YY")
)
$start = Get-Date($StartDate)
$end = Get-Date($EndDate)
$low = $start.AddDays(-150)
$high = $end.AddDays(-150)
$passusers = Get-ADUser -Filter { PasswordLastSet -gt $low -and PasswordLastSet -lt $high -and userAccountControl -ne '66048' -and userAccountControl -ne '66080' -and enabled -eq $true} -Properties PasswordLastSet,GivenName,DisplayName,mail,LastLogon | Sort-Object -Property DisplayName
$accts = #()
foreach($user in $passusers) {
$passLastSet = [string]$user.PasswordLastSet
$Expiration = (Get-Date($passLastSet)).addDays(150)
$obj = New-Object System.Object
$obj | Add-Member -MemberType NoteProperty -Name Name -Value $user.DisplayName
$obj | Add-Member -MemberType NoteProperty -Name Email -Value $user.mail
$obj | Add-Member -MemberType NoteProperty -Name Expiration -Value $expiration
$accts += $obj
}
Write-Output ($accts | Format-Table | Out-String)
This prints to the console perfectly:
Name Email Expiration
---- ----- ----------
Victor Demon demonv#nsula.edu 1/3/2016 7:16:18 AM
However when called with | Export-Csv it doesn't:
#TYPE System.String
Length
5388
I've tried multiple variations using objects, and data tables, however it seems like I can only get it to work for console or for CSV, not for both.
Replace
Write-Output ($accts | Format-Table | Out-String)
with
$accts
That way your users can run your script any way they like, e.g.
.\your_script.ps1 | Format-Table
.\your_script.ps1 | Format-List
.\your_script.ps1 | Export-Csv
.\your_script.ps1 | Out-GridView
...
Format-Table | Out-String converts your output to a single string whereas Export-Csv expects a list of objects as input (the object properties then become the columns of the CSV). If Export-Csv is fed a string, the only property is Length, so you get a CSV with one column and one record.
$accts | ConvertTo-Csv | Tee -File output.csv | ConvertFrom-Csv

powershell command to list all users, their home directories + sizes

I need a script or command that would list all users on a computer plus their home directories and sizes of their home directories. I can do it only for users are looged in. I also managed to get a list of all users :
$adsi = [ADSI]"WinNT://$env:COMPUTERNAME"
$adsi.Children | where {$_.SchemaClassName -eq 'user'} | Select-Object #{n='UserName'
e={$_.Name}}
but I don't know how to get home dir, plus size from that list.
thanks in advance
Here is a powershell loop that outputs objects with the properties you are looking for (Name, LocalPath, FolderSize), formatted as a table. This combines a few techniques to get the values you are looking for.
Get-WmiObject win32_userprofile | % {
try {
$out = new-object psobject
$out | Add-Member noteproperty Name (New-Object System.Security.Principal.SecurityIdentifier($_.SID)).Translate([System.Security.Principal.NTAccount]).Value
$out | Add-Member noteproperty LocalPath $_.LocalPath
$out | Add-Member noteproperty FolderSize ("{0:N2}" -f ((Get-ChildItem -Recurse $_.LocalPath | Measure-Object -property length -sum -ErrorAction SilentlyContinue).sum / 1MB) + " MB")
$out
} catch {}
} | Format-Table