ActionPlans/Start-DecodeSafeLinksURL.ps1

<#
        .SYNOPSIS
        Decode Microsoft Defender for Office 365 Safe Links to show original URL
 
        .DESCRIPTION
        Provide Microsoft Defender for Office 365 Safe Links and export in a HTML format the original URL
        Can be executed on multiple encoded URL and in the end all decoded URLs can be seen the the HTML output
 
        .EXAMPLE
        Provide the re-written URL:
        https://nam06.safelinks.protection.outlook.com/?url=http://www.contoso.com/&data=04|01|user1@contoso.com|83ffsdfa384443fadq342743b|72f988fasdfa4d011db47|1|0|6376688415|Unknown|TWFpbGZMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwfadsfaCI6Mn0=|1000&sdata=qOwctqh5fadfaai/tglS4avTxToy67X4M8fadsfasaA=&reserved=0
         
        .LINK
        Online documentation: https://answers.microsoft.com/
 
    #>

Clear-Host

# Variable to know if any URL needs to be decoded
[bool]$decode = $true 

# Create timestamp
$ts = get-date -Format yyyyMMdd_HHmmss

# Create export folder
try {
    $ExportPath = "$global:WSPath\DecodeSafeLinksUrl_$ts"
    mkdir $ExportPath -Force | out-null
    Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Create ExportPath" -Description "Success"
}
catch {
    Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Create ExportPath" -Description "Couldn't create folder $global:WSPath\DecodeSafeLinksUrl_$ts. Error: $($_.Exception.Message)"
    Write-Host "Couldn't create folder $global:WSPath\DecodeSafeLinksUrl_$ts"
    Read-Key
    Start-O365TroubleshootersMenu
}



#Import assembly System.Web which contains HttpUtility.UrlDecode method
try {
    Add-Type -AssemblyName System.Web
}
catch {
    Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Referrence assembly System.Web" -Description "Error: $($_.Exception.Message)"
    Write-Host "Couldn't load assembly System.Web. The script will return to the main menu"
    Read-Key
    Start-O365TroubleshootersMenu
}


# creating a list to store original URLs
$ListOfOriginalAndDecodedUrls = New-Object -TypeName "System.Collections.ArrayList"

While ($decode) {
    # Read from console the encoded URL
    $encodedURL = Read-Host("Please provide the Microsoft Defender for Office 365 Safe Links URL that you want to decode to original URL")
  
    
    

    try {   
        # Decode URL using UrlDecode from System.Web.HttpUtility
        $decodedURL = [System.Web.HttpUtility]::UrlDecode($encodedURL)
    
    
        #$decodedURL = (($decodedURL -Split "url=")[1] -split "&data=;")[0]
    
        # check if decoded URL is of SafeLinks format
        # throw System.ArgumentException if the format is not supported
        if ($decodedURL -match ".safelinks.protection.outlook.com\/.*\?url=.+&data=") {
            $decodedURL = (($decodedURL -Split "/?url=")[1] -Split "&data=")[0]
        }
        elseif ($decodedURL -match ".safelinks.protection.outlook.com\/.*\?url=.+&amp;data=") {
            $decodedURL = (($decodedURL -Split "/?url=")[1] -Split "&amp;data=")[0]
        }
        else { throw  New-Object System.ArgumentException "$encodedURL is not in the correct Safe Links format", "encodedURL" }
    }
    
    catch [System.ArgumentException] {
        Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Decoding URL" -Description "Couldn't decode and parse URL: $encodedURL"
        Write-Host "Couldn't decode and parse URL: $encodedURL"
        $decodedURL = $null
        Read-Key
    }
    catch {
        Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Decoding URL" -Description "Unhandled error! Input URL: $encodedURL, Exception message: $($PSItem.Exception.Message)"
        Write-Host "Unhandled error! Input URL: $encodedURL, Exception message: $PSItem.Exception.Message"
        $decodedURL = $null
        Read-Key
    }

    # Log at the console and logging file the decoded URL
    Write-Host "The decoded URL is:" -ForegroundColor Green
    Write-Host $decodedURL
    Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Decoding URL" -Description "Decoded and Parse URL is: $decodedURL"
    Read-Key
    $urlHashTabel = @{
        encodedURL = $encodedURL
        decodedURL = $decodedURL 
    }

    #Cast HashTabel into PSCustomObject and add it to the List collection
    $null = $ListOfOriginalAndDecodedUrls.Add([PSCustomObject]$urlHashTabel)
    
    # Ask if any new URL needs to be decoded
    Clear-Host
    Write-Host "Do you need a new URL to be decoded?"
    $answer = Get-Choice "Yes", "No"
    if ($answer -eq 'y') {
        $decode = $true 
    }
    elseif ($answer -eq 'n') {
        $decode = $false 
    }

}


