TeamsBot.psm1



function Send-TeamsBotMessage () {
<#
 .Synopsis
  Send messages to a Teams Channel using Powershell!
 
 .Description
  This module allows you to send messages to Teams channels using the Webhooks Feature of Microsoft teams.
  It supports sending customized cards for more advanced scenarios.
 
    
                 
  .Parameter Message
  The message to be sent to the Teams channel
  Some markdown features are possible, see here:
  https://support.microsoft.com/en-us/office/use-markdown-formatting-in-teams-4d10bd65-55e2-4b2d-a1f3-2bebdcd2c772
     
  .Parameter Title
  A title to be included with the message
     
  .Parameter AppName
  Optionally include the app name and make it clickiable using markdown
     
  .Parameter SubTitle
  Optionally include a Subtitle which will appear bolded
 
  .Parameter ActionButtonTitle
  Optionally include a button with this title
    
  .Parameter ActionButtonLink
  Link for the button
   
     
  .Parameter Card
  For more advanced scenarios, a custom card object can be created and then passed with this parameters
  See $GitHubLink for more information
 
  .Parameter WebhookURL
  The WebhookURL to send the message to.
  The Url can also be persisted using Set-TeamsBotWebhookUrl or specified using Environment variable TeamsBot_WebHookUrl
 
 .Example
   # Preconfigure the WebhookUrl
   Set-TeamsBotWebhookUrl -WebhookURL 'https://url'
 
 .Example
   # Send a basic message
   Send-TeamsBotMessage -Message "Hello" -Title "My Title" -WebhookUrl
 
 .Example
   # Send a basic message including the WebhookUrl inline
   Send-TeamsBotMessage -Message "Hello" -Title "My Title" -WebhookUrl 'https://url'
 
 .Example
   # Send a basic message and include an action button
   Send-TeamsBotMessage -Message "Hello" -Title "My Title" -ActionButtonTitle "View site" -ActionButtonLink "https://bing.com"
 
 .Example
   # Use a customized card and send the message
    $SampleCard=New-TeamsBotCard
    $SampleCard.AddTitle("Test Title")
    $SampleCard.AddAppName("[Created with TeamBot Powershell module]($GitHubRepo)")
    $SampleCard.AddSubTitle("Test SubTitle")
    $SampleCard.AddTextBlock(@"
 
    *This is the main textblock which supports Markdown*
 
    - section 1
    - section 2
    - section 3
 
"@
    )
    $SampleCard.AddAction("Action 1","https://bing.com")
    $SampleCard.AddAction("Action 2","https://bing.com")
 
    Send-TeamsBotMessage -Card $SampleCard
 
#>

 param(

    [Parameter(Mandatory = $true, ParameterSetName = 'Directmessage')]
                
    [String]$Message,

    [Parameter(Mandatory = $true, ParameterSetName = 'Directmessage')] 
    [String]$Title,

    [Parameter(Mandatory = $false, ParameterSetName = 'Directmessage')] 
    [String]$AppName,

    [Parameter(Mandatory = $false, ParameterSetName = 'Directmessage')] 
    [String]$SubTitle,
    
    [Parameter(Mandatory = $false, ParameterSetName = 'Directmessage')]
    [Parameter(Mandatory = $false, ParameterSetName = 'IncludeAction')] 
    [String]$ActionButtonTitle="View Details",

    [Parameter(Mandatory = $true, ParameterSetName = 'IncludeAction')] 
    [Parameter(Mandatory = $false, ParameterSetName = 'Directmessage')] 
    [String]$ActionButtonLink,

    [Parameter(Mandatory = $true, ParameterSetName = 'UsingCard')] 
    [PsCustomObject]$Card,

    [Parameter(Mandatory = $false)] 
    [String]$WebhookURL,

    [Parameter(Mandatory = $false)] 
    [switch]$WhatIf
    
  )




  if ($Message) {
  
        # Lets use the default template and card setup

        Write-Verbose -Message "Using Default template"

        $DefaultCard=New-TeamsBotCard
        $DefaultCard.AddTitle($Title)
        
        if ($AppName -ne $null) { $DefaultCard.AddAppName($AppName)}
        if ($SubTitle -ne $null) { $DefaultCard.AddSubTitle($SubTitle)}                                                                                                                                                                   
                                                                                                                            
        $DefaultCard.AddTextBlock($Message)
        
        if ($ActionButtonTitle -ne $null -and $ActionButtonLink ) { 
                $DefaultCard.AddAction($ActionButtonTitle,$ActionButtonLink) 
        }                                                                                                                                                 
            
        try {
            $UseThisCard = $DefaultCard.GetCard()
        } catch {
            Write-Error "The card could not be rendered, check the template file $CustomTemplatePath -or if you suspect a bug, please file an issue at $GitHubRepo"
        }
  }

  if ($Card) {

    Write-Verbose -Message "Using a pre created Card"

    # This will take in a Card object directly and use it.

    try {
        $UseThisCard = $Card.GetCard()
    } catch {
        Write-Error "The card could not be rendered, for assistance or to file an issue, please visit $GitHubRepo"
    }


  }

  if ($WebhookURL) {
    
    Write-Verbose -Message "Using WebhooUrl from command line parameter"


  } else {
    # If webhook was not specified then
    # check for other sources
    Write-Verbose -Message "Obtaining configured WebHookUrl"
    $WebHookURL = Get-TeamsBotWebhookUrl
  }


  # If we got this far, lets send the message

  # Prepare the complete payload, and convert to JSON format
  $jsonPayload=@{
        type="message"
        attachments=@(@{
              contentType="application/vnd.microsoft.card.adaptive"
              contentUrl="https://github.com/luisfeliz79/TeamBotPowerShellModule"
              content=$UseThisCard
            })
  } | ConvertTo-Json -Depth 99


  if ($jsonPayload -ne $null) {
    #Write-Verbose "Payload:"
    #Write-Verbose $jsonPayload

    if ($WhatIf) {
        Write-Host $jsonPayload
        Write-warning "WhatIf: I would had sent the message with the payload above"

     } else {
        Write-Verbose "Sending message...."        
        $response=Invoke-RestMethod -Method Post -Uri $WebHookURL -ContentType 'application/json' -Body $jsonPayload -UserAgent "TeamBotPowerShellModule/$Version"    
        Write-Verbose ($response | ConvertTo-Json -Depth 99)
    }
  }




}

