[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
set-executionpolicy -executionpolicy  RemoteSigned

$egurkhaPath=(Get-Item Env:EGURKHA_INSTALL_DIR).value.ToString()
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$egEncryPath=$scriptPath+"\EGFileEncryption.psm1"
$egDatnKy=$scriptPath+"\GetDatnKeyFiles.psm1"
Import-Module $egEncryPath,$egDatnKy

$testargs=$args
$userName=$testargs[0]
$Password=Eg-O365Dcr -EncStr $testargs[1]
$proxyUsr=$testargs[2]
$proxyPass=Eg-O365Dcr -EncStr $testargs[3]
$rName=$testargs[4]
if($proxyUsr.toString().toLower().Trim() -eq 'none') { $proxyUsr=$proxyUsr.toString().toLower().Trim() }
if($proxyPass.toString().toLower().Trim() -eq 'none') { $proxyPass=$proxyPass.toString().toLower().Trim() }

clear

$RprtNameAndmTime=$rName.split("#")
$reportingname=$RprtNameAndmTime[0]
$mTime=$RprtNameAndmTime[1]

$azureVal=Eg-GetAzureEnv -UserName $userName
$azureEnvArr=$azureVal.Split(',')



$ManualThrottle=0
[double]$ActiveThrottle=.25
$ResetSeconds=870

$MyDir=$egurkhaPath+'/agent/EXO/'+$reportingname
if(!(Test-Path -Path $MyDir )){
    New-Item -ItemType directory -Path $MyDir
} 
$WriteLog=$true
$LogFile = $egurkhaPath+'/agent/EXO/'+$reportingname+"\groups.log"
$LogFile1 = $egurkhaPath+'/agent/EXO/'+$reportingname+"\groups1.log"
$isFrstTimLog=$true



# Writes output to a log file with a time date stamp
Function Write-Log {
	Param ([string]$string)

	[string]$date = Get-Date -Format G
	
    if ($WriteLog) {
       ( "[" + $date + "] - [" + $reportingname+"] mTime -  " + $mTime + " - " + $string ) | Out-File -FilePath $LogFile -Append } 

    if($isFrstTimLog){     
        if ($WriteLog -eq $true){ #if flag is true 
            if ([System.IO.File]::Exists($LogFile) -and (Get-Item $LogFile).length -gt 2mb) {  #if the size of file is greater than 1MB 
                if([System.IO.File]::Exists($LogFile1)){  #if logfile1 already exists, delete logfile1 
                    Remove-Item $LogFile1 
                } 
                Rename-Item $LogFile $LogFile1 
            }
        }
        $isFrstTimLog=$false
    }

}

Function Start-SleepWithProgress {
	Param([int]$sleeptime)

	For ($i=0;$i -le $sleeptime;$i++){
		$timeleft = ($sleeptime - $i);
		Write-Progress -Activity "Sleeping" -CurrentOperation "$Timeleft More Seconds" -PercentComplete (($i/$sleeptime)*100);
		start-sleep 1
	}
	
	Write-Progress -Completed -Activity "Sleeping"
}

Function New-CleanO365Session {

    $Credential = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $userName, $(convertto-securestring $Password -asplaintext -force)
	
    $i = 0
	while (($Credential -eq $Null) -and ($i -lt 5)){
		$script:Credential = Get-Credential -Message "Please provide your Exchange Online Credentials"
		$i++
	}

	if ($Credential -eq $null){
		Write-log "[Error] - Failed to get credentials"
		Write-Error -Message "Failed to get credentials" -ErrorAction Stop
	}

	Write-Log "Removing all PS Sessions"

	Get-PSSession | Remove-PSSession -Confirm:$false
	[System.GC]::Collect()
	Write-Log ("Sleeping 15 seconds for Session Tear Down")
	Start-SleepWithProgress -SleepTime 15
	$Error.Clear()
	
	# Create the session
	Write-Log "Creating new PS Session"
	$sessionOption = New-PSSessionOption -SkipRevocationCheck
	if($proxyUsr -ne 'none' -and $proxyPass -ne 'none'){
	    $proxyCred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $proxyUsr, $(convertto-securestring $proxyPass -asplaintext -force)
	    $sessionOption = New-PSSessionOption -SkipRevocationCheck -ProxyAccessType WinHttpConfig -ProxyAuthentication basic -ProxyCredential $proxyCred
	}
	$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $azureEnvArr[1] -Credential $Credential -Authentication Basic -AllowRedirection -SessionOption $sessionOption -WarningAction SilentlyContinue
		
	# Check for an error while creating the session
	if ($Error.Count -gt 0){
	
		Write-Log "[ERROR] - Error while setting up session"
		Write-log $Error
		$ErrorCount++
		if ($ErrorCount -gt 3){
			$deleky=0
			Write-log "[ERROR] - Failed to setup session after multiple tries"
			Write-log "[ERROR] - Aborting Script"		  
			exit
		}
		Write-Log "Sleeping 60s so that issue can potentially be resolved"
		Start-SleepWithProgress -sleeptime 60

		New-CleanO365Session
	}
	else {
		$ErrorCount = 0
	}
	
	# Import the PS session
	$null = Import-PSSession $session -AllowClobber -WarningAction SilentlyContinue -DisableNameChecking
	
	# Set the Start time for the current session
	Set-Variable -Scope script -Name SessionStartTime -Value (Get-Date)

}

Function Test-O365Session {

	$ObjectTime = Get-Date
	$SessionInfo = $null
	$SessionInfo = Get-PSSession

	if ($SessionInfo -eq $null) { 
		Write-Log "[ERROR] - No Session Found"
		Write-log "Recreating Session"
		New-CleanO365Session
	}	
	elseif ($SessionInfo.State -ne "Opened"){
		Write-Log "[ERROR] - Session not in Open State"
		Write-log ($SessionInfo | fl | Out-String )
		Write-log "Recreating Session"
		New-CleanO365Session
	}
	elseif (($ObjectTime - $SessionStartTime).totalseconds -gt $ResetSeconds){
		Write-Log ("Session Has been active for greater than " + $ResetSeconds + " seconds" )
		Write-Log "Rebuilding Connection"
		[int]$DelayinSeconds = ((($ResetSeconds * $ActiveThrottle) / 2) - 15)

		if ($DelayinSeconds -gt 0){
		
			Write-Log ("Sleeping " + $DelayinSeconds + " addtional seconds to allow throttle recovery")
			Start-SleepWithProgress -SleepTime $DelayinSeconds
		}
		else {
			Write-Log ("Active Delay calculated to be " + ($DelayinSeconds + 15) + " seconds no addtional delay needed")
		}

		New-CleanO365Session
	}
	else {

	}

	if ($ManualThrottle -gt 0){
		Write-log ("Sleeping " + $ManualThrottle + " milliseconds")
		Start-Sleep -Milliseconds $ManualThrottle
	}
}

Function Get-EstimatedTimeToCompletion {
	param([int]$ProcessedCount)

	$ProcessedCount++
	if (($ProcessedCount % 100) -eq 0){
		$CurrentDate = Get-Date
		$AveragePerObject = (((($CurrentDate) - $ScriptStartTime).totalseconds) / $ProcessedCount)
		Write-Log ("[STATS] - Total Number of Objects:     " + $ObjectCount)
		Write-Log ("[STATS] - Number of Objects processed: " + $ProcessedCount)
		Write-Log ("[STATS] - Average seconds per object:  " + $AveragePerObject)
		Write-Log ("[STATS] - Estimated completion time:   " + $CurrentDate.addseconds((($ObjectCount - $ProcessedCount) * $AveragePerObject)))
	}

	return $ProcessedCount
}


$rptPath='EXO/'+$reportingname

$sysDateFmt=Get-Date -Format 'dd/MM/yyyy HH:mm:ss'
$endDat=[datetime]::ParseExact($sysDateFmt,'dd/MM/yyyy HH:mm:ss',$null) 
$startDat=$endDat.AddMinutes(-$mTime)
$isErrorOccur= $false

Set-StrictMode -Version 2
$ErrorCount = 0
New-CleanO365Session
$ScriptStartTime = Get-Date
try {
    #---------------START CMDLET----------------------
    $distgroups = Eg-WriteFile -ComntRptPath $rptPath -FileName "distgroups" -keyFileName "kdistgroups" -EgPath $egurkhaPath
    Try{
        <#invoke-command -scriptblock { 
            Get-distributiongroup | select-object GroupType,DisplayName,isvalid,ManagedBy,WindowsEmailAddress,Alias,EmailAddresses,WhenChangedUTC,WhenCreatedUTC,AddressListMembership
            } -session (get-pssession) | export-csv $distgroups[1]#>

        $tempdist=Get-distributiongroup -ResultSize unlimited | select-object GroupType,DisplayName,isvalid,ManagedBy,PrimarySmtpAddress,Alias,EmailAddresses,WhenChangedUTC,WhenCreatedUTC,AddressListMembership 
        if($tempdist){
            foreach($in in $tempdist)
            {
                try{               
		    $identy=$in.PrimarySmtpAddress
		    $cnt=0
		    if($identy)
		    {   
                            Test-O365Session
			    [array]$memblist=[array](Get-DistributionGroupMember -Identity $identy)
			    if($memblist){
			    try {$cnt=$memblist.count }
			    catch{ $cnt=0 }
			    }
			    else { $cnt=0  }
		    }

		    [array]$newObject = [PSCustomObject][ordered]@{
                    GroupType = $in.GroupType
                    DisplayName = $in.DisplayName
                    isvalid = $in.isvalid
                    ManagedBy = $in.ManagedBy
                    WhenChangedUTC = $in.WhenChangedUTC                
                    WhenCreatedUTC = $in.WhenCreatedUTC              
                    AddressListMembership = $in.AddressListMembership
                    PrimarySmtpAddress = $in.PrimarySmtpAddress
                    Alias = $in.Alias
                    EmailAddresses = $in.EmailAddresses 
                    GroupMemberscount=$cnt
                }
                $newObject | Export-Csv -Path $distgroups[1] -NoTypeInformation -Append
	        }
               catch{
                    $errmsg =$_.Exception.Message
                    Write-log ("Exception in distribution loop " + $errmsg)
               }
            
            }
        }
        else{ 
	        $tempdist | Export-Csv -Path $distgroups[1]
	        Write-log 'there is no distributiongroups available'
        } 



    }Catch{$isErrorOccur=$true} 
    if($isErrorOccur -eq $true -and (Get-Item $distgroups[1]).length -le 2kb){
        Write-Log "[ERROR] - Error in excuting the distributiongroup cmdlet "
        Remove-Item $distgroups[1]
        $isErrorOccur=$false
    }else{
        $null=Protect-File  $distgroups[1] -Algorithm AES -KeyAsPlainText $distgroups[0] -RemoveSource
    }

    #---------------START CMDLET----------------------
    Test-O365Session
    $recipients = Eg-WriteFile -ComntRptPath $rptPath -FileName "dynamicdistgroups" -keyFileName "kdynamicdistgroups" -EgPath $egurkhaPath
    Try{
       <# Get-Recipient | select RecipientType, DisplayName, isvalid, ManagedBy, WhenChangedUTC, WhenCreatedUTC, AddressListMembership, PrimarySmtpAddress, Alias, EmailAddresses,WhenSoftDeleted  | 
            Where-Object { $_.RecipientType -eq 'DynamicDistributionGroup'}  | export-csv $recipients[1] #>
            $temprecipent=Get-Recipient -ResultSize unlimited -RecipientType 'DynamicDistributionGroup'| select RecipientType, DisplayName, isvalid, ManagedBy, WhenChangedUTC, WhenCreatedUTC, AddressListMembership, PrimarySmtpAddress, Alias, EmailAddresses,WhenSoftDeleted  
    if($temprecipent){
       foreach($in in $temprecipent)
        {
            try
	    {

		$identy=$in.DisplayName
		$cnt=0
		if($identy)
		{ 
              
			[array]$memblist=[array]((Get-Recipient -RecipientPreviewFilter (Get-DynamicDistributionGroup $in.PrimarySmtpAddress).RecipientFilter) | select Displayname)
			if($memblist)
			{
			try
			{
			$cnt=$memblist.count
			}
			catch{ $cnt=0  }

			}else { $cnt=0  }

		}

			[array]$newObject = [PSCustomObject][ordered]@{
			DisplayName = $in.DisplayName
			isvalid = $in.isvalid
			ManagedBy = $in.ManagedBy
			WhenChangedUTC = $in.WhenChangedUTC                
			WhenCreatedUTC = $in.WhenCreatedUTC              
			AddressListMembership = $in.AddressListMembership
			PrimarySmtpAddress = $in.PrimarySmtpAddress
			Alias = $in.Alias
			EmailAddresses = $in.EmailAddresses 
			WhenSoftDeleted = $in.WhenSoftDeleted
			GroupMemberscount=$cnt
		}

		$newObject | Export-Csv -Path $recipients[1] -NoTypeInformation -Append

            }

	    catch{
               $errmsg =$_.Exception.Message
                Write-log ("Exception in Get-recipent loop" + $errmsg)
            }
	}
    }
    else{
        $temprecipent | Export-Csv -Path $recipients[1]
        Write-log 'there is no dynicdistributiongroups available'
    }
    }Catch{$isErrorOccur=$true}
    if($isErrorOccur -eq $true -and (Get-Item $recipients[1]).length -le 2kb){
        Write-Log "[ERROR] - Error in excuting the recipients cmdlet "
        Remove-Item $recipients[1]
        $isErrorOccur=$false 
    }else{
        $null=Protect-File  $recipients[1] -Algorithm AES -KeyAsPlainText $recipients[0] -RemoveSource
    }
    
    #---------------START CMDLET----------------------
    Test-O365Session
    $unifiedgroups = Eg-WriteFile -ComntRptPath $rptPath -FileName "unifiedgroups" -keyFileName "kunifiedgroups" -EgPath $egurkhaPath  
    Try{
        invoke-command -scriptblock { 
           Get-UnifiedGroup -ResultSize unlimited | select-object GroupType,isvalid,AccessType,ManagedBy,DisplayName,PrimarySmtpAddress,Alias,EmailAddresses,WhenChangedUTC,WhenCreatedUTC,GroupMemberCount,GroupExternalMemberCount,WhenSoftDeleted
            } -session (get-pssession) | export-csv $unifiedgroups[1] 
    }Catch{$isErrorOccur=$true}  
    if($isErrorOccur -eq $true -and (Get-Item $unifiedgroups[1]).length -le 2kb){
        Write-Log "[ERROR] - Error in excuting the unifiedgroups cmdlet "
        Remove-Item $unifiedgroups[1]
        $isErrorOccur=$false
    }else{
        $null=Protect-File  $unifiedgroups[1] -Algorithm AES -KeyAsPlainText $unifiedgroups[0] -RemoveSource
    }
}catch{
    $ErrorMessage = $_.Exception.Message
    write-log "ErrorMessage : " + $ErrorMessage   
} 

$csvDir=$egurkhaPath+'/agent/EXO/'+$reportingname+'/'
    Eg-DeleteCsvFiles -FilePath $csvDir -Pattern 'distgroups'
    Eg-DeleteCsvFiles -FilePath $csvDir -Pattern 'dynamicdistgroups'
    Eg-DeleteCsvFiles -FilePath $csvDir -Pattern 'unifiedgroups'

Write-Log "Script Complete Destroying PS Sessions"
Get-PSSession | Remove-PSSession -Confirm:$false
