TeamsPhoneSoftwareUpdater.psm1

<#PSScriptInfo
 
.VERSION 1.0.1
 
.GUID
cf43c4ef-a648-4f67-854f-017b7394ec3c
 
.AUTHOR
Simon Jones
 
.COMPANYNAME
SACOMS
 
.COPYRIGHT
(c) 2024 Simon Jones. All rights reserved.
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
https://github.com/SimonJonesZEE/MicrosoftTeamsPhone-SoftwareUpdater
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
Microsoft Teams Phone Software Updater
 
#>

Param()

#################################
# #
# DO NOT EDIT BELOW THIS LINE #
# #
#################################

#region - STARTUP

# This will set the session windows title bar with the name of the script
$host.ui.RawUI.WindowTitle = "Teams Phone Software Updater v1.0"
# screen wash
Clear-Host
# set the path variable
$path = "$PSScriptRoot"
# create folder structure
if ((Test-Path -Path "$path\arc") -eq $false) {
    New-Item -Path "$path\" -Name "arc" -ItemType "directory"
}
if ((Test-Path -Path "$path\data") -eq $false) {
    New-Item -Path "$path\" -Name "data" -ItemType "directory"
}
if ((Test-Path -Path "$path\logs") -eq $false) {
    New-Item -Path "$path\" -Name "logs" -ItemType "directory"
}
if ((Test-Path -Path "$path\tmp") -eq $false) {
    New-Item -Path "$path\" -Name "tmp" -ItemType "directory"
}
# start the transcript
Start-Transcript -Path "$path\logs\transcript.txt"

# Connect the Microsoft.Graph PowerShell module
Function Auth {
    try {
        Connect-MgGraph -ContextScope Process -Scopes TeamworkDevice.ReadWrite.All -ErrorAction Stop
    }
        catch {
        Exit
        ('Error - {0}' -f $_.Exception.Message) | Out-File "$path\logs\debug.txt" -append
        }
}

# This will call the Auth function when this script is run
Auth

#endregion

#region - FUNCTIONS