function New-TeamsBotCard() {

<#
 .Synopsis
  Functions to create an Adaptive card. for Help see "https://github.com/luisfeliz79/TeamsBotPowerShellModule"
  Some markdown features are possible, see here:
  https://support.microsoft.com/en-us/office/use-markdown-formatting-in-teams-4d10bd65-55e2-4b2d-a1f3-2bebdcd2c772
 
 .Example
   # Use a customized card and send the message
    $SampleCard=New-TeamsBotCard
    $SampleCard.AddTitle("Test Title")
    $SampleCard.AddAppName("[Created with TeamBot Powershell module]($GitHubRepo)")
    $SampleCard.AddSubTitle("Test SubTitle")
    $SampleCard.AddTextBlock(@"
 
    *This is the main textblock which supports Markdown*
 
    - section 1
    - section 2
    - section 3
 
"@
    )
    $SampleCard.AddAction("Action 1","https://bing.com")
    $SampleCard.AddAction("Action 2","https://bing.com")
 
    Send-TeamsBotMessage -Card $SampleCard
#>



# Define some functions for this object type
$AddTextBlock={
param ([string]$value)
    $This.body+=( @{
        type="TextBlock"
        text=$value
        isSubtle="true"
        wrap="true"
    } )
}

$AddSubTitle={
param ([string]$value)
    $This.body+=( @{
        type="TextBlock"
        text=$value
        isSubtle="true"
        wrap="false"
        weight='Bolder'
    } )
}

$AddTitle={
param ([string]$value)
    $This.body+=( @{
        type="TextBlock"
        text=$value
        isSubtle="true"
        wrap="false"
        size='Large'
        weight='Bolder'
    } )
}

$AddAppName={
param ([string]$value)
    $This.body+=( @{
        type="TextBlock"
        text=$value
        isSubtle="true"
        color='Accent'
        weight='Bolder'
        size='Small'
        spacing='None'
    } )
}

$AddCustomBodyPart={
param ($value)
    $This.body+=( $value )
}



$AddAction={
param ([string]$value1,[string]$value2)
    $This.actions+=( 
    @{
      type='Action.OpenUrl'
      title=$value1
      url=$value2
    }
    )
}

$GetCard={
    return $This
}

# Create the high level object
$NewTeamsBotCard=[PsCustomObject]@{
        '$schema'="http://adaptivecards.io/schemas/adaptive-card.json"
        type="AdaptiveCard"
        version='1.4'
        body=@()
        actions= @()
    }
# Add functions
$NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddTextBlock -Value $AddTextBlock -Force
$NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddSubTitle -Value $AddSubTitle -Force
$NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddTitle -Value $AddTitle -Force
$NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddAppName -Value $AddAppName -Force
$NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddAction -Value $AddAction -Force
$NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name GetCard -Value $GetCard -Force
$NewTeamsBotCard | Add-member -MemberType ScriptMethod -Name AddCustomBodyPart -Value $AddCustomBodyPart -Force


return $NewTeamsBotCard 

 
}
function Set-TeamsBotWebhookUrl () {
<#
 .Synopsis
  Persists the WebHookUrl securely to an encrypted file - $HOME/TeamsBotEncryptedStorage.enc
  After this step has been completed, the WebHookUrl does not have to specified on Send-TeamsBotMessage commands
#>

 param(
    [Parameter(Mandatory = $true)]
    [String]$WebhookURL
  )

  try {
    Write-Verbose  "Saving WebhookURL as a SecureString to $HOME/TeamsBotEncryptedStorage.enc ..."
    $WebhookURL| ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "$HOME/TeamsBotEncryptedStorage.enc" -ErrorAction Stop
  } catch {
    Write-Error "Unable to save WebhookURL To file $HOME/TeamsBotEncryptedStorage.enc"
  }

}
function Clear-TeamsBotWebhookUrl () {
<#
 .Synopsis
  Clears the WebHookUrl by deleting file $HOME/TeamsBotEncryptedStorage.enc
  
#>

   try {
    Write-Verbose  "Removing file $HOME/TeamsBotEncryptedStorage.enc ..."
    Remove-item -Path "$HOME/TeamsBotEncryptedStorage.enc" 
  } catch {
    Write-Error "Unable to remove file $HOME/TeamsBotEncryptedStorage.enc"
  }
}
function Get-TeamsBotWebhookUrl () {

<#
 .Synopsis
  Gets the WebHookUrl either from Environment variable TeamsBot_WebHookUrl (first) or if it exists, from $HOME/TeamsBotEncryptedStorage.enc (second)
#>


# This function will try several methods to obtain the WebhookURL

# First try checking for an Environment variable


    if ($Env:TeamsBot_WeBHookURL) {

        Write-Verbose "Using WebhookUrl found in TeamsBot_WEBHookURL environment variable"
        return $Env:TeamsBot_WebHookURL

    }

    if ((Test-Path -Path $HOME/TeamsBotEncryptedStorage.enc) -eq $true) {

        Write-Verbose "Using WebHookURL found in $HOME/TeamsBotEncryptedStorage.enc"

        try {

            $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR((Get-Content -Path "$HOME/TeamsBotEncryptedStorage.enc" | ConvertTo-SecureString))
            $URL=[System.Runtime.InteropServices.Marshal]::PtrToStringUni($BSTR)
            return $URL
        } catch {
            Write-Error "Could not read from $HOME/TeamsBotEncryptedStorage.enc"
            Exit
        }

    }

    Write-error "WebhookURL has not been configured, use Set-TeamsBotWebhookUrl, or environment variable TeamsBot_WEBHookURL"
    break
}

$GitHubRepo="https://github.com/luisfeliz79/TeamsBotPowerShellModule"
$Version="1.0.0"

# Export-ModuleMember -Cmdlet * -Function *

Export-ModuleMember -Function Send-TeamsBotMessage
Export-ModuleMember -Function Set-TeamsBotWebhookUrl
Export-ModuleMember -Function Clear-TeamsBotWebhookUrl
Export-ModuleMember -Function New-TeamsBotCard