A while ago I created the “CollectLogsScript” (see my old A better way to collect logs from your Exchange servers blog post) which I have since rebranded to “ExchangeLogCollector”. Seeing that this has proven popular, I have continued to make some major improvements to the script over the years. The script was recently moved over to GitHub to allow people to know and understand what changes I have made so there are no surprises - those of you wanting to see the changes/commits in the branch of code can do so by clicking here. Moving to GitHub also allows the option for someone else to submit issues that they are running into so that they can be addressed. For those looking simply to download the latest version of the script, go to the release page and download the latest ps1 itself.

A recent major improvement that I have made was to enable remote collection from other Exchange servers. This allows the data collection to be done with even more ease and with less admin overhead to collect the data required. This is only able to be done on machines that will allow you to run Invoke-Command remotely against them. From my testing thus far, it appears that machines running on Windows 2008 R2 are not able to do this functionality. If a server fails remote collection, you will still be able to run the script locally on the server without any issues.

When running this script, you’ll always want to be run it from a server that you want to also collect data from or some data will be missing from the data collection – the script will not run properly against a tools machine. Here is what it looks like when you run the script now.

I have added a disclaimer because this script can collect large amounts of data - if you aren’t careful, you can fill up a drive on the server. I still have the logical check to make sure there are at least 15GB free on the specified drive which should be enough in most circumstances – there will always be some variables in play here, but the 15GB free space check is expected to be sufficient. In past versions of the script, I did have a DiskCheckOverride switch that you could use to skip over the check for the disk space, however, with this current version of having the remote option I don’t have that in place till I have some advanced logic in place to allow near zero chance of any drives filling up.

After you have agreed to the disclaimer, the script checks to make sure the servers in the list are up and able to be collected from remotely. Then we do the disk free space check and proceed to collect any Exchange-specific cmdlets as you can’t run Exchange cmdlets within Invoke-Command. If any server fails one of these tests, it will remove them from the list. You will need to collect from any listed servers manually.

After everything has executed locally that we need to, we then send the Invoke-Command to all the servers in the list. You will start to see something like in the image below where we are collecting and zipping up the selected data.

Once we are done collecting data from all the servers, we will proceed to check the actual size of the zipped file from every server and verify we have enough space free to copy the data to the local server. This way, it will be even easier to collect and upload the data.

With the new features that I have added to the script hopefully this makes data collection from an Exchange environment even easier than before. This major improvement moving forward should make it easier for admins to collect data from multiple servers with little to no hassle. This makes all of our jobs easier – ensuring that we collect all the data we need when we need to collect it to resolve issues!

脚本下载:

