Maintain control of your Microsoft 365 data
Post Reply
matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

VBM365 powershell script Audit

Post by matteu » 10 people like this post

Hello,

This is the script I just created to audit Veeam Backup for microsoft 365.
It's not complete but feel free to ask me what you need :)

Code: Select all

# =======================================================
# 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

Mike Resseler
Product Manager
Posts: 7595
Liked: 1117 times
Joined: Feb 08, 2013 3:08 pm
Full Name: Mike Resseler
Location: Belgium
Contact:

Re: VBM365 powershell script Audit

Post by Mike Resseler »

Thanks for putting it here! A lot of people will like this.

matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

Re: VBM365 powershell script Audit

Post by matteu »

Thanks, I'm waiting the answer for the repository hostname and I will put new version with backup copy + storage object part.

jorgedlcruz
Veeam Software
Posts: 833
Liked: 427 times
Joined: Jul 17, 2015 6:54 pm
Full Name: Jorge de la Cruz
Contact:

Re: VBM365 powershell script Audit

Post by jorgedlcruz »

Hello Matteu,
Great job, some quick feedback after running it, it was so fast and smooth, awesome job.

The header is pointing to a UK Internet Services Company or something?
Image

This is the build version in logs, which is okay for more internal consumption I guess (thanks Polina for pointing out), it might be the compatible version with VBR, or the Explorers version, but not the VB365 server. I usually get this from the new API endpoint /v6/ServiceInstance
Image

The Repositories section is great, but it could be better, as my Repository is Object Storage:
Image

So there is a big part that is not shown here, the Object Repo part, and the settings of that object repo:
Image

Hope feedback is useful! Keep them coming!
Jorge de la Cruz
Senior Analyst, Product Management | Veeam ONE @ Veeam Software

@jorgedlcruz
https://www.jorgedelacruz.es / https://jorgedelacruz.uk
vExpert 2014-2022 / InfluxAce

matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

Re: VBM365 powershell script Audit

Post by matteu »

Hello
Ecellent feedback :)
It s exactly what I hope people do :)

Right for title it s my company ^^. I will fix it tomorow

Oh yes version should be 6 something I didnt notice it. I will try to fix it. I know how to use simple PS command but I don t know how to manage REST api correctly and need to find some documentation to learn it.

I added object storage on the script 2hours after I make this topic for s3 compatible and azure. I don t know if it will work with Amazon I can t test it because I don t have tenan.
I will post new version with the others fix tomorow :)

matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

Re: VBM365 powershell script Audit

Post by matteu »

OK, so I update the code for the title but I'm waiting an answer on an other topic I create here to find the correct version 6.0.0.385 without rest api because I would like my script to work without any prerequesite.

jorgedlcruz
Veeam Software
Posts: 833
Liked: 427 times
Joined: Jul 17, 2015 6:54 pm
Full Name: Jorge de la Cruz
Contact:

Re: VBM365 powershell script Audit

Post by jorgedlcruz »

Awesome work, Matteu,
I have amended my response as well with a link to a KB where you can see the VB365 version, and the logs version, worse case you can always add a case where version is 11.xx whatever then is VB365 v6.x whatever, but wait for Polina, I am sure she can point you to a better direction than that.

Great work, mate
Jorge de la Cruz
Senior Analyst, Product Management | Veeam ONE @ Veeam Software

@jorgedlcruz
https://www.jorgedelacruz.es / https://jorgedelacruz.uk
vExpert 2014-2022 / InfluxAce

matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

Re: VBM365 powershell script Audit

Post by matteu »

Feel free with more feedback :)
Then, I'm not english and I probably do some "error" don't hesitate to tell me :)
New version with all fixes and object part (and different green color) :

Code: Select all

# =======================================================
# 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

jorgedlcruz
Veeam Software
Posts: 833
Liked: 427 times
Joined: Jul 17, 2015 6:54 pm
Full Name: Jorge de la Cruz
Contact:

Re: VBM365 powershell script Audit

Post by jorgedlcruz »

Amazing work, Damien,
I just ran it, and I can not see my schedule, it appears N/A:
Image

Other than that, looking awesome, cheers.
Jorge de la Cruz
Senior Analyst, Product Management | Veeam ONE @ Veeam Software

@jorgedlcruz
https://www.jorgedelacruz.es / https://jorgedelacruz.uk
vExpert 2014-2022 / InfluxAce

matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

Re: VBM365 powershell script Audit

Post by matteu » 4 people like this post

Thanks again :)

I did it on backup copy but forget to use it on backup job.

Fixed :

Code: Select all

# =======================================================
# 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"

$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 = [string]$obj.SchedulePolicy.DailyTime + " " + $obj.SchedulePolicy.DailyType
        }
        if ($obj.schedulepolicy.EnableSchedule -and $obj.schedulepolicy.type -eq "Periodically")
        {
             $JobSchedule = $obj.SchedulePolicy.PeriodicallyEvery
        }
        $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

Mahong
Veeam Software
Posts: 22
Liked: 1 time
Joined: Dec 19, 2017 8:01 am
Full Name: Ma Hong
Contact:

Re: VBM365 powershell script Audit

Post by Mahong »

