Skip to main content

Veeam backup microsoft 365 script audit


damien commenge
Forum|alt.badge.img+5

Hello,

 

This is a script to audit VBM365. 

Feel free to say what you would like if it’s missing :) I know it’s not “complete”

 

# =======================================================
# NAME: VBM365audit.ps1
# AUTHOR: Commenge Damien, Axians Cloud Builder
# DATE: 11/07/2022
#
# VERSION 1.0
# COMMENTS: This script is created to Audit Veeam backup for microsoft 365
# <N/A> is used for not available
# =======================================================

$date = (get-date -Format "dd_MM_yyyy_HH_mm")

#Create directory
New-Item -ItemType Directory -Path "C:\temp\VBM365Audit\$date" -Force | Out-Null

#ReportPath
$ReportPath="C:\temp\VBM365Audit\$date"
#Report file HTML path
$htmlReportPath = "$ReportPath\VeeamBackupMicrosoft365.html"

$HTMLCSS = @'
<style>
body{color:black;font-family:Vinci Sans Light;font-size:0.79em;line-height:1.25;margin:5;}
a{color:black;}
H1{color:white;font-family:Verdana;font-weight:bold;font-size:20pt;margin-bottom:50px;margin-top:40px;text-align:center;background-color:#005EB8;}
H2{color:#A20067;font-family:Verdana;font-size:16pt;margin-left:14px;text-align:left;}
H3{color:#005EB8;font-family:Verdana;font-size:13pt;margin-left:16px;}
H4{color:black;font-family:Verdana;font-size:11pt;margin-left:16px;}
table {border-collapse: collapse;margin-left:10px;border-radius:7px 7px 0px 0px;}
th, td {padding: 8px;text-align: left;border-bottom: 1px solid #ddd;}
th {background-color: #296b0c;color: white;}
td:first-child{font-weight:bold;}
tr:nth-child(even){background-color: #f2f2f2}
table.table2 td:first-child{background-color: #A20067;color: white}
</style>
'@

#Connect to VBO Server
Write-host "$(get-date -Format HH:mm) - Connecting to VBM 365 server"
try {
    Connect-VBOServer -ErrorAction Stop
    Write-host "$(get-date -Format HH:mm) - Connected to VBM 365 server"

}
catch [System.Management.Automation.RuntimeException]{
    Write-host "$(get-date -Format HH:mm) - Connexion is already done"
}
catch {
    Write-host "$(get-date -Format HH:mm) - $($_.Exception.message) " -ForegroundColor Red
    break
}

 <#
 .Synopsis
    Get configuration Summary from Veeam Microsoft 365 server
 .DESCRIPTION
    Get server name, OS, OS build and VBM365 version
 .EXAMPLE 
    Get-DCVBMSummary
 #>
function Get-DCVBMSummary
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Summary"

    $VBM365ServerName = $env:COMPUTERNAME
    $VBM365ServerOS = (Get-WmiObject win32_operatingsystem).caption
    $OSBuild = Get-ItemPropertyValue -path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion" -name 'UBR'
    $VBM365Version = (Get-Module Veeam.Archiver.PowerShell).NestedModules.Version.ToString()

    [PScustomObject]@{
        Name = $VBM365ServerName
        OS = $VBM365ServerOS
        OSBuild = $OSBuild
        VBM365Version = $VBM365Version
    }
}

 <#
 .Synopsis
    Get configuration about organizations
 .DESCRIPTION
    Get organization name, account used, type (on premise, hybride, O365), service (exchange, sharepoint), region, authentication (basic, modern with legacy protocol, modern), auxiliar backup account/application number
 .EXAMPLE 
    Get-DCVBMOrganization
 #>
function Get-DCVBMOrganization
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Organization"

    $OrgName = (Get-VBOOrganization).OfficeName
    $OrgAccount = (Get-VBOOrganization).username
    $OrgType = (Get-VBOOrganization).type
    $OrgService = (Get-VBOOrganization).BackupParts
    $OrgRegion = (Get-VBOOrganization).region
    if ((Get-VBOOrganization).Office365ExchangeConnectionSettings -ne $null)
    {
        $OrgAuth = (Get-VBOOrganization).Office365ExchangeConnectionSettings.AuthenticationType
    }
    else
    {
        $OrgAuth = (Get-VBOOrganization).Office365SharePointConnectionSettings.AuthenticationType
    }
    if ($OrgAuth -eq "Basic")
    {
        $AuxAccount = (Get-VBOOrganization).backupaccounts.count

    }
    else
    {
        $AuxAccount = (Get-VBOOrganization).backupapplications.count

    }

    [PScustomObject]@{
        Name = $OrgName
        Account = $OrgAccount
        Type = $OrgType
        Service = $OrgService
        Region = $OrgRegion
        Authentication = $OrgAuth
        AuxAccount = $AuxAccount
    }
}

 <#
 .Synopsis
    Get configuration about job configuration
 .DESCRIPTION
    Get job name, type, included object, excluded object, repository, proxy, schedule, active or disabled state
 .EXAMPLE 
    Get-DCVBMJob
 #>
function Get-DCVBMJob
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Jobs"

    foreach ($obj in Get-VBOJob)
    {
        $JobName = $obj.name
        $JobType = $obj.JobBackupType
        $JobIncludedObj = $obj.SelectedItems -join ","
        $JobExcludedObj = $obj.ExcludedItems -join ","
        $JobRepository = $obj.Repository
        #Get proxy name from associated proxy ID repository
        $JobProxy = (Get-VBOProxy -id (Get-VBORepository -name $obj.Repository).proxyid).Hostname
        $JobSchedule = "<N/A>"
        if ($obj.schedulepolicy.EnableSchedule -and $obj.schedulepolicy.Type -eq "daily")
        {
            $JobSchedule = $obj.schedulepolicy.dailytime.tostring()
        }
        $JobEnabled = $obj.IsEnabled


        [PScustomObject]@{
            Name = $JobName
            Type = $JobType
            InclObject = $JobIncludedObj
            ExclObject = $OrgService
            Repository = $JobRepository
            Proxy = $JobProxy
            Schedule = $JobSchedule
            Enabled = $JobEnabled
        }
    }
}

 <#
 .Synopsis
    Get configuration about proxy configuration
 .DESCRIPTION
    Get proxy name, port, thread number, throttling, internet proxy used or not, internet proxy port and account
 .EXAMPLE 
    Get-DCVBMProxy
 #>
function Get-DCVBMProxy
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Proxy"

    foreach ($obj in Get-VBOProxy)
    {
        $ProxyName = $obj.hostname
        $ProxyPort = $obj.port
        $ProxyThread = $obj.ThreadsNumber
        $ProxyThrottling = [string]$obj.ThrottlingValue + " " + $obj.ThrottlingUnit
        $ProxyIntHost = "<N/A>"
        $ProxyInternetPort = "<N/A>"
        $ProxyInternetAccount = "<N/A>"
        if ($obj.InternetProxy.UseInternetProxy)
        {
            $ProxyIntHost = $obj.InternetProxy.UseInternetProxy.Host
            $ProxyInternetPort = $obj.InternetProxy.UseInternetProxy.Port
            $ProxyInternetAccount = $obj.InternetProxy.UseInternetProxy.User
        }

        [PScustomObject]@{
            Name = $ProxyName
            Port = $ProxyPort
            Thread = $ProxyThread
            Throttling = $ProxyThrottling
            IntProxyHost = $ProxyIntHost
            IntProxyPort = $ProxyInternetPort
            IntProxyAccount = $ProxyInternetAccount
        }
    }
}

 <#
 .Synopsis
    Get configuration about repository configuration
 .DESCRIPTION
    Get repository name, proxy associated, path, host, retention type and value
 .EXAMPLE 
    Get-DCVBMRepository
 #>
function Get-DCVBMRepository
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Repository"

    foreach ($obj in Get-VBORepository)
    {
        $RepositoryName = $obj.name
        $RepositoryProxy =  (Get-VBOProxy -id (Get-VBORepository -name $obj.name).proxyid).Hostname
        $RepositoryPath = $obj.Path
        $RepositoryHost = ""
        $RepositoryRetention = [string]$obj.retentionperiod + " " + $obj.RetentionType

        [PScustomObject]@{
            Name = $RepositoryName
            Proxy = $RepositoryProxy
            Path = $RepositoryPath
            Host = $RepositoryHost
            Retention = $RepositoryRetention
        }
    }
}

 <#
 .Synopsis
    Get configuration about license
 .DESCRIPTION
    Get license type, expiration date, customer, contact, usage
 .EXAMPLE 
    Get-DCVBMLicense
 #>
function Get-DCVBMLicense
{

    Write-host "$(get-date -Format HH:mm) - VBM365 License"

        $LicenseType = (Get-VBOLicense).type
        $LicenseExpiration =  (Get-VBOLicense).expirationdate.ToShortDateString()
        $LicenseTo = (Get-VBOLicense).LicensedTo
        $LicenseContact = (Get-VBOLicense).ContactPerson
        $LicenseUser = [string](Get-VBOLicense).usedNumber + "/" + (Get-VBOLicense).TotalNumber

        [PScustomObject]@{
            Type = $LicenseType
            Expiration = $LicenseExpiration
            To = $LicenseTo
            Contact = $LicenseContact
            Number = $LicenseUser
        }
}

 <#
 .Synopsis
    Get configuration about restore operator configuration
 .DESCRIPTION
    Get role name, organization, operator, associated object, excluded object
 .EXAMPLE 
    Get-DCVBMRestoreOperator
 #>
function Get-DCVBMRestoreOperator
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Restore Operator"

    foreach ($obj in Get-VBORbacRole)
    {
        $RoleName = $obj.name
        $OrganizationName =  (Get-VBOOrganization -Id ($obj.OrganizationId)).Name
        $OperatorName = $obj.operators.DisplayName -join ","
        $IncludedObject = "Organization"
        if ($obj.RoleType -ne "EntireOrganization")
        {
            $IncludedObject = $obj.SelectedItems.DisplayName -join ","
        }
        $ExcludedObject = "<N/A>"
         if ($obj.ExcludedItems -ne $null)
         {
            $ExcludedObject = $obj.ExcludedItems.DisplayName -join ","
         }
        [PScustomObject]@{
            Role = $RoleName
            Organization = $OrganizationName
            Operator = $OperatorName
            IncludedObject = $IncludedObject
            ExcludedObject = $ExcludedObject
        }
    }
}

 <#
 .Synopsis
    Get configuration about RestAPI configuration
 .DESCRIPTION
    Get state, token life time, port, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVBMRestAPI
 #>
function Get-DCVBMRestAPI
{
    Write-host "$(get-date -Format HH:mm) - VBM365 REST API"

        $Enabled = (Get-VBORestAPISettings).IsServiceEnabled
        $TokenTime =  (Get-VBORestAPISettings).AuthTokenLifeTime
        $Port = (Get-VBORestAPISettings).HTTPSPort
        $CertThumbprint = (Get-VBORestAPISettings).CertificateThumbprint
        $CertFriendlyName = (Get-VBORestAPISettings).CertificateFriendlyName
        $CertExpiration = (Get-VBORestAPISettings).CertificateExpirationDate.ToShortDateString()

        [PScustomObject]@{
            Enabled = $Enabled
            TokenTime = $TokenTime
            Port = $Port
            CertThumbprint = $CertThumbprint
            CertFriendlyName = $CertFriendlyName
            CertExpiration = $CertExpiration
        }
}


 <#
 .Synopsis
    Get configuration about Restore portal configuration
 .DESCRIPTION
    Get state, application ID, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVBMRestorePortal
 #>
function Get-DCVBMRestorePortal
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Restore portal"

    $Enabled = (Get-VBORestorePortalSettings).IsServiceEnabled
    $ApplicationID =  (Get-VBORestorePortalSettings).ApplicationId.Guid
    $CertThumbprint = (Get-VBORestorePortalSettings).CertificateThumbprint
    $CertFriendlyName = (Get-VBORestorePortalSettings).CertificateFriendlyName
    $CertExpiration = (Get-VBORestorePortalSettings).CertificateExpirationDate.ToShortDateString()

    [PScustomObject]@{
        Enabled = $Enabled
        ApplicationID = $ApplicationID
        CertThumbprint = $CertThumbprint
        CertFriendlyName = $CertFriendlyName
        CertExpiration = $CertExpiration
    }
}

 <#
 .Synopsis
    Get configuration about operator Authentication portal configuration
 .DESCRIPTION
    Get state, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVBMOperatorAuthentication
 #>
