> ## Documentation Index
> Fetch the complete documentation index at: https://www.thetnaing.com/llms.txt
> Use this file to discover all available pages before exploring further.

# PowerShell Scripts

Some sample PowerShell Scripts I used to automate and scale operations.\\

**Brief Explanation & Intent**

**What it does**:\
Connects to Microsoft Teams and exports detailed voice/phone configuration for users. It’s smart — if you provide `TeamsPhoneUserList.csv` with a `userPrincipalName` column, it only checks those users. If that file isn’t there, it dumps the entire tenant.

**Intent / Why you’d run this**:

1. **Migration tracking** — See who’s still on-prem vs Teams-only via `HostingProvider` and `InterpretedUserType`.
2. **License audits** — Find users with Phone System licenses `AssignedPlan` but no `LineURI` = wasted money.
3. **Troubleshooting** — One CSV with `LineURI`, `DialPlan`, `OnlineVoiceRoutingPolicy`, `IsSipEnabled` for helpdesk.
4. **Number inventory** — Full list of DIDs assigned in `LineURI` for carrier porting or cleanup.
5. **Compliance reporting** — Track `WhenChanged`, `SoftDeletionTimeStamp` for leavers and change control.

```text theme={null}
<#
.SYNOPSIS
    Teams Phone System User Audit & Export
    
.DESCRIPTION
    Pulls key Teams Voice configuration for users and exports to CSV.
    If an input CSV with 'userPrincipalName' exists, it processes only those users.
    If no input file, it exports all CsOnlineUsers in the tenant.
    
    Intent: Audit, migrate, troubleshoot, and report on Teams Phone setup.
    Use for license cleanup, migration tracking, number inventory, and helpdesk lookups.

.OUTPUTS
    CSV with DisplayName, UserPrincipalName, LineURI, HostingProvider, OnlineVoiceRoutingPolicy,
    DialPlan, Alias, AccountEnabled, AssignedPlan, Identity, InterpretedUserType, IsSipEnabled,
    OnPremEnterpriseVoiceEnabled, OnPremSIPEnabled, LastSyncTimeStamp, WhenCreated, WhenChanged,
    SoftDeletionTimeStamp
#>

# 1. Connect to Teams
Connect-MicrosoftTeams

# 2. Set file paths
$InputFile = "C:\Users\108959\Downloads\TeamsPhoneUserList.csv"  # Leave as-is to use targeted list, or rename/delete to run full tenant
$Timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$OutputFile = "$HOME\Downloads\TeamsPhoneAudit_$Timestamp.csv"

# 3. Define attributes to collect
$Properties = @(
    'DisplayName','UserPrincipalName','LineURI','HostingProvider','OnlineVoiceRoutingPolicy',
    'DialPlan','Alias','AccountEnabled','AssignedPlan','Identity','InterpretedUserType',
    'IsSipEnabled','OnPremEnterpriseVoiceEnabled','OnPremSIPEnabled','LastSyncTimeStamp',
    'WhenCreated','WhenChanged','SoftDeletionTimeStamp'
)

# 4. Get users - targeted or full tenant
if (Test-Path $InputFile) {
    Write-Host "Input file found. Running targeted export for users in: $InputFile" -ForegroundColor Cyan
    $Users = Import-Csv -Path $InputFile
    $Report = foreach ($User in $Users) {
        Write-Host "Processing $($User.userPrincipalName)"
        try {
            Get-CsOnlineUser -Identity $User.userPrincipalName -ErrorAction Stop | Select-Object $Properties
        }
        catch {
            Write-Warning "Failed to get $($User.userPrincipalName): $_"
        }
    }
}
else {
    Write-Host "No input file found. Running full tenant export. This may take a while..." -ForegroundColor Yellow
    $Report = Get-CsOnlineUser -ResultSize Unlimited | Select-Object $Properties
}

# 5. Export + summary
$Report | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Host "`nExport complete: $OutputFile" -ForegroundColor Green
Write-Host "Total records exported: $($Report.Count)" -ForegroundColor Green
```

**Brief Explanation & Intent**\
\
This is your "one-click Teams Phone onboarding". Feed it lists of users → AD gets updated, licenses assigned, numbers enabled, policies applied, and you get an email proof with logs.

```text theme={null}
<#
.SYNOPSIS
    End-to-End Teams Phone Provisioning for M365
    
.DESCRIPTION
    1. Updates AD OfficePhone from CSV
    2. Sets UsageLocation + assigns licenses via Microsoft Graph
    3. Enables Teams Phone, assigns LineURI, Voicemail, Routing Policy, Dial Plan
    4. Exports results + emails report with transcript
    
    Intent: Bulk onboard users to Teams Phone System. Use for new hires, migrations, 
    or site rollouts. Replaces legacy MSOnline + SkypeOnlineConnector modules.

.PREREQUISITES
    Install-Module Microsoft.Graph -Scope CurrentUser
    Install-Module MicrosoftTeams -Scope CurrentUser
    Install-Module ActiveDirectory -Scope CurrentUser
#>

# ==================== CONFIG ====================
$TranscriptPath = "C:\Projects\SLG\EV-enabled\info-output_$(Get-Date -f yyyyMMdd_HHmm).txt"
$ADPhoneCSV     = "C:\Users\0001\Downloads\code.csv"                    # Columns: name,OfficePhone
$LicenseCSV     = "C:\Projects\Taylor\users-licenses.csv"               # Columns: UserPrincipalName,usagelocation,SKU
$VoiceCSV       = "C:\Projects\SLG\EV-enabled\VoiceEnable.csv"          # Columns: UPN,Phone,CountryCode
$OutputCSV      = "C:\Projects\SLG\EV-enabled\PhoneEnabledUsers_$(Get-Date -f yyyyMMdd_HHmm).csv"