# This will prompt the user to select a text file which contains one or more TeamworkDeviceIds
function Select-txtFile {
        param([string]$Title="Please select the batch file",[string]$Directory=$("$path\data\"),[string]$Filter='Text Files (*.txt)|*.txt')
        [System.Reflection.Assembly]::LoadWithPartialName("PresentationFramework") | Out-Null
        $objForm = New-Object Microsoft.Win32.OpenFileDialog
        $objForm.InitialDirectory = $Directory
        $objForm.Filter = $Filter
        $objForm.Title = $Title
        $show = $objForm.ShowDialog()
    if ($show -eq $true) {
        [String]$txtFile = $objForm.FileName
        Write-Warning "The following file was selected: $($txtFile.Split("\")[$_.Length-2])"
        $continue = Read-Host "Press [C] to continue"
        $check = Get-Content $txtFile
    if (($continue.ToLower() -eq "c") -and (-not[String]::IsNullOrWhiteSpace($check))) {
        Return $txtFile
        }else {
            Write-Error 'No data in selected text file.'
        }
    }
    Return 0
}

# Archives the session files and stores them in the '$path\arc\' directory
function Archive {
    try {
        Stop-Transcript
        Get-ChildItem -Path "$path\tmp\*", "$path\logs\*" | Compress-Archive -DestinationPath "$path\arc\$($customer)-$($site)-$((Get-Date).ToString('dd-MM-yyyy')).zip" -Force -ErrorAction Stop
        Start-Transcript -Path "$path\logs\transcript.txt"
    }
        catch {
            ('Error: Archive Reports - {0}' -f $_.Exception.Message) | Out-File "$path\logs\debug.txt" -Append
        }
}

# Prompt the user to input a site name or code for reference
function Batch_File {
$confirm = Read-Host "Are you sure you want to load a new file? [Y] Yes [N] No"
    if ($confirm -eq 'Y') {
        do {
            Clear-Host
            $site = Read-Host "Enter a site name or code"
            $displaysite = '(' + $site + ')'
        }
        while ($site -like '')
        $batchfile = Select-txtFile
        if ($batchfile -ne '0' -and $null -ne $batchfile) {
            $filename = ($($batchfile.Split("\")[$_.Length-2]))
            $displayfilename = '(' + $filename + ')'
            # if a new file is selected clear variables
            $displaycounter = $null
            $displaycounter2 = $null
            $ids = $null
            $flag = $null
            $flag2 = $null
            Remove-Item "$path\tmp\*"
        }else {
            # if no file is selected clear variables
            $batchfile = $null
            $displaysite = $null
            $displayfilename = $null
            $displaycounter = $null
            $displaycounter2 = $null
            $ids = $null
            $flag = $null
            $flag2 = $null
            Remove-Item "$path\tmp\*"
        }
    Options_Menu_GUI
    }
}

# Clear the debug.txt file
function Clear_debug {
    if(Test-Path -Path "$path\logs\debug.txt" -PathType Leaf) {
        Remove-Item "$path\logs\debug.txt"
    }
}

# Verify TeamworkDeviceId's against the batch file and export data to a Csv file so it can be imported for computation and user analysis
function Analyze_file {
    if ($null -ne $batchfile -and (Test-Path -LiteralPath "$path\tmp\did.csv") -eq $false) {
        $targetid = Get-Content "$batchfile"
        $userarrayq = $targetid | Measure-Object
        $file = $userarrayq.count
        $i = 0
        try {
            foreach ($id in $targetid) {
                $percentcomplete = ($i / $file) * 100; $i++
                Write-Progress -Activity ('Analyzing TeamworkDeviceId: ' + $id) -Status ('file ' + $i + ' of ' + $file) -PercentComplete $percentcomplete
                $hs = Get-MgBetaTeamworkDevice -TeamworkDeviceId $id -ErrorAction Stop | ForEach-Object {$_.HealthStatus}
                $id = Get-MgBetaTeamworkDevice -TeamworkDeviceId $id -ErrorAction Stop | ForEach-Object {$_.Id}
                $dn = Get-MgBetaTeamworkDevice -TeamworkDeviceId $id -ErrorAction Stop | ForEach-Object {$_.CurrentUser.DisplayName}
                $sw = Get-MgBetaTeamworkDeviceHealth -TeamworkDeviceId $id -ErrorAction Stop
                $fw = $sw.softwareupdatehealth.FirmwareSoftwareUpdateStatus
                $cp = $sw.softwareupdatehealth.CompanyPortalSoftwareUpdateStatus
                $tm = $sw.softwareupdatehealth.TeamsClientSoftwareUpdateStatus
                # create and add data to did
                $params = [ordered] @{
                    "HealthStatus" = $hs | Where-Object {$fw.SoftwareFreshness -ne 'latest'}
                    "Id" = $id
                    "DisplayName" = $dn
                    "SoftwareType" = 'FirmwareUpdate'
                    "Status" = ''
                    "SID" = ''
                    "AvailableVersion" = $fw.AvailableVersion
                    "CurrentVersion" = $fw.CurrentVersion
                    "SoftwareFreshness" = $fw.SoftwareFreshness
                    "Sync" = ''
                }
                $newrow = New-Object PSObject -Property $params
                $importtable += $newrow | Export-Csv "$path\tmp\did.csv" -Append -NoTypeInformation
                # add data to did
                $params = [ordered] @{
                    "HealthStatus" = $hs | Where-Object {$cp.SoftwareFreshness -ne 'latest'}
                    "Id" = $id
                    "DisplayName" = $dn
                    "SoftwareType" = 'CompanyPortalUpdate'
                    "Status" = ''
                    "SID" = ''
                    "AvailableVersion" = $cp.AvailableVersion
                    "CurrentVersion" = $cp.CurrentVersion
                    "SoftwareFreshness" = $cp.SoftwareFreshness
                    "Sync" = ''
                }
                $newrow = New-Object PSObject -Property $params
                $importtable += $newrow | Export-Csv "$path\tmp\did.csv" -Append -NoTypeInformation
                # add data to did
                $params = [ordered] @{
                    "HealthStatus" = $hs | Where-Object {$tm.SoftwareFreshness -ne 'latest'}
                    "Id" = $id
                    "DisplayName" = $dn
                    "SoftwareType" = 'TeamsClientUpdate'
                    "Status" = ''
                    "SID" = ''
                    "AvailableVersion" = $tm.AvailableVersion
                    "CurrentVersion" = $tm.CurrentVersion
                    "SoftwareFreshness" = $tm.SoftwareFreshness
                    "Sync" = ''
                 }
                 $newrow = New-Object PSObject -Property $params
                 $importtable += $newrow | Export-Csv "$path\tmp\did.csv" -Append -NoTypeInformation
            }
        }
        catch {Write-Output ('No Dice: {0}' -f $id) ('Error: Analyze File - {0}' -f $_.Exception.Message) | Out-File "$path\logs\debug.txt" -Append}
    $num = @()
    $dev = @()
    $targetusers = Import-Csv "$path\tmp\did.csv"
        foreach ($user in $targetusers) {
            $num += ($user.Id | Select-Object -Unique | Where-Object {$user.HealthStatus -eq 'nonUrgent'})
            $dev += ($user.Id | Select-Object -Unique)
        }
    $counter = ($num | Select-Object -Unique).Count
    $displaycounter = '(' + $counter + ')'
    $devices = ($dev | Select-Object -Unique).Count
    $ids = '- ' + $devices + ' x device(s)'
    $flag = $false
    }

Write-Progress -Activity "Sleep" -Completed
Options_Menu_GUI
}

# Update software
function Update_software {
    if ($null -ne $batchfile -and $counter -gt 0 -and (Test-Path -LiteralPath "$path\tmp\did.csv") -eq $true) {
        $targetid = Import-Csv "$path\tmp\did.csv"
        $csv = "$path\tmp\did.csv"
        $ofile = New-Object System.IO.FileInfo $csv
    try {
        # check if did.csv file is closed before continuing
        $ostream = $ofile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
        if ($ostream) {$ostream.Close()}
        try {
            foreach ($user in $targetid | Where-Object {$_.HealthStatus -eq 'nonUrgent'}) {
                $uid = Get-MgBetaTeamworkDevice -TeamworkDeviceId $user.Id -ErrorAction Stop
                $sw = Get-MgBetaTeamworkDeviceHealth -TeamworkDeviceId $user.Id -ErrorAction Stop
                $fw = $sw.softwareupdatehealth.FirmwareSoftwareUpdateStatus
                $cp = $sw.softwareupdatehealth.CompanyPortalSoftwareUpdateStatus
                $tm = $sw.softwareupdatehealth.TeamsClientSoftwareUpdateStatus
                $ops = Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $user.Id -ErrorAction Stop | Where-Object {$_.Id -eq $user.SID}
                # handle with a SID if conditions are met
                if ($ops.Status -eq 'Queued' -or $ops.Status -eq 'InProgress') {
                    Write-Progress ('Software update ' + $ops.Status + ' on: ' + $user.DisplayName)
                    # add data to did
                    $user.HealthStatus = $uid.HealthStatus
                    $user.Status = $ops.Status
                    $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                }elseif ($ops.Status -eq 'Failed') {
                    # re-attempt firmware update
                    if ($user.SoftwareType -eq 'FirmwareUpdate') {
                        Write-Progress -Activity ('Retrying Software update on: ' + $user.DisplayName)
                        Update-MgBetaTeamworkDeviceSoftware -TeamworkDeviceId $user.Id -SoftwareType "firmware" -SoftwareVersion $user.AvailableVersion -ErrorAction Stop
                        $sid = (Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $user.Id -ErrorAction Stop | ForEach-Object {$_.Id} | Select-Object -Index '0')
                        # add data to did
                        $user.SID = $sid
                        $user.Status = 'Queued'
                        $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                    }
                    # re-attempt company portal update
                    if ($user.SoftwareType -eq 'CompanyPortalUpdate') {
                        Write-Progress -Activity ('Retrying Software update on: ' + $user.DisplayName)
                        Update-MgBetaTeamworkDeviceSoftware -TeamworkDeviceId $user.Id -SoftwareType "companyPortal" -SoftwareVersion $user.AvailableVersion -ErrorAction Stop
                        $sid = (Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $user.Id -ErrorAction Stop | ForEach-Object {$_.Id} | Select-Object -Index '0')
                        # add data to did
                        $user.SID = $sid
                        $user.Status = 'Queued'
                        $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                    }
                    # re-attempt teams update
                    if ($user.SoftwareType -eq 'TeamsClientUpdate') {
                        Write-Progress -Activity ('Retrying Software update on: ' + $user.DisplayName)
                        Update-MgBetaTeamworkDeviceSoftware -TeamworkDeviceId $user.Id -SoftwareType "teamsClient" -SoftwareVersion $user.AvailableVersion -ErrorAction Stop
                        $sid = (Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $user.Id -ErrorAction Stop | ForEach-Object {$_.Id} | Select-Object -Index '0')
                        # add data to did
                        $user.SID = $sid
                        $user.Status = 'Queued'
                        $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                    }
                }elseif ($ops.Status -eq 'Successful') {
                    Write-Progress -Activity ('Please wait...')
                    # check for step firmware from previous update
                   if ($user.SoftwareType -eq 'FirmwareUpdate' -and $user.Sync -eq $fw.CurrentVersion) {
                        # prep for step
                        if ($fw.SoftwareFreshness -eq 'updateAvailable') {
                            $user.HealthStatus = $uid.HealthStatus
                            $user.Status = ''
                            $user.SID = ''
                            $user.AvailableVersion = $fw.AvailableVersion
                            $user.CurrentVersion = $fw.CurrentVersion
                            $user.SoftwareFreshness = $fw.SoftwareFreshness
                            $user.Sync = ''
                            $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                        # clean up previous update
                        }else {
                            $user.HealthStatus = ''
                            $user.Status = $ops.Status
                            $user.SID = ''
                            $user.AvailableVersion = $fw.AvailableVersion
                            $user.CurrentVersion = $fw.CurrentVersion
                            $user.SoftwareFreshness = $fw.SoftwareFreshness
                            $user.Sync = ''
                            $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                        }
                    # wait for sync
                    }elseif ($user.SoftwareType -eq 'FirmwareUpdate' -and $user.Sync -ne $fw.CurrentVersion) {
                    $user.Status = $ops.Status
                    $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                    }
                    # check for step company portal from previous update
                     if ($user.SoftwareType -eq 'CompanyPortalUpdate' -and $user.Sync -eq $cp.CurrentVersion) {
                        # prep for step
                        if ($cp.SoftwareFreshness -eq 'updateAvailable') {
                            $user.HealthStatus = $uid.HealthStatus
                            $user.Status = ''
                            $user.SID = ''
                            $user.AvailableVersion = $cp.AvailableVersion
                            $user.CurrentVersion = $cp.CurrentVersion
                            $user.SoftwareFreshness = $cp.SoftwareFreshness
                            $user.Sync = ''
                            $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                        # clean up previous update
                        }else {
                            $user.HealthStatus = ''
                            $user.Status = $ops.Status
                            $user.SID = ''
                            $user.AvailableVersion = $cp.AvailableVersion
                            $user.CurrentVersion = $cp.CurrentVersion
                            $user.SoftwareFreshness = $cp.SoftwareFreshness
                            $user.Sync = ''
                            $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                        }
                    # wait for sync
                    }elseif ($user.SoftwareType -eq 'CompanyPortalUpdate' -and $user.Sync -ne $cp.CurrentVersion) {
                    $user.Status = $ops.Status
                    $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                    }
                    # check for step teams client from previous update
                    if ($user.SoftwareType -eq 'TeamsClientUpdate' -and $user.Sync -eq $tm.CurrentVersion) {
                        if ($tm.SoftwareFreshness -eq 'updateAvailable') {
                            $user.HealthStatus = $uid.HealthStatus
                            $user.Status = ''
                            $user.SID = ''
                            $user.AvailableVersion = $tm.AvailableVersion
                            $user.CurrentVersion = $tm.CurrentVersion
                            $user.SoftwareFreshness = $tm.SoftwareFreshness
                            $user.Sync = ''
                            $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                        # clean up previous update
                        }else {
                            $user.HealthStatus = ''
                            $user.Status = $ops.Status
                            $user.SID = ''
                            $user.AvailableVersion = $tm.AvailableVersion
                            $user.CurrentVersion = $tm.CurrentVersion
                            $user.SoftwareFreshness = $tm.SoftwareFreshness
                            $user.Sync = ''
                            $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                        }
                    # wait for sync
                    }elseif ($user.SoftwareType -eq 'TeamsClientUpdate' -and $user.Sync -ne $tm.CurrentVersion) {
                    $user.Status = $ops.Status
                    $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                    }
                        }else {
                            # check if the firmware requires an update
                            Write-Progress -Activity ('Update software on: ' + $user.DisplayName)
                            if ($null -ne $fw.AvailableVersion -and $fw.AvailableVersion -ne $fw.CurrentVersion | Where-Object {$user.SoftwareType -eq 'FirmwareUpdate'}) {
                                Update-MgBetaTeamworkDeviceSoftware -TeamworkDeviceId $user.Id -SoftwareType "firmware" -SoftwareVersion $fw.AvailableVersion -ErrorAction Stop
                                $sid = (Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $user.Id -ErrorAction Stop | ForEach-Object {$_.Id} | Select-Object -Index '0')
                                # add data to did
                                $user.SID = $sid
                                $user.SoftwareType = 'FirmwareUpdate'
                                $user.Status = 'Queued'
                                $user.AvailableVersion = $fw.AvailableVersion
                                $user.CurrentVersion = $fw.CurrentVersion
                                $user.SoftwareFreshness = $fw.SoftwareFreshness
                                $user.Sync = $fw.AvailableVersion
                                $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                            }
                            # check if the company portal requires an update
                            if ($null -ne $cp.AvailableVersion -and $cp.AvailableVersion -ne $cp.CurrentVersion | Where-Object {$user.SoftwareType -eq 'CompanyPortalUpdate'}) {
                                Update-MgBetaTeamworkDeviceSoftware -TeamworkDeviceId $user.Id -SoftwareType "companyPortal" -SoftwareVersion $cp.AvailableVersion -ErrorAction Stop
                                $sid = (Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $user.Id -ErrorAction Stop | ForEach-Object {$_.Id} | Select-Object -Index '0')
                                # add data to did
                                $user.SID = $sid
                                $user.SoftwareType = 'CompanyPortalUpdate'
                                $user.Status = 'Queued'
                                $user.AvailableVersion = $cp.AvailableVersion
                                $user.CurrentVersion = $cp.CurrentVersion
                                $user.SoftwareFreshness = $cp.SoftwareFreshness
                                $user.Sync = $cp.AvailableVersion
                                $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                            }
                            # check if the teams app requires an update
                            if ($null -ne $tm.AvailableVersion -and $tm.AvailableVersion -ne $tm.CurrentVersion | Where-Object {$user.SoftwareType -eq 'TeamsClientUpdate'}) {
                                Update-MgBetaTeamworkDeviceSoftware -TeamworkDeviceId $user.Id -SoftwareType "teamsClient" -SoftwareVersion $tm.AvailableVersion -ErrorAction Stop
                                $sid = (Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $user.Id -ErrorAction Stop | ForEach-Object {$_.Id} | Select-Object -Index '0')
                                # add data to did
                                $user.SID = $sid
                                $user.SoftwareType = 'TeamsClientUpdate'
                                $user.Status = 'Queued'
                                $user.AvailableVersion = $tm.AvailableVersion
                                $user.CurrentVersion = $tm.CurrentVersion
                                $user.SoftwareFreshness = $tm.SoftwareFreshness
                                $user.Sync = $tm.AvailableVersion
                                $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                            }
                        }
                }
        }
        catch {Write-Output ('No Dice: {0}' -f $user.DisplayName) ('Error: Update software - {0}' -f $_.Exception.Message) | Out-File "$path\logs\debug.txt" -Append}
        # re-check update software
        $targetid = Import-Csv "$path\tmp\did.csv"
        try {
            foreach ($user in $targetid | Where-Object {$_.HealthStatus -eq '' -and $_.Status -ne 'Successful'}) {
                Write-Progress -Activity ('Please wait...')
                $sw = Get-MgBetaTeamworkDeviceHealth -TeamworkDeviceId $user.Id -ErrorAction Stop
                $fw = $sw.softwareupdatehealth.FirmwareSoftwareUpdateStatus
                $cp = $sw.softwareupdatehealth.CompanyPortalSoftwareUpdateStatus
                $tm = $sw.softwareupdatehealth.TeamsClientSoftwareUpdateStatus
                if($user.SoftwareType -eq 'FirmwareUpdate' | Where-Object {$fw.SoftwareFreshness -ne 'latest'}) {
                    $user.HealthStatus = $uid.HealthStatus
                    $user.AvailableVersion = $fw.AvailableVersion
                    $user.CurrentVersion = $fw.CurrentVersion
                    $user.SoftwareFreshness = $fw.SoftwareFreshness
                    $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                }
                if($user.SoftwareType -eq 'CompanyPortalUpdate' | Where-Object {$cp.SoftwareFreshness -ne 'latest'}) {
                    $user.HealthStatus = $uid.HealthStatus
                    $user.AvailableVersion = $cp.AvailableVersion
                    $user.CurrentVersion = $cp.CurrentVersion
                    $user.SoftwareFreshness = $cp.SoftwareFreshness
                    $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                }
                if($user.SoftwareType -eq 'TeamsClientUpdate' | Where-Object {$tm.SoftwareFreshness -ne 'latest'}) {
                    $user.HealthStatus = $uid.HealthStatus
                    $user.AvailableVersion = $tm.AvailableVersion
                    $user.CurrentVersion = $tm.CurrentVersion
                    $user.SoftwareFreshness = $tm.SoftwareFreshness
                    $targetid | Export-Csv "$path\tmp\did.csv" -NoTypeInformation
                }
            }
        }
        catch {Write-Output ('No Dice: {0}' -f $user.DisplayName) ('Error: Re-check update software - {0}' -f $_.Exception.Message) | Out-File "$path\logs\debug.txt" -Append}
    $num = @()
    $targetusers = Import-Csv "$path\tmp\did.csv"
        foreach ($user in $targetusers) {
            $num += ($user.Id | Select-Object -Unique | Where-Object {$user.HealthStatus -eq 'nonUrgent'})
        }
    $counter = ($num | Select-Object -Unique).Count
    $displaycounter = '(' + $counter + ')'
    $flag = $true
    }
    catch {Write-Warning 'Please close the did.csv file and try again.'
    Pause
    }
    }
Write-Progress -Activity "Sleep" -Completed
Options_Menu_GUI
}

# Prompt the user to select a text file of one or more devices to be restarted
function Restart {
    if ($null -ne $batchfile -and $null -eq $flag2) {
        $confirm = Read-Host "Proceed with Teams Phone restart? [Y] Yes [N] No"
        Clear-Host
        if ($confirm -eq 'Y') {
            $targetid = Get-Content "$batchfile"
            $userarrayq = $targetid | Measure-Object
            $file = $userarrayq.count
            $i = 0
            try {
                foreach ($id in $targetid) {
                    $percentcomplete = ($i / $file) * 100; $i++
                    Write-Progress -Activity ('Restart on TeamworkDeviceId: ' + $id) -Status ('file ' + $i + ' of ' + $file) -PercentComplete $percentcomplete
                    $id = Get-MgBetaTeamworkDevice -TeamworkDeviceId $id -ErrorAction Stop | ForEach-Object {$_.Id}
                    $dn = Get-MgBetaTeamworkDevice -TeamworkDeviceId $id -ErrorAction Stop | ForEach-Object {$_.CurrentUser.DisplayName}
                    Restart-MgBetaTeamworkDevice -TeamworkDeviceId $id -ErrorAction Stop
                    $sid = (Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $id -ErrorAction Stop | ForEach-Object {$_.Id} | Select-Object -Index '0')
                    # add data to res
                    $params = [ordered] @{
                        "Id" = $id
                        "DisplayName" = $dn
                        "Status" = 'Queued'
                        "SID" = $sid
                    }
                    $newrow = New-Object PSObject -Property $params
                    $importtable += $newrow | Export-Csv "$path\tmp\res.csv" -Append -NoTypeInformation
                }
            }
            catch {Write-Output ('No Dice: {0}' -f $id) ('Error: Device restart - {0}' -f $_.Exception.Message) | Out-File "$path\logs\debug.txt" -Append}
            $counter2 = $file
            $displaycounter2 = '(' + $counter2 + ')'
            $flag2 = $true
        }
    }elseif ($null -ne $batchfile -and $counter2 -gt 0 -and $null -ne $flag2) {
        $targetid = Import-Csv "$path\tmp\res.csv"
        $csv2 = "$path\tmp\res.csv"
        $ofile2 = New-Object System.IO.FileInfo $csv2
         try {
            # check if did.csv file is closed before continuing
            $ostream2 = $ofile2.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
            if ($ostream2) {$ostream2.Close()}
                try {
                    foreach ($user in $targetid) {
                        $ops = Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $user.Id -ErrorAction Stop | Where-Object {$_.Id -eq $user.SID}
                        if ($ops.Status -eq 'Queued' -or $ops.Status -eq 'InProgress') {
                            Write-Progress ('Device restart ' + $ops.Status + ' on: ' + $user.DisplayName)
                            # add data to res
                            $user.Status = $ops.Status
                            $targetid | Export-Csv "$path\tmp\res.csv" -NoTypeInformation
                        }elseif ($ops.Status -eq 'Failed') {
                            Write-Progress -Activity ('Retrying Device restart on: ' + $user.DisplayName)
                            Restart-MgBetaTeamworkDevice -TeamworkDeviceId $user.Id -ErrorAction Stop
                            $sid = (Get-MgBetaTeamworkDeviceOperation -TeamworkDeviceId $user.Id -ErrorAction Stop | ForEach-Object {$_.Id} | Select-Object -Index '0')
                            # add data to res
                            $user.SID = $sid
                            $user.Status = 'Queued'
                            $targetid | Export-Csv "$path\tmp\res.csv" -NoTypeInformation
                        }elseif ($ops.Status -eq 'Successful') {
                            Write-Progress -Activity ('Please wait...')
                            # add data to res
                            $user.Status = $ops.Status
                            $user.SID = ''
                            $targetid | Export-Csv "$path\tmp\res.csv" -NoTypeInformation
                        }
                    }
                }
                catch {Write-Output ('No Dice: {0}' -f $user.DisplayName) ('Error: Verify restart - {0}' -f $_.Exception.Message) | Out-File "$path\logs\debug.txt" -Append}
                $num = @()
                $targetusers = Import-Csv "$path\tmp\res.csv"
                foreach ($user in $targetusers) {
                    $num += ($user.Id | Select-Object -Unique | Where-Object {$user.Status -ne 'Successful'})
                }
                $counter2 = ($num | Select-Object -Unique).Count
                $displaycounter2 = '(' + $counter2 + ')'
        }
        catch {Write-Warning 'Please close the res.csv file and try again.'
        Pause
        }
    }
Write-Progress -Activity "Sleep" -Completed
Options_Menu_GUI
}

# Remove session files on exit
function Quit {
    Stop-Transcript
    Disconnect-MgGraph
    Remove-Item "$path\tmp\*", "$path\logs\*"
}

#endregion

#region - SUB-FUNCTIONS

# User selects option A on the GUI which calls a function
function Option_1 {
Clear-Host
Archive
}

# User selects option B on the GUI which calls a function
function Option_2 {
Clear-Host
Clear_debug
}

# User selects option C on the GUI which calls a function
function Option_3 {
Clear-Host
Batch_file
}

# User selects option 1 on the GUI which calls a function
function Option_4 {
Clear-Host
Analyze_file
}

# User selects option 2 on the GUI which calls a function
function Option_5 {
Clear-Host
Update_software
}

# User selects option R on the GUI which calls a function
function Option_6 {
Clear-Host
Restart
}

# User selects option Q on the GUI which calls a function
function Option_Q {
Clear-Host
Quit
}

function Receive_Output_Red {
    process {Write-Host $_ -ForegroundColor Red}
}
function Receive_Output_Green {
    process {Write-Host $_ -ForegroundColor Green}
}

#endregion

#region - MENU GUI

function Options_Menu_GUI {
$customer = Get-MgOrganization | ForEach-Object DisplayName
do
{
Clear-Host
    Write-Host ''
    Write-Host "$customer $displaysite".ToUpper()
    Write-Host ''
    Write-Host ' Choose an option' -ForegroundColor Yellow
    Write-Host ''
    Write-Host ' 1. Archive'
    Write-Host ''
    Write-Host ' 2. Clear debug'
    Write-Host ''
    Write-Host " 3. Select file $displayfilename"
    Write-Host ''
    Write-Host " 4. Analyze file $ids"
    Write-Host ''
    if ($counter -gt 0 -and $flag -eq $false) {
    Write-Host ' 5. Update software ' -NoNewLine
    Write-OutPut $displaycounter | Receive_Output_Red
    }elseif ($counter -gt 0 -and $flag -eq $true) {
    Write-Host ' 5. Verify software ' -NoNewLine
    Write-OutPut $displaycounter | Receive_Output_Red
    }elseif ($counter -eq 0) {
    Write-Host ' 5. Update software ' -NoNewLine
    Write-OutPut $displaycounter | Receive_Output_Green
    }else {
    Write-Host ' 5. Update software'
    }
    Write-Host ''
    if ($counter2 -gt 0 -and $flag2 -eq $false) {
    Write-Host ' 6. Device restart ' -NoNewLine
    Write-OutPut $displaycounter2 | Receive_Output_Red
    }elseif ($counter2 -gt 0 -and $flag2 -eq $true) {
    Write-Host ' 6. Verify restart ' -NoNewLine
    Write-OutPut $displaycounter2 | Receive_Output_Red
    }elseif ($counter2 -eq 0) {
    Write-Host ' 6. Device restart ' -NoNewLine
    Write-OutPut $displaycounter2 | Receive_Output_Green
    }else {
    Write-Host ' 6. Device restart'
    }
    Write-Host ''
    Write-Host ' Q. Quit'
    Write-Host ''
    $Menu = Read-Host -Prompt ' (1-6 or Q to Quit)'

    Switch ($Menu) {
            1
        {
            Option_1
        }
            2
        {
            Option_2
        }
            3
        {
            Option_3
        }
            4
        {
            Option_4
        }
            5
        {
            Option_5
        }
            6
        {
            Option_6
        }
            Q
        {
            Option_Q
            Clear-Host
            Exit
        }
    }
}
    until ($Menu -eq 'q')
}
Options_Menu_GUI

#endregion