Added Files

This commit is contained in:
DistractADD
2021-07-06 13:16:46 +10:00
parent f2475a3bdd
commit cfddd4fad2
393 changed files with 65842 additions and 0 deletions

View File

@@ -0,0 +1,172 @@
<#
.SYNOPSIS
Allows you to collect the Lync/Skype for Business Client logs and puts them
in a Zip file on your desktop.
.DESCRIPTION
This script identifies which version of Lync 2013 or Skype for Business 2015/2016
client that you are using to identify where the Tracing folder is stored. Then
it checks to see if the lync.exe is running. If so, it prompts you to exit the
client so that it can zip the complete tracing folder and place it on your desktop.
.EXAMPLE
.\Collect-CsClientLogs.ps1
This will collect the logs and put them on your desktop in a file named Tracing_DATETIME.zip
.NOTES
The client tracing logs contain personally identifiable information or PII. If
you are sending these logs to someone for analysis, do not send it in any manner
that isn't encrypted with SSL or TLS. Email is not a secure way to transfer
this data.
This script DOES NOT work with Lync 2010. Lync 2010 Client logs are in %UserProfile%\Tracing
#>
Function getDateTimeForFileName
{
$DT = (Get-Date)
$FileNameAddition = '_'
$FileNameAddition += ($DT.Month).ToString('00') + '-'
$FileNameAddition += ($DT.Day).ToString('00') + '-'
$FileNameAddition += ($DT.Year).ToString('0000') + '_'
$FileNameAddition += ($DT.Hour).ToString('00') + '.'
$FileNameAddition += ($DT.Minute).ToString('00') + '.'
$FileNameAddition += ($DT.Second).ToString('00')
Return $FileNameAddition
}
# Show PII Warning
Write-Warning -Message "The client tracing logs contain personally identifiable information or PII. If you are sending these logs to someone for analysis, do not send it in any manner that isn't encrypted with SSL or TLS. Email is not a secure way to transfer this data."
$Answer = Read-Host -Prompt 'Type YES and hit [Enter] if you understand this warning'
If (-not ($Answer -eq 'yes'))
{
Write-Warning -Message "You did not type `"Yes`" to the above warning. Script has ended and no data has been collected"
Break
}
# Stop Lync and Skype from Running
Write-Warning -Message 'The following programs must be closed: Outlook, and Skype for Business. Please close them now.'
$Answer2 = Read-Host -Prompt 'Are Skype for Business and Outlook closed? YES or NO?'
while ($Answer2 -ne 'yes')
{
Write-Output -InputObject "Please close the programs and confirm with 'YES'"
$Answer2 = Read-Host -Prompt 'Waiting for answer: '
}
# Turn off the proceesses on the machine. These lines will forcibly kill the programs.
$OutlookProcess = (Get-Process -Name Outlook -ErrorVariable OutlookError -ErrorAction SilentlyContinue)
if ($OutlookProcess -ne $null)
{
$OutlookProcess.CloseMainWindow()
}
$LyncPS = (Get-Process -Name lync* -ErrorVariable LyncError -ErrorAction SilentlyContinue)
if ($LyncPS -ne $null)
{
$LyncPS.CloseMainWindow()
}
# Figure out which Lync/Skype version is being used.
$OfficeInstalls = Get-ChildItem -Path hklm:\software\microsoft\windows\currentversion\uninstall | ForEach-Object -Process {
Get-ItemProperty -Path $_.pspath
} | Where-Object -FilterScript {
($_.displayname -match 'Office') -and ($_.InstallLocation.Length -gt 1)
}
$Found = $False
ForEach ($Path in $OfficeInstalls.InstallLocation)
{
$File = Get-ChildItem -Path $Path -Filter 'Lync.exe' -Recurse
If ($File.Name.Length -gt 0)
{
$LyncVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($File.FullName).FileVersion
$LyncPath = $File.FullName
$Found = $true
}
}
If ($Found)
{
$Version = $LyncVersion.Substring(0, 4)
}
# Set the Tracing Folder Path
$LogPath = ($env:USERPROFILE + '\AppData\Local\Microsoft\Office\' + $Version + '\Lync\Tracing')
if (Test-Path -Path $LogPath)
{
# Check to see if Lync.exe is running.
$LyncPID = ((Get-WmiObject -Class win32_process | Where-Object -FilterScript {
($_.ProcessName -eq 'lync.exe') -and ($_.GetOwner().User -eq $env:USERNAME)
}).ProcessID)
$LyncProcess = (Get-Process -Id $LyncPID -ErrorAction SilentlyContinue)
While ($LyncProcess.ProcessName.Length -ne 0)
{
# If Running Prompt to Exit Lync.exe
Write-Warning -Message 'Lync/Skype is still running'
Write-Output -InputObject 'Please Exit Lync/Skype and press Any Key to continue...'
$null = ($Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown'))
$LyncProcess = (Get-Process -Id $LyncPID -ErrorAction SilentlyContinue)
}
# Compress entire Tracing Folder and place on Desktop (Filename with DateTimeStamp in name)
$ZipFile = 'Tracing$(getDateTimeForFilename).zip'
Write-Output -InputObject ('Zipping Tracing folder and placing on your Desktop ({0})' -f $ZipFile)
$null = (Add-Type -AssemblyName 'system.io.compression.filesystem')
# Alter the destination
[io.compression.zipfile]::CreateFromDirectory($LogPath, "$env:USERPROFILE\Desktop\$ZipFile")
Write-Output -InputObject 'Log Collection Complete.'
Write-Output -InputObject "Press `"Y`" to Launch the Lync/Skype Client. Hit any other key to quit."
$Answer = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
If ($Answer.VirtualKeyCode -eq 89)
{
. "$LyncPath"
}
}
else
{
Write-Output -InputObject "Cannot find Tracing folder path ($LogPath)"
Write-Output -InputObject 'This might be because you have never launched Lync or the Script detected the wrong version'
Write-Output -InputObject 'You are going to have to manually collect the logs'
}
#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

View File