function Get-DCVBMOperatorAuthentication
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Authentication"

    $Enabled = (Get-VBOOperatorAuthenticationSettings).AuthenticationEnabled
    $CertThumbprint = (Get-VBORestAPISettings).CertificateThumbprint
    $CertFriendlyName = (Get-VBOOperatorAuthenticationSettings).CertificateFriendlyName
    $CertExpiration = (Get-VBOOperatorAuthenticationSettings).CertificateExpirationDate

    [PScustomObject]@{
        Enabled = $Enabled
        CertThumbprint = $CertThumbprint
        CertFriendlyName = $CertFriendlyName
        CertExpiration = $CertExpiration
    }
}

 <#
 .Synopsis
    Get configuration about internet proxy
 .DESCRIPTION
    Get state, host, port and account
 .EXAMPLE 
    Get-DCVBMInternetProxy
 #>
function Get-DCVBMInternetProxy
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Internet Proxy"

    $IntProxyEnabled = (Get-VBOInternetProxySettings).UseInternetProxy
    $IntProxyHost = "<N/A>"
    $IntProxyPort = "<N/A>"
    $IntProxyUser = "<N/A>"
    if ((Get-VBOInternetProxySettings).UseInternetProxy)
    {
        $IntProxyHost = (Get-VBOInternetProxySettings).Host
        $IntProxyPort = (Get-VBOInternetProxySettings).Port
        $IntProxyUser = (Get-VBOInternetProxySettings).User
    }

    [PScustomObject]@{
        Enabled = $IntProxyEnabled
        Host = $IntProxyHost
        Port = $IntProxyPort
        Account = $IntProxyUser
    }
}

 <#
 .Synopsis
    Get configuration about SMTP
 .DESCRIPTION
    Get state, server, port, ssl, account
 .EXAMPLE 
    Get-DCVBMSMTP
 #>
function Get-DCVBMSMTP
{

    Write-host "$(get-date -Format HH:mm) - VBM365 SMTP configuration"

    $SMTPEnabled = (Get-VBOEmailSettings).EnableNotification
    $SMTPServer = "<N/A>"
    $SMTPPort = "<N/A>"
    $SMTPSSL = "<N/A>"
    $SMTPAccount = "<N/A>"
    if ((Get-VBOEmailSettings).EnableNotification)
    {
        $SMTPServer = (Get-VBOEmailSettings).SMTPServer
        $SMTPPort = (Get-VBOEmailSettings).Port
        $SMTPSSL = (Get-VBOEmailSettings).UseSSL
        if ((Get-VBOEmailSettings).UseAuthentication)
        {
            $SMTPAccount = (Get-VBOEmailSettings).Username
        }
    }

    [PScustomObject]@{
        Enabled = $SMTPEnabled
        Server = $SMTPServer
        Port = $SMTPPort
        SSL = $SMTPSSL
        Account = $SMTPAccount
    }
}


 <#
 .Synopsis
    Get configuration about Notifications
 .DESCRIPTION
    Get state, sender, receiver, notification on success, warning and failure, send only last retry notification
 .EXAMPLE 
    Get-DCVBMNotification
 #>
function Get-DCVBMNotification
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Notifications"

    $NotificationEnabled = (Get-VBOEmailSettings).EnableNotification
    $NotificationSender = "<N/A>"
    $NotificationReceiver = "<N/A>"
    $NotificationSuccess = "<N/A>"
    $NotificationWarning = "<N/A>"
    $NotificationFailure = "<N/A>"
    $LastRetryNotificationOnly = "<N/A>"
    if ((Get-VBOEmailSettings).EnableNotification)
    {
        $NotificationSender = (Get-VBOEmailSettings).From -join ","
        $NotificationReceiver = (Get-VBOEmailSettings).To -join ","
        $NotificationSuccess = (Get-VBOEmailSettings).NotifyOnSuccess
        $NotificationWarning = (Get-VBOEmailSettings).NotifyOnWarning
        $NotificationFailure = (Get-VBOEmailSettings).NotifyOnFailure
        $LastRetryNotificationOnly = (Get-VBOEmailSettings).SupressUntilLastRetry
    }

    [PScustomObject]@{
        Enabled = $NotificationEnabled
        Sender = $NotificationSender
        Receiver = $NotificationReceiver
        OnSuccess = $NotificationSuccess
        OnWarning = $NotificationWarning
        OnFailure = $NotificationFailure
        OnlyLastRetry = $LastRetryNotificationOnly
    }
}


 <#
 .Synopsis
    Create array for HTML report
 .DESCRIPTION
    Create array with title and precontent
 .EXAMPLE 
    CreateArray -title "my Title" -var $MyData -PreContent $MyPrecontent
 #>
Function CreateArray ($Title,$Var,$PreContent)
{
    if ($Title)
    {
        "<h3>$Title</h3>"
    }
    if ($PreContent)
    {
        $Var | ConvertTo-Html -Fragment -PreContent $PreContent
    }
    else
    {
        $Var | ConvertTo-Html -Fragment
    }
}


<#
.Synopsis
   Generate HTML report
.DESCRIPTION
   Use all variable to build html report with CSS style 
.EXAMPLE
   Get-HTMLReport -Path "c:\temp\report.html"
#>

function Get-HTMLReport
{
    [CmdletBinding()]

    Param
    (
        #HTML file path
        [Parameter(Mandatory=$true)]
        [string] $Path,

        #HTML file name
        [string] $FileName = "VBM365Audit.html"
    )
    Write-Host "Building HTML"

    #region HTML
    @"
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>Axians vSphere Report</title>
    $HTMLCSS
    </head>
    <body>
    <br><br><br><br>

    <h1>VEEAM Backup for Microsoft 365 Report</h1>

    $(CreateArray -title "Summary" -var $DCVBMSummary) 
    $(CreateArray -title "License" -var $DCVBMLicense)
    $(CreateArray -title "SMTP" -var $DCVBMSMTP)
    $(CreateArray -title "Notifications" -var $DCVBMNotification)
    $(CreateArray -title "Internet Proxy" -var $DCVBMInternetProxy)

    $(CreateArray -title "REST API" -var $DCVBMRestAPI)
    $(CreateArray -title "Restore portal" -var $DCVBMRestorePortal)
    $(CreateArray -title "Operator authentication" -var $DCVBMOperatorAuthentication )

    $(CreateArray -title "Repositories" -var $DCVBMRepository)
    $(CreateArray -title "Proxies" -var $DCVBMProxy)

    $(CreateArray -title "Organizations" -var $DCVBMOrganization)
    $(CreateArray -title "Jobs" -var $DCVBMJob)

    $(CreateArray -title "Restore operators" -var $DCVBMRestoreOperator )

    </body>
"@ | Out-File -Encoding utf8 $htmlReportPath

    Invoke-Item $htmlReportPath


}
#endregion


#Write here all function that need to be displayed 

$DCVBMSummary = Get-DCVBMSummary
$DCVBMOrganization = Get-DCVBMOrganization
$DCVBMJob = Get-DCVBMJob
$DCVBMProxy = Get-DCVBMProxy
$DCVBMRepository = Get-DCVBMRepository
$DCVBMLicense = Get-DCVBMLicense
$DCVBMRestoreOperator = Get-DCVBMRestoreOperator
$DCVBMRestAPI = Get-DCVBMRestAPI
$DCVBMRestorePortal = Get-DCVBMRestorePortal
$DCVBMOperatorAuthentication = Get-DCVBMOperatorAuthentication
$DCVBMInternetProxy = Get-DCVBMInternetProxy
$DCVBMSMTP = Get-DCVBMSMTP
$DCVBMNotification = Get-DCVBMNotification



Get-HTMLReport -Path "$ReportPath\$domain"


Disconnect-VBOServer

 

8 comments

Chris.Childerhose
Forum|alt.badge.img+21

This is great thanks for sharing 👍


damien commenge
Forum|alt.badge.img+5

Sample here 

 

I add object repository + backup copy job settings

I’m waiting an answer on the forum for host repository name to be found 
I see it’s impossible to edit my previous post, new code is here :

 

# =======================================================
# NAME: VBM365audit.ps1
# AUTHOR: Commenge Damien, Axians Cloud Builder
# DATE: 11/07/2022
#
# VERSION 1.0
# COMMENTS: This script is created to Audit Veeam backup for microsoft 365
# <N/A> is used for not available
# =======================================================

$date = (get-date -Format "dd_MM_yyyy_HH_mm")

#Create directory
New-Item -ItemType Directory -Path "C:\temp\VBM365Audit\$date" -Force | Out-Null

#ReportPath
$ReportPath="C:\temp\VBM365Audit\$date"
#Report file HTML path
$htmlReportPath = "$ReportPath\VeeamBackupMicrosoft365.html"