$RoutingPolicy  = "TaylorsVoiceRoutingPolicy"
$DialPlan       = "Taylors Dial Plan"
$DefaultCountry = "+60"  # Used if CSV doesn't have CountryCode column

$MailParams = @{
    SmtpServer   = 'smtp.office365.com'
    Port         = '587'
    UseSSL       = $true
    From         = 'voice.admin@taylors.edu.my'
    To           = 'thet.naing@softwareone.com', 'thetnaing@gmail.com'
    Subject      = "Teams Phone Provisioning Complete - $(Get-Date -Format g)"
    Body         = 'Provisioning run finished. See attached CSV and transcript for details.'
}

# ==================== START LOGGING ====================
Start-Transcript -Path $TranscriptPath

try {
    # ==================== CONNECT ====================
    Write-Host "Connecting to Microsoft Graph + Teams..." -ForegroundColor Cyan
    Connect-MgGraph -Scopes "User.ReadWrite.All","Organization.Read.All" -NoWelcome
    Connect-MicrosoftTeams
    
    # ==================== 1. UPDATE AD PHONE NUMBERS ====================
    if (Test-Path $ADPhoneCSV) {
        Write-Host "Updating AD OfficePhone attributes..." -ForegroundColor Yellow
        Import-Csv $ADPhoneCSV | ForEach-Object {
            try {
                Set-ADUser -Identity $_.name -OfficePhone $_.OfficePhone -ErrorAction Stop
                Write-Host "AD updated: $($_.name) -> $($_.OfficePhone)"
            }
            catch { Write-Warning "AD update failed for $($_.name): $_" }
        }
    }

    # ==================== 2. ASSIGN LICENSES + USAGE LOCATION ====================
    if (Test-Path $LicenseCSV) {
        Write-Host "Setting UsageLocation + Licenses..." -ForegroundColor Yellow
        Import-Csv $LicenseCSV | ForEach-Object {
            $upn = $_.UserPrincipalName
            try {
                # Set UsageLocation first - required for licensing
                Update-MgUser -UserId $upn -UsageLocation $_.usagelocation -ErrorAction Stop
                
                # Add license - check if already assigned
                $user = Get-MgUser -UserId $upn -Property AssignedLicenses
                if ($user.AssignedLicenses.SkuId -notcontains (Get-MgSubscribedSku | Where SkuPartNumber -eq $_.SKU).SkuId) {
                    Set-MgUserLicense -UserId $upn -AddLicenses @{SkuId = (Get-MgSubscribedSku | Where SkuPartNumber -eq $_.SKU).SkuId } -RemoveLicenses @() -ErrorAction Stop
                    Write-Host "License assigned: $upn -> $($_.SKU)"
                }
                else { Write-Host "License already present: $upn" }
            }
            catch { Write-Warning "Licensing failed for $upn : $_" }
        }
    }

    # ==================== 3. ENABLE TEAMS PHONE ====================
    if (Test-Path $VoiceCSV) {
        Write-Host "Enabling Teams Phone + Policies..." -ForegroundColor Yellow
        Import-Csv $VoiceCSV | ForEach-Object {
            $user = $_.UPN
            $countryCode = if ($_.CountryCode) { $_.CountryCode } else { $DefaultCountry }
            $telUri = "tel:$countryCode$($_.Phone)"
            
            try {
                # Enable EV + LineURI + Voicemail
                Set-CsPhoneNumberAssignment -Identity $user -PhoneNumber "$countryCode$($_.Phone)" -PhoneNumberType DirectRouting -ErrorAction Stop
                
                # Wait for provisioning - poll instead of fixed sleep
                $timeout = 120; $timer = 0
                do {
                    Start-Sleep -Seconds 5
                    $timer += 5
                    $csUser = Get-CsOnlineUser -Identity $user
                } while (-not $csUser.LineURI -and $timer -lt $timeout)
                
                if (-not $csUser.LineURI) { throw "LineURI did not provision within $timeout seconds" }
                
                # Assign policies
                Grant-CsOnlineVoiceRoutingPolicy -Identity $user -PolicyName $RoutingPolicy -ErrorAction Stop
                Grant-CsTenantDialPlan -Identity $user -PolicyName $DialPlan -ErrorAction Stop
                Write-Host "Voice enabled: $user -> $telUri"
            }
            catch { Write-Warning "Teams Phone setup failed for $user : $_" }
        }
    }

    # ==================== 4. EXPORT RESULTS ====================
    Write-Host "Exporting enabled users..." -ForegroundColor Yellow
    Get-CsOnlineUser -Filter {EnterpriseVoiceEnabled -eq $true} | 
        Select-Object DisplayName,UserPrincipalName,LineURI,OnlineVoiceRoutingPolicy,DialPlan | 
        Export-Csv -Path $OutputCSV -NoTypeInformation
    
    Write-Host "Export complete: $OutputCSV" -ForegroundColor Green

    # ==================== 5. EMAIL REPORT ====================
    $MailParams.Attachments = $OutputCSV, $TranscriptPath
    $MailParams.Credential = Get-Credential -Message "Enter SMTP credentials for $($MailParams.From)"
    Send-MailMessage @MailParams
    Write-Host "Email sent to $($MailParams.To -join ', ')" -ForegroundColor Green
}
catch {
    Write-Error "Script failed: $_"
}
finally {
    Stop-Transcript
    Disconnect-MgGraph | Out-Null
    Disconnect-MicrosoftTeams | Out-Null
}
```