@@ -0,0 +1,278 @@
#requires -Version 3.0
<#
.SYNOPSIS
List all active Lync/Skype for Business conferences
.DESCRIPTION
List all active Lync/Skype for Business conferences
.PARAMETER FrontendPool
Please enter the Lync/Skype for Business Frontend Pool FQDN
.EXAMPLE
PS C:\> .\Get-CsActiveConferences.ps1 -FrontendPool 'atl-cs-001.litwareinc.com'
.NOTES
Originally written by Richard Brynteson
.LINK
https://masteringlync.com/2013/11/19/list-all-active-conferences-via-powershell/
#>
[CmdletBinding(ConfirmImpact = 'None',
SupportsShouldProcess)]
param
(
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 1,
HelpMessage = 'Please enter the Frontend Pool FQDN')]
[ValidateNotNullOrEmpty()]
[Alias('PoolFQDN')]
[string]
$FrontendPool
)
begin
{
# Convert UTC to Local timezone
function Convert-UTCtoLocal
{
<#
.SYNOPSIS
Convert UTC to Local timezone
.DESCRIPTION
Convert UTC to Local timezone
.PARAMETER UTCTime
UTC Time Format datetime
.EXAMPLE
PS C:\> Convert-UTCtoLocal -UTCTime Value
Convert UTC to Local timezone
.OUTPUTS
datetime
.INPUTS
datetime
.NOTES
Just a small internal Helper Script
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([datetime])]
param
(
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 1,
HelpMessage = 'UTC Time Format datetime')]
[ValidateNotNullOrEmpty()]
[datetime]
$UTCTime
)
begin
{
# Cleanup
$LocalTime = $null
}
process
{
# Transform the Format
$paramGetWmiObject = @{
Class = 'win32_timezone'
ErrorAction = 'Stop'
WarningAction = 'SilentlyContinue'
}
$strCurrentTimeZone = ((Get-WmiObject @paramGetWmiObject).StandardName)
$TZ = [TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone)
$LocalTime = [TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)
}
end
{
# Dump it
return $LocalTime
}
}
# Create a Dummy Object
$Results = @()
}
process
{
if ($pscmdlet.ShouldProcess('FrontendPool', 'Get A List of Computers that are members'))
{
try
{
# Cleanup
$FrontendPoolComputers = $null
# Get all member servers of the Lync pool
$paramGetCsPool = @{
Identity = $FrontendPool
ErrorAction = 'Stop'
WarningAction = 'SilentlyContinue'
}
$FrontendPoolComputers = ((Get-CsPool @paramGetCsPool).Computers)
}
catch
{
# Get error record
[Management.Automation.ErrorRecord]$e = $_
# Retrieve information about the 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
}
# Do some verbose stuff for troubleshooting
$info | Out-String | Write-Verbose
# Thow the error and go...
Write-Error -Message "$info.Exception" -ErrorAction Stop
# This is a point the code should never reach (You told PowerShell to Ignore the ErrorAction above!)
break
# OK, now we have reached a point the we would never, never ever, see
exit 1
}
if (-not $FrontendPoolComputers)
{
# Get error record
[Management.Automation.ErrorRecord]$e = $_
# Retrieve information about the 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
}
# Do some verbose stuff for troubleshooting
$info | Out-String | Write-Verbose
# Thow the error and go...
Write-Error -Message 'No members of the Lync Pool found...' -ErrorAction Stop
# This is a point the code should never reach (You told PowerShell to Ignore the ErrorAction above!)
break
# OK, now we have reached a point the we would never, never ever, see
exit 1
}
}
if ($pscmdlet.ShouldProcess('FrontendPool', 'Get A List of Computers that are members'))
{
#Loop Through Front-End Pool
foreach ($Computer in $FrontendPoolComputers)
{
try
{
# Create the Object with a SQL command
$paramInvokeSQLCmd = @{
ServerInstance = "$Computer\rtclocal"
Database = 'rtcdyn'
Query = "SELECT ActiveConference.ConfId AS 'Conference ID', ActiveConference.Locked, Participant.UserAtHost AS 'Participant', Participant.JoinTime AS 'Join Time', Participant.EnterpriseId, ActiveConference.IsLargeMeeting AS 'Large Meeting' FROM ActiveConference INNER JOIN Participant ON ActiveConference.ConfId = Participant.ConfId;"
ErrorAction = 'Stop'
WarningAction = 'SilentlyContinue'
}
$Result = (Invoke-SQLCmd @paramInvokeSQLCmd)
$Result | Add-Member -NotePropertyName 'Frontend' -NotePropertyValue $Computer
$Result.'Join Time' = Convert-UTCtoLocal -UTCTime $Result.'Join Time'
# Append
$Results += $Result
}
catch
{
# Get error record
[Management.Automation.ErrorRecord]$e = $_
# Retrieve information about the 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
}
# Do some verbose stuff for troubleshooting
$info | Out-String | Write-Verbose
# A simple warning is OK here
Write-Warning -Message "$info.Exception" -WarningAction Continue -ErrorAction Continue
}
}
}
}
end
{
if ($Results)
{
# Dump it
$Results
}
else
{
# Thow the error and go...
Write-Error -Message 'No Results found!' -ErrorAction Stop
# This is a point the code should never reach (You told PowerShell to Ignore the ErrorAction above!)
break
# OK, now we have reached a point the we would never, never ever, see
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

View File

@@ -0,0 +1,119 @@
#requires -Version 1.0
<#
.SYNOPSIS
Find AD disabled Skype for Business Users
.DESCRIPTION
Find accounts that are disabled in the Active Directory but are still Skype for Business enabled
.PARAMETER disable
Should all users that are disbled in the Active Directory also be disabled in Skype for Business
.EXAMPLE
PS C:\> Invoke-FindS4BUsersToDisable
# Find AD disabled Skype for Business Users
.EXAMPLE
PS C:\> Invoke-FindS4BUsersToDisable -disable
# Find and disable AD disabled Skype for Business Users
.NOTES
Be carfull with the -disable switch
It might disable monitoring users and/or Skype enabled resource accounts
#>
param
(
[Parameter(Position = 1)]
[Alias('d')]
[switch]
$disable
)
begin
{
# Define the defaults
$SC = 'SilentlyContinue'
# Cleanup
$S4BUsersToDisable = $null
}
process
{
# Splat
$paramGetCsAdUser = @{
ResultSize = 'Unlimited'
ErrorAction = $SC
WarningAction = $SC
}
$S4BUsersToDisable = (Get-CsAdUser @paramGetCsAdUser | Where-Object -FilterScript {
$_.UserAccountControl -match 'AccountDisabled' -and $_.Enabled -eq $true
} | Select-Object -Property Name, Enabled, SipAddress)
}
end
{
if ($disable)
{
# Disable all user found
foreach ($S4BUserToDisable in $S4BUsersToDisable)
{
Write-Verbose -Message ('We try to disable {0} now' -f $S4BUserToDisable.SipAddress)
try
{
# Splat
$paramDisableCsUser = @{
ErrorAction = 'Stop'
WarningAction = $SC
}
$null = ($S4BUserToDisable.SipAddress | Disable-CsUser @paramDisableCsUser)
Write-Verbose -Message ('The user {0} is now disabled' -f $S4BUserToDisable.SipAddress)
}
catch
{
Write-Warning -Message ('We where unable to disable {0}' -f $S4BUserToDisable.SipAddress)
}
}
}
else
{
# Dump all Users
$S4BUsersToDisable
}
# Cleanup
$S4BUsersToDisable = $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

View 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.

View File

@@ -0,0 +1,824 @@
<#
.SYNOPSIS
Create the S4B Client QoS Group Policy
.DESCRIPTION
Create the Skype for Busines related Quality of Services Client Group Policy
.EXAMPLE
PS C:\> .\Client_GPO.ps1
.EXAMPLE
PS C:\> .\Client_GPO.ps1 -verbose
.NOTES
Check that the ports and port ranges fit your requirements!
The ports and ranges we use here should fit the Skype for Business Online setup
#>
[CmdletBinding()]
param ()
#Requires -RunAsAdministrator
BEGIN
{
#region Variables
# Ports to use for Application Sharing
[string]$AppSharePorts = '50040:50059'
# QoS marking for Application Sharing
[string]$AppShareMark = '24'
# Ports to use for Video
[string]$VideoPorts = '50020:50039'
# QoS marking for Video
[string]$VideoMark = '34'
# Ports to use for Audio
[string]$AudioPorts = '50000:50019'
# QoS marking for Audio
[string]$AudioMark = '46'
# Ports to use for File Transfer
[string]$FileTransferPorts = '5350:5369'
# QoS marking for File Transfer
[string]$FileTransferMark = '14'
# Legacy Media Ports (OCS 2007 R2 Media)
[string]$LegacyMediaPorts = '5370:5389'
# Lync SIP Ports
[string]$LyncSipPorts = '5390:5409'
#endregion Variables
#region Executables
# Executables
[string]$MediaEngineService = 'MediaEngineService.exe'
[string]$mstsc = 'mstsc.exe'
[string]$LyncStore = 'lyncmx.exe'
[string]$Lync = 'lync.exe'
[string]$Communicator = 'communicator.exe'
[string]$AttendantConsole = 'AttendantConsole.exe'
#endregion Executables
#region GroupPolicyInfo
# GPO (Policy) Name
[string]$PolicyName = 'S4B QoS - Client'
# GPO (Policy) Comment
[string]$PolicyComment = 'DSCP markings for Lync/Skype for Business client traffic. This GPO should be applied to all Organizational Units (OUs) containing client machines that will use Lync/Skype for Business.'
#endregion GroupPolicyInfo
#region Defaults
# Define some Defaults
[string]$SC = 'SilentlyContinue'
[string]$STP = 'Stop'
[string]$MinusOne = '-1'
[string]$OneZero = '1.0'
[string]$One = '1'
[string]$WC = '*'
[string]$ThrotRate = 'Throttle Rate'
[string]$DscpVal = 'DSCP Value'
[string]$RemIPLen = 'Remote IP Prefix Length'
[string]$RemIP = 'Remote IP'
[string]$RemPort = 'Remote Port'
[string]$LocIPLen = 'Local IP Prefix Length'
[string]$LocIP = 'Local IP'
[string]$LocPort = 'Local Port'
[string]$Protocol = 'Protocol'
[string]$AppName = 'Application Name'
[string]$Version = 'Version'
[string]$STRG = 'String'
[string]$UserSettingsDisabled = 'UserSettingsDisabled'
[string]$ServicesTcpipQoSName = 'HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\QoS'
[string]$ServicesTcpipQoSValue = 'Do not use NLA'
[string]$Action = 'Update'
[string]$Context = 'Computer'
#endregion Defaults
#region ModuleHandler
try
{
# List of Modules
$Modules = 'ActiveDirectory', 'GroupPolicy'
# Loop over the Module List
foreach ($Module in $Modules)
{
# Import the Module
Write-Verbose -Message ('Importing {0}' -f $Module)
$null = (Import-Module -Name $Module -ErrorAction $STP -WarningAction $SC)
Write-Verbose -Message ('Imported {0}' -f $Module)
}
}
catch
{
# Whoops
Write-Error -Message ('Unable to import the {0} Module, please check your Setup!' -f $Module) -ErrorAction $STP
# We are done here...
break
}
#endregion ModuleHandler
}
PROCESS
{
#region CreateGroupPolicy
try
{
Write-Verbose -Message ('Try to create {0}' -f $PolicyName)
#Cleanup
$paramNewGPO = $null
# Splat reusable parameters
$paramNewGPO = @{
Name = $PolicyName
Comment = $PolicyComment
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
}
$null = (New-GPO @paramNewGPO)
Write-Verbose -Message ('Created {0}' -f $PolicyName)
}
catch
{
Write-Verbose -Message ('The Policy {0} exists' -f $PolicyName)
}
#endregion CreateGroupPolicy
#region ModifyGroupPolicy
try
{
Write-Verbose -Message ('Try to modify {0}' -f $PolicyName)
$null = ((Get-GPO -Name $PolicyName).GpoStatus = $UserSettingsDisabled)
Write-Verbose -Message ('Modified {0}' -f $PolicyName)
}
catch
{
Write-Error -Message ('Unable to modify {0}' -f $PolicyName) -ErrorAction $STP
# We are done here...
break
}
#endregion ModifyGroupPolicy
#region ServicesTcpipQoSName
try
{
Write-Verbose -Message ('Try to Set {0} to {1} {2} in {3}' -f $ServicesTcpipQoSName, $ServicesTcpipQoSValue, $One, $PolicyName)
# Cleanup
$paramSetGPPrefRegistryValue = $null
# Splat reusable parameters
$paramSetGPPrefRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Context = $Context
Key = $ServicesTcpipQoSName
ValueName = $ServicesTcpipQoSValue
Value = $One
Type = $STRG
Action = $Action
}
$null = (Set-GPPrefRegistryValue @paramSetGPPrefRegistryValue)
Write-Verbose -Message ('Set {0} to {1} {2} in {3}' -f $ServicesTcpipQoSName, $ServicesTcpipQoSValue, $One, $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to Set {0} to {1} {2} in {3}' -f $ServicesTcpipQoSName, $ServicesTcpipQoSValue, $One, $PolicyName)
}
#endregion ServicesTcpipQoSName
#region communicator_exe
try
{
Write-Verbose -Message ('Try to set OCS 2007 R2 Media - communicator.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\OCS 2007 R2 Media - communicator.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Communicator, $WC, $LegacyMediaPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set OCS 2007 R2 Media - communicator.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set OCS 2007 R2 Media - communicator.exe in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Lync 2010 Audio QoS - communicator.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2010 Audio QoS - communicator.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Communicator, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2010 Audio QoS - communicator.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync 2010 Audio QoS - communicator.exe in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Lync 2010 Video QoS - communicator.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2010 Video QoS - communicator.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Communicator, $WC, $VideoPorts, $WC, $WC, $WC, $WC, $WC, $VideoMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2010 Video QoS - communicator.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync 2010 Video QoS - communicator.exe in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Lync 2010 Application Sharing QoS - communicator.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2010 Application Sharing QoS - communicator.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Communicator, $WC, $AppSharePorts, $WC, $WC, $WC, $WC, $WC, $AppShareMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2010 Application Sharing QoS - communicator.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to Set Lync 2010 Application Sharing QoS - communicator.exe in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Lync 2010 File Transfer QoS - communicator.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2010 File Transfer QoS - communicator.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Communicator, $WC, $FileTransferPorts, $WC, $WC, $WC, $WC, $WC, $FileTransferMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2010 File Transfer QoS - communicator.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync 2010 File Transfer QoS - communicator.exe in {0}' -f $PolicyName)
}
#endregion communicator_exe
#region attendantconsole_exe
try
{
Write-Verbose -Message ('Try to set Lync 2010 Attendant Audio QoS - attendantconsole.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2010 Attendant Audio QoS - attendantconsole.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $AttendantConsole, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2010 Attendant Audio QoS - attendantconsole.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync 2010 Attendant Audio QoS - attendantconsole.exe in {0}' -f $PolicyName)
}
#endregion attendantconsole_exe
#region lync_exe
try
{
Write-Verbose -Message ('Try to set Lync 2013 Audio QoS - lync.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2013 Audio QoS - lync.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Lync, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2013 Audio QoS - lync.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync 2013 Audio QoS - lync.exe in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Lync 2013 Video QoS - lync.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2013 Video QoS - lync.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Lync, $WC, $VideoPorts, $WC, $WC, $WC, $WC, $WC, $VideoMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2013 Video QoS - lync.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync 2013 Video QoS - lync.exe in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Lync 2013 Application Sharing QoS - lync.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2013 Application Sharing QoS - lync.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Lync, $WC, $AppSharePorts, $WC, $WC, $WC, $WC, $WC, $AppShareMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2013 Application Sharing QoS - lync.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync 2013 Application Sharing QoS - lync.exe in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Lync 2013 File Transfer QoS - lync.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2013 File Transfer QoS - lync.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Lync, $WC, $FileTransferPorts, $WC, $WC, $WC, $WC, $WC, $FileTransferMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2013 File Transfer QoS - lync.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync 2013 File Transfer QoS - lync.exe in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Lync 2013 SIP - lync.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync 2013 SIP - lync.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $Lync, $WC, $LyncSipPorts, $WC, $WC, $WC, $WC, $WC, $AppShareMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync 2013 SIP - lync.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync 2013 SIP - lync.exe in {0}' -f $PolicyName)
}
#endregion lync_exe
#region lyncmx_exe
try
{
Write-Verbose -Message ('Try to set Lync Windows Store App Audio QoS - lyncmx.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync Windows Store App Audio QoS - lyncmx.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $LyncStore, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync Windows Store App Audio QoS - lyncmx.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync Windows Store App Audio QoS - lyncmx.exe in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Lync Windows Store App Video QoS - lyncmx.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Lync Windows Store App Video QoS - lyncmx.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $LyncStore, $WC, $VideoPorts, $WC, $WC, $WC, $WC, $WC, $VideoMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Lync Windows Store App Video QoS - lyncmx.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Lync Windows Store App Video QoS - lyncmx.exe in {0}' -f $PolicyName)
}
#endregion lyncmx_exe
#region VdiSetup
try
{
Write-Verbose -Message ('Try to set VDI Audio QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\VDI Audio QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $mstsc, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set VDI Audio QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set VDI Audio QoS in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set VDI Video QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\VDI Video QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $mstsc, $WC, $VideoPorts, $WC, $WC, $WC, $WC, $WC, $VideoMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set VDI Video QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set VDI Video QoS in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set VDI Application Sharing QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\VDI Application Sharing QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $mstsc, $WC, $AppSharePorts, $WC, $WC, $WC, $WC, $WC, $AppShareMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set VDI Application Sharing QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set VDI Application Sharing QoS in {0}' -f $PolicyName)
}
#endregion VdiSetup
#region VdiHdxSetup
try
{
Write-Verbose -Message ('Try to set VDI Audio QoS (Citrix HDX RealTime Optimization Pack 2.0) in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\VDI Audio QoS (Citrix HDX RealTime Optimization Pack 2.0)'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $MediaEngineService, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set VDI Audio QoS (Citrix HDX RealTime Optimization Pack 2.0) in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set VDI Audio QoS (Citrix HDX RealTime Optimization Pack 2.0) in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set VDI Video QoS (Citrix HDX RealTime Optimization Pack 2.0) in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\VDI Video QoS (Citrix HDX RealTime Optimization Pack 2.0)'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $MediaEngineService, $WC, $VideoPorts, $WC, $WC, $WC, $WC, $WC, $VideoMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set VDI Video QoS (Citrix HDX RealTime Optimization Pack 2.0) in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set VDI Video QoS (Citrix HDX RealTime Optimization Pack 2.0) in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set VDI Application Sharing QoS (Citrix HDX RealTime Optimization Pack 2.0) in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\VDI Application Sharing QoS (Citrix HDX RealTime Optimization Pack 2.0)'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $MediaEngineService, $WC, $AppSharePorts, $WC, $WC, $WC, $WC, $WC, $AppShareMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set VDI Application Sharing QoS (Citrix HDX RealTime Optimization Pack 2.0) in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set VDI Application Sharing QoS (Citrix HDX RealTime Optimization Pack 2.0) in {0}' -f $PolicyName)
}
#endregion VdiHdxSetup
}
END
{
Write-Output -InputObject ('Done with the creation of {0}' -f $PolicyName)
}
#region License
<#
Copyright (c) 2017, Joerg Hochwald. 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.
By using the Software, you agree to the License, Terms and Conditions above!
#>
<#
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)!
#>
#endregion License

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,357 @@
<#
.SYNOPSIS
Create the S4B Related Exchange UM QoS Group Policy
.DESCRIPTION
Create the Skype for Busines related Exchange Unified Messaging Quality of Services Group Policy
.EXAMPLE
PS C:\> .\ExchangeUM_GPO.ps1
.EXAMPLE
PS C:\> .\ExchangeUM_GPO.ps1 -verbose
.NOTES
Check that the ports and port ranges fit your requirements!
The ports and ranges we use here should fit the Skype for Business Online setup
#>
[CmdletBinding()]
param ()
#Requires -RunAsAdministrator
BEGIN
{
#region Variables
# QoS marking for Audio
$SC = 'SilentlyContinue'
$STP = 'Stop'
[string]$AudioMark = '46'
#endregion Variables
#region GroupPolicyInfo
# GPO (Policy) Name
[string]$PolicyName = 'S4B QoS - Exchange UM'
# GPO (Policy) Comment
[string]$PolicyComment = 'DSCP markings for Exchange UM traffic. This GPO should be applied to all Organizational Units (OUs) containing Exchange UM servers.'
#endregion GroupPolicyInfo
#region Defaults
# Define some Defaults
[string]$MinusOne = '-1'
[string]$OneZero = '1.0'
[string]$One = '1'
[string]$WC = '*'
[string]$ThrotRate = 'Throttle Rate'
[string]$DscpVal = 'DSCP Value'
[string]$RemIPLen = 'Remote IP Prefix Length'
[string]$RemIP = 'Remote IP'
[string]$RemPort = 'Remote Port'
[string]$LocIPLen = 'Local IP Prefix Length'
[string]$LocIP = 'Local IP'
[string]$LocPort = 'Local Port'
[string]$Protocol = 'Protocol'
[string]$AppName = 'Application Name'
[string]$Version = 'Version'
[string]$STRG = 'String'
[string]$UserSettingsDisabled = 'UserSettingsDisabled'
[string]$ServicesTcpipQoSName = 'HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\QoS'
[string]$ServicesTcpipQoSValue = 'Do not use NLA'
[string]$Action = 'Update'
[string]$Context = 'Computer'
#endregion Defaults
#region ModuleHandler
try
{
# List of Modules
$Modules = 'ActiveDirectory', 'GroupPolicy'
# Loop over the Module List
foreach ($Module in $Modules)
{
# Import the Module
Write-Verbose -Message ('Importing {0}' -f $Module)
$null = (Import-Module -Name $Module -ErrorAction $STP -WarningAction $SC)
Write-Verbose -Message ('Imported {0}' -f $Module)
}
}
catch
{
# Whoops
Write-Error -Message ('Unable to import the {0} Module, please check your Setup!' -f $Module) -ErrorAction $STP
# We are done here...
break
}
#endregion ModuleHandler
}
PROCESS
{
#region CreateGroupPolicy
try
{
Write-Verbose -Message ('Try to create {0}' -f $PolicyName)
#Cleanup
$paramNewGPO = $null
# Splat reusable parameters
$paramNewGPO = @{
Name = $PolicyName
Comment = $PolicyComment
ErrorAction = Stop
WarningAction = SilentlyContinue
Confirm = $false
}
$null = (New-GPO @paramNewGPO)
Write-Verbose -Message ('Created {0}' -f $PolicyName)
}
catch
{
Write-Verbose -Message ('The Policy {0} exists' -f $PolicyName)
}
#endregion CreateGroupPolicy
#region ModifyGroupPolicy
try
{
Write-Verbose -Message ('Try to modify {0}' -f $PolicyName)
$null = ((Get-GPO -Name $PolicyName).GpoStatus = $UserSettingsDisabled)
Write-Verbose -Message ('Modified {0}' -f $PolicyName)
}
catch
{
Write-Error -Message ('Unable to modify {0}' -f $PolicyName) -ErrorAction $STP
# We are done here...
break
}
#endregion ModifyGroupPolicy
#region ServicesTcpipQoSName
try
{
Write-Verbose -Message ('Try to Set {0} to {1} {2} in {3}' -f $ServicesTcpipQoSName, $ServicesTcpipQoSValue, $One, $PolicyName)
# Cleanup
$paramSetGPPrefRegistryValue = $null
# Splat reusable parameters
$paramSetGPPrefRegistryValue = @{
Name = $PolicyName
ErrorAction = Stop
WarningAction = SilentlyContinue
Context = $Context
Key = $ServicesTcpipQoSName
ValueName = $ServicesTcpipQoSValue
Value = $One
Type = $STRG
Action = $Action
}
$null = (Set-GPPrefRegistryValue @paramSetGPPrefRegistryValue)
Write-Verbose -Message ('Set {0} to {1} {2} in {3}' -f $ServicesTcpipQoSName, $ServicesTcpipQoSValue, $One, $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to Set {0} to {1} {2} in {3}' -f $ServicesTcpipQoSName, $ServicesTcpipQoSValue, $One, $PolicyName)
}
#endregion ServicesTcpipQoSName
#region EdgeToExchangeAudio
try
{
Write-Verbose -Message ('Try to set Edge to Exchange UM Audio QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Edge to Exchange UM Audio QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $WC, $WC, '1024:65535', $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Edge to Exchange UM Audio QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Edge to Exchange UM Audio QoS in {0}' -f $PolicyName)
}
#endregion EdgeToExchangeAudio
#region umservices_exe
try
{
Write-Verbose -Message ('Try to set Exchange UM Audio to Edge QoS - umservices.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Exchange UM Audio to Edge QoS - umservices.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, 'umservices.exe', $WC, '', $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Exchange UM Audio to Edge QoS - umservices.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Exchange UM Audio to Edge QoS - umservices.exe in {0}' -f $PolicyName)
}
#endregion umservices_exe
#region Microsoft_Exchange_UM_CallRouter_exe
try
{
Write-Verbose -Message ('Try to set Exchange UM Audio to Edge QoS - Microsoft.Exchange.UM.CallRouter.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Exchange UM Audio to Edge QoS - Microsoft.Exchange.UM.CallRouter.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, 'Microsoft.Exchange.UM.CallRouter.exe', $WC, '', $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Exchange UM Audio to Edge QoS - Microsoft.Exchange.UM.CallRouter.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Exchange UM Audio to Edge QoS - Microsoft.Exchange.UM.CallRouter.exe in {0}' -f $PolicyName)
}
#endregion Microsoft_Exchange_UM_CallRouter_exe
#region umworkerprocess_exe
try
{
Write-Verbose -Message ('Try to set Exchange UM Audio to Edge QoS - umworkerprocess.exe in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Exchange UM Audio to Edge QoS - umworkerprocess.exe'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, 'umworkerprocess.exe', $WC, '', $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Exchange UM Audio to Edge QoS - umworkerprocess.exe in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Exchange UM Audio to Edge QoS - umworkerprocess.exe in {0}' -f $PolicyName)
}
#endregion umworkerprocess_exe
}
END
{
Write-Output -InputObject ('Done with the creation of {0}' -f $PolicyName)
}
#region License
<#
Copyright (c) 2017, Joerg Hochwald. 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.
By using the Software, you agree to the License, Terms and Conditions above!
#>
<#
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)!
#>
#endregion License

View File

@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2019, 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.

View File

@@ -0,0 +1,500 @@
<#
.SYNOPSIS
Create the S4B Server QoS Group Policy
.DESCRIPTION
Create the Skype for Busines related Quality of Services Server Group Policy
.EXAMPLE
PS C:\> .\Server_GPO.ps1
.EXAMPLE
PS C:\> .\Server_GPO.ps1 -verbose
.NOTES
Check that the ports and port ranges fit your requirements!
The ports and ranges we use here should fit the Skype for Business Online setup
#>
[CmdletBinding()]
param ()
#Requires -RunAsAdministrator
BEGIN
{
#region Variables
# Ports to use for Application Sharing
[string]$AppSharePorts = '50040:50059'
# QoS marking for Application Sharing
[string]$AppShareMark = '24'
# Ports to use for Video
[string]$VideoPorts = '50020:50039'
# QoS marking for Video
[string]$VideoMark = '34'
# Ports to use for Audio
[string]$AudioPorts = '50000:50019'
# QoS marking for Audio
[string]$AudioMark = '46'
#endregion Variables
#region GroupPolicyInfo
# GPO (Policy) Name
[string]$PolicyName = 'S4B QoS - Server'
# GPO (Policy) Comment
[string]$PolicyComment = 'DSCP markings for Lync/Skype for Business front end server traffic. This GPO should be applied to all Organizational Units (OUs) containing Lync/Skype for Business front-end servers.'
#endregion GroupPolicyInfo
#region Executables
# Executables
[string]$OcsAppServerHost = 'OcsAppServerHost.exe'
[string]$avmcusvc = 'avmcusvc.exe'
[string]$asmcusvc = 'asmcusvc.exe'
#endregion Executables
#region Defaults
# Define some Defaults
[string]$SC = 'SilentlyContinue'
[string]$STP = 'Stop'
[string]$MinusOne = '-1'
[string]$OneZero = '1.0'
[string]$One = '1'
[string]$WC = '*'
[string]$ThrotRate = 'Throttle Rate'
[string]$DscpVal = 'DSCP Value'
[string]$RemIPLen = 'Remote IP Prefix Length'
[string]$RemIP = 'Remote IP'
[string]$RemPort = 'Remote Port'
[string]$LocIPLen = 'Local IP Prefix Length'
[string]$LocIP = 'Local IP'
[string]$LocPort = 'Local Port'
[string]$Protocol = 'Protocol'
[string]$AppName = 'Application Name'
[string]$Version = 'Version'
[string]$STRG = 'String'
[string]$UserSettingsDisabled = 'UserSettingsDisabled'
[string]$ServicesTcpipQoSName = 'HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\QoS'
[string]$ServicesTcpipQoSValue = 'Do not use NLA'
[string]$Action = 'Update'
[string]$Context = 'Computer'
#endregion Defaults
#region ModuleHandler
try
{
# List of Modules
$Modules = 'ActiveDirectory', 'GroupPolicy'
# Loop over the Module List
foreach ($Module in $Modules)
{
# Import the Module
Write-Verbose -Message ('Importing {0}' -f $Module)
$null = (Import-Module -Name $Module -ErrorAction $STP -WarningAction $SC)
Write-Verbose -Message ('Imported {0}' -f $Module)
}
}
catch
{
# Whoops
Write-Error -Message ('Unable to import the {0} Module, please check your Setup!' -f $Module) -ErrorAction $STP
# We are done here...
break
}
#endregion ModuleHandler
}
PROCESS
{
#region CreateGroupPolicy
try
{
Write-Verbose -Message ('Try to create {0}' -f $PolicyName)
#Cleanup
$paramNewGPO = $null
# Splat reusable parameters
$paramNewGPO = @{
Name = $PolicyName
Comment = $PolicyComment
ErrorAction = Stop
WarningAction = SilentlyContinue
Confirm = $false
}
$null = (New-GPO @paramNewGPO)
Write-Verbose -Message ('Created {0}' -f $PolicyName)
}
catch
{
Write-Verbose -Message ('The Policy {0} exists' -f $PolicyName)
}
#endregion CreateGroupPolicy
#region ModifyGroupPolicy
try
{
Write-Verbose -Message ('Try to modify {0}' -f $PolicyName)
$null = ((Get-GPO -Name $PolicyName).GpoStatus = $UserSettingsDisabled)
Write-Verbose -Message ('Modified {0}' -f $PolicyName)
}
catch
{
Write-Error -Message ('Unable to modify {0}' -f $PolicyName) -ErrorAction $STP
# We are done here...
break
}
#endregion ModifyGroupPolicy
#region ServicesTcpipQoSName
try
{
Write-Verbose -Message ('Try to Set {0} to {1} {2} in {3}' -f $ServicesTcpipQoSName, $ServicesTcpipQoSValue, $One, $PolicyName)
# Cleanup
$paramSetGPPrefRegistryValue = $null
# Splat reusable parameters
$paramSetGPPrefRegistryValue = @{
Name = $PolicyName
ErrorAction = Stop
WarningAction = SilentlyContinue
Context = $Context
Key = $ServicesTcpipQoSName
ValueName = $ServicesTcpipQoSValue
Value = $One
Type = $STRG
Action = $Action
}
$null = (Set-GPPrefRegistryValue @paramSetGPPrefRegistryValue)
Write-Verbose -Message ('Set {0} to {1} {2} in {3}' -f $ServicesTcpipQoSName, $ServicesTcpipQoSValue, $One, $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to Set {0} to {1} {2} in {3}' -f $ServicesTcpipQoSName, $ServicesTcpipQoSValue, $One, $PolicyName)
}
#endregion ServicesTcpipQoSName
#region ServerConferencing
try
{
Write-Verbose -Message ('Try to set Server Conferencing Audio QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Server Conferencing Audio QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $avmcusvc, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Server Conferencing Audio QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Server Conferencing Audio QoS in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Server Conferencing Video QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Server Conferencing Video QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $avmcusvc, $WC, $VideoPorts, $WC, $WC, $WC, $WC, $WC, $VideoMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Server Conferencing Video QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Server Conferencing Video QoS in {0}' -f $PolicyName)
}
#endregion ServerConferencing
#region ServerApplicationSharing
try
{
Write-Verbose -Message ('Try to set Server Application Sharing QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Server Application Sharing QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $asmcusvc, $WC, $AppSharePorts, $WC, $WC, $WC, $WC, $WC, $AppShareMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Server Application Sharing QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Server Application Sharing QoS in {0}' -f $PolicyName)
}
#endregion ServerApplicationSharing
#region ServerResponseGroup
try
{
Write-Verbose -Message ('Try to set Server Response Group QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Server Response Group QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $OcsAppServerHost, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Server Response Group QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Server Response Group QoS in {0}' -f $PolicyName)
}
#endregion ServerResponseGroup
#region ServerConferenceAnnouncement
try
{
Write-Verbose -Message ('Try to set Server Conference Announcement Service QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Server Conference Announcement Service QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $OcsAppServerHost, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Server Conference Announcement Service QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Server Conference Announcement Service QoS in {0}' -f $PolicyName)
}
#endregion ServerConferenceAnnouncement
#region ServerCallPark
try
{
Write-Verbose -Message ('Try to set Server Call Park QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Server Call Park QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $OcsAppServerHost, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Server Call Park QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Server Call Park QoS in {0}' -f $PolicyName)
}
#endregion ServerCallPark
#region ServerUCMAApplications
try
{
Write-Verbose -Message ('Try to set Server UCMA Applications Audio QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Server UCMA Applications Audio QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $OcsAppServerHost, $WC, $AudioPorts, $WC, $WC, $WC, $WC, $WC, $AudioMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Server UCMA Applications Audio QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Server UCMA Applications Audio QoS in {0}' -f $PolicyName)
}
try
{
Write-Verbose -Message ('Try to set Server UCMA Applications Video QoS in {0}' -f $PolicyName)
# Cleanup
$paramSetGPRegistryValue = $null
# Splat reusable parameters
$paramSetGPRegistryValue = @{
Name = $PolicyName
ErrorAction = $STP
WarningAction = $SC
Confirm = $false
Key = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\QoS\Server UCMA Applications Video QoS'
ValueName = $Version, $AppName, $Protocol, $LocPort, $LocIP, $LocIPLen, $RemPort, $RemIP, $RemIPLen, $DscpVal, $ThrotRate
Type = $STRG
Value = $OneZero, $OcsAppServerHost, $WC, $VideoPorts, $WC, $WC, $WC, $WC, $WC, $VideoMark, $MinusOne
}
$null = (Set-GPRegistryValue @paramSetGPRegistryValue)
Write-Verbose -Message ('Set Server UCMA Applications Video QoS in {0}' -f $PolicyName)
}
catch
{
Write-Warning -Message ('Unable to set Server UCMA Applications Video QoS in {0}' -f $PolicyName)
}
#endregion ServerUCMAApplications
}
END
{
Write-Output -InputObject ('Done with the creation of {0}' -f $PolicyName)
}
#region License
<#
Copyright (c) 2017, Joerg Hochwald. 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.
By using the Software, you agree to the License, Terms and Conditions above!
#>
<#
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)!
#>
#endregion License

View File

@@ -0,0 +1,443 @@
<#
.SYNOPSIS
Setup the S4B server for QoS
.DESCRIPTION
Setup the Skype for Business 2015 Server for Quality of Services
.PARAMETER FrontEndPool
Skype for Business Front End Pool
.PARAMETER EdgePool
Skype for Business Edge Pool
.EXAMPLE
PS C:\> .\Skype_Server_Config.ps1
.EXAMPLE
PS C:\> .\Skype_Server_Config.ps1 -verbose
.NOTES
Check that the ports and port ranges fit your requirements!
The ports and ranges we use here should fit the Skype for Business Online setup
#>
[CmdletBinding()]
param
(
[Parameter(ValueFromPipeline,
Position = 1)]
[string]
$FrontEndPool = 's4bfe.fra.hicts.net',
[Parameter(ValueFromPipeline,
Position = 2)]
[string]
$EdgePool = 's4bedge.dmz.hicts.net'
)
#Requires -RunAsAdministrator
BEGIN
{
#region Variables
# QoS marking for Audio
[string]$AudioMark = '46'
# Audio Start Port
[string]$AudioPortStart = '50000'
# Number of Ports to use
[string]$AudioPortCount = '20'
# Video Start Port
[string]$VideoPortStart = ([int]$AudioPortStart + [int]$AudioPortCount)
# Legacy variante of the above (without calculating)
#[string]$VideoPortStart = '50020'
# Number of Ports to use
[string]$VideoPortCount = '20'
# App Sharing Start Port
[string]$AppSharingPortStart = ([int]$VideoPortStart + [int]$VideoPortCount)
# Legacy variante of the above (without calculating)
#[string]$AppSharingPortStart = '50040'
# Number of Ports to use
[string]$AppSharingPortCount = '20'
# Start File Transfer Port
[string]$ClientFileTransferPort = '5350'
# Number of Ports to use
[string]$ClientFileTransferPortRange = '20'
# Start Legacy Media Port
[string]$ClientMediaPort = '5370'
# Number of Ports to use (Legacy)
[string]$ClientMediaPortRange = '20'
# Number of Ports to use (Legacy)
[string]$MediaCommunicationPortCount = '10000'
<#
# Legacy variables
# Skype for Business Front End Pool
[string]$FrontEndPool = 's4bfe.fra.hicts.net'
# Skype for Business Edge Pool
[string]$EdgePool = 's4bedge.dmz.hicts.net'
#>
#endregion Variables
#region Defaults
# Define some Defaults
[string]$SC = 'SilentlyContinue'
[string]$STP = 'Stop'
[string]$Global = 'global'
[string]$Voice8021p = '0'
#endregion Defaults
#region CheckCmd
# All Skype for Business Server related commands
$AllCommands = 'Set-CsConferencingConfiguration', 'Set-CsUCPhoneConfiguration', 'Set-CsMediaConfiguration', 'Set-CsConferenceServer', 'Set-CsApplicationServer', 'Set-CsMediationServer', 'Set-CsWebServer', 'Set-CsEdgeServer'
# Loop over the list of commands
foreach ($TheCommand in $AllCommands)
{
try
{
Write-Verbose -Message ('Check for {0}' -f $TheCommand)
# Cleanup
$paramGetCommand = $null
# Splat reusable parameters
$paramGetCommand = @{
Name = $TheCommand
ErrorAction = $STP
WarningAction = $SC
}
$null = (Get-Command @paramGetCommand)
Write-Verbose -Message ('Found {0}' -f $TheCommand)
}
catch
{
# Whoops
$paramWriteError = @{
Message = ('Unable to find {0} - Please check your Setup!' -f $TheCommand)
ErrorAction = $STP
}
Write-Error @paramWriteError
# We are done here...
break
}
}
#endregion CheckCmd
}
PROCESS
{
#region ConferencingConfiguration
try
{
Write-Verbose -Message 'Change Conferencing Configuration'
# Cleanup
$paramSetCsConferencingConfiguration = $null
# Splat reusable parameters
$paramSetCsConferencingConfiguration = @{
Identity = $Global
ClientAudioPort = $AudioPortStart
ClientAudioPortRange = $AudioPortCount
ClientVideoPort = $VideoPortStart
ClientVideoPortRange = $VideoPortCount
ClientAppSharingPort = $AppSharingPortStart
ClientAppSharingPortRange = $AppSharingPortCount
ClientFileTransferPort = $ClientFileTransferPort
ClientFileTransferPortRange = $ClientFileTransferPortRange
ClientMediaPortRangeEnabled = $true
ClientMediaPort = $ClientMediaPort
ClientMediaPortRange = $ClientMediaPortRange
ErrorAction = $STP
WarningAction = $SC
}
$null = (Set-CsConferencingConfiguration @paramSetCsConferencingConfiguration)
Write-Verbose -Message 'Changed Conferencing Configuration'
}
catch
{
Write-Warning -Message 'Unable to Set Conferencing Configuration'
}
#endregion ConferencingConfiguration
#region ChangeUCPhoneConfiguration
try
{
Write-Verbose -Message 'Change UC Phone Configuration'
# Cleanup
$paramSetCsUCPhoneConfiguration = $null
# Splat reusable parameters
$paramSetCsUCPhoneConfiguration = @{
Identity = $Global
VoiceDiffServTag = $AudioMark
Voice8021p = $Voice8021p
ErrorAction = $STP
WarningAction = $SC
}
$null = (Set-CsUCPhoneConfiguration @paramSetCsUCPhoneConfiguration)
Write-Verbose -Message 'Changed UC Phone Configuration'
}
catch
{
Write-Warning -Message 'Unable to Set UC Phone Configuration'
}
#endregion ChangeUCPhoneConfiguration
#region ChangeMediaConfiguration
try
{
Write-Verbose -Message 'Change Media Configuration'
# Cleanup
$paramSetCsMediaConfiguration = $null
# Splat reusable parameters
$paramSetCsMediaConfiguration = @{
Identity = $Global
EnableQoS = $true
ErrorAction = $STP
WarningAction = $SC
}
$null = (Set-CsMediaConfiguration @paramSetCsMediaConfiguration)
Write-Verbose -Message 'Changed Media Configuration'
}
catch
{
Write-Warning -Message 'Unable to Set Media Configuration'
}
#endregion ChangeMediaConfiguration
#region ChangeConferenceServerConfiguration
try
{
Write-Verbose -Message 'Change Conference Server Configuration'
# Cleanup
$paramSetCsConferenceServer = $null
# Splat reusable parameters
$paramSetCsConferenceServer = @{
Identity = $FrontEndPool
AppSharingPortStart = $AppSharingPortStart
AppSharingPortCount = $AppSharingPortCount
AudioPortStart = $AudioPortStart
AudioPortCount = $AudioPortCount
VideoPortStart = $VideoPortStart
VideoPortCount = $VideoPortCount
ErrorAction = $STP
WarningAction = $SC
}
$null = (Set-CsConferenceServer @paramSetCsConferenceServer)
Write-Verbose -Message 'Changed Conference Server Configuration'
}
catch
{
Write-Warning -Message 'Unable to Set Conference Server Configuration'
}
#endregion ChangeConferenceServerConfiguration
#region ChangeApplicationServerConfiguration
try
{
Write-Verbose -Message 'Change Application Server Configuration'
# Cleanup
$paramSetCsApplicationServer = $null
# Splat reusable parameters
$paramSetCsApplicationServer = @{
Identity = $FrontEndPool
AppSharingPortStart = $AppSharingPortStart
AppSharingPortCount = $AppSharingPortCount
AudioPortStart = $AudioPortStart
AudioPortCount = $AudioPortCount
VideoPortStart = $VideoPortStart
VideoPortCount = $VideoPortCount
ErrorAction = $STP
WarningAction = $SC
}
$null = (Set-CsApplicationServer @paramSetCsApplicationServer)
Write-Verbose -Message 'Changed Application Server Configuration'
}
catch
{
Write-Warning -Message 'Unable to Set Application Server Configuration'
}
#endregion ChangeApplicationServerConfiguration
#region ChangeMediationServerConfiguration
try
{
Write-Verbose -Message 'Change Mediation Server Configuration'
#Cleanup
$paramSetCsMediationServer = $null
# Splat reusable parameters
$paramSetCsMediationServer = @{
Identity = $FrontEndPool
AudioPortStart = $AudioPortStart
AudioPortCount = $AudioPortCount
ErrorAction = $STP
WarningAction = $SC
}
$null = (Set-CsMediationServer @paramSetCsMediationServer)
Write-Verbose -Message 'Changed Mediation Server Configuration'
}
catch
{
Write-Warning -Message 'Unable to Set Mediation Server Configuration'
}
#endregion ChangeMediationServerConfiguration
#region ChangeWebServerConfiguration
try
{
Write-Verbose -Message 'Change Web Server Configuration'
#Cleanup
$paramSetCsWebServer = $null
# Splat reusable parameters
$paramSetCsWebServer = @{
Identity = $FrontEndPool
AppSharingPortStart = $AppSharingPortStart
AppSharingPortCount = $AppSharingPortCount
ErrorAction = $STP
WarningAction = $SC
}
$null = (Set-CsWebServer @paramSetCsWebServer)
Write-Verbose -Message 'Changed Web Server Configuration'
}
catch
{
Write-Warning -Message 'Unable to Set Web Server Configuration'
}
#endregion ChangeWebServerConfiguration
#region ChangeEdgeServerConfiguration
try
{
Write-Verbose -Message 'Change Edge Server Configuration'
# Cleanup
$paramSetCsEdgeServer = $null
# Splat reusable parameters
$paramSetCsEdgeServer = @{
Identity = $EdgePool
MediaCommunicationPortStart = $AudioPortStart
MediaCommunicationPortCount = $MediaCommunicationPortCount
ErrorAction = $STP
WarningAction = $SC
}
$null = (Set-CsEdgeServer @paramSetCsEdgeServer)
Write-Verbose -Message 'Changed Edge Server Configuration'
}
catch
{
Write-Warning -Message 'Unable to Set Edge Server Configuration'
}
#endregion ChangeEdgeServerConfiguration
}
END
{
Write-Output -InputObject 'Done with the Skype for Business QoS setup.'
}
#region License
<#
Copyright (c) 2017, Joerg Hochwald. 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.
By using the Software, you agree to the License, Terms and Conditions above!
#>
<#
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)!
#>
#endregion License

View File

@@ -0,0 +1,8 @@
# Legacy Notice
I no longer run Exchange, Skype for Business, or any other Office Server on Premises.
This is my personal [reaction](https://hochwald.net/microsoft-rolls-back-decision-to-take-away-internal-usage-rights-from-partners/) to the changes that Microsoft [announced](https://hochwald.net/microsoft-is-going-to-kill-internal-use-rights-benefit-for-partners/) for the Internal Use Rights (IUR) program. I know that they decided to reverse that changes and in theory, I could still legally use the software. However, I decided to decommission everything licensed under the terms of the Internal Use Rights (IUR) program.
In my opinion, the community always should have some benefits from the Internal Use Rights (IUR) program and/or Action Pack. Now that I decided to drop out, there will be no more such benefits.
I will _no longer maintain_ the scripts related to the Microsoft Office (on Premises) servers. They will remain here, but unmaintained. Fork the repository and maintain or extend them if you like to. The [License](https://github.com/jhochwald/PowerShell-collection/blob/master/LICENSE) allows that easily.

View File

@@ -0,0 +1,63 @@
# Skype for Business QoS Settings
Setup Quality of Services (QoS) on Skype for Business Servers and Clients.
## You Network
You must configure your network equipment to match the marks that are configured on the client/server part.
Some people get this QoS wrong: This configuration enables your Clients and Servers to mark the traffic! Not more, not less. Your network equipment must do the dirty work and prioritize and/or reserve bandwidth that match your requirements.
If you just load the stuff here, nothing will change. Your Skype Clients and servers will mark the packets and that's about it!
## What it does
It configures the Skype for Business Servers to use a small range of ports for each function (e.g. Voice or Video). This range should match the Skype for Business Online (SfBO) configuration.
All Skype for Business Clients should use these configuration after a restart/re-login. Even non-Windows clients will be using the configuration, because it is configured on the server.
For Skype for Business Servers and Windows Based Clients, a dedicated Group Policy will be established. You should apply these to all OU's where the Clients and/or Servers are located.
The Client Policy also contains configuration/settings for VDI instances, and even for Citrix HDX setup's.
There is also the matching Edge configuration, these boxes should never be domain joined. Therefore, we use local registry settings!
To make the end-to-end setup, there is also a dedicated Group Policy for Exchange Servers. This Policy should be applied at minimum to all Exchange Servers that hosts the Unified Messaging Role. I apply these to all Exchange Servers.
## Please review everything
Before using the scripts to configure and/or load anything, you should review them! Do not just execute them. These scripts will change a lot and it will reconfigure a lot on your Skype for Business servers!!!
Don't blame me if something doesn't work as you might expect it.
## Detailed configuration
The source is the documentation! I know, that sounds typical for a geek... But if you take a closer look at the scripts, you will see a lot of comments and documentation snippets. They should make the settings and a lot of the logic clear.
Microsoft (MSFT) and the community provide a lot of very good and detailed documentation about Skype and QoS.
## Content
Here is a quick overview of the content
### `Client_GPO.ps1`
Create the Skype for Busines related Quality of Services Client Group Policy
### `Edge_REG.ps1`
Setup the Skype for Business 2015 Edge Server for Quality of Services
Edge Servers are not domain joined, we have to modify the registry instead of using a Group Policy
### `ExchangeUM_GPO.ps1`
Create the Skype for Busines related Exchange Unified Messaging Quality of Services Group Policy
### `Server_GPO.ps1`
Create the Skype for Busines related Quality of Services Server Group Policy
### `Skype_Server_Config.ps1`
Setup the Skype for Business 2015 Server for Quality of Services
## Signed
There is a signed version of the scripts within the 'signed' directory. The scripts are the same, they are signed with a valid certificate.
## Support
Are you kidding me? This is free software. Take it, or leave it!
## Final remarks
You Network Equipment must support QoS End-to-End!
Teams is not supported (yet).
Some of the new ports for Skype for Business Online (SfBO) are still missing. I might provide an updated version for them soon.
Hybrid with Skype for Business Online (SfBO) will work! But if you want to use QoS End-To-End, Fast Track might be required. Ask Microsoft!

View File

@@ -0,0 +1,85 @@
#requires -Version 1.0
<#
.SYNOPSIS
Skype for Business should use Proxy Server
.DESCRIPTION
Skype for Business should use Proxy Server to sign in instead of trying a direct connection.
Works with Skype for Business 2015 and 2016 and should work with Lync 1013 as well.
.EXAMPLE
PS C:\> .\Set-Skype4BProxyUsage.ps1
.NOTES
Please note: This is a per user setting!
SIP is not used between Clients (aka P2P or Cleint to Client).
It wil be used between Client and Server and/or Server and Server.
Media Bypass will be used for RTP media between Clients (when possible)
.LINK
https://support.microsoft.com/en-us/help/3207112/skype-for-business-should-use-proxy-server-to-sign-in-instead-of-tryin
.LINK
https://blogs.technet.microsoft.com/uclobby/2016/12/08/enabling-lyncsfb-client-to-use-proxy-server-for-sip-traffic-instead-of-trying-direct-connection/
#>
[CmdletBinding()]
param ()
$parameters = @{
Path = 'HKCU:\Software\Microsoft\UCCPlatform\Lync'
Name = 'EnableDetectProxyForAllConnections'
PropertyType = 'DWORD'
Value = '1'
Force = $true
ErrorAction = 'Stop'
WarningAction = 'SilentlyContinue'
}
try
{
$null = (New-ItemProperty @parameters)
Write-Verbose -Message 'New value set.'
}
catch
{
try
{
$null = (Set-ItemProperty @parameters)
Write-Verbose -Message 'Existing value modified.'
}
catch
{
Write-Warning -Message 'Unable to create/set the value.'
}
}
#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

View File

@@ -0,0 +1,228 @@
function Test-LyncSRVRecords
{
<#
.SYNOPSIS
Check for existing Lync/Skype for Business DNS Records
.DESCRIPTION
Check for existing Lync/Skype for Business DNS Records
.PARAMETER DomainName
Domain name to check, e.g. enatec.net
Defaults to the DNS domain of the localhost
.PARAMETER DNS
Domain Name Server to use. Defaults to the CloudFlare Server 1.1.1.1
.EXAMPLE
PS C:\> Test-LyncSRVRecords
Check for existing Lync/Skype for Business DNS Records for the DNS Domain of the local host
.EXAMPLE
PS C:\> Test-LyncSRVRecords -DomainName 'contoso.com'
Check for existing Lync/Skype for Business DNS Records for contoso.com
.EXAMPLE
PS C:\> Test-LyncSRVRecords -DomainName 'contoso.com' -DNS '8.8.8.8'
Check for existing Lync/Skype for Business DNS Records for contoso.com on the Google public DNS Server
.NOTES
Original by J. Hulsmans (@JHulsmans) https://about.me/jonihulsmans - MIT licensed
Refactored and migrated to psobject output instead of Write-Host
.LINK
https://github.com/JHulsmans/PowerShell/blob/master/DNS/CheckSRVRecord.ps1
#>
[CmdletBinding(ConfirmImpact = 'None')]
[OutputType([psobject])]
param
(
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 0)]
[ValidateNotNullOrEmpty()]
[Alias('Domain')]
[string]
$DomainName = ((Get-WmiObject -Class win32_computersystem).Domain),
[Parameter(ValueFromPipeline,
ValueFromPipelineByPropertyName,
Position = 1)]
[ValidateNotNullOrEmpty()]
[string]
$DNS = '1.1.1.1'
)
begin
{
# Definne some defaults
$Type = 'SRV'
$SCT = 'SilentlyContinue'
# Set a default to prevent Null pointer exceptions, You can use $null here as well if you know what you're doing
$NotFound = 'unknown'
# Create the new Object
$FinalResult = New-Object -TypeName psobject
}
process
{
$CnameResult = (Resolve-DnsName -Name sip.$DomainName -Server $DNS -ErrorAction $SCT)
$LyncDiscoverResult = (Resolve-DnsName -Name lyncdiscover.$DomainName -Type A -Server $DNS -ErrorAction $SCT)
$LyncDiscoverResultv6 = (Resolve-DnsName -Name lyncdiscover.$DomainName -Type AAAA -Server $DNS -ErrorAction $SCT)
$FederationResult = (Resolve-DnsName -Name _sipfederationtls._tcp.$DomainName -Type $Type -Server $DNS -ErrorAction $SCT)
$SipTlsResult = (Resolve-DnsName -Name _sip._tls.$DomainName -Type $Type -Server $DNS -ErrorAction $SCT)
if ($CnameResult)
{
$FinalResult | Add-Member -MemberType NoteProperty -Name SipHost -Value sip.$DomainName
$FinalResult | Add-Member -MemberType NoteProperty -Name Cname -Value $(@(foreach ($result in $CnameResult.namehost)
{
$result
}
))
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name SipHost -Value $NotFound
$FinalResult | Add-Member -MemberType NoteProperty -Name Cname -Value $NotFound
}
if ($LyncDiscoverResult)
{
if ($LyncDiscoverResult.Name)
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscover -Value ($LyncDiscoverResult.Name | Sort-Object | Get-Unique -OnType)
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscover -Value $NotFound
}
if ($LyncDiscoverResult.NameHost)
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscoverCname -Value ($LyncDiscoverResult.NameHost | Sort-Object | Get-Unique -OnType)
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscoverCname -Value $NotFound
}
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscover -Value $NotFound
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscoverCname -Value $NotFound
}
# Get the IPv6 entry, if exists
if ($LyncDiscoverResultv6)
{
if ($LyncDiscoverResultv6.Name)
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscoverV6 -Value ($LyncDiscoverResultv6.Name | Sort-Object | Get-Unique -OnType)
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscoverV6 -Value $NotFound
}
if ($LyncDiscoverResultv6.NameHost)
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscoverCnameV6 -Value ($LyncDiscoverResultv6.NameHost | Sort-Object | Get-Unique -OnType)
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscoverCnameV6 -Value $NotFound
}
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscoverV6 -Value $NotFound
$FinalResult | Add-Member -MemberType NoteProperty -Name LyncDiscoverCnameV6 -Value $NotFound
}
if ($FederationResult)
{
$FinalResult | Add-Member -MemberType NoteProperty -Name Federation -Value $FederationResult.NameTarget
if ($FederationResult.NameTarget -like '*.lync.com')
{
$IsOnline = $true
}
else
{
$IsOnline = $null
}
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name Federation -Value $NotFound
$IsOnline = $null
}
if ($SipTlsResult)
{
$FinalResult | Add-Member -MemberType NoteProperty -Name SipTls -Value $SipTlsResult.NameTarget
if ($SipTlsResult.NameTarget -like '*.lync.com')
{
$IsOnline = $true
}
else
{
$IsOnline = $null
}
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name SipTls -Value $NotFound
$IsOnline = $null
}
if ($IsOnline)
{
$FinalResult | Add-Member -MemberType NoteProperty -Name IsOnine -Value $true
}
else
{
$FinalResult | Add-Member -MemberType NoteProperty -Name IsOnine -Value $false
}
}
end
{
$FinalResult
}
}
#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

