Continuing from my previous question:
I have Powershell script that exports Mailboxes Size Results to CSV file.
The Results contain "Total Size" column that display results, and follow by Name.
However, i want the exported CSV file to filter and display only "greater then" 25GB Results, from high to low.
Like that:
Now, there is the traditional way to use excel to filter to Numbers in the CSV results- after the powershell export.
But, i want to have it in the CSV file, so i do not have to do it over and over again.
Here's the script:
Param
(
[Parameter(Mandatory = $false)]
[switch]$MFA,
[switch]$SharedMBOnly,
[switch]$UserMBOnly,
[string]$MBNamesFile,
[string]$UserName,
[string]$Password
)
Function Get_MailboxSize
{
$Stats=Get-MailboxStatistics -Identity $UPN
$IsArchieved=$Stats.IsArchiveMailbox
$ItemCount=$Stats.ItemCount
$TotalItemSize=$Stats.TotalItemSize
$TotalItemSizeinBytes= $TotalItemSize –replace “(.*\()|,| [a-z]*\)”, “”
$TotalSize=$stats.TotalItemSize.value -replace "\(.*",""
$DeletedItemCount=$Stats.DeletedItemCount
$TotalDeletedItemSize=$Stats.TotalDeletedItemSize
#Export result to csv
$Result=#{'Display Name'=$DisplayName;'User Principal Name'=$upn;'Mailbox Type'=$MailboxType;'Primary SMTP Address'=$PrimarySMTPAddress;'IsArchieved'=$IsArchieved;'Item Count'=$ItemCount;'Total Size'=$TotalSize;'Total Size (Bytes)'=$TotalItemSizeinBytes;'Deleted Item Count'=$DeletedItemCount;'Deleted Item Size'=$TotalDeletedItemSize;'Issue Warning Quota'=$IssueWarningQuota;'Prohibit Send Quota'=$ProhibitSendQuota;'Prohibit send Receive Quota'=$ProhibitSendReceiveQuota}
$Results= New-Object PSObject -Property $Result
$Results | Select-Object 'Display Name','User Principal Name','Mailbox Type','Primary SMTP Address','Item Count',#{Name = 'Total Size'; Expression = {($_."Total Size").Split(" ")[0]}},#{Name = 'Unit'; Expression = {($_."Total Size").Split(" ")[1]}},'Total Size (Bytes)','IsArchieved','Deleted Item Count','Deleted Item Size','Issue Warning Quota','Prohibit Send Quota','Prohibit Send Receive Quota' | Export-Csv -Path $ExportCSV -Notype -Append
}
Function main()
{
#Check for EXO v2 module inatallation
$Module = Get-Module ExchangeOnlineManagement -ListAvailable
if($Module.count -eq 0)
{
Write-Host Exchange Online PowerShell V2 module is not available -ForegroundColor yellow
$Confirm= Read-Host Are you sure you want to install module? [Y] Yes [N] No
if($Confirm -match "[yY]")
{
Write-host "Installing Exchange Online PowerShell module"
Install-Module ExchangeOnlineManagement -Repository PSGallery -AllowClobber -Force
}
else
{
Write-Host EXO V2 module is required to connect Exchange Online.Please install module using Install-Module ExchangeOnlineManagement cmdlet.
Exit
}
}
#Connect Exchange Online with MFA
if($MFA.IsPresent)
{
Connect-ExchangeOnline
}
#Authentication using non-MFA
else
{
#Storing credential in script for scheduling purpose/ Passing credential as parameter
if(($UserName -ne "") -and ($Password -ne ""))
{
$SecuredPassword = ConvertTo-SecureString -AsPlainText $Password -Force
$Credential = New-Object System.Management.Automation.PSCredential $UserName,$SecuredPassword
}
else
{
$Credential=Get-Credential -Credential $null
}
Connect-ExchangeOnline -Credential $Credential
}
#Output file declaration
$ExportCSV=".\MailboxSizeReport_$((Get-Date -format yyyy-MMM-dd-ddd` hh-mm` tt).ToString()).csv"
$Result=""
$Results=#()
$MBCount=0
$PrintedMBCount=0
Write-Host Generating mailbox size report...
#Check for input file
if([string]$MBNamesFile -ne "")
{
#We have an input file, read it into memory
$Mailboxes=#()
$Mailboxes=Import-Csv -Header "MBIdentity" $MBNamesFile
foreach($item in $Mailboxes)
{
$MBDetails=Get-Mailbox -Identity $item.MBIdentity
$UPN=$MBDetails.UserPrincipalName
$MailboxType=$MBDetails.RecipientTypeDetails
$DisplayName=$MBDetails.DisplayName
$PrimarySMTPAddress=$MBDetails.PrimarySMTPAddress
$IssueWarningQuota=$MBDetails.IssueWarningQuota -replace "\(.*",""
$ProhibitSendQuota=$MBDetails.ProhibitSendQuota -replace "\(.*",""
$ProhibitSendReceiveQuota=$MBDetails.ProhibitSendReceiveQuota -replace "\(.*",""
$MBCount++
Write-Progress -Activity "`n Processed mailbox count: $MBCount "`n" Currently Processing: $DisplayName"
Get_MailboxSize
$PrintedMBCount++
}
}
#Get all mailboxes from Office 365
else
{
Get-Mailbox -ResultSize Unlimited | foreach {
$UPN=$_.UserPrincipalName
$Mailboxtype=$_.RecipientTypeDetails
$DisplayName=$_.DisplayName
$PrimarySMTPAddress=$_.PrimarySMTPAddress
$IssueWarningQuota=$_.IssueWarningQuota -replace "\(.*",""
$ProhibitSendQuota=$_.ProhibitSendQuota -replace "\(.*",""
$ProhibitSendReceiveQuota=$_.ProhibitSendReceiveQuota -replace "\(.*",""
$MBCount++
Write-Progress -Activity "`n Processed mailbox count: $MBCount "`n" Currently Processing: $DisplayName"
if($SharedMBOnly.IsPresent -and ($Mailboxtype -ne "SharedMailbox"))
{
return
}
if($UserMBOnly.IsPresent -and ($MailboxType -ne "UserMailbox"))
{
return
}
Get_MailboxSize
$PrintedMBCount++
}
}
#Open output file after execution
If($PrintedMBCount -eq 0)
{
Write-Host No mailbox found
}
else
{
Write-Host `nThe output file contains $PrintedMBCount mailboxes.
if((Test-Path -Path $ExportCSV) -eq "True")
{
Write-Host `nThe Output file available in $ExportCSV -ForegroundColor Green
$Prompt = New-Object -ComObject wscript.shell
$UserInput = $Prompt.popup("Do you want to open output file?",`
0,"Open Output File",4)
If ($UserInput -eq 6)
{
Invoke-Item "$ExportCSV"
}
}
}
#Disconnect Exchange Online session
Disconnect-ExchangeOnline -Confirm:$false | Out-Null
}
. main
How can i achieve that?
It's a bit of an unfortunate scenario, but if you're outputting the results to the file on each iteration, you have 2 options:
At the end of the script, read the output file, filter the >25gb mailboxes, sort the objects, then output again
Instead of writing the user mailbox to the file each user, save to a
variable instead. At the end, filter, sort, then export to file
Without going too far into the code...
Option 1
Might be simplest, as you're working off two input sizes already. After you've retrieved all mailboxes and gotten all statistics, read the exported csv file and filter + sort the data. Then, export the info back to the file, overwriting. Something like
$tempImport = Import-CSV $exportCSV | Where-Object {($_.'Total Size' -ge 25) -and ($_.Unit -eq "GB")} | Sort-Object 'Total Size' -descending
$tempImport | Export-CSV $exportCSV -noTypeInformation
PowerShell may not like overwriting a file read-in on the same command, hence the saving as a temp variable.
Option 2
Create a live variable storing all mailbox data, and write the information at the end of the script instead of opening the file to append data each iteration. Then, at the end of the script, filter and sort before exporting.
$global:largeMailboxes = #() # definition to allow reading through all functions
Then, instead of exporting to CSV each time, add the result to the above variable
$tvar = $null
$tvar = $Results | Select-Object 'Display Name','User Principal Name','Mailbox Type','Primary SMTP Address','Item Count',#{Name = 'Total Size'; Expression = {($_."Total Size").Split(" ")[0]}},#{Name = 'Unit'; Expression = {($_."Total Size").Split(" ")[1]}},'Total Size (Bytes)','IsArchieved','Deleted Item Count','Deleted Item Size','Issue Warning Quota','Prohibit Send Quota','Prohibit Send Receive Quota'
$global:largeMailboxes += $tvar
#
# Alternatively, only add the mailbox if it's larger than 25GB, to avoid adding objects you don't care about
if ($TotalItemSizeinBytes -ge 26843545600) # This is 25 GB, better to make a variable called $minSize or such to store this in, in case you want to change it later.
{
# Above code to add to global variable
}
Once all mailboxes have been added, sort the object
$global:largeMailboxes = $global:largeMailboxes | Sort-Object 'Total Size' -descending
Then export as needed
$global:largeMailboxes | Export-CSV $exportCSV -NoTypeInformation
I have a PowerShell script to disable email forwarding in Office 365 using a CSV file. I want to catch all errors to an external Txt file.
Here's my code:
$Groups |
ForEach-Object {
$PrimarySmtpAddress = $_.PrimarySmtpAddress
try {
# disable Mail forwarding
Set-Mailbox -Identity $PrimarySmtpAddress -ForwardingSmtpAddress $Null
}
Catch {
$PrimarySmtpAddress | Out-File $logfile -Append
}
}
but it doesn't catch errors.
Is there any instruction to catch errors to an external file?
Any solution will be helpful.
From Jeff Zeitlin's and TheMadTechnician's comments, changes noted in inline comments:
$Groups | ForEach-Object {
$PrimarySmtpAddress = $_.PrimarySmtpAddress
Try {
# disable Mail forwarding
#Added ErrorAction Stop to cause errors to be terminating
Set-Mailbox -Identity $PrimarySmtpAddress -ForwardingSmtpAddress $Null -ErrorAction Stop
}
Catch {
#Removed Write-Host as Write-Host writes to the host, not down the pipeline, Write-Output would also work
"$PrimarySmtpAddress" | Out-File $logfile -Append
}
}
Try this:
$ErrorMessage = $_.Exception.Message
#or $ErrorMessage= $Error[0].Exception.Message
if($ErrorMessage -ne $null) {
... Your custom code
}
Exchange Online (a.k.a O365) does not honor the thrown error for your catch statement to work. We have had to set
$global:ErrorActionPreference=Stop
to get the error object to return
Note: We implemented this using the following at beginning of function
$saved=$global:ErrorActionPreference
$global:ErrorActionPreference=Stop
and reverted the setting at the end of the function using
$global:ErrorActionPreference=$saved
I have the below powershell script that I call via a command prompt outputting any text to >> .log file. What it does is it creates 2 OU's based on variables from an input file, checks to see if those OU's got created and finally outputs to a .log file (this is entered in the command prompt). It works as expected when executing the code as a domain admin on the abc.acme.ldt.com domain; it creares the OU's and outputs the text to .log file as expected.
But I'm experiencing a weird problem when running it as a forest admin acme.ldt.com user (with local domain admin privileges on that child domain ABC); It's able to create the OU's successfully but for whatever the reason it does not output the text file to the .log file. If I check with a [ADSI]::Exists("full-manual-path") I get a TRUE in response, so the script does create the OU's but I just cant get the text to appear in the .log file as I do when executing as a domain admin on the ABC domain.
Import-Csv ".\source\input.csv" | ForEach {
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $OU_Name1 = $_.'OU Name1' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $OU_Name2 = $_.'OU Name2' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $OU_Name3 = $_.'OU Name3' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $Path1 = $_.'OU Path1' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $Path2 = $_.'OU Path2' }
If ($_.FQDN -eq $(gwmi win32_computersystem).domain) { $Full_windows7_OU_Path2 = $_.'Full Windows 7 OU path2' }
}
New-ADorganizationalUnit -Name $OU_Name1 -Path "$Path1"
Start-Sleep -s 10
New-ADorganizationalUnit -Name $OU_Name2 -Path "$Path2"
New-ADorganizationalUnit -Name $OU_Name3 -Path "$Path2"
if ([ADSI]::Exists("LDAP://$Full_windows7_OU_Path2"))
{
Write-Host "# Checking Logs to Confirm the OU Structure For Win7 Has been created #"
} Else {
Exit
}
Sometimes the simplest things let us doubt ourselves..
As I said in the comment:
Check if that user has write permissions on the share with: "test" | Out-File $location
You're welcome :)
As the title suggests, how do you make it so all of the Write-Outputs - no matter where they appear - automatically append to your defined log file? That way the script will be nicer to read and it removes a tiny bit of work!
Little example below, id like to see none of the "| Out-File" if possible, yet have them still output to that file!
$Author = 'Max'
$Time = Get-Date -Format "HH:mm:ss.fff"
$Title = "Illegal Software Removal"
$LogName = "Illegal_Remove_$($env:COMPUTERNAME).log"
$Log = "C:\Windows\Logs\Software" + "\" + $LogName
$RemoteLog = "\\Server\Adobe Illegal Software Removal"
Set-PSBreakpoint -Variable Time -Mode Read -Action { $global:Time = Get-Date -format "HH:mm:ss.fff" } | Out-Null
If((Test-Path $Log) -eq $False){ New-Item $Log -ItemType "File" -Force | Out-Null }
Else { $Null }
"[$Time][Startup] $Title : Created by $Author" | Out-File $Log -Append
"[$Time][Startup] Configuring initial variables required before run..." | Out-File $Log -Append
EDIT: This needs to work on PS v2.0, I don't want the output to appear on screen at all only in the log. So I have the same functionality, but the script would look like so...
"[$Time][Startup] $Title : Created by $Author"
"[$Time][Startup] Configuring initial variables required before run..."
You have two options, one is to do the redirection at the point the script is invoked e.g.:
PowerShell.exe -Command "& {c:\myscript.ps1}" > c:\myscript.log
Or you can use the Start-Transcript command to record everything (except exe output) the shell sees. After the script is done call Stop-Transcript.
I'm making a script to add some user from a csv to my AD and it doesn't work for some reason that i can't find out ^^'.
I'm using the file ADlog to see where my code goes or not and it goes in the "else (Woot?)" so maybe it can't access to my AD thx to a mistake in my code or ... dunno
#connection to the Active Directory
$objOU=[ADSI]"LDAP://localhost:389/DC=maho,DC=lan"
if($objOU.Children -ne $null) {
# import data from the csv file
$dataSource=import-csv ("\user.csv")
ForEach($dataRecord in $dataSource) {
$ou=$dataRecord.service
#checking the existance of the UO
if(($objOU.Children | where {$_.Path -match "OU=$ou"}) -eq $null){
#if it doesn't, we creat it
$objOU = $objOU.create("organizationalUnit", "ou="+$ou)
$objOU.SetInfo()
"UO not there" | Add-Content C:\ADlog.txt
}
else {
#if it does exist we point on it to creat the new user
$objOU = $objOU.Children.Find("OU=$ou")
"WOOT ?" | Add-Content C:\ADlog.txt
}
$SamAccountName=$dataRecord.login
$GivenName=$dataRecord.fname
$sn=$dataRecord.lname
$cn=$GivenName + " " + $sn
$displayName=$cn
$description=$dataRecord.description
$UserPrincipalname=$SamAccountName +"#"+$DNS_DomainName
#we create the obj user in the AD
$objUser=$objOU.Create("User","CN="+$cn)
$objUser.Put("SamAccountName",$SamAccountName)
$objUser.Put("UserPrincipalName",$UserPrincipalName)
$objUser.Put("DisplayName",$Displayname)
$objUser.Put("Description",$description)
$objUser.Put("GivenName",$GivenName)
$objUser.Put("sn",$sn)
$objUser.SetInfo()
#$objUser.setPassword("")
#empty to make the user choise his own passwd
#we activate the account
$objUser.psbase.InvokeSet("AccountDisabled",$false)
$objUser.SetInfo()
#we check that the acc is created
if(($objOU.Children | where {$_.Path -match "CN=$cn"}) -ne $null) {
"User : "+$UserPrincipalName+" Ok" | Add-Content C:\ADlog.txt
}
$objOU=[ADSI]"LDAP://localhost:389/DC=maho,DC=lan"
}
Write-Host "Sucess!"
#Delete the reg key
Remove-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run"-Name "Unattend*"
}
else {
"Failure" | Add-Content C:\ADlog.txt
}
Check out This Scripting Guy article, pretty straight forward
http://blogs.technet.com/b/heyscriptingguy/archive/2011/12/22/use-powershell-to-read-a-csv-file-and-create-active-directory-user-accounts.aspx