$HTMLCSS = @'
<style>
body{color:black;font-family:Vinci Sans Light;font-size:0.79em;line-height:1.25;margin:5;}
a{color:black;}
H1{color:white;font-family:Verdana;font-weight:bold;font-size:20pt;margin-bottom:50px;margin-top:40px;text-align:center;background-color:#005EB8;}
H2{color:#A20067;font-family:Verdana;font-size:16pt;margin-left:14px;text-align:left;}
H3{color:#005EB8;font-family:Verdana;font-size:13pt;margin-left:16px;}
H4{color:black;font-family:Verdana;font-size:11pt;margin-left:16px;}
table {border-collapse: collapse;margin-left:10px;border-radius:7px 7px 0px 0px;}
th, td {padding: 8px;text-align: left;border-bottom: 1px solid #ddd;}
th {background-color: #296b0c;color: white;}
td:first-child{font-weight:bold;}
tr:nth-child(even){background-color: #f2f2f2}
table.table2 td:first-child{background-color: #A20067;color: white}
</style>
'@

#Connect to VBO Server
Write-host "$(get-date -Format HH:mm) - Connecting to VBM 365 server"
try {
    Connect-VBOServer -ErrorAction Stop
    Write-host "$(get-date -Format HH:mm) - Connected to VBM 365 server"

}
catch [System.Management.Automation.RuntimeException]{
    Write-host "$(get-date -Format HH:mm) - Connexion is already done"
}
catch {
    Write-host "$(get-date -Format HH:mm) - $($_.Exception.message) " -ForegroundColor Red
    break
}

 <#
 .Synopsis
    Get configuration Summary from Veeam Microsoft 365 server
 .DESCRIPTION
    Get server name, OS, OS build and VBM365 version
 .EXAMPLE 
    Get-DCVBMSummary
 #>
function Get-DCVBMSummary
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Summary"

    $VBM365ServerName = $env:COMPUTERNAME
    $VBM365ServerOS = (Get-WmiObject win32_operatingsystem).caption
    $OSBuild = Get-ItemPropertyValue -path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion" -name 'UBR'
    $VBM365Version = (Get-Module Veeam.Archiver.PowerShell).NestedModules.Version.ToString()

    [PScustomObject]@{
        Name = $VBM365ServerName
        OS = $VBM365ServerOS
        OSBuild = $OSBuild
        VBM365Version = $VBM365Version
    }
}

 <#
 .Synopsis
    Get configuration about organizations
 .DESCRIPTION
    Get organization name, account used, type (on premise, hybride, O365), service (exchange, sharepoint), region, authentication (basic, modern with legacy protocol, modern), auxiliar backup account/application number
 .EXAMPLE 
    Get-DCVBMOrganization
 #>
function Get-DCVBMOrganization
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Organization"

    $OrgName = (Get-VBOOrganization).OfficeName
    $OrgAccount = (Get-VBOOrganization).username
    $OrgType = (Get-VBOOrganization).type
    $OrgService = (Get-VBOOrganization).BackupParts
    $OrgRegion = (Get-VBOOrganization).region
    if ((Get-VBOOrganization).Office365ExchangeConnectionSettings -ne $null)
    {
        $OrgAuth = (Get-VBOOrganization).Office365ExchangeConnectionSettings.AuthenticationType
    }
    else
    {
        $OrgAuth = (Get-VBOOrganization).Office365SharePointConnectionSettings.AuthenticationType
    }
    if ($OrgAuth -eq "Basic")
    {
        $AuxAccount = (Get-VBOOrganization).backupaccounts.count

    }
    else
    {
        $AuxAccount = (Get-VBOOrganization).backupapplications.count

    }

    [PScustomObject]@{
        Name = $OrgName
        Account = $OrgAccount
        Type = $OrgType
        Service = $OrgService
        Region = $OrgRegion
        Authentication = $OrgAuth
        AuxAccount = $AuxAccount
    }
}

 <#
 .Synopsis
    Get configuration about backup job configuration
 .DESCRIPTION
    Get job name, type, included object, excluded object, repository, proxy, schedule, active or disabled state
 .EXAMPLE 
    Get-DCVBMBackupJob
 #>
function Get-DCVBMBackupJob
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Backup Jobs"

    foreach ($obj in Get-VBOJob)
    {
        $JobName = $obj.name
        $JobType = $obj.JobBackupType
        $JobIncludedObj = $obj.SelectedItems -join ","
        $JobExcludedObj = $obj.ExcludedItems -join ","
        $JobRepository = $obj.Repository
        #Get proxy name from associated proxy ID repository
        $JobProxy = (Get-VBOProxy -id (Get-VBORepository -name $obj.Repository).proxyid).Hostname
        $JobSchedule = "<N/A>"
        if ($obj.schedulepolicy.EnableSchedule -and $obj.schedulepolicy.Type -eq "daily")
        {
            $JobSchedule = $obj.schedulepolicy.dailytime.tostring()
        }
        $JobEnabled = $obj.IsEnabled


        [PScustomObject]@{
            Name = $JobName
            Type = $JobType
            InclObject = $JobIncludedObj
            ExclObject = $OrgService
            Repository = $JobRepository
            Proxy = $JobProxy
            Schedule = $JobSchedule
            Enabled = $JobEnabled
        }
    }
}

<#
 .Synopsis
    Get configuration about backup copy job configuration
 .DESCRIPTION
    Get job name, repository, backupjob linked, schedule, active or disabled state
 .EXAMPLE 
    Get-DCVBMBackupCopyJob
 #>
function Get-DCVBMBackupCopyJob
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Backup copy Jobs"

    foreach ($obj in Get-VBOCopyJob)
    {
        $JobName = $obj.name
        $JobRepository = $obj.Repository
        $JobBackupLinked = $obj.BackupJob
        if ($obj.schedulepolicy.type -eq "daily")
        {
             $JobSchedule = [string]$obj.SchedulePolicy.DailyTime + " " + $obj.SchedulePolicy.DailyType
        }
        if ($obj.schedulepolicy.type -eq "Periodically")
        {
             $JobSchedule = $obj.SchedulePolicy.PeriodicallyEvery
        }
        else 
        {
            $JobSchedule = $obj.SchedulePolicy.Type
        }
        $JobEnabled = $obj.IsEnabled

        [PScustomObject]@{
            Name = $JobName
            Repository = $JobRepository
            BackupLinked = $JobBackupLinked
            Schedule = $JobSchedule
            Enabled = $JobEnabled
        }
    }
}


 <#
 .Synopsis
    Get configuration about proxy configuration
 .DESCRIPTION
    Get proxy name, port, thread number, throttling, internet proxy used or not, internet proxy port and account
 .EXAMPLE 
    Get-DCVBMProxy
 #>
function Get-DCVBMProxy
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Proxy"

    foreach ($obj in Get-VBOProxy)
    {
        $ProxyName = $obj.hostname
        $ProxyPort = $obj.port
        $ProxyThread = $obj.ThreadsNumber
        $ProxyThrottling = [string]$obj.ThrottlingValue + " " + $obj.ThrottlingUnit
        $ProxyIntHost = "<N/A>"
        $ProxyInternetPort = "<N/A>"
        $ProxyInternetAccount = "<N/A>"
        if ($obj.InternetProxy.UseInternetProxy)
        {
            $ProxyIntHost = $obj.InternetProxy.UseInternetProxy.Host
            $ProxyInternetPort = $obj.InternetProxy.UseInternetProxy.Port
            $ProxyInternetAccount = $obj.InternetProxy.UseInternetProxy.User
        }

        [PScustomObject]@{
            Name = $ProxyName
            Port = $ProxyPort
            Thread = $ProxyThread
            Throttling = $ProxyThrottling
            IntProxyHost = $ProxyIntHost
            IntProxyPort = $ProxyInternetPort
            IntProxyAccount = $ProxyInternetAccount
        }
    }
}

 <#
 .Synopsis
    Get configuration about repository configuration
 .DESCRIPTION
    Get repository name, proxy associated, path, host, retention type and value, repository object name and encryption
 .EXAMPLE 
    Get-DCVBMRepository
 #>
function Get-DCVBMRepository
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Repository"

    foreach ($obj in Get-VBORepository)
    {
        $RepositoryName = $obj.name
        $RepositoryProxy =  (Get-VBOProxy -id (Get-VBORepository -name $obj.name).proxyid).Hostname
        $RepositoryPath = $obj.Path
        #En attente forum https://forums.veeam.com/veeam-backup-for-microsoft-365-f47/powershell-host-repository-t81718.html
        $RepositoryHost = ""
        $RepositoryRetention = [string]$obj.retentionperiod + " " + $obj.RetentionType
        $RepositoryObjectName = "<N/A>"
        if ($obj.ObjectStorageRepository -ne $null)
        {
            $RepositoryObjectName = $obj.ObjectStorageRepository.Name
        }
        $encryption = $obj.EnableObjectStorageEncryption
        [PScustomObject]@{
            Name = $RepositoryName
            Proxy = $RepositoryProxy
            Path = $RepositoryPath
            Host = $RepositoryHost
            ObjectRepository = $RepositoryObjectName
            Retention = $RepositoryRetention
            Encryption = $encryption
        }
    }
}

 <#
 .Synopsis
    Get configuration about object repository configuration
 .DESCRIPTION
    Get repository name, folder, type, size limit and if it's long term achive
 .EXAMPLE 
    Get-DCVBMRepository
 #>
function Get-DCVBMObjectRepository
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Object Repository"

    foreach ($obj in Get-VBOObjectStorageRepository)
    {
        $RepositoryName = $obj.name
        $RepositoryFolder =  $obj.Folder
        $RepositoryType = $obj.Type
        $RepositorySizeLimit = "<N/A>"
        if ($obj.EnableSizeLimit)
        {
            $RepositorySizeLimit = [String]$obj.UsedSpace + "/" + $obj.SizeLimit
        }
        $RepositoryArchive = $obj.IsLongTerm
        [PScustomObject]@{
            Name = $RepositoryName
            Folder = $RepositoryFolder
            Type = $RepositoryType
            SizeLimit = $RepositorySizeLimit
            LongTerm = $RepositoryArchive
        }
    }
}

 <#
 .Synopsis
    Get configuration about license
 .DESCRIPTION
    Get license type, expiration date, customer, contact, usage
 .EXAMPLE 
    Get-DCVBMLicense
 #>
function Get-DCVBMLicense
{

    Write-host "$(get-date -Format HH:mm) - VBM365 License"

        $LicenseType = (Get-VBOLicense).type
        $LicenseExpiration =  (Get-VBOLicense).expirationdate.ToShortDateString()
        $LicenseTo = (Get-VBOLicense).LicensedTo
        $LicenseContact = (Get-VBOLicense).ContactPerson
        $LicenseUser = [string](Get-VBOLicense).usedNumber + "/" + (Get-VBOLicense).TotalNumber

        [PScustomObject]@{
            Type = $LicenseType
            Expiration = $LicenseExpiration
            To = $LicenseTo
            Contact = $LicenseContact
            Number = $LicenseUser
        }
}

 <#
 .Synopsis
    Get configuration about restore operator configuration
 .DESCRIPTION
    Get role name, organization, operator, associated object, excluded object
 .EXAMPLE 
    Get-DCVBMRestoreOperator
 #>
function Get-DCVBMRestoreOperator
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Restore Operator"

    foreach ($obj in Get-VBORbacRole)
    {
        $RoleName = $obj.name
        $OrganizationName =  (Get-VBOOrganization -Id ($obj.OrganizationId)).Name
        $OperatorName = $obj.operators.DisplayName -join ","
        $IncludedObject = "Organization"
        if ($obj.RoleType -ne "EntireOrganization")
        {
            $IncludedObject = $obj.SelectedItems.DisplayName -join ","
        }
        $ExcludedObject = "<N/A>"
         if ($obj.ExcludedItems -ne $null)
         {
            $ExcludedObject = $obj.ExcludedItems.DisplayName -join ","
         }
        [PScustomObject]@{
            Role = $RoleName
            Organization = $OrganizationName
            Operator = $OperatorName
            IncludedObject = $IncludedObject
            ExcludedObject = $ExcludedObject
        }
    }
}

 <#
 .Synopsis
    Get configuration about RestAPI configuration
 .DESCRIPTION
    Get state, token life time, port, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVBMRestAPI
 #>
function Get-DCVBMRestAPI
{
    Write-host "$(get-date -Format HH:mm) - VBM365 REST API"

        $Enabled = (Get-VBORestAPISettings).IsServiceEnabled
        $TokenTime =  (Get-VBORestAPISettings).AuthTokenLifeTime
        $Port = (Get-VBORestAPISettings).HTTPSPort
        $CertThumbprint = (Get-VBORestAPISettings).CertificateThumbprint
        $CertFriendlyName = (Get-VBORestAPISettings).CertificateFriendlyName
        $CertExpiration = (Get-VBORestAPISettings).CertificateExpirationDate.ToShortDateString()

        [PScustomObject]@{
            Enabled = $Enabled
            TokenTime = $TokenTime
            Port = $Port
            CertThumbprint = $CertThumbprint
            CertFriendlyName = $CertFriendlyName
            CertExpiration = $CertExpiration
        }
}


 <#
 .Synopsis
    Get configuration about Restore portal configuration
 .DESCRIPTION
    Get state, application ID, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVBMRestorePortal
 #>
function Get-DCVBMRestorePortal
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Restore portal"

    $Enabled = (Get-VBORestorePortalSettings).IsServiceEnabled
    $ApplicationID =  (Get-VBORestorePortalSettings).ApplicationId.Guid
    $CertThumbprint = (Get-VBORestorePortalSettings).CertificateThumbprint
    $CertFriendlyName = (Get-VBORestorePortalSettings).CertificateFriendlyName
    $CertExpiration = (Get-VBORestorePortalSettings).CertificateExpirationDate.ToShortDateString()

    [PScustomObject]@{
        Enabled = $Enabled
        ApplicationID = $ApplicationID
        CertThumbprint = $CertThumbprint
        CertFriendlyName = $CertFriendlyName
        CertExpiration = $CertExpiration
    }
}

 <#
 .Synopsis
    Get configuration about operator Authentication portal configuration
 .DESCRIPTION
    Get state, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVBMOperatorAuthentication
 #>