View File

@@ -0,0 +1,8 @@
# Legacy Notice
I no longer run Exchange, Skype for Business, or any other Office Server on Premises.
This is my personal [reaction](https://hochwald.net/microsoft-rolls-back-decision-to-take-away-internal-usage-rights-from-partners/) to the changes that Microsoft [announced](https://hochwald.net/microsoft-is-going-to-kill-internal-use-rights-benefit-for-partners/) for the Internal Use Rights (IUR) program. I know that they decided to reverse that changes and in theory, I could still legally use the software. However, I decided to decommission everything licensed under the terms of the Internal Use Rights (IUR) program.
In my opinion, the community always should have some benefits from the Internal Use Rights (IUR) program and/or Action Pack. Now that I decided to drop out, there will be no more such benefits.
I will _no longer maintain_ the scripts related to the Microsoft Office (on Premises) servers. They will remain here, but unmaintained. Fork the repository and maintain or extend them if you like to. The [License](https://github.com/jhochwald/PowerShell-collection/blob/master/LICENSE) allows that easily.

View 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.

View 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.

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" />
<supportedRuntime version="v2.0" />
</startup>
</configuration>

View File

@@ -0,0 +1,55 @@
$paramGetChildItem = @{
Path = 'Cert:\CurrentUser\My'
Recurse = $true
ErrorAction = 'SilentlyContinue'
WarningAction = 'SilentlyContinue'
}
$paramRemoveItem = @{
ErrorAction = 'SilentlyContinue'
WarningAction = 'SilentlyContinue'
Force = $true
Confirm = $false
}
Get-ChildItem @paramGetChildItem | Where-Object -FilterScript {
$_.Issuer -like 'CN=Communications Server'
} | Remove-Item @paramRemoveItem
#region CHANGELOG
<#
Soon
#>
#endregion CHANGELOG
#region LICENSE
<#
LICENSE:
Copyright 2018 by enabling Technology - http://enatec.io
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.
By using the Software, you agree to the License, Terms and Conditions above!
#>
#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