<#
.NOTESName: ExchangeLogCollector.ps1Author: David PaulsonRequires: Powershell on an Exchange 2010+ Server with Adminstrator rightsVersion History:2.0.0 - Major updates have been made to the script and a new publish of it was done.2.0.1 - Missing HTTPErr Logs to the script.2.0.2 - Fix Bug with loading EMS and search directory2.0.3 - Switch "ClusterLogs" to "High_Availabilty_Logs" and adjust the switch as well to avoid confusion.Added a feature that checks to see if you pass some switches or it throws a warning asking are you sure to continue. 2.1 - Major Updates. Remote Collection now possible with -Server switch. Moved over to github. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDINGBUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANDNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
.SYNOPSISCollects the requested logs off the Exchange server based off the switches that are used.
.DESCRIPTIONCollects the requested logs off the Exchange server based off the switches that are used.
.PARAMETER FilePathThe Location of where you would like the data to be copied over to
.PARAMETER ServersAn array of servers that you would like to collect data from.
.PARAMETER EWSLogsWill collect the EWS logs from the Exchange Server
.PARAMETER IISLogs Will Collect the IIS Logs from the Exchange Server
.PARAMETER DailyPerformanceLogsUsed to collect Exchange 2013+ Daily Performance Logs
.PARAMETER ManagedAvailability Used to collect managed Availability Logs from the Exchange 2013+ Server
.PARAMETER Experfwiz Used to collect Experfwiz data from the server
.PARAMETER RPCLogsUsed to collect the PRC Logs from the server
.PARAMETER EASLogsUsed to collect the Exchange Active Sync Proxy Logs
.PARAMETER ECPLogsUsed to collect the ECP Logs from the Exchange server
.PARAMETER AutoDLogsUsed to Collect the AutoD Logs from the server
.PARAMETER OWALogsUsed to collect the OWA Logs from the server
.PARAMETER ADDriverLogsUsed to collect the AD Driver Logs from the server
.PARAMETER SearchLogsUsed to collect the Search Logs from the server
.PARAMETER HighAvailabilityLogsUsed to collect the High Availability Information from the server
.PARAMETER MapiLogsUsed to collect the Mapi Logs from the server
.PARAMETER MessageTrackingLogsUsed to collect the Message Tracking Logs from the server
.PARAMETER HubProtocolLogsUsed to collect the Hub Protocol Logs from the server
.PARAMETER HubConnectivityLogsUsed to collect the Hub Connectivity Logs from the server
.PARAMETER FrontEndConnectivityLogsUsed to collect the Front End Connectivity Logs from the server
.PARAMETER FrontEndProtocolLogsUsed to collect the Front End Protocol Logs from the server
.PARAMETER MailboxConnectivityLogsUsed to collect the Mailbox Connectivity Logs from the server
.PARAMETER MailboxProtocolLogsUsed to collect the Mailbox Protocol Logs from the server
.PARAMETER QueueInformationThisServerUsed to collect the Queue Information from this server
.PARAMETER ReceiveConnectorsUsed to collect the Receive Connector information from this server
.PARAMETER SendConnectorsUsed to collect the Send connector information from the Org
.PARAMETER DAGInformationUsed to collect the DAG Information for this DAG
.PARAMETER GetVdirsUsed to collect the Virtual Directories of the environment
.PARAMETER TransportConfigUsed to collect the Transport Configuration from this Exchange Server
.PARAMETER DefaultTransportLoggingUsed to Get all the default logging that is enabled on the Exchange Server for Transport Information
.PARAMETER Exmon Used to Collect the Exmon Information
.PARAMETER ServerInfoUsed to collect the general Server information from the server
.PARAMETER MSInfo Old switch that was used for collecting the general Server information
.PARAMETER CollectAllLogsBasedOnDaysWorthUsed to collect some of the default logging based off Days Worth vs the whole directory
.PARAMETER DiskCheckOverrideUsed to over the Availalbe Disk space required in order this script to run
.PARAMETER AppSysLogsUsed to collect the Application and System Logs. Default is set to true
.PARAMETER AllPossibleLogsSwitch to enable all default logging enabled on the Exchange server.
.PARAMETER NoZipUsed to not zip up the data by default
.PARAMETER SkipEndCopyOverBoolean to prevent the copy over after a remote collection.
#PARAMETER CustomData                             - Might bring this back in later build. Used to collect data from a custom directory
#PARAMETER CustomDataDirectory Tell which directory you would like to collect data from
.PARAMETER DaysWorthTo determine how far back we would like to collect data from
.PARAMETER ScriptDebugTo enable Debug Logging for the script to determine what might be wrong with the script
.PARAMETER DatabaseFailoverIssueTo enable the common switches to assist with determine the cause of database failover issues
.PARAMETER Experfwiz_LogmanNameTo be able to set the Experfwiz Logman Name that we would be looking for. By Default "Exchange_Perfwiz"
.PARAMETER Exmon_LogmanNameTo be able to set the Exmon Logman Name that we would be looking for. By Default "Exmon_Trace"
.PARAMETER AcceptEULASwitch used to bypass the disclaimer confirmation #>#Parameters
[CmdletBinding()]
Param ([string]$FilePath = "C:\MS_Logs_Collection",
[Array]$Servers,
[switch]$EWSLogs,
[switch]$IISLogs,
[switch]$DailyPerformanceLogs,
[switch]$ManagedAvailability,
[switch]$Experfwiz,
[switch]$RPCLogs,
[switch]$EASLogs,
[switch]$ECPLogs,
[switch]$AutoDLogs,
[switch]$OWALogs,
[switch]$ADDriverLogs,
[switch]$SearchLogs,
[switch]$HighAvailabilityLogs,
[switch]$ClusterLogs,
[switch]$MapiLogs,
[switch]$MessageTrackingLogs,
[switch]$HubProtocolLogs,
[switch]$HubConnectivityLogs,
[switch]$FrontEndConnectivityLogs,
[switch]$FrontEndProtocolLogs,
[switch]$MailboxConnectivityLogs,
[switch]$MailboxProtocolLogs,
[switch]$QueueInformationThisServer,
[switch]$ReceiveConnectors,
[switch]$SendConnectors,
[switch]$DAGInformation,
[switch]$GetVdirs,
[switch]$TransportConfig,
[switch]$DefaultTransportLogging,
[switch]$Exmon,
[switch]$ServerInfo,
[switch]$CollectAllLogsBasedOnDaysWorth = $false,
[switch]$DiskCheckOverride,
[switch]$AppSysLogs = $true,
[switch]$AllPossibleLogs,
[switch]$NoZip,
[bool]$SkipEndCopyOver,
[int]$DaysWorth = 3,
[switch]$DatabaseFailoverIssue,
[string]$Experfwiz_LogmanName = "Exchange_Perfwiz",
[string]$Exmon_LogmanName = "Exmon_Trace",
[switch]$AcceptEULA,
[switch]$ScriptDebug)$scriptVersion = 2.3###############################################
#                                             #
#              Local Functions                #
#                                             #
################################################disclaimer
Function Display-Disclaimer {
$display = @"Exchange Log Collector v{0}THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDINGBUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANDNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.-This script will copy over data based off the switches provied. -We will check for at least 15 GB of free space at the local target directory BEFORE attempting to copy over the data.-Please run this script at your own risk. "@ -f $scriptVersionClear-HostWrite-Host $displaydo{if(-not $AcceptEULA){$r = Read-Host ("Do you wish to continue ('y' or 'n')")}else{$r = "y"}}while(($r -ne "y" -and $r -ne "n"))if(-not ($AcceptEULA) -and $r -eq "n"){exit }}Function Display-FeedBack {Write-Host ""Write-Host ""Write-Host ""Write-Host "Looks like the script is done. If you ran into any issues or have additional feedback, please feel free to reach out dpaul@microsoft.com."
}#Function to load the EXShell
Function Load-ExShell {if($exinstall -eq $null){$testV14 = Test-Path 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup'$testV15 = Test-Path 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup'if($testV14){$Script:exinstall = (get-itemproperty HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup).MsiInstallPath }elseif ($testV15) {$Script:exinstall = (get-itemproperty HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath    }else{Write-Host "It appears that you are not on an Exchange 2010 or newer server. Sorry I am going to quit."exit}$script:exbin = $Script:exinstall + "\Bin"Write-Host "Loading Exchange PowerShell Module..."add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010}}#Function to test if you are an admin on the server
Function Is-Admin {$currentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent() )If( $currentPrincipal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator )) {return $true}else {return $false}
}Function Display-ScriptDebug{
param(
[Parameter(Mandatory=$true)]$stringdata
)if($ScriptDebug){Write-Host("[Script Debug] : {0}" -f $stringdata) -ForegroundColor Cyan}
}Function Get-ZipEnabled {if($NoZip){return $false}else{return $true}
}Function Get-TransportLoggingInformationPerServer {
param(
[string]$Server,
[int]$version
)Display-ScriptDebug("Function Enter: Get-TransportLoggingInformationPerServer")Display-ScriptDebug("Passed - Server: {0} Version: {1}" -f $Server, $version)$hubObject = New-Object PSCustomObject$tranportLoggingObject = New-Object PSCustomObjectif($version -ge 15){#Hub Transport Layer $data = Get-TransportService -Identity $Server$hubObject | Add-Member -MemberType NoteProperty -Name ConnectivityLogPath -Value ($data.ConnectivityLogPath.PathName)$hubObject | Add-Member -MemberType NoteProperty -Name MessageTrackingLogPath -Value ($data.MessageTrackingLogPath.PathName) $hubObject | Add-Member -MemberType NoteProperty -Name PipelineTracingPath -Value ($data.PipelineTracingPath.PathName)$hubObject | Add-Member -MemberType NoteProperty -Name ReceiveProtocolLogPath -Value ($data.ReceiveProtocolLogPath.PathName)$hubObject | Add-Member -MemberType NoteProperty -Name SendProtocolLogPath -Value ($data.SendProtocolLogPath.PathName)$hubObject | Add-Member -MemberType NoteProperty -Name QueueLogPath -Value ($data.QueueLogPath.PathName)$hubObject | Add-Member -MemberType NoteProperty -Name WlmLogPath -Value ($data.WlmLogPath.PathName)$tranportLoggingObject | Add-Member -MemberType NoteProperty -Name HubLoggingInfo -Value $hubObject#Front End Transport Layer $FETransObject = New-Object PSCustomObject$data = Get-FrontendTransportService -Identity $Server$FETransObject | Add-Member -MemberType NoteProperty -Name ConnectivityLogPath -Value ($data.ConnectivityLogPath.PathName)$FETransObject | Add-Member -MemberType NoteProperty -Name ReceiveProtocolLogPath -Value ($data.ReceiveProtocolLogPath.PathName)$FETransObject | Add-Member -MemberType NoteProperty -Name SendProtocolLogPath -Value ($data.SendProtocolLogPath.PathName)$FETransObject | Add-Member -MemberType NoteProperty -Name AgentLogPath -Value ($data.AgentLogPath.PathName)$tranportLoggingObject | Add-Member -MemberType NoteProperty -Name FELoggingInfo -Value $FETransObject#Mailbox Transport Layer $mbxObject = New-Object PSCustomObject$data = Get-MailboxTransportService -Identity $Server$mbxObject | Add-Member -MemberType NoteProperty -Name ConnectivityLogPath -Value ($data.ConnectivityLogPath.PathName)$mbxObject | Add-Member -MemberType NoteProperty -Name ReceiveProtocolLogPath -Value ($data.ReceiveProtocolLogPath.PathName)$mbxObject | Add-Member -MemberType NoteProperty -Name SendProtocolLogPath -Value ($data.SendProtocolLogPath.PathName)$mbxObject | Add-Member -MemberType NoteProperty -Name PipelineTracingPath -Value ($data.PipelineTracingPath.PathName)$mbxObject | Add-Member -MemberType NoteProperty -Name MailboxDeliveryThrottlingLogPath -Value ($data.MailboxDeliveryThrottlingLogPath.PathName)$tranportLoggingObject | Add-Member -MemberType NoteProperty -Name MBXLoggingInfo -Value $mbxObject }elseif($version -eq 14){$data = Get-TransportServer -Identity $Server$hubObject | Add-Member -MemberType NoteProperty -Name ConnectivityLogPath -Value ($data.ConnectivityLogPath.PathName)$hubObject | Add-Member -MemberType NoteProperty -Name MessageTrackingLogPath -Value ($data.MessageTrackingLogPath.PathName)$hubObject | Add-Member -MemberType NoteProperty -Name PipelineTracingPath -Value ($data.PipelineTracingPath.PathName)$hubObject | Add-Member -MemberType NoteProperty -Name ReceiveProtocolLogPath -Value ($data.ReceiveProtocolLogPath.PathName)$hubObject | Add-Member -MemberType NoteProperty -Name SendProtocolLogPath -Value ($data.SendProtocolLogPath.PathName)$tranportLoggingObject | Add-Member -MemberType NoteProperty -Name HubLoggingInfo -Value $hubObject}else {Write-Host("trying to determine transport information for server {0} and was able to determine the correct version type" -f $Server)return     }Display-ScriptDebug("ReceiveConnectors: {0} QueueInformationThisServer: {1}" -f $ReceiveConnectors, $QueueInformationThisServer)if($ReceiveConnectors){$value = Get-ReceiveConnector -Server $Server $tranportLoggingObject | Add-Member -MemberType NoteProperty -Name ReceiveConnectorData -Value $value }if($QueueInformationThisServer){$value = Get-Queue -Server $Server $tranportLoggingObject | Add-Member -MemberType NoteProperty -Name QueueData -Value $value }Display-ScriptDebug("Function Exit: Get-TransportLoggingInformationPerServer")return $tranportLoggingObject
}Function Get-ServerObjects {
param(
[Parameter(Mandatory=$true)][Array]$ValidServers
)Display-ScriptDebug ("Function Enter: Get-ServerObjects")Display-ScriptDebug ("Passed {0} of Servers" -f $ValidServers.Count)$svrsObject = @()$oldErrorAction = $ErrorActionPreference$ErrorActionPreference = "Stop"foreach($svr in $ValidServers){Display-ScriptDebug -stringdata ("Working on Server {0}" -f $svr)try{$exchSvr = Get-ExchangeServer $svr}catch{Write-Host("Failed to detect server {0} as an Exchange Server" -f $svr) -ForegroundColor RedWrite-Host("Removing from the list")continue }$sobj = New-Object PSCustomObject$sobj | Add-Member -Name ServerName -MemberType NoteProperty -Value ($svr)$svrRole = $exchSvr.ServerRoleDisplay-ScriptDebug ("Pulled out ServerRole: {0}" -f $svrRole.ToString())#Set Exchange Version value 14 Exchange 2010, 15 Exchange 2013, 16 Exchange 2016$svrAdmin = $exchSvr.AdminDisplayVersionDisplay-ScriptDebug ("Pulled out AdminDisplayVersion: {0}" -f $svrAdmin.ToString())if($svrAdmin.Major -eq 14){$exVersion = 14}elseif($svrAdmin.Major -eq 15){if($svrAdmin.Minor -eq 0){$exVersion = 15}else{$exVersion = 16}}else {#don't know what version of Exchange this is, we shouldn't add it Write-Host("Unable to determine the version of Server {0} so we aren't going to collect data from it" -f $svr)    continue }Function IsMailbox{param([string]$value)if($value -like "*Mailbox*"){return $true} else{ return $false}}Function IsCAS{param([string]$value,[int]$version)if(($version -eq 16) -or ($value -like "*ClientAccess*")){return $true} else{return $false}}Function IsHub {param([string]$value,[int]$version)if(($version -ge 15) -or ($value -like "*HubTransport*")){return $true}{return $false}}Function IsDAGMember{param([bool]$IsMailbox,[string]$ServerName)if($IsMailbox){if((Get-MailboxServer $ServerName).DatabaseAvailabilityGroup -ne $null){return $true}else{return $false}}else {return $false}}$sobj | Add-Member -Name Mailbox -MemberType NoteProperty -Value (IsMailbox -Value $svrRole)$sobj | Add-Member -Name CAS -MemberType NoteProperty -Value (IsCAS -Value $svrRole -Version $exVersion)$sobj | Add-Member -Name Hub -MemberType NoteProperty -Value (IsHub -Value $svrRole -Version $exVersion)$sobj | Add-Member -Name Version -MemberType NoteProperty -Value $exVersion$sobj | Add-Member -Name DAGMember -MemberType NoteProperty -Value (IsDAGMember -IsMailbox $sobj.Mailbox -ServerName $svr)Display-ScriptDebug ("IsMailbox: {0} IsCas: {1} IsHub: {2} IsDAGMember: {3} exVersion: {4} AnyTransportSwitchesEnabled: {5}" -f ($sobj.Mailbox), ($sobj.CAS), ($sobj.Hub), ($sobj.DAGMember), $exVersion, $Script:AnyTransportSwitchesEnabled)if($Script:AnyTransportSwitchesEnabled -and $sobj.Hub){$sobj | Add-Member -Name TransportInfoCollect -MemberType NoteProperty -Value $true $sobj | Add-Member -Name TransportInfo -MemberType NoteProperty -Value (Get-TransportLoggingInformationPerServer -Server $svr -version $exVersion )}else {$sobj | Add-Member -Name TransportInfoCollect -MemberType NoteProperty -Value $false    }$svrsObject += $sobj }$ErrorActionPreference = $oldErrorActionif (($svrsObject -eq $null) -or ($svrsObject.Count -eq 0)){Write-Host("Something wrong happened in Get-ServerObjects stopping script") -ForegroundColor Redexit }Display-ScriptDebug("Function Exit: Get-ServerObjects")Return $svrsObject
}Function Get-ArgumentList {
param(
[Parameter(Mandatory=$true)][array]$Servers
)$obj = New-Object PSCustomObject $obj | Add-Member -Name FilePath -MemberType NoteProperty -Value $FilePath$obj | Add-Member -Name ManagedAvailability -MemberType NoteProperty -Value $ManagedAvailability$obj | Add-Member -Name Zip -MemberType NoteProperty -Value (Get-ZipEnabled)$obj | Add-Member -Name AppSysLogs -MemberType NoteProperty -Value $AppSysLogs$obj | Add-Member -Name EWSLogs -MemberType NoteProperty -Value $EWSLogs$obj | Add-Member -Name DailyPerformanceLogs -MemberType NoteProperty -Value $DailyPerformanceLogs$obj | Add-Member -Name RPCLogs -MemberType NoteProperty -Value $RPCLogs $obj | Add-Member -Name EASLogs -MemberType NoteProperty -Value $EASLogs $obj | Add-Member -Name ECPLogs -MemberType NoteProperty -Value $ECPLogs $obj | Add-Member -Name AutoDLogs -MemberType NoteProperty -Value $AutoDLogs$obj | Add-Member -Name OWALogs -MemberType NoteProperty -Value $OWALogs$obj | Add-Member -Name ADDriverLogs -MemberType NoteProperty -Value $ADDriverLogs$obj | Add-Member -Name SearchLogs -MemberType NoteProperty -Value $SearchLogs$obj | Add-Member -Name HighAvailabilityLogs -MemberType NoteProperty -Value $HighAvailabilityLogs$obj | Add-Member -Name MapiLogs -MemberType NoteProperty -Value $MapiLogs$obj | Add-Member -Name MessageTrackingLogs -MemberType NoteProperty -Value $MessageTrackingLogs$obj | Add-Member -Name HubProtocolLogs -MemberType NoteProperty -Value $HubProtocolLogs$obj | Add-Member -Name HubConnectivityLogs -MemberType NoteProperty -Value $HubConnectivityLogs$obj | Add-Member -Name FrontEndConnectivityLogs -MemberType NoteProperty -Value $FrontEndConnectivityLogs$obj | Add-Member -Name FrontEndProtocolLogs -MemberType NoteProperty -Value $FrontEndProtocolLogs$obj | Add-Member -Name MailboxConnectivityLogs -MemberType NoteProperty -Value $MailboxConnectivityLogs$obj | Add-Member -Name MailboxProtocolLogs -MemberType NoteProperty -Value $MailboxProtocolLogs$obj | Add-Member -Name QueueInformationThisServer -MemberType NoteProperty -Value $QueueInformationThisServer$obj | Add-Member -Name ReceiveConnectors -MemberType NoteProperty -Value $ReceiveConnectors $obj | Add-Member -Name SendConnectors -MemberType NoteProperty -Value $SendConnectors $obj | Add-Member -Name DAGInformation -MemberType NoteProperty -Value $DAGInformation $obj | Add-Member -Name GetVdirs -MemberType NoteProperty -Value $GetVdirs $obj | Add-Member -Name TransportConfig -MemberType NoteProperty -Value $TransportConfig$obj | Add-Member -Name DefaultTransportLogging -MemberType NoteProperty -Value $DefaultTransportLogging$obj | Add-Member -Name ServerInfo -MemberType NoteProperty -Value $ServerInfo$obj | Add-Member -Name CollectAllLogsBasedOnDaysWorth -MemberType NoteProperty -Value $CollectAllLogsBasedOnDaysWorth$obj | Add-Member -Name DaysWorth -MemberType NoteProperty -Value $DaysWorth $obj | Add-Member -Name IISLogs -MemberType NoteProperty -Value $IISLogs $obj | Add-Member -Name AnyTransportSwitchesEnabled -MemberType NoteProperty -Value $script:AnyTransportSwitchesEnabled$svrobjs = Get-ServerObjects -ValidServers $Servers$obj | Add-Member -Name ServerObjects -MemberType NoteProperty -Value $svrobjs$obj | Add-Member -Name HostExeServerName -MemberType NoteProperty -Value ($env:COMPUTERNAME)$obj | Add-Member -Name Experfwiz -MemberType NoteProperty -Value $Experfwiz$obj | Add-Member -Name Experfwiz_LogmanName -MemberType NoteProperty -Value $Experfwiz_LogmanName$obj | Add-Member -Name Exmon -MemberType NoteProperty -Value $Exmon$obj | Add-Member -Name Exmon_LogmanName -MemberType NoteProperty -Value $Exmon_LogmanName$obj | Add-Member -Name ScriptDebug -MemberType NoteProperty -Value $ScriptDebug#Collect only if enabled we are going to just keep it on the base of the passed parameter object to make it simple if($GetVdirs){$obj | Add-Member -Name VDirsInfo -MemberType NoteProperty -Value (Get-VdirsLDAP)}$mbx = $falseforeach($svr in $svrobjs){if($svr.ServerName -eq $env:COMPUTERNAME){$mbx = $true$checkSvr = $svr}}if(($mbx) -and ($HighAvailabilityLogs) -and ($checkSvr.DAGMember)){Write-Host("Generating cluster logs for the local server's DAG only")Write-Host("Server: {0}" -f $checkSvr.ServerName)#Only going to do this for the local server's DAG $cmd = "Cluster log /g"Invoke-Expression -Command $cmd | Out-Null}if($DAGInformation){$obj | Add-Member -MemberType NoteProperty -Name DAGInfoData -Value (Get-DAGInformation)}if($SendConnectors){$value = Get-SendConnector $obj | Add-Member -MemberType NoteProperty -Name SendConnectorData -Value $value}Return $obj
}Function Test-PossibleCommonScenarios {#all possible logs if($AllPossibleLogs){$Script:EWSLogs = $true $Script:IISLogs = $true $Script:DailyPerformanceLogs = $true$Script:ManagedAvailability = $true $Script:RPCLogs = $true $Script:EASLogs = $true $Script:AutoDLogs = $true$Script:OWALogs = $true $Script:ADDriverLogs = $true $Script:HighAvailabilityLogs = $true $Script:ServerInfo = $true $Script:GetVdirs = $true$Script:DAGInformation = $true $Script:DefaultTransportLogging = $true$Script:MapiLogs = $true }if($DefaultTransportLogging){$Script:HubConnectivityLogs = $true $Script:MessageTrackingLogs = $true $Script:QueueInformationThisServer = $true $Script:SendConnectors = $true $Script:ReceiveConnectors = $true $Script:TransportConfig = $true$Script:FrontEndConnectivityLogs = $true $Script:MailboxConnectivityLogs = $true $Script:FrontEndProtocolLogs = $true }if($DatabaseFailoverIssue){$Script:DailyPerformanceLogs = $true$Script:HighAvailabilityLogs = $true $Script:ManagedAvailability = $true $Script:DAGInformation = $true}#See if any transport logging is enabled. $Script:AnyTransportSwitchesEnabled = $falseif($HubProtocolLogs -or $HubConnectivityLogs -or $MessageTrackingLogs -or$QueueInformationThisServer -or$SendConnectors -or $ReceiveConnectors -or$TransportConfig -or$FrontEndConnectivityLogs -or $FrontEndProtocolLogs -or $MailboxConnectivityLogs -or$MailboxProtocolLogs -or $DefaultTransportLogging){$Script:AnyTransportSwitchesEnabled = $true}}Function Test-NoSwitchesProvided {if($EWSLogs -or $IISLogs -or $DailyPerformanceLogs -or $ManagedAvailability -or $Experfwiz -or $RPCLogs -or $EASLogs -or $ECPLogs -or $AutoDLogs -or $SearchLogs -or $OWALogs -or $ADDriverLogs -or$HighAvailabilityLogs -or$MapiLogs -or $Script:AnyTransportSwitchesEnabled -or$DAGInformation -or$GetVdirs -or $Exmon -or $ServerInfo){return}else {Write-Host ""    Write-Warning "Doesn't look like any parameters were provided, are you sure you are running the correct command? This is ONLY going to collect the Application and System Logs."Write-Warning "Enter 'y' to continue and 'n' to stop the script"do{$a = Read-Host "Please enter 'y' or 'n'"}while($a -ne 'y' -and $a -ne 'n')if($a -eq 'n'){exit}else{Write-Host "Okay moving on..."}}
}Function Test-RemoteExecutionOfServers {
param(
[Parameter(Mandatory=$true)][Array]$Server_List
)Display-ScriptDebug("Function Enter: Test-RemoteExecutionOfServers")$Servers_up = @() Write-Host "Checking to see if the servers are up in this list:"foreach($server in $Server_List) {Write-Host $server}Write-Host ""Write-Host "Checking their status...."foreach($server in $Server_List){Write-Host("Checking server {0}....." -f $server) -NoNewlineif((Test-Connection $server -Quiet)){   Write-Host "Online" -ForegroundColor Green$Servers_up += $server}else {Write-Host "Offline" -ForegroundColor RedWrite-Host ("Removing Server {0} from the list to collect data from" -f $server)}}#Now we should check to see if can use WRM with invoke-commandWrite-Host ""Write-Host "For all the servers that are up, we are going to see if remote execution will work"#shouldn't need to test if they are Exchange servers, as we should be doing that locally as well. $valid_Servers = @()$oldErrorAction = $ErrorActionPreference$ErrorActionPreference = "Stop"foreach($server in $Servers_up){try {Write-Host("Checking Server {0}....." -f $server) -NoNewLineInvoke-Command -ComputerName $server -ScriptBlock { Get-Process | Out-Null}#if that doesn't fail, we should be okay to add it to the working list Write-Host("Passed") -ForegroundColor Green$valid_Servers += $server}catch {Write-Host("Failed") -ForegroundColor RedWrite-Host("Removing Server {0} from the list to collect data from" -f $server)}}Display-ScriptDebug("Function Exit: Test-RemoteExecutionOfServers")$ErrorActionPreference = $oldErrorActionreturn $valid_Servers
}Function Get-VdirsLDAP {$authTypeEnum = @"
namespace AuthMethods
{using System;[Flags]public enum AuthenticationMethodFlags{None = 0,Basic = 1,Ntlm = 2,Fba = 4,Digest = 8,WindowsIntegrated = 16,LiveIdFba = 32,LiveIdBasic = 64,WSSecurity = 128,Certificate = 256,NegoEx = 512,// Exchange 2013OAuth = 1024,Adfs = 2048,Kerberos = 4096,Negotiate = 8192,LiveIdNegotiate = 16384,}
}
"@Write-Host "Collecting Virtual Directory Information..."Add-Type -TypeDefinition $authTypeEnum -Language CSharp$objRootDSE = [ADSI]"LDAP://rootDSE"$strConfigurationNC = $objRootDSE.configurationNamingContext$objConfigurationNC = New-object System.DirectoryServices.DirectoryEntry("LDAP://$strConfigurationNC")$searcher = new-object DirectoryServices.DirectorySearcher$searcher.filter = "(&(objectClass=msExchVirtualDirectory)(!objectClass=container))" $searcher.SearchRoot = $objConfigurationNC$Searcher.CacheResults = $false  $Searcher.SearchScope = "Subtree"$Searcher.PageSize = 1000  # Get all the results$colResults  = $searcher.FindAll()$objects = @()# Loop through the results andforeach ($objResult in $colResults){$objItem = $objResult.getDirectoryEntry()$objProps = $objItem.Properties$place = $objResult.Path.IndexOf("CN=Protocols,CN=")$ServerDN = [ADSI]("LDAP://" + $objResult.Path.SubString($place,($objResult.Path.Length - $place)).Replace("CN=Protocols,",""))[string]$Site = $serverDN.Properties.msExchServerSite.ToString().Split(",")[0].Replace("CN=","")[string]$server = $serverDN.Properties.adminDisplayName.ToString()[string]$version = $serverDN.Properties.serialNumber.ToString()$obj = New-Object PSObject $obj | Add-Member -MemberType NoteProperty -name Server -value $server$obj | Add-Member -MemberType NoteProperty -name Version -value $version$obj | Add-Member -MemberType NoteProperty -name Site -value $Site[string]$var = $objProps.DistinguishedName.ToString().Split(",")[0].Replace("CN=","")$obj | Add-Member -MemberType NoteProperty -name VirtualDirectory -value $var[string]$var = $objProps.msExchInternalHostName$obj | Add-Member -MemberType NoteProperty -name InternalURL -value $varif (-not [string]::IsNullOrEmpty($objProps.msExchInternalAuthenticationMethods)){$obj | Add-Member -MemberType NoteProperty -name InternalAuthenticationMethods -value ([AuthMethods.AuthenticationMethodFlags]$objProps.msExchInternalAuthenticationMethods)}else{$obj | Add-Member -MemberType NoteProperty -name InternalAuthenticationMethods -value $null}[string]$var = $objProps.msExchExternalHostName$obj | Add-Member -MemberType NoteProperty -name ExternalURL -value $var if (-not [string]::IsNullOrEmpty($objProps.msExchExternalAuthenticationMethods)){$obj | Add-Member -MemberType NoteProperty -name ExternalAuthenticationMethods -value ([AuthMethods.AuthenticationMethodFlags]$objProps.msExchExternalAuthenticationMethods)}else{$obj | Add-Member -MemberType NoteProperty -name ExternalAuthenticationMethods -value $null}if (-not [string]::IsNullOrEmpty($objProps.msExch2003Url)){[string]$var = $objProps.msExch2003Url$obj | Add-Member -MemberType NoteProperty -name Exchange2003URL  -value $var}else{$obj | Add-Member -MemberType NoteProperty -name Exchange2003URL -value $null}[Array]$objects += $obj}return $objects
}Function Get-ExchangeServerDAGName {
param(
[string]$Server
)Display-ScriptDebug("Function Enter: Get-ExchangeServerDAGName")$oldErrorAction = $ErrorActionPreference$ErrorActionPreference = "Stop"try {$dagName = (Get-MailboxServer $Server).DatabaseAvailabilityGroup.Name Display-ScriptDebug("Returning dagName: {0}" -f $dagName)Display-ScriptDebug("Function Exit: Get-ExchangeServerDAGName")return $dagName}catch {Write-Host("Looks like this server {0} isn't a Mailbox Server. Unable to get DAG Infomration." -f $Server)return $null }finally{$ErrorActionPreference = $oldErrorAction }
}Function Get-MailboxDatabaseInformationFromDAG{
param(
[parameter(Mandatory=$true)]$DAGInfo
)Display-ScriptDebug("Function Enter: Get-MailboxDatabaseInformationFromDAG")Write-Host("Getting Database information from {0} DAG member servers" -f $DAGInfo.Name)$AllDupMDB = @()foreach($serverobj in $DAGInfo.Servers){foreach($server in $serverobj.Name){$AllDupMDB += Get-MailboxDatabase -Server $server -Status }}#remove all dups $MailboxDBS = @()foreach($t_mdb in $AllDupMDB){$add = $trueforeach($mdb in $MailboxDBS){if($mdb.Name -eq $t_mdb.Name){$add = $falsebreak}}if($add){$MailboxDBS += $t_mdb}}Write-Host("Found the following databases:")foreach($mdb in $MailboxDBS){Write-Host($mdb)}$MailboxDBInfo = @() foreach($mdb in $MailboxDBS){$mdb_Name = $mdb.Name $dbObj = New-Object PSCustomObject$dbObj | Add-Member -MemberType NoteProperty -Name MDBName -Value $mdb_Name$dbObj | Add-Member -MemberType NoteProperty -Name MDBInfo -Value $mdb$value = Get-MailboxDatabaseCopyStatus $mdb_Name\*$dbObj | Add-Member -MemberType NoteProperty -Name MDBCopyStatus -Value $value$MailboxDBInfo += $dbObj}Display-ScriptDebug("Function Exit: Get-MailboxDatabaseInformationFromDAG")return $MailboxDBInfo
}Function Get-DAGInformation {$DAGName = Get-ExchangeServerDAGName -Server $env:COMPUTERNAME #only going to get the local server's DAG infoif($DAGName -ne $null){$dagObj = New-Object PSCustomObject$value = Get-DatabaseAvailabilityGroup $DAGName -Status $dagObj | Add-Member -MemberType NoteProperty -Name DAGInfo -Value $value $value = Get-DatabaseAvailabilityGroupNetwork $DAGName $dagObj | Add-Member -MemberType NoteProperty -Name DAGNetworkInfo -Value $value$dagObj | Add-Member -MemberType NoteProperty -Name AllMdbs -Value (Get-MailboxDatabaseInformationFromDAG -DAGInfo $dagObj.DAGInfo)return $dagObj}
}#Logic for determining the free space on the drive
Function Get-FreeSpaceFromDrives {
param(
[Parameter(Mandatory=$true)][string]$Root_Full_Path,
[Parameter(Mandatory=$true)][Array]$Drives_WMI
)$driveLetter = ($Root_Full_Path.Split("\"))[0]$Free_Space = $Drives_WMI | ?{$_.DriveLetter -eq $driveLetter} | select DriveLetter, label, @{LABEL='GBfreespace';EXPRESSION={$_.freespace/1GB}}return $Free_Space
}Function Get-DisksData {$drives = gwmi win32_volume -Filter 'drivetype = 3'$obj = New-Object PSCustomObject$obj | Add-Member -MemberType NoteProperty -Name Drives -Value $drives$obj | Add-Member -MemberType NoteProperty -Name ServerName -Value ($env:COMPUTERNAME)return $obj
}Function Test-DiskSpace {
param(
[Parameter(Mandatory=$true)][array]$Servers,
[Parameter(Mandatory=$true)][string]$Path,
[Parameter(Mandatory=$true)][int]$CheckSize
)Display-ScriptDebug("Function Enter: Test-DiskSpace")Display-ScriptDebug("Passed - Path: {0} CheckSize: {1}" -f $Path, $CheckSize)Write-Host("Checking the free space on the servers before collecting the data...")$script_block = ${Function:Get-DisksData}$Servers_Data = Invoke-Command -ComputerName $Servers -ScriptBlock $script_block$Passed_Servers = @()foreach($server in $Servers_Data){$Free_Space = Get-FreeSpaceFromDrives -Root_Full_Path $Path -Drives_WMI $server.Drivesif($Free_Space.GBfreespace -gt $CheckSize){Write-Host("[{0}] : We have more than {1} GB of free space at {2}" -f $server.ServerName, $CheckSize, $Path)$Passed_Servers += $server.ServerName}else {Write-Host("[{0}] : We have less than {1} GB of free space on {2}" -f $server.ServerName, $CheckSize, $Path)}}if($Passed_Servers.Count -ne $Servers.Count){Write-Host("Looks like all the servers didn't pass the disk space check.")Write-Host("We will only collect data from these servers: ")foreach($svr in $Passed_Servers){Write-Host("{0}" -f $svr)}do{$r = Read-Host("Are you sure you want to continue? 'y' or 'n'")}while($r -ne 'y' -and $r -ne 'n')if($r -eq 'n'){exit }}Display-ScriptDebug("Function Exit: Test-DiskSpace")return $Passed_Servers
}Function Get-RemoteLogLocation {
param(
[parameter(Mandatory=$true)][array]$Servers,
[parameter(Mandatory=$true)][string]$RootPath
)Function Get-ZipLocation {param([parameter(Mandatory=$true)][string]$RootPath)$like = "*-{0}*.zip" -f (Get-Date -Format Md)$Item = $RootPath + (Get-ChildItem $RootPath | ?{$_.Name -like $like} | sort CreationTime -Descending)[0]$obj = New-Object -TypeName PSCustomObject $obj | Add-Member -MemberType NoteProperty -Name ServerName -Value $env:COMPUTERNAME$obj | Add-Member -MemberType NoteProperty -Name ZipFolder -Value $Item$obj | Add-Member -MemberType NoteProperty -Name Size -Value ((Get-Item $Item).Length)return $obj}$script_block = ${function:Get-ZipLocation}$LogInfo = Invoke-Command -ComputerName $Servers -ScriptBlock $script_block -ArgumentList $RootPath return $LogInfo
}Function Test-DiskSpaceForCopyOver {
param(
[parameter(Mandatory=$true)][array]$LogPathObject,
[parameter(Mandatory=$true)][string]$RootPath
)Display-ScriptDebug("Function Enter: Test-DiskSpaceForCopyOver")foreach($SvrObj in $LogPathObject){$iTotalSize += $SvrObj.Size }#switch it to GB in size $iTotalSizeGB = $iTotalSize / 1GB#Get the local free space again $driveObj = Get-DisksData$FreeSpace = Get-FreeSpaceFromDrives -Root_Full_Path $RootPath -Drives_WMI $driveObj.Drives$extraSpace = 10if($FreeSpace.GBfreespace -gt ($iTotalSizeGB + $extraSpace)){Write-Host("[{0}] : Looks like we have enough free space at the path to copy over the data" -f $env:COMPUTERNAME)Write-Host("[{0}] : FreeSpace: {1} TestSize: {2} Path: {3}" -f $env:COMPUTERNAME, $FreeSpace.GBfreespace, ($iTotalSizeGB + $extraSpace), $RootPath)return $true}else {Write-Host("[{0}] : Looks like we don't have enough free space to copy over the data" -f $env:COMPUTERNAME) -ForegroundColor YellowWrite-Host("[{0}] : FreeSpace: {1} TestSize: {2} Path: {3}" -f $env:COMPUTERNAME, $FreeSpace.GBfreespace, ($iTotalSizeGB + $extraSpace), $RootPath)return $false}}###############################################
#                                             #
#          Possible Remote Functions          #
#                                             #
###############################################Function Remote-Functions {
param(
[Parameter(Mandatory=$true)][object]$PassedInfo
)Function New-FolderCreate {param([string]$Folder)if(-not (Test-Path -Path $Folder)){Write-Host("[{0}] : Creating Directory {1}" -f $Script:LocalServerName, $Folder)[System.IO.Directory]::CreateDirectory($Folder) | Out-Null}else {Write-Host("[{0}] : Directory {1} is already created!" -f $Script:LocalServerName, $Folder)}}Function Remote-DisplayScriptDebug {param([Parameter(Mandatory=$true)]$stringdata )if($PassedInfo.ScriptDebug){Write-Host("[{0} - Script Debug] : {1}" -f $env:COMPUTERNAME, $stringdata) -ForegroundColor Cyan}}Function Zip-Folder {param([string]$Folder,[bool]$ZipItAll)if($PassedInfo.Zip){if(-not($ZipItAll)){#Zip location $zipFolder = $Folder + ".zip"if(Test-Path -Path $zipFolder){#Folder exist for some reason [int]$i = 1do{$zipFolder = $Folder + "-" + $i + ".zip"$i++}while(Test-Path -Path $zipFolder)}}else {$zipFolder = "{0}-{1}.zip" -f $Folder, (Get-Date -Format Md)if(Test-Path -Path $zipFolder){[int]$i = 1$date = Get-Date -Format Mddo{$zipFolder = "{0}-{1}-{2}.zip" -f $Folder, $date, $i$i++}while(Test-Path -Path $zipFolder)}}if(-not($ZipItAll)){Write-Host("[{0}] : Zipping up the folder {1}" -f $Script:LocalServerName, $Folder)}else{Write-Host("[{0}] : Zipping up all the data for the server...." -f $Script:LocalServerName)}[System.IO.Compression.ZipFile]::CreateFromDirectory($Folder, $zipFolder)if((Test-Path -Path $zipFolder)){Remove-Item $Folder -Force -Recurse}}}Function Copy-FullLogFullPathRecurse {param([Parameter(Mandatory=$true)][string]$LogPath,[Parameter(Mandatory=$true)][string]$CopyToThisLocation)   Remote-DisplayScriptDebug("Function Enter: Copy-FullLogFullPathRecurse")Remote-DisplayScriptDebug("Passed - LogPath: {0} CopyToThisLocation: {1}" -f $LogPath, $CopyToThisLocation)New-FolderCreate -Folder $CopyToThisLocation Copy-Item $LogPath\* $CopyToThisLocation -RecurseZip-Folder $CopyToThisLocationRemote-DisplayScriptDebug("Function Exit: Copy-FullLogFullPathRecurse")}Function Copy-LogsBasedOnTime {param([Parameter(Mandatory=$true)][string]$LogPath,[Parameter(Mandatory=$true)][string]$CopyToThisLocation)Remote-DisplayScriptDebug("Function Enter: Copy-LogsBasedOnTime")Remote-DisplayScriptDebug("Passed - LogPath: {0} CopyToThisLocation: {1}" -f $LogPath, $CopyToThisLocation)New-FolderCreate -Folder $CopyToThisLocation$date = (Get-Date).AddDays(0-$PassedInfo.DaysWorth)$copyFromDate = "$($Date.Month)/$($Date.Day)/$($Date.Year)"$SkipCopy = $false #We are not copying files recurse so we need to not include possible directories or we will throw an error $Files = Get-ChildItem $LogPath | Sort-Object LastWriteTime -Descending | ?{$_.LastWriteTime -ge $copyFromDate -and $_.Mode -notlike "d*"}#if we don't have any logs, we want to attempt to copy something if($Files -eq $null){Write-Warning("[{0}] : Oops! Looks like I wasn't able to find what you are looking for, so I am going to attempt to collect the newest log for you" -f $Script:LocalServerName)$Files = Get-ChildItem $LogPath | Sort-Object LastWriteTime -Descending | Select-Object -First 1 #If we are still null, we want to let them know If($Files -eq $null){$SkipCopy = $true Write-Warning("[{0}] : It doesn't look like you have any data in this location {1}." -f $Script:LocalServerName, $LogPath)Write-Warning("[{0}] : You should look into the reason as to why, because this shouldn't occur." -f $Script:LocalServerName)#Going to place a file in this location so we know what happened$tempFile = $CopyToThisLocation + "\NoFilesDetected.txt"New-Item $tempFile -ItemType File -Value $LogPath Start-Sleep 5}}Remote-DisplayScriptDebug("Found {0} number of files at the location {1}" -f $Files.Count, $LogPath)#ResetFiles to full path $FilesFullPath = @()$Files | %{$FilesFullPath += $_.VersionInfo.FileName}if(-not ($SkipCopy)){Copy-BulkItems -CopyToLocation $CopyToThisLocation -ItemsToCopyLocation $FilesFullPathZip-Folder -Folder $CopyToThisLocation}Remote-DisplayScriptDebug("Function Exit: Copy-LogsBasedOnTime")}Function Copy-BulkItems {param([string]$CopyToLocation,[Array]$ItemsToCopyLocation)#Create the folder New-FolderCreate -Folder $CopyToLocation foreach($item in $ItemsToCopyLocation){Copy-Item -Path $item -Destination $CopyToLocation}}Function Remove-EventLogChar {param([string]$location )Get-ChildItem $location | Rename-Item -NewName {$_.Name -replace "%4","-"}}Function Test-IISMultiW3SVCDirectores {if($Script:this_ServerObject.Version -ge 15){$i = 3}else{$i = 2}if((Get-ChildItem $Script:IISLogDirectory | ?{$_.Name -like "W3SVC*"}).Count -ge $i ){return $true}return $false}Function Test-CommandExists {param([string]$command)$oldAction = $ErrorActionPreference$ErrorActionPreference = "Stop"try {if(Get-Command $command){return $true}}catch {return $false}finally{$ErrorActionPreference = $oldAction}}Function Set-IISDirectoryInfo {Remote-DisplayScriptDebug("Function Enter: Set-IISDirectoryInfo")if((Test-CommandExists -command "Get-WebConfigurationProperty")){Remote-DisplayScriptDebug("Get-WebConfigurationProperty command exists")$Script:IISLogDirectory = ((Get-WebConfigurationProperty "system.applicationHost/sites/siteDefaults" -Name logFile).directory).Replace("%SystemDrive%",$env:SystemDrive) Remote-DisplayScriptDebug("Set IISLogDirectory: {0}" -f $Script:IISLogDirectory)}else {$Script:IISLogDirectory = "C:\inetpub\logs\LogFiles\" #Default location for IIS Logs Remote-DisplayScriptDebug("Get-WebConfigurationProperty command doesn't exists. Set IISLogDirectory to: {0}" -f $Script:IISLogDirectory)}if((-not(Test-Path $Script:IISLogDirectory)) -or (-not(Test-Path ($Script:IISLogDirectory + "\W3SVC1")))){#Something bad happened, We don't know where the logs are so we are going to return a false for that we failedWrite-Host("[{0}] : Failed to determine where the IIS Logs are located at. Unable to collect them." -f $Script:LocalServerName)return $false }Remote-DisplayScriptDebug("Function Exit: Set-IISDirectoryInfo")return $true }####### Collect Logs Functions #####################Function Collect-ServerInfo {Remote-DisplayScriptDebug("Function Enter: Collect-ServerInfo")$copyTo = $Script:RootCopyToDirectory + "\General_Server_Info"New-FolderCreate -Folder $copyTo #Get MSInfo from server msinfo32.exe /nfo $copyTo\msinfo.nfo Write-Warning("[{0}] : Waiting for msinfo32.exe process to end before moving on..." -f $Script:LocalServerName)while((Get-Process | ?{$_.ProcessName -eq "msinfo32"}).ProcessName -eq "msinfo32"){sleep 5;}Gcm exsetup | %{$_.FileVersionInfo} > "$copyTo\GCM.txt"fltmc > "$copyTo\FilterDrivers.txt"Get-HotFix | Select Source, Description, HotFixID, InstalledBy, InstalledOn | Export-Clixml "$copyTo\HotFixInfo.xml"Zip-Folder -Folder $copyToRemote-DisplayScriptDebug("Function Exit: Collect-ServerInfo")}Function Get-HighAvailabilityLogs_V15 {$Logs = @() $root = $script:LocalsysRoot$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4AppLogMirror.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4BlockReplication.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4Debug.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4Monitoring.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4Network.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4Operational.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4Seeding.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4TruncationDebug.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-MailboxDatabaseFailureItems%4Operational.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-MailboxDatabaseFailureItems%4Debug.evtx"return $Logs }Function Get-HighAvailabilityLogs_V14{$Logs = @()$root = $script:LocalsysRoot$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4BlockReplication.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4Debug.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4Operational.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4SeedingDebug.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-HighAvailability%4TruncationDebug.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-MailboxDatabaseFailureItems%4Operational.evtx"$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-MailboxDatabaseFailureItems%4Debug.evtx"return $Logs }Function Collect-HighAvailabilityLogs {if($Script:this_ServerObject.Mailbox){$copyTo = $Script:RootCopyToDirectory + "\High_Availability_logs"$Logs = @() if($Script:this_ServerObject.DAGMember){#Cluster log /g for some reason, we can't run this within invoke-command as we get a permission issue not sure why, as everything else works. #going to run this cmdlet outside of invoke-command like all the other exchange cmdlets $test = $script:LocalsysRoot + "\Cluster\Reports\Cluster.log"if(Test-Path -Path $test){$Logs += $test}}if($Script:this_ServerObject.Version -ge 15){$Logs += Get-HighAvailabilityLogs_V15}elseif($Script:this_ServerObject.Version -eq 14){$Logs += Get-HighAvailabilityLogs_V14 }else {Write-Host("[{0}] : unknown server version: {1}" -f $Script:LocalServerName, $Script:this_ServerObject.Version) -ForegroundColor Redreturn }Copy-BulkItems -CopyToLocation $copyTo -ItemsToCopyLocation $Logs Remove-EventLogChar -location $copyToZip-Folder -Folder $copyTo}else {Write-Host("[{0}] : Doesn't look like this server has the Mailbox Role Installed. Not going to collect the High Availability Logs" -f $Script:LocalServerName)}}Function Collect-AppSysLogs {$root = $script:LocalsysRoot$Logs = @()$Logs += $root + "\System32\Winevt\Logs\Application.evtx"$Logs += $root + "\System32\Winevt\Logs\system.evtx"$Logs += $root + "\System32\Winevt\Logs\MSExchange Management.evtx"$copyTo = $Script:RootCopyToDirectory + "\App_Sys_Logs"Copy-BulkItems -CopyToLocation $copyTo -ItemsToCopyLocation $Logs Zip-Folder -Folder $copyTo}Function Collect-ManagedAvailabilityLogs {$root = $script:LocalsysRoot$Logs = @()$Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-ActiveMonitoring%4ProbeResult.evtx" #Probe Results Logs $Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-ManagedAvailability%4RecoveryActionResults.evtx" #Recovery Action Results Logs $Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-ManagedAvailability%4RecoveryActionLogs.evtx" #Recovery Action Logs $Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-ActiveMonitoring%4ResponderDefinition.evtx" #Responder Definition Logs $Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-ActiveMonitoring%4ResponderResult.evtx" #Responder Results Logs $Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-ActiveMonitoring%4MonitorDefinition.evtx" #Monitor Definition Logs $Logs += $root + "\System32\Winevt\Logs\Microsoft-Exchange-ManagedAvailability%4Monitoring.evtx" #Monitoring Logs $copyTo = $Script:RootCopyToDirectory + "\MA_Logs"Copy-BulkItems -CopyToLocation $copyTo -ItemsToCopyLocation $LogsRemove-EventLogChar -location $copyTo Zip-Folder -Folder $copyTo }Function Enable-ZipAssembly {$oldErrorAction = $ErrorActionPreference$ErrorActionPreference = "Stop"try {Add-Type -AssemblyName System.IO.Compression.Filesystem }catch {Write-Host("[{0}] : Failed to load .NET Compression assembly. Disable the ability to zip data" -f $Script:LocalServerName)$PassedInfo.Zip = $false}finally{$ErrorActionPreference = $oldErrorAction}}Function Get-ThisServerObject {foreach($srv in $PassedInfo.ServerObjects){if($srv.ServerName -eq $Script:LocalServerName){$Script:this_ServerObject = $srv }}if($Script:this_ServerObject -eq $null -or $Script:this_ServerObject.ServerName -ne $Script:LocalServerName){#Something went wrong.... Write-Host("[{0}] : Something went wrong trying to find the correct Server Object for this server. Stopping this instance of Execution"-f $Script:LocalServerName)exit }}Function Set-RootCopyDirectory{$date = Get-Date -Format yyyyMd$str = "{0}\{1}\{2}" -f $PassedInfo.FilePath, $date, $Script:LocalServerNamereturn $str}Function Set-InstanceRunningVars{$Script:LocalServerName = $env:COMPUTERNAME$script:LocalsysRoot = $env:SystemRoot$Script:RootCopyToDirectory = Set-RootCopyDirectory#Set the local Server Object Information Get-ThisServerObject #Set Exchange Install path per running instance if((Test-Path 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup')){#Exchange 2010 install $Script:this_Exinstall = (get-itemproperty HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup).MsiInstallPath  }elseif((Test-Path 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup')){#Exchange 2013 and 2016$Script:this_Exinstall = (get-itemproperty HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath }else {Write-Host("[{0}] : Something went wrong trying to find the Exchange install path on this server. Stopping this instance of Execution" -f $Script:LocalServerName)exit }        #shortcut to Exbin directory (probably not really needed)$Script:this_ExBin = $Script:this_Exinstall + "Bin\"}Function Save-DataInfoToFile {param($dataIn,$SaveToLocation )$xmlOut = $SaveToLocation + ".xml"$txtOut = $SaveToLocation + ".txt"if($data -ne $null){$dataIn | Export-Clixml $xmlOut -Encoding UTF8$dataIn | fl * | Out-File $txtOut}}####################################                                 ##         Logman Functions        ##                                 ####################################Function Start-Logman {param([Parameter(Mandatory=$true)][string]$logmanName,[Parameter(Mandatory=$true)][string]$Server_Name)Write-Host("Starting Data Collection {0} on server {1}" -f $logmanName,$Server_Name)logman start -s $Server_Name $logmanName}Function Stop-Logman {param([Parameter(Mandatory=$true)][string]$logmanName,[Parameter(Mandatory=$true)][string]$Server_Name)Write-Host("Stopping Data Collection {0} on server {1}" -f $logmanName,$Server_Name)logman stop -s $Server_Name $logmanName}Function Copy-LogmanData{param([Parameter(Mandatory=$true)]$objLogman)switch ($objLogman.LogmanName){"Exchange_Perfwiz" {$FolderName = "ExPerfWiz_Data"; break}"Exmon_Trace" {$FolderName = "ExmonTrace_Data"; break}default {$FolderName = "Logman_Data"; break}}$strDirectory = $objLogman.RootPath$copyTo = $Script:RootCopyToDirectory + "\" + $FolderNameNew-FolderCreate -Folder $copyToif(Test-Path $strDirectory){$wildExt = "*" + $objLogman.Ext$filterDate = $objLogman.StartDate$files = Get-ChildItem $strDirectory | ?{($_.Name -like $wildExt) -and ($_.CreationTime -ge $filterDate)}if($files -ne $null){foreach($file in $files){Write-Host("[{0}] : Copying over file {1}..." -f $Script:LocalServerName, $file.VersionInfo.FileName)copy $file.VersionInfo.FileName $copyTo}Zip-Folder -Folder $copyTo}else {Write-Host ("[{0}] : Failed to find any files in the directory: '{1}' that was greater than or equal to this time: {2}" -f $Script:LocalServerName, $strDirectory, $filterDate) -ForegroundColor YellowWrite-Host ("[{0}] : Going to try to see if there are any files in this directory for you..." -f $Script:LocalServerName) -NoNewline$files = Get-ChildItem $strDirectory | ?{$_.Name -like $wildExt}if($files -ne $null){#only want to get lastest data $newestFilesTime = ($files | Sort CreationTime -Descending)[0].CreationTime.AddDays(-1)$newestFiles = $files | ?{$_.CreationTime -ge $newestFilesTime}foreach($file in $newestFiles){Write-Host("[{0}] : Copying over file {1}..." -f $Script:LocalServerName, $file.VersionInfo.FileName)copy $file.VersionInfo.FileName $copyTo}Zip-Folder -Folder $copyTo}else {Write-Warning ("[{0}] : Failed to find any files in the directory: '{1}'" -f $Script:LocalServerName, $strDirectory)      $tempFile = $copyTo + "\NoFiles.txt"    New-Item $tempFile -ItemType File -Value $strDirectory}}}else {Write-Warning ("[{0}] : Doesn't look like this Directory is valid. {1}" -f $Script:LocalServerName, $strDirectory)$tempFile = $copyTo + "\NotValidDirectory.txt"New-Item $tempFile -ItemType File -Value $strDirectory}}Function Get-LogmanData {param([Parameter(Mandatory=$true)][string]$logmanName,[Parameter(Mandatory=$true)][string]$Server_Name)$objLogman = Get-LogmanObject -logmanName $logmanName -Server_Name $Server_Nameif($objLogman -ne $null){switch ($objLogman.Status) {"Running" {Write-Host ("[{0}] : Looks like logman {1} is running...." -f $Script:LocalServerName, $logmanName)Write-Host ("[{0}] : Going to stop {1} to prevent corruption...." -f $Script:LocalServerName, $logmanName)Stop-Logman -logmanName $logmanName -Server_Name $Server_NameCopy-LogmanData -objLogman $objLogmanWrite-Host("[{0}] : Starting Logman {1} again for you...." -f $Script:LocalServerName, $logmanName)Start-Logman -logmanName $logmanName -Server_Name $Server_NameWrite-Host ("[{0}] : Done starting Logman {1} for you" -f $Script:LocalServerName, $logmanName)break;}"Stopped" {Write-Host ("[{0}] : Doesn't look like Logman {1} is running, so not going to stop it..." -f $Script:LocalServerName, $logmanName)Copy-LogmanData -objLogman $objLogmanbreak;}Default {Write-Host ("[{0}] : Don't know what the status of Logman '{1}' is in" -f $Script:LocalServerName, $logmanName)Write-Host ("[{0}] : This is the status: {1}" -f $Script:LocalServerName, $objLogman.Status)Write-Host ("[{0}] : Going to try stop it just in case..." -f $Script:LocalServerName)Stop-Logman -logmanName $logmanName -Server_Name $Server_NameCopy-LogmanData -objLogman $objLogmanWrite-Host ("[{0}] : Not going to start it back up again...." -f $Script:LocalServerName)Write-Warning ("[{0}] : Please start this logman '{1}' if you need to...." -f $Script:LocalServerName, $logmanName)break; }}}else {Write-Host("[{0}] : Can't find {1} on {2} ..... Moving on." -f $Script:LocalServerName, $logmanName, $Server_Name)    }}Function Get-LogmanStatus {param([Parameter(Mandatory=$true)]$rawLogmanData )$status = "Status:"$stop = "Stopped"$run = "Running"if(-not($rawLogmanData[2].Contains($status))){$i = 0while((-not($rawLogmanData[$i].Contains($status))) -and ($i -lt ($rawLogmanData.count - 1))){$i++}}else {$i = 2}$strLine = $rawLogmanData[$i]if($strLine.Contains($stop)){$currentStatus = $stop}elseif($strLine.Contains($run)){$currentStatus = $run}else{$currentStatus = "unknown"}return $currentStatus}Function Get-LogmanRootPath {param([Parameter(Mandatory=$true)]$rawLogmanData)$Root_Path = "Root Path:"if(-not($rawLogmanData[3].Contains($Root_Path))){$i = 0while((-not($rawLogmanData[$i].Contains($Root_Path))) -and ($i -lt ($rawLogmanData.count - 1))){$i++}}else {$i = 3}$strRootPath = $rawLogmanData[$i]$replace = $strRootPath.Replace("Root Path:", "")[int]$Index = $replace.IndexOf(":") - 1$strReturn = $replace.SubString($Index)return $strReturn}Function Get-LogmanStartDate {param([Parameter(Mandatory=$true)]$rawLogmanData)$strStart_Date = "Start Date:"if(-not($rawLogmanData[11].Contains($strStart_Date))){$i = 0while((-not($rawLogmanData[$i].Contains($strStart_Date))) -and ($i -lt ($rawLogmanData.count - 1))){$i++}#Circular Log collection doesn't contain Start Dateif(-not($rawLogmanData[$i].Contains($strStart_Date))){$strReturn = (Get-Date).AddDays(-1).ToString()return $strReturn}}else {$i = 11}$strLine = $rawLogmanData[$i][int]$index = $strLine.LastIndexOf(" ") + 1 $strReturn = $strLine.SubString($index)return $strReturn}Function Get-LogmanExt {param([Parameter(Mandatory=$true)]$rawLogmanData )$strLocation = "Output Location:"if(-not($rawLogmanData[15].Contains($strLocation))){$i = 0while((-not($rawLogmanData[$i].Contains($strLocation))) -and ($i -lt ($rawLogmanData.Count - 1))){$i++}}else{ $i = 15}$strLine = $rawLogmanData[$i][int]$index = $strLine.LastIndexOf(".")if($index -ne -1){$strExt = $strLine.SubString($index)}else {$strExt = $null}return $strExt}Function Get-LogmanObject {param([Parameter(Mandatory=$true)][string]$logmanName,[Parameter(Mandatory=$true)][string]$Server_Name)$rawDataResults = logman -s $Server_Name $logmanNameif($rawDataResults[$rawDataResults.Count - 1].Contains("Set was not found.")){return $null}else {$objLogman = New-Object -TypeName psobject$objLogman | Add-Member -MemberType NoteProperty -Name LogmanName -Value $logmanName$objLogman | Add-Member -MemberType NoteProperty -Name Status -Value (Get-LogmanStatus -rawLogmanData $rawDataResults)$objLogman | Add-Member -MemberType NoteProperty -Name RootPath -Value (Get-LogmanRootPath -rawLogmanData $rawDataResults)$objLogman | Add-Member -MemberType NoteProperty -Name StartDate -Value (Get-LogmanStartDate -rawLogmanData $rawDataResults)$objLogman | Add-Member -MemberType NoteProperty -Name Ext -Value (Get-LogmanExt -rawLogmanData $rawDataResults)$objLogman | Add-Member -MemberType NoteProperty -Name RestartLogman -Value $false$objLogman | Add-Member -MemberType NoteProperty -Name ServerName -Value $Server_Name$objLogman | Add-Member -MemberType NoteProperty -Name RawData -Value $rawDataResults$objLogman | Add-Member -MemberType NoteProperty -Name SaveRootLocation -Value $FilePathreturn $objLogman}}Function  Collect-LogmanExperfwiz{Get-LogmanData -logmanName $PassedInfo.Experfwiz_LogmanName -Server_Name $Script:LocalServerName}Function Collect-LogmanExmon{Get-LogmanData -logmanName $PassedInfo.Exmon_LogmanName -Server_Name $Script:LocalServerName}Function Remote-Main {Remote-DisplayScriptDebug("Function Enter: Remote-Main")Set-InstanceRunningVarsif($PassedInfo.Zip){Enable-ZipAssembly}$cmdsToRun = @() ##############################################                                           ##              Exchange 2013 +              ##                                           ##############################################$copyInfo = "-LogPath '{0}' -CopyToThisLocation '{1}'"if($Script:this_ServerObject.Version -ge 15){Remote-DisplayScriptDebug("Server Version greater than 15")if($PassedInfo.EWSLogs){if($Script:this_ServerObject.Mailbox){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\EWS"),($Script:RootCopyToDirectory + "\EWS_BE_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){ $cmdsToRun += ("Copy-LogsBasedOnTime {0}" -f $info)}else {$cmdsToRun += ("Copy-FullLogFullPathRecurse {0}" -f $info)}}if($Script:this_ServerObject.CAS){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\HttpProxy\Ews"),($Script:RootCopyToDirectory + "\EWS_Proxy_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){ $cmdsToRun += ("Copy-LogsBasedOnTime {0}" -f $info)}else{$cmdsToRun += ("Copy-FullLogFullPathRecurse {0}" -f $info)}}}if($PassedInfo.RPCLogs){if($Script:this_ServerObject.Mailbox){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\RPC Client Access"), ($Script:RootCopyToDirectory + "\RCA_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){ $cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else{$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}if($Script:this_ServerObject.CAS){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\HttpProxy\RpcHttp"), ($Script:RootCopyToDirectory + "\RCA_Proxy_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){ $cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else{$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\RpcHttp"), ($Script:RootCopyToDirectory + "\RPC_Http_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth) {$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info }else {$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}if($Script:this_ServerObject.CAS -and $PassedInfo.EASLogs){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\HttpProxy\Eas"), ($Script:RootCopyToDirectory + "\EAS_Proxy_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth) {$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else {$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}if($PassedInfo.AutoDLogs){if($Script:this_ServerObject.Mailbox){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\Autodiscover"), ($Script:RootCopyToDirectory + "\AutoD_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth) {$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else { $cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}if($Script:this_ServerObject.CAS){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\HttpProxy\Autodiscover"), ($Script:RootCopyToDirectory + "\AutoD_Proxy_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth) {$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else { $cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info }}}if($PassedInfo.OWALogs){if($Script:this_ServerObject.Mailbox){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\OWA"), ($Script:RootCopyToDirectory + "\OWA_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth) {$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else {$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}if($Script:this_ServerObject.CAS){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\HttpProxy\OwaCalendar"), ($Script:RootCopyToDirectory + "\OWA_Proxy_Calendar_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth) {$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else { $cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\HttpProxy\Owa"), ($Script:RootCopyToDirectory + "\OWA_Proxy_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth) {$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info }else {$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}}if($PassedInfo.ADDriverLogs){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\ADDriver"), ($Script:RootCopyToDirectory + "\AD_Driver_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){ $cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else {$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}if($PassedInfo.MapiLogs){if($Script:this_ServerObject.Mailbox){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\MAPI Client Access"), ($Script:RootCopyToDirectory + "\MAPI_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth) {$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else {$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}if($Script:this_ServerObject.CAS){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\HttpProxy\Mapi"), ($Script:RootCopyToDirectory + "\MAPI_Proxy_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else {$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}}if($PassedInfo.ECPLogs){if($Script:this_ServerObject.Mailbox){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\ECP"), ($Script:RootCopyToDirectory + "\ECP_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else {$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}if($Script:this_ServerObject.CAS){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\HttpProxy\Ecp"), ($Script:RootCopyToDirectory + "\ECP_Proxy_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else {$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}}if($Script:this_ServerObject.Mailbox -and $PassedInfo.SearchLogs){$info = ($copyInfo -f ($Script:this_ExBin + "Search\Ceres\Diagnostics\Logs"), ($Script:RootCopyToDirectory + "\Search_Diag_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info $info = ($copyInfo -f ($Script:this_ExBin + "Search\Ceres\Diagnostics\ETLTraces"), ($Script:RootCopyToDirectory + "\Search_Diag_ETLs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}if($PassedInfo.DailyPerformanceLogs){#Daily Performace Logs are always by days worth $info = ($copyInfo -f ($Script:this_Exinstall + "Logging\Diagnostics\DailyPerformanceLogs"), ($Script:RootCopyToDirectory + "\Daily_Performance_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info }if($PassedInfo.ManagedAvailability){  $cmdsToRun += 'Collect-ManagedAvailabilityLogs'}if($PassedInfo.IISLogs){if(Set-IISDirectoryInfo){if(-not(Test-IISMultiW3SVCDirectores)){if($Script:this_ServerObject.CAS){$info = ($copyInfo -f ($Script:IISLogDirectory + "\W3SVC1"), ($Script:RootCopyToDirectory + "\IIS_FE_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}if($Script:this_ServerObject.Mailbox){$info = ($copyInfo -f ($Script:IISLogDirectory + "\W3SVC2"), ($Script:RootCopyToDirectory + "\IIS_BE_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}}else {$Folders = Get-ChildItem $Script:IISLogDirectoryforeach($folder in $Folders.Name){if($folder -like "W3SVC*"){$info = ($copyInfo -f ($Script:IISLogDirectory + "\" + $folder), ($Script:RootCopyToDirectory + "\IIS_" + $folder + "_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}}}$info = ($copyInfo -f ($script:LocalsysRoot +"\System32\LogFiles\HTTPERR"), ($Script:RootCopyToDirectory + "\HTTPERR_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info }}}#############################################                                          ##              Exchange 2010               ##                                          #############################################if($Script:this_ServerObject.Version -eq 14){if($Script:this_ServerObject.CAS){if($PassedInfo.RPCLogs){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\RPC Client Access"), ($Script:RootCopyToDirectory + "\RCA_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){ $cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else{$cmdsToRun += "Copy-FullLogFullPathRecurse {0}" -f $info}}if($PassedInfo.EWSLogs){$info = ($copyInfo -f ($Script:this_Exinstall + "Logging\EWS"),($Script:RootCopyToDirectory + "\EWS_BE_Logs"))if($PassedInfo.CollectAllLogsBasedOnDaysWorth){ $cmdsToRun += ("Copy-LogsBasedOnTime {0}" -f $info)}else {$cmdsToRun += ("Copy-FullLogFullPathRecurse {0}" -f $info)}}}if($PassedInfo.IISLogs -and (Set-IISDirectoryInfo)){if(-not (Test-IISMultiW3SVCDirectores)){$info = ($copyInfo -f ($Script:IISLogDirectory + "\W3SVC1"), ($Script:RootCopyToDirectory + "\IIS_FE_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}else {$Folders = Get-ChildItem $Script:IISLogDirectoryforeach($folder in $Folders.Name){if($folder -like "W3SVC*"){$info = ($copyInfo -f ($Script:IISLogDirectory + "\" + $folder), ($Script:RootCopyToDirectory + "\IIS_" + $folder + "_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}}}$info = ($copyInfo -f ($script:LocalsysRoot +"\System32\LogFiles\HTTPERR"), ($Script:RootCopyToDirectory + "\HTTPERR_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info }}#############################################                                          ##          All Exchange Versions           ##                                          #############################################if($PassedInfo.AnyTransportSwitchesEnabled -and $Script:this_ServerObject.TransportInfoCollect){if($PassedInfo.MessageTrackingLogs){$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.HubLoggingInfo.MessageTrackingLogPath), ($Script:RootCopyToDirectory + "\Message_Tracking_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}if($PassedInfo.HubProtocolLogs){$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.HubLoggingInfo.ReceiveProtocolLogPath), ($Script:RootCopyToDirectory + "\Hub_Receive_Protocol_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.HubLoggingInfo.SendProtocolLogPath), ($Script:RootCopyToDirectory + "\Hub_Send_Protocol_Logs"))}if($PassedInfo.HubConnectivityLogs){$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.HubLoggingInfo.ConnectivityLogPath), ($Script:RootCopyToDirectory + "\Hub_Connectivity_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}if($PassedInfo.QueueInformationThisServer){#current queue data $data = $Script:this_ServerObject.TransportInfo.QueueData$create = $Script:RootCopyToDirectory + "\Queue_Data"New-FolderCreate $create $saveLocation = $create + "\Current_Queue_Info"Save-DataInfoToFile -dataIn $data -SaveToLocation $saveLocationif($Script:this_ServerObject.Version -ge 15){$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.HubLoggingInfo.QueueLogPath), ($Script:RootCopyToDirectory + "\Queue_V15_Data"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}}if($PassedInfo.ReceiveConnectors){$data = $Script:this_ServerObject.TransportInfo.ReceiveConnectorData$create = $Script:RootCopyToDirectory + "\Connectors"New-FolderCreate $create$saveLocation = ($create + "\{0}_Receive_Connectors") -f $Script:LocalServerNameSave-DataInfoToFile -dataIn $data -SaveToLocation $saveLocation}if($PassedInfo.TransportConfig){if($Script:this_ServerObject.Version -ge 15){$items = @()$items += $Script:this_ExBin + "\EdgeTransport.exe.config" $items += $Script:this_ExBin + "\MSExchangeFrontEndTransport.exe.config" $items += $Script:this_ExBin + "\MSExchangeDelivery.exe.config" $items += $Script:this_ExBin + "\MSExchangeSubmission.exe.config"}else {$items = @()$items += $Script:this_ExBin + "\EdgeTransport.exe.config"}Copy-BulkItems -CopyToLocation ($Script:RootCopyToDirectory + "\Transport_Configuration") -ItemsToCopyLocation $items}#Exchange 2013+ only if($Script:this_ServerObject.Version -ge 15){if($PassedInfo.FrontEndConnectivityLogs){$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.FELoggingInfo.ConnectivityLogPath), ($Script:RootCopyToDirectory + "\FE_Connectivity_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}if($PassedInfo.FrontEndProtocolLogs){$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.FELoggingInfo.ReceiveProtocolLogPath), ($Script:RootCopyToDirectory + "\FE_Receive_Protocol_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.FELoggingInfo.SendProtocolLogPath), ($Script:RootCopyToDirectory + "\FE_Send_Protocol_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}if($PassedInfo.MailboxConnectivityLogs){$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.MBXLoggingInfo.ConnectivityLogPath + "\Delivery"), ($Script:RootCopyToDirectory + "\MBX_Delivery_Connectivity_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.MBXLoggingInfo.ConnectivityLogPath + "\Submission"), ($Script:RootCopyToDirectory + "\MBX_Submission_Connectivity_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}if($PassedInfo.MailboxProtocolLogs){$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.MBXLoggingInfo.ReceiveProtocolLogPath), ($Script:RootCopyToDirectory + "\MBX_Receive_Protocol_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info$info = ($copyInfo -f ($Script:this_ServerObject.TransportInfo.MBXLoggingInfo.SendProtocolLogPath), ($Script:RootCopyToDirectory + "\MBX_Send_Protocol_Logs"))$cmdsToRun += "Copy-LogsBasedOnTime {0}" -f $info}}}if($PassedInfo.HighAvailabilityLogs){$cmdsToRun += "Collect-HighAvailabilityLogs"}if($PassedInfo.ServerInfo){$cmdsToRun += "Collect-ServerInfo"}if($PassedInfo.AppSysLogs){$cmdsToRun += 'Collect-AppSysLogs'}if($PassedInfo.Experfwiz){$cmdsToRun += "Collect-LogmanExperfwiz"}if($PassedInfo.Exmon){$cmdsToRun += "Collect-LogmanExmon"}#Execute the cmds foreach($cmd in $cmdsToRun){Remote-DisplayScriptDebug("cmd: {0}" -f $cmd)Invoke-Expression $cmd}#Dump out the data that only needs to be collected once, on the server that hosted the execution of the scriptif($Script:LocalServerName -eq ($PassedInfo.HostExeServerName)){Remote-DisplayScriptDebug("Writting only once data")if($PassedInfo.GetVdirs){$target = $Script:RootCopyToDirectory + "\ConfigNC_msExchVirtualDirectory_All.CSV"$PassedInfo.VDirsInfo | Sort-Object -Property Server | Export-Csv $target -NoTypeInformation}if($PassedInfo.DAGInformation){$data = $PassedInfo.DAGInfoData $dagName = $data.DAGInfo.Name $create =  $Script:RootCopyToDirectory + "\" + $dagName + "_DAG_MDB_Information"New-FolderCreate -Folder $create $saveLocation = $create + "\{0}"Save-DataInfoToFile -dataIn ($data.DAGInfo) -SaveToLocation ($saveLocation -f ($dagName +"_DAG_Info"))Save-DataInfoToFile -dataIn ($data.DAGNetworkInfo) -SaveToLocation ($saveLocation -f ($dagName + "DAG_Network_Info"))foreach($mdb in $data.AllMdbs){Save-DataInfoToFile -dataIn ($mdb.MDBInfo) -SaveToLocation ($saveLocation -f ($mdb.MDBName + "_DB_Info"))Save-DataInfoToFile -dataIn ($mdb.MDBCopyStatus) -SaveToLocation ($saveLocation -f ($mdb.MDBName + "_DB_CopyStatus"))}}if($PassedInfo.SendConnectors){$data = $PassedInfo.SendConnectorData$create = $Script:RootCopyToDirectory + "\Connectors"New-FolderCreate $create$saveLocation = $create + "\Send_Connectors"Save-DataInfoToFile -dataIn $data -SaveToLocation $saveLocation}}#Zip it all up Zip-Folder -Folder $Script:RootCopyToDirectory -ZipItAll $true}Remote-Main}##################Main###################
Function Main {Display-DisclaimerTest-PossibleCommonScenariosTest-NoSwitchesProvidedif(-not (Is-Admin)){Write-Warning "Hey! The script needs to be executed in elevated mode. Start the Exchange Mangement Shell as an Administrator."exit }Load-ExShellif($Servers -ne $null){#possible to return null or only a single server back (localhost)$ValidServers = Test-RemoteExecutionOfServers -Server_List $Serversif($ValidServers -ne $null){$ValidServers = Test-DiskSpace -Servers $ValidServers -Path $FilePath -CheckSize 15$remote_ScriptingBlock = ${Function:Remote-Functions}Invoke-Command -ComputerName $ValidServers -ScriptBlock $remote_ScriptingBlock -ArgumentList (Get-ArgumentList -Servers $ValidServers)$RootPath = "{0}\{1}\" -f $FilePath, (Get-Date -Format yyyyMd)$LogPaths = Get-RemoteLogLocation -Servers $ValidServers -RootPath $RootPathif((-not($SkipEndCopyOver)) -and (Test-DiskSpaceForCopyOver -LogPathObject $LogPaths -RootPath $RootPath)){Write-Host("")Write-Host("Copying over the data may take some time depending on the network")foreach($svr in $LogPaths){#Don't want to do the local hostif($svr.ServerName -ne $env:COMPUTERNAME){$remoteCopyLocation = "\\{0}\{1}" -f $svr.ServerName, ($svr.ZipFolder.Replace(":","$"))Write-Host("[{0}] : Copying File {1}...." -f $svr.ServerName, $remoteCopyLocation) Copy-Item -Path $remoteCopyLocation -Destination $RootPathWrite-Host("[{0}] : Done copying file" -f $svr.ServerName)}}}else {Write-Host("")Write-Host("Please collect the following files from these servers and upload them: ")foreach($svr in $LogPaths){Write-Host("Server: {0} Path: {1}" -f $svr.ServerName, $svr.ZipFolder) }}}else {#We have failed to do invoke-command on all the servers.... so we are going to do the same logic locallyWrite-Host("Failed to do remote collection for all the servers in the list...") -ForegroundColor Yellowdo{$read = Read-Host("Do you want me to collect from the local server only? 'y' or 'n'")}while($read -ne "y" -and $read -ne "n")if($read -eq "y"){Remote-Functions -PassedInfo (Get-ArgumentList -Servers $env:COMPUTERNAME)}}}else {Write-Host("Note: Remote Collection is now possible for Windows Server 2012 and greater on the remote machine. Just use the -Servers paramater with a list of Exchange Server names") -ForegroundColor YellowWrite-Host("Going to collect the data locally")Remote-Functions -PassedInfo (Get-ArgumentList -Servers $env:COMPUTERNAME)}Display-FeedBack}Main

转载于:https://blog.51cto.com/3032439/2067984

Exchange Log Collector Script相关推荐

  1. 【Ubuntu】ubuntu工具 记录shell终端的内容到文件中:script

    ###用法 $ script -h Usage: script [options] [file] Options: -a, --append append the output -c, --comma ...

  2. 自己编写jQuery动态引入js文件插件 (jquery.import.dynamic.script)

    这个插件主要是结合jquery或者xhr异步请求来使用的,它可以把已经引入过的js文件记录在浏览器内存中,当下次再引入相同的文件就忽略该文件的引入. 当你用$.load("dir/my-pa ...

  3. linux小工具(2)终端记录器script命令

    前言:(内容不多,请耐心阅读) 首先,终端界面的显示是有缓存大小限制的,当在终端打印的消息超出缓存范围,它前面的打印消息就自动丢失. 那么,当需要记录下一段时间内的shell终端的所有输入命令和打印消 ...

  4. script标签里src为php,如何获取指定为script标记的'src'的文件的内容?

    tl; dr脚本标记不受CORS和同源策略的约束,因此javascript / DOM无法提供对通过 长版本: 大多数其他答案(以及公认的答案)正确表明," 正确 "的方式来获取通 ...

  5. javascript --- [jsonp] script标签的妙用(绕过同源限制)

    1. 同源 1.1 什么是同源 协议.域名.端口号相同 1.2 为什么有同源政策 同源政策是为了保护用户信息的安全,放置恶意的网站窃取数据.最初的同源政策是指A网站再客户端设置的Cookie,B网站是 ...

  6. vue 3.2 的 script setup 语法

    vue 3.2 已经正式支持 <script setup> 语法,并且现在就可以在生产环境下使用了,接下开始学习基本用法. <script setup> 是在单文件组件 (SF ...

  7. script setup 实验性 vue 语法

    这是一个简单的计数器例子,模板中使用 count 变量,inc 函数. <template><button @click="inc">{{count}}&l ...

  8. Java Script 02

    JS 对象 JS对象有哪些分类 宿主对象(host Objects):是由JS宿主环境提高的对象.它的行为完全由宿主环境决定,比如web浏览器. 内置对象:由JS语言提高的对象(Date对象,Math ...

  9. java script基础入门·2

    java script基础入门2 方法声明 <script>function arr(a,b) {return a+b;}let sum=arr(11,12);window.documen ...

最新文章

  1. eclipse或者myeclipse的代码提示功能
  2. sklearn GBDT(梯度下降树)模型使用RandomSearchCV获取最优参数及可视化​​​​​​​
  3. c++:用顺序表实现简单的栈
  4. js用button激活 Alert 元素关闭按钮的交互功能
  5. 禁用win10触摸屏手势_Win10平板边缘滑动手势大全及开启/关闭方法
  6. c++多线程结束后需要释放_缓刑结束后是否需要继续坐牢?
  7. Hanoi 汉诺塔——通俗易懂地讲解(c++)
  8. ScalaTour 2.函数
  9. 前端json编辑器和富文本编辑器的使用
  10. Java .class 反编译 Luyten,导出 .java文件,查看jar 包目录,超级简单,实用
  11. 双轨制二叉树节点对象
  12. Playground 教程之SceneKit绘制个Torus圆环面
  13. 为什么有的人职场上混得如鱼得水,有的人却混得狼狈不堪呀?
  14. IE浏览器快速切换各个版本
  15. vanilla是什么意思
  16. 数学家对物理学家的鄙视_物理学家的未来经济学
  17. 欢聚时代”狼人杀“产品岗面试总结——产品岗
  18. 平塘天眼和大数据有什么关系_聊聊平塘“天眼”的那些事儿,“FAST”到底有多牛?...
  19. 亿级流量电商网站微服务架构图(图灵学院)
  20. ABB系统备份与恢复(重做系统)S4C系统

热门文章

  1. Oracle的连接与会话
  2. urlScan 配置阻止sql注入
  3. 非常漂亮的仿腾讯弹出层效果
  4. 终端的录制、回放与实时共享
  5. 亲近自然的加州玻璃豪宅
  6. maemo环境安装问题和解决方案(ubuntu 10.04)
  7. python列表修改数据_使用列表理解修改数据框架列
  8. ios NSString 正则表达式 其它字符
  9. Wireshark网络分析实例集锦(大学霸内部资料)
  10. qchart画完以后删除_画错了,重新画一幅吧!”这句话对学画画的孩子来说,伤害有多大?...