function Get-DCVBMOperatorAuthentication
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Authentication"

    $Enabled = (Get-VBOOperatorAuthenticationSettings).AuthenticationEnabled
    $CertThumbprint = (Get-VBORestAPISettings).CertificateThumbprint
    $CertFriendlyName = (Get-VBOOperatorAuthenticationSettings).CertificateFriendlyName
    $CertExpiration = (Get-VBOOperatorAuthenticationSettings).CertificateExpirationDate

    [PScustomObject]@{
        Enabled = $Enabled
        CertThumbprint = $CertThumbprint
        CertFriendlyName = $CertFriendlyName
        CertExpiration = $CertExpiration
    }
}

 <#
 .Synopsis
    Get configuration about internet proxy
 .DESCRIPTION
    Get state, host, port and account
 .EXAMPLE 
    Get-DCVBMInternetProxy
 #>
function Get-DCVBMInternetProxy
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Internet Proxy"

    $IntProxyEnabled = (Get-VBOInternetProxySettings).UseInternetProxy
    $IntProxyHost = "<N/A>"
    $IntProxyPort = "<N/A>"
    $IntProxyUser = "<N/A>"
    if ((Get-VBOInternetProxySettings).UseInternetProxy)
    {
        $IntProxyHost = (Get-VBOInternetProxySettings).Host
        $IntProxyPort = (Get-VBOInternetProxySettings).Port
        $IntProxyUser = (Get-VBOInternetProxySettings).User
    }

    [PScustomObject]@{
        Enabled = $IntProxyEnabled
        Host = $IntProxyHost
        Port = $IntProxyPort
        Account = $IntProxyUser
    }
}

 <#
 .Synopsis
    Get configuration about SMTP
 .DESCRIPTION
    Get state, server, port, ssl, account
 .EXAMPLE 
    Get-DCVBMSMTP
 #>
function Get-DCVBMSMTP
{

    Write-host "$(get-date -Format HH:mm) - VBM365 SMTP configuration"

    $SMTPEnabled = (Get-VBOEmailSettings).EnableNotification
    $SMTPServer = "<N/A>"
    $SMTPPort = "<N/A>"
    $SMTPSSL = "<N/A>"
    $SMTPAccount = "<N/A>"
    if ((Get-VBOEmailSettings).EnableNotification)
    {
        $SMTPServer = (Get-VBOEmailSettings).SMTPServer
        $SMTPPort = (Get-VBOEmailSettings).Port
        $SMTPSSL = (Get-VBOEmailSettings).UseSSL
        if ((Get-VBOEmailSettings).UseAuthentication)
        {
            $SMTPAccount = (Get-VBOEmailSettings).Username
        }
    }

    [PScustomObject]@{
        Enabled = $SMTPEnabled
        Server = $SMTPServer
        Port = $SMTPPort
        SSL = $SMTPSSL
        Account = $SMTPAccount
    }
}


 <#
 .Synopsis
    Get configuration about Notifications
 .DESCRIPTION
    Get state, sender, receiver, notification on success, warning and failure, send only last retry notification
 .EXAMPLE 
    Get-DCVBMNotification
 #>
function Get-DCVBMNotification
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Notifications"

    $NotificationEnabled = (Get-VBOEmailSettings).EnableNotification
    $NotificationSender = "<N/A>"
    $NotificationReceiver = "<N/A>"
    $NotificationSuccess = "<N/A>"
    $NotificationWarning = "<N/A>"
    $NotificationFailure = "<N/A>"
    $LastRetryNotificationOnly = "<N/A>"
    if ((Get-VBOEmailSettings).EnableNotification)
    {
        $NotificationSender = (Get-VBOEmailSettings).From -join ","
        $NotificationReceiver = (Get-VBOEmailSettings).To -join ","
        $NotificationSuccess = (Get-VBOEmailSettings).NotifyOnSuccess
        $NotificationWarning = (Get-VBOEmailSettings).NotifyOnWarning
        $NotificationFailure = (Get-VBOEmailSettings).NotifyOnFailure
        $LastRetryNotificationOnly = (Get-VBOEmailSettings).SupressUntilLastRetry
    }

    [PScustomObject]@{
        Enabled = $NotificationEnabled
        Sender = $NotificationSender
        Receiver = $NotificationReceiver
        OnSuccess = $NotificationSuccess
        OnWarning = $NotificationWarning
        OnFailure = $NotificationFailure
        OnlyLastRetry = $LastRetryNotificationOnly
    }
}


 <#
 .Synopsis
    Create array for HTML report
 .DESCRIPTION
    Create array with title and precontent
 .EXAMPLE 
    CreateArray -title "my Title" -var $MyData -PreContent $MyPrecontent
 #>
Function CreateArray ($Title,$Var,$PreContent)
{
    if ($Title)
    {
        "<h3>$Title</h3>"
    }
    if ($PreContent)
    {
        $Var | ConvertTo-Html -Fragment -PreContent $PreContent
    }
    else
    {
        $Var | ConvertTo-Html -Fragment
    }
}


<#
.Synopsis
   Generate HTML report
.DESCRIPTION
   Use all variable to build html report with CSS style 
.EXAMPLE
   Get-HTMLReport -Path "c:\temp\report.html"
#>

function Get-HTMLReport
{
    [CmdletBinding()]

    Param
    (
        #HTML file path
        [Parameter(Mandatory=$true)]
        [string] $Path,

        #HTML file name
        [string] $FileName = "VBM365Audit.html"
    )
    Write-Host "Building HTML"

    #region HTML
    @"
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>Axians vSphere Report</title>
    $HTMLCSS
    </head>
    <body>
    <br><br><br><br>

    <h1>VEEAM Backup for Microsoft 365 Report</h1>

    $(CreateArray -title "Summary" -var $DCVBMSummary) 
    $(CreateArray -title "License" -var $DCVBMLicense)
    $(CreateArray -title "SMTP" -var $DCVBMSMTP)
    $(CreateArray -title "Notifications" -var $DCVBMNotification)
    $(CreateArray -title "Internet Proxy" -var $DCVBMInternetProxy)

    $(CreateArray -title "REST API" -var $DCVBMRestAPI)
    $(CreateArray -title "Restore portal" -var $DCVBMRestorePortal)
    $(CreateArray -title "Authentication" -var $DCVBMAuthentication )

    $(CreateArray -title "Repositories" -var $DCVBMRepository)
    $(CreateArray -title "Object Repositories" -var $DCVBMObjectRepository)

    $(CreateArray -title "Proxies" -var $DCVBMProxy)

    $(CreateArray -title "Organizations" -var $DCVBMOrganization)
    $(CreateArray -title "Backup jobs" -var $DCVBMBackupJob)
    $(CreateArray -title "Backup copy jobs" -var $DCVBMBackupCopyJob)



    $(CreateArray -title "Restore operators" -var $DCVBMRestoreOperator )

    </body>
"@ | Out-File -Encoding utf8 $htmlReportPath

    Invoke-Item $htmlReportPath


}
#endregion






#Write here all function that need to be displayed in all reports types

$DCVBMSummary = Get-DCVBMSummary
$DCVBMOrganization = Get-DCVBMOrganization
$DCVBMBackupJob = Get-DCVBMBackupJob
$DCVBMProxy = Get-DCVBMProxy
$DCVBMRepository = Get-DCVBMRepository
$DCVBMLicense = Get-DCVBMLicense
$DCVBMRestoreOperator = Get-DCVBMRestoreOperator
$DCVBMRestAPI = Get-DCVBMRestAPI
$DCVBMRestorePortal = Get-DCVBMRestorePortal
$DCVBMOperatorAuthentication = Get-DCVBMOperatorAuthentication
$DCVBMInternetProxy = Get-DCVBMInternetProxy
$DCVBMSMTP = Get-DCVBMSMTP
$DCVBMNotification = Get-DCVBMNotification
$DCVBMObjectRepository = Get-DCVBMObjectRepository
$DCVBMBackupCopyJob = Get-DCVBMBackupCopyJob



Get-HTMLReport -Path "$ReportPath\$domain"


Disconnect-VBOServer

 


damien commenge
Forum|alt.badge.img+5

New version with some fixes :

-VBM version

-Host for repository is the proxy (I ignored it)

-Change green color

# =======================================================
# NAME: VBM365audit.ps1
# AUTHOR: Commenge Damien, Axians Cloud Builder
# DATE: 11/07/2022
#
# VERSION 1.01
# COMMENTS: This script is created to Audit Veeam backup for microsoft 365
# <N/A> is used for not available
# =======================================================

$date = (get-date -Format "dd_MM_yyyy_HH_mm")

#Create directory
New-Item -ItemType Directory -Path "C:\temp\VBM365Audit\$date" -Force | Out-Null

#ReportPath
$ReportPath="C:\temp\VBM365Audit\$date"
#Report file HTML path
$htmlReportPath = "$ReportPath\VeeamBackupMicrosoft365.html"

