Added Files
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Cleanup Microsoft Teams Client
|
||||
|
||||
.DESCRIPTION
|
||||
Cleanup Microsoft Teams Client by deleting several local cache files
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Clear-MicrosoftTeamsClientCache.ps1
|
||||
|
||||
Cleanup Microsoft Teams Client by deleting several local cache files
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Clear-MicrosoftTeamsClientCache.ps1 -Verbose
|
||||
|
||||
Cleanup Microsoft Teams Client by deleting several local cache files, but be verbose while doing it
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Clear-MicrosoftTeamsClientCache.ps1 -WhatIf
|
||||
Cleanup Microsoft Teams Client by deleting several local cache files - Dry Run!!!
|
||||
|
||||
.NOTES
|
||||
Due to some issues, Windows is not supported at this time!
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Medium',
|
||||
SupportsShouldProcess)]
|
||||
param ()
|
||||
|
||||
if ($IsMacOS -eq $true)
|
||||
{
|
||||
$AppDataBasePath = '~/Library/Application Support/Microsoft/Teams/'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'Due to some issues, Windows is not supported at this time!'
|
||||
|
||||
exit 1
|
||||
|
||||
$AppDataBasePath = ($env:APPDATA + '\Microsoft\teams\')
|
||||
}
|
||||
|
||||
#region BoundParameters
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Verbose']).IsPresent)
|
||||
{
|
||||
$VerboseValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$VerboseValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Debug']).IsPresent)
|
||||
{
|
||||
$DebugValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$DebugValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['WhatIf']).IsPresent)
|
||||
{
|
||||
$WhatIfValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$WhatIfValue = $false
|
||||
}
|
||||
#endregion BoundParameters
|
||||
|
||||
#region
|
||||
$paramGetChildItem = @{
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
Recurse = $true
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
|
||||
$paramRemoveItem = @{
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
WhatIf = $WhatIfValue
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
Recurse = $true
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region
|
||||
if ($PSCmdlet.ShouldProcess('Microsoft Teams Client', 'Hard Kill'))
|
||||
{
|
||||
$null = (Get-Process -Name Teams -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue)
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
#endregion
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'blob_storage') @paramGetChildItem -Verbose -Debug | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem -WhatIf
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'databases') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'Cache') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'gpucache') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'IndexedDB') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName -Confirm:$false -Force -Recurse -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'Local Storage') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path ($AppDataBasePath + 'tmp') @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
Get-ChildItem -Path $AppDataBasePath -Include 'old_logs_*.txt', 'logs.txt', 'in_progress_download_metadata_store' @paramGetChildItem | ForEach-Object -Process {
|
||||
Remove-Item -Path $_.FullName @paramRemoveItem
|
||||
}
|
||||
|
||||
if (Test-Path -Path ($AppDataBasePath + 'installTime.txt'))
|
||||
{
|
||||
$InstallDateInput = (Get-Content -Path ($AppDataBasePath + 'installTime.txt'))
|
||||
$Culture = (New-Object -TypeName System.Globalization.CultureInfo -ArgumentList ('de-DE'))
|
||||
$InstallDate = (Get-Date -Date $InstallDateInput -Format ($Culture.DateTimeFormat.ShortDatePattern))
|
||||
|
||||
Write-Output -InputObject ('Latest Version of Microsoft Teams from: {0}' -f $InstallDate)
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,535 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Microsoft Teams Client customization settings via PowerShell
|
||||
|
||||
.DESCRIPTION
|
||||
Microsoft Teams Client customization settings via PowerShell
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Default_MicrosoftTeams_DesktopConfig.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Default_MicrosoftTeams_DesktopConfig.ps1 -verbose
|
||||
|
||||
.NOTES
|
||||
Refactored and extended version of Desktop-Config-Json.ps1 by eshlomo1
|
||||
|
||||
.LINK
|
||||
https://github.com/eshlomo1/MS_Teams/blob/master/Desktop-Config-Json.ps1
|
||||
|
||||
.LINK
|
||||
https://www.eshlomo.us/microsoft-teams-client-personalization-with-powershell/
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
#region DefaultSettings
|
||||
$AppPrefSetOpenAsHidden = $false
|
||||
$AppPrefSetOpenAtLogin = $false
|
||||
$AppPrefSetRegisterAsIMProvider = $true
|
||||
$AppPrefSetRunningOnClose = $false
|
||||
$NotificationWindowOnClose = $true
|
||||
$OverrideOpenAsHiddenProperty = $true
|
||||
$IsAppFirstRun = $false
|
||||
$CurrentWebLanguage = 'en-us'
|
||||
#endregion DefaultSettings
|
||||
|
||||
#region Cleanup
|
||||
$ChangedConfig = $null
|
||||
$SourceConfigFile = $null
|
||||
$Teams = $null
|
||||
#endregion Cleanup
|
||||
|
||||
#region SetConfigPath
|
||||
if (($PSVersionTable.PSEdition -eq 'Core') + ($PSVersionTable.Platform -eq 'Unix') -and ($PSVersionTable.OS -like 'Darwin*'))
|
||||
{
|
||||
# OK, macOS is supported
|
||||
$SourceConfigFile = ($Env:HOME + '/Library/Application Support/Microsoft/Teams/desktop-config.json')
|
||||
}
|
||||
elseif (($PSVersionTable.PSEdition -eq 'Core') + ($PSVersionTable.Platform -eq 'Unix') -and ($PSVersionTable.OS -like 'Linux*'))
|
||||
{
|
||||
# Sorry, Linux is not supported...
|
||||
$paramWriteError = @{
|
||||
Message = 'Sorry, Linux is not supported...'
|
||||
Exception = 'Sorry, Linux is not supported!'
|
||||
Category = 'NotImplemented'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
{
|
||||
# Windows? Really??? OK, sure this is supported
|
||||
$SourceConfigFile = ($env:userprofile + '\AppData\Roaming\Microsoft\Teams\desktop-config.json')
|
||||
}
|
||||
#endregion SetConfigPath
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if (Test-Path -Path $SourceConfigFile -ErrorAction SilentlyContinue -WarningAction Continue)
|
||||
{
|
||||
#region GetConfig
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramGetContent = @{
|
||||
Path = $SourceConfigFile
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$Teams = (Get-Content @paramGetContent | ConvertFrom-Json -ErrorAction Stop)
|
||||
|
||||
# Cleanup
|
||||
$paramGetContent = $null
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
Write-Error -Message $e.Exception.Message -ErrorAction Stop -Exception $e.Exception -TargetObject $e.CategoryInfo.TargetName
|
||||
|
||||
break
|
||||
}
|
||||
#endregion GetConfig
|
||||
|
||||
#region
|
||||
if ($Teams.appPreferenceSettings)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.openAsHidden)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.openAsHidden -ne $AppPrefSetOpenAsHidden)
|
||||
{
|
||||
Write-Verbose -Message 'Value of openAsHidden will be changed to the desired default'
|
||||
|
||||
$Teams.appPreferenceSettings.openAsHidden = $AppPrefSetOpenAsHidden
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of openAsHidden was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of openAsHidden is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter openAsHidden will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'openAsHidden'
|
||||
Value = $AppPrefSetOpenAsHidden
|
||||
}
|
||||
$null = ($Teams.appPreferenceSettings | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter openAsHidden was created with the desired default value'
|
||||
}
|
||||
|
||||
if ($Teams.appPreferenceSettings.openAtLogin)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.openAtLogin -ne $AppPrefSetOpenAtLogin)
|
||||
{
|
||||
Write-Verbose -Message 'Value of openAtLogin will be changed to the desired default'
|
||||
|
||||
$Teams.appPreferenceSettings.openAtLogin = $AppPrefSetOpenAtLogin
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of openAtLogin was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of openAtLogin is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter openAtLogin will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'openAtLogin'
|
||||
Value = $AppPrefSetOpenAtLogin
|
||||
}
|
||||
$null = ($Teams.appPreferenceSettings | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter openAtLogin was created with the desired default value'
|
||||
}
|
||||
|
||||
if (($PSVersionTable.PSEdition -eq 'Core') + ($PSVersionTable.Platform -eq 'Unix') -and ($PSVersionTable.OS -like 'Darwin*') )
|
||||
{
|
||||
Write-Verbose -Message 'The setting registerAsIMProvider is not supported on macOS...'
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.registerAsIMProvider)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.registerAsIMProvider -ne $AppPrefSetRegisterAsIMProvider)
|
||||
{
|
||||
Write-Verbose -Message 'Value of registerAsIMProvider will be changed to the desired default'
|
||||
|
||||
$Teams.appPreferenceSettings.registerAsIMProvider = $AppPrefSetRegisterAsIMProvider
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of registerAsIMProvider was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of registerAsIMProvider is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter registerAsIMProvider will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'registerAsIMProvider'
|
||||
Value = $AppPrefSetRegisterAsIMProvider
|
||||
}
|
||||
$null = ($Teams.appPreferenceSettings | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter registerAsIMProvider was created with the desired default value'
|
||||
}
|
||||
}
|
||||
|
||||
if ($Teams.appPreferenceSettings.runningOnClose)
|
||||
{
|
||||
if ($Teams.appPreferenceSettings.runningOnClose -ne $AppPrefSetRunningOnClose)
|
||||
{
|
||||
Write-Verbose -Message 'Value of runningOnClose will be changed to the desired default'
|
||||
|
||||
$Teams.appPreferenceSettings.runningOnClose = $AppPrefSetRunningOnClose
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of runningOnClose was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of runningOnClose is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter runningOnClose will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'runningOnClose'
|
||||
Value = $AppPrefSetRunningOnClose
|
||||
}
|
||||
$null = ($Teams.appPreferenceSettings | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter runningOnClose was created with the desired default value'
|
||||
}
|
||||
}
|
||||
|
||||
if ($Teams.notificationWindowOnClose)
|
||||
{
|
||||
if ($Teams.notificationWindowOnClose -ne $NotificationWindowOnClose)
|
||||
{
|
||||
Write-Verbose -Message 'Value of notificationWindowOnClose will be changed to the desired default'
|
||||
|
||||
$Teams.notificationWindowOnClose = $NotificationWindowOnClose
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of notificationWindowOnClose was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of notificationWindowOnClose is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter currentWebLanguage will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'notificationWindowOnClose'
|
||||
Value = $NotificationWindowOnClose
|
||||
}
|
||||
$null = ($Teams | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter currentWebLanguage was created with the desired default value'
|
||||
}
|
||||
|
||||
if ($Teams.overrideOpenAsHiddenProperty)
|
||||
{
|
||||
if ($Teams.overrideOpenAsHiddenProperty -ne $OverrideOpenAsHiddenProperty)
|
||||
{
|
||||
Write-Verbose -Message 'Value of overrideOpenAsHiddenProperty will be changed to the desired default'
|
||||
|
||||
$Teams.overrideOpenAsHiddenProperty = $OverrideOpenAsHiddenProperty
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of overrideOpenAsHiddenProperty was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of overrideOpenAsHiddenProperty is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter overrideOpenAsHiddenProperty will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'overrideOpenAsHiddenProperty'
|
||||
Value = $OverrideOpenAsHiddenProperty
|
||||
}
|
||||
$null = ($Teams | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter overrideOpenAsHiddenProperty was created with the desired default value'
|
||||
}
|
||||
|
||||
if ($Teams.isAppFirstRun)
|
||||
{
|
||||
if ($Teams.isAppFirstRun -ne $IsAppFirstRun)
|
||||
{
|
||||
Write-Verbose -Message 'Value of isAppFirstRun will be changed to the desired default'
|
||||
|
||||
$Teams.isAppFirstRun = $IsAppFirstRun
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of isAppFirstRun was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of isAppFirstRun is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter isAppFirstRun will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'isAppFirstRun'
|
||||
Value = $false
|
||||
}
|
||||
$null = ($Teams | Add-Member @paramAddMember)
|
||||
|
||||
# Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter isAppFirstRun was created with the desired default value'
|
||||
}
|
||||
|
||||
if ($Teams.currentWebLanguage)
|
||||
{
|
||||
if ($Teams.currentWebLanguage -ne $CurrentWebLanguage)
|
||||
{
|
||||
Write-Verbose -Message 'Value of currentWebLanguage will be changed to the desired default'
|
||||
|
||||
$Teams.currentWebLanguage = $CurrentWebLanguage
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'Value of currentWebLanguage was changed to the desired default'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'Value of currentWebLanguage is unchanged'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'The Parameter currentWebLanguage will be created with the desired default value'
|
||||
|
||||
# Splat the parameters
|
||||
$paramAddMember = @{
|
||||
MemberType = 'NoteProperty'
|
||||
Name = 'currentWebLanguage'
|
||||
Value = $CurrentWebLanguage
|
||||
}
|
||||
$null = ($Teams | Add-Member @paramAddMember)
|
||||
|
||||
#Cleanup
|
||||
$paramAddMember = $null
|
||||
|
||||
# Set the change indicator
|
||||
$ChangedConfig = $true
|
||||
|
||||
Write-Verbose -Message 'The Parameter currentWebLanguage was created with the desired default value'
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SaveNewConfig
|
||||
if ($ChangedConfig)
|
||||
{
|
||||
Write-Verbose -Message 'Changed configuration will be saved'
|
||||
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramConvertToJson = @{
|
||||
Compress = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
|
||||
$paramSetContent = @{
|
||||
Path = $SourceConfigFile
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
|
||||
$null = ($Teams | ConvertTo-Json @paramConvertToJson | Set-Content @paramSetContent)
|
||||
|
||||
# Cleanup
|
||||
$paramConvertToJson = $null
|
||||
$paramSetContent = $null
|
||||
$Teams = $null
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
Write-Error -Message $e.Exception.Message -ErrorAction Stop -Exception $e.Exception -TargetObject $e.CategoryInfo.TargetName
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
Write-Verbose -Message 'Changed configuration was saved'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message 'No changes made to the configuration'
|
||||
}
|
||||
#endregion SaveNewConfig
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'No Configuration File for Microsoft Teams was found.'
|
||||
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,65 @@
|
||||
#requires -Version 2.0 -Modules MicrosoftTeams
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get a List of external Microsoft Teams Applications
|
||||
|
||||
.DESCRIPTION
|
||||
Get a List of external Microsoft Teams Applications for the tenant.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-AllExternalTeamsApps.ps1
|
||||
|
||||
Get a List of external Microsoft Teams Applications for the tenant.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-AllExternalTeamsApps.ps1 | Select-Object -Property DisplayName, DistributionMethod
|
||||
|
||||
Get a List of external Microsoft Teams Applications for the tenant.
|
||||
|
||||
.NOTES
|
||||
You need to use the Microsoft Teams Cmdlets module
|
||||
|
||||
If you don't have, install it from the gallery:
|
||||
Install-Module -Name MicrosoftTeams
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param ()
|
||||
|
||||
<#
|
||||
Simple filter: External Apps will have the ExternalId field filled,
|
||||
where store apps (from the Microsoft Teams App Store) not.
|
||||
#>
|
||||
Get-TeamsApp | Where-Object -FilterScript {
|
||||
$_.ExternalId
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,717 @@
|
||||
#requires -Version 3.0 -Modules MicrosoftTeams
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Collects assigned phone numbers from Microsoft Teams
|
||||
|
||||
.DESCRIPTION
|
||||
This script queries Microsoft Teams for assigned numbers and displays in a formatted table with the option to export the report in several formats
|
||||
During processing LineURI's are run against a regex pattern to extract the DDI/DID and the extension to a separate column
|
||||
|
||||
This script collects Microsoft Teams objects including:
|
||||
Users, Meeting Rooms, Online Application Instances (Resource Accounts)
|
||||
|
||||
.PARAMETER OutputType
|
||||
Define the Script Output
|
||||
|
||||
Valid values are:
|
||||
CONSOLE - Dump a formatted list into the console
|
||||
HTML - Create a simple HTML report with Tables. Only here to be compatible to our older version
|
||||
XML - Create a simple Extensible Markup Language (XML) report
|
||||
YAML - Create a simple YAML Ain't Markup Language (YAML) report
|
||||
JSON - Create a simple JavaScript Object Notation (JSON) report. Handy if you need to upload the data via WebServices/APIs
|
||||
CSV - Create a simple comma-separated values (CSV) report. This is perfect for re-use within Excel, or other applications
|
||||
|
||||
If you leave it empty (this is the default), the object will be dumped to the console!
|
||||
This can become handy, if you use this script to generate the report and re-use it in the pipe or your own application
|
||||
|
||||
.PARAMETER Path
|
||||
Where to store the Report File
|
||||
|
||||
Default is 'C:\scripts\PowerShell\logs\'
|
||||
|
||||
.PARAMETER DateFormat
|
||||
Use the format for Get-Date
|
||||
|
||||
Default is 'yyyyMMdd-HHmmUTC'
|
||||
|
||||
.PARAMETER UTC
|
||||
Use ToUniversalTime for the Date Strings
|
||||
|
||||
Default is $true
|
||||
|
||||
.PARAMETER Report
|
||||
Define what to report.
|
||||
|
||||
Valid values are:
|
||||
Users - Report numbers assigned to users
|
||||
MeetingRooms - Report numbers assigned to Meetings Room accounts
|
||||
ResourceAccounts - Report numbers assigned to Applications. (Auto Attendants (AA) and/or Call Queues (CQ) are supported)
|
||||
All - All assigned numbers (all above merged into one report)
|
||||
|
||||
Default is 'All'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1
|
||||
|
||||
The Report will be dumped to the console (unformatted)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CONSOLE -Report MeetingRooms
|
||||
|
||||
Dump a formatted report for numbers assigned to Meeting Rooms into the console
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CONSOLE -Report ResourceAccounts
|
||||
|
||||
Dump a formatted report for numbers assigned to Resource Accounts into the console
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CONSOLE -Report Users
|
||||
|
||||
Dump a formatted report for numbers assigned to Resource Accounts into the console
|
||||
This will contain function users for Resource Accounts and Meeting Rooms, but they will be shown as user object!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CONSOLE -Report all
|
||||
|
||||
Dump a formatted report for every assigned number into the console
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType HTML
|
||||
|
||||
Create a simple HTML report with Tables.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType XML
|
||||
|
||||
Create a simple Extensible Markup Language (XML) report
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType YAML
|
||||
|
||||
Create a simple YAML Ain't Markup Language (YAML) report
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType JSON
|
||||
|
||||
Create a simple JavaScript Object Notation (JSON) report.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Get-TeamsAssignedNumbers.ps1 -OutputType CSV
|
||||
|
||||
Create a simple comma-separated values (CSV) report.
|
||||
|
||||
.LINK
|
||||
https://github.com/ucgeek/Get-TeamsAssignedNumbers
|
||||
|
||||
.LINK
|
||||
https://github.com/ucgeek/Get-TeamsAssignedNumbers/blob/master/LICENSE
|
||||
|
||||
.NOTES
|
||||
Based on the work off Andrew Morpeth (@ucgeek and https://ucgeek.co/)
|
||||
Licensed under the GNU General Public License v3.0 terms (by @ucgeek)
|
||||
|
||||
REQUIREMENTS:
|
||||
If you haven't already, you will need to install the MicrosoftTeams PowerShell module
|
||||
The script assumes, you are connect to the Teams/Skype for Business Online Service of Microsoft Office 365
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[AllowNull()]
|
||||
[AllowEmptyString()]
|
||||
[AllowEmptyCollection()]
|
||||
[ValidateSet('CONSOLE', 'HTML', 'XML', 'YAML', 'JSON', 'CSV', IgnoreCase = $true)]
|
||||
[Alias('ReportFormat')]
|
||||
[string]
|
||||
$OutputType = $null,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[AllowNull()]
|
||||
[AllowEmptyString()]
|
||||
[AllowEmptyCollection()]
|
||||
[string]
|
||||
$Path = 'C:\scripts\PowerShell\logs',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[AllowNull()]
|
||||
[AllowEmptyString()]
|
||||
[AllowEmptyCollection()]
|
||||
[string]
|
||||
$DateFormat = 'yyyyMMdd-HHmmUTC',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('UseUTC')]
|
||||
[switch]
|
||||
$UTC,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[AllowEmptyCollection()]
|
||||
[AllowEmptyString()]
|
||||
[AllowNull()]
|
||||
[ValidateSet('Users', 'MeetingRooms', 'ResourceAccounts', 'All', IgnoreCase = $true)]
|
||||
[Alias('ReportType')]
|
||||
[string[]]
|
||||
$Report = 'All'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region BoundParameters
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Verbose']).IsPresent)
|
||||
{
|
||||
$VerboseValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$VerboseValue = $false
|
||||
}
|
||||
|
||||
if (($PSCmdlet.MyInvocation.BoundParameters['Debug']).IsPresent)
|
||||
{
|
||||
$DebugValue = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$DebugValue = $false
|
||||
}
|
||||
#endregion BoundParameters
|
||||
|
||||
#region DateToUTC
|
||||
if (-not ($UTC))
|
||||
{
|
||||
$UTC = $true
|
||||
}
|
||||
#endregion DateToUTC
|
||||
|
||||
#region UseDateUTC
|
||||
if (($UTC -eq $true) -and ($DateFormat))
|
||||
{
|
||||
$FileName = ('MicrosoftTeamsAssignedNumbers_' + ((Get-Date).ToUniversalTime()).ToString($DateFormat))
|
||||
}
|
||||
#endregion UseDateUTC
|
||||
|
||||
#region UseDateFormat
|
||||
if ($DateFormat)
|
||||
{
|
||||
$FileName = ('MicrosoftTeamsAssignedNumbers_' + ((Get-Date).ToString($DateFormat)))
|
||||
}
|
||||
else
|
||||
{
|
||||
# This is the default
|
||||
$FileName = ('MicrosoftTeamsAssignedNumbers_' + (Get-Date -Format s).replace(':', '-'))
|
||||
}
|
||||
#endregion UseDateFormat
|
||||
|
||||
#region PathMangle
|
||||
if ($Path)
|
||||
{
|
||||
# Save to a given PATH
|
||||
$FilePath = ($Path + '\' + $FileName)
|
||||
}
|
||||
else
|
||||
{
|
||||
# Save here (where the script was started)
|
||||
$FilePath = ('.\' + $FileName)
|
||||
}
|
||||
#endregion PathMangle
|
||||
|
||||
#region Regex
|
||||
# Regex values
|
||||
$LineURIRegex = '^(?:tel:)?(?:\+)?(\d+)(?:;ext=(\d+))?(?:;([\w-]+))?$'
|
||||
#endregion Regex
|
||||
|
||||
#region ReportType
|
||||
if (-not ($Report))
|
||||
{
|
||||
$Report = 'All'
|
||||
}
|
||||
#endregion ReportType
|
||||
|
||||
# Cleanup
|
||||
$ReportData = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
#region Users
|
||||
if (($Report -eq 'Users') -or ($Report -eq 'All'))
|
||||
{
|
||||
# Get Users with LineURI
|
||||
$UsersLineURI = $null
|
||||
$paramGetCsOnlineUser = @{
|
||||
ResultSize = 30000
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
Filter = {
|
||||
(LineURI -ne $null)
|
||||
}
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$paramSelectObject = @{
|
||||
Property = 'UserPrincipalName', 'LineURI', 'DisplayName', 'FirstName', 'LastName', 'Enabled', 'SipAddress'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$UsersLineURI = (Get-CsOnlineUser @paramGetCsOnlineUser | Select-Object @paramSelectObject)
|
||||
|
||||
if ($UsersLineURI)
|
||||
{
|
||||
Write-Verbose -Message 'Processing User Numbers'
|
||||
|
||||
foreach ($ReportingItem in $UsersLineURI)
|
||||
{
|
||||
$Matches = @()
|
||||
|
||||
($ReportingItem.PhoneNumber -match $LineURIRegex | Out-Null)
|
||||
|
||||
$ReportingObject = (New-Object -TypeName System.Object)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'UserPrincipalName' -Value $ReportingItem.UserPrincipalName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'LineURI' -Value $ReportingItem.LineURI)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DDI' -Value $Matches[1])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Ext' -Value $Matches[2])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DisplayName' -Value $ReportingItem.DisplayName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'FirstName' -Value $ReportingItem.FirstName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'LastName' -Value $ReportingItem.LastName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'SipAddress' -Value $($ReportingItem.SipAddress -replace 'sip:', ''))
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $ReportingItem.Enabled)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Type' -Value 'User')
|
||||
|
||||
# Add to array
|
||||
$null = ($ReportData += $ReportingObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Users
|
||||
|
||||
#region MeetingRooms
|
||||
if (($Report -eq 'MeetingRooms') -or ($Report -eq 'All'))
|
||||
{
|
||||
# Get meeting room numbers
|
||||
$MeetingRoomLineURI = $null
|
||||
|
||||
$paramGetCsMeetingRoom = @{
|
||||
ResultSize = 10000
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
Filter = {
|
||||
LineURI -ne $null
|
||||
}
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$paramSelectObject = @{
|
||||
Property = 'UserPrincipalName', 'LineURI', 'DisplayName', 'Enabled', 'SipAddress'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$MeetingRoomLineURI = (Get-CsMeetingRoom @paramGetCsMeetingRoom | Select-Object @paramSelectObject)
|
||||
|
||||
if ($MeetingRoomLineURI)
|
||||
{
|
||||
Write-Verbose -Message 'Processing Meeting Room Numbers'
|
||||
|
||||
foreach ($ReportingItem in $MeetingRoomLineURI)
|
||||
{
|
||||
$Matches = @()
|
||||
|
||||
($ReportingItem.PhoneNumber -match $LineURIRegex | Out-Null)
|
||||
|
||||
$ReportingObject = (New-Object -TypeName System.Object)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'UserPrincipalName' -Value $ReportingItem.UserPrincipalName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'LineURI' -Value $ReportingItem.LineURI)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DDI' -Value $Matches[1])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Ext' -Value $Matches[2])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DisplayName' -Value $ReportingItem.DisplayName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'SipAddress' -Value $($ReportingItem.SipAddress -replace 'sip:', ''))
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $ReportingItem.Enabled)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Type' -Value 'Meeting Room')
|
||||
|
||||
# Remove existing User entry (Rooms have an user object as well)
|
||||
if ($ReportData.UserPrincipalName -contains $ReportingItem.UserPrincipalName)
|
||||
{
|
||||
$ReportData = ($ReportData | Where-Object -FilterScript {
|
||||
($_.UserPrincipalName -ne $ReportingItem.UserPrincipalName)
|
||||
})
|
||||
}
|
||||
|
||||
# Add to array
|
||||
$null = ($ReportData += $ReportingObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion MeetingRooms
|
||||
|
||||
#region ResourceAccounts
|
||||
if (($Report -eq 'ResourceAccounts') -or ($Report -eq 'All'))
|
||||
{
|
||||
# Get online resource accounts
|
||||
$OnlineApplicationInstanceLineURI = $null
|
||||
|
||||
$paramGetCsOnlineApplicationInstance = @{
|
||||
Force = $true
|
||||
ResultSize = 10000
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$paramSelectObject = @{
|
||||
Property = 'UserPrincipalName', 'DisplayName', 'PhoneNumber', 'ApplicationId', 'Enabled'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$OnlineApplicationInstanceLineURI = (Get-CsOnlineApplicationInstance @paramGetCsOnlineApplicationInstance | Where-Object -FilterScript {
|
||||
($_.PhoneNumber -ne $null)
|
||||
} -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | Select-Object @paramSelectObject)
|
||||
|
||||
if ($OnlineApplicationInstanceLineURI)
|
||||
{
|
||||
Write-Verbose -Message 'Processing Online Application Instances (Resource Accounts) Numbers'
|
||||
|
||||
foreach ($ReportingItem in $OnlineApplicationInstanceLineURI)
|
||||
{
|
||||
$Matches = @()
|
||||
|
||||
($ReportingItem.PhoneNumber -match $LineURIRegex | Out-Null)
|
||||
|
||||
<#
|
||||
Workaround:
|
||||
|
||||
Get-CsOnlineApplicationInstance does not return an "Enabled" and "SipAddress" field,
|
||||
so we try to re-use any existing object information
|
||||
|
||||
Will not work all the time, only if regular users are reported as well!
|
||||
#>
|
||||
if ($ReportData.UserPrincipalName -contains $ReportingItem.UserPrincipalName)
|
||||
{
|
||||
# Cleanup
|
||||
$WorkaroundInfo = $null
|
||||
|
||||
$WorkaroundInfo = ($ReportData | Where-Object -FilterScript {
|
||||
($_.UserPrincipalName -eq $ReportingItem.UserPrincipalName)
|
||||
} | Select-Object -Property 'Enabled', 'SipAddress')
|
||||
|
||||
if (($WorkaroundInfo).Enabled)
|
||||
{
|
||||
$isAppEnabled = (($WorkaroundInfo).Enabled)
|
||||
}
|
||||
else
|
||||
{
|
||||
$isAppEnabled = 'unknown'
|
||||
}
|
||||
|
||||
if (($WorkaroundInfo).SipAddress)
|
||||
{
|
||||
$isSipAddress = (($WorkaroundInfo).SipAddress)
|
||||
}
|
||||
else
|
||||
{
|
||||
$isSipAddress = 'unknown'
|
||||
}
|
||||
}
|
||||
|
||||
$ReportingObject = (New-Object -TypeName System.Object)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'UserPrincipalName' -Value $ReportingItem.UserPrincipalName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'LineURI' -Value $ReportingItem.PhoneNumber)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DDI' -Value $Matches[1])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Ext' -Value $Matches[2])
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'DisplayName' -Value $ReportingItem.DisplayName)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'SipAddress' -Value $isSipAddress)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $isAppEnabled)
|
||||
$null = ($ReportingObject | Add-Member -MemberType NoteProperty -Name 'Type' -Value $(
|
||||
if ($ReportingItem.ApplicationId -eq 'ce933385-9390-45d1-9512-c8d228074e07')
|
||||
{
|
||||
'Auto Attendant Resource Account'
|
||||
}
|
||||
elseif ($ReportingItem.ApplicationId -eq '11cd3e2e-fccb-42ad-ad00-878b93575e07')
|
||||
{
|
||||
'Call Queue Resource Account'
|
||||
}
|
||||
else
|
||||
{
|
||||
'Unknown Resource Account'
|
||||
}
|
||||
))
|
||||
|
||||
# Remove existing User entry (Apps have an user object as well)
|
||||
if ($ReportData.UserPrincipalName -contains $ReportingItem.UserPrincipalName)
|
||||
{
|
||||
$ReportData = ($ReportData | Where-Object -FilterScript {
|
||||
($_.UserPrincipalName -ne $ReportingItem.UserPrincipalName)
|
||||
})
|
||||
}
|
||||
|
||||
# Add to array
|
||||
$null = ($ReportData += $ReportingObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion ResourceAccounts
|
||||
|
||||
# Sort the Array data, based on the LineURI object
|
||||
$paramSortObject = @{
|
||||
Property = 'LineURI'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$ReportData = ($ReportData | Sort-Object @paramSortObject)
|
||||
|
||||
#region Output
|
||||
switch ($OutputType)
|
||||
{
|
||||
CSV
|
||||
{
|
||||
$FilePath = ($FilePath + '.csv')
|
||||
|
||||
$paramConvertToCsv = @{
|
||||
Delimiter = ','
|
||||
NoTypeInformation = $true
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
$PsCsv = ($ReportData | ConvertTo-Csv @paramConvertToCsv)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsCsv | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your CSV report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
JSON
|
||||
{
|
||||
$FilePath = ($FilePath + '.json')
|
||||
|
||||
$paramConvertToJson = @{
|
||||
Depth = 5
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$PsJson = @($ReportData | ConvertTo-Json @paramConvertToJson)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsJson | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your JSON report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
YAML
|
||||
{
|
||||
if (Get-Command -Name 'ConvertTo-Yaml' -ErrorAction SilentlyContinue)
|
||||
{
|
||||
$FilePath = ($FilePath + '.yml')
|
||||
|
||||
<#
|
||||
Workaround for ConvertTo-Yaml
|
||||
#>
|
||||
$paramJsonWorkaround = @{
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$ReportData = @($ReportData | ConvertTo-Json @paramJsonWorkaround | ConvertFrom-Json @paramJsonWorkaround)
|
||||
|
||||
$paramConvertToYaml = @{
|
||||
Data = $ReportData
|
||||
Force = $true
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$PsYaml = (ConvertTo-Yaml @paramConvertToYaml)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsYaml | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your YAML report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
else
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Exception = 'The ConvertTo-Yaml command was not found'
|
||||
Message = 'Please ensure, that the ''powershell-yaml'' module is installed.'
|
||||
Category = 'NotInstalled'
|
||||
RecommendedAction = 'Please use ''Install-Module -Name powershell-yaml'' to install the required module!'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
XML
|
||||
{
|
||||
$FilePath = ($FilePath + '.xml')
|
||||
|
||||
$paramConvertToXml = @{
|
||||
As = 'Stream'
|
||||
InputObject = $ReportData
|
||||
NoTypeInformation = $true
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$PsXML = (ConvertTo-Xml @paramConvertToXml)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsXML | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your XML report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
HTML
|
||||
{
|
||||
$FilePath = ($FilePath + '.html')
|
||||
|
||||
$Header = @"
|
||||
<title>Microsoft Teams assigned phone number report</title>
|
||||
<meta charset='UTF-8'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<style>
|
||||
table {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th {
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
background-color: #6495ED;
|
||||
}
|
||||
|
||||
td {
|
||||
border-width: 1px;
|
||||
padding: 3px;
|
||||
border-style: solid;
|
||||
border-color: black;
|
||||
}
|
||||
</style>
|
||||
"@
|
||||
|
||||
$htmlParams = @{
|
||||
Title = 'Microsoft Teams assigned phone number report'
|
||||
Head = $Header
|
||||
body = '<h3>Microsoft Teams assigned phone number report</h3>'
|
||||
PreContent = '<p>The following Phone numbers are assigned in Microsoft Teams:</p>'
|
||||
PostContent = '<p><i>Last updated: ' + ((Get-Date).ToUniversalTime()).ToString('HH:MM dd.MM.yyyy (UTC)') + '</i></p>'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
$PsHtml = ($ReportData | ConvertTo-Html @htmlParams)
|
||||
|
||||
$paramOutFile = @{
|
||||
FilePath = $FilePath
|
||||
Force = $true
|
||||
Append = $false
|
||||
Encoding = 'utf8'
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($PsHtml | Out-File @paramOutFile)
|
||||
|
||||
Write-Verbose -Message ('Your HTML report was saved to: {0}' -f $FilePath)
|
||||
}
|
||||
CONSOLE
|
||||
{
|
||||
$paramFormatTable = @{
|
||||
AutoSize = $true
|
||||
Property = 'UserPrincipalName', 'LineURI', 'DDI', 'Ext', 'DisplayName', 'Type'
|
||||
Verbose = $VerboseValue
|
||||
Debug = $DebugValue
|
||||
}
|
||||
($ReportData | Format-Table @paramFormatTable)
|
||||
|
||||
Write-Verbose -Message 'Formated Object was dumped'
|
||||
}
|
||||
default
|
||||
{
|
||||
$ReportData
|
||||
|
||||
Write-Verbose -Message 'Unformated Object was dumped'
|
||||
}
|
||||
}
|
||||
#endregion Output
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
# Cleanup
|
||||
$ReportData = $null
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,276 @@
|
||||
function Get-TeamsServiceNumbers
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the Phone numbers assigned to Teams/SfB Services
|
||||
|
||||
.DESCRIPTION
|
||||
Get the Phone numbers assigned to Teams/SfB Services
|
||||
Supported are AutoAttendant and/or CallQueue
|
||||
|
||||
.PARAMETER AutoAttendant
|
||||
Get the numbers assigned to AutoAttendant(s)
|
||||
|
||||
.PARAMETER CallQueue
|
||||
Get the numbers assigned to CallQueue(s)
|
||||
|
||||
.PARAMETER All
|
||||
Get all Numbers, assignee to AutoAttendant(s) and CallQueue(s)
|
||||
|
||||
.PARAMETER LeaveTel
|
||||
Normally the function dumps phone numbers with a stripped tel:
|
||||
With this switch the function will dump it with the leading tel:
|
||||
|
||||
.PARAMETER Export
|
||||
Export the result to a CSV
|
||||
|
||||
.PARAMETER Path
|
||||
Path for the CSV Export
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -All
|
||||
|
||||
Get all Services numbers, AutoAttendant(s) and CallQueue(s), and dump them to the terminal
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -All -Export -Path '.\TeamsServiceNumbers.csv'
|
||||
|
||||
Get all Services numbers, AutoAttendant(s) and CallQueue(s), and export them to the given CSV file '.\TeamsServiceNumbers.csv'
|
||||
TeamsServiceNumbers.csv is in the directory where the user is right now (and calls the function)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -All -Export -Path 'c:\temp\TeamsServiceNumbers.csv'
|
||||
|
||||
Get all Services numbers, AutoAttendant(s) and CallQueue(s), and export them to the given CSV file 'c:\temp\TeamsServiceNumbers.csv'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -All -Export
|
||||
|
||||
Get all Services numbers, AutoAttendant(s) and CallQueue(s), and export them to a CSV
|
||||
The funtion will ask for the Path to the CSV File
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -AutoAttendant
|
||||
|
||||
Get all AutoAttendant(s) Services numbers and dump them to the terminal
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -AA
|
||||
|
||||
Get all AutoAttendant(s) Services numbers and dump them to the terminal
|
||||
Same as above, but use the Alias (Shorter)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -CallQueue
|
||||
|
||||
Get all CallQueue(s) Services numbers and dump them to the terminal
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-TeamsServiceNumbers -CQ
|
||||
|
||||
Get all CallQueue(s) Services numbers and dump them to the terminal
|
||||
Same as above, but use the Alias (Shorter)
|
||||
|
||||
.NOTES
|
||||
Additional information about the function.
|
||||
#>
|
||||
|
||||
[CmdletBinding(DefaultParameterSetName = 'AllNumbers',
|
||||
ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param
|
||||
(
|
||||
[Parameter(ParameterSetName = 'AANumbers',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[Alias('AA')]
|
||||
[switch]
|
||||
$AutoAttendant = $null,
|
||||
[Parameter(ParameterSetName = 'CQNumbers',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[Alias('CQ')]
|
||||
[switch]
|
||||
$CallQueue = $null,
|
||||
[Parameter(ParameterSetName = 'AllNumbers',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[Alias('Any')]
|
||||
[switch]
|
||||
$All,
|
||||
[Parameter(ParameterSetName = '__AllParameterSets',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[switch]
|
||||
$LeaveTel = $null,
|
||||
[Parameter(ParameterSetName = '__AllParameterSets',
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[Alias('ExportCsv', 'CSV')]
|
||||
[switch]
|
||||
$Export = $false
|
||||
)
|
||||
|
||||
dynamicparam
|
||||
{
|
||||
if ($PSBoundParameters['Export'])
|
||||
{
|
||||
# The PATH parameter is only needed if -Export is given
|
||||
$PathAttribute = New-Object System.Management.Automation.ParameterAttribute
|
||||
$PathAttribute.Mandatory = $true
|
||||
$PathAttribute.HelpMessage = "Path for the CSV Export:"
|
||||
$PathAttribute.ValueFromPipeline = $true
|
||||
$PathAttribute.ValueFromPipelineByPropertyName = $true
|
||||
$PathAttribute.ParameterSetName = '__AllParameterSets'
|
||||
$attributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
|
||||
$attributeCollection.Add($PathAttribute)
|
||||
$PathParam = New-Object System.Management.Automation.RuntimeDefinedParameter('Path', [String], $attributeCollection)
|
||||
$paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
|
||||
$paramDictionary.Add('Path', $PathParam)
|
||||
$paramDictionary
|
||||
}
|
||||
}
|
||||
|
||||
begin
|
||||
{
|
||||
switch ($PsCmdlet.ParameterSetName)
|
||||
{
|
||||
'AANumbers'
|
||||
{
|
||||
$AutoAttendant = $true
|
||||
}
|
||||
'CQNumbers'
|
||||
{
|
||||
$CallQueue = $true
|
||||
}
|
||||
'AllNumbers'
|
||||
{
|
||||
$All = $true
|
||||
}
|
||||
default
|
||||
{
|
||||
$All = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($PSBoundParameters.Path)
|
||||
{
|
||||
$Path = $PSBoundParameters.Path
|
||||
}
|
||||
|
||||
$NumberReport = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if (($AutoAttendant) -or ($All))
|
||||
{
|
||||
foreach ($AA in (Get-CsAutoAttendant -ErrorAction Continue))
|
||||
{
|
||||
foreach ($AppInstance in $AA.ApplicationInstances)
|
||||
{
|
||||
$AAName = $AA.Name
|
||||
$AppPhoneNum = $null
|
||||
|
||||
if ($LeaveTel)
|
||||
{
|
||||
$AppPhoneNum = ((Get-CsOnlineApplicationInstance -Identity $AppInstance -ErrorAction Continue).PhoneNumber)
|
||||
}
|
||||
else
|
||||
{
|
||||
$AppPhoneNum = (((Get-CsOnlineApplicationInstance -Identity $AppInstance -ErrorAction Continue).PhoneNumber).replace('tel:', ''))
|
||||
}
|
||||
|
||||
Write-Verbose ('AutoAttendant ' + $AA.Name + ' has ' + $AppPhoneNum + ' assigned')
|
||||
|
||||
$NewRow = $null
|
||||
$NewRow = [PSCustomObject][ordered]@{
|
||||
Name = ($AA.Name)
|
||||
Number = ($AppPhoneNum)
|
||||
Type = 'AutoAttendant'
|
||||
}
|
||||
|
||||
$NumberReport += $newrow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (($CallQueue) -or ($All))
|
||||
{
|
||||
foreach ($CQ in (Get-CsCallQueue -ErrorAction Continue))
|
||||
{
|
||||
foreach ($AppInstance in $CQ.ApplicationInstances)
|
||||
{
|
||||
$CQName = $null
|
||||
$CQName = $CQ.Name
|
||||
|
||||
$AppPhoneNum = $null
|
||||
|
||||
if ($LeaveTel)
|
||||
{
|
||||
$AppPhoneNum = ((Get-CsOnlineApplicationInstance -Identity $AppInstance -ErrorAction Continue).PhoneNumber)
|
||||
}
|
||||
else
|
||||
{
|
||||
$AppPhoneNum = (((Get-CsOnlineApplicationInstance -Identity $AppInstance -ErrorAction Continue).PhoneNumber).replace('tel:', ''))
|
||||
}
|
||||
|
||||
Write-Verbose ('CallQueue ' + $CQ.Name + ' has ' + $AppPhoneNum + ' assigned')
|
||||
|
||||
$NewRow = $null
|
||||
$NewRow = [PSCustomObject][ordered]@{
|
||||
Name = ($CQ.Name)
|
||||
Number = ($AppPhoneNum)
|
||||
Type = 'CallQueue'
|
||||
}
|
||||
|
||||
$NumberReport += $newrow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
if (($PSBoundParameters['Export']) -or ($Path))
|
||||
{
|
||||
$NumberReport | Export-Csv -Path $Path -NoTypeInformation -Encoding UTF8 -ErrorAction Stop -WarningAction Continue
|
||||
|
||||
Write-Verbose -Message $NumberReport
|
||||
}
|
||||
else
|
||||
{
|
||||
$NumberReport
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,446 @@
|
||||
function Get-bdcMicrosoftTeamsReporting
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get a Report for all Microsoft Teams Teams
|
||||
|
||||
.DESCRIPTION
|
||||
Get a Report for all Microsoft Teams Teams
|
||||
|
||||
.PARAMETER Connect
|
||||
Executes Connect-MicrosoftTeams for you
|
||||
|
||||
.PARAMETER Disconnect
|
||||
Executes Disconnect-MicrosoftTeams for you as soon as the report is generated
|
||||
|
||||
.PARAMETER GiphyDetails
|
||||
Include Giphy Details in the report
|
||||
|
||||
.PARAMETER MemesDetails
|
||||
Include Memes Details in the report
|
||||
|
||||
.PARAMETER GuestDetails
|
||||
Include Guest Details in the report
|
||||
|
||||
.PARAMETER Detailed
|
||||
Report some more Details about the Teams.
|
||||
|
||||
.PARAMETER AllDetails
|
||||
All of the Details are reported, might be a bit verbose for some.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting
|
||||
|
||||
Get a Report for all Microsoft Teams Teams
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting | Where-Object -FilterScript {
|
||||
$_.owners -eq 0
|
||||
} | Select-Object -ExpandProperty DisplayName
|
||||
|
||||
Find all Teams without an owner.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting | Where-Object -FilterScript {
|
||||
$_.owners -eq 1
|
||||
} | Select-Object -ExpandProperty DisplayName | ForEach-Object -Process {
|
||||
Write-Warning -Message "Looks like $_ is an orphaned objects, it has no owner!" -ErrorAction Continue
|
||||
}
|
||||
|
||||
Find all Teams without an owner. Teams without an owner are bad teams...
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting | Where-Object -FilterScript {
|
||||
($_.Members -eq 0) -and ($_.Guests -eq 0)
|
||||
} | Select-Object -ExpandProperty DisplayName | ForEach-Object -Process {
|
||||
Write-Warning -Message "Looks like $_ has no members and guests!" -ErrorAction Continue
|
||||
}
|
||||
|
||||
Find Teams without members and guests, empty teams are boring and, more or less, useless
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting | Where-Object -FilterScript {
|
||||
($_.Archived -eq $true) -and ($_.ShowInTeamsSearchAndSuggestions -eq $true)
|
||||
} | Select-Object -ExpandProperty DisplayName | ForEach-Object -Process {
|
||||
Write-Warning -Message "Looks like $_ is archived but searchable!" -ErrorAction Continue
|
||||
}
|
||||
|
||||
Find archived Teams that are still searchable, might not be a bad thing...
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -Connect -Disconnect
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, invokes the Connect-MicrosoftTeams and Disconnect-MicrosoftTeams for you
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -AllDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, with all the details (very verbose)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -GiphyDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, and include Giphy Details
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -MemesDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, and include Memes Details
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -GiphyDetails -MemesDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, and include Giphy and Memes Details
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -GuestDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, and include Guest Details
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -Detailed
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, with more details then the regular report
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Get-bdcMicrosoftTeamsReporting -Detailed -GuestDetails
|
||||
|
||||
Get a Report for all Microsoft Teams Teams, with more details then the regular report and Guest Details
|
||||
|
||||
.NOTES
|
||||
Reworked function to deliver everything we need to have for our Office 365 reporting service.
|
||||
See the examples above and you will get an idea what you can do with filtering :-)
|
||||
|
||||
.LINK
|
||||
https://www.powershellgallery.com/packages/MicrosoftTeams/1.0.3
|
||||
|
||||
.LINK
|
||||
https://github.com/MicrosoftDocs/office-docs-powershell/tree/master/teams
|
||||
|
||||
.LINK
|
||||
Get-Team
|
||||
|
||||
.LINK
|
||||
Get-TeamUser
|
||||
|
||||
.LINK
|
||||
Get-TeamChannel
|
||||
|
||||
.LINK
|
||||
Connect-MicrosoftTeams
|
||||
|
||||
.LINK
|
||||
Disconnect-MicrosoftTeams
|
||||
|
||||
.LINK
|
||||
https://aka.ms/InstallModule
|
||||
|
||||
.LINK
|
||||
https://github.com/tomarbuthnot/Microsoft-Teams-PowerShell
|
||||
|
||||
.LINK
|
||||
https://opensource.org/licenses/BSD-3-Clause
|
||||
#>
|
||||
|
||||
[CmdletBinding(ConfirmImpact = 'None')]
|
||||
[OutputType([psobject])]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('DoConnect')]
|
||||
[switch]
|
||||
$Connect,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('DoDisconnect')]
|
||||
[switch]
|
||||
$Disconnect,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('IncludeGiphyDetails', 'Giphy')]
|
||||
[switch]
|
||||
$GiphyDetails,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('IncludeMemesDetails', 'Memes')]
|
||||
[switch]
|
||||
$MemesDetails,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('IncludeGuestDetails', 'Guest')]
|
||||
[switch]
|
||||
$GuestDetails,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('DetailedReport')]
|
||||
[switch]
|
||||
$Detailed,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('VerboseReport')]
|
||||
[switch]
|
||||
$AllDetails
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Connect
|
||||
if ($Connect)
|
||||
{
|
||||
# Logon
|
||||
$null = (Connect-MicrosoftTeams)
|
||||
}
|
||||
#endregion Connect
|
||||
|
||||
# Crete an empty Report variable
|
||||
$MicrosoftTeamsReport = @()
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get all Microsoft Teams Teams and loop over them
|
||||
try
|
||||
{
|
||||
Get-Team -ErrorAction Stop | ForEach-Object -Process {
|
||||
try
|
||||
{
|
||||
Write-Verbose -Message ('Generate the Report for the Microsoft Teams Team {0}' -f $_.DisplayName)
|
||||
|
||||
# Cleanup
|
||||
$TeamUserDetails = $null
|
||||
|
||||
# Get the User information for the Microsoft Teams Team and save it for reuse
|
||||
$TeamUserDetails = $null
|
||||
$TeamUserDetails = (Get-TeamUser -GroupId $_.GroupID -ErrorAction Stop)
|
||||
|
||||
# Get the Channel information for the Microsoft Teams Team
|
||||
$TeamChannelDetails = $null
|
||||
$TeamChannelDetails = ((Get-TeamChannel -GroupId $_.GroupID -ErrorAction Stop).count)
|
||||
|
||||
# Put all details into an object
|
||||
$SingleTeamReport = (New-Object -TypeName PSobject)
|
||||
|
||||
#region FillSingleTeamReport
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'DisplayName' -Value $_.DisplayName
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Description' -Value $_.Description
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Visibility' -Value $_.Visibility
|
||||
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Archived' -Value $_.Archived
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'ShowInTeamsSearchAndSuggestions' -Value $_.ShowInTeamsSearchAndSuggestions
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Channels' -Value $TeamChannelDetails
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Owners' -Value (($TeamUserDetails | Where-Object -FilterScript {
|
||||
$_.Role -like 'owner'
|
||||
}).count)
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Members' -Value (($TeamUserDetails | Where-Object -FilterScript {
|
||||
$_.Role -like 'member'
|
||||
}).count)
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Guests' -Value (($TeamUserDetails | Where-Object -FilterScript {
|
||||
$_.Role -like 'guest'
|
||||
}).count)
|
||||
|
||||
#region GiphyDetails
|
||||
if ($GiphyDetails -or $AllDetails)
|
||||
{
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowGiphy' -Value $_.AllowGiphy
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'GiphyContentRating' -Value $_.GiphyContentRating
|
||||
}
|
||||
#endregion GiphyDetails
|
||||
|
||||
#region MemesDetails
|
||||
if ($MemesDetails -or $AllDetails)
|
||||
{
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowStickersAndMemes' -Value $_.AllowStickersAndMemes
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowCustomMemes' -Value $_.AllowCustomMemes
|
||||
}
|
||||
#endregion MemesDetails
|
||||
|
||||
#region GuestDetails
|
||||
if ($GuestDetails -or $AllDetails)
|
||||
{
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowGuestCreateUpdateChannels' -Value $_.AllowGuestCreateUpdateChannels
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowGuestDeleteChannels' -Value $_.AllowGuestDeleteChannels
|
||||
}
|
||||
#endregion GuestDetails
|
||||
|
||||
#region DetailedReport
|
||||
if ($Detailed -or $AllDetails)
|
||||
{
|
||||
# Based on the idea of Tom Arbuthnot (https://github.com/tomarbuthnot/Microsoft-Teams-PowerShell)
|
||||
$DescriptionWordCount = (($_.Description | Out-String | Measure-Object -Word).words)
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'DescriptionWordCount' -Value $DescriptionWordCount
|
||||
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'DescriptionScore' -Value $(if ($DescriptionWordCount -eq 0)
|
||||
{
|
||||
'Terrible'
|
||||
}
|
||||
elseif ($DescriptionWordCount -le 2)
|
||||
{
|
||||
'Poor'
|
||||
}
|
||||
elseif ($DescriptionWordCount -le 5)
|
||||
{
|
||||
'OK'
|
||||
}
|
||||
elseif ($DescriptionWordCount -ge 6)
|
||||
{
|
||||
'Good'
|
||||
}
|
||||
else
|
||||
{
|
||||
'Unknown'
|
||||
}
|
||||
)
|
||||
|
||||
# As requested by Peter Duda
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'Classification' -Value $(if ($_.Classification)
|
||||
{
|
||||
$_.Classification
|
||||
}
|
||||
else
|
||||
{
|
||||
'None'
|
||||
}
|
||||
)
|
||||
|
||||
# New since 2020/01
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'MailNickName' -Value $(if ($_.MailNickName)
|
||||
{
|
||||
$_.MailNickName
|
||||
}
|
||||
else
|
||||
{
|
||||
'None'
|
||||
}
|
||||
)
|
||||
|
||||
# Verbose reporting
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowCreateUpdateChannels' -Value $_.AllowCreateUpdateChannels
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowDeleteChannels' -Value $_.AllowDeleteChannels
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowAddRemoveApps' -Value $_.AllowAddRemoveApps
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowCreateUpdateRemoveTabs' -Value $_.AllowCreateUpdateRemoveTabs
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowCreateUpdateRemoveConnectors' -Value $_.AllowCreateUpdateRemoveConnectors
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowUserEditMessages' -Value $_.AllowUserEditMessages
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowUserDeleteMessages' -Value $_.AllowUserDeleteMessages
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowOwnerDeleteMessages' -Value $_.AllowOwnerDeleteMessages
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowTeamMentions' -Value $_.AllowTeamMentions
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'AllowChannelMentions' -Value $_.AllowChannelMentions
|
||||
}
|
||||
#endregion DetailedReport
|
||||
|
||||
#region FinalValue
|
||||
$SingleTeamReport | Add-Member -MemberType NoteProperty -Name 'GroupId' -Value $_.GroupId
|
||||
#endregion FinalValue
|
||||
#endregion FillSingleTeamReport
|
||||
|
||||
# Append to the Report
|
||||
$MicrosoftTeamsReport += $SingleTeamReport
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region WarningHandler
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteWarning = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
WarningAction = 'Continue'
|
||||
}
|
||||
Write-Warning @paramWriteWarning
|
||||
#region WarningHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region ErrorHandler
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Just in case
|
||||
Exit 1
|
||||
#region ErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
#region Disconnect
|
||||
if ($Disconnect)
|
||||
{
|
||||
# Logoff
|
||||
$null = (Disconnect-MicrosoftTeams -Confirm:$false)
|
||||
}
|
||||
#endregion Disconnect
|
||||
|
||||
#region ShowReport
|
||||
# Dump the Report
|
||||
$MicrosoftTeamsReport
|
||||
#endregion ShowReport
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,300 @@
|
||||
#requires -Version 3.0 -Modules BitsTransfer -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Download, install, and Tweak System and Apps for Terminal Server use
|
||||
|
||||
.DESCRIPTION
|
||||
Download, install, and Tweak System and Apps for Terminal Server (WVD/VDI/WDS) use
|
||||
|
||||
.NOTES
|
||||
Early testing release - Future releases might get some parameters
|
||||
|
||||
Changelog:
|
||||
1.0.0: Initial Release
|
||||
|
||||
Version 1.0.0
|
||||
|
||||
.LINK
|
||||
http://enatec.io
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
Write-Output -InputObject 'Download, install, and Tweak System and Apps for Terminal Server use'
|
||||
|
||||
# Default URL (Assume we use 64Bit)
|
||||
[string]$FSLogixUrl = 'https://aka.ms/fslogix_download'
|
||||
|
||||
#region PossibleParameters
|
||||
# Where to Store it
|
||||
[string]$Target = ($env:Temp)
|
||||
|
||||
# File Name
|
||||
[string]$TargetName = 'fslogix.zip'
|
||||
|
||||
# Install Switch
|
||||
[string]$Arguments = '/install /quiet /norestart'
|
||||
#endregion PossibleParameters
|
||||
|
||||
#region Defaults
|
||||
# Set the full path of the downloaded installer
|
||||
[string]$InstallerPackage = ($Target + '\' + $TargetName)
|
||||
|
||||
[string]$InstallerDestination = (($InstallerPackage).Replace('.zip', ''))
|
||||
[string]$InstallerExecutable = ($InstallerDestination + '\x64\Release\FSLogixAppsSetup.exe')
|
||||
$SCT = 'SilentlyContinue'
|
||||
$STP = 'Stop'
|
||||
#endregion Defaults
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
Write-Verbose -Message ('Downloading {0} to {1}' -f $TargetName, $InstallerPackage)
|
||||
|
||||
# Use BitsTransfer to download the latest installer
|
||||
$paramStartBitsTransfer = @{
|
||||
Source = $FSLogixUrl
|
||||
Destination = $InstallerPackage
|
||||
Priority = 'High'
|
||||
TransferPolicy = 'Always'
|
||||
ErrorAction = $STP
|
||||
}
|
||||
$null = (Start-BitsTransfer @paramStartBitsTransfer)
|
||||
|
||||
# Expand FSLogix Installer
|
||||
$paramTestPath = @{
|
||||
Path = $InstallerPackage
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (Test-Path @paramTestPath)
|
||||
{
|
||||
$paramTestPath = @{
|
||||
Path = $InstallerDestination
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (-not (Test-Path @paramTestPath))
|
||||
{
|
||||
$paramNewItem = @{
|
||||
Path = $InstallerDestination
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ItemType = 'Directory'
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-Item @paramNewItem)
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
# Expand-Archive is to buggy!
|
||||
$null = (Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction $STP)
|
||||
$null = ([IO.Compression.ZipFile]::ExtractToDirectory($InstallerPackage, $InstallerDestination))
|
||||
}
|
||||
catch
|
||||
{
|
||||
# OK! That is crappy, but it still works well as a fallback.
|
||||
$shellApp = (New-Object -ComObject Shell.Application -ErrorAction $STP)
|
||||
$shellZip = $shellApp.NameSpace([String]$InstallerPackage)
|
||||
$shellDest = $shellApp.NameSpace($InstallerDestination)
|
||||
$shellDest.CopyHere($shellZip.items())
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = $STP
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# We are done
|
||||
break
|
||||
}
|
||||
|
||||
# Install FSLogix
|
||||
$paramTestPath = @{
|
||||
Path = $InstallerExecutable
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (Test-Path @paramTestPath)
|
||||
{
|
||||
$paramGetItemProperty = @{
|
||||
Path = $InstallerExecutable
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$InstallerVersion = ((Get-ItemProperty @paramGetItemProperty).VersionInfo.ProductVersion)
|
||||
|
||||
Write-Verbose -Message ('Running FSLogix installer version {0}' -f $InstallerVersion)
|
||||
|
||||
$paramStartProcess = @{
|
||||
FilePath = $InstallerExecutable
|
||||
ArgumentList = $Arguments
|
||||
Wait = $true
|
||||
PassThru = $true
|
||||
ErrorAction = $STP
|
||||
}
|
||||
$InstallerProcess = (Start-Process @paramStartProcess)
|
||||
|
||||
if (($InstallerProcess | Select-Object -ExpandProperty ExitCode) -eq 0)
|
||||
{
|
||||
Write-Verbose -Message ('Installed FSLogix version {0}' -f $InstallerVersion)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message ('Installer exit code {0}.' -f $InstallerProcess.ExitCode)
|
||||
}
|
||||
|
||||
Write-Verbose -Message ('Removing file: {0}' -f $InstallerPackage)
|
||||
|
||||
# Remove the downloaded Installaer Package
|
||||
$paramRemoveItem = @{
|
||||
Path = $InstallerPackage
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Remove-Item @paramRemoveItem)
|
||||
|
||||
# Install the expanded stuff
|
||||
$paramRemoveItem = @{
|
||||
Path = $InstallerDestination
|
||||
Recurse = $true
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Remove-Item @paramRemoveItem)
|
||||
|
||||
# Legacy HKLM Path for WVD/VDI/WDS Environment
|
||||
$paramNewItem = @{
|
||||
Path = 'HKLM:\SOFTWARE\Citrix\PortICA'
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-Item @paramNewItem)
|
||||
|
||||
# Ensure that the registry path exists
|
||||
$paramNewItem = @{
|
||||
Path = 'HKLM:\SOFTWARE\Microsoft\Teams'
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-Item @paramNewItem)
|
||||
|
||||
# Tell Microsoft Teams that it runs in an WVD/VDI/WDS Environment
|
||||
# Source: https://docs.microsoft.com/en-us/azure/virtual-desktop/teams-on-wvd
|
||||
$paramNewItemProperty = @{
|
||||
Path = 'HKLM:\SOFTWARE\Microsoft\Teams'
|
||||
Name = 'IsWVDEnvironment'
|
||||
PropertyType = 'DWORD'
|
||||
Value = 1
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-ItemProperty @paramNewItemProperty)
|
||||
|
||||
# Ensure that the registry path exists
|
||||
$paramNewItem = @{
|
||||
Path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run32'
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-Item @paramNewItem)
|
||||
|
||||
# Do not start Microsoft Teams after Login
|
||||
$paramNewItemProperty = @{
|
||||
Path = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run32'
|
||||
Name = 'Teams'
|
||||
PropertyType = 'Binary'
|
||||
Value = ([byte[]](0x01, 0x00, 0x00, 0x00, 0x1a, 0x19, 0xc3, 0xb9, 0x62, 0x69, 0xd5, 0x01))
|
||||
Confirm = $false
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-ItemProperty @paramNewItemProperty)
|
||||
}
|
||||
else
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = $STP
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# We are done
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,137 @@
|
||||
#requires -Version 3.0 -Modules NetSecurity -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Tweak the Firewall Rules for Microsoft Teams clients
|
||||
|
||||
.DESCRIPTION
|
||||
Tweak the Firewall Rules for Microsoft Teams clients for all users that have it installed
|
||||
|
||||
.NOTES
|
||||
Early testing release
|
||||
|
||||
Changelog:
|
||||
1.0.0: Initial Release
|
||||
|
||||
Version 1.0.0
|
||||
|
||||
.LINK
|
||||
http://enatec.io
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param ()
|
||||
|
||||
begin
|
||||
{
|
||||
Write-Output -InputObject 'Tweak the Firewall Rules for Microsoft Teams clients for all users that have it installed'
|
||||
|
||||
#region Defaults
|
||||
$SCT = 'SilentlyContinue'
|
||||
#endregion Defaults
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Creates firewall rules for Microsoft Teams
|
||||
$AllUsers = $null
|
||||
|
||||
$paramJoinPath = @{
|
||||
Path = $env:SystemDrive
|
||||
ChildPath = 'Users'
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$paramGetChildItem = @{
|
||||
Path = (Join-Path @paramJoinPath)
|
||||
ErrorAction = $SCT
|
||||
Exclude = 'Public', 'ADMINI~*'
|
||||
}
|
||||
$AllUsers = (Get-ChildItem @paramGetChildItem)
|
||||
|
||||
if ($null -ne $AllUsers)
|
||||
{
|
||||
foreach ($SingleUser in $AllUsers)
|
||||
{
|
||||
# Cleanup
|
||||
$FullTeamsPath = $null
|
||||
|
||||
# get the Executable
|
||||
$paramJoinPath = @{
|
||||
Path = $SingleUser.FullName
|
||||
ChildPath = 'AppData\Local\Microsoft\Teams\Current\Teams.exe'
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$FullTeamsPath = (Join-Path @paramJoinPath)
|
||||
|
||||
$paramTestPath = @{
|
||||
Path = $FullTeamsPath
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (Test-Path @paramTestPath)
|
||||
{
|
||||
$paramGetNetFirewallApplicationFilter = @{
|
||||
Program = $FullTeamsPath
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetFirewallApplicationFilter @paramGetNetFirewallApplicationFilter))
|
||||
{
|
||||
# Cleanup
|
||||
$NetFirewallRuleName = $null
|
||||
|
||||
# Apply the Rulename
|
||||
$NetFirewallRuleName = ('Teams.exe for user {0}' -f $SingleUser.Name)
|
||||
|
||||
'UDP', 'TCP' | ForEach-Object -Process {
|
||||
$paramNewNetFirewallRule = @{
|
||||
DisplayName = $NetFirewallRuleName
|
||||
Direction = 'Inbound'
|
||||
Profile = 'Any'
|
||||
Program = $FullTeamsPath
|
||||
Action = 'Allow'
|
||||
Protocol = $_
|
||||
Enabled = 'True'
|
||||
Confirm = $false
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (New-NetFirewallRule @paramNewNetFirewallRule)
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
$NetFirewallRuleName = $null
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
$FullTeamsPath = $null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,184 @@
|
||||
function Invoke-mtrDisableModernAuthentication
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Disable Modern Authentication for a Microsoft Teams Room Device Account
|
||||
|
||||
.DESCRIPTION
|
||||
Disable Modern Authentication for a Microsoft Teams Room Device Account
|
||||
It dsables it in Exchange Online and Skype for Business Online. It also configures the tenant to do so, if needed.
|
||||
|
||||
.PARAMETER Identity
|
||||
The Microsoft Teams Rooms (MTR) Account Search String
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-mtrDisableModernAuthentication.ps1 -Identity 'MyTeamRoom'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Invoke-mtrDisableModernAuthentication.ps1 -Identity 'TeamRoom@contoso.com'
|
||||
|
||||
.NOTES
|
||||
Just a quick and dirty tool to do the job, nothing fancy and without a real error handling!
|
||||
-> Use at your own risk!
|
||||
|
||||
You need to be a tenant admin to configure all the things
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory, HelpMessage = 'The Microsoft Teams Rooms (MTR) Account Search String',
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('SearchString', 'mtrAccount')]
|
||||
[string]
|
||||
$Identity
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Defaults
|
||||
$STP = 'Stop'
|
||||
$SCT = 'SilentlyContinue'
|
||||
#endregion Defaults
|
||||
|
||||
#region GeneralParameters
|
||||
$RemovePSSessionDefaultParams = @{
|
||||
Confirm = $false
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
|
||||
$RemoveModuleDefaultParams = @{
|
||||
Force = $true
|
||||
Confirm = $false
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
#endregion GeneralParameters
|
||||
|
||||
Write-Verbose -Message 'Message'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
#region ConnectAzureAD
|
||||
$null = (Connect-AzureAD)
|
||||
#endregion ConnectAzureAD
|
||||
|
||||
#region ConnectSkypeForBusinessOnline
|
||||
# We use a crappy workaround, because the Modern Auth window never shows up to querry the admin UPN, and I do NOT trust the command to querry it
|
||||
$SkypeForBusinessSession = (New-CsOnlineSession -UserName (Read-Host -Prompt 'Please enter the admin principal name (ex. admin@contoso.com)'))
|
||||
$paramImportPSSession = @{
|
||||
Session = $SkypeForBusinessSession
|
||||
DisableNameChecking = $true
|
||||
AllowClobber = $true
|
||||
}
|
||||
$null = (Import-PSSession @paramImportPSSession)
|
||||
#endregion ConnectSkypeForBusinessOnline
|
||||
|
||||
#region ConnectExchangeOnline
|
||||
# We use the ExchangeOnlineShell Module from the Gallery
|
||||
if (-not (Get-Command -Name Get-Mailbox -ErrorAction $SCT))
|
||||
{
|
||||
$paramConnectExchangeOnlineShell = @{
|
||||
Confirm = $false
|
||||
WarningAction = $SCT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
$null = (Connect-ExchangeOnlineShell @paramConnectExchangeOnlineShell)
|
||||
}
|
||||
#endregion ConnectExchangeOnline
|
||||
|
||||
#region CheckModernAuth
|
||||
# Do we have Modern Auth enabled Global?
|
||||
if ((Get-OrganizationConfig | Select-Object -ExpandProperty OAuth2ClientProfileEnabled) -eq $true)
|
||||
{
|
||||
# Disconnect Modern Authentication (For a single user) - In this case the MTR
|
||||
$paramRevokeAzureADUserAllRefreshToken = @{
|
||||
ObjectId = (Get-AzureADUser -SearchString $Identity | Select-Object -ExpandProperty objectId)
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Revoke-AzureADUserAllRefreshToken @paramRevokeAzureADUserAllRefreshToken)
|
||||
$null = (Revoke-AzureADUserAllRefreshToken @paramRevokeAzureADUserAllRefreshToken)
|
||||
|
||||
# Allow non Modern Auth in Skype for Business
|
||||
if ((Get-CsOAuthConfiguration -ErrorAction $SCT | Select-Object -ExpandProperty ClientAdalAuthOverride) -ne 'Allowed')
|
||||
{
|
||||
$paramSetCsOAuthConfiguration = @{
|
||||
ClientAdalAuthOverride = 'Allowed'
|
||||
Confirm = $false
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Set-CsOAuthConfiguration @paramSetCsOAuthConfiguration)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Shame on you!
|
||||
Write-Warning -Message 'Looks like Modern Auth is not enabled for this tenant!' -WarningAction $STP
|
||||
}
|
||||
#endregion CheckModernAuth
|
||||
|
||||
#region DisconnectAzureAD
|
||||
$null = (Disconnect-AzureAD -Confirm:$false -ErrorAction $SCT)
|
||||
#endregion DisconnectAzureAD
|
||||
|
||||
#region DisconnectSkypeForBusiness
|
||||
$paramRemoveModule = @{
|
||||
Name = (Get-Command -Name Set-CsOAuthConfiguration -ErrorAction $SCT | Select-Object -ExpandProperty Source)
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
|
||||
$null = (Remove-Module @paramRemoveModule)
|
||||
$null = ($SkypeForBusinessSession.Id | Remove-PSSession @RemovePSSessionDefaultParams)
|
||||
#endregion DisconnectSkypeForBusiness
|
||||
|
||||
#region DisconnectExchangeOnline
|
||||
$ExchangeSessionID = (Get-PSSession | Where-Object {
|
||||
$_.ComputerName -eq 'outlook.office365.com'
|
||||
} | Select-Object -ExpandProperty Id)
|
||||
|
||||
if ($ExchangeSessionID)
|
||||
{
|
||||
$paramDisconnectExchangeOnlineShell = @{
|
||||
SessionID = $ExchangeSessionID
|
||||
Confirm = $false
|
||||
}
|
||||
$null = (Disconnect-ExchangeOnlineShell @paramDisconnectExchangeOnlineShell)
|
||||
}
|
||||
|
||||
# Will be removed soon (Disconnect-ExchangeOnlineShell will handle this for us!)
|
||||
$RemoveModuleName = (Get-Command -Name Get-OrganizationConfig -ErrorAction $SCT | Select-Object -ExpandProperty Source)
|
||||
|
||||
if ($RemoveModuleName)
|
||||
{
|
||||
$paramRemoveModule = @{
|
||||
Name = $RemoveModuleName
|
||||
Force = $true
|
||||
ErrorAction = $SCT
|
||||
}
|
||||
$null = (Remove-Module @RemoveModuleDefaultParams)
|
||||
}
|
||||
#endregion DisconnectExchangeOnline
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
#region FinalCleanup
|
||||
# Just in case: We remove all sessions that might still be around
|
||||
$null = ((Get-PSSession -ErrorAction $SCT | Where-Object {
|
||||
$_.ComputerName -eq 'outlook.office365.com'
|
||||
}) | Remove-PSSession @RemovePSSessionDefaultParams)
|
||||
|
||||
$null = ((Get-PSSession -ErrorAction $SCT | Where-Object {
|
||||
$_.ComputerName -like 'admin*.online.lync.com'
|
||||
}) | Remove-PSSession @RemovePSSessionDefaultParams)
|
||||
|
||||
# Remove the Modules (Here just in case we missed something above)
|
||||
$null = (Remove-Module -Name (Get-Command -Name Connect-ExchangeOnlineShell -ErrorAction $SCT | Select-Object -ExpandProperty Source) @RemoveModuleDefaultParams)
|
||||
$null = (Remove-Module -Name (Get-Command -Name Disconnect-AzureAD -ErrorAction $SCT | Select-Object -ExpandProperty Source) @RemoveModuleDefaultParams)
|
||||
$null = (Remove-Module -Name (Get-Command -Name New-CsOnlineSession -ErrorAction $SCT | Select-Object -ExpandProperty Source) @RemoveModuleDefaultParams)
|
||||
#endregion FinalCleanup
|
||||
}
|
||||
}
|
||||
29
Powershell/PowerShell-collection/MicrosoftTeams/LICENSE
Normal file
29
Powershell/PowerShell-collection/MicrosoftTeams/LICENSE
Normal file
@@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology <http://enatec.io>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,448 @@
|
||||
#requires -Version 3.0
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Creates a new Microsoft Teams team with the MicrosoftTeams Module.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates a new Microsoft Teams team with the MicrosoftTeams Module.
|
||||
The new team will be backed by a newly created unified group and SharePoint Online Site.
|
||||
|
||||
The script depends on Microsoft's Version 0.9.6 of the MicrosoftTeams Module.
|
||||
Please note: Not all authentications methods of the latest MicrosoftTeams Module are supported!
|
||||
|
||||
.PARAMETER msTeamsCreds
|
||||
Specifies a PSCredential object. For more information about the PSCredential object, type Get-Help Get-Credential.
|
||||
The PSCredential object provides the user ID and password for organizational ID credentials.
|
||||
|
||||
.PARAMETER mfa
|
||||
Use the web based authentication. Supports MFA and prevents issues in non ADFS implementations.
|
||||
|
||||
.PARAMETER DisplayName
|
||||
Todeam display name. Team Name Characters Limit is 256.
|
||||
|
||||
.PARAMETER Alias
|
||||
Same as displayName without any spaces. Team Alias Characters Limit is 64
|
||||
|
||||
.PARAMETER Description
|
||||
Team description. Team Description Characters Limit is 1024.
|
||||
|
||||
.PARAMETER AccessType
|
||||
Team access type. Valid values are "Private" and "Public". Default is "Private". (This parameter has the same meaning as -AccessType in New-UnifiedGroup.)
|
||||
|
||||
.PARAMETER AddCreatorAsMember
|
||||
This setting lets you decide if you will be added as a member of the team. The default is false.
|
||||
|
||||
.PARAMETER Owner
|
||||
UPN/Mail of the Teams Owner, multiple values are supported!
|
||||
|
||||
.PARAMETER User
|
||||
member Users for the Group, Please use UPN or Mail.
|
||||
Multiple values are supported.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -mfa -DisplayName 'Contoso Support'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Support'. Uses Weblog (supports MFA)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -msTeamsCreds $O365 -DisplayName 'Contoso Support'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Support'. Uses existing credentials stored in the variable $O365 to authenticate.
|
||||
This might be the perfect way for automation, but use stored credentials might also be insecure.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Support'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Support'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Support' -Alias 'AITSupport'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Support' with an Alias 'AITSupport'
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Info-pool' -AccessType 'public'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Info-pool', public mean open to join for every member of the organization.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Development' -Description 'Contoso IT Development Team' -Owner 'john.doe@acontoso.com'
|
||||
|
||||
Creates the Microsoft Team 'Contoso Development', sets a description and add 'john.doe@contoso.com' as Owner.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\New-AITMicrosoftTeams -DisplayName 'Contoso Core Dev' -AddCreatorAsMember $true
|
||||
|
||||
Creates the Microsoft Team 'Contoso Core Dev' and adds the creator to the new Team.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Install-Module -Name MicrosoftTeams
|
||||
|
||||
Install the dependency Module from Microsoft via PowerShellGet.
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
1.0.3 2019-04-26: Fix Module Statement to use the correct version (0.9.6) to avoid issues with our workaround.
|
||||
1.0.2 2019-02-05: Reintroduce the -MFA switch to support the web based authentication. Prevent issues in non ADFS implementations.
|
||||
1.0.1 2019-02-04: Add workaround for AddCreatorAsMember Bug (Creator is added as owner all the time)
|
||||
1.0.0 2018-12-31: Internal Release
|
||||
|
||||
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
|
||||
|
||||
Dependencies:
|
||||
The script depends on Microsoft's Version 0.9.6 of the MicrosoftTeams PowerShell Module.
|
||||
The MicrosoftTeams PowerShell Module GA Version (1.0.0) is not yet tested!
|
||||
|
||||
Install it with PowerShellGet:
|
||||
PS C:\> Install-Module -Name MicrosoftTeams -RequiredVersion 0.9.6
|
||||
|
||||
.LINK
|
||||
https://www.powershellgallery.com/packages/MicrosoftTeams/0.9.6
|
||||
|
||||
.LINK
|
||||
https://aka.ms/InstallModule
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName = 'MFA',
|
||||
ConfirmImpact = 'None')]
|
||||
param
|
||||
(
|
||||
[Parameter(ParameterSetName = 'Credentials',
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[System.Management.Automation.Credential()]
|
||||
[Alias('TeamsCredentials', 'TeamsAdminCredentials', 'Office365creds')]
|
||||
[pscredential]
|
||||
$msTeamsCreds,
|
||||
[Parameter(ParameterSetName = 'MFA',
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[Alias('UseMFA')]
|
||||
[switch]
|
||||
$mfa,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Team display name.')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('TeamsDisplayName')]
|
||||
[string]
|
||||
$DisplayName,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[Alias('TeamsAlias')]
|
||||
[string]
|
||||
$Alias,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 3)]
|
||||
[Alias('TeamsDescription')]
|
||||
[string]
|
||||
$Description,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 4)]
|
||||
[ValidateSet('HiddenMembership', 'Private', 'Public', IgnoreCase = $true)]
|
||||
[Alias('TeamsAccessType')]
|
||||
[string]
|
||||
$AccessType = 'Private',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 5)]
|
||||
[Alias('AddCreatorAsTeamsMember')]
|
||||
[switch]
|
||||
$AddCreatorAsMember = $false,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 6)]
|
||||
[Alias('TeamsOwner')]
|
||||
[string[]]
|
||||
$Owner,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 7)]
|
||||
[Alias('TeamsUser', 'TeamsMember')]
|
||||
[string[]]
|
||||
$User
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region VersionRequirement
|
||||
try
|
||||
{
|
||||
$paramRemoveModule = @{
|
||||
Name = 'MicrosoftTeams'
|
||||
Force = $true
|
||||
ErrorAction = 'SilentlyContinue'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Remove-Module @paramRemoveModule)
|
||||
|
||||
$paramImportModule = @{
|
||||
Name = 'MicrosoftTeams'
|
||||
MaximumVersion = '0.9.6'
|
||||
Force = $true
|
||||
ErrorAction = 'Stop'
|
||||
WarningAction = 'SilentlyContinue'
|
||||
}
|
||||
$null = (Import-Module @paramImportModule)
|
||||
}
|
||||
catch
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Message = 'Microsoft´s Version 0.9.6 of the MicrosoftTeams PowerShell Module'
|
||||
ErrorAction = 'Stop'
|
||||
Category = 'NotInstalled'
|
||||
Exception = 'Required Module not found'
|
||||
RecommendedAction = 'Please install Version 0.9.6 of the MicrosoftTeams PowerShell Module via Install-Module -Name MicrosoftTeams -RequiredVersion 0.9.6'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
}
|
||||
#endregion VersionRequirement
|
||||
|
||||
#region AuthChecker
|
||||
if (($msTeamsCreds) -and ($mfa))
|
||||
{
|
||||
$paramWriteError = @{
|
||||
Message = 'You have selected muliple authentication methods. This is not valid'
|
||||
Exception = 'Muliple authentication methods selected'
|
||||
Category = 'AuthenticationError'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
}
|
||||
#endregion AuthChecker
|
||||
|
||||
#region Defaults
|
||||
#region AccessType
|
||||
if (-not ($AccessType))
|
||||
{
|
||||
$AccessType = 'Private'
|
||||
}
|
||||
#endregion AccessType
|
||||
|
||||
#region AddCreatorAsMember
|
||||
if (-not ($AddCreatorAsMember))
|
||||
{
|
||||
$AddCreatorAsMember = $false
|
||||
}
|
||||
#endregion AddCreatorAsMember
|
||||
#endregion defaults
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess($DisplayName, 'Create'))
|
||||
{
|
||||
try
|
||||
{
|
||||
#region Authentication
|
||||
if (-not ($mfa))
|
||||
{
|
||||
#region CredentialHandler
|
||||
if (-not ($msTeamsCreds))
|
||||
{
|
||||
# Get the credentials / Use it within the script only
|
||||
$script:msTeamsCreds = (Get-Credential -Message 'Please use credentials with Teams Admin capabilities.')
|
||||
}
|
||||
#endregion CredentialHandler
|
||||
|
||||
#region ConnectMicrosoftTeams
|
||||
$paramConnectMicrosoftTeams = @{
|
||||
Credential = $msTeamsCreds
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Connect-MicrosoftTeams @paramConnectMicrosoftTeams)
|
||||
#endregion ConnectMicrosoftTeams
|
||||
}
|
||||
else
|
||||
{
|
||||
#region ConnectMicrosoftTeams
|
||||
# Use the Web login
|
||||
$paramConnectMicrosoftTeams = @{
|
||||
Confirm = $false
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Connect-MicrosoftTeams @paramConnectMicrosoftTeams)
|
||||
#endregion ConnectMicrosoftTeams
|
||||
}
|
||||
#endregion Authentication
|
||||
|
||||
#region NewTeam
|
||||
#region SplatDefaults
|
||||
$paramNewTeam = @{
|
||||
DisplayName = $DisplayName
|
||||
Visibility = $AccessType
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
#endregion SplatDefaults
|
||||
|
||||
#region Optionals
|
||||
if (($msTeamsCreds.UserName) -and ($AddCreatorAsMember -eq $true))
|
||||
{
|
||||
$paramNewTeam | Add-Member -MemberType NoteProperty -Name Owner -Value $msTeamsCreds.UserName
|
||||
}
|
||||
|
||||
if ($Alias)
|
||||
{
|
||||
$paramNewTeam | Add-Member -MemberType NoteProperty -Name Alias -Value $Alias
|
||||
}
|
||||
|
||||
if ($Description)
|
||||
{
|
||||
$paramNewTeam | Add-Member -MemberType NoteProperty -Name Description -Value $Description
|
||||
}
|
||||
#region Optionals
|
||||
|
||||
#region CreateTeam
|
||||
$NewTeam = (New-Team @paramNewTeam)
|
||||
#endregion CreateTeam
|
||||
|
||||
if (-not ($NewTeam.GroupId))
|
||||
{
|
||||
Write-Error -Message ('Error while try to create {0}' -f $DisplayName)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose -Message "The new Team id is $($NewTeam.GroupId)"
|
||||
|
||||
#region BugWorkAround
|
||||
#BUG: There is a bug in the AddCreatorAsMember implemntation of Microsoft
|
||||
if ($AddCreatorAsMember -eq $false)
|
||||
{
|
||||
Write-Verbose -Message 'Workaround: Workaround for the AddCreatorAsMember of the Microsoft MicrosoftTeams Module'
|
||||
Remove-TeamUser -GroupId $NewTeam.GroupId -User $msTeamsCreds.UserName -ErrorAction SilentlyContinue
|
||||
}
|
||||
#endregion BugWorkAround
|
||||
|
||||
#region SetOwner
|
||||
if ($Owner)
|
||||
{
|
||||
foreach ($Admin in $Owner)
|
||||
{
|
||||
try
|
||||
{
|
||||
$paramAddTeamUser = @{
|
||||
GroupId = $NewTeam.GroupId
|
||||
User = $Admin
|
||||
Role = 'Owner'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-TeamUser @paramAddTeamUser)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to add {0} as owner to the Team {1}' -f $Admin, $DisplayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message ('The Team {0} has no owner!' -f $DisplayName)
|
||||
}
|
||||
#endregion SetOwner
|
||||
|
||||
#region Setmember
|
||||
if ($User)
|
||||
{
|
||||
foreach ($Member in $User)
|
||||
{
|
||||
try
|
||||
{
|
||||
$paramAddTeamUser = @{
|
||||
GroupId = $NewTeam.GroupId
|
||||
User = $Member
|
||||
Role = 'Member'
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-TeamUser @paramAddTeamUser)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to add {0} as member to the Team {1}' -f $Member, $DisplayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Setmember
|
||||
}
|
||||
#endregion NewTeam
|
||||
}
|
||||
catch
|
||||
{
|
||||
#region ErrorHandler
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
Write-Error -Message ($info.Exception) -ErrorAction Stop
|
||||
|
||||
# Only here to catch a global ErrorAction overwrite
|
||||
break
|
||||
#endregion ErrorHandler
|
||||
}
|
||||
finally
|
||||
{
|
||||
#region Cleanup
|
||||
$null = (Disconnect-MicrosoftTeams -Confirm:$false)
|
||||
#endregion Cleanup
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message ('Created the Team {0}' -f $DisplayName)
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,719 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Create a Project team in Teams with folder structure in files tab
|
||||
|
||||
.TeamsDescription
|
||||
Create a Project team in Teams with folder structure in files tab
|
||||
Based on Alexander Holmeset's version.
|
||||
|
||||
.DESCRIPTION
|
||||
A detailed description of the file.
|
||||
|
||||
.PARAMETER TeamName
|
||||
Name of the Microsoft Teams team
|
||||
|
||||
.PARAMETER TeamsOwner
|
||||
TeamsOwner of the new Microsoft Teams team
|
||||
|
||||
.PARAMETER privatepublic
|
||||
Os it a private or Public team?
|
||||
|
||||
.PARAMETER TeamsDescription
|
||||
The TeamsDescription for the new team
|
||||
|
||||
.PARAMETER ClientId
|
||||
Azure AD Application (client) ID
|
||||
|
||||
.PARAMETER TenantId
|
||||
Azure AD Tenant ID
|
||||
|
||||
.PARAMETER ClientSecret
|
||||
Azure AD secret
|
||||
|
||||
.PARAMETER TenantName
|
||||
Office 365 Tenant Name (e.g. contoso for https://contoso.sharepoint.com)
|
||||
|
||||
.PARAMETER DocumentLibrary
|
||||
Document Library Folder, default is /shared documents
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\ProjectTeamStructure.ps1 -TeamName 'Value1' -TeamsOwner 'Value2'
|
||||
|
||||
.NOTES
|
||||
Original found in Alexander Holmeset's Blog
|
||||
My version starts to make it a bit more flexible (e.g. more parameters)
|
||||
I might update this to be more configurable in the future
|
||||
|
||||
.LINK
|
||||
https://alexholmeset.blog/2019/05/01/project-team-in-teams-with-folder-structure-in-files-tab/
|
||||
|
||||
.LINK
|
||||
https://gist.githubusercontent.com/AlexanderHolmeset/d447cd7c24dd91c3275ad17a5091f0ed/raw/79478f1e789ab36a9236f21a3161685091b12e62/ProjectTeamStructure.ps1
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'Name of the Microsoft Teams team')]
|
||||
[Parameter (Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Name')]
|
||||
[String]
|
||||
$TeamName,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Owner of the new Microsoft Teams team')]
|
||||
[Parameter (Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('Owner')]
|
||||
[String]
|
||||
$TeamsOwner,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2)]
|
||||
[Parameter (Mandatory)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$privatepublic = 'Public',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 3)]
|
||||
[Parameter (Mandatory)]
|
||||
[Alias('description')]
|
||||
[String]
|
||||
$TeamsDescription,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 4)]
|
||||
[Alias('OAuthClientId')]
|
||||
[string]
|
||||
$ClientId,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 5)]
|
||||
[Alias('OAuthTenantId')]
|
||||
[string]
|
||||
$TenantId,
|
||||
[Parameter(Position = 6)]
|
||||
[Alias('OAuthClientSecret')]
|
||||
[string]
|
||||
$ClientSecret,
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 7)]
|
||||
[string]
|
||||
$TenantName = 'contoso',
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 8)]
|
||||
[string]
|
||||
$DocumentLibrary = '/shared documents'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
<#
|
||||
# Azure AD OAuth Application Token for Graph API
|
||||
# Get OAuth token for a AAD Application (returned as $token)
|
||||
# Application (client) ID, tenant ID and secret
|
||||
$ClientId = 'xxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
$TenantId = 'xxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
$ClientSecret = 'xxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
#>
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
# Get the credentials to use
|
||||
$Cred = (Get-Credential)
|
||||
|
||||
# Connect to Exchange Online
|
||||
$paramNewPSSession = @{
|
||||
ConfigurationName = 'Microsoft.Exchange'
|
||||
ConnectionUri = 'https://outlook.office365.com/powershell-liveid'
|
||||
Credential = $Cred
|
||||
Authentication = 'Basic'
|
||||
AllowRedirection = $true
|
||||
}
|
||||
|
||||
$Session = (New-PSSession @paramNewPSSession)
|
||||
$paramImportPSSession = @{
|
||||
Session = $Session
|
||||
DisableNameChecking = $true
|
||||
AllowClobber = $true
|
||||
}
|
||||
|
||||
$null = (Import-PSSession @paramImportPSSession)
|
||||
|
||||
# Connect to Microsoft Teams
|
||||
$null = (Connect-MicrosoftTeams -Credential $Cred)
|
||||
|
||||
# Contruct URI
|
||||
$uri = 'https://login.microsoftonline.com/' + $TenantId + '/oauth2/v2.0/token'
|
||||
|
||||
# Construct the JSON Body
|
||||
$body1 = @{
|
||||
client_id = $ClientId
|
||||
scope = 'https://graph.microsoft.com/.default'
|
||||
client_secret = $ClientSecret
|
||||
grant_type = 'client_credentials'
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
# Get OAuth 2.0 Token
|
||||
$paramInvokeWebRequest = @{
|
||||
Method = 'Post'
|
||||
Uri = $uri
|
||||
ContentType = 'application/x-www-form-urlencoded'
|
||||
Body = $body1
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
}
|
||||
$tokenRequest = (Invoke-WebRequest @paramInvokeWebRequest)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the Token
|
||||
$token = (($tokenRequest.Content | ConvertFrom-Json).access_token)
|
||||
|
||||
# Get ID of team requester and set as owner.
|
||||
$uri = 'https://graph.microsoft.com/beta/users/' + $TeamsOwner + '?$select=id'
|
||||
$method = 'GET'
|
||||
|
||||
try
|
||||
{
|
||||
$paramInvokeWebRequest = @{
|
||||
Method = $method
|
||||
Uri = $uri
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
}
|
||||
$query = (Invoke-WebRequest @paramInvokeWebRequest)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the ID
|
||||
$ownerID = (($query.content | ConvertFrom-Json).id)
|
||||
|
||||
# Specify the URI to call and method
|
||||
$uri = 'https://graph.microsoft.com/beta/teams'
|
||||
$method = 'Post'
|
||||
|
||||
# Construct the JSON Body
|
||||
<#
|
||||
Please review this defaults,
|
||||
these settings are applied to the new Microsoft Teams team!
|
||||
#>
|
||||
$body = @"
|
||||
{
|
||||
"template@odata.bind": "https://graph.microsoft.com/beta/teamsTemplates/standard",
|
||||
"displayName": "$TeamName",
|
||||
"description": "$TeamsDescription",
|
||||
"channels": [
|
||||
{
|
||||
"displayName": "01-Management",
|
||||
"isFavoriteByDefault": true,
|
||||
"description": "Description"
|
||||
},
|
||||
{
|
||||
"displayName": "02-Developement",
|
||||
"isFavoriteByDefault": true,
|
||||
"description": "DEscription"
|
||||
},
|
||||
{
|
||||
"displayName": "03-Marketing",
|
||||
"isFavoriteByDefault": true,
|
||||
"description": "Description"
|
||||
},
|
||||
{
|
||||
"displayName": "04-Finance",
|
||||
"isFavoriteByDefault": true,
|
||||
"description": "Description"
|
||||
}
|
||||
],
|
||||
"memberSettings": {
|
||||
"allowCreateUpdateChannels": true,
|
||||
"allowDeleteChannels": false,
|
||||
"allowAddRemoveApps": true,
|
||||
"allowCreateUpdateRemoveTabs": true,
|
||||
"allowCreateUpdateRemoveConnectors": true
|
||||
},
|
||||
"guestSettings": {
|
||||
"allowCreateUpdateChannels": false,
|
||||
"allowDeleteChannels": false
|
||||
},
|
||||
"funSettings": {
|
||||
"allowGiphy": true,
|
||||
"giphyContentRating": "Moderate",
|
||||
"allowStickersAndMemes": true,
|
||||
"allowCustomMemes": true
|
||||
},
|
||||
"messagingSettings": {
|
||||
"allowUserEditMessages": true,
|
||||
"allowUserDeleteMessages": true,
|
||||
"allowOwnerDeleteMessages": true,
|
||||
"allowTeamMentions": true,
|
||||
"allowChannelMentions": true
|
||||
},
|
||||
"visibility": "$Private",
|
||||
"owners@odata.bind": [
|
||||
"https://graph.microsoft.com/beta/users('$ownerID')"
|
||||
]
|
||||
}
|
||||
"@
|
||||
|
||||
try
|
||||
{
|
||||
$paramInvokeWebRequest = @{
|
||||
Method = $method
|
||||
Uri = $uri
|
||||
ContentType = 'application/json'
|
||||
Body = $body
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
}
|
||||
$query = (Invoke-WebRequest @paramInvokeWebRequest)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the Data
|
||||
$location = ($query.Headers).Location
|
||||
$GroupID = $location.Substring(8, 36)
|
||||
|
||||
# Wait a minute to setup the stuff
|
||||
Start-Sleep -Seconds 60
|
||||
|
||||
# Get the Mail info about the new team
|
||||
$TeamSiteName = ((Get-Team -groupid $GroupID).MailNickName)
|
||||
|
||||
# Set some defaults
|
||||
$SiteURL = 'https://' + $TenantName + '.sharepoint.com/sites/' + $TeamSiteName
|
||||
$DocumentLibrary = '/shared documents'
|
||||
|
||||
# Channels
|
||||
# Config Variables
|
||||
$FolderNames = '01-Management', '02-Developement', '03-Marketing', '04-Finance'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
#sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# 01-Management
|
||||
# Config Variables
|
||||
$FolderNames = 'Meetings', 'Presentations'
|
||||
$RelativeURL = $DocumentLibrary + '/01-management' #Relative URL of the Parent Folder
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# 02-Developement
|
||||
# Config Variables
|
||||
$FolderNames = 'Design', 'Specs', 'Labeling'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary + '/02-Developement'
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Subfolder
|
||||
$FolderNames = 'Sketches', 'Requirements'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary + '/02-Developement/Design'
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# 03-Marketing
|
||||
# Config Variables
|
||||
$FolderNames = 'Communication Brief', 'Competitor Review', 'Consumer Insights', 'Product FAQ', 'Product Information', 'Product Strategy'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary + '/03-Marketing'
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# 04-Finance
|
||||
# Config Variables
|
||||
$FolderNames = 'Budget', 'Presentations'
|
||||
|
||||
# Relative URL of the Parent Folder
|
||||
$RelativeURL = $DocumentLibrary + '/04-Finance'
|
||||
|
||||
try
|
||||
{
|
||||
# Connect to PNP Online
|
||||
$null = (Connect-PnPOnline -Url $SiteURL -Credentials $Cred)
|
||||
|
||||
# sharepoint online create folder powershell
|
||||
foreach ($Folder in $FolderNames)
|
||||
{
|
||||
$paramAddPnPFolder = @{
|
||||
Name = $Folder
|
||||
Folder = $RelativeURL
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$null = (Add-PnPFolder @paramAddPnPFolder)
|
||||
|
||||
Write-Verbose -Message ("New Folder '{0}' Added!" -f $Folder)
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
300
Powershell/PowerShell-collection/MicrosoftTeams/RemoveWiki.ps1
Normal file
300
Powershell/PowerShell-collection/MicrosoftTeams/RemoveWiki.ps1
Normal file
@@ -0,0 +1,300 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Remove the Wiki tab on Microsoft Teams teams
|
||||
|
||||
.DESCRIPTION
|
||||
Remove the Wiki tab on Microsoft Teams teams
|
||||
I like Teams, but I never use the Wiki within Teams.
|
||||
Alexander Holmeset figured out a smart way to get rid of the Wiki tab.
|
||||
|
||||
.PARAMETER ClientId
|
||||
Azure AD Application (client) ID
|
||||
|
||||
.PARAMETER TenantId
|
||||
Azure AD Tenant ID
|
||||
|
||||
.PARAMETER ClientSecret
|
||||
Azure AD secret
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\RemoveWiki.ps1 -ClientId 'Value1' -TenantId 'Value2' -ClientSecret 'Value3'
|
||||
|
||||
.NOTES
|
||||
Original found in Alexander Holmeset's Blog
|
||||
My version starts to make it a bit more flexible (e.g. more parameters)
|
||||
|
||||
.LINK
|
||||
https://alexholmeset.blog/2019/05/10/remove-the-wiki-tab/
|
||||
|
||||
.LINK
|
||||
https://gist.github.com/AlexanderHolmeset/e40c7e9297ae9cc01cb832871a9ff770
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0,
|
||||
HelpMessage = 'Azure AD Application (client) ID')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('OAuthClientId')]
|
||||
[string]
|
||||
$ClientId,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 1,
|
||||
HelpMessage = 'Azure AD Tenant ID')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('OAuthTenantId')]
|
||||
[string]
|
||||
$TenantId,
|
||||
[Parameter(Mandatory,
|
||||
ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 2,
|
||||
HelpMessage = 'Azure AD secret')]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('OAuthClientSecret')]
|
||||
[string]
|
||||
$ClientSecret
|
||||
)
|
||||
|
||||
process
|
||||
{
|
||||
# Contruct URI
|
||||
$uri = 'https://login.microsoftonline.com/' + $TenantId + '/oauth2/v2.0/token'
|
||||
|
||||
try
|
||||
{
|
||||
# Construct Body
|
||||
$body1 = @{
|
||||
client_id = $ClientId
|
||||
scope = 'https://graph.microsoft.com/.default'
|
||||
client_secret = $ClientSecret
|
||||
grant_type = 'client_credentials'
|
||||
}
|
||||
|
||||
# Get OAuth 2.0 Token
|
||||
$paramInvokeWebRequest = @{
|
||||
Method = 'Post'
|
||||
Uri = $uri
|
||||
ContentType = 'application/x-www-form-urlencoded'
|
||||
Body = $body1
|
||||
ErrorAction = 'Stop'
|
||||
UseBasicParsing = $true
|
||||
}
|
||||
$tokenRequest = (Invoke-WebRequest @paramInvokeWebRequest)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the Token
|
||||
$token = ($tokenRequest.Content | ConvertFrom-Json).access_token
|
||||
|
||||
# Just in case
|
||||
Write-Verbose -Message $token
|
||||
|
||||
try
|
||||
{
|
||||
# URI to call
|
||||
$uri = 'https://graph.microsoft.com/v1.0/groups'
|
||||
$paramInvokeRestMethod = @{
|
||||
Method = 'GET'
|
||||
Uri = $uri
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
$query = (Invoke-RestMethod @paramInvokeRestMethod)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Stop'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
|
||||
# Extract the Value
|
||||
$groups = $query.value
|
||||
|
||||
foreach ($group in $groups)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ($group.resourceProvisioningOptions -contains 'Team')
|
||||
{
|
||||
# Extract the ID
|
||||
$id = $group.id
|
||||
|
||||
# Build the URI
|
||||
$uri2 = 'https://graph.microsoft.com/v1.0/teams/' + $id + '/channels'
|
||||
|
||||
$paramInvokeRestMethod = @{
|
||||
Method = 'Get'
|
||||
Uri = $uri2
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
}
|
||||
$query2 = (Invoke-RestMethod @paramInvokeRestMethod)
|
||||
|
||||
# Extract the Value
|
||||
$Channels = $query2.value
|
||||
|
||||
foreach ($Channel in $Channels)
|
||||
{
|
||||
$id2 = $Channel.id
|
||||
$uri3 = 'https://graph.microsoft.com/v1.0/teams/' + $id + '/channels/' + $id2 + '/tabs'
|
||||
$paramInvokeRestMethod = @{
|
||||
Method = 'Get'
|
||||
Uri = $uri3
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
}
|
||||
$query3 = (Invoke-RestMethod @paramInvokeRestMethod)
|
||||
|
||||
# Extract the Value
|
||||
$tabs = $query3.value
|
||||
|
||||
# Find the Wiki Tab
|
||||
$WikiTabs = ($tabs | Where-Object -FilterScript {
|
||||
$_.displayname -eq 'Wiki'
|
||||
})
|
||||
|
||||
if ($WikiTabs)
|
||||
{
|
||||
foreach ($wikitab in $WikiTabs)
|
||||
{
|
||||
# Extract the ID
|
||||
$wikitabID = $wikitab.id
|
||||
|
||||
# Build the URI
|
||||
$uri4 = 'https://graph.microsoft.com/v1.0/teams/' + $id + '/channels/' + $id2 + '/tabs/' + $wikitabID
|
||||
|
||||
$paramInvokeRestMethod = @{
|
||||
Method = 'DELETE'
|
||||
Uri = $uri4
|
||||
ContentType = 'application/json'
|
||||
Headers = @{
|
||||
Authorization = 'Bearer ' + $token
|
||||
}
|
||||
}
|
||||
$query4 = (Invoke-RestMethod @paramInvokeRestMethod)
|
||||
|
||||
Write-Verbose -Message $query4
|
||||
|
||||
Write-Output -InputObject 'wikitab removed'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
# get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# output information. Post-process collected info, and log info (optional)
|
||||
$info | Out-String | Write-Verbose
|
||||
|
||||
$paramWriteError = @{
|
||||
Message = $e.Exception.Message
|
||||
ErrorAction = 'Continue'
|
||||
Exception = $e.Exception
|
||||
TargetObject = $e.CategoryInfo.TargetName
|
||||
}
|
||||
Write-Error @paramWriteError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,131 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Replace the Domain for all UnifiedGroups (and Microsoft Teams) Primary SMTP Address
|
||||
|
||||
.DESCRIPTION
|
||||
Replace the Domain for all UnifiedGroups (and Microsoft Teams) Primary SMTP Address
|
||||
|
||||
.PARAMETER OldDomain
|
||||
The old Domain (e.g. contoso.com)
|
||||
|
||||
.PARAMETER NewDomain
|
||||
The new Domain (e.g. contoso.net)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\ReplaceDomainForAllUnifiedGroups.ps1 -OldDomain 'contoso.com' -NewDomain 'contoso.net'
|
||||
|
||||
Replace the Primary SMTP Addresses for all UnifiedGroups (and Microsoft Teams) that are in the domain 'contoso.com' with the someone in the Domain 'contoso.net'
|
||||
e.g. if an old address was myTeam@contoso.com would end up as myTeam@contoso.new
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps
|
||||
|
||||
.LINK
|
||||
http://hochwald.net
|
||||
|
||||
.NOTES
|
||||
Quick and dirty approach, without any real Error handling.
|
||||
A friend asked me for a solution after a merger to replace all Primary SMTP Addresses and get rid of the old domain (legal requirement in this case)
|
||||
|
||||
You need be be connected to an Exchange Online Session (NOT part of this script).
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess = $true)]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true,
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias('DomainToReplace')]
|
||||
[string]
|
||||
$OldDomain,
|
||||
[Parameter(Mandatory = $true,
|
||||
ValueFromPipeline = $true,
|
||||
ValueFromPipelineByPropertyName = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$NewDomain
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$OldMailFilter = ('@' + $OldDomain)
|
||||
|
||||
# Cleanup
|
||||
$AllUnifiedGroups = $null
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
$AllUnifiedGroups = (Get-UnifiedGroup | Where-Object -FilterScript {
|
||||
$_.PrimarySmtpAddress -like ('*' + $OldMailFilter)
|
||||
} | Select-Object -Property Identity, DisplayName, PrimarySmtpAddress)
|
||||
|
||||
if ($AllUnifiedGroups)
|
||||
{
|
||||
foreach ($item in $AllUnifiedGroups)
|
||||
{
|
||||
if ($item.PrimarySmtpAddress -like ('*' + $OldMailFilter))
|
||||
{
|
||||
$OldMailAddress = $null
|
||||
$OldMailAddress = (($item).PrimarySmtpAddress)
|
||||
|
||||
$NewMailAddress = $null
|
||||
$NewMailAddress = ($OldMailAddress.Replace($OldMailFilter, ('@' + $NewDomain)))
|
||||
Write-Verbose -Message ('Replace: {0} with: {1}' -f $OldMailAddress, $NewMailAddress)
|
||||
|
||||
# Add the new Address
|
||||
$null = (Set-UnifiedGroup -Identity (($item).Identity) -EmailAddresses: @{
|
||||
Add = $NewMailAddress
|
||||
} -Confirm:$false)
|
||||
|
||||
# Make new Address the primary SMTP address
|
||||
$null = (Set-UnifiedGroup -Identity (($item).Identity) -PrimarySmtpAddress $NewMailAddress -Confirm:$false)
|
||||
|
||||
# Remove the old SMTP Address
|
||||
$null = (Set-UnifiedGroup -Identity (($item).Identity) -EmailAddresses: @{
|
||||
Remove = $OldMailAddress
|
||||
} -Confirm:$false)
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message ('Sorry, the PrimarySmtpAddress of {0} is not in {1}' -f $item.DisplayName, $OldDomain)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output -InputObject 'Nothing to do!!!'
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,210 @@
|
||||
#requires -Version 3.0 -Modules NetQos -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Apply QoS Settings for Microsoft Teams
|
||||
|
||||
.DESCRIPTION
|
||||
Apply Network Quality of Service (QoS) settings for Microsoft Teams.
|
||||
|
||||
.PARAMETER AppPathNameMatchCondition
|
||||
Specifies the name by which an application is run, such as application.exe or %ProgramFiles%\application.exe application.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-QoSForMicrosoftTeams.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-QoSForMicrosoftTeamsRoom.ps1 -AppPathNameMatchCondition 'Teams.exe'
|
||||
|
||||
.NOTES
|
||||
Changelog:
|
||||
1.0.0: Initial Release (Adopted from Set-QoSForMicrosoftTeamsRoomDevices.ps1)
|
||||
|
||||
Version 1.0.0
|
||||
|
||||
.LINK
|
||||
Get-NetQosPolicy
|
||||
|
||||
.LINK
|
||||
New-NetQosPolicy
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/microsoftteams/qos-in-teams-clients
|
||||
|
||||
.LINK
|
||||
http://enatec.io
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('AppName')]
|
||||
[string]
|
||||
$AppPathNameMatchCondition = 'Teams.exe'
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
Write-Output -InputObject 'Apply Network Quality of Service (QoS) settings for Microsoft Teams'
|
||||
|
||||
#region Defaults
|
||||
$CNT = 'Continue'
|
||||
$STP = 'Stop'
|
||||
$SCT = 'SilentlyContinue'
|
||||
|
||||
[string]$AppSharingPolicy = 'Microsoft Teams AppSharing'
|
||||
[string]$VideoPolicy = 'Microsoft Teams Video'
|
||||
[string]$AudioPoliy = 'Microsoft Teams Audio'
|
||||
#endregion Defaults
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('QoS-Settings', 'Apply'))
|
||||
{
|
||||
#region Audio
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $AudioPoliy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50000
|
||||
IPSrcPortEndMatchCondition = 50019
|
||||
DSCPAction = 46
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $AudioPoliy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $AudioPoliy)
|
||||
}
|
||||
}
|
||||
#endregion Audio
|
||||
|
||||
#region Video
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $VideoPolicy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50020
|
||||
IPSrcPortEndMatchCondition = 50039
|
||||
DSCPAction = 34
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $VideoPolicy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $VideoPolicy)
|
||||
}
|
||||
}
|
||||
#endregion Video
|
||||
|
||||
#region AppSharing
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $AppSharingPolicy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50040
|
||||
IPSrcPortEndMatchCondition = 50059
|
||||
DSCPAction = 28
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $AppSharingPolicy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $AppSharingPolicy)
|
||||
}
|
||||
}
|
||||
#endregion AppSharing
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,203 @@
|
||||
#requires -Version 3.0 -Modules NetQos -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Apply QoS Settings for Microsoft Teams Room Devices
|
||||
|
||||
.DESCRIPTION
|
||||
Apply Network Quality of Service (QoS) settings for Microsoft Teams Room Devices.
|
||||
I use this script to deploy the QoS settings to MTR devices via Intune.
|
||||
|
||||
.PARAMETER AppPathNameMatchCondition
|
||||
Specifies the name by which an application is run, such as application.exe or %ProgramFiles%\application.exe application.
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-QoSForMicrosoftTeamsRoomDevices.ps1
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> .\Set-QoSForMicrosoftTeamsRoomDevices.ps1 -AppPathNameMatchCondition 'Teams.exe'
|
||||
|
||||
.NOTES
|
||||
Idea based on a Twitter chat with @StaleHansen
|
||||
|
||||
Please ensure to check the Ports!
|
||||
They must match you Teams Admin Centr (TAC) settings.
|
||||
|
||||
.LINK
|
||||
Get-NetQosPolicy
|
||||
|
||||
.LINK
|
||||
New-NetQosPolicy
|
||||
|
||||
.LINK
|
||||
https://docs.microsoft.com/en-us/microsoftteams/qos-in-teams-clients
|
||||
|
||||
.LINK
|
||||
https://twitter.com/StaleHansen/status/1294341225647083522
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low',
|
||||
SupportsShouldProcess)]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName)]
|
||||
[Alias('AppName')]
|
||||
[string]
|
||||
$AppPathNameMatchCondition = $null
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
$AppSharingPolicy = 'MTR AppSharing'
|
||||
$VideoPolicy = 'MTR Video'
|
||||
$AudioPoliy = 'MTR Audio'
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($pscmdlet.ShouldProcess('QoS-Settings', 'Apply'))
|
||||
{
|
||||
#region Audio
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $AudioPoliy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50000
|
||||
IPSrcPortEndMatchCondition = 50019
|
||||
DSCPAction = 46
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $AudioPoliy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $AudioPoliy)
|
||||
}
|
||||
}
|
||||
#endregion Audio
|
||||
|
||||
#region Video
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $VideoPolicy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50020
|
||||
IPSrcPortEndMatchCondition = 50039
|
||||
DSCPAction = 34
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $VideoPolicy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $VideoPolicy)
|
||||
}
|
||||
}
|
||||
#endregion Video
|
||||
|
||||
#region AppSharing
|
||||
$paramGetNetQosPolicy = @{
|
||||
Name = $AppSharingPolicy
|
||||
ErrorAction = $SCT
|
||||
WarningAction = $SCT
|
||||
}
|
||||
if (-not (Get-NetQosPolicy @paramGetNetQosPolicy))
|
||||
{
|
||||
try
|
||||
{
|
||||
# Splat the parameters
|
||||
$paramNewNetQosPolicy = @{
|
||||
NetworkProfile = 'All'
|
||||
IPSrcPortStartMatchCondition = 50040
|
||||
IPSrcPortEndMatchCondition = 50059
|
||||
DSCPAction = 28
|
||||
IPProtocolMatchCondition = 'Both'
|
||||
Name = $AppSharingPolicy
|
||||
Confirm = $false
|
||||
WarningAction = $CNT
|
||||
ErrorAction = $STP
|
||||
}
|
||||
|
||||
# Do we have an application name?
|
||||
if ($AppPathNameMatchCondition)
|
||||
{
|
||||
$paramNewNetQosPolicy.Add('AppPathNameMatchCondition', $AppPathNameMatchCondition)
|
||||
}
|
||||
|
||||
$null = (New-NetQosPolicy @paramNewNetQosPolicy)
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Warning -Message ('Unable to apply {0} QoS Poliy' -f $AppSharingPolicy)
|
||||
}
|
||||
}
|
||||
#endregion AppSharing
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,128 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Create a Microsoft Teams Room Device in Office 365
|
||||
|
||||
.DESCRIPTION
|
||||
Create and setup a Microsoft Teams Room Device in Microsoft Office 365
|
||||
|
||||
.NOTES
|
||||
Review the variable here.
|
||||
|
||||
You must be connected to the following Services:
|
||||
- Exchange Online
|
||||
- MSOL (Not AzureAD!)
|
||||
- Skype for Business Online (Not Teams!)
|
||||
|
||||
.LINK
|
||||
https://hochwald.net/microsoft-teams-room-device-1-2/
|
||||
|
||||
.LINK
|
||||
https://hochwald.net/microsoft-teams-room-device-2-2/
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param ()
|
||||
|
||||
# Display Name of the Room
|
||||
$RoomName = 'Your-Teams-Room'
|
||||
|
||||
# Alias of the Room (For the UPN, SMTP, and SIP Address)
|
||||
$RoomAlias = 'YourTeamsRoom'
|
||||
|
||||
# Keep this safe
|
||||
$RoomPassword = 'YourSuperSecretRoomPassword'
|
||||
<#
|
||||
At the moment, the password for a room/resource will never expire!
|
||||
So keep this in a safe place. And there is no second factor (MFA).
|
||||
#>
|
||||
|
||||
# The Domain for the UPN, and the SMTP address
|
||||
$RoomDomain = 'contoso.com'
|
||||
|
||||
# The Response text for meeting requests
|
||||
$RoomAdditionalResponse = 'This is a Microsoft Teams Team Room'
|
||||
<#
|
||||
Basic HTML is supported here!
|
||||
This text will be in the meeting respoinse mail, so use it as a info or teaser
|
||||
#>
|
||||
|
||||
# The ALIAS of the license to apply.
|
||||
# In this case it is the MEETING_ROOM License in the tenant with the name contoso
|
||||
$RoomLicence = 'contoso:MEETING_ROOM'
|
||||
<#
|
||||
The license must be availible (Buy it before create the room)
|
||||
#>
|
||||
|
||||
# We need one User that we use to find the SIP Registrar Pool (For Skype for Business and Teams SIP handling)
|
||||
$CsOnlineUser = 'john.doe'
|
||||
|
||||
#region AutomatedStrings
|
||||
# Build some strings
|
||||
$RoomUserPrincipalName = ($RoomAlias + '@' + $RoomDomain)
|
||||
$CsOnlineUserTemplate = ($CsOnlineUser + '@' + $RoomDomain)
|
||||
<#
|
||||
I use the same domain for the UPN and the SMTP/SIP address,
|
||||
and I highly recommend you to do the same!
|
||||
#>
|
||||
#endregion AutomatedStrings
|
||||
|
||||
#region NewMailbox
|
||||
# Create the Mailbox
|
||||
$paramNewMailbox = @{
|
||||
Name = $RoomName
|
||||
Alias = $RoomAlias
|
||||
Room = $true
|
||||
EnableRoomMailboxAccount = $true
|
||||
MicrosoftOnlineServicesID = $RoomUserPrincipalName
|
||||
RoomMailboxPassword = (ConvertTo-SecureString -String $RoomPassword -AsPlainText -Force)
|
||||
}
|
||||
New-Mailbox @paramNewMailbox
|
||||
#endregion NewMailbox
|
||||
|
||||
#region SetCalendarProcessing
|
||||
# Tweak Calendar settings
|
||||
$paramSetCalendarProcessing = @{
|
||||
Identity = $RoomName
|
||||
AutomateProcessing = 'AutoAccept'
|
||||
AddOrganizerToSubject = $false
|
||||
DeleteComments = $false
|
||||
DeleteSubject = $false
|
||||
RemovePrivateProperty = $false
|
||||
AddAdditionalResponse = $true
|
||||
AdditionalResponse = $RoomAdditionalResponse
|
||||
}
|
||||
Set-CalendarProcessing @paramSetCalendarProcessing
|
||||
<#
|
||||
Please review the parameters above!
|
||||
They might not match your taste or requirements
|
||||
You can add more: Use 'Get-Help Set-CalendarProcessing -details' to see all supported paramaters
|
||||
#>
|
||||
#endregion SetCalendarProcessing
|
||||
|
||||
#region SetMsolUser
|
||||
# Usage location and password tweak
|
||||
$paramSetMsolUser = @{
|
||||
UserPrincipalName = $RoomUserPrincipalName
|
||||
PasswordNeverExpires = $true
|
||||
UsageLocation = 'DE'
|
||||
}
|
||||
Set-MsolUser @paramSetMsolUser
|
||||
#endregion SetMsolUser
|
||||
|
||||
#region SetMsolUserLicense
|
||||
# Apply the license
|
||||
$paramSetMsolUserLicense = @{
|
||||
UserPrincipalName = $RoomUserPrincipalName
|
||||
AddLicenses = $RoomLicence
|
||||
}
|
||||
Set-MsolUserLicense @paramSetMsolUserLicense
|
||||
#endregion SetMsolUserLicense
|
||||
|
||||
#region EnableCsMeetingRoom
|
||||
# Enable SIP (Skype for Business/Teams)
|
||||
$paramEnableCsMeetingRoom = @{
|
||||
Identity = $RoomUserPrincipalName
|
||||
RegistrarPool = (Get-CsOnlineUser -Identity $CsOnlineUserTemplate | Select-Object -ExpandProperty RegistrarPool)
|
||||
SipAddressType = 'EmailAddress'
|
||||
}
|
||||
Enable-CsMeetingRoom @paramEnableCsMeetingRoom
|
||||
#endregion EnableCsMeetingRoom
|
||||
@@ -0,0 +1,227 @@
|
||||
function Update-UnifiedGroupsToTeams
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Converts all Microsoft Office 365 Groups into a new Microsoft Teams Team
|
||||
|
||||
.DESCRIPTION
|
||||
Converts all Microsoft Office 365 Groups into a new Microsoft Teams Team
|
||||
Microsoft Office 365 Groups are also known as Unified Office 365 Groups
|
||||
|
||||
.PARAMETER ReportOnly
|
||||
Shows a list of Microsoft Office 365 Groups that would be migrated to a new Microsoft Teams Team.
|
||||
This is a DryRun only!
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Update-UnifiedGroupsToTeams
|
||||
|
||||
Converting all Microsoft Office 365 Groups into a new Microsoft Teams Team
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Update-UnifiedGroupsToTeams -ReportOnly
|
||||
|
||||
Do a DryRun (Just get a List of Unified Groups that do NOT have a Microsoft Teams Team)
|
||||
|
||||
.EXAMPLE
|
||||
PS C:\> Compare-Object -ReferenceObject ((Get-Team | Select-Object -ExpandProperty GroupId)) -DifferenceObject ((Get-UnifiedGroup -ResultSize Unlimited | Select-Object -ExpandProperty ExternalDirectoryObjectId)) -PassThru
|
||||
|
||||
Get a short difference list (this function is not required to do so)
|
||||
|
||||
.NOTES
|
||||
Releasenotes:
|
||||
1.0.1 2019-04-21: Add a bit more error handling
|
||||
1.0.0 2018-04-14: Internal Release
|
||||
|
||||
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
|
||||
|
||||
Dependencies:
|
||||
The script depends on Microsoft's Version 0.9.6, or newer, of the MicrosoftTeams PowerShell Module
|
||||
|
||||
Install it with PowerShellGet:
|
||||
PS C:\> Install-Module MicrosoftTeams
|
||||
|
||||
You need to be connected to Office 365 (Exchange Online). The function will check that.
|
||||
|
||||
.LINK
|
||||
https://www.powershellgallery.com/packages/MicrosoftTeams/0.9.6
|
||||
|
||||
.LINK
|
||||
https://aka.ms/InstallModule
|
||||
#>
|
||||
[CmdletBinding(ConfirmImpact = 'Low')]
|
||||
param
|
||||
(
|
||||
[Parameter(ValueFromPipeline,
|
||||
ValueFromPipelineByPropertyName,
|
||||
Position = 0)]
|
||||
[Alias('DryRun')]
|
||||
[switch]
|
||||
$ReportOnly
|
||||
)
|
||||
|
||||
begin
|
||||
{
|
||||
#region Defaults
|
||||
$CNT = 'Continue'
|
||||
$STP = 'Stop'
|
||||
#endregion Defaults
|
||||
|
||||
try
|
||||
{
|
||||
#region ConnectionCheck
|
||||
if (-not (Get-Command -Name Get-UnifiedGroup -ErrorAction SilentlyContinue))
|
||||
{
|
||||
$ErrorParameter = @{
|
||||
Message = 'Please connect to Office 365/Exchange Online before using this function!'
|
||||
Category = 'ResourceUnavailable'
|
||||
RecommendedAction = 'Connect to Office 365/Exchange Online before using this function'
|
||||
ErrorAction = $STP
|
||||
}
|
||||
Write-Error @ErrorParameter
|
||||
}
|
||||
#endregion ConnectionCheck
|
||||
|
||||
#region GetUnifiedGroups
|
||||
$GetUnifiedGroupParameter = @{
|
||||
ResultSize = 'Unlimited'
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$AllOffice365UnifiedGroups = (Get-UnifiedGroup @GetUnifiedGroupParameter | Select-Object -Property DisplayName, ExternalDirectoryObjectId)
|
||||
#endregion GetUnifiedGroups
|
||||
|
||||
#region GetMicrosoftTeams
|
||||
$GetTeamParameter = @{
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$AllMicrosoftTeams = (Get-Team @GetTeamParameter | Select-Object -ExpandProperty GroupId)
|
||||
#endregion GetMicrosoftTeams
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# Retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
# Dump the FULL error record
|
||||
Write-Warning -Message ($info | Out-String)
|
||||
|
||||
Write-Error -Message $info.Exception -Exception $info.Exception -ErrorAction $STP
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
process
|
||||
{
|
||||
if ($AllOffice365UnifiedGroups)
|
||||
{
|
||||
#region Loop
|
||||
foreach ($Office365UnifiedGroup in $AllOffice365UnifiedGroups)
|
||||
{
|
||||
if (-not ($AllMicrosoftTeams -match $Office365UnifiedGroup.ExternalDirectoryObjectId))
|
||||
{
|
||||
if ($ReportOnly)
|
||||
{
|
||||
#region ReportOnly
|
||||
$SingleOffice365UnifiedGroup = $Office365UnifiedGroup.DisplayName
|
||||
Write-Output -InputObject ('Microsoft Teams for Unified Group {0} is missing' -f $SingleOffice365UnifiedGroup)
|
||||
#endregion ReportOnly
|
||||
}
|
||||
else
|
||||
{
|
||||
#region CreateMissingTeam
|
||||
Write-Verbose -Message ('Create Microsoft Teams Team for Unified Group {0}' -f $SingleOffice365UnifiedGroup)
|
||||
|
||||
try
|
||||
{
|
||||
$NewTeamParameter = @{
|
||||
Group = $Office365UnifiedGroup
|
||||
ErrorAction = $STP
|
||||
WarningAction = $CNT
|
||||
}
|
||||
$NewTeam = (New-Team @NewTeamParameter)
|
||||
|
||||
Write-Debug -Message $NewTeam
|
||||
|
||||
Write-Verbose -Message ('Created Microsoft Teams Team for Unified Group {0}' -f $SingleOffice365UnifiedGroup)
|
||||
}
|
||||
catch
|
||||
{
|
||||
# Get error record
|
||||
[Management.Automation.ErrorRecord]$e = $_
|
||||
|
||||
# Retrieve information about runtime error
|
||||
$info = [PSCustomObject]@{
|
||||
Exception = $e.Exception.Message
|
||||
Reason = $e.CategoryInfo.Reason
|
||||
Target = $e.CategoryInfo.TargetName
|
||||
Script = $e.InvocationInfo.ScriptName
|
||||
Line = $e.InvocationInfo.ScriptLineNumber
|
||||
Column = $e.InvocationInfo.OffsetInLine
|
||||
}
|
||||
|
||||
$TheException = $info.Exception
|
||||
|
||||
Write-Warning -Message ('Microsoft Teams creation for {0} failed with {1} ' -f $SingleOffice365UnifiedGroup, $TheException)
|
||||
|
||||
# Dump the FULL error record
|
||||
Write-Verbose -Message ($info | Out-String)
|
||||
}
|
||||
#endregion CreateMissingTeam
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Loop
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Warning -Message 'No Unified Groups found in your Tenant...'
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
{
|
||||
Write-Verbose -Message 'Done.'
|
||||
}
|
||||
}
|
||||
|
||||
#region LICENSE
|
||||
<#
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2021, enabling Technology
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#>
|
||||
#endregion LICENSE
|
||||
|
||||
#region DISCLAIMER
|
||||
<#
|
||||
DISCLAIMER:
|
||||
- Use at your own risk, etc.
|
||||
- This is open-source software, if you find an issue try to fix it yourself. There is no support and/or warranty in any kind
|
||||
- This is a third-party Software
|
||||
- The developer of this Software is NOT sponsored by or affiliated with Microsoft Corp (MSFT) or any of its subsidiaries in any way
|
||||
- The Software is not supported by Microsoft Corp (MSFT)
|
||||
- By using the Software, you agree to the License, Terms, and any Conditions declared and described above
|
||||
- If you disagree with any of the terms, and any conditions declared: Just delete it and build your own solution
|
||||
#>
|
||||
#endregion DISCLAIMER
|
||||
@@ -0,0 +1,23 @@
|
||||
# Use the latest Microsoft Teams PowerShell Module to connect
|
||||
# Not the Skype for Business Online Module (outdated)
|
||||
|
||||
# Get all Teams Meeting Policies
|
||||
Get-CsTeamsMeetingPolicy | Select-Object -ExpandProperty Identity
|
||||
|
||||
# Get all Teams Meeting Policies, exclude all TAG Policies (You can not modify them with Get-CsTeamsMeetingPolicy)
|
||||
Get-CsTeamsMeetingPolicy | Where-Object -FilterScript {
|
||||
$_.Identity -notlike 'Tag:*'
|
||||
} | Select-Object -ExpandProperty Identity
|
||||
|
||||
# Modify the Global Policy
|
||||
Set-CsTeamsMeetingPolicy -Identity Global -AllowEngagementReport Enabled
|
||||
|
||||
# Modify any Policy by name
|
||||
Set-CsTeamsMeetingPolicy -Identity 'Meetings' | Set-CsTeamsMeetingPolicy -AllowEngagementReport Enabled
|
||||
|
||||
# Modify all Policies (exclude the TAG Policies, because you can not modify them with Get-CsTeamsMeetingPolicy)
|
||||
Get-CsTeamsMeetingPolicy | Where-Object -FilterScript {
|
||||
$_.Identity -notlike 'Tag:*'
|
||||
} | ForEach-Object -Process {
|
||||
Set-CsTeamsMeetingPolicy -Identity $_.Identity -AllowEngagementReport Enabled -ErrorAction Continue
|
||||
}
|
||||
Reference in New Issue
Block a user