@matteu awesome tools,I love it. Would you pls to post a sample audit report, so I can follow the script quickly. Thanks!

tsmith_co
Veeam Software
Posts: 117
Liked: 37 times
Joined: Dec 12, 2013 1:23 pm
Full Name: Tim Smith
Location: Ohio
Contact:

Re: VBM365 powershell script Audit

Post by tsmith_co »

@matteu This looks great! I'll try it out in my lab this week! My only pre-testing feedback is that if you wanted to standardize of the acronym, we use the VB365, since VBM is the metadata file extension for VBR backup chains.
Tim Smith
https://tsmith.co
@tsmith_co

dwrandolph
Novice
Posts: 6
Liked: 1 time
Joined: Dec 12, 2012 12:19 am
Full Name: Donald Randolph
Contact:

Re: VBM365 powershell script Audit

Post by dwrandolph »

A small pet peeve. Use ISO 8601 "yyyy-MM-dd HH:mm" for date formats. Avoids confusion with different regions dd-mm-yyyy or mm-dd-yyyy. Is easier to sort. And can be fed back into PowerShell for later calculations.

matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

Re: VBM365 powershell script Audit

Post by matteu »

Thanks for all these feedback, I update the last version of the script soon and I post it again :)
I did some code improvement because of powershell comunity advices !

matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

Re: VBM365 powershell script Audit

Post by matteu » 3 people like this post

Sample here :

Image

Image

Image

New code version with what you asked :) (I hope)

Code: Select all

# =======================================================
# NAME: VBM365audit.ps1
# AUTHOR: Commenge Damien, Axians Cloud Builder
# DATE: 11/07/2022
#
# VERSION 1.02
# 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
# =======================================================
#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-DCVBMSummary
 #>
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-DCVBMOrganization
 #>
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-DCVBMBackupJob
 #>
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-DCVBMBackupCopyJob
 #>
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-DCVBMProxy
 #>
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-DCVBMRepository
 #>
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-DCVBMRepository
 #>
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-DCVBMLicense
 #>
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-DCVBMRestoreOperator
 #>
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-DCVBMRestAPI
 #>
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-DCVBMRestorePortal
 #>
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-DCVBMOperatorAuthentication
 #>
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-DCVBMInternetProxy
 #>
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-DCVBMSMTP
 #>
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-DCVBMNotification
 #>
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
    @"
    <!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 "Get-DCVBMOperatorAuthentication" -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


BaptisteT
Veeam Software
Posts: 400
Liked: 61 times
Joined: Mar 15, 2019 4:21 pm
Full Name: Baptiste Tellier
Contact:

Re: VBM365 powershell script Audit

Post by BaptisteT »

hi @matteu,

Perhaps once you have enough feedback, considerer uploading your nice report on https://github.com/VeeamHub/powershell

Great job !

maximeg
Service Provider
Posts: 8
Liked: 4 times
Joined: Jul 15, 2019 3:30 pm
Full Name: Maxime Guiraud
Contact:

Re: VBM365 powershell script Audit

Post by maximeg »

Hi Matteu and BaptisteT
Thanks for this script !
I ve just try it in our lab, maybe you can modify 2 points:

-- VBM365 License
It s not an important improvement, because this script is for production purpose, but in our lab we have a Community edition license, this version doesn't have an expiration date so the function Get-DCVB365License generate an error message.
2022-07-20 14:54 - VBM365 License
You cannot call a method on a null-valued expression.

PS C:\> Get-VBOLicense
Status : Valid
ExpirationDate :
Type : Community
LicensedTo :
ContactPerson :
TotalNumber : 10 (3 used)
SupportExpirationDate :

-- VBM365 REST API
Restore Portal is installed on a dedicated machine which act also as a proxy, so the Veeam.Archiver.RESTful.Service is running on this machine instead of the VBO server

PS C:\>Get-VBORestAPISettings
Get-VBORestAPISettings : Service not found: Veeam.Archiver.RESTful.Service

I hope we meet each other soon ;)

matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

Re: VBM365 powershell script Audit

Post by matteu »

Hello,
Thank you for your feedback.

For Veeam community you can have some error message yes because I don't use it and you're right, it's for production purpose ^^

For the remote Rest API, unfortunately, I don't find any documentation about how to get it with powershell.

chris.childerhose
Veeam Vanguard
Posts: 355
Liked: 80 times
Joined: Aug 13, 2014 6:03 pm
Full Name: Chris Childerhose
Location: Toronto, ON
Contact:

Re: VBM365 powershell script Audit

Post by chris.childerhose »

I like this script for auditing. I will provide feedback once I run it some more.
-----------------------
Chris Childerhose
Veeam Vanguard / Veeam Legend / Veeam Ceritified Architect / VMCE
vExpert / VCAP-DCA / VCP6 / MCITP
Personal blog: https://just-virtualization.tech
Twitter: @cchilderhose

matteu
Veeam Legend
Posts: 408
Liked: 72 times
Joined: May 11, 2018 8:42 am
Contact:

Re: VBM365 powershell script Audit

Post by matteu » 1 person likes this post

Perfect, thanks :)
I sent mail to know how to put it on the github veeam repo community I m waiting an answer :)

Post Reply

Who is online

Users browsing this forum: No registered users and 14 guests