$HTMLTitle = "VBM365 report"
$HTMLCSS = @'
<style>
body{color:black;font-family:Vinci Sans Light;font-size:0.79em;line-height:1.25;margin:5;}
a{color:black;}
H1{color:white;font-family:Verdana;font-weight:bold;font-size:20pt;margin-bottom:50px;margin-top:40px;text-align:center;background-color:#005EB8;}
H2{color:#A20067;font-family:Verdana;font-size:16pt;margin-left:14px;text-align:left;}
H3{color:#005EB8;font-family:Verdana;font-size:13pt;margin-left:16px;}
H4{color:black;font-family:Verdana;font-size:11pt;margin-left:16px;}
table {border-collapse: collapse;margin-left:10px;border-radius:7px 7px 0px 0px;}
th, td {padding: 8px;text-align: left;border-bottom: 1px solid #ddd;}
th {background-color: #006400;color: white;}
td:first-child{font-weight:bold;}
tr:nth-child(even){background-color: #f2f2f2}
table.table2 td:first-child{background-color: #A20067;color: white}
</style>
'@

#Connect to VBO Server
Write-host "$(get-date -Format HH:mm) - Connecting to VBM 365 server"
try {
    Connect-VBOServer -ErrorAction Stop
    Write-host "$(get-date -Format HH:mm) - Connected to VBM 365 server"

}
catch [System.Management.Automation.RuntimeException]{
    Write-host "$(get-date -Format HH:mm) - Connexion is already done"
}
catch {
    Write-host "$(get-date -Format HH:mm) - $($_.Exception.message) " -ForegroundColor Red
    break
}

 <#
 .Synopsis
    Get configuration Summary from Veeam Microsoft 365 server
 .DESCRIPTION
    Get server name, OS, OS build and VBM365 version
 .EXAMPLE 
    Get-DCVBMSummary
 #>
function Get-DCVBMSummary
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Summary"

    $VBM365ServerName = $env:COMPUTERNAME
    $VBM365ServerOS = (Get-WmiObject win32_operatingsystem).caption
    $OSBuild = Get-ItemPropertyValue -path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion" -name 'UBR'
    #No way to find version with powershell but associated version with VBR is available here : https://www.veeam.com/kb4106 
    $VBRbuild = (Get-Module Veeam.Archiver.PowerShell).nestedmodules.version.tostring()
    switch ($VBRbuild)
    {
        "10.0.2.1061"   {$VBM365Build = "5.0.0.1061"}
        "10.0.2.1063"   {$VBM365Build = "5.0.0.1063"}
        "10.0.2.1070"   {$VBM365Build = "5.0.0.1070"}
        "10.0.3.179"    {$VBM365Build = "5.0.1.179"}
        "10.0.3.207"    {$VBM365Build = "5.0.1.207"}
        "10.0.3.225"    {$VBM365Build = "5.0.1.225"}
        "10.0.3.252"    {$VBM365Build = "5.0.1.252"}
        "10.0.4.22"     {$VBM365Build = "5.0.2.22"}
        "10.0.4.42"     {$VBM365Build = "5.0.2.42"}
        "10.0.5.1033"   {$VBM365Build = "5.0.3.1033"}
        "10.0.5.1035"   {$VBM365Build = "5.0.3.1035"}
        "10.0.5.1051"   {$VBM365Build = "5.0.3.1051"}
        "10.0.5.1060"   {$VBM365Build = "5.0.3.1060"}
        "10.0.5.1063"   {$VBM365Build = "5.0.3.1063"}
        "11.1.0.367"    {$VBM365Build = "6.0.0.367"}
        "11.1.0.379"    {$VBM365Build = "6.0.0.379"}
        "11.1.0.385"    {$VBM365Build = "6.0.0.385"}
        Default         {$VBM365Build = "Unknown Value, script update is necessary"}
    }

    [PScustomObject]@{
        Name = $VBM365ServerName
        OS = $VBM365ServerOS
        OSBuild = $OSBuild
        VBM365Version = $VBM365Build
    }
}

 <#
 .Synopsis
    Get configuration about organizations
 .DESCRIPTION
    Get organization name, account used, type (on premise, hybride, O365), service (exchange, sharepoint), region, authentication (basic, modern with legacy protocol, modern), auxiliar backup account/application number
 .EXAMPLE 
    Get-DCVBMOrganization
 #>
function Get-DCVBMOrganization
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Organization"

    $OrgName = (Get-VBOOrganization).OfficeName
    $OrgAccount = (Get-VBOOrganization).username
    $OrgType = (Get-VBOOrganization).type
    $OrgService = (Get-VBOOrganization).BackupParts
    $OrgRegion = (Get-VBOOrganization).region
    if ((Get-VBOOrganization).Office365ExchangeConnectionSettings -ne $null)
    {
        $OrgAuth = (Get-VBOOrganization).Office365ExchangeConnectionSettings.AuthenticationType
    }
    else
    {
        $OrgAuth = (Get-VBOOrganization).Office365SharePointConnectionSettings.AuthenticationType
    }
    if ($OrgAuth -eq "Basic")
    {
        $AuxAccount = (Get-VBOOrganization).backupaccounts.count

    }
    else
    {
        $AuxAccount = (Get-VBOOrganization).backupapplications.count

    }

    [PScustomObject]@{
        Name = $OrgName
        Account = $OrgAccount
        Type = $OrgType
        Service = $OrgService
        Region = $OrgRegion
        Authentication = $OrgAuth
        AuxAccount = $AuxAccount
    }
}

 <#
 .Synopsis
    Get configuration about backup job configuration
 .DESCRIPTION
    Get job name, type, included object, excluded object, repository, proxy, schedule, active or disabled state
 .EXAMPLE 
    Get-DCVBMBackupJob
 #>
function Get-DCVBMBackupJob
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Backup Jobs"

    foreach ($obj in Get-VBOJob)
    {
        $JobName = $obj.name
        $JobType = $obj.JobBackupType
        $JobIncludedObj = $obj.SelectedItems -join ","
        $JobExcludedObj = $obj.ExcludedItems -join ","
        $JobRepository = $obj.Repository
        #Get proxy name from associated proxy ID repository
        $JobProxy = (Get-VBOProxy -id (Get-VBORepository -name $obj.Repository).proxyid).Hostname
        $JobSchedule = "<N/A>"
        if ($obj.schedulepolicy.EnableSchedule -and $obj.schedulepolicy.Type -eq "daily")
        {
            $JobSchedule = $obj.schedulepolicy.dailytime.tostring()
        }
        $JobEnabled = $obj.IsEnabled


        [PScustomObject]@{
            Name = $JobName
            Type = $JobType
            InclObject = $JobIncludedObj
            ExclObject = $JobExcludedObj
            Repository = $JobRepository
            Proxy = $JobProxy
            Schedule = $JobSchedule
            Enabled = $JobEnabled
        }
    }
}

<#
 .Synopsis
    Get configuration about backup copy job configuration
 .DESCRIPTION
    Get job name, repository, backupjob linked, schedule, active or disabled state
 .EXAMPLE 
    Get-DCVBMBackupCopyJob
 #>
function Get-DCVBMBackupCopyJob
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Backup copy Jobs"

    foreach ($obj in Get-VBOCopyJob)
    {
        $JobName = $obj.name
        $JobRepository = $obj.Repository
        $JobBackupLinked = $obj.BackupJob
        if ($obj.schedulepolicy.type -eq "daily")
        {
             $JobSchedule = [string]$obj.SchedulePolicy.DailyTime + " " + $obj.SchedulePolicy.DailyType
        }
        if ($obj.schedulepolicy.type -eq "Periodically")
        {
             $JobSchedule = $obj.SchedulePolicy.PeriodicallyEvery
        }
        else 
        {
            $JobSchedule = $obj.SchedulePolicy.Type
        }
        $JobEnabled = $obj.IsEnabled

        [PScustomObject]@{
            Name = $JobName
            Repository = $JobRepository
            BackupLinked = $JobBackupLinked
            Schedule = $JobSchedule
            Enabled = $JobEnabled
        }
    }
}


 <#
 .Synopsis
    Get configuration about proxy configuration
 .DESCRIPTION
    Get proxy name, port, thread number, throttling, internet proxy used or not, internet proxy port and account
 .EXAMPLE 
    Get-DCVBMProxy
 #>
function Get-DCVBMProxy
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Proxy"

    foreach ($obj in Get-VBOProxy)
    {
        $ProxyName = $obj.hostname
        $ProxyPort = $obj.port
        $ProxyThread = $obj.ThreadsNumber
        $ProxyThrottling = [string]$obj.ThrottlingValue + " " + $obj.ThrottlingUnit
        $ProxyIntHost = "<N/A>"
        $ProxyInternetPort = "<N/A>"
        $ProxyInternetAccount = "<N/A>"
        if ($obj.InternetProxy.UseInternetProxy)
        {
            $ProxyIntHost = $obj.InternetProxy.UseInternetProxy.Host
            $ProxyInternetPort = $obj.InternetProxy.UseInternetProxy.Port
            $ProxyInternetAccount = $obj.InternetProxy.UseInternetProxy.User
        }

        [PScustomObject]@{
            Name = $ProxyName
            Port = $ProxyPort
            Thread = $ProxyThread
            Throttling = $ProxyThrottling
            IntProxyHost = $ProxyIntHost
            IntProxyPort = $ProxyInternetPort
            IntProxyAccount = $ProxyInternetAccount
        }
    }
}

 <#
 .Synopsis
    Get configuration about repository configuration
 .DESCRIPTION
    Get repository name, proxy associated, path, retention type and value, repository object name and encryption
 .EXAMPLE 
    Get-DCVBMRepository
 #>
function Get-DCVBMRepository
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Repository"

    foreach ($obj in Get-VBORepository)
    {
        $RepositoryName = $obj.name
        $RepositoryProxy =  (Get-VBOProxy -id (Get-VBORepository -name $obj.name).proxyid).Hostname
        $RepositoryPath = $obj.Path
        #En attente forum https://forums.veeam.com/veeam-backup-for-microsoft-365-f47/powershell-host-repository-t81718.html
        $RepositoryRetention = [string]$obj.retentionperiod + " " + $obj.RetentionType
        $RepositoryObjectName = "<N/A>"
        if ($obj.ObjectStorageRepository -ne $null)
        {
            $RepositoryObjectName = $obj.ObjectStorageRepository.Name
        }
        $encryption = $obj.EnableObjectStorageEncryption
        [PScustomObject]@{
            Name = $RepositoryName
            Proxy = $RepositoryProxy
            Path = $RepositoryPath
            ObjectRepository = $RepositoryObjectName
            Retention = $RepositoryRetention
            Encryption = $encryption
        }
    }
}

 <#
 .Synopsis
    Get configuration about object repository configuration
 .DESCRIPTION
    Get repository name, folder, type, size limit and if it's long term achive
 .EXAMPLE 
    Get-DCVBMRepository
 #>
function Get-DCVBMObjectRepository
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Object Repository"

    foreach ($obj in Get-VBOObjectStorageRepository)
    {
        $RepositoryName = $obj.name
        $RepositoryFolder =  $obj.Folder
        $RepositoryType = $obj.Type
        $RepositorySizeLimit = "<N/A>"
        if ($obj.EnableSizeLimit)
        {
            $RepositorySizeLimit = [String]$obj.UsedSpace + "/" + $obj.SizeLimit
        }
        $RepositoryArchive = $obj.IsLongTerm
        [PScustomObject]@{
            Name = $RepositoryName
            Folder = $RepositoryFolder
            Type = $RepositoryType
            SizeLimit = $RepositorySizeLimit
            LongTerm = $RepositoryArchive
        }
    }
}

 <#
 .Synopsis
    Get configuration about license
 .DESCRIPTION
    Get license type, expiration date, customer, contact, usage
 .EXAMPLE 
    Get-DCVBMLicense
 #>
function Get-DCVBMLicense
{

    Write-host "$(get-date -Format HH:mm) - VBM365 License"

        $LicenseType = (Get-VBOLicense).type
        $LicenseExpiration =  (Get-VBOLicense).expirationdate.ToShortDateString()
        $LicenseTo = (Get-VBOLicense).LicensedTo
        $LicenseContact = (Get-VBOLicense).ContactPerson
        $LicenseUser = [string](Get-VBOLicense).usedNumber + "/" + (Get-VBOLicense).TotalNumber

        [PScustomObject]@{
            Type = $LicenseType
            Expiration = $LicenseExpiration
            To = $LicenseTo
            Contact = $LicenseContact
            Number = $LicenseUser
        }
}

 <#
 .Synopsis
    Get configuration about restore operator configuration
 .DESCRIPTION
    Get role name, organization, operator, associated object, excluded object
 .EXAMPLE 
    Get-DCVBMRestoreOperator
 #>
function Get-DCVBMRestoreOperator
{
    Write-host "$(get-date -Format HH:mm) - VBM365 Restore Operator"

    foreach ($obj in Get-VBORbacRole)
    {
        $RoleName = $obj.name
        $OrganizationName =  (Get-VBOOrganization -Id ($obj.OrganizationId)).Name
        $OperatorName = $obj.operators.DisplayName -join ","
        $IncludedObject = "Organization"
        if ($obj.RoleType -ne "EntireOrganization")
        {
            $IncludedObject = $obj.SelectedItems.DisplayName -join ","
        }
        $ExcludedObject = "<N/A>"
         if ($obj.ExcludedItems -ne $null)
         {
            $ExcludedObject = $obj.ExcludedItems.DisplayName -join ","
         }
        [PScustomObject]@{
            Role = $RoleName
            Organization = $OrganizationName
            Operator = $OperatorName
            IncludedObject = $IncludedObject
            ExcludedObject = $ExcludedObject
        }
    }
}

 <#
 .Synopsis
    Get configuration about RestAPI configuration
 .DESCRIPTION
    Get state, token life time, port, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVBMRestAPI
 #>