#region CreateHtmlReport

try {
    

    #Create the collection of sections of HTML
    $TheObjectToConvertToHTML = New-Object -TypeName "System.Collections.ArrayList"
    for ($i = 0; $i -lt $ListOfOriginalAndDecodedUrls.Count; $i++) {
        if ($null -eq $ListOfOriginalAndDecodedUrls[$i].decodedURL) {
            [string]$SectionTitle = "Decode Safe Links URL - $($i+1)"
            [string]$Description = "$encodedURL is not in the correct Safe Links format"
            [PSCustomObject]$ListOfOriginalAndDecodedUrlsHtml = New-ObjectForHTMLReport -SectionTitle $SectionTitle -SectionTitleColor "Red" -Description $Description -DataType "String" -EffectiveDataString " "
            $null = $TheObjectToConvertToHTML.Add($ListOfOriginalAndDecodedUrlsHtml)
        }
        else {
            [string]$SectionTitle = "Decode Safe Links URL - $($i+1)"
            [string]$Description = "The encoded Microsoft Defender for Office 365 Safe Links URL is decoded to show the original URL"
            [PSCustomObject]$ListOfOriginalAndDecodedUrlsHtml = New-ObjectForHTMLReport -SectionTitle $SectionTitle -SectionTitleColor "Green" -Description $Description -DataType "CustomObject" -EffectiveDataArrayList  $ListOfOriginalAndDecodedUrls[$i] -TableType "List"
            $null = $TheObjectToConvertToHTML.Add($ListOfOriginalAndDecodedUrlsHtml)
        }

    }

    #Build HTML report out of the previous HTML sections
    [string]$FilePath = $ExportPath + "\DecodeSafeLinksUrl.html"
    Export-ReportToHTML -FilePath $FilePath -PageTitle "Microsoft Defender for Office 365 Safe Links Decoder" -ReportTitle "Microsoft Defender for Office 365 Safe Links Decoder" -TheObjectToConvertToHTML $TheObjectToConvertToHTML

    Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Generate HTML Report" -Description "Success"
}
catch {
    Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Generate HTML Report" -Description "Error: $($PSItem.Exception.Message)"
    
}
#Ask end-user for opening the HTMl report
$OpenHTMLfile = Read-Host "Do you wish to open HTML report file now?`nType Y(Yes) to open or N(No) to exit!"
if ($OpenHTMLfile.ToLower() -like "*y*") {
    Write-Host "Opening report...." -ForegroundColor Cyan
    Start-Process $FilePath
}
#endregion ResultReport
   
# Print location where the data was exported
Write-Host "`nOutput was exported in the following location: $ExportPath" -ForegroundColor Yellow 
Read-Key


# Create CSV
try {
    $ListOfOriginalAndDecodedUrls | Export-Csv -Path "$ExportPath\DecodeSafeLinksUrl.csv" -NoTypeInformation
    Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Generate CSV Report" -Description "Success"
}
catch {
    Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Generate CSV Report" -Description "Error: $($PSItem.Exception.Message)"
}

# return to main menu
Write-Log -function "Start-AP_DecodeSafeLinksURL" -step  "Load Start-O365Troubleshooters Menu" -Description "Success"
Write-Host "The script will return to main menu."
Read-Key
Start-O365TroubleshootersMenu