function Get-DCVBMRestAPI
{
    Write-host "$(get-date -Format HH:mm) - VBM365 REST API"

        $Enabled = (Get-VBORestAPISettings).IsServiceEnabled
        $TokenTime =  (Get-VBORestAPISettings).AuthTokenLifeTime
        $Port = (Get-VBORestAPISettings).HTTPSPort
        $CertThumbprint = (Get-VBORestAPISettings).CertificateThumbprint
        $CertFriendlyName = (Get-VBORestAPISettings).CertificateFriendlyName
        $CertExpiration = (Get-VBORestAPISettings).CertificateExpirationDate.ToShortDateString()

        [PScustomObject]@{
            Enabled = $Enabled
            TokenTime = $TokenTime
            Port = $Port
            CertThumbprint = $CertThumbprint
            CertFriendlyName = $CertFriendlyName
            CertExpiration = $CertExpiration
        }
}


 <#
 .Synopsis
    Get configuration about Restore portal configuration
 .DESCRIPTION
    Get state, application ID, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVBMRestorePortal
 #>
function Get-DCVBMRestorePortal
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Restore portal"

    $Enabled = (Get-VBORestorePortalSettings).IsServiceEnabled
    $ApplicationID =  (Get-VBORestorePortalSettings).ApplicationId.Guid
    $CertThumbprint = (Get-VBORestorePortalSettings).CertificateThumbprint
    $CertFriendlyName = (Get-VBORestorePortalSettings).CertificateFriendlyName
    $CertExpiration = (Get-VBORestorePortalSettings).CertificateExpirationDate.ToShortDateString()

    [PScustomObject]@{
        Enabled = $Enabled
        ApplicationID = $ApplicationID
        CertThumbprint = $CertThumbprint
        CertFriendlyName = $CertFriendlyName
        CertExpiration = $CertExpiration
    }
}

 <#
 .Synopsis
    Get configuration about operator Authentication portal configuration
 .DESCRIPTION
    Get state, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVBMOperatorAuthentication
 #>
function Get-DCVBMOperatorAuthentication
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Authentication"

    $Enabled = (Get-VBOOperatorAuthenticationSettings).AuthenticationEnabled
    $CertThumbprint = (Get-VBORestAPISettings).CertificateThumbprint
    $CertFriendlyName = (Get-VBOOperatorAuthenticationSettings).CertificateFriendlyName
    $CertExpiration = (Get-VBOOperatorAuthenticationSettings).CertificateExpirationDate

    [PScustomObject]@{
        Enabled = $Enabled
        CertThumbprint = $CertThumbprint
        CertFriendlyName = $CertFriendlyName
        CertExpiration = $CertExpiration
    }
}

 <#
 .Synopsis
    Get configuration about internet proxy
 .DESCRIPTION
    Get state, host, port and account
 .EXAMPLE 
    Get-DCVBMInternetProxy
 #>
function Get-DCVBMInternetProxy
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Internet Proxy"

    $IntProxyEnabled = (Get-VBOInternetProxySettings).UseInternetProxy
    $IntProxyHost = "<N/A>"
    $IntProxyPort = "<N/A>"
    $IntProxyUser = "<N/A>"
    if ((Get-VBOInternetProxySettings).UseInternetProxy)
    {
        $IntProxyHost = (Get-VBOInternetProxySettings).Host
        $IntProxyPort = (Get-VBOInternetProxySettings).Port
        $IntProxyUser = (Get-VBOInternetProxySettings).User
    }

    [PScustomObject]@{
        Enabled = $IntProxyEnabled
        Host = $IntProxyHost
        Port = $IntProxyPort
        Account = $IntProxyUser
    }
}

 <#
 .Synopsis
    Get configuration about SMTP
 .DESCRIPTION
    Get state, server, port, ssl, account
 .EXAMPLE 
    Get-DCVBMSMTP
 #>
function Get-DCVBMSMTP
{

    Write-host "$(get-date -Format HH:mm) - VBM365 SMTP configuration"

    $SMTPEnabled = (Get-VBOEmailSettings).EnableNotification
    $SMTPServer = "<N/A>"
    $SMTPPort = "<N/A>"
    $SMTPSSL = "<N/A>"
    $SMTPAccount = "<N/A>"
    if ((Get-VBOEmailSettings).EnableNotification)
    {
        $SMTPServer = (Get-VBOEmailSettings).SMTPServer
        $SMTPPort = (Get-VBOEmailSettings).Port
        $SMTPSSL = (Get-VBOEmailSettings).UseSSL
        if ((Get-VBOEmailSettings).UseAuthentication)
        {
            $SMTPAccount = (Get-VBOEmailSettings).Username
        }
    }

    [PScustomObject]@{
        Enabled = $SMTPEnabled
        Server = $SMTPServer
        Port = $SMTPPort
        SSL = $SMTPSSL
        Account = $SMTPAccount
    }
}


 <#
 .Synopsis
    Get configuration about Notifications
 .DESCRIPTION
    Get state, sender, receiver, notification on success, warning and failure, send only last retry notification
 .EXAMPLE 
    Get-DCVBMNotification
 #>
function Get-DCVBMNotification
{

    Write-host "$(get-date -Format HH:mm) - VBM365 Notifications"

    $NotificationEnabled = (Get-VBOEmailSettings).EnableNotification
    $NotificationSender = "<N/A>"
    $NotificationReceiver = "<N/A>"
    $NotificationSuccess = "<N/A>"
    $NotificationWarning = "<N/A>"
    $NotificationFailure = "<N/A>"
    $LastRetryNotificationOnly = "<N/A>"
    if ((Get-VBOEmailSettings).EnableNotification)
    {
        $NotificationSender = (Get-VBOEmailSettings).From -join ","
        $NotificationReceiver = (Get-VBOEmailSettings).To -join ","
        $NotificationSuccess = (Get-VBOEmailSettings).NotifyOnSuccess
        $NotificationWarning = (Get-VBOEmailSettings).NotifyOnWarning
        $NotificationFailure = (Get-VBOEmailSettings).NotifyOnFailure
        $LastRetryNotificationOnly = (Get-VBOEmailSettings).SupressUntilLastRetry
    }

    [PScustomObject]@{
        Enabled = $NotificationEnabled
        Sender = $NotificationSender
        Receiver = $NotificationReceiver
        OnSuccess = $NotificationSuccess
        OnWarning = $NotificationWarning
        OnFailure = $NotificationFailure
        OnlyLastRetry = $LastRetryNotificationOnly
    }
}


 <#
 .Synopsis
    Create array for HTML report
 .DESCRIPTION
    Create array with title and precontent
 .EXAMPLE 
    CreateArray -title "my Title" -var $MyData -PreContent $MyPrecontent
 #>
Function CreateArray ($Title,$Var,$PreContent)
{
    if ($Title)
    {
        "<h3>$Title</h3>"
    }
    if ($PreContent)
    {
        $Var | ConvertTo-Html -Fragment -PreContent $PreContent
    }
    else
    {
        $Var | ConvertTo-Html -Fragment
    }
}


<#
.Synopsis
   Generate HTML report
.DESCRIPTION
   Use all variable to build html report with CSS style 
.EXAMPLE
   Get-HTMLReport -Path "c:\temp\report.html"
#>

function Get-HTMLReport
{
    [CmdletBinding()]

    Param
    (
        #HTML file path
        [Parameter(Mandatory=$true)]
        [string] $Path,

        #HTML file name
        [string] $FileName = "VBM365Audit.html"
    )
    Write-Host "Building HTML"

    #region HTML
    @"
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>$HTMLTitle</title>
    $HTMLCSS
    </head>
    <body>
    <br><br><br><br>

    <h1>VEEAM Backup for Microsoft 365 Report</h1>

    $(CreateArray -title "Summary" -var $DCVBMSummary) 
    $(CreateArray -title "License" -var $DCVBMLicense)
    $(CreateArray -title "SMTP" -var $DCVBMSMTP)
    $(CreateArray -title "Notifications" -var $DCVBMNotification)
    $(CreateArray -title "Internet Proxy" -var $DCVBMInternetProxy)

    $(CreateArray -title "REST API" -var $DCVBMRestAPI)
    $(CreateArray -title "Restore portal" -var $DCVBMRestorePortal)
    $(CreateArray -title "Get-DCVBMOperatorAuthentication" -var $DCVBMOperatorAuthentication )

    $(CreateArray -title "Repositories" -var $DCVBMRepository)
    $(CreateArray -title "Object Repositories" -var $DCVBMObjectRepository)

    $(CreateArray -title "Proxies" -var $DCVBMProxy)

    $(CreateArray -title "Organizations" -var $DCVBMOrganization)
    $(CreateArray -title "Backup jobs" -var $DCVBMBackupJob)
    $(CreateArray -title "Backup copy jobs" -var $DCVBMBackupCopyJob)



    $(CreateArray -title "Restore operators" -var $DCVBMRestoreOperator )

    </body>
"@ | Out-File -Encoding utf8 $htmlReportPath

    Invoke-Item $htmlReportPath


}
#endregion






#Write here all function that need to be displayed in all reports types

$DCVBMSummary = Get-DCVBMSummary
$DCVBMOrganization = Get-DCVBMOrganization
$DCVBMBackupJob = Get-DCVBMBackupJob
$DCVBMProxy = Get-DCVBMProxy
$DCVBMRepository = Get-DCVBMRepository
$DCVBMLicense = Get-DCVBMLicense
$DCVBMRestoreOperator = Get-DCVBMRestoreOperator
$DCVBMRestAPI = Get-DCVBMRestAPI
$DCVBMRestorePortal = Get-DCVBMRestorePortal
$DCVBMOperatorAuthentication = Get-DCVBMOperatorAuthentication
$DCVBMInternetProxy = Get-DCVBMInternetProxy
$DCVBMSMTP = Get-DCVBMSMTP
$DCVBMNotification = Get-DCVBMNotification
$DCVBMObjectRepository = Get-DCVBMObjectRepository
$DCVBMBackupCopyJob = Get-DCVBMBackupCopyJob



Get-HTMLReport -Path "$ReportPath\$domain"


Disconnect-VBOServer

Don’t hesitate about feedback :)


  • New Here
  • 2 comments
  • July 25, 2022

Hello Damien, 

really a nice script. I have only two suggestions for improvement:

1st) I would create the directory for the report path after defining the $ReportPath variable and use the $ReportPath variable to create the folder. Like this:

$date = (get-date -Format "dd_MM_yyyy_HH_mm")

#ReportPath
$ReportPath="C:\PATHNAME\VBM365Audit\$date"

#Create directory
New-Item -ItemType Directory -Path $ReportPath -Force | Out-Null

#Report file HTML path
$htmlReportPath = "$ReportPath\VeeamBackupMicrosoft365.html"


2nd) With my community edition, I received an error message when determining the expiration date of the license. So I would check the license type first. Like this:

if ($LicenseType -ne "Community") {
	$LicenseExpiration =  (Get-VBOLicense).expirationdate.ToShortDateString()
} else {
	$LicenseExpiration = ""
}

Thank you and have a nice day

Jan


Chris.Childerhose
Forum|alt.badge.img+21
jotge wrote:

Hello Damien, 

really a nice script. I have only two suggestions for improvement:

1st) I would create the directory for the report path after defining the $ReportPath variable and use the $ReportPath variable to create the folder. Like this:

$date = (get-date -Format "dd_MM_yyyy_HH_mm")

#ReportPath
$ReportPath="C:\PATHNAME\VBM365Audit\$date"

#Create directory
New-Item -ItemType Directory -Path $ReportPath -Force | Out-Null

#Report file HTML path
$htmlReportPath = "$ReportPath\VeeamBackupMicrosoft365.html"


2nd) With my community edition, I received an error message when determining the expiration date of the license. So I would check the license type first. Like this:

if ($LicenseType -ne "Community") {
	$LicenseExpiration =  (Get-VBOLicense).expirationdate.ToShortDateString()
} else {
	$LicenseExpiration = ""
}

Thank you and have a nice day

Jan

I like the report directory suggestions. Will keep things organized so you could run this from one location on multiple servers in other locations. 😁


damien commenge
Forum|alt.badge.img+5

Hello :)

I totally agree for the first.

For the second, the script is for production purpose and community edition is not.

 

Update :

 

# =======================================================
# NAME: VBM365audit.ps1
# AUTHOR: Commenge Damien, Axians Cloud Builder
# DATE: 11/07/2022
#
# VERSION 1.03
# COMMENTS: This script is created to Audit Veeam backup for microsoft 365
# <N/A> is used for not available
# 16/07/2022 : Update lot of code for better performance
# 18/07/2022 : Change date format and replace VBM to VB365
# 26/07/2022 : Optimize path creation
# =======================================================
#Requires -modules Veeam.Archiver.PowerShell

#Date to create folder
$Date = Get-Date -Format "yyyy-MM-dd HH_mm"
#ReportPath to create folder
$ReportPath="C:\temp\VBM365Audit\$Date"
#Create folder
New-Item -ItemType Directory -Path $ReportPath -Force | Out-Null
#Report file HTML path
$HTMLReportPath = "$ReportPath\VeeamBackupMicrosoft365.html"

#Web page title
$HTMLTitle = "VBM365 report"
#Web page CSS style
$HTMLCSS = @'
<style>
    body{color:black;font-family:Vinci Sans Light;font-size:0.79em;line-height:1.25;margin:5;}
    a{color:black;}
    H1{color:white;font-family:Verdana;font-weight:bold;font-size:20pt;margin-bottom:50px;margin-top:40px;text-align:center;background-color:#005EB8;}
    H2{color:#A20067;font-family:Verdana;font-size:16pt;margin-left:14px;text-align:left;}
    H3{color:#005EB8;font-family:Verdana;font-size:13pt;margin-left:16px;}
    H4{color:black;font-family:Verdana;font-size:11pt;margin-left:16px;}
    table {border-collapse: collapse;margin-left:10px;border-radius:7px 7px 0px 0px;}
    th, td {padding: 8px;text-align: left;border-bottom: 1px solid #ddd;}
    th {background-color: #006400;color: white;}
    td:first-child{font-weight:bold;}
    tr:nth-child(even){background-color: #f2f2f2}
    table.table2 td:first-child{background-color: #A20067;color: white}
</style>
'@

#Connect to VBO Server
Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - Connecting to VBM 365 server"
try {
    Connect-VBOServer -ErrorAction Stop
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - Connected to VBM 365 server"
}
catch [System.Management.Automation.RuntimeException]{
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - Connexion is already done"
}
catch {
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - $($_.Exception.message) " -ForegroundColor Red
    return
}

 <#
 .SYNOPSIS
    Get configuration Summary from Veeam Microsoft 365 server
 .DESCRIPTION
    Get server name, OS, OS build and VBM365 version
 .EXAMPLE 
    Get-DCVB365Summary
 #>
function Get-DCVB365Summary
{
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Summary"

    $ServerName   = $env:COMPUTERNAME
    $ServerOS     = (Get-CimInstance Win32_OperatingSystem).Caption
    $OSBuild            = Get-ItemPropertyValue -path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion" -name 'UBR'
    #No way to find version with powershell but associated version with VBR is available here : https://www.veeam.com/kb4106 
    $VBRbuild           = (Get-Module Veeam.Archiver.PowerShell).nestedmodules.version.tostring()

    $VB365Build = Switch ($VBRbuild)
    {
        "10.0.2.1061"   {"5.0.0.1061"}
        "10.0.2.1063"   {"5.0.0.1063"}
        "10.0.2.1070"   {"5.0.0.1070"}
        "10.0.3.179"    {"5.0.1.179"}
        "10.0.3.207"    {"5.0.1.207"}
        "10.0.3.225"    {"5.0.1.225"}
        "10.0.3.252"    {"5.0.1.252"}
        "10.0.4.22"     {"5.0.2.22"}
        "10.0.4.42"     {"5.0.2.42"}
        "10.0.5.1033"   {"5.0.3.1033"}
        "10.0.5.1035"   {"5.0.3.1035"}
        "10.0.5.1051"   {"5.0.3.1051"}
        "10.0.5.1060"   {"5.0.3.1060"}
        "10.0.5.1063"   {"5.0.3.1063"}
        "11.1.0.367"    {"6.0.0.367"}
        "11.1.0.379"    {"6.0.0.379"}
        "11.1.0.385"    {"6.0.0.385"}
        Default         {"Unknown Value, script update is necessary"}
    }

    [PScustomObject]@{
        Name            = $ServerName
        OS              = $ServerOS
        OSBuild         = $OSBuild
        VB365Version   = $VB365Build
    }
}

 <#
 .SYNOPSIS
    Get configuration about organizations
 .DESCRIPTION
    Get organization name, account used, type (on premise, hybride, O365), service (exchange, sharepoint), region, authentication (basic, modern with legacy protocol, modern), auxiliar backup account/application number
 .EXAMPLE 
    Get-DCVB365Organization
 #>
function Get-DCVB365Organization
{
    Write-host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Organization"

    $Organization = Get-VBOOrganization

    if ($Organization.Office365ExchangeConnectionSettings)
    {
        $OrgAuth = (Get-VBOOrganization).Office365ExchangeConnectionSettings.AuthenticationType
    }
    else
    {
        $OrgAuth = (Get-VBOOrganization).Office365SharePointConnectionSettings.AuthenticationType
    }
    if ($OrgAuth -eq "Basic")
    {
        $AuxAccount = (Get-VBOOrganization).backupaccounts.count
    }
    else
    {
        $AuxAccount = (Get-VBOOrganization).backupapplications.count
    }

    [PScustomObject]@{
        Name            = $Organization.OfficeName
        Account         = $Organization.username
        Type            = $Organization.type
        Service         = $Organization.BackupParts
        Region          = $Organization.region
        Authentication  = $OrgAuth
        AuxAccount      = $AuxAccount
    }
}

 <#
 .SYNOPSIS
    Get configuration about backup job configuration
 .DESCRIPTION
    Get job name, type, included object, excluded object, repository, proxy, schedule, active or disabled state
 .EXAMPLE 
    Get-DCVB365BackupJob
 #>
function Get-DCVB365BackupJob
{
    Write-host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Backup Jobs"

    foreach ($Job in Get-VBOJob)
    {
        #Get proxy name from associated proxy ID repository
        $JobSchedule = "<N/A>"
        if ($Job.schedulepolicy.EnableSchedule -and $Job.SchedulePolicy.Type -eq "daily")
        {
             $JobSchedule = [string]$Job.SchedulePolicy.DailyTime + " " + $Job.SchedulePolicy.DailyType
        }
        if ($Job.schedulepolicy.EnableSchedule -and $Job.SchedulePolicy.Type -eq "Periodically")
        {
             $JobSchedule = $Job.SchedulePolicy.PeriodicallyEvery
        }

        [PScustomObject]@{
            Name        = $Job.Name
            Type        = $Job.JobBackupType
            InclObject  = $Job.SelectedItems -join ", "
            ExclObject  = $Job.ExcludedItems -join ", "
            Repository  = $Job.Repository
            Proxy       = (Get-VBOProxy -id (Get-VBORepository -Name $Job.Repository).ProxyID).Hostname
            Schedule    = $JobSchedule
            Enabled     = $Job.IsEnabled
        }
    }
}

<#
 .SYNOPSIS
    Get configuration about backup copy job configuration
 .DESCRIPTION
    Get job name, repository, backupjob linked, schedule, active or disabled state
 .EXAMPLE 
    Get-DCVB365BackupCopyJob
 #>
function Get-DCVB365BackupCopyJob
{
    Write-host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Backup copy Jobs"

    foreach ($CopyJob in Get-VBOCopyJob)
    {
        if ($CopyJob.SchedulePolicy.Type -eq "daily")
        {
             $JobSchedule = [string]$CopyJob.SchedulePolicy.DailyTime + " " + $CopyJob.SchedulePolicy.DailyType
        }
        if ($CopyJob.SchedulePolicy.Type -eq "Periodically")
        {
             $JobSchedule = $CopyJob.SchedulePolicy.PeriodicallyEvery
        }
        else 
        {
            $JobSchedule = $CopyJob.SchedulePolicy.Type
        }
        [PScustomObject]@{
            Name            = $CopyJob.name
            Repository      = $CopyJob.Repository
            BackupLinked    = $CopyJob.BackupJob
            Schedule        = $JobSchedule
            Enabled         = $CopyJob.IsEnabled
        }
    }
}


 <#
 .SYNOPSIS
    Get configuration about proxy configuration
 .DESCRIPTION
    Get proxy name, port, thread number, throttling, internet proxy used or not, internet proxy port and account
 .EXAMPLE 
    Get-DCVB365Proxy
 #>
function Get-DCVB365Proxy
{

    Write-host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Proxy"

    foreach ($Proxy in Get-VBOProxy)
    {
        $Proxy = [PScustomObject]@{
            Name            = $Proxy.hostname
            Port            = $Proxy.port
            Thread          = $Proxy.ThreadsNumber
            Throttling      = [string]$Proxy.ThrottlingValue + " " + $Proxy.ThrottlingUnit
            IntProxyHost    = "<N/A>"
            IntProxyPort    = "<N/A>"
            IntProxyAccount = "<N/A>"
        }
        if ($Proxy.InternetProxy.UseInternetProxy)
        {
            $Proxy.IntProxyHost     = $Proxy.InternetProxy.UseInternetProxy.Host
            $Proxy.IntProxyPort     = $Proxy.InternetProxy.UseInternetProxy.Port
            $Proxy.IntProxyAccount  = $Proxy.InternetProxy.UseInternetProxy.User
        }
    }
    $Proxy
}

 <#
 .SYNOPSIS
    Get configuration about repository configuration
 .DESCRIPTION
    Get repository name, proxy associated, path, retention type and value, repository object name and encryption
 .EXAMPLE 
    Get-DCVB365Repository
 #>
function Get-DCVB365Repository
{

    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Repository"

    foreach ($Repository in Get-VBORepository)
    {
        $Proxy        =  (Get-VBOProxy -id (Get-VBORepository -name $Repository.Name).ProxyID).Hostname
        $Retention    = [string]$Repository.RetentionPeriod + " " + $Repository.RetentionType
        $ObjectName   = "<N/A>"
        if ($Repository.ObjectStorageRepository)
        {
            $ObjectName = $Repository.ObjectStorageRepository.Name
        }
        [PScustomObject]@{
            Name                = $Repository.Name
            Proxy               = $Proxy
            Path                = $Repository.Path
            ObjectRepository    = $ObjectName
            Retention           = $Retention
            Encryption          = $Repository.EnableObjectStorageEncryption
        }
    }
}

 <#
 .SYNOPSIS
    Get configuration about object repository configuration
 .DESCRIPTION
    Get repository name, folder, type, size limit and if it's long term achive
 .EXAMPLE 
    Get-DCVB365ObjectRepository
 #>
function Get-DCVB365ObjectRepository
{
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Object Repository"

    foreach ($ObjectStorage in Get-VBOObjectStorageRepository)
    {
        $SizeLimit = "<N/A>"
        if ($ObjectStorage.EnableSizeLimit)
        {
            $SizeLimit = [String]$ObjectStorage.UsedSpace + "/" + $ObjectStorage.SizeLimit
        }
        [PScustomObject]@{
            Name        = $ObjectStorage.name
            Folder      = $ObjectStorage.Folder
            Type        = $ObjectStorage.Type
            SizeLimit   = $SizeLimit
            LongTerm    = $ObjectStorage.IsLongTerm
        }
    }
}

 <#
 .SYNOPSIS
    Get configuration about license
 .DESCRIPTION
    Get license type, expiration date, customer, contact, usage
 .EXAMPLE 
    Get-DCVB365License
 #>
function Get-DCVB365License
{

    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 License"
    $License         = (Get-VBOLicense)
    $Usage    = [string]$License.usedNumber + "/" + (Get-VBOLicense).TotalNumber

    [PScustomObject]@{
        Type        = $License.Type
        Expiration  = $License.ExpirationDate.ToShortDateString()
        To          = $License.LicensedTo
        Contact     = $License.ContactPerson
        Number      = $Usage
    }
}

 <#
 .SYNOPSIS
    Get configuration about restore operator configuration
 .DESCRIPTION
    Get role name, organization, operator, associated object, excluded object
 .EXAMPLE 
    Get-DCVB365RestoreOperator
 #>
function Get-DCVB365RestoreOperator
{
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Restore Operator"

    foreach ($Role in Get-VBORbacRole)
    {
        $IncludedObject = "Organization"
        $ExcludedObject = "<N/A>"
        if ($Role.RoleType -ne "EntireOrganization")
        {
            $IncludedObject = $Role.SelectedItems.DisplayName -join ","
        }
        if ($Role.ExcludedItems)
        {
        $ExcludedObject = $Role.ExcludedItems.DisplayName -join ","
        }
        [PScustomObject]@{
            Role = $Role.Name
            Organization    = (Get-VBOOrganization -Id ($Role.OrganizationId)).Name
            Operator        = $Role.Operators.DisplayName -join ", "
            IncludedObject  = $IncludedObject
            ExcludedObject  = $ExcludedObject
        }
    }
}

 <#
 .SYNOPSIS
    Get configuration about RestAPI configuration
 .DESCRIPTION
    Get state, token life time, port, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVB365RestAPI
 #>
function Get-DCVB365RestAPI
{
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 REST API"

    $RestAPI = Get-VBORestAPISettings

    [PScustomObject]@{
        Enabled             = $RestAPI.IsServiceEnabled
        CertThumbprint      = $RestAPI.CertificateThumbprint
        CertFriendlyName    = $RestAPI.CertificateFriendlyName
        CertExpiration      = $RestAPI.CertificateExpirationDate.ToShortDateString()
        TokenTime           = $RestAPI.AuthTokenLifeTime
        Port                = $RestAPI.HTTPSPort
    }
}


 <#
 .SYNOPSIS
    Get configuration about Restore portal configuration
 .DESCRIPTION
    Get state, application ID, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVB365RestorePortal
 #>
function Get-DCVB365RestorePortal
{

    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Restore portal"

    $RestorePortal = Get-VBORestorePortalSettings

    [PScustomObject]@{
        Enabled             = $RestorePortal.IsServiceEnabled
        CertThumbprint      = $RestorePortal.CertificateThumbprint
        CertFriendlyName    = $RestorePortal.CertificateFriendlyName
        CertExpiration      = $RestorePortal.CertificateExpirationDate.ToShortDateString()
        ApplicationID       = $RestorePortal.ApplicationId.Guid
    }
}

 <#
 .SYNOPSIS
    Get configuration about operator Authentication portal configuration
 .DESCRIPTION
    Get state, certificate thumbprint friendly name and expiration date
 .EXAMPLE 
    Get-DCVB365OperatorAuthentication
 #>
function Get-DCVB365OperatorAuthentication
{
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Authentication"

    $OperatorAuthentication = Get-VBOOperatorAuthenticationSettings

    [PScustomObject]@{
        Enabled             = $OperatorAuthentication.AuthenticationEnabled
        CertThumbprint      = "NotAvailable.WaitingNextPatch"
        CertFriendlyName    = $OperatorAuthentication.CertificateFriendlyName
        CertExpiration      = $OperatorAuthentication.CertificateExpirationDate
    }
}

 <#
 .SYNOPSIS
    Get configuration about internet proxy
 .DESCRIPTION
    Get state, host, port and account
 .EXAMPLE 
    Get-DCVB365InternetProxy
 #>
function Get-DCVB365InternetProxy
{
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Internet Proxy"
    $InternetProxySetting = Get-VBOInternetProxySettings

    $InternetProxy = [PScustomObject]@{
        Enabled   = $InternetProxySetting.UseInternetProxy
        Host      = "<N/A>"
        Port      = "<N/A>"
        Account   = "<N/A>"
    }
    if ($InternetProxySetting.UseInternetProxy)
    {
        $InternetProxy.Host    = $InternetProxySetting.Host
        $InternetProxy.Port    = $InternetProxySetting.Port
        $InternetProxy.Account = $InternetProxySetting.User
    }
    $InternetProxy
}

 <#
 .SYNOPSIS
    Get configuration about SMTP
 .DESCRIPTION
    Get state, server, port, ssl, account
 .EXAMPLE 
    Get-DCVB365SMTP
 #>
function Get-DCVB365SMTP
{
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 SMTP configuration"

    $SMTPSetting = Get-VBOEmailSettings

    $SMTP = [PScustomObject]@{
        Enabled = $SMTPSetting.EnableNotification
        Server  = "<N/A>"
        Port    = "<N/A>"
        SSL     = "<N/A>"
        Account = "<N/A>"
    }
    if ($SMTPSetting.EnableNotification)
    {
        $SMTP.Server = $SMTPSetting.SMTPServer
        $SMTP.Port   = $SMTPSetting.Port
        $SMTP.SSL    = $SMTPSetting.UseSSL
        if ($SMTPSetting.UseAuthentication)
        {
            $SMTP.Account = $SMTPSetting.Username
        }
    }
    $SMTP
}


 <#
 .SYNOPSIS
    Get configuration about Notifications
 .DESCRIPTION
    Get state, sender, receiver, notification on success, warning and failure, send only last retry notification
 .EXAMPLE 
    Get-DCVB365Notification
 #>
function Get-DCVB365Notification
{

    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Notifications"
    $NotificationSetting = (Get-VBOEmailSettings)

    $Notification = [PScustomObject]@{
        Enabled         = $NotificationSetting.EnableNotification
        Sender          = "<N/A>"
        Receiver        = "<N/A>"
        OnSuccess       = "<N/A>"
        OnWarning       = "<N/A>"
        OnFailure       = "<N/A>"
        OnlyLastRetry   = "<N/A>"
    }
    if ($NotificationSetting.EnableNotification)
    {
        $Notification.Sender         = $NotificationSetting.From -join ", "
        $Notification.Receiver       = $NotificationSetting.To -join ", "
        $Notification.OnSuccess      = $NotificationSetting.NotifyOnSuccess
        $Notification.OnWarning      = $NotificationSetting.NotifyOnWarning
        $Notification.OnFailure      = $NotificationSetting.NotifyOnFailure
        $Notification.OnlyLastRetry  = $NotificationSetting.SupressUntilLastRetry
    }
    $Notification
}


 <#
 .SYNOPSIS
    Create array for HTML report
 .DESCRIPTION
    Create array with title and precontent
 .EXAMPLE 
    CreateArray -title "my Title" -var $MyData -PreContent $MyPrecontent
 #>

Function CreateArray
{ 
    param (
        $Title,
        $Var,
        $PreContent
    )

    if ($Title)
    {
        "<h3>$Title</h3>"
    }
    if ($PreContent)
    {
        $Var | ConvertTo-Html -Fragment -PreContent $PreContent
    }
    else
    {
        $Var | ConvertTo-Html -Fragment
    }
}


<#
.SYNOPSIS
   Generate HTML report
.DESCRIPTION
   Use all variable to build html report with CSS style 
.EXAMPLE
   Get-HTMLReport -Path "C:\temp\report.html"
#>

Function Get-HTMLReport
{
    [CmdletBinding()]

    Param
    (
        #HTML file path
        [Parameter(Mandatory)]
        [System.IO.FileInfo]$Path,

        #HTML file name
        [string] $FileName = "VBM365Audit.html"
    )
    Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm") - VBM365 Building HTML"
    #region HTML
    # chrisdent: STYLE: In the code below `CreateArray` is something of a misleading function name.
    # chrisdent: ENHANCEMENT: Perhaps consider using a string builder.
    @"
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>$HTMLTitle</title>
    $HTMLCSS
    </head>
    <body>
    <br><br><br><br>

    <h1>VEEAM Backup for Microsoft 365 Report</h1>

    $(CreateArray -title "Summary" -var $DCVB365Summary) 
    $(CreateArray -title "License" -var $DCVB365License)
    $(CreateArray -title "SMTP" -var $DCVB365SMTP)
    $(CreateArray -title "Notifications" -var $DCVB365Notification)
    $(CreateArray -title "Internet Proxy" -var $DCVB365InternetProxy)

    $(CreateArray -title "REST API" -var $DCVB365RestAPI)
    $(CreateArray -title "Restore portal" -var $DCVB365RestorePortal)
    $(CreateArray -title "Operator Authentication" -var $DCVB365OperatorAuthentication )

    $(CreateArray -title "Repositories" -var $DCVB365Repository)
    $(CreateArray -title "Object Repositories" -var $DCVB365ObjectRepository)

    $(CreateArray -title "Proxies" -var $DCVB365Proxy)

    $(CreateArray -title "Organizations" -var $DCVB365Organization)
    $(CreateArray -title "Backup jobs" -var $DCVB365BackupJob)
    $(CreateArray -title "Backup copy jobs" -var $DCVB365BackupCopyJob)



    $(CreateArray -title "Restore operators" -var $DCVB365RestoreOperator )

    </body>
"@ | Out-File -Encoding utf8 $HTMLReportPath

    Invoke-Item $HTMLReportPath


}
#endregion

#Write here all function that need to be displayed in all reports types

$DCVB365Summary                   = Get-DCVB365Summary
$DCVB365Organization              = Get-DCVB365Organization
$DCVB365BackupJob                 = Get-DCVB365BackupJob
$DCVB365Proxy                     = Get-DCVB365Proxy
$DCVB365Repository                = Get-DCVB365Repository
$DCVB365License                   = Get-DCVB365License
$DCVB365RestoreOperator           = Get-DCVB365RestoreOperator
$DCVB365RestAPI                   = Get-DCVB365RestAPI
$DCVB365RestorePortal             = Get-DCVB365RestorePortal
$DCVB365OperatorAuthentication    = Get-DCVB365OperatorAuthentication
$DCVB365InternetProxy             = Get-DCVB365InternetProxy
$DCVB365SMTP                      = Get-DCVB365SMTP
$DCVB365Notification              = Get-DCVB365Notification
$DCVB365ObjectRepository          = Get-DCVB365ObjectRepository
$DCVB365BackupCopyJob             = Get-DCVB365BackupCopyJob


#Create HTML Report
Get-HTMLReport -Path "$ReportPath\$domain"


Disconnect-VBOServer


 


  • Not a newbie anymore
  • 1 comment
  • September 29, 2022

Hi Damien,

Very nice job and script.

In my case I have only “,” for job with Group Selection Base.

So I modify your script to retreive AD Group.

 

if ($Job.SelectedItems.Type -eq "SecurityGroup")
{
   $InclObject = $Job.SelectedItems.Group.DisplayName -join ", "    
}
else
{
   $InclObject = $Job.SelectedItems -join ", " 
}
if ($Job.ExcludedItems.Type -eq "SecurityGroup")
{
   $ExclObject = $Job.ExcludedItems.Group.DisplayName -join ", "
}
else
{
   $ExclObject = $Job.ExcludedItems -join ", "
}
[PScustomObject]@{
   Name        = $Job.Name
   Type        = $Job.JobBackupType
   InclObject  = $InclObject
   ExclObject  = $ExclObject
   Repository  = $Job.Repository
   Proxy       = (Get-VBOProxy -id (Get-VBORepository -Name $Job.Repository).ProxyID).Hostname
   Schedule    = $JobSchedule
   Enabled     = $Job.IsEnabled
}

 

 

Regards


damien commenge
Forum|alt.badge.img+5
  • Author
  • Veeam Legend
  • 115 comments
  • September 29, 2022

Thanks for the feedback and fix :)


Comment