├── AzureCT ├── AvailabilityTesting.md ├── Linux │ └── glp.sh ├── PerformanceTesting.md ├── PowerShell │ ├── AzureCT │ │ ├── AzureCT.psd1 │ │ ├── AzureCT.psm1 │ │ └── Public │ │ │ ├── Clear-AzureCTHistory.ps1 │ │ │ ├── Get-AzureNetworkAvailability.ps1 │ │ │ ├── Get-HostName.ps1 │ │ │ ├── Get-IPTrace.ps1 │ │ │ ├── Get-LinkPerformance.ps1 │ │ │ ├── Get-Test.ps1 │ │ │ ├── Install-LinkPerformance.ps1 │ │ │ ├── README.md │ │ │ ├── Remove-AzureCT.ps1 │ │ │ ├── Set-iPerfFirewallRules.ps1 │ │ │ └── Show-AzureCTResults.ps1 │ ├── Install-AzureCT.ps1 │ └── SwapLocal.ps1 ├── README.md ├── ServerSide │ ├── AvailabilityDetail.xml │ ├── AvailabilityHeader.xml │ ├── AvailabilityTrace.xml │ ├── ClearHistory.aspx │ ├── DisplayAvailability.css │ ├── DisplayAvailability.html │ ├── DisplayAvailability.js │ ├── IISBuild.ps1 │ ├── TemplateAvailabilityDetail.xml │ ├── TemplateAvailabilityHeader.xml │ ├── TemplateAvailabilityTrace.xml │ ├── Upload.aspx │ ├── Web.config │ ├── WebTest.aspx │ └── jquery.js └── media │ ├── AzureCTAvailability.png │ ├── AzureCTPerformance.png │ ├── AzureNMT.png │ ├── DisplayErrors1.png │ ├── DisplayErrors2.png │ ├── DisplayOneMinute.png │ ├── DisplayTenHour.png │ ├── DisplayTimeout.png │ ├── PowerShellErrors.png │ ├── PowerShellOneMinute.png │ ├── PowerShellTenHour.png │ ├── PowerShellTenSeconds.png │ ├── PowerShellTimeout.png │ ├── RunErrors.md │ ├── RunOneMinute.md │ ├── RunTenHour.md │ ├── RunTimeout.md │ └── Temp │ ├── Diagram50.png │ ├── DirectToOnPremises50.png │ ├── Landing.md │ ├── MonolythicAppNVA50.png │ ├── MonolythicApplication50.png │ ├── MultipleNVAStack50.png │ ├── NVAVPN50.png │ ├── Publicpeering50.png │ ├── SandwichDMZ25.png │ └── SharedSecurityStack50.png ├── AzurePortal ├── HybridVideo.mp4 └── HybridVideo.vtt ├── ERPartnerDocs ├── ExpressRoute Partner Support.pdf └── ExpressRoute_partner_docs.zip ├── LAX-Migration └── ExR Migration LA to LA2 Post.pdf ├── LICENSE ├── README.md └── SECURITY.md /AzureCT/AvailabilityTesting.md: -------------------------------------------------------------------------------- 1 | # Azure Connectivity Toolkit (AzureCT) 2 | 3 | ## Link Availability 4 | This collection of server side web pages and local PowerShell that will generate, collect, store, and display availability statistics of the network between you and a newly built Windows VM in Azure. It will do more in the future, but currently only provides availability information. 5 | 6 | It is designed to provide an indication, over time, of the link between a Virtual Machine in Azure and an on-premise network. While the focus is on network availability, the test is done from a PC client to an IIS server in Azure. This provides a view into the availability of an end-to-end scenario, not just a single point or component in the complex chain that makes up a VPN or an ExpressRoute network connection. The hope is that this will provide insight into the end-to-end network availability. 7 | 8 | [![0]][0] 9 | 10 | >**Note**: This tool is not certified by Microsoft, nor is it supported by Microsoft support. Download and use at your own risk. While the author is an employee of Microsoft, this tool is provided as my best effort to provide insight into the connectivity between an on-premise network and an Azure endpoint. See the [Support and Legal Disclaimers](#support-and-legal-disclaimers) below for more info. 11 | 12 | ### Fast Start 13 | If you just want to install the toolkit, this is the place to start: 14 | 15 | 1. Create a new Windows Server Azure VM on an ExpressRoute connected VNet 16 | 2. On the new Azure VM, in an elevated PowerShell Prompt, run the following command: 17 | 18 | ```powershell 19 | (new-object Net.WebClient).DownloadString("https://aka.ms/AzureCTServer") | Invoke-Expression 20 | ``` 21 | 22 | 3. On your local PC run the following command from PowerShell: 23 | 24 | ```powershell 25 | (new-object Net.WebClient).DownloadString("https://aka.ms/AzureCT") | Invoke-Expression 26 | ``` 27 | 28 | 4. On your local PC you now have the Get-AzureNetworkAvailability command to run availability tests! 29 | 30 | 31 | ### Tool Usage 32 | #### Prerequisites 33 | This tool has three perquisite resources that must be in place before using: 34 | 35 | 1. An Azure virtual network with a VPN or ExpressRoute site-to-site connection to another (usually "on-premise") network. 36 | 2. A newly created Azure Virtual Machine (VM), running Windows Server 2012 or greater, on the Azure VNet that is reachable from the on-premise network. The files and configuration of the Azure VM will be modified, potentially in disruptive ways. To avoid conflicts and/or errors it is important that the Azure VM used is newly built and is a "clean" build, meaning with no other applications or data installed. 37 | 3. A client PC (or server) running PowerShell 3.0 or greater on the on-premise network that can reach (via RDP or Remote Desktop) the Azure VM. 38 | 39 | #### Installation Instructions 40 | 1. Local PC Instructions: 41 | - Install the AzureCT PowerShell module by running the following command in a PowerShell prompt: 42 | 43 | ```powershell 44 | (new-object Net.WebClient).DownloadString("https://aka.ms/AzureCT") | Invoke-Expression 45 | ``` 46 | - This will install a new PowerShell module with eight PowerShell cmdlets; Get-AzureNetworkAvailability, Clear-AzureCTHistory, Show-AzureCTResults, Get-HostName, Get-IPTrace, and Remove-AzureCT, Install-LinkPerformance, and Get-LinkPerformance. 47 | 2. Azure VM Instructions: 48 | - Note the IP Address for this Azure VM that was assigned by the VNet, this will be used many times. 49 | - Install the web application by running the following command in an elevated PowerShell prompt (ie "Run as Administrator") on the Azure VM. 50 | 51 | ```powershell 52 | (new-object Net.WebClient).DownloadString("https://aka.ms/AzureCTServer") | Invoke-Expression 53 | ``` 54 | 55 | - This script will turn on ICMP (ping), install IIS, .Net 4.5, and copy some IIS application files from GitHub. If any errors occur with the file copies, or your server doesn't have access to the Internet, the files can be manually copied. Copy all files from the ServerSide directory of this GitHub to the C:\Inetpub\wwwroot folder on the server. **Note**: If needed, this script can be run multiple times on the server until all errors are resolved. If you manually copy the files, please run the script again to ensure proper file permissions are set on the files. 56 | 4. Validate Installation: 57 | - Go to `http://`; e.g. http://10.0.0.1 58 | - You should successfully bring up a web page titled "Azure Connectivity Toolkit - Availability Home Page". This validates that the web server was successfully set-up and reachable by the local PC. **Note:** Since the Get-AzureNetworkAvailability script hasn't been run, this web page will just be the framework with no real data in it yet. Don't worry, we're about to generate some data! 59 | 60 | > **IMPORTANT**: If warnings are received on either the server or the client regarding ExecutionPolicy in PowerShell, you may need to update your PowerShell settings to allow remote scripts to be run. In PowerShell more information can be found by running "Get-Help about_Execution_Policies" or at this web site: [MSDN][MSDN] 61 | > 62 | > I usually opt for the RemoteSigned setting, but security for your organization should be considered when selecting a new ExecutionPolicy. This can be done by running "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned" from an admin PowerShell prompt. You will only need to change this setting once as it is a persistent global PowerShell setting on each machine. 63 | 64 | 65 | #### Running the tool 66 | 1. On the local Client PC, open a PowerShell prompt. 67 | 2. The main cmdlet is Get-AzureNetworkAvailability. This function will make a web call to the remote server once every 10 seconds for the duration of the test. This function has three input parameters: 68 | - **RemoteHost** - This is required and is the Azure VM IP Address copied in step 2 of the Installation Instructions above. 69 | - **DurationMinutes** - This optional parameter signifies the duration of the Get-AzureNetworkAvailability command in minutes. It is an integer value (whole number). The default value is 1. 70 | - **TimeoutSeconds** - This optional parameter signifies how long each call will wait for a response. The default value is 5 seconds. 71 | 4. For the first run, I recommend doing a test run of 1 minute (default option). To do this, in the PowerShell prompt run the following command (where 10.0.0.1 is the private IP address of the Azure VM): 72 | 73 | ```powershell 74 | Get-AzureNetworkAvailability -RemoteHost 10.0.0.1 75 | ``` 76 | 5. Future execution of this script should be set for a given set of minutes, for example a 10 hour test: 77 | 78 | ```powershell 79 | Get-AzureNetworkAvailability -RemoteHost 10.0.0.1 -DurationMinutes 600 80 | ``` 81 | 82 | >Note: Data from each run of the Get-AzureNetworkAvailability command will uploaded and saved to the Azure VM. If there are errors uploading the data or the command is terminated before uploading, the data is stored locally on the PC until the next successful run of Get-AzureNetworkAvailability. Uploaded data accumulates on the Azure VM and is selectable and displayed using the default IIS page on the Azure VM. 83 | 84 | #### Tool Output 85 | Get-AzureNetworkAvailability will issue a call to a web page on the remote server (WebTest.aspx), based on the response (either an error, a timeout, or a successful response) the script will then wait ten seconds and try again. Each call will produce command line output to the PowerShell prompt of one of the following. 86 | 87 | >**Possible Script Output** 88 | > 89 | >! (exclamation point) - Successful Call 90 | > 91 | >. (period) - Unsuccessful Call (timeout) 92 | > 93 | >\* (asterisk) - IP was reached and a web server responded, but with unexpected data or an error (e.g. 404) 94 | 95 | Each call to the web server is also recorded locally, in the %temp% directory, in two XML files. 96 | -AvailabilityHeader.xml 97 | -AvailabilityDetail.xml 98 | 99 | When this command finishes, a summary of the run will be output to the PowerShell prompt similar to ping results. 100 | 101 | The XML files are also uploaded to the server and a web browser should open on the local client machine with the details of all Get-AzureNetworkAvailability jobs run against that server. If the Get-AzureNetworkAvailability command was successful, and the data successfully uploaded to the server, the local XML files will be deleted from the local Client PC. If any errors with the job or the data upload, the XML will remain on the local Client PC until a successful Get-AzureNetworkAvailability run at which point all previous data sets will be uploaded and the XML files deleted locally. 102 | 103 | Example screen shots can be seen for these conditions: 104 | 105 | - [A Successful one minute run][One Minute] 106 | - [A successful ten hour run][Ten Hour] 107 | - [A successful run with errors][Errors] 108 | - [An unsuccessful run][Timeout] 109 | 110 | #### Data Presentation and Review 111 | After running Get-AzureNetworkAvailability, a web page should open on the local PC, displaying the data for all script runs. 112 | The page can be opened at any time by opening a browser and navigating to `http://` e.g. http://10.0.0.1. 113 | 114 | The drop down on that page will show all the data sets (by data and time) contained in the servers XML files. 115 | 116 | Selecting a specific data set will display the graph and detailed tabular data for that run, as well as the summary information. 117 | 118 | #### Other Tool Cmdlets 119 | There are five other commands that can be run: 120 | - Clear-AzureCTHistory 121 | - Show-AzureCTResults 122 | - Get-HostName 123 | - Get-IPTrace 124 | - Remove-AzureCT 125 | 126 | Both the Clear-AzureCTHistory and Show-AzureCTResults cmdlets have a single input parameter: 127 | - **RemoteHost** - This parameter is required for Show-AzureCTResults and optional for Clear-AzureCTHistory, for both scripts this parameter is the IP Address of the Azure VM copied in step 2 of the Installation Instructions above. 128 | 129 | ##### Clear-AzureCTHistory 130 | This function will delete any Get-AzureNetworkAvailability data on both the local PC and the remote Azure VM (if the remote server IP is provided). This command is never required to be run, but can be helpful if there are many entries in the web page drop-down box, a new series of tests is about to be run, or if the XML file size becomes slow rendering in the browser. 131 | 132 | ##### Show-AzureCTResults 133 | This function will open a web browser on the local Client PC to display the Get-AzureNetworkAvailability data saved to the remote Azure VM. 134 | 135 | ##### Get-HomeName 136 | This function uses a passed in IP address and does a DNS Host Name look-up using the default DNS look-up setting of the machine it's run on. 137 | 138 | ##### Get-IPTrace 139 | This function uses a passed in IP address and performs a Trace Route like function. It's output is for the main Get-AzureNetworkAvailability function. To make this more human readable, use the Format-Table option. 140 | 141 | ```powershell 142 | Get-IPTrace 10.0.0.1 | Format-Table 143 | ``` 144 | 145 | ## Removing the Azure Connectivity Toolkit 146 | Once testing is complete the Azure VM should be deleted to avoid unnecessary Azure usage (and associated charges) and all local files can be deleted. The only files on the local machine are the PowerShell module files copied from GitHub, iPerf and PSPPing files in the C:\ACTTools directory (if Install-LinkPerformance was run), and potentially three XML files (if Get-AzureNetworkAvailability was run) in the Local Client PC %temp% directory. 147 | 148 | To ensure 100% removal of all artifacts from this tool perform the following step: 149 | 150 | 1. Run the Remove-AzureCT command from PowerShell. This will remove the PowerShell module and any local data files. 151 | 152 | ```powershell 153 | Remove-AzureCT 154 | ``` 155 | ## Incorporated Licenses 156 | This tool incorporates [JQuery](https://jquery.org/license/ "JQuery License") for XML manipulation and is included in the ServerSide files. JQuery.js is included and used under the requirements of the MIT License, and in compliance with the main JQuery license proviso "*You are free to use any jQuery Foundation project in any other project (even commercial projects) as long as the copyright header is left intact.*" 157 | 158 | ## Support and Legal Disclaimers 159 | Microsoft provides no support for this software. All support, assistance, and information is on this site alone. 160 | 161 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 REGENTS 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; INCREMENTAL AZURE COSTS INCURRED THROUGH USE OF THIS SOFTWARE; 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. 162 | 163 | 164 | [0]: ./media/AzureCTAvailability.png "AzureCT Availability Test Diagram" 165 | 166 | 167 | [One Minute]: ./media/RunOneMinute.md 168 | [Ten Hour]: ./media/RunTenHour.md 169 | [Errors]: ./media/RunErrors.md 170 | [Timeout]: ./media/RunTimeout.md 171 | [MSDN]: https://technet.microsoft.com/en-us/library/hh849812.aspx 172 | -------------------------------------------------------------------------------- /AzureCT/Linux/glp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Get-LinkPerformance for Linux, version 1.0 4 | 5 | # 1. Define Functions 6 | # 2. Evaluate and Set input parameters 7 | # 3. Initialize Variables 8 | # 4. Clear old run files 9 | # 5. Validate Ping connectivity (two ping) 10 | # 6. Validate iPerf3 connectivity (two ping) 11 | # 7. Start Ping Job 12 | # 8. iPerf Test Loop 13 | # 9. Parse each job file for data 14 | # 9.1 iPerf file loop 15 | # 9.2.1 iPerf line loop 16 | # 10. Output results 17 | 18 | # 1. Define Functions 19 | function getIndex { 20 | # $1 = Array count being analyzed 21 | # $2 = The percentile being sought 22 | 23 | if [ $(( $1 * $2 % 100 )) -eq 0 ] 24 | then 25 | # Whole number 26 | k=$(( $1 * $2 / 100 )) 27 | else 28 | # Fraction 29 | k=$(( $1 * $2 / 100 + 1 )) 30 | fi 31 | 32 | if [ $k -eq 0 ] 33 | then 34 | k=1 35 | elif [ $k -gt $1 ] 36 | then 37 | k=$1 38 | fi 39 | 40 | echo $k 41 | } 42 | 43 | function valid_ip() 44 | { 45 | # From https://www.linuxjournal.com/content/validating-ip-address-bash-script 46 | local ip=$1 47 | local stat=1 48 | 49 | if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then 50 | OIFS=$IFS 51 | IFS='.' 52 | ip=($ip) 53 | IFS=$OIFS 54 | [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ 55 | && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] 56 | stat=$? 57 | fi 58 | return $stat 59 | } 60 | 61 | # 2. Evaluate and Set input parameters 62 | printf "\n" 63 | gotError="Nope" 64 | msgError="" 65 | if valid_ip $1 66 | then 67 | RemoteHost=$1 68 | else 69 | msgError+="Invalid or missing remote host IP address.\n\n" 70 | gotError="Yep" 71 | fi 72 | 73 | if [[ $2 =~ ^[0-9]+$ ]] 74 | then 75 | if (( $2 > 3 && $2 < 86401 )) 76 | then 77 | TestSeconds=$2 78 | else 79 | msgError+="Invalid or missing TestSeconds.\n" 80 | msgError+="Value must be between 10 and 86,400 (24 hours).\n\n" 81 | gotError="Yep" 82 | fi 83 | else 84 | msgError+="Invalid or missing TestSeconds.\n" 85 | msgError+="Value must be an integer between 10 and 86,400 (24 hours).\n\n" 86 | gotError="Yep" 87 | fi 88 | 89 | if [[ "$gotError" == "Yep" ]] 90 | then 91 | printf "glp: missing operand\n" 92 | printf "usage:" 93 | tput bold 94 | printf " glp \n\n" 95 | tput sgr0 96 | printf "$msgError" 97 | exit 98 | fi 99 | 100 | # 3. Initialize Variables 101 | WebSource="https://github.com/Azure/NetworkMonitoring" 102 | strPingTest="PingTest.log" 103 | strPerfTest="PerfTest.log" 104 | strTestFile[1]="Ping.log" 105 | strTestFile[2]="P01perf.log" 106 | strTestFile[3]="P06perf.log" 107 | strTestFile[4]="P16perf.log" 108 | strTestFile[5]="P17perf.log" 109 | strTestFile[6]="P32perf.log" 110 | logDir="data" 111 | OutputArray=() 112 | PingArray=() 113 | PingLoss="Error" 114 | PingSent="Error" 115 | PingP50="Error" 116 | PingP90="Error" 117 | PingP95="Error" 118 | PingMin="Error" 119 | PingMax="Error" 120 | PingAvg="Error" 121 | TestName=() 122 | TestName[1]="Stage 1 of 6: Latency Test..." 123 | TestName[2]="Stage 2 of 6: Single Thread Test..." 124 | TestName[3]="Stage 3 of 6: 6 Thread Test..." 125 | TestName[4]="Stage 4 of 6: 16 Thread Test..." 126 | TestName[5]="Stage 5 of 6: 16 Thread Test with 1Mb window..." 127 | TestName[6]="Stage 6 of 6: 32 Thread Test..." 128 | Threads=() 129 | Threads[1]=0 130 | Threads[2]=1 131 | Threads[3]=6 132 | Threads[4]=16 133 | Threads[5]=16 134 | Threads[6]=32 135 | TPut=() 136 | 137 | # 4. Clear old run files 138 | if [ -d "$logDir" ] 139 | then 140 | rm -f ./$logDir/* 141 | else 142 | mkdir $logDir 143 | fi 144 | 145 | # 5. Validate Ping connectivity (two ping) 146 | ping $RemoteHost -c 2 -W 4 > ./$logDir/$strPingTest 147 | while IFS= read -r line 148 | do 149 | if [[ $line == *100??packet?loss* ]] 150 | then 151 | tput bold 152 | printf "Unable to ping remote machine.\n\n" 153 | tput sgr0 154 | printf "Things to check:\n" 155 | printf " - Ensure the remote server is listening and reachable from this machine\n" 156 | printf " - Check host and network firewalls to ensure ICMPv4 is allowed\n\n" 157 | printf "See $WebSource for more information.\n\n" 158 | exit 159 | fi 160 | done < $logDir/$strPingTest 161 | 162 | # 6. Validate iPerf3 connectivity (two ping) 163 | iperf3 -c $RemoteHost -t 2 -i 0 -P 1 -b 1k --logfile ./$logDir/$strPerfTest 164 | while IFS= read -r line 165 | do 166 | if [[ $line == *error?-?unable?to?connect* ]] 167 | then 168 | tput bold 169 | printf "Unable to start iPerf session.\n\n" 170 | tput sgr0 171 | printf "Things to check:\n" 172 | printf " - Ensure iPerf is running in server mode (iperf3 -s) on the remote host at $RemoteHost\n" 173 | printf " - Ensure remote iPerf server is listening on the default port 5201\n" 174 | printf " - Check host and network firewalls to ensure this port is open on both hosts and any network devices between them\n" 175 | printf " - Ensure iPerf files are installed\n" 176 | printf " - Ensure remote iPerf version is compatible with local version\n\n" 177 | printf "See $WebSource for more information.\n\n" 178 | exit 179 | fi 180 | done < $logDir/$strPerfTest 181 | 182 | # 7. Start Ping Job 183 | printf "$(date '+%m/%d/%Y %H:%M:%S') - " 184 | tput setaf 6 185 | printf "${TestName[1]}\n" 186 | tput sgr0 187 | ping $RemoteHost -c $TestSeconds > ./$logDir/${strTestFile[1]} 188 | 189 | # 8. iPerf Test Loop 190 | for i in {2..6} 191 | do 192 | printf "$(date '+%m/%d/%Y %H:%M:%S') - " 193 | tput setaf 6 194 | printf "${TestName[$i]}\n" 195 | tput sgr0 196 | if [ $i -eq 5 ] 197 | then 198 | iperf3 -c $RemoteHost -t $TestSeconds -i 0 -P ${Threads[$i]} -w1M --logfile ./$logDir/${strTestFile[$i]} 199 | else 200 | iperf3 -c $RemoteHost -t $TestSeconds -i 0 -P ${Threads[$i]} --logfile ./$logDir/${strTestFile[$i]} 201 | fi 202 | done 203 | 204 | # 9. Parse each job file for data 205 | # 9.1 Ping file loop 206 | while IFS= read -r line 207 | do 208 | # Starting ping line loop 209 | if [[ $line == *ttl=* ]] 210 | then 211 | IFS='=' read -r -a array <<< "$line" 212 | PingArray+=(`echo "${array[3]}" | cut -d' ' -f 1`) 213 | elif [[ $line == *received* ]] 214 | then 215 | PingSent=`echo $line | cut -d' ' -f 1` 216 | PingLoss=`echo $line | cut -d',' -f 3 | cut -d' ' -f 2` 217 | elif [[ $line == *min?avg?max* ]] 218 | then 219 | PingMin=`echo $line | cut -d'/' -f 4 | cut -d' ' -f 3` 220 | PingMax=`echo $line | cut -d'/' -f 6` 221 | PingAvg=`echo $line | cut -d'/' -f 5` 222 | fi 223 | done < $logDir/${strTestFile[1]} 224 | 225 | # 9.2 Get percentile vaules 226 | # http://www.dummies.com/education/math/statistics/how-to-calculate-percentiles-in-statistics/ 227 | IFS=$'\n' sortedPing=($(sort -n <<<"${PingArray[*]}")) 228 | PingArrayCount=${#sortedPing[@]} 229 | PingP50=${sortedPing[`getIndex $PingArrayCount 50` - 1]} 230 | PingP90=${sortedPing[`getIndex $PingArrayCount 90` - 1]} 231 | PingP95=${sortedPing[`getIndex $PingArrayCount 95` - 1]} 232 | 233 | # 9.3 iPerf file loop 234 | for i in {2..6} 235 | do 236 | # 9.3.1 iPerf line loop 237 | WholeLine="" 238 | while IFS= read -r line 239 | do 240 | if [ $i -eq 2 ] 241 | then 242 | if [[ $line == *receiver* ]] 243 | then 244 | WholeLine=$line 245 | fi 246 | else 247 | if [[ $line == *SUM* && $line == *receiver* ]] 248 | then 249 | WholeLine=$line 250 | fi 251 | fi 252 | done < $logDir/${strTestFile[$i]} 253 | PaddedLine=`echo "$WholeLine" | cut -c38-55` 254 | ValuePart=`echo "$PaddedLine" | cut -d' ' -f 2` 255 | ScalePart=`echo "$PaddedLine" | cut -d' ' -f 3` 256 | if [[ "$ScalePart" == "Gbits/sec" ]] 257 | then 258 | ScaleConv="Gbps" 259 | elif [[ "$ScalePart" == "Mbits/sec" ]] 260 | then 261 | ScaleConv="Mbps" 262 | else 263 | ScaleConv="$ScalePart" 264 | fi 265 | TPut[$i]="$ValuePart $ScaleConv" 266 | done 267 | tput setaf 6 268 | printf 'Test complete!\n' 269 | tput sgr0 270 | printf "\n" 271 | 272 | # 10. Output results 273 | format1="%-30s %4s %-17s %-17s\n" 274 | format2="%-19s %9s\n" 275 | 276 | temp1="$PingMin/$PingAvg/$PingMax" 277 | temp2="$PingP50/$PingP90/$PingP95" 278 | 279 | #format 1 "| %30s | |4s| | 17s | | 17s |" 280 | #format 2 "| %19s | | %9s |" 281 | #printf " 1 2 3 4 5 6 7 8\n" 282 | #printf "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n" 283 | printf "\n" 284 | printf "Test Bandwidth Loss min/avg/max P50/P90/P95\n" 285 | printf -- "---- --------- ---- ----------- -----------\n" 286 | printf "$format1" "Latency" "$PingLoss" "$temp1" "$temp2" 287 | printf "$format2" "1 Session" "${TPut[2]}" 288 | printf "$format2" "6 Sessions" "${TPut[3]}" 289 | printf "$format2" "16 Sessions" "${TPut[4]}" 290 | printf "$format2" "16 with 1Mb window" "${TPut[5]}" 291 | printf "$format2" "32 Sessions" "${TPut[6]}" 292 | printf "\n" 293 | -------------------------------------------------------------------------------- /AzureCT/PerformanceTesting.md: -------------------------------------------------------------------------------- 1 | # Azure Connectivity Toolkit (AzureCT) 2 | 3 | ## Link Performance 4 | This collection of PowerShell commandlets will download required files to run the Get-LinkPerformance command which runs a series of iPerf load tests and PSPing TCP pings concurrently between a local source and a remote host running iPerf3 in server mode. Six tests of increasing load are performed and results are output at the conclusion of the test. 5 | 6 | [![0]][0] 7 | 8 | >**Note**: This tool is not certified by Microsoft, nor is it supported by Microsoft support. Download and use at your own risk. While the author is an employee of Microsoft, this tool is provided as my best effort to provide insight into the connectivity between an on-premise network and an Azure endpoint. See the [Support and Legal Disclaimers](#support-and-legal-disclaimers) below for more info. 9 | 10 | ### Fast Start 11 | If you just want to install the toolkit, this is the place to start: 12 | 13 | 1. Install [iPerf3][iPerf] on a host (Linux or Windows) on the "far end" or remote side of the network link you're testing. If the remote host is a Window machine you can install the AzureCT and run the Install command mentioned below to install and configure iPerf. If there is a host firewall ensure port 5201 is open to allow iPerf to run. 14 | 2. On the local "near end" host run the following command from PowerShell to install the AzureCT PowerShell module: 15 | 16 | ```powershell 17 | (new-object Net.WebClient).DownloadString("https://aka.ms/AzureCT") | Invoke-Expression 18 | ``` 19 | 20 | 3. Run the Install-LinkPerformance command, this will download PSPing and iPerf as well as configure your windows firewall to allow ICMP and iPerf. 21 | 4. On your local host you now have the Get-LinkPerformance command to run availability tests! 22 | 23 | ### Tool Usage 24 | The Get-LinkPerformance command will run a series of iPerf load tests and PSPing TCP pings concurrently between a local source and a remote host running iPerf3 in server mode. Six tests of increasing load are performed and results are output at the conclusion of the test. 25 | 26 | The remote server must be running iPerf3 in server mode; e.g iPerf3 -s 27 | 28 | On the local machine from which Get-LinkPerformance is executed, various parameters can be used to affect the testing. The output is a combination of both the load test and the latency test while the performance test is running. 29 | 30 | Each row of output represents the summation of a given test, the follow test conditions are run: 31 | - No load, a PSPing TCP test without iPerf3 running, a pure TCP latency test 32 | - 1 Session, a PSPing TCP test with iPerf3 running a single thread of load 33 | - 6 Sessions, a PSPing TCP test with iPerf3 running a six thread load test 34 | - 16 Sessions, a PSPing TCP test with iPerf3 running a 16 thread load test 35 | - 16 Sessions with 1 Mb window, a PSPing TCP test with iPerf3 running a 16 thread load test with a 1 Mb window 36 | - 32 Sessions, a PSPing TCP test with iPerf3 running a 32 thread load test 37 | 38 | For each test iPerf is started and allowed to run for 10 seconds to establish the load and allow it to level. PSPing is then started to record latency during the load test. 39 | 40 | Results from each test are stored in a text file in the AzureCT Tools directory (C:\ACTTools) 41 | 42 | Output for each test is displayed in a table formatted object with the following columns: 43 | 44 | - Name: The name of the test for these values, e.g. No load, 1 session, etc 45 | - Bandwidth: The average bandwidth achieved by iPerf for the given test 46 | - Loss: percentage of packets lost during the PSPing test 47 | - P50 Latency: the 50th percentile of latency seen during the test (median) 48 | 49 | If the Detailed Output option (-DetailedOutput) is used the following columns are also output in a list format: 50 | 51 | - P90 Latency: the 90th percentile of latency seen during the test 52 | - P95 Latency: the 95th percentile of latency seen during the test 53 | - Avg Latency: the average TCP ping latency seen during the test 54 | - Min Latency: the minimum TCP ping latency seen during the test 55 | - Max Latency: the maximum TCP ping latency seen during the test 56 | 57 | #### Prerequisites 58 | This tool has three perquisite resources that must be in place before using: 59 | 60 | 1. An Azure virtual network with a VPN or ExpressRoute site-to-site connection to another (usually "on-premise") network. 61 | 2. A remote host running iPerf3 (compatible with iPerf3.1.3) in server mode (e.g. "iPerf3 -s") with the local firewall allowing port 5201 iPerf traffic as well as the admin port (3389 for Windows or 22 for Linux) open for the TCP ping traffic. 62 | 3. A client PC (or server) running PowerShell 3.0 or greater on the on-premise network that can reach the remote VM. 63 | 64 | #### Installation Instructions 65 | 1. Local Host Instructions: 66 | - Install the AzureCT PowerShell module by running the following command in a PowerShell prompt: 67 | 68 | ```powershell 69 | (new-object Net.WebClient).DownloadString("https://aka.ms/AzureCT") | Invoke-Expression 70 | ``` 71 | 72 | - This will install a new PowerShell module with eight PowerShell cmdlets; Get-AzureNetworkAvailability, Clear-AzureCTHistory, Show-AzureCTResults, Get-HostName, Get-IPTrace, Remove-AzureCT, Install-LinkPerformance, and Get-LinkPerformance. 73 | - Run the Install-LinkPerformance command to download iPerf and PSPing as well as set the firewall rules. Note: The -Force option can be used for unattended installations. 74 | 2. Remote Host Instructions 75 | - Note: If the remote host is Windows, you can install the AzureCT module as in step one above and then run the Install-LinkPerformance command to install and configure iPerf. 76 | - Install iPerf3 from [iperf.fr][iPerf] 77 | - Start iPerf3 in server mode (e.g. "iPerf3 -s") 78 | - Open firewall port 5201 (default iPerf3 port) 79 | - Ensure host is listening on the admin port (3389 for windows or 22 or Linux) 80 | 81 | #### Running the Tool 82 | 1. On the local host, open a PowerShell prompt. 83 | 2. Run the "Get-Module" command to see if AzureCT is loaded, if not run "Import-Module AzureCT" to load the module. 84 | 2. Run the Install-LinkPerformance. This command only needs to be run once for a given host. However if required files are deleted or the host is configured so that Get-LinkPerformance can't run successfully you will be prompted to run Install-LinkPerformance again to get the host enabled for successful testing. 85 | 3. The main cmdlet is Get-LinkPerformance. This function will run six load tests in sequence and output the results. This function has four input parameters: 86 | - **RemoteHost** - This parameter is required and is the Remote Host IP Address. This host must be running iPerf3 in server mode. 87 | - **RemoteHostOS** - This optional parameter signifies the operating system of the REMOTE host. Valid values are "Windows" or "Linux". It is assumed that if the remote host is Linux it is listening on port 22. If Windows PSPing will use the RDP port 3389. 88 | - **TestSeconds** - This optional parameter signifies the duration of the PSPing test in seconds. It is an integer value (whole number). The range of valid values is 10 - 3600 seconds (10 seconds - 1 hour). The default value is 60 seconds (1 minute). 89 | - **DetailedOutput** - This optional parameter affects the output of the data results. Normal output consists of the Test Name, Bandwidth, Packet Loss, and the 50th percentile value for latency. With this parameter enabled addition data fields (Count of packets sent for each test, the Minimum, Maximum, Average, 90th, and 95th percentile latency values) are also sent as output. When this option is used I recommend piping to a variable or formatting the output as shown in step 5. 90 | 4. For the first run, I recommend doing a test run of 10 seconds (minimum TestSecond value). To do this, in the PowerShell prompt run the following command (where 10.0.0.1 is the private IP address of the remote VM, assuming for this example a Windows remote host): 91 | 92 | ```powershell 93 | Get-LinkPerformance -RemoteHost 10.0.0.1 -TestSeconds 10 94 | ``` 95 | 5. Future executions of this script can be set for a given duration, for example a 1 hour test (maximum TestSecond value) with a Linux remote host and detailed output (with detailed output I like to format the results as a table, or pipe to a variable): 96 | 97 | ```powershell 98 | Get-LinkPerformance -RemoteHost 10.0.0.1 -TestSeconds 3600 -RemoteHostOS Linux -DetailedOutput | ft 99 | ``` 100 | or 101 | ```powershell 102 | $myResults = Get-LinkPerformance -RemoteHost 10.0.0.1 -TestSeconds 3600 -RemoteHostOS Linux -DetailedOutput 103 | $myResults | ft 104 | ``` 105 | 106 | #### Tool Output 107 | 108 | [![1]][1] 109 | 110 | While the test is running, the progress of each test run (Stage) will be displayed, and the text of which test run is currently executing will be displayed in the command prompt. 111 | 112 | Once all testing is completed, a table formatted matrix of the test results will be output (the results will be list formatted if the -DetailedOutput option is used). 113 | 114 | These results can be read directly at the command prompt or piped into another command or variable. 115 | 116 | Also, the detailed test results data are stored in text files in the C:\ACTTools directory. 117 | 118 | ## Removing the Azure Connectivity Toolkit 119 | Once testing is complete the Azure VM can be deleted to avoid unnecessary Azure usage (and associated charges) and all local files can be deleted. The only files on the local machine are the PowerShell module files copied from GitHub, iPerf and PSPPing files in the C:\ACTTools directory (if Install-LinkPerformance was run), and potentially three XML files (if Get-AzureNetworkAvailability was run) in the Local Client PC %temp% directory. 120 | 121 | To ensure 100% removal of all artifacts from this tool perform the following step: 122 | 123 | 1. Run the Remove-AzureCT command from PowerShell. This will remove the PowerShell module and any local data files. 124 | 125 | ```powershell 126 | Remove-AzureCT 127 | ``` 128 | ## Incorporated Licenses 129 | This tool incorporates [JQuery](https://jquery.org/license/ "JQuery License") for XML manipulation and is included in the ServerSide files. JQuery.js is included and used under the requirements of the MIT License, and in compliance with the main JQuery license proviso "*You are free to use any jQuery Foundation project in any other project (even commercial projects) as long as the copyright header is left intact.*" 130 | 131 | ## Support and Legal Disclaimers 132 | Microsoft provides no support for this software. All support, assistance, and information is on this site alone. 133 | 134 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 REGENTS 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; INCREMENTAL AZURE COSTS INCURRED THROUGH USE OF THIS SOFTWARE; 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. 135 | 136 | 137 | [0]: ./media/AzureCTPerformance.png "AzureCT Performance Test Diagram" 138 | [1]: ./media/PowerShellTenSeconds.png "Ten-Second Performance Test" 139 | 140 | 141 | [iPerf]: http://iPerf.fr 142 | -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/AzureCT.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/PowerShell/AzureCT/AzureCT.psd1 -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/AzureCT.psm1: -------------------------------------------------------------------------------- 1 | #Get public and private function definition files. 2 | $Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue ) 3 | 4 | #Dot source the files 5 | Foreach($import in @($Public)) 6 | { 7 | Try 8 | { 9 | . $import.fullname 10 | } 11 | Catch 12 | { 13 | Write-Error -Message "Failed to import function $($import.fullname): $_" 14 | } 15 | } 16 | 17 | $ModuleManifest = Test-ModuleManifest -path $PSScriptRoot\AzureCT.psd1 18 | $script:XMLSchemaVersion = ([string]$ModuleManifest.Version.Major) + "." + ([string]$ModuleManifest.Version.Minor) 19 | 20 | Export-ModuleMember -Function Get-AzureNetworkAvailability 21 | Export-ModuleMember -Function Get-IPTrace 22 | Export-ModuleMember -Function Clear-AzureCTHistory 23 | Export-ModuleMember -Function Show-AzureCTResults 24 | Export-ModuleMember -Function Remove-AzureCT 25 | 26 | Export-ModuleMember -Function Install-LinkPerformance 27 | Export-ModuleMember -Function Get-LinkPerformance 28 | -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Clear-AzureCTHistory.ps1: -------------------------------------------------------------------------------- 1 | function Clear-AzureCTHistory { 2 | # Clear-History 3 | # This script deletes local xml file 4 | # if they exist, and calls a web 5 | # service if an IP address is passed 6 | 7 | Param( 8 | [Parameter(ValueFromPipeline=$true)] 9 | [string]$RemoteHost = '' 10 | ) 11 | 12 | Write-Host 13 | Write-Warning "This script will erase all prior Get-AzureNetworkAvailability data on this and the remote server (if a remote address was supplied)" 14 | $theAnswer = Read-Host -Prompt "Do you wish to continue? [Y], n" 15 | if ($theAnswer -eq '') {$theAnswer="Y"} 16 | if ($theAnswer -ne "Y") { 17 | Write-Host "Clear-History canceled, no data was cleared." 18 | return 19 | } 20 | 21 | # Clear remote data if address provided. 22 | if ($RemoteHost -eq '') { 23 | Write-Host "No remote address was provided, no remote data was cleared." 24 | } 25 | else { 26 | Write-Host "Clearing data from the remote server." -ForegroundColor Cyan 27 | $uri = "http://$RemoteHost/ClearHistory.aspx" 28 | $response = (Invoke-WebRequest -Uri $uri -Method Post -Body "Yes").Content 29 | if ($response -eq "Good") { 30 | Write-Host "All Get-AzureNetworkAvailability data was cleared from the remote server." -ForegroundColor Green 31 | } 32 | else { 33 | Write-Warning "An error occured and Get-AzureNetworkAvailability data may not have been cleared from the remote server." 34 | } 35 | } 36 | 37 | # Clear local data if files exist. 38 | Write-Host "Clearing data from local machine..." -ForegroundColor Cyan 39 | $FileList = @() 40 | $FileList += "$env:TEMP\AvailabilityHeader.xml" 41 | $FileList += "$env:TEMP\AvailabilityDetail.xml" 42 | $FileList += "$env:TEMP\AvailabilityTrace.xml" 43 | 44 | ForEach ($File in $FileList) { 45 | If (Test-Path "$env:TEMP\$File") { 46 | try { 47 | Remove-Item -Path "$env:TEMP\$File" -Force 48 | Write-Host "$File was cleared from this computer." -ForegroundColor Green 49 | } 50 | catch { 51 | Write-Warning "$env:TEMP\$File was not cleared from this computer." 52 | } 53 | } 54 | else { 55 | Write-Host "$File was not found on this computer." -ForegroundColor Green 56 | } # End If 57 | } # End ForEach 58 | } # End Function -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Get-AzureNetworkAvailability.ps1: -------------------------------------------------------------------------------- 1 | function Get-AzureNetworkAvailability { 2 | <# 3 | .SYNOPSIS 4 | Makes repeated calls to a web site on a private vnet and logs the success/failure and response times. 5 | 6 | .DESCRIPTION 7 | Generate, collect, and store availability statistics of the network between you and a newly built Windows VM in Azure. 8 | It is designed to provide an indication, over time, of the link between a Virtual Machine in Azure and an on-premise 9 | network. While the focus is on network availability, the test is done from a PC client to an IIS server in Azure. 10 | This provides a view into the availability of an end-to-end scenario, not just a single point or component in the 11 | complex chain that makes up a VPN or an ExpressRoute network connection. The hope is that this will provide insight 12 | into the end-to-end network availability. 13 | 14 | The resultant data set does not provide rich insight if a problem is encountered during a test, over time this will 15 | improve but this initial release only reflects the statistics around availability seen while an active test is running. 16 | 17 | Local Host Output of this command will show: 18 | ! - Successfull Call 19 | . - Unsuccsefull Call (timeout) 20 | * - IP was reached but wrong data or error (404) was returned 21 | 22 | At the end of this function a summary block will display summary information of the entire data set collect. 23 | The data set, stored locally in XML, will be uploaded to the IIS server in Azure. 24 | At the conslusion of this command a web browser will be initiated to show a web page from the IIS Server to observe 25 | the collected data. 26 | 27 | .PARAMETER RemoteHost 28 | This parameter is required and is the Azure VM VNet IP Address. 29 | 30 | .PARAMETER DurationMinutes 31 | This optional parameter signifies the duration of the Get-AzureNetworkAvailability command in minutes. It is an 32 | integer value (whole number). The default value is 1. 33 | 34 | .PARAMETER TimeoutSeconds 35 | This optional parameter signifies how long each call will wait for a response. The default value is 5 seconds. 36 | 37 | .EXAMPLE 38 | Get-AzureNetworkAvailability -RemoteHost 10.0.0.1 39 | 40 | # Get network availability stats from a web server at 10.0.0.1 for one minute (default duration) 41 | 42 | .EXAMPLE 43 | Get-AzureNetworkAvailability -RemoteHost 10.0.0.1 -DurationMinutes 600 44 | 45 | # Get network availability stats from a web server at 10.0.0.1 for ten hours (600 minutes) 46 | 47 | .EXAMPLE 48 | (Get-AzureVM -ServiceName 'myServiceName' -Name 'myVMName').IpAddress | Get-AzureNetworkAvailability 49 | 50 | # Pull local IP address from a VM in Azure and pipe it to the Get-AzureNetworkAvailability cmdlet 51 | 52 | .LINK 53 | https://github.com/tracsman/AzureCT 54 | 55 | .LINK 56 | Show-Results 57 | 58 | .LINK 59 | Clear-History 60 | 61 | .NOTES 62 | A specially built IIS server running in Azure is required for this cmdlet to work properly. 63 | More information can be found at https://github.com/tracsman/AzureCT 64 | 65 | #> 66 | 67 | # Evaluate and Set input parameters 68 | [cmdletBinding()] 69 | Param( 70 | [Parameter(ValueFromPipeline=$true, 71 | Mandatory=$true, 72 | HelpMessage='Enter IP Address of Remote Azure VM')] 73 | [ipaddress]$RemoteHost, 74 | [int]$DurationMinutes=1, 75 | [int]$TimeoutSeconds=5 76 | ) 77 | 78 | # Initialize 79 | $FilePath = $env:TEMP 80 | $HeaderFileName = "$FilePath\AvailabilityHeader.xml" 81 | $DetailFileName = "$FilePath\AvailabilityDetail.xml" 82 | $TraceFileName = "$FilePath\AvailabilityTrace.xml" 83 | $RunDuration = New-TimeSpan -Minutes $DurationMinutes 84 | $GoodTraceCaptured = $false 85 | [int]$MinutesBetweenTracePulls = 1 86 | $LastTraceTime = (Get-Date) - (New-TimeSpan -Minutes $MinutesBetweenTracePulls) 87 | [int]$ReferenceTraceID = 0 88 | [int]$CallCount=0 89 | [int]$JobGood=0 90 | [int]$JobBad=0 91 | [int]$JobMin=2000000000 92 | [int]$JobMax=0 93 | [int]$JobMedian=0 94 | [int]$WrapWidth = $Host.UI.RawUI.BufferSize.Width - 5 95 | $JobID = [System.Guid]::NewGuid().toString() 96 | $ErrorFlag = $false 97 | 98 | # Check for Header File 99 | If ((Test-Path $HeaderFileName) -eq $false) { 100 | [string]$JobHeaderFile = "" 101 | $JobHeaderFile | Out-File -FilePath $HeaderFileName -Encoding ascii} 102 | 103 | # Check for Detail File 104 | If ((Test-Path $DetailFileName) -eq $false) { 105 | [string]$JobDetailFile = "" 106 | $JobDetailFile | Out-File -FilePath $DetailFileName -Encoding ascii} 107 | 108 | # Check for Trace File 109 | If ((Test-Path $TraceFileName) -eq $false) { 110 | [string]$TraceFile = "
" 111 | $TraceFile | Out-File -FilePath $TraceFileName -Encoding ascii} 112 | 113 | # Load Files and Get Ready for new run 114 | # Pull current Header and Detail xml files 115 | [xml]$JobHeaderFile = Get-Content $HeaderFileName 116 | [xml]$JobDetailFile = Get-Content $DetailFileName 117 | [xml]$TraceFile = Get-Content $TraceFileName 118 | 119 | # Create new Job Header xml node (in local file) 120 | $JobStart = Get-Date -Format 's' 121 | $JobHeader = "" 122 | $JobHeader = (@($JobHeaderFile.Jobs.Job)[0]).Clone() 123 | $JobHeader.ID =[string]$JobID 124 | $JobHeader.StartTime = [string]$JobStart 125 | $JobHeader.Target = [string]$RemoteHost.IPAddressToString 126 | $JobHeader.TimeoutSeconds = [string]$TimeoutSeconds 127 | $JobHeaderFile.Jobs.AppendChild($JobHeader) | Out-Null 128 | $JobHeaderFile.Save($HeaderFileName) 129 | 130 | # Job Loop, duration as defined by user input 131 | Try { 132 | Write-Host 133 | Write-Host "Starting Avilability test to $RemoteHost..." -ForegroundColor Cyan 134 | Write-Host 135 | 136 | # Run an initial call to load ARP tables and IIS caches along the call path 137 | Try { 138 | $WebCall = (Invoke-WebRequest -Uri http://$RemoteHost/WebTest.aspx -TimeoutSec 2)} 139 | Catch {} 140 | 141 | $CallArray = @() 142 | $TraceArray = @() 143 | Do { 144 | $CallCount+=1 145 | $CallTime = Get-Date -Format 'yyyy-MM-ddTHH:mm:ss.fff' 146 | $ErrorType = "None" 147 | $CallDisplay = "n" # Null, this should never show 148 | $CallDisplayDescription = "Null" # This should never show 149 | 150 | # Call WebTest.aspx 151 | ########################################### 152 | # The following line is the magic, it is # 153 | # the actual connectivity test being run. # 154 | # $WebCall holds the results of the test. # 155 | # $CallDuration is the call duration in ms.# 156 | ########################################### 157 | 158 | Try { 159 | $TraceArray += Start-Job -ScriptBlock {Get-IPTrace -RemoteHost $args[0] -JobID $args[1] -CallID $args[2]} -Name 'AzureCT.Tracing' -ArgumentList $RemoteHost, $JobID, $CallCount 160 | $CallDuration = Measure-Command {$WebCall = (Invoke-WebRequest -Uri http://$RemoteHost/WebTest.aspx -TimeoutSec $TimeoutSeconds)} 161 | 162 | # Pull server data from the test 163 | $ServerTime = ($WebCall.AllElements | ? {$_.tagName -eq 'HEAD'}).innerText 164 | $Result = ($WebCall.AllElements | ? {$_.tagName -eq 'BODY'}).innerText 165 | } 166 | Catch { 167 | if ($error[0].Exception.Status -eq "Timeout") {$ErrorType = "Timeout"} 168 | Else {$ErrorType = "Other"} # Other Error, probably 404 169 | $WebCall = "" 170 | $CallDuration = "" 171 | $ServerTime = "" 172 | Try {$Result = $error[0].Exception.Message.ToString()} 173 | Catch {$Result = "Unknown Error"} 174 | } 175 | # Validate Server Return 176 | $Valid = [bool]($Result.Trim() -eq '1.0') 177 | 178 | If ($Valid) {$CallDisplay="!"; $CallDisplayDescription="Valid Call Response"} 179 | Elseif ($ErrorType -eq "None") {$CallDisplay="*"; $CallDisplayDescription="Bad Data Returned"; $Result = "Page Title: " + (($WebCall.AllElements | ? {$_.tagName -eq 'TITLE'}).innerText)} 180 | Elseif ($ErrorType -eq "Timeout") {$CallDisplay="."; $CallDisplayDescription="Timeout"} 181 | Else {$CallDisplay="*"; $CallDisplayDescription="Call Response Error"} 182 | 183 | # Do we need to keep the associated trace? 184 | # Note: the Tag field is matched at the end of this script 185 | # and the trace data for those called tagged "true" 186 | # are uploaded to the server. 187 | If (-Not $GoodTraceCaptured -and $Valid) { 188 | $GoodTraceCaptured = $true 189 | $ReferenceTraceID = $CallCount 190 | $LastTraceTime = Get-Date 191 | $Tagged = $true 192 | } 193 | ElseIf (-Not $Valid -and -Not $ErrorFlag) { 194 | $ErrorFlag = $true 195 | $LastTraceTime = Get-Date 196 | $Tagged = $true 197 | } 198 | ElseIf ($LastTraceTime -lt (Get-Date) - (New-TimeSpan -Minutes $MinutesBetweenTracePulls)) { 199 | $LastTraceTime = Get-Date 200 | $Tagged = $true 201 | } 202 | ElseIf ($Valid) { 203 | $Tagged = $false 204 | $ErrorFlag = $false 205 | } 206 | Else { 207 | $Tagged = $false 208 | } 209 | 210 | # Update Counters 211 | If ($Valid) {$JobGood+=1} Else {$JobBad+=1} 212 | [decimal]$SuccessRate = $JobGood/$CallCount*100 213 | $SuccessRate = "{0:N2}" -f $SuccessRate 214 | If ($CallDuration.TotalMilliseconds -lt $JobMin) {$JobMin = $CallDuration.TotalMilliseconds} 215 | If ($CallDuration.TotalMilliseconds -gt $JobMax) {$JobMax = $CallDuration.TotalMilliseconds} 216 | If ($Valid) {$CallArray += $CallDuration.TotalMilliseconds} 217 | 218 | # Create Job Details xml 219 | $JobDetail="" 220 | $JobDetail = (@($JobDetailFile.JobRecords.JobRecord)[0]).Clone() 221 | $JobDetail.JobID = [string]$JobID 222 | $JobDetail.CallID = [string]$CallCount 223 | $JobDetail.TimeStamp = [string]$CallTime 224 | $JobDetail.Return = $Result 225 | $JobDetail.Display = $CallDisplayDescription 226 | $JobDetail.Valid = [string]$Valid 227 | $JobDetail.Duration = [string]$CallDuration.TotalMilliseconds 228 | $JobDetail.Tag = [string]$Tagged 229 | 230 | # Log new results xml to local file 231 | $JobDetailFile.JobRecords.AppendChild($JobDetail) | Out-Null 232 | $JobDetailFile.Save($DetailFileName) 233 | 234 | # Log summary results to local file 235 | ForEach($Node in $JobHeaderFile.Jobs.Job) { 236 | If ($Node.ID -eq $JobID) { 237 | $UpdatedNode = $Node 238 | $UpdatedNode.CallCount = [string]$CallCount 239 | $UpdatedNode.SuccessRate = [string]$SuccessRate 240 | $UpdatedNode.JobMin = [string]$JobMin 241 | $UpdatedNode.JobMax = [string]$JobMax 242 | $UpdatedNode.ReferenceTrace = [string]$ReferenceTraceID 243 | $JobHeaderFile.Jobs.ReplaceChild($UpdatedNode, $Node) | Out-Null 244 | }} 245 | $JobHeaderFile.Save($HeaderFileName) 246 | 247 | # Write output 248 | Write-Host $CallDisplay -NoNewline 249 | If ($CallCount%$WrapWidth -eq 0) {Write-Host} 250 | 251 | # Decide how long to sleep 252 | $SleepTime = 10000 - ((Get-Date) - [datetime]$CallTime).TotalMilliseconds 253 | If ($SleepTime -lt 0) {$SleepTime = 0} 254 | sleep -Milliseconds $SleepTime 255 | } # Do End 256 | While (([datetime]$JobStart + $RunDuration) -gt (Get-Date)) 257 | } # Try End 258 | 259 | Finally { 260 | 261 | # Calculate end of job stats 262 | $JobEnd = Get-Date -Format 's' 263 | 264 | # Get Median Call Latency 265 | $CallArray = $CallArray | Sort 266 | If ($CallArray.count -eq 0) { 267 | $JobMedian = 0 268 | } 269 | ElseIf ($CallArray.count%2) { 270 | $JobMedian = $CallArray[[math]::Floor($CallArray.count/2)] 271 | } 272 | Else { 273 | $JobMedian = ($CallArray[$CallArray.Count/2],$CallArray[$CallArray.count/2-1] | Measure -Average).Average 274 | } 275 | 276 | # Write summary host output 277 | Write-Host 278 | Write-Host 279 | Write-Host "Statistics for $RemoteHost" 280 | 281 | Write-Host " Calls: Sent = " -NoNewline 282 | Write-Host $CallCount -NoNewline 283 | Write-Host ", Received = " -NoNewline 284 | Write-Host $JobGood -NoNewline -ForegroundColor Green 285 | Write-Host " (" -NoNewline 286 | Write-Host $SuccessRate"%" -NoNewline -ForegroundColor Green 287 | Write-Host "), Lost = " -NoNewline 288 | Write-Host $JobBad -ForegroundColor Red 289 | 290 | Write-Host "Approximate round trip times in milli-seconds:" 291 | Write-Host " Minimum = " -NoNewline 292 | Write-Host $JobMin -NoNewline 293 | Write-Host "ms, Maximum = " -NoNewline 294 | Write-Host $JobMax -NoNewline 295 | Write-Host "ms, Median = " -NoNewline 296 | Write-Host $JobMedian -NoNewline 297 | Write-Host "ms" 298 | 299 | Write-Host 300 | 301 | # Update Job Header xml in local file 302 | ForEach($node in $JobHeaderFile.Jobs.Job) { 303 | If ($node.ID -eq $JobID) { 304 | $UpdatedNode = $Node 305 | $UpdatedNode.EndTime = [string]$JobEnd 306 | $UpdatedNode.JobMedian = [string]$JobMedian 307 | $JobHeaderFile.Jobs.ReplaceChild($UpdatedNode, $Node) | Out-Null 308 | } 309 | } 310 | $JobHeaderFile.Save($HeaderFileName) 311 | 312 | # Wait for traces to finish 313 | While ((Get-Job -Name "AzureCT.Tracing" | Where State -eq 'Running').Count -gt 0) { 314 | Sleep -Seconds 2 315 | Write-Host "Waiting for Trace Route jobs to finish..." 316 | } 317 | 318 | # Build the Trace File for Upload 319 | ForEach ($Node in $JobDetailFile.JobRecords.JobRecord) { 320 | If ($Node.JobID -eq $JobID -and $Node.Tag -eq "True") { 321 | $PSJobData = Receive-Job -Job $TraceArray[$Node.CallID - 1] 322 | ForEach ($TraceRow in $PSJobData) { 323 | $TraceNode ="" 324 | $TraceNode = (@($TraceFile.TraceRecords.TraceRecord)[0]).Clone() 325 | $TraceNode.JobID = [string]$TraceRow.JobID 326 | $TraceNode.CallID = [string]$TraceRow.CallID 327 | $TraceNode.TimeStamp = [string]$TraceRow.TimeStamp 328 | $TraceNode.HopID = [string]$TraceRow.HopCount 329 | $TraceNode.Address = [string]$TraceRow.Address 330 | $TraceNode.TripTime = [string]$TraceRow.RoundTripTime 331 | $TraceFile.TraceRecords.AppendChild($TraceNode) | Out-Null 332 | $TraceFile.Save($TraceFileName) 333 | } # End ForEach $TraceRow 334 | } # End If 335 | } # End ForEach $Node 336 | 337 | ForEach ($Job in (Get-Job)) { 338 | Remove-Job $Job 339 | } 340 | 341 | # Upload Header, Detail, and Trace xml to server 342 | $uri = "http://$RemoteHost/Upload.aspx" 343 | $contentType = "multipart/form-data" 344 | Try { 345 | $header = @{FileID = "Header"} 346 | $HeaderUploadResponse = (Invoke-WebRequest -Uri $uri -ContentType $contentType -Method Post -Body $JobHeaderFile.OuterXml -Headers $header -TimeoutSec 10).Content.Trim() 347 | 348 | $header = @{FileID = "Detail"} 349 | $DetailUploadResponse = (Invoke-WebRequest -Uri $uri -ContentType $contentType -Method Post -Body $JobDetailFile.OuterXml -Headers $header -TimeoutSec 15).Content.Trim() 350 | 351 | $header = @{FileID = "Trace"} 352 | $TraceUploadResponse = (Invoke-WebRequest -Uri $uri -ContentType $contentType -Method Post -Body $TraceFile.OuterXml -Headers $header -TimeoutSec 10).Content.Trim() 353 | } 354 | Catch { 355 | $HeaderUploadResponse = "Bad" 356 | $DetailUploadResponse = "Bad" 357 | $TraceUploadResponse = "Bad" 358 | } 359 | 360 | Write-Host 361 | If ($HeaderUploadResponse -eq "Good" -and $DetailUploadResponse -eq "Good" -and $TraceUploadResponse -eq "Good") { 362 | Write-Host "Data uploaded to remote server sucessfully" 363 | 364 | # Spawn local web browser showing report details from server 365 | Write-Host "Launching browser to http://$RemoteHost" 366 | Start-Process -FilePath "http://$RemoteHost" 367 | 368 | # Close and Clean Up 369 | # Clean up local files 370 | Remove-Item $HeaderFileName 371 | Remove-Item $DetailFileName 372 | Remove-Item $TraceFileName 373 | } 374 | Else { 375 | Write-Warning "Data upload to remote server failed." 376 | Write-Warning "Please check to ensure the remote server has all the files required to run this tool." 377 | Write-Warning "Also ensure the XML files in the 'c:\inetpub\wwwroot' have 'Full Control' file access for the local IIS_IUSRS account" 378 | } 379 | Write-Host 380 | } # Finally End 381 | } # Function End 382 | 383 | -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Get-HostName.ps1: -------------------------------------------------------------------------------- 1 |  2 | function Get-HostName { 3 | param ( 4 | [Parameter(Mandatory = $true, ValueFromPipeline=$true, HelpMessage='Enter IP Address')] 5 | [ipaddress] $HostIP) 6 | Try { 7 | Return [System.Net.Dns]::GetHostEntry($HostIP).HostName 8 | } 9 | Catch { 10 | Return '' 11 | } 12 | } -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Get-IPTrace.ps1: -------------------------------------------------------------------------------- 1 | function Get-IPTrace { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter(Mandatory = $true, ValueFromPipeline=$true, HelpMessage='Enter IP Address of Remote Azure VM')] 5 | [ipaddress] $RemoteHost, 6 | [System.Guid]$JobID = '00000000-0000-0000-0000-000000000000', 7 | [int]$CallID=0) 8 | 9 | $Ping = New-Object -TypeName System.Net.NetworkInformation.Ping 10 | $PingOptions = New-Object -TypeName System.Net.NetworkInformation.PingOptions 11 | $Payload = [byte[]][char[]]'MyData' 12 | 13 | $i = 1 14 | while ($i -le 30) { 15 | $TraceStart = Get-Date -Format 'yyyy-MM-ddTHH:mm:ss.fff' 16 | $PingOptions.Ttl = $i 17 | $Response = $Ping.Send($RemoteHost, 500, $Payload, $PingOptions) 18 | $Trace = New-Object -TypeName PSObject -Property @{ 19 | JobID = $JobID 20 | CallID = $CallID 21 | TimeStamp = $TraceStart 22 | HopCount = $PingOptions.Ttl 23 | Address = $Response.Address 24 | RoundTripTime = $Response.RoundtripTime 25 | } 26 | $TraceStatus = $Response.Status 27 | If ($TraceStatus -eq 'TtlExpired') { 28 | $PingOptions.Ttl = $i + 2 29 | $Response = $Ping.Send($Trace.Address, 500, $Payload, $PingOptions) 30 | If ($Response.Status -eq 'TimedOut') { 31 | $Trace.RoundTripTime = '*' 32 | } 33 | Else { 34 | $Trace.RoundTripTime = $Response.RoundtripTime 35 | } 36 | } 37 | ElseIf ($TraceStatus -eq 'TimedOut') { 38 | $Trace.Address = 'Hop Timeout' 39 | $Trace.RoundTripTime = '*' 40 | } 41 | Write-Output -InputObject $Trace 42 | 43 | If ($TraceStatus -eq 'Success') {Break} 44 | 45 | $i++ 46 | } # End While 47 | 48 | } # End Function -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Get-LinkPerformance.ps1: -------------------------------------------------------------------------------- 1 | function Get-LinkPerformance { 2 | # 1. Evaluate and Set input parameters 3 | # 2. Initialize 4 | # 3. Clear old run files 5 | # 4. Validate iPerf3 connectivity (two ping)Error Stop 6 | # 5. Validate PSPing connectivity (two ping)Error Stop 7 | # 6. Main Test Loop 8 | # 6.1 Start iPerf job if required 9 | # 6.2 Start PSPing job 10 | # 6.3 Wait for jobs to finish 11 | # 7. Parse each job file for data 12 | # 7.1 iPerf3 log file line loop 13 | # 7.2 PSPing log file line loop 14 | # 7.3 Get Percentile values 15 | # 7.4 Add results to object array 16 | # 8. Output results 17 | 18 | <# 19 | .SYNOPSIS 20 | Run a series of iPerf load tests and PSPing TCP pings concurrently between a local source and a remote host 21 | running iPerf3 in server mode. Seven tests of increasing load are performed and results are output at the 22 | conclusion of the test. 23 | 24 | .DESCRIPTION 25 | Run a series of iPerf load tests and PSPing TCP pings concurrently between a local source and a remote host 26 | running iPerf3 in server mode. Seven tests of increasing load are performed and results are output at the 27 | conclusion of the test. 28 | 29 | The remote server must be running iPerf3 in server mode; e.g iPerf3 -s 30 | 31 | On the local server from which this function is run, vaious parameters can be used to affect the testing. 32 | The output is a combination of both the load test and the latency test while the perf test is running. 33 | Each row of output represtents the summation of a given test, the follow test conditions are run: 34 | - No load, a PSPing TCP test without iPerf3 running, a pure latency test 35 | - 1 Session, a PSPIing TCP test with iPerf3 running a single thread of load 36 | - 6 Sessions, a PSPing TCP test with iPerf3 running a six thread load test 37 | - 16 Sessions, a PSPing TCP test with iPerf3 running a 16 thread load test 38 | - 16 Sessions with 1Mb window, a PSPing TCP test with iPerf3 running a 16 thread load test with a 1Mb window 39 | - 32 Sessions, a PSPing TCP test with iPerf3 running a 32 thread load test 40 | 41 | For each test iPerf is started and allowed to run for 10 seconds to establish the load and allow it to level. 42 | PSPing is then started to record latency during the load test. 43 | 44 | Results from each test are stored in a text file in the AzureCT Tools directory (C:\ACTTools) 45 | 46 | Output for each test is displayed in a table formatted object with the following columns: 47 | - Name: The name of the test for these values, eg No load, 1 session, etc 48 | - Bandwidth: The average bandwidth achieved by iPerf for the given test 49 | - Loss: percentage of packets lost during the PSPing test 50 | - P50 Latency: the 50th percentile of latency seen during the test 51 | 52 | If the detailed output option (-DetailedOutput) is used, the following columns are also output: 53 | - P90 Latency: the 90th percentile of latency seen during the test 54 | - P95 Latency: the 95th percentile of latency seen during the test 55 | - Avg Latency: the average TCP ping latency seen during the test 56 | - Min Latency: the minumum TCP ping latency seen during the test 57 | - Max Latency: the maximum TCP ping latency seen during the test 58 | 59 | .PARAMETER RemoteHost 60 | This parameter is required and is the Remote Host IP Address. This host must be running iPerf3 in server mode and 61 | be listening on either port 22 (SSH) for Linux hosts or 3389 (RDP) for Windows hosts. 62 | 63 | .PARAMETER RemoteHostOS 64 | This optional parameter signifies the operating system of the REMOTE host. Valid values are "Windows" or "Linux". 65 | It is assumed that if the remote host is Linux it is listening on port 22. If Windows PSPing will use the RDP port 66 | 3389. 67 | 68 | .PARAMETER TestSeconds 69 | This optional parameter signifies the duration of the PSPing test in seconds. It is an integer value (whole number). 70 | The range of valid values is 10 - 3600 seconds (10 seconds - 1 hour). The default value is 60 seconds (1 minute). 71 | 72 | .PARAMETER DetailedOutput 73 | This optional parameter affects the output of the data results. Normal output consists of the Test Name, Bandwidth, 74 | Packet Loss, and the 50th percentile value for latency. With this parameter enabled addition data fields (Count of 75 | packets sent for each test, the Minimum, Maximum, Average, 90th, and 95th percentile latency values) are also sent 76 | as output. 77 | 78 | .EXAMPLE 79 | Get-LinkPerformance -RemoteHost 10.0.0.1 80 | 81 | This command returns network performance stats from a windows server at 10.0.0.1 for 6 one minute tests (default 82 | host type (Windows) and test duration (60 seconds)) 83 | 84 | .EXAMPLE 85 | Get-LinkPerformance -RemoteHost 10.0.0.1 -HostType Linux -TestSeconds 3600 86 | 87 | This command returns network performance stats from a Linux server at 10.0.0.1 for 6 one-hour tests (3600 seconds) 88 | 89 | .EXAMPLE 90 | (Get-AzureVM -ServiceName 'myServiceName' -Name 'myVMName').IpAddress | Get-LinkPerformance 91 | 92 | This command pulls the VNet IP address from a VM in Azure and pipes it to the Get-AzureNetworkAvailability cmdlet 93 | 94 | .LINK 95 | https://github.com/Azure/NetworkMonitoring 96 | 97 | .NOTES 98 | This script will run against a remote server that must be running iPerf3 in server mode with firewall ports 99 | open to allow iPerf and the approprate PSPing port (22 or 3389). If the remote server is a windows machine 100 | an easy way to ensure proper configuration is to install the LinkPerformance tool on that remote machine and 101 | then run iPerf3 in server mode (iperf3 -s) 102 | More information can be found at https://github.com/Azure/NetworkMonitoring 103 | 104 | #> 105 | 106 | # 1. Evaluate and Set input parameters 107 | [cmdletBinding()] 108 | Param( 109 | [Parameter(ValueFromPipeline=$true, 110 | Mandatory=$true, 111 | HelpMessage='Enter IP Address of Remote Host')] 112 | [ipaddress]$RemoteHost, 113 | [ValidateSet(“Windows”,”Linux”)] 114 | [string]$RemoteHostOS="Windows", 115 | [ValidateRange(10,3600)] 116 | [int]$TestSeconds=60, 117 | [switch]$DetailedOutput=$false 118 | ) 119 | 120 | # 2. Initialize 121 | $ToolPath = "C:\ACTTools\" 122 | $WebSource = "https://github.com/Azure/NetworkMonitoring" 123 | $FileArray = "P00", "P01", "P06", "P16", "P17", "P32" 124 | $PingDuration = $TestSeconds 125 | $LoadDuration = $TestSeconds + 10 126 | If ($RemoteHostOS -eq "Windows") {$PingPort="3389"} Else {$PingPort="22"} 127 | [String]$HostPort = [string]$RemoteHost + ":" + [String]$PingPort 128 | 129 | # 3. Clear old run files 130 | Remove-Job -Name ACT.LinkPerf -Force -ErrorAction SilentlyContinue 131 | If (Test-Path $ToolPath"TestPing.log"){Remove-Item $ToolPath"TestPing.log"} 132 | If (Test-Path $ToolPath"TestPerf.log"){Remove-Item $ToolPath"TestPerf.log"} 133 | If (Test-Path $ToolPath"P*ping.log"){Remove-Item $ToolPath"P*ping.log"} 134 | If (Test-Path $ToolPath"P*perf.log"){Remove-Item $ToolPath"P*perf.log"} 135 | 136 | # 4. Validate iPerf3 connectivity (two ping)Error Stop 137 | $FileName = $ToolPath + "\TestPerf.log" 138 | $iPerfJob = Start-Job -ScriptBlock {C:\ACTTools\iperf3.exe -c $args[0] -t 2 -i 0 -P 1 --logfile $args[1]} -Name 'ACT.LinkPerf' -ArgumentList "$RemoteHost", "$FileName" 139 | Wait-Job -Name "ACT.LinkPerf" | Out-Null 140 | # Line Loop 141 | $TPut = "Error" 142 | Try { 143 | $Lines = Get-Content $FileName -ErrorAction Stop 144 | ForEach ($Line in $Lines) { 145 | If (($Line -like "*receiver*")) {$TPut = $Line.Substring(38,17).Trim()} # End If 146 | } # End For 147 | } # End Try 148 | Catch {} 149 | If ($TPut -eq "Error") { 150 | Write-Host 151 | Write-Warning "Unable to start iPerf session. 152 | 153 | Things to check: 154 | - Ensure iPerf is running in server mode (iperf3 -s) on the remote host at $RemoteHost 155 | - Ensure remote iPerf server is listening on the default port 5201 156 | - Check host and network firewalls to ensure this port is open on both hosts and any network devices between them 157 | - Ensure iPerf files are installed in C:\ACTTools, if not rerun Install-LinkPerformance 158 | - Ensure remote iPerf version is compatible with local version 159 | 160 | See $WebSource for more information." 161 | Return } # End If 162 | 163 | # 5. Validate PSPing connectivity (two ping)Error Stop 164 | $FileName = $ToolPath+"\TestPing.log" 165 | $iPerfJob = Start-Job -ScriptBlock {C:\ACTTools\psping.exe -n 2 -4 $args[0] -nobanner > $args[1]} -Name 'ACT.LinkPerf' -ArgumentList "$HostPort", "$FileName" 166 | Wait-Job -Name "ACT.LinkPerf" | Out-Null 167 | # Line Loop 168 | $Loss = "Error" 169 | Try { 170 | $Lines = Get-Content $FileName -ErrorAction Stop 171 | ForEach ($Line in $Lines) { 172 | If ($Line -like "*Sent*") { 173 | $Loss = $Line.Substring($Line.IndexOf("(",0)+1,$Line.IndexOf(")",0)-$Line.IndexOf("(",0)-1) 174 | } # End If 175 | } # End For 176 | } # End Try 177 | Catch {} 178 | If ($Loss -eq "100% loss" -or $Loss -eq "Error") { 179 | Write-Host 180 | Write-Warning "Unable to TCP ping remote machine. 181 | 182 | Things to check: 183 | - Ensure $HostPort is listening and reachable from this machine 184 | - Ensure remote OS attribute setting is correct, it's currently set to ""$RemoteHostOS"" 185 | - Check host and network firewalls to ensure this port is open 186 | - Ensure PSPing.exe is installed in C:\ACTTools, if not rerun Install-LinkPerformance 187 | 188 | See $WebSource for more information." 189 | Return 190 | } # End If 191 | 192 | 193 | # 6. Main Test Loop 194 | ForEach ($FilePrefix in $FileArray) { 195 | switch($FilePrefix) { 196 | "P00" {$Threads = 00; $TestName = "Stage 1 of 6: No Load Ping Test..."} 197 | "P01" {$Threads = 01; $TestName = "Stage 2 of 6: Single Thread Test..."} 198 | "P06" {$Threads = 06; $TestName = "Stage 3 of 6: 6 Thread Test..."} 199 | "P16" {$Threads = 16; $TestName = "Stage 4 of 6: 16 Thread Test..."} 200 | "P17" {$Threads = 16; $TestName = "Stage 5 of 6: 16 Thread Test with 1Mb window..."} 201 | "P32" {$Threads = 32; $TestName = "Stage 6 of 6: 32 Thread Test..."} 202 | default {Write-Error "Invalid FilePrefix, execution stopping!"; Return} 203 | } # End Switch 204 | 205 | # Decalare Test Starting 206 | Write-Host (Get-Date)' - ' -NoNewline 207 | Write-Host $TestName -ForegroundColor Cyan 208 | 209 | # 6.1 Start iPerf job if required 210 | $FileName = $ToolPath + "\" + $FilePrefix + "perf.log" 211 | Switch($FilePrefix) { 212 | "P00" {} 213 | "P17" { 214 | $iPerfJob = Start-Job -ScriptBlock {C:\ACTTools\iperf3.exe -c $args[0] -t $args[1] -i 0 -P $args[2] -w1M --logfile $args[3]} -Name 'ACT.LinkPerf' -ArgumentList "$RemoteHost", "$LoadDuration", "$Threads", "$FileName" 215 | Sleep -Seconds 5} 216 | default { 217 | $iPerfJob = Start-Job -ScriptBlock {C:\ACTTools\iperf3.exe -c $args[0] -t $args[1] -i 0 -P $args[2] --logfile $args[3]} -Name 'ACT.LinkPerf' -ArgumentList "$RemoteHost", "$LoadDuration", "$Threads", "$FileName" 218 | Sleep -Seconds 5} 219 | } # End Switch 220 | 221 | # 6.2 Start PSPing job 222 | $FileName = $ToolPath + "\" + $FilePrefix + "ping.log" 223 | [string]$StringDuration = $PingDuration.ToString() + "s" 224 | $iPerfJob = Start-Job -ScriptBlock {C:\ACTTools\psping.exe -n $args[0] -4 $args[1] -nobanner > $args[2]} -Name 'ACT.LinkPerf' -ArgumentList "$StringDuration", "$HostPort", "$FileName" 225 | 226 | # 6.3 Wait for jobs to finish 227 | If ($FilePrefix -eq "P00") {$time = $PingDuration + 2} 228 | Else {$time = $LoadDuration + 1} # End If 229 | foreach($i in (1..$time)) { 230 | $percentage = $i / $time 231 | $remaining = New-TimeSpan -Seconds ($time - $i) 232 | $message = "{0:p0} complete, remaining time {1}" -f $percentage, $remaining 233 | Write-Progress -Activity $message -PercentComplete ($percentage * 100) -CurrentOperation $TestName 234 | Start-Sleep 1 235 | } # End Foreach 236 | While ((Get-Job -Name 'ACT.LinkPerf' -ErrorAction SilentlyContinue | Where State -eq 'Running').Count -gt 0) { 237 | Write-Verbose "Waiting for job threads to finish..." 238 | Sleep 2 239 | } # End While 240 | } # End For 241 | 242 | Write-Host "Testing Complete!" -ForegroundColor Cyan 243 | 244 | # 7. Parse each job file for data 245 | $TestResults=@() 246 | # File Loop 247 | ForEach ($FilePrefix in $FileArray) { 248 | switch($FilePrefix) { 249 | "P00" {$TestName = "No Load"} 250 | "P01" {$TestName = "1 Session"} 251 | "P06" {$TestName = "6 Sessions"} 252 | "P16" {$TestName = "16 Sessions"} 253 | "P17" {$TestName = "16 Sessions with 1Mb window"} 254 | "P32" {$TestName = "32 Sessions"} 255 | default {} 256 | } # End Switch 257 | 258 | # 7.1 iPerf3 log file line loop 259 | $FileName = $ToolPath + "\" + $FilePrefix + "perf.log" 260 | $TPut = "Error" 261 | If ($FilePrefix -eq "P00") { 262 | $TPut = "N/A"} 263 | Else { 264 | Try { 265 | $Lines = Get-Content $FileName -ErrorAction Stop 266 | ForEach ($Line in $Lines) { 267 | If ($FilePrefix -eq "P01") {If (($Line -like "*receiver*")) {$TPut = $Line.Substring(38,17).Trim()} #End If 268 | } 269 | Else { 270 | If (($Line -like "*SUM*" -and $Line -like "*receiver*")) {$TPut = $Line.Substring(38,17).Trim()} #End If 271 | } # End Else 272 | } # End For 273 | } # End Try 274 | Catch {Write-Warning "Error reading or processing file: $FileName"} 275 | } # End If 276 | 277 | 278 | # 7.2 PSPing log file line loop 279 | $FileName = $ToolPath + "\" + $FilePrefix + "ping.log" 280 | $PingArray = New-Object System.Collections.Generic.List[System.Object] 281 | $PingLoss = "Error" 282 | $PingSent = "Error" 283 | $PingP50 = "Error" 284 | $PingP90 = "Error" 285 | $PingP95 = "Error" 286 | $PingMin = "Error" 287 | $PingMax = "Error" 288 | $PingAvg = "Error" 289 | Try { 290 | $Lines = Get-Content $FileName -ErrorAction Stop 291 | ForEach ($Line in $Lines) { 292 | If ($Line.Contains("Connecting")) { 293 | $Step1 = (($Line -split ':')[4]) 294 | $Step2 = $Step1.Trim() 295 | [Decimal]$Step3 = $Step2.TrimEnd("ms") 296 | $PingArray.Add($Step3) 297 | } # EndIf 298 | If ($Line -like "*Sent*") { 299 | $PingSent = $Line.Substring($Line.IndexOf("=", $Line.IndexOf("Sent",0))+2, $Line.IndexOf(",", $Line.IndexOf("Sent",0))-$Line.IndexOf("=", $Line.IndexOf("Sent",0))-2) 300 | $PingLoss = $Line.Substring($Line.IndexOf("(",0)+1,$Line.IndexOf(")",0)-$Line.IndexOf("(",0)-1) 301 | } # End If 302 | If ($Line -like "*Minimum*") { 303 | $PingMin = $Line.Substring($Line.IndexOf("=", $Line.IndexOf("Minimum",0))+2, $Line.IndexOf(",", $Line.IndexOf("Minimum",0))-$Line.IndexOf("=", $Line.IndexOf("Minimum",0))-2) 304 | $PingMax = $Line.Substring($Line.IndexOf("=", $Line.IndexOf("Maximum",0))+2, $Line.IndexOf(",", $Line.IndexOf("Maximum",0))-$Line.IndexOf("=", $Line.IndexOf("Maximum",0))-2) 305 | $PingAvg = $Line.Substring($Line.IndexOf("=", $Line.IndexOf("Average",0))+2) 306 | } # End If 307 | } # End For 308 | } # End Try 309 | Catch {Write-Warning "Error reading or processing file: $FileName"} 310 | 311 | # 7.3 Get Percentile values 312 | # Remove the warm up ping and sort the arrary 313 | $PingArray.RemoveAt(0) 314 | $SortedArrary = $PingArray | Sort-Object 315 | # http://www.dummies.com/education/math/statistics/how-to-calculate-percentiles-in-statistics/ 316 | # Pick 50th Percentile 317 | If ($SortedArrary.count%.5) {$PingP50 = $SortedArrary[[math]::Ceiling($SortedArrary.count*.5)-1]} 318 | Else {$PingP50 = ($SortedArrary[$SortedArrary.Count*.5] + $SortedArrary[$SortedArrary.count*.5-1])/2} 319 | # Pick 90th Percentile 320 | If ($SortedArrary.count%.9) {$PingP90 = $SortedArrary[[math]::Ceiling($SortedArrary.count*.9)-1]} 321 | Else {$PingP90 = ($SortedArrary[$SortedArrary.Count*.9] + $SortedArrary[$SortedArrary.count*.9-1])/2} 322 | # Pick 95th Percentile 323 | If ($SortedArrary.count%.95) {$PingP95 = $SortedArrary[[math]::Ceiling($SortedArrary.count*.95)-1]} 324 | Else {$PingP95 = ($SortedArrary[$SortedArrary.Count*.95] + $SortedArrary[$SortedArrary.count*.95-1])/2} 325 | 326 | # 7.4 Add results to object array 327 | $Test = New-Object -TypeName PSObject 328 | $Test | Add-Member -Name 'Name' -MemberType NoteProperty -Value $TestName 329 | $Test | Add-Member -Name 'Bandwidth' -MemberType NoteProperty -Value $TPut 330 | $Test | Add-Member -Name 'Count' -MemberType NoteProperty -Value $PingSent 331 | $Test | Add-Member -Name 'Loss' -MemberType NoteProperty -Value $PingLoss 332 | $Test | Add-Member -Name 'P50' -MemberType NoteProperty -Value $PingP50'ms' 333 | $Test | Add-Member -Name 'P90' -MemberType NoteProperty -Value $PingP90'ms' 334 | $Test | Add-Member -Name 'P95' -MemberType NoteProperty -Value $PingP95'ms' 335 | $Test | Add-Member -Name 'Avg' -MemberType NoteProperty -Value $PingAvg 336 | $Test | Add-Member -Name 'Min' -MemberType NoteProperty -Value $PingMin 337 | $Test | Add-Member -Name 'Max' -MemberType NoteProperty -Value $PingMax 338 | 339 | $TestResults += $Test 340 | } # End Foreach 341 | 342 | # 8. Output results 343 | If ($DetailedOutput) {Write-Output $TestResults} 344 | Else {Write-Output $TestResults | Select Name, Bandwidth, Loss, P50} 345 | 346 | } # End Function 347 | -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Get-Test.ps1: -------------------------------------------------------------------------------- 1 | Function Get-Test { 2 | Write-Host "Get-Test Start" 3 | Write-Host "Get-Test End" 4 | } -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Install-LinkPerformance.ps1: -------------------------------------------------------------------------------- 1 | function Install-LinkPerformance{ 2 | # 1. Warning check 3 | # 2. Initialize 4 | # 3. Create C:\ACTTools dir 5 | # 4. Check for iPerf files 6 | # 4.1 If either are needed, download, extract 7 | # 5. Check for PSPing 8 | # 5.1 If needed, download 9 | # 6. Check other files 10 | # 7. Pull from GitHub if needed 11 | # 8. Kill PSPing popup 12 | # 9. Open Firewall rules 13 | 14 | <# 15 | .SYNOPSIS 16 | Downloads critial files required to run the Get-LinkPerformance command in the Azure Connectivity Toolkit. 17 | 18 | .DESCRIPTION 19 | To enable the Get-LinkPerformance command to run succesfully, certain third party applications are 20 | needed as well as local host configurations. The Install-LinkPerformance command will download and 21 | configure these requirements. 22 | 23 | This command only needs to be run once for a given host. However if required files are deleted or 24 | the host is configured so that Get-LinkPerformance can't run successfully you will be prompted to 25 | run Install-LinkPerformance again to get the host enabled for successfull testing. 26 | 27 | When called, this cmdlet will perform the following step: 28 | 1. Create a C:\ACTTools directory 29 | 2. Download iPerf3 files to the directory 30 | 3. Download PSPing to the directory 31 | 4. Download two files from GitHub (a firewalls rule script, and a readme file) 32 | 5. Accept the EULA for PSPing 33 | 6. Open the local host firewall for ICMP and Port 5201 traffic 34 | 35 | .PARAMETER Force 36 | This optional parameter will bypass the "Are you sure" prompt and enable a silent or scripted installation. 37 | 38 | .EXAMPLE 39 | Install-LinkPerformance 40 | 41 | This command will prompt the user to ensure they accept the changes performed by this installation. If conditions 42 | are accepted, the installation continues, if not accepted, the installation ends with no changes make to the host. 43 | 44 | .EXAMPLE 45 | Install-LinkPerformance -Force 46 | 47 | This command will bypass the user prompt and begin the installation and configuration changes. 48 | 49 | .LINK 50 | https://github.com/Azure/NetworkMonitoring 51 | 52 | #> 53 | 54 | 55 | Param([switch]$Force=$false) 56 | 57 | # 1. Warning check 58 | If (-not $Force) { 59 | Write-Host 60 | Write-Host " " -BackgroundColor Black 61 | Write-Host " *************************** " -ForegroundColor Red -BackgroundColor Black 62 | Write-Host " *** *** " -ForegroundColor Red -BackgroundColor Black 63 | Write-Host " ***" -ForegroundColor Red -BackgroundColor Black -NoNewline 64 | Write-Host " !!!Warning!!! " -ForegroundColor Yellow -BackgroundColor Black -NoNewline 65 | Write-host "*** " -ForegroundColor Red -BackgroundColor Black 66 | Write-Host " *** *** " -ForegroundColor Red -BackgroundColor Black 67 | Write-Host " *************************** " -ForegroundColor Red -BackgroundColor Black 68 | Write-Host " " -BackgroundColor Black 69 | Write-Host 70 | Write-Host " This script will install 3rd party products: iPerf3 and PSPing" -ForegroundColor Cyan 71 | Write-Host " As well as open firewall port 5201 and allow ICMPv4" -ForegroundColor Cyan 72 | Write-Host 73 | $foo = Read-Host -Prompt "Are you sure you wish to continue? [y]" 74 | If ($foo -ne "y" -and $foo -ne "") {Return} 75 | 76 | } # End If 77 | 78 | 79 | # 2. Initialize 80 | $ToolPath = "C:\ACTTools\" 81 | $GitHubURL = "https://raw.githubusercontent.com/tracsman/NetworkMonitoring/LinkPerf/AzureCT/PowerShell/AzureCT/Public/" 82 | $PSPingURL = "https://live.sysinternals.com/psping.exe" 83 | $iPerf3URL = "https://iperf.fr/download/windows/iperf-3.1.3-win64.zip" 84 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 85 | 86 | # 3. Create C:\ACTTools dir 87 | If (-Not (Test-Path $ToolPath)){New-Item -ItemType Directory -Force -Path $ToolPath | Out-Null} 88 | 89 | 90 | # 4. Check for iPerf files 91 | # Yes I know I should make the file pull (and other things) a callable function, but lazy is ok sometimes 92 | If (-Not (Test-Path $ToolPath"iperf3.exe") -or -Not (Test-Path $ToolPath"cygwin1.dll")){ 93 | # 4.1 If either are needed, download, extract 94 | $File = $ToolPath + "iperf-3.1.3-win64.zip" 95 | Try { 96 | $webClient = new-object System.Net.WebClient 97 | $webClient.DownloadFile($iPerf3URL, $File) 98 | } 99 | Catch { 100 | Write-Host 101 | Write-Warning "Something bad happened with the iPerf download. Most likely either files are missing at the source or this host doesn't have internet access." 102 | Write-Host 103 | Write-Host "You can manually add the files and rerun this Install script." 104 | Write-Host "To manually install iPerf3:" 105 | Write-Host " 1. Download the zip file from $iPerf3URL" 106 | Write-Host " 2. Extract zipped files (iPerf3.exe and cygwin1.dll) to $ToolPath" 107 | Write-Host " 3. With those files in place, rerun this install." 108 | Write-Host 109 | Return 110 | } # End Try 111 | 112 | Try { 113 | Add-Type -AssemblyName System.IO.Compression.FileSystem 114 | [System.IO.Compression.ZipFile]::ExtractToDirectory($File, $ToolPath) 115 | move-item -path ($ToolPath + "iperf-3.1.3-win64\*.*") -destination $ToolPath -Force 116 | Remove-Item -Path ($ToolPath + "iperf-3.1.3-win64\") -Force 117 | Remove-Item -Path $File -Force 118 | } 119 | Catch { 120 | Write-Host 121 | Write-Warning "Something bad happened Unzipping and moving the iPerf files. Most likely .Net or other required subsystem files are not loaded." 122 | Write-Host 123 | Write-Host "You can manually add the files and rerun this Install script." 124 | Write-Host "To manually install iPerf3:" 125 | Write-Host " 1. Find $File" 126 | Write-Host " 2. Extract zipped files (iPerf3.exe and cygwin1.dll) to $ToolPath (not a subdirectory!)" 127 | Write-Host " 3. With those files in place, rerun this install." 128 | Write-Host 129 | Return 130 | } # End Try 131 | } # End If 132 | 133 | 134 | # 5. Check for PSPing 135 | If (-Not (Test-Path $ToolPath"psping.exe")){ 136 | # 5.1 If needed, download 137 | $File = $ToolPath + "psping.exe" 138 | Try { 139 | $webClient = new-object System.Net.WebClient 140 | $webClient.DownloadFile($PSPingURL, $File) 141 | } 142 | Catch { 143 | Write-Host 144 | Write-Warning "Something bad happened with the PSPing download. Most likely either files are missing at the source or this host doesn't have internet access." 145 | Write-Host 146 | Write-Host "You can manually add the file and rerun this Install script." 147 | Write-Host "To manually install PSPing:" 148 | Write-Host " 1. Download the file from $PSPingURL" 149 | Write-Host " 2. Move the psping.exe file to the $ToolPath directory." 150 | Write-Host " 3. With psping.exe in place, rerun this install." 151 | Write-Host 152 | Return 153 | } # End Try 154 | } # End If 155 | 156 | # 6. Check other files 157 | $FileName = @() 158 | If (-Not (Test-Path ($ToolPath + "Set-iPerfFirewallRules.ps1"))){$FileName += 'Set-iPerfFirewallRules.ps1'} 159 | If (-Not (Test-Path ($ToolPath + "README.md"))){$FileName += 'README.md'} 160 | 161 | # 7. Pull from GitHub if needed 162 | If ($FileName.Count -gt 0) { 163 | Try { 164 | ForEach ($File in $FileName) { 165 | $webClient = new-object System.Net.WebClient 166 | $webClient.DownloadFile( $GitHubURL + $File, $ToolPath + $File ) 167 | } #End ForEach 168 | } 169 | Catch { 170 | Write-Host 171 | Write-Warning "Something bad happened pulling files from GitHub. Most likely either files are missing at the source or this host doesn't have internet access." 172 | Write-Host 173 | Write-Host "You can manually add the four files and rerun this Install script." 174 | Write-Host "To manually install the files:" 175 | Write-Host " 1. Go to $GitHubURL" 176 | Write-Host " 2. Save the files 'Set-iPerfFirewallRules.ps1' and 'README.md' to the local $ToolPath directory." 177 | Write-Host " 3. With these files in place, rerun this install." 178 | Write-Host 179 | Return 180 | } # End Try 181 | } # End If 182 | 183 | # 8. Kill PSPing popup 184 | $cmd = $ToolPath + "psping.exe -accepteula | Out-Null" 185 | Invoke-Expression -Command $cmd 186 | 187 | # 9. Open Firewall rules 188 | If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) 189 | {Start-Process powershell -Verb runAs -ArgumentList ($ToolPath + "Set-iPerfFirewallRules.ps1")} 190 | Else {Invoke-Expression -Command ($ToolPath + "Set-iPerfFirewallRules.ps1")} 191 | 192 | } # End Function 193 | -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/README.md: -------------------------------------------------------------------------------- 1 | # README File for the LinkPerformance functions 2 | 3 | Description goes here 4 | -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Remove-AzureCT.ps1: -------------------------------------------------------------------------------- 1 | # Remove-AzureCT 2 | function Remove-AzureCT { 3 | 4 | Clear-AzureCTHistory -ErrorAction SilentlyContinue 5 | 6 | $ToolPath = "C:\ACTTools\" 7 | If (Test-Path $ToolPath){ 8 | Remove-Item -Force -Path $ToolPath -Recurse -ErrorAction Stop | Out-Null 9 | Write-Host "AzureCT tools directory removed" -ForegroundColor Green 10 | } # End If 11 | 12 | # $Destination = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath 'WindowsPowerShell\Modules\AzureCT' 13 | $Destination = 'C:\Program Files\WindowsPowerShell\Modules\AzureCT\' 14 | If (Test-Path $Destination) { 15 | Try { 16 | Remove-Item $Destination -Recurse 17 | Write-Host "AzureCT PowerShell Module removed" -ForegroundColor Green 18 | } 19 | Catch { 20 | Write-Warning "The AzureCT PowerShell Module was not removed." 21 | Write-Warning "You should manually delete the AzureCT directory at:" 22 | Write-Warning $Destination 23 | } #End Try 24 | } 25 | Else { 26 | Write-Host "AzureCT PowerShell Module was not found on this machine." 27 | } # End If 28 | 29 | Remove-Module -Name AzureCT -ErrorAction SilentlyContinue 30 | Write-Host "AzureCT module unloaded from memory" -ForegroundColor Green 31 | 32 | Write-Host "AzureCT removed" -ForegroundColor Green 33 | } # End Function -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Set-iPerfFirewallRules.ps1: -------------------------------------------------------------------------------- 1 | # Must be run as admin 2 | 3 | # Turn On ICMPv4 4 | Try {Get-NetFirewallRule -Name Allow_ICMPv4_in -ErrorAction Stop | Out-Null} 5 | Catch {New-NetFirewallRule -DisplayName "Allow ICMPv4" -Name Allow_ICMPv4_in -Action Allow -Enabled True -Profile Any -Protocol ICMPv4 | Out-Null} 6 | 7 | # Turn On iPerf3 8 | Try {Get-NetFirewallRule -Name Allow_iPerf3_in -ErrorAction Stop | Out-Null} 9 | Catch {New-NetFirewallRule -DisplayName "Allow iPerf3" -Name Allow_iPerf3_in -Action Allow -Enabled True -Profile Any -Protocol TCP -LocalPort 5201 | Out-Null} 10 | -------------------------------------------------------------------------------- /AzureCT/PowerShell/AzureCT/Public/Show-AzureCTResults.ps1: -------------------------------------------------------------------------------- 1 | function Show-AzureCTResults { 2 | # Show-Results 3 | # This script opens a web browser and 4 | # navigates to the passed in IP Address. 5 | 6 | Param( 7 | [Parameter(ValueFromPipeline=$true, Mandatory=$true)] 8 | [ipaddress]$RemoteHost 9 | ) 10 | Write-Host 11 | Write-Host "Launching browser to http://$RemoteHost" 12 | Write-Host 13 | Start-Process -FilePath "http://$RemoteHost" 14 | } # End Function -------------------------------------------------------------------------------- /AzureCT/PowerShell/Install-AzureCT.ps1: -------------------------------------------------------------------------------- 1 | # Install-AzureCT Module 2 | # To kick me off from a URL run the following: 3 | # (new-object Net.WebClient).DownloadString("https://raw.githubusercontent.com/Azure/NetworkMonitoring/master/AzureCT/PowerShell/Install-AzureCT.ps1") | Invoke-Expression 4 | # (new-object Net.WebClient).DownloadString("https://raw.githubusercontent.com/tracsman/NetworkMonitoring/LinkPerf/AzureCT/PowerShell/Install-AzureCT.ps1") | Invoke-Expression 5 | 6 | function Install-AzureCT { 7 | 8 | $uri = 'https://raw.githubusercontent.com/Azure/NetworkMonitoring/master/AzureCT/PowerShell/AzureCT/' 9 | 10 | $FileName = @() 11 | $FileName += 'AzureCT.psd1' 12 | $FileName += 'AzureCT.psm1' 13 | $FileName += 'Public/Clear-AzureCTHistory.ps1' 14 | $FileName += 'Public/Get-AzureNetworkAvailability.ps1' 15 | $FileName += 'Public/Get-HostName.ps1' 16 | $FileName += 'Public/Get-IPTrace.ps1' 17 | $FileName += 'Public/Remove-AzureCT.ps1' 18 | $FileName += 'Public/Show-AzureCTResults.ps1' 19 | 20 | $FileName += 'Public/Install-LinkPerformance.ps1' 21 | $FileName += 'Public/Get-LinkPerformance.ps1' 22 | 23 | #$Destination = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath 'WindowsPowerShell\Modules\AzureCT\' 24 | $Destination = 'C:\Program Files\WindowsPowerShell\Modules\AzureCT\' 25 | New-Item -Path ($Destination) -ItemType Directory -Force | Out-Null 26 | New-Item -Path ($Destination + "Public") -ItemType Directory -Force | Out-Null 27 | 28 | Write-Host 29 | 30 | ForEach ($File in $FileName) { 31 | $webClient = new-object System.Net.WebClient 32 | $webClient.DownloadFile( $uri + $File, $Destination + $File ) 33 | Write-Host "Copied successfully:" $File 34 | } 35 | 36 | $executionPolicy = (Get-ExecutionPolicy) 37 | $executionRestricted = ($executionPolicy -eq "Restricted") 38 | If ($executionRestricted) { 39 | Write-Warning "Your execution policy is $executionPolicy, this means you will not be able import or use any scripts including modules." 40 | Write-Warning "To fix this change your execution policy to something like RemoteSigned." 41 | Write-Host 42 | Write-Warning " PS> Set-ExecutionPolicy RemoteSigned" 43 | Write-Host 44 | Write-Warning "For more information execute:" 45 | Write-Host 46 | Write-Warning " PS> Get-Help about_execution_policies" 47 | } 48 | Else { 49 | # ensure AzureCT is imported from the location it was just installed to 50 | # Import-Module -Name AzureCT 51 | } 52 | Write-Host "AzureCT is installed and ready to use" -Foreground Green 53 | Write-Host 54 | } # End Function 55 | 56 | Install-AzureCT 57 | -------------------------------------------------------------------------------- /AzureCT/PowerShell/SwapLocal.ps1: -------------------------------------------------------------------------------- 1 | $Old = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath 'WindowsPowerShell\Modules\AzureCT\' 2 | $New = "D:\git\NetworkMonitoring\AzureCT\PowerShell\AzureCT" 3 | 4 | If ((Get-Module -Name AzureCT).Count -gt 0) {Remove-Module AzureCT} 5 | If (Test-Path $Old) {Remove-Item $Old -Recurse} 6 | Copy-Item $New -Destination $Old -Recurse 7 | Import-Module AzureCT 8 | ForEach ($Job in (Get-Job)) { 9 | Remove-Job $Job 10 | } 11 | Write-Host "Swap Complete" -ForegroundColor Green 12 | 13 | -------------------------------------------------------------------------------- /AzureCT/README.md: -------------------------------------------------------------------------------- 1 | # Azure Connectivity Toolkit (AzureCT) 2 | 3 | ## Overview 4 | The Azure Connectivity Toolkit (AzureCT) is a PowerShell module and collection of server side web pages which can test, generate, collect, store, and display performance and availability statistics of the network between you and Azure. The two main areas of functionality are: 5 | 6 | - [Network Performance Testing][Performance Doc]: The Get-LinkPerformance command runs a series of iPerf3 bandwidth load tests while concurrently doing a TCP ping to show latency under various loads. 7 | - [Network Availability Testing][Availability Doc]: The Get-AzureNetworkAvailability command runs pings and traceroutes over an extended period of time to show end to end availability and hop latency. 8 | 9 | ---------- 10 | 11 | ## [Link Performance][Performance Doc] 12 | 13 | [![1]][1] 14 | 15 | This collection of PowerShell commandlets will download required files to run the Get-LinkPerformance command which runs a series of iPerf load tests and PSPing TCP pings concurrently between a local source and a remote host running iPerf3 in server mode. Six tests of increasing load are performed and results are output at the conclusion of the test. This testing is designed to show link latency and bandwidth capabilities under various conditions. 16 | 17 | **Requirements**: Link Performance testing requires a local Windows machine from which PowerShell is run and a remote host, either Linux or Windows, running iPerf3 and listening on an admin port either 22 for Linux or 3389 for Windows. 18 | 19 | To install and test Link Performance follow the instructions here: [Performance Testing Instructions][Performance Doc] 20 | 21 | ## [Link Availability][Availability Doc] 22 | 23 | [![0]][0] 24 | 25 | This collection of server side web pages and local PowerShell that will generate, collect, store, and display availability statistics of the network between you and a newly built Windows VM in Azure. 26 | 27 | It is designed to provide an indication, over time, of the link between a Virtual Machine in Azure and an on-premise network. While the focus is on network availability, the test is done from a PC client to an IIS server in Azure. This provides a view into the availability of an end-to-end scenario, not just a single point or component in the complex chain that makes up a VPN or an ExpressRoute network connection. The hope is that this will provide insight into the end-to-end network availability. 28 | 29 | **Requirements**: Link Availability testing requires a local Windows machine from which PowerShell is run and a newly built remote Windows VM running IIS and a small web application. 30 | 31 | To install and test Link Performance follow the instructions here: [Availability Testing Instructions][Availability Doc] 32 | 33 | >**Note**: These tools are not certified by Microsoft, nor are they supported by Microsoft support. Download and use at your own risk. While the author is an employee of Microsoft, these tools are provided as my best effort to provide insight into the connectivity between an on-premise network and an Azure endpoint. See the [Support and Legal Disclaimers](#support-and-legal-disclaimers) below for more info. 34 | 35 | ## Removing the Azure Connectivity Toolkit 36 | Once testing is complete the Azure VM can be deleted to avoid unnecessary Azure usage (and associated charges) and all local files can be deleted. The only files on the local machine are the PowerShell module files copied from GitHub, iPerf and PSPPing files in the C:\ACTTools directory (if Install-LinkPerformance was run), and potentially three XML files (if Get-AzureNetworkAvailability was run) in the Local Client PC %temp% directory. 37 | 38 | To ensure 100% removal of all artifacts from the Azure Connectivity Toolkit perform the following step: 39 | 40 | 1. Run the Remove-AzureCT command from PowerShell. This will remove the PowerShell module and any local data files. 41 | 42 | ```powershell 43 | Remove-AzureCT 44 | ``` 45 | 46 | ## History 47 | 48 | - 2016-02-03 - Initial beta release 1.6.0.1 49 | - 2016-02-07 - Updated beta release 1.6.0.2 50 | - 2016-02-22 - Added more functions and client side trace 1.9.0.1 51 | - 2017-06-26 - Added link performance related commands 52 | 53 | ## Incorporated Licenses 54 | This tool incorporates [JQuery](https://jquery.org/license/ "JQuery License") for XML manipulation and is included in the ServerSide files. JQuery.js is included and used under the requirements of the MIT License, and in compliance with the main JQuery license proviso "*You are free to use any jQuery Foundation project in any other project (even commercial projects) as long as the copyright header is left intact.*" 55 | 56 | ## Support and Legal Disclaimers 57 | Microsoft provides no support for this software. All support, assistance, and information is on this site alone. 58 | 59 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 REGENTS 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; INCREMENTAL AZURE COSTS INCURRED THROUGH USE OF THIS SOFTWARE; 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. 60 | 61 | 62 | [0]: ./media/AzureCTAvailability.png "AzureCT Availability Test Diagram" 63 | [1]: ./media/AzureCTPerformance.png "AzureCT Performance Test Diagram" 64 | 65 | 66 | [Performance Doc]: ./PerformanceTesting.md 67 | [Availability Doc]: ./AvailabilityTesting.md 68 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/AvailabilityDetail.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/AvailabilityHeader.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/AvailabilityTrace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/ClearHistory.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="VB" %> 2 | <%@ Import Namespace="System.IO" %> 3 | <% 4 | Dim myResult As String 5 | Dim WebStream As StreamReader = New StreamReader(Request.InputStream) 6 | Dim strBody As String = WebStream.ReadToEnd 7 | Dim strHeader As String = HttpContext.Current.Server.MapPath(".\AvailabilityHeader.xml") 8 | Dim strDetail As String = HttpContext.Current.Server.MapPath(".\AvailabilityDetail.xml") 9 | Dim strTrace As String = HttpContext.Current.Server.MapPath(".\AvailabilityTrace.xml") 10 | Dim strHeaderTemplate As String = HttpContext.Current.Server.MapPath(".\TemplateAvailabilityHeader.xml") 11 | Dim strDetailTemplate As String = HttpContext.Current.Server.MapPath(".\TemplateAvailabilityDetail.xml") 12 | Dim strTraceTemplate As String = HttpContext.Current.Server.MapPath(".\TemplateAvailabilityTrace.xml") 13 | If strBody = "Yes" Then 14 | Try 15 | If File.Exists(strHeader) Then File.Copy(strHeaderTemplate, strHeader, True) 16 | If File.Exists(strDetail) Then File.Copy(strDetailTemplate, strDetail, True) 17 | If File.Exists(strTrace) Then File.Copy(strTraceTemplate, strTrace, True) 18 | myResult = "Good" 19 | Catch ex As Exception 20 | myResult = "Bad" 21 | End Try 22 | Else 23 | myResult = "Bad" 24 | End If 25 | %> 26 | <%=myResult%> -------------------------------------------------------------------------------- /AzureCT/ServerSide/DisplayAvailability.css: -------------------------------------------------------------------------------- 1 |  body { 2 | font-family: Verdana; 3 | font-size: 14px; 4 | } 5 | table {border: 1px solid black;} 6 | th, td.SumHead { 7 | background: #FFFFFF; 8 | border: 1px solid #B0B0B0; 9 | font-weight: bold; 10 | padding: 3px 10px; 11 | text-align: center; 12 | } 13 | th#time {width:250px;} 14 | th#display {width:390px;} 15 | th#duration {width:140px;} 16 | th#trace {width:150px;} 17 | td { 18 | padding: 3px 5px; 19 | text-align: center; 20 | } 21 | td#SumHead {column-span:all; 22 | text-align:left; 23 | } 24 | tr:nth-child(even) { 25 | background: #99CCFF; 26 | } 27 | tr:nth-child(odd) { 28 | background: #CCFFFF; 29 | } 30 | #SummaryTable tr {background: #ffffff;} 31 | #SummaryTable td:nth-child(odd) {text-align:right;} 32 | #SummaryTable td:nth-child(even) {text-align:left;} 33 | #SummaryTable td:nth-child(1) {width: 105px;} 34 | #SummaryTable td:nth-child(2) {width: 200px;} 35 | #SummaryTable td:nth-child(3) {width: 90px;} 36 | #SummaryTable td:nth-child(4) {width: 200px;} 37 | #SummaryTable td:nth-child(5) {width: 130px;} 38 | #SummaryTable td:nth-child(6) {width: 230px;} 39 | 40 | #MessageDiv { 41 | position: fixed; 42 | width: 400px; 43 | top: 200px; 44 | left: 320px; 45 | padding-top: 10px; 46 | height: 150px; 47 | background-color: antiquewhite; 48 | text-align: center; 49 | font-size: x-large; 50 | border: double; 51 | visibility: hidden; 52 | z-index: 10; 53 | } 54 | 55 | #TraceDiv { 56 | position: fixed; 57 | width: 375px; 58 | top: 150px; 59 | left: 323px; 60 | padding: 10px; 61 | height: 400px; 62 | background-color: #eeeeee; 63 | border:double; 64 | overflow-y:scroll; 65 | visibility:hidden; 66 | z-index: 3; 67 | } 68 | #TraceTable td:nth-child(4) {padding-left: 20px; 69 | text-align:left;} 70 | th#HopID {width:60px;} 71 | th#Address {width:140px;} 72 | th#Latency {width:80px;} 73 | #TraceTable tr:nth-child(even) {background: #c2e1ff} 74 | #TraceTable tr:nth-child(odd) {background: #cce9ff} 75 | 76 | span {font-size:small;} 77 | .b {font-weight:bold;} -------------------------------------------------------------------------------- /AzureCT/ServerSide/DisplayAvailability.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Azure Connectivity Toolkit 6 | 7 | 8 | 9 | 10 | 11 |

Azure Connectivity Toolkit - Availability Tool

12 |

This page shows the details of any Get-AzureNetworkAvailability job submitted to this server, based on the specific data set selected in the drop down.

13 |
Select an Availaibity data set to see details: 14 | 16 |
17 |
18 |
19 | 20 |
21 |
22 |
23 |
24 |
25 |
26 |

Data Loading

27 |

Please Wait...

28 |
29 |
30 | 65 |
66 |
67 | 68 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/DisplayAvailability.js: -------------------------------------------------------------------------------- 1 | // File: DisplayAvailability.js 2 | 3 | // Start function when DOM has completely loaded 4 | $(document).ready(function () { 5 | // Open the AvailabilityHeader.xml file 6 | $.get('AvailabilityHeader.xml', {}, function (xml) { 7 | 8 | // Define Option Var 9 | myHTMLOutput = ''; 10 | x = 0; 11 | 12 | // Run the function for each Job in xml file 13 | $('Job', xml).each(function (i) { 14 | 15 | jobID = $(this).find('ID').text(); 16 | if (jobID != "") { 17 | jobStart = $(this).find('StartTime').text(); 18 | var dStart = new Date(jobStart); 19 | 20 | // Build Option Row for Drop down 21 | myHTMLOutput += ''; 22 | x += 1; 23 | }; 24 | }); 25 | 26 | // Update the Job List drop down with the HTML string 27 | $("#JobList").append(myHTMLOutput); 28 | 29 | // Select last job and call onchange event to load job details 30 | document.getElementById("JobList").selectedIndex = x - 1; 31 | document.getElementById("JobList").onchange(); 32 | 33 | }); 34 | }); 35 | 36 | function PullJobDetails() { 37 | // Get the selected Job ID from the drop down 38 | headerJobID = document.getElementById("JobList").value; 39 | currentStartTime = ''; 40 | currentEndTime = ''; 41 | currentTarget = ''; 42 | currentTimeoutSeconds = ''; 43 | currentCallCount = ''; 44 | currentSuccessRate = ''; 45 | currentJobMin = ''; 46 | currentJobMax = ''; 47 | currentJobMedian = ''; 48 | currentJobDuration = ''; 49 | currentJobDisplay = ''; 50 | 51 | // Define graph var 52 | var data = []; 53 | 54 | // Set Data Loading Message to visible 55 | document.getElementById('MessageDiv').style.visibility = 'visible'; 56 | 57 | // Open the AvailabilityHeader.xml file 58 | $.get('AvailabilityHeader.xml', {}, function (xml) { 59 | 60 | // Run the function for each Job in xml file 61 | $('Job', xml).each(function (i) { 62 | 63 | jobID = $(this).find('ID').text(); 64 | 65 | // Pull Job Header info into variables 66 | if (jobID == headerJobID) { 67 | currentStartTime = $(this).find('StartTime').text(); 68 | currentEndTime = $(this).find('EndTime').text(); 69 | currentTarget = $(this).find('Target').text(); 70 | currentTimeoutSeconds = $(this).find('TimeoutSeconds').text(); 71 | currentCallCount = $(this).find('CallCount').text(); 72 | currentSuccessRate = $(this).find('SuccessRate').text(); 73 | currentJobMin = $(this).find('JobMin').text(); 74 | currentJobMax = $(this).find('JobMax').text(); 75 | currentJobMedian = $(this).find('JobMedian').text(); 76 | 77 | var t1 = new Date(currentStartTime); 78 | var t2 = new Date(currentEndTime); 79 | var dif = (t2 - t1) / 1000; 80 | 81 | var runDays = Math.floor(dif / 86400); 82 | var rem = dif - (runDays * 86400); 83 | 84 | var runHours = Math.floor(rem / 3600); 85 | var rem = rem - (runHours * 3600); 86 | 87 | var runMinutes = Math.floor(rem / 60); 88 | var runSeconds = rem - (runMinutes * 60); 89 | 90 | if ((+runDays) == (+1)) { var unitDays = 'Day'; } else { var unitDays = 'Days'; }; 91 | 92 | currentJobDuration = runDays + ' ' + unitDays + ', ' + pad(runHours) + ':' + pad(runMinutes) + ':' + pad(runSeconds) + ' (hh:mm:ss)'; 93 | 94 | myHTMLOutput = ''; 95 | myHTMLOutput += ''; 96 | myHTMLOutput += ''; 97 | myHTMLOutput += ''; 98 | myHTMLOutput += ''; 99 | myHTMLOutput += ''; 100 | myHTMLOutput += ''; 101 | myHTMLOutput += ''; 102 | myHTMLOutput += ''; 103 | myHTMLOutput += ''; 104 | myHTMLOutput += ''; 105 | myHTMLOutput += ''; 106 | myHTMLOutput += ''; 107 | myHTMLOutput += ''; 108 | myHTMLOutput += ''; 109 | myHTMLOutput += ''; 110 | myHTMLOutput += ''; 111 | myHTMLOutput += ''; 112 | myHTMLOutput += ''; 113 | myHTMLOutput += ''; 114 | myHTMLOutput += ''; 115 | myHTMLOutput += ''; 116 | myHTMLOutput += ''; 117 | myHTMLOutput += ''; 118 | myHTMLOutput += ''; 119 | myHTMLOutput += ''; 120 | myHTMLOutput += ''; 121 | myHTMLOutput += ''; 122 | myHTMLOutput += '
Job Details:
Start Time:' + dateString(t1, 'noMilli') + 'End Time:' + dateString(t2, 'noMilli') + 'Job Duration:' + currentJobDuration + '
Target IP:' + currentTarget + 'Calls Sent:' + currentCallCount + ' (' + currentSuccessRate + '%) SuccessfulTimeout Value:' + currentTimeoutSeconds + ' Seconds
Results Summary:
Min:' + currentJobMin + ' msMax:' + currentJobMax + ' msMedian:' + currentJobMedian + ' ms
'; 123 | $("#SummaryDiv").html(myHTMLOutput); 124 | 125 | }; 126 | }); 127 | }); 128 | 129 | // Open the AvailabilityDetail.xml file 130 | $.get('AvailabilityDetail.xml', {}, function (xml) { 131 | 132 | // Define HTML string Var 133 | myHTMLOutput = ''; 134 | myHTMLOutput += ''; 178 | myHTMLOutput += ''; 179 | myHTMLOutput += ''; 180 | if (callTagged == 'True') { 181 | myHTMLOutput += ""; 182 | } 183 | else { 184 | myHTMLOutput += ''; 185 | }; 186 | myHTMLOutput += ''; 187 | 188 | // Build graph array 189 | var myCallID = (+callID); 190 | var datapoint = { x: pos, y: Math.round(callDuration), z: callValid }; 191 | data.push(datapoint); 192 | 193 | }; 194 | }); 195 | myHTMLOutput += "
' + callDisplay + '' + Math.round(callDuration) + ' msView Trace 
"; 196 | 197 | // Update the DIV called ResultsDiv with the HTML string 198 | $("#ResultsDiv").html(myHTMLOutput); 199 | 200 | var myTick; 201 | if (currentCallCount < 15) { myTick = 1; } else { myTick = currentCallCount / 15; }; 202 | var myYMax; 203 | if (currentJobMax > 500) { myYMax = currentJobMax; } else { myYMax = 500; }; 204 | 205 | // Instanitate the graph 206 | ClearChart("ResultsGraph"); 207 | var myLineChart = new LineChart({ 208 | canvasId: "ResultsGraph", 209 | minX: 0, 210 | minY: 0, 211 | maxX: currentCallCount, 212 | maxY: myYMax, 213 | unitsPerTickX: myTick, 214 | unitsPerTickY: myYMax / 8 215 | }); 216 | 217 | // Draw the chart 218 | myLineChart.drawLine(data, "blue", 1); 219 | 220 | }); 221 | 222 | // Set Data Loading Message to visible 223 | document.getElementById('MessageDiv').style.visibility = 'hidden'; 224 | }; 225 | 226 | function showTrace(JobID, CallID) { 227 | // Open the AvailabilityHeader.xml file 228 | $.get('AvailabilityTrace.xml', {}, function (xml) { 229 | 230 | // Define HTML string Var 231 | myHTMLOutput = 'Select Trace Route'; 232 | myHTMLOutput += ''; 233 | myHTMLOutput += ''; 234 | myHTMLOutput += ''; 235 | myHTMLOutput += ''; 236 | myHTMLOutput += ''; 237 | myHTMLOutput += ''; 238 | 239 | 240 | // Run the function for each Trace in xml file 241 | $('TraceRecord', xml).each(function (i) { 242 | 243 | traceJobID = $(this).find('JobID').text(); 244 | traceCallID = $(this).find('CallID').text(); 245 | 246 | // Pull Job Header info into variables 247 | if (traceJobID == JobID && traceCallID == CallID) { 248 | traceTimeStamp = $(this).find('TimeStamp').text(); 249 | traceHopID = $(this).find('HopID').text(); 250 | traceAddress = $(this).find('Address').text(); 251 | traceTripTime = $(this).find('TripTime').text(); 252 | 253 | myHTMLOutput += ''; 254 | myHTMLOutput += ''; 255 | myHTMLOutput += ''; 256 | 257 | switch (traceTripTime) { 258 | case '*': 259 | myHTMLOutput += ''; 260 | break; 261 | case '0': 262 | myHTMLOutput += ''; 263 | break; 264 | default: 265 | myHTMLOutput += ''; 266 | }; 267 | myHTMLOutput += ''; 268 | }; 269 | }); 270 | 271 | myHTMLOutput += '
Hop #IP AddressLatency
' + traceHopID + '' + traceAddress + '*< 1 ms' + traceTripTime + ' ms
'; 272 | myHTMLOutput += '
'; 273 | myHTMLOutput += ''; 274 | myHTMLOutput += ''; 275 | myHTMLOutput += '
'; 276 | myHTMLOutput += '
'; 277 | myHTMLOutput += 'Notes:
'; 278 | myHTMLOutput += 'The maximum trace route time will normally be less than the Duration value on the main web page. This is because the trace route is only calculating network latency, whereas the Duration column includes the processing time of the IIS server.'; 279 | myHTMLOutput += '

'; 280 | myHTMLOutput += 'This trace route was started *after* the associated web call was completed. Network conditions may have changed in the short time span between the Web Call and the Trace Route. Also, each trace route row is a separate network trace, network conditions can vary between each trace event as well.'; 281 | myHTMLOutput += '
'; 282 | myHTMLOutput += '
'; 283 | $("#TraceDiv").html(myHTMLOutput); 284 | document.getElementById('TraceDiv').style.visibility = 'visible'; 285 | }); 286 | }; 287 | 288 | function closeTrace() { 289 | document.getElementById('TraceDiv').style.visibility = 'hidden'; 290 | }; 291 | 292 | function pad(num) { 293 | return ('000' + num).substr(-2); 294 | }; 295 | 296 | function dateString(dDate, sOption) { 297 | var yyyy = dDate.getFullYear().toString(); 298 | var mm = (dDate.getMonth() + 1).toString(); 299 | var dd = dDate.getDate().toString(); 300 | var hh = dDate.getHours().toString(); 301 | var MM = dDate.getMinutes().toString(); 302 | var ss = dDate.getSeconds().toString(); 303 | 304 | switch (sOption) { 305 | case 'noMilli': 306 | var sDisplay = yyyy + '-' + (mm[1] ? mm : "0" + mm[0]) + '-' + (dd[1] ? dd : "0" + dd[0]) + ' | ' + (hh[1] ? hh : "0" + hh[0]) + ':' + (MM[1] ? MM : "0" + MM[0]) + ':' + (ss[1] ? ss : "0" + ss[0]); 307 | break; 308 | case 'withMilli': 309 | var fff = ('000' + dDate.getMilliseconds().toString()).substr(-3); 310 | var sDisplay = yyyy + '-' + (mm[1] ? mm : "0" + mm[0]) + '-' + (dd[1] ? dd : "0" + dd[0]) + ' | ' + (hh[1] ? hh : "0" + hh[0]) + ':' + (MM[1] ? MM : "0" + MM[0]) + ':' + (ss[1] ? ss : "0" + ss[0]) + '.' + fff; 311 | break; 312 | default: 313 | var sDisplay = ''; 314 | }; 315 | return sDisplay; 316 | }; 317 | 318 | function LineChart(con) { 319 | 320 | // user defined properties 321 | this.canvas = document.getElementById(con.canvasId); 322 | this.minX = con.minX; 323 | this.minY = con.minY; 324 | this.maxX = con.maxX; 325 | this.maxY = con.maxY; 326 | this.unitsPerTickX = con.unitsPerTickX; 327 | this.unitsPerTickY = con.unitsPerTickY; 328 | 329 | // constants 330 | this.padding = 10; 331 | this.tickSize = 5; 332 | this.axisColor = "#555"; 333 | this.pointRadius = 3; 334 | this.font = "12pt Calibri"; 335 | this.fontHeight = 12; 336 | this.xAxisAdjustment = 15; 337 | this.yAxisAdjustment = 11; 338 | 339 | // relationships 340 | this.context = this.canvas.getContext("2d"); 341 | this.rangeX = this.maxX - this.minX; 342 | this.rangeY = this.maxY - this.minY; 343 | this.numXTicks = Math.round(this.rangeX / this.unitsPerTickX); 344 | this.numYTicks = Math.round(this.rangeY / this.unitsPerTickY); 345 | this.x = this.getLongestValueWidth() + this.padding * 2; 346 | this.y = this.padding * 2; 347 | this.width = (this.canvas.width - this.x - this.padding * 2) - this.yAxisAdjustment; 348 | this.height = this.canvas.height - this.y - this.padding - this.fontHeight - this.xAxisAdjustment; 349 | this.scaleX = this.width / this.rangeX; 350 | this.scaleY = this.height / this.rangeY; 351 | 352 | // draw title and axis labels 353 | this.context.textAlign = 'center'; 354 | var ChartLabel = 'Graph of Call Response Time'; 355 | this.context.fillText(ChartLabel, (this.width / 2) + 50, 20); 356 | 357 | var xLabel = 'Time (duration of this data set)'; 358 | this.context.fillText(xLabel, (this.width / 2) + 50, 285); 359 | 360 | var yLabel = 'Response Time (ms)'; 361 | this.context.save(); 362 | this.context.rotate(-Math.PI / 2); 363 | this.context.fillText(yLabel, -150, 18); 364 | this.context.restore(); 365 | 366 | // draw x y axis and tick marks 367 | this.drawXAxis(); 368 | this.drawYAxis(); 369 | }; 370 | 371 | function ClearChart(CanID) { 372 | var canvas = document.getElementById(CanID); 373 | var context = canvas.getContext('2d'); 374 | context.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight); 375 | }; 376 | 377 | LineChart.prototype.getLongestValueWidth = function () { 378 | this.context.font = this.font; 379 | var longestValueWidth = 0; 380 | for (var n = 0; n <= this.numYTicks; n++) { 381 | var value = this.maxY - (n * this.unitsPerTickY); 382 | longestValueWidth = Math.max(longestValueWidth, this.context.measureText(value).width); 383 | } 384 | return longestValueWidth; 385 | }; 386 | 387 | LineChart.prototype.drawXAxis = function () { 388 | var context = this.context; 389 | context.save(); 390 | context.beginPath(); 391 | context.moveTo(this.x + this.yAxisAdjustment, this.y + this.height); 392 | context.lineTo(this.x + this.width + this.yAxisAdjustment, this.y + this.height); 393 | context.strokeStyle = this.axisColor; 394 | context.lineWidth = 2; 395 | context.stroke(); 396 | 397 | // draw tick marks 398 | //for (var n = 0; n < this.numXTicks; n++) { 399 | // context.beginPath(); 400 | // context.moveTo((n + 1) * this.width / this.numXTicks + this.x, this.y + this.height); 401 | // context.lineTo((n + 1) * this.width / this.numXTicks + this.x, this.y + this.height - this.tickSize); 402 | // context.stroke(); 403 | //} 404 | 405 | // draw labels 406 | context.font = this.font; 407 | context.fillStyle = "black"; 408 | context.textAlign = "center"; 409 | context.textBaseline = "middle"; 410 | 411 | //for (var n = 0; n < this.numXTicks; n++) { 412 | // var label = Math.round((n + 1) * this.maxX / this.numXTicks); 413 | // context.save(); 414 | // context.translate((n + 1) * this.width / this.numXTicks + this.x, this.y + this.height + this.padding); 415 | // context.fillText(label, 0, 0); 416 | // context.restore(); 417 | //} 418 | context.restore(); 419 | }; 420 | 421 | LineChart.prototype.drawYAxis = function () { 422 | var context = this.context; 423 | context.save(); 424 | context.save(); 425 | context.beginPath(); 426 | context.moveTo(this.x + this.yAxisAdjustment, this.y); 427 | context.lineTo(this.x + this.yAxisAdjustment, this.y + this.height); 428 | context.strokeStyle = this.axisColor; 429 | context.lineWidth = 2; 430 | context.stroke(); 431 | context.restore(); 432 | 433 | // draw tick marks 434 | for (var n = 0; n < this.numYTicks; n++) { 435 | context.beginPath(); 436 | context.moveTo(this.x + this.yAxisAdjustment, n * this.height / this.numYTicks + this.y); 437 | context.lineTo(this.x + this.tickSize + this.yAxisAdjustment, n * this.height / this.numYTicks + this.y); 438 | context.stroke(); 439 | } 440 | 441 | // draw values 442 | context.font = this.font; 443 | context.fillStyle = "black"; 444 | context.textAlign = "right"; 445 | context.textBaseline = "middle"; 446 | 447 | for (var n = 0; n < this.numYTicks; n++) { 448 | var value = Math.round(this.maxY - n * this.maxY / this.numYTicks); 449 | context.save(); 450 | context.translate(this.x - this.padding + this.yAxisAdjustment, n * this.height / this.numYTicks + this.y); 451 | context.fillText(value, 0, 0); 452 | context.restore(); 453 | } 454 | context.restore(); 455 | }; 456 | 457 | LineChart.prototype.drawLine = function (data, color, width) { 458 | 459 | var context = this.context; 460 | context.save(); 461 | this.transformContext(); 462 | context.lineWidth = width; 463 | context.strokeStyle = color; 464 | context.fillStyle = color; 465 | context.beginPath(); 466 | context.moveTo(data[0].x + 20, data[0].y * this.scaleY); 467 | 468 | for (var n = 0; n < data.length; n++) { 469 | var point = data[n]; 470 | 471 | // draw segment 472 | context.lineTo(point.x + 20, point.y * this.scaleY); 473 | context.stroke(); 474 | context.closePath(); 475 | context.beginPath(); 476 | if (data[n].z == "False") { context.fillStyle = "red"; }; 477 | context.arc(point.x + 20, point.y * this.scaleY, this.pointRadius, 0, 2 * Math.PI, false); 478 | context.fill(); 479 | context.closePath(); 480 | if (data[n].z == "False") { context.fillStyle = color; }; 481 | 482 | // position for next segment 483 | context.beginPath(); 484 | context.moveTo(point.x + 20, point.y * this.scaleY); 485 | } 486 | context.restore(); 487 | }; 488 | 489 | LineChart.prototype.transformContext = function () { 490 | var context = this.context; 491 | 492 | // move context to center of canvas 493 | this.context.translate(this.x, this.y + this.height); 494 | 495 | // invert the y scale so that that increments 496 | // as you move upwards 497 | context.scale(1, -1); 498 | }; 499 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/IISBuild.ps1: -------------------------------------------------------------------------------- 1 | # IIS Server Post Build Config Script 2 | # To kick me off from a URL run the following: 3 | # (new-object Net.WebClient).DownloadString("https://github.com/tracsman/AzureCT/raw/master/ServerSide/IISBuild.ps1") | Invoke-Expression 4 | 5 | $GitHubBranch = "master" 6 | $GitHUbRepo = "https://raw.githubusercontent.com/Azure/NetworkMonitoring/$GitHubBranch/AzureCT/ServerSide/" 7 | 8 | # Must be run from an elevated PS prompt! 9 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { 10 | Write-Warning "This script must be run As Administrator, please open a new PowerShell prompt using the Run As Administrator option and re-run this script." 11 | Break} 12 | 13 | # Turn On ICMPv4 14 | Write-Host 15 | Write-Host "Creating ICMP Rule in Windows Firewall" -ForegroundColor Cyan 16 | New-NetFirewallRule -Name Allow_ICMPv4 -DisplayName "Allow ICMPv4" -Protocol ICMPv4 -Enabled True -Profile Any -Action Allow -ErrorAction SilentlyContinue 17 | 18 | # Install IIS 19 | Write-Host 20 | Write-Host "Installing IIS and .Net 4.5, this can take some time (up to 15+ minutes)..." -ForegroundColor Cyan 21 | add-windowsfeature Web-Server, Web-WebServer, Web-Common-Http, Web-Default-Doc, Web-Dir-Browsing, Web-Http-Errors, Web-Static-Content, Web-Health, Web-Http-Logging, Web-Performance, Web-Stat-Compression, Web-Security, Web-Filtering, Web-App-Dev, Web-ISAPI-Ext, Web-ISAPI-Filter, Web-Net-Ext, Web-Net-Ext45, Web-Asp-Net45, Web-Mgmt-Tools, Web-Mgmt-Console 22 | 23 | # Create Web App Pages 24 | # Create FileName Array 25 | $FileName = @() 26 | 27 | # Stuff Array with FileNames 28 | $FileName += "AvailabilityDetail.xml" 29 | $FileName += "AvailabilityHeader.xml" 30 | $FileName += "AvailabilityTrace.xml" 31 | $FileName += "ClearHistory.aspx" 32 | $FileName += "DisplayAvailability.css" 33 | $FileName += "DisplayAvailability.html" 34 | $FileName += "DisplayAvailability.js" 35 | $FileName += "jquery.js" 36 | $FileName += "TemplateAvailabilityDetail.xml" 37 | $FileName += "TemplateAvailabilityHeader.xml" 38 | $FileName += "TemplateAvailabilityTrace.xml" 39 | $FileName += "Upload.aspx" 40 | $FileName += "Web.config" 41 | $FileName += "WebTest.aspx" 42 | 43 | # Loop through the array and pull files from GitHub to the Server 44 | Write-Host 45 | Write-Host "Pulling Web pages from GitHub" -ForegroundColor Cyan 46 | Write-Host "Coping files from the 'ServerSide' directory on GitHub to the local 'c:\inetpub\wwwroot\' directory." 47 | $Issues = $false 48 | $i=0 49 | $FileName | ForEach{ 50 | Try { 51 | $webClient = new-object System.Net.WebClient 52 | $webClient.DownloadFile($GitHUbRepo + $FileName[$i], "c:\inetpub\wwwroot\" + $FileName[$i] ) 53 | Write-Host "Copied successfully:" $FileName[$i] 54 | } 55 | Catch { 56 | $Issues = $true 57 | Write-Warning "Download Error:" $FileName[$i] "was not downloaded. Copy this file manually, or rerun this script."} 58 | $i++ 59 | } 60 | # Update File Permmisions to Allow writing access on XML files 61 | # Create Array 62 | $FileName = @() 63 | 64 | # Stuff Array with XML files 65 | $FileName += "C:\inetpub\wwwroot\AvailabilityDetail.xml" 66 | $FileName += "C:\inetpub\wwwroot\AvailabilityHeader.xml" 67 | $FileName += "C:\inetpub\wwwroot\AvailabilityTrace.xml" 68 | $FileName += "C:\inetpub\wwwroot\TemplateAvailabilityDetail.xml" 69 | $FileName += "C:\inetpub\wwwroot\TemplateAvailabilityHeader.xml" 70 | $FileName += "C:\inetpub\wwwroot\TemplateAvailabilityTrace.xml" 71 | 72 | # Loop through array and set file permissions 73 | $i=0 74 | $ar = New-Object System.Security.AccessControl.FileSystemAccessRule("IIS_IUSRS", "FullControl", "Allow") 75 | $FileName | ForEach { 76 | Try { 77 | $acl = Get-Acl $FileName[$i] 78 | $acl.SetAccessRule($ar) 79 | Set-Acl $FileName[$i] $Acl} 80 | Catch { 81 | $Issues = $true 82 | Write-Warning "An error occured applying write ACLs to the $FileName[$i] file." 83 | Write-Warning "Rerun this command or you can manualy apply 'Full Control' permissions to the IIS_IUSRS account on the xml file in the 'c:\inetpub\www\' directory."} 84 | $i++ 85 | } 86 | # Say our good-byes and close up shop 87 | Write-Host 88 | If ($Issues) { 89 | Write-Warning "Issues encountered, please see statement(s) above in red for details!" 90 | } 91 | Else {Write-Host "Web App Creation Successfull!" -ForegroundColor Green} 92 | Write-Host 93 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/TemplateAvailabilityDetail.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/TemplateAvailabilityHeader.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/TemplateAvailabilityTrace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/Upload.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="VB" %> 2 | <%@ Import Namespace="System.XML" %> 3 | <% 4 | Dim myResult As String = "Bad" 5 | Dim strFileID As String 6 | Dim strXMLNode As String 7 | Dim strFileCurrent As String 8 | Dim strFileHeader As String = "AvailabilityHeader.xml" 9 | Dim strFileDetail As String = "AvailabilityDetail.xml" 10 | Dim strFileTrace As String = "AvailabilityTrace.xml" 11 | 12 | Dim xmlOutput As XmlDocument 13 | Dim xmlInput As XmlDocument 14 | Dim xmlTemp As XmlDocumentFragment 15 | 16 | Try 17 | strFileID = Request.Headers.GetValues("FileID").First 18 | 19 | Select Case strFileID 20 | Case "Header" 21 | strFileCurrent = HttpContext.Current.Server.MapPath(".\" & strFileHeader) 22 | strXMLNode = ".//Jobs/Job" 23 | Case "Detail" 24 | strFileCurrent = HttpContext.Current.Server.MapPath(".\" & strFileDetail) 25 | strXMLNode = ".//JobRecords/JobRecord" 26 | Case "Trace" 27 | strFileCurrent = HttpContext.Current.Server.MapPath(".\" & strFileTrace) 28 | strXMLNode = ".//TraceRecords/TraceRecord" 29 | Case Else 30 | Throw New System.Exception("An exception has occurred.") 31 | End Select 32 | 33 | xmlInput = New XmlDocument 34 | xmlInput.Load(Request.InputStream) 35 | xmlOutput = New XmlDocument 36 | xmlOutput.Load(strFileCurrent) 37 | 38 | Dim nodelist As XmlNodeList = xmlInput.SelectNodes(strXMLNode) 39 | For Each node As XmlNode In nodelist 40 | If node.FirstChild.InnerText <> "" Then 41 | xmlTemp = xmlOutput.CreateDocumentFragment() 42 | xmlTemp.InnerXml = node.OuterXml 43 | xmlOutput.DocumentElement.AppendChild(xmlTemp) 44 | End If 45 | Next 46 | xmlOutput.Save(strFileCurrent) 47 | myResult = "Good" 48 | 49 | Catch ex As Exception 50 | myResult = "Bad" 51 | End Try 52 | %> 53 | <%=myResult%> 54 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AzureCT/ServerSide/WebTest.aspx: -------------------------------------------------------------------------------- 1 | <%@ Page Language="vb" AutoEventWireup="false" %> 2 | <%@ Import Namespace="System.IO" %> 3 | <% Dim tTime as Date = Now() %> 4 | 5 | 6 | 7 | <%=tTime%> 8 | 9 | 10 | 1.0 11 | 12 | 13 | -------------------------------------------------------------------------------- /AzureCT/media/AzureCTAvailability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/AzureCTAvailability.png -------------------------------------------------------------------------------- /AzureCT/media/AzureCTPerformance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/AzureCTPerformance.png -------------------------------------------------------------------------------- /AzureCT/media/AzureNMT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/AzureNMT.png -------------------------------------------------------------------------------- /AzureCT/media/DisplayErrors1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/DisplayErrors1.png -------------------------------------------------------------------------------- /AzureCT/media/DisplayErrors2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/DisplayErrors2.png -------------------------------------------------------------------------------- /AzureCT/media/DisplayOneMinute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/DisplayOneMinute.png -------------------------------------------------------------------------------- /AzureCT/media/DisplayTenHour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/DisplayTenHour.png -------------------------------------------------------------------------------- /AzureCT/media/DisplayTimeout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/DisplayTimeout.png -------------------------------------------------------------------------------- /AzureCT/media/PowerShellErrors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/PowerShellErrors.png -------------------------------------------------------------------------------- /AzureCT/media/PowerShellOneMinute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/PowerShellOneMinute.png -------------------------------------------------------------------------------- /AzureCT/media/PowerShellTenHour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/PowerShellTenHour.png -------------------------------------------------------------------------------- /AzureCT/media/PowerShellTenSeconds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/PowerShellTenSeconds.png -------------------------------------------------------------------------------- /AzureCT/media/PowerShellTimeout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/PowerShellTimeout.png -------------------------------------------------------------------------------- /AzureCT/media/RunErrors.md: -------------------------------------------------------------------------------- 1 | # Azure Connectivity Toolkit (AzureCT) - Availability Tool 2 | 3 | [Return to the README Page][HOME] 4 | 5 | ## PowerShell 6 | The following screen shot shows the PowerShell command and results of a five minute run of the Get-AzureNetworkAvailability script with two types of errors: 7 | 8 | ![0] 9 | 10 | - The **!** (exclamation point) represents successful calls to the Azure VM 11 | - The **\*** (asterisk) represents invalid data returned by the server (ie the server responded with an error or unexpected data) 12 | - The **.** (period) represents a call timeout. 13 | 14 | ## Web Display Screen Shot 15 | Upon completion of the script it opens a local browser and displays from the remote Azure VM a graph, summary data, and detail data of the most recent run. 16 | 17 | The first "bad data" returned took 1,728ms (I changed the web page on the server, the long latency delay was the IIS server loading the new page), the next 5 calls were of normal latency as the server was responding as normal, but not with the response expected. 18 | 19 | The next set of error data points were timeouts, these are seen as the five red points sitting on the X-Axis of the graph. In this case, I turned off the IIS server on the Azure VM and the PowerShell script was longer receiving any response to the web call, thus a timeout condition occurred. Timeout data points do not count for Min, Max, or Median data points, as these calls were not successful. 20 | 21 | The specific error reason can be seen in the detailed table at the bottom of the page. 22 | 23 | ![1] 24 | ![2] 25 | 26 | 27 | [0]: PowerShellErrors.png "One Minute PowerShell Run" 28 | [1]: DisplayErrors1.png "Web Server Display of Data Set" 29 | [2]: DisplayErrors2.png "Web Server Display of Data Set" 30 | 31 | 32 | [HOME]: ../../../ -------------------------------------------------------------------------------- /AzureCT/media/RunOneMinute.md: -------------------------------------------------------------------------------- 1 | # Azure Connectivity Toolkit (AzureCT) - Availability Tool 2 | 3 | [Return to the README Page][HOME] 4 | 5 | ## PowerShell 6 | The following screen shot shows the PowerShell command and results of a successful one minute run of the Get-AzureNetworkAvailability script: 7 | 8 | ![0] 9 | 10 | ## Web Display Screen Shot 11 | Upon completion of the script it opens a local browser and displays from the remote Azure VM a graph, summary data, and detail data of the most recent run. Past data sets are available in the drop down. 12 | 13 | ![1] 14 | 15 | 16 | [0]: PowerShellOneMinute.png "One Minute PowerShell Run" 17 | [1]: DisplayOneMinute.png "Web Server Display of Data Set" 18 | 19 | 20 | [HOME]: ../../../ -------------------------------------------------------------------------------- /AzureCT/media/RunTenHour.md: -------------------------------------------------------------------------------- 1 | # Azure Connectivity Toolkit (AzureCT) - Availability Tool 2 | 3 | [Return to the README Page][HOME] 4 | 5 | ## PowerShell 6 | The following screen shot shows the PowerShell command and results of a successful ten hour run of the Get-AzureNetworkAvailability script: 7 | 8 | ![0] 9 | 10 | ## Web Display Screen Shot 11 | Upon completion of the script it opens a local browser and displays from the remote Azure VM a graph, summary data, and detail data of the most recent run. Past data sets are available in the drop down. The individual runs are truncated in the screen shot as there were 3,600 rows in the bottom table, one for each call to the web server. 12 | 13 | ![1] 14 | 15 | 16 | [0]: PowerShellTenHour.png "One Minute PowerShell Run" 17 | [1]: DisplayTenHour.png "Web Server Display of Data Set" 18 | 19 | 20 | [HOME]: ../../../ -------------------------------------------------------------------------------- /AzureCT/media/RunTimeout.md: -------------------------------------------------------------------------------- 1 | # Azure Connectivity Toolkit (AzureCT) - Availability Tool 2 | 3 | [Return to the README Page][HOME] 4 | 5 | ## PowerShell 6 | The following screen shot shows the PowerShell command and results of an unsuccessful one minute run of the Get-AzureNetworkAvailability script and then a successful one minute run: 7 | 8 | ![0] 9 | 10 | In this example, I found the IP address for CNN.COM and used that instead of my Azure VM IP Address. The test timed out (the * (asterisk) symbol) each call. At the end there was a yellow warning, stating that the data could not be uploaded. 11 | 12 | I then ran the script again, this time with the right IP address. At the successful conclusion of that run, both data sets were uploaded to the server as show in the next section. 13 | 14 | ## Web Display Screen Shot 15 | Each call to the server failed as shown by the red points sitting on the X-axis. Note the Target IP in the summary section as this is the IP address used in the call that timed out. 16 | 17 | ![1] 18 | 19 | 20 | [0]: PowerShellTimeout.png "One Minute PowerShell Run" 21 | [1]: DisplayTimeout.png "Web Server Display of Data Set" 22 | 23 | 24 | [HOME]: ../../../ -------------------------------------------------------------------------------- /AzureCT/media/Temp/Diagram50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/Temp/Diagram50.png -------------------------------------------------------------------------------- /AzureCT/media/Temp/DirectToOnPremises50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/Temp/DirectToOnPremises50.png -------------------------------------------------------------------------------- /AzureCT/media/Temp/Landing.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | 19 | # Microsoft Azure Network Architecture Patterns 20 | 21 | ## Overview 22 | This page contains many diagrams of successful network architectures. Each diagram is also click-able to see more detailed information on each design. 23 | 24 | 25 | 26 | 27 | The page is divided into four sections from the perspective of an Azure VNet: 28 | 29 | 1. [Inbound Flows](#inbound-flows) - These patterns are focused on traffic inbound from the internet to a Virtual Network in Azure, optionally with connections back to an on-premise network. 30 | 31 | 2. [Outbound Flows](#outbound-flows) - These patterns are focused on traffic outbound from an Azure Virtual Network heading towards either the internet, an on-premise network, or another Azure VNet (Site-to-Site or VNet Peering connected). 32 | 33 | 3. [Bi-Directional Flows](#bi-directional-flows) - These patterns are focused on traffic both inbound and outbound between different networks, a combination of the above two sections. 34 | 35 | 4. [Forced Tunneling Flows](#forced-tunneling-flows) - These patterns are focused on scenarios using ExpressRoute with the forced tunneling feature turned on, usually with no direct inbound or outbound Internet connection to the Azure VNet. 36 | 37 | ## Inbound Flows 38 | These patterns are focused on traffic inbound from the internet to a Virtual Network in Azure, optionally with connections back to an on-premise network. 39 | 40 | ### Direct To On Premises 41 | ![0] 42 | 43 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut vel ornare lorem. In sapien nisl, pellentesque vel justo at, facilisis finibus diam. Donec aliquet id dolor sit amet luctus. Donec sed nulla in justo pulvinar faucibus. In dignissim elit et neque faucibus sodales at vitae sem. Vivamus aliquet dapibus orci vel auctor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent elementum ligula lectus, eget convallis mauris pulvinar non. Aenean velit enim, varius at mauris id, sagittis facilisis orci. Aliquam dui felis, porta et ultrices at, blandit vel sapien. Etiam dignissim posuere augue, a dapibus dolor euismod vitae. Proin bibendum lacus ut arcu pretium lacinia. Nam facilisis placerat ornare. 44 | 45 | ### Monolythic Application 46 | ![1] 47 | 48 | Vivamus id convallis orci. Phasellus nec sem gravida, luctus nisl ac, placerat arcu. Donec blandit ex quis nibh faucibus, ac convallis diam aliquet. Sed eget nunc non felis interdum efficitur. Nam nec ipsum luctus, interdum justo at, pretium ex. Suspendisse consectetur orci quis dignissim rutrum. Proin id sapien egestas, aliquet nunc id, tincidunt metus. Duis volutpat a sapien ac volutpat. Aenean a sagittis nisi. 49 | 50 | ### Monolythic App NVA 51 | ![2] 52 | 53 | Sed et dictum nisi. Vivamus non imperdiet nisi, quis tempor sem. Maecenas sit amet ex ante. Aliquam porta mi at lorem egestas, eu fermentum diam iaculis. Duis venenatis ligula ipsum, a ornare magna venenatis vel. Fusce pretium mattis lorem vitae blandit. Morbi sed nisl libero. Suspendisse potenti. Vestibulum ultricies, eros vel sodales feugiat, tortor erat varius metus, vel posuere nisl dui at velit. Aliquam erat volutpat. Integer sit amet augue nulla. Etiam auctor bibendum nulla in auctor. Suspendisse potenti. Sed pretium iaculis turpis, eget finibus velit facilisis vestibulum. Cras vel sem vitae eros mattis lobortis. 54 | 55 | ### Multiple NVA Stack 56 | ![3] 57 | 58 | Etiam convallis magna et porta lacinia. Mauris fermentum leo nec velit rutrum scelerisque. Integer nisi lacus, ultrices et malesuada vitae, lacinia quis metus. Suspendisse non augue eros. Quisque ut dolor varius, lobortis mauris ac, consectetur lacus. Nam porttitor ullamcorper ante semper elementum. Aliquam faucibus in metus eu vulputate. Nam fringilla magna ac augue faucibus semper. Nullam nec velit suscipit, convallis sem sit amet, ullamcorper nisl. Donec sapien diam, ultricies vel urna at, feugiat facilisis elit. Vivamus suscipit a lorem nec feugiat. Sed vitae faucibus velit, eget porta est. Etiam eu quam augue. Aliquam eget volutpat diam. Maecenas lacinia nisi ac nunc cursus luctus. Suspendisse vitae sollicitudin justo, at molestie leo. 59 | 60 | ### Shared Security Stack 61 | ![6] 62 | 63 | Maecenas sodales urna id nisl commodo consequat. Praesent sed erat mi. Phasellus at vestibulum felis. Suspendisse fringilla, turpis sit amet tincidunt porta, nibh orci gravida lacus, vel tincidunt sapien purus at metus. Proin quam dui, placerat a hendrerit vel, convallis eget felis. Sed facilisis pharetra eros, eu vestibulum erat cursus sit amet. Cras commodo odio at elit sollicitudin congue. Donec blandit purus nec elementum feugiat. 64 | 65 | ### NVA VPM 66 | ![4] 67 | 68 | Nullam eu mi ac elit efficitur blandit et non purus. Nunc rutrum dolor eu feugiat consequat. Nullam mollis enim varius sapien sodales pellentesque. In sit amet erat scelerisque, venenatis est vel, convallis velit. Morbi eget lectus vel enim aliquam faucibus. Vestibulum fermentum semper arcu ac tristique. Cras gravida dui augue, sed ullamcorper neque rhoncus vel. Nam a nulla tellus. Morbi molestie quam non sem rutrum, nec scelerisque metus ultrices. Sed lacinia ex non neque facilisis, quis tempor nulla vulputate. 69 | 70 | ### Sandwich DMZ 71 | ![7] 72 | 73 | Cras mattis massa vitae eros tempus dignissim. Integer molestie eros vitae semper luctus. Maecenas posuere enim id metus porta interdum. Nullam vitae enim in dolor mattis aliquam. Fusce nisl neque, condimentum et ante nec, suscipit blandit magna. Donec sapien risus, porta nec nulla quis, viverra viverra nisi. Interdum et malesuada fames ac ante ipsum primis in faucibus. 74 | 75 | ## Outbound Flows 76 | These patterns are focused on traffic outbound from an Azure Virtual Network heading towards either the internet, an on-premise network, or another Azure VNet (Site-to-Site or VNet Peering connected). 77 | 78 | 79 | 80 | ## Bi-directional Flows 81 | These patterns are focused on traffic both inbound and outbound between different networks, a combination of the above two sections. 82 | 83 | 84 | 85 | ## Forced Tunneling Flows 86 | These patterns are focused on scenarios using ExpressRoute with the forced tunneling feature turned on, usually with no direct inbound or outbound Internet connection to the Azure VNet. 87 | 88 | ### Public Peering 89 | ![5] 90 | 91 | Nulla ut lobortis arcu. Praesent nec rhoncus sem. Duis consectetur ante et dolor vestibulum rhoncus. Ut nec accumsan diam, id ultrices est. Nulla sollicitudin vehicula metus, et bibendum nibh malesuada et. Proin interdum magna a odio finibus, ac fermentum dui tincidunt. Curabitur viverra quam eget nulla facilisis, vel fermentum nulla faucibus. Praesent bibendum porta ante vitae convallis. In at tellus fringilla arcu vehicula rutrum. Fusce hendrerit turpis vel leo ornare vehicula. Ut consectetur ex sed lobortis bibendum. Maecenas ac tortor commodo, consectetur leo quis, rutrum diam. 92 | 93 | 94 | 95 | ## Appendix - Comments on High Availability 96 | Proin ut felis luctus, viverra nunc et, elementum lectus. Vivamus mattis nibh pharetra ultrices consectetur. Cras non pellentesque diam. In ultricies quam nisi, eu tincidunt mauris aliquam eget. Praesent quis mattis velit. Nam egestas, justo luctus vehicula pretium, eros elit dictum nulla, in egestas elit velit eu risus. Aliquam commodo tellus nibh, at fermentum ante aliquam consequat. Nunc ante nulla, fringilla a molestie sit amet, varius ac metus. Sed at lacus consequat, condimentum velit nec, porttitor mauris. Duis nec dolor maximus, rhoncus erat at, eleifend diam. Cras sed lorem sit amet sem suscipit ultricies in ut purus. Sed ut egestas sapien, eget laoreet nisi. Nulla facilisi. Maecenas aliquet est et facilisis porta. 97 | 98 | ## Appendix - Protocol Chart 99 | | Layer | Protocol | Works Across VNet | Works Across VPN | Works Across ExpressRoute | Works Across Azure Edge | 100 | |:-----:|:---------|:-----------------:|:----------------:|:-------------------------:|:-----------------------:| 101 | | 2 | ARP 102 | | 2 | CDP 103 | | 2 | Ethernet 104 | | 2 | L2TP 105 | | 2 | LLDP 106 | | 2 | MPLS 107 | | 2 | PPP 108 | | 2 | STP 109 | | 3 | ICMP 110 | | 3 | IGMP 111 | | 3 | IPSec 112 | | 3 | IPv4 113 | | 3 | IPv6 114 | | 3 | PIM-DM 115 | | 3 | PIM-SM 116 | | 3 | RIP 117 | | 4 | FCP 118 | | 4 | TCP 119 | | 4 | UDP 120 | | 5 | PPTP 121 | | 5 | RPC 122 | | 7 | HTTP 123 | | 7 | LDAP 124 | | 7 | NFS 125 | | 7 | NTP 126 | | 7 | RDP 127 | | 7 | SMB 128 | | 7 | SMTP 129 | | 7 | SSH 130 | | 7 | TLS/SSL 131 | 132 | 133 | 134 | 135 | [0]: ./DirectToOnPremises50.png "Direct To On Premises Diagram" 136 | [1]: ./MonolythicApplication50.png "Monolythic Application Diagram" 137 | [2]: ./MonolythicAppNVA50.png "Monolythic App NVA Diagram" 138 | [3]: ./MultipleNVAStack50.png "Multiple NVA Stack Diagram" 139 | [4]: ./NVAVPN50.png "NVA VPN Diagram" 140 | [5]: ./Publicpeering50.png "Public Peering Diagram" 141 | [6]: ./SharedSecurityStack50.png "Shared Security Stack Diagram" 142 | [7]: ./SandwichDMZ25.png "Sandwich DMZ Diagram" 143 | 144 | 145 | [Link1]: https://github.com/tracsman/AzureCT/archive/master.zip "Download Zip File Here" 146 | [Link2]: ./media/RunOneMinute.md 147 | -------------------------------------------------------------------------------- /AzureCT/media/Temp/MonolythicAppNVA50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/Temp/MonolythicAppNVA50.png -------------------------------------------------------------------------------- /AzureCT/media/Temp/MonolythicApplication50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/Temp/MonolythicApplication50.png -------------------------------------------------------------------------------- /AzureCT/media/Temp/MultipleNVAStack50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/Temp/MultipleNVAStack50.png -------------------------------------------------------------------------------- /AzureCT/media/Temp/NVAVPN50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/Temp/NVAVPN50.png -------------------------------------------------------------------------------- /AzureCT/media/Temp/Publicpeering50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/Temp/Publicpeering50.png -------------------------------------------------------------------------------- /AzureCT/media/Temp/SandwichDMZ25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/Temp/SandwichDMZ25.png -------------------------------------------------------------------------------- /AzureCT/media/Temp/SharedSecurityStack50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzureCT/media/Temp/SharedSecurityStack50.png -------------------------------------------------------------------------------- /AzurePortal/HybridVideo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/AzurePortal/HybridVideo.mp4 -------------------------------------------------------------------------------- /AzurePortal/HybridVideo.vtt: -------------------------------------------------------------------------------- 1 | WEBVTT - https://maestrasuite.com 2 | 3 | 0 4 | 00:00:00.880 --> 00:00:03.969 5 | A few months ago, we changed 6 | our public documentation to 7 | 8 | 1 9 | 00:00:03.980 --> 00:00:06.609 10 | organize the Azure networking 11 | services and features 12 | 13 | 2 14 | 00:00:06.620 --> 00:00:07.599 15 | into four pillars. 16 | 17 | 3 18 | 00:00:08.000 --> 00:00:10.169 19 | I'm here to talk to you 20 | about the hybrid connectivity 21 | 22 | 4 23 | 00:00:10.180 --> 00:00:12.859 24 | pillar, which is also 25 | reflected in the Azure portal. 26 | 27 | 5 28 | 00:00:13.500 --> 00:00:15.589 29 | When I say hybrid 30 | connectivity, I mean getting 31 | 32 | 6 33 | 00:00:15.600 --> 00:00:19.068 34 | from the physical world, 35 | on-prem or from a device like 36 | 37 | 7 38 | 00:00:19.080 --> 00:00:22.599 39 | a cell phone or a laptop, 40 | into resources in Azure. 41 | 42 | 8 43 | 00:00:23.400 --> 00:00:26.179 44 | First, let's look at 45 | the Azure VPN service. 46 | 47 | 9 48 | 00:00:28.200 --> 00:00:31.289 49 | VPN gateway is a collection 50 | of objects in Azure working 51 | 52 | 10 53 | 00:00:31.300 --> 00:00:34.849 54 | together to enable an IPsec 55 | or TLS tunnel to Azure 56 | 57 | 11 58 | 00:00:34.860 --> 00:00:35.919 59 | across the Internet. 60 | 61 | 12 62 | 00:00:36.180 --> 00:00:38.989 63 | This is done in one of two 64 | ways, with site-to-site 65 | 66 | 13 67 | 00:00:39.000 --> 00:00:41.409 68 | tunnels starting at your 69 | on-premise location with 70 | 71 | 14 72 | 00:00:41.420 --> 00:00:44.569 73 | a physical device like a 74 | router or firewall, or a 75 | 76 | 15 77 | 00:00:44.580 --> 00:00:46.749 78 | point-to-site connection 79 | from your mobile device 80 | 81 | 16 82 | 00:00:46.760 --> 00:00:49.629 83 | like a cell phone, tablet, 84 | laptop, or other supported 85 | 86 | 17 87 | 00:00:49.640 --> 00:00:50.959 88 | Internet connected devices. 89 | 90 | 18 91 | 00:00:51.280 --> 00:00:53.929 92 | For both point-to-site and 93 | site-to-site, you start 94 | 95 | 19 96 | 00:00:53.940 --> 00:00:57.019 97 | with a VPN gateway connected 98 | to your Azure VNet. 99 | 100 | 20 101 | 00:00:57.720 --> 00:00:59.819 102 | With point-to-site, a client 103 | application or client config, 104 | 105 | 21 106 | 00:00:59.830 --> 00:00:59.919 107 | is installed on the device 108 | and is connected securely 109 | 110 | 22 111 | 00:00:59.930 --> 00:00:59.959 112 | to the VPN gateway. 113 | 114 | 23 115 | 00:01:06.890 --> 00:01:10.338 116 | For a site-to-site connection, 117 | a local network gateway object 118 | 119 | 24 120 | 00:01:10.350 --> 00:01:13.299 121 | is created that represents 122 | the IP address of the on-prem 123 | 124 | 25 125 | 00:01:13.310 --> 00:01:16.519 126 | device and then a connection 127 | object is created to join 128 | 129 | 26 130 | 00:01:16.530 --> 00:01:19.429 131 | the local network gateway 132 | to the VPN gateway. 133 | 134 | 27 135 | 00:01:19.650 --> 00:01:23.209 136 | This establishes the secure 137 | tunnel through the Internet. 138 | 139 | 28 140 | 00:01:25.430 --> 00:01:28.149 141 | Next, we look at the 142 | ExpressRoute service. 143 | 144 | 29 145 | 00:01:29.820 --> 00:01:33.088 146 | Like VPN, ExpressRoute is 147 | about getting connectivity 148 | 149 | 30 150 | 00:01:33.100 --> 00:01:35.529 151 | from your premise 152 | to Microsoft, but in 153 | 154 | 31 155 | 00:01:35.540 --> 00:01:37.849 156 | ExpressRoute's case, 157 | doing this by not 158 | 159 | 32 160 | 00:01:37.860 --> 00:01:38.659 161 | using the internet. 162 | 163 | 33 164 | 00:01:39.360 --> 00:01:41.368 165 | Most customers work with 166 | a service provider like 167 | 168 | 34 169 | 00:01:41.380 --> 00:01:44.948 170 | AT &T or any of our over 171 | 200 ExpressRoute partners 172 | 173 | 35 174 | 00:01:44.960 --> 00:01:47.669 175 | to provide a private, 176 | non-internet path to 177 | 178 | 36 179 | 00:01:47.680 --> 00:01:48.499 180 | Microsoft's network. 181 | 182 | 37 183 | 00:01:49.040 --> 00:01:51.109 184 | Once connected with an 185 | ExpressRoute circuit, you 186 | 187 | 38 188 | 00:01:51.120 --> 00:01:54.519 189 | can go to Microsoft public 190 | and Azure public services 191 | 192 | 39 193 | 00:01:54.530 --> 00:01:57.219 194 | like SQL Server, Azure 195 | Storage, Dynamics, or 196 | 197 | 40 198 | 00:01:57.230 --> 00:01:58.769 199 | in some cases, M365. 200 | 201 | 41 202 | 00:01:58.930 --> 00:02:01.879 203 | This is done using public 204 | IP addresses over Microsoft 205 | 206 | 42 207 | 00:02:01.890 --> 00:02:04.649 208 | Peering, the orange 209 | lines in this diagram. 210 | 211 | 43 212 | 00:02:05.150 --> 00:02:07.558 213 | In this scenario, you would 214 | also use a route filter 215 | 216 | 44 217 | 00:02:07.570 --> 00:02:10.759 218 | feature to reduce the BGP 219 | overhead to only receive 220 | 221 | 45 222 | 00:02:10.770 --> 00:02:13.279 223 | the specific address 224 | ranges for the regions 225 | 226 | 46 227 | 00:02:13.290 --> 00:02:14.429 228 | or services you need. 229 | 230 | 47 231 | 00:02:14.650 --> 00:02:17.349 232 | However, most commonly 233 | used is private peering. 234 | 235 | 48 236 | 00:02:17.650 --> 00:02:19.479 237 | This is the blue box 238 | in the lower right-hand 239 | 240 | 49 241 | 00:02:19.490 --> 00:02:20.349 242 | corner of the diagram. 243 | 244 | 50 245 | 00:02:20.890 --> 00:02:23.839 246 | Using an ExpressRoute gateway 247 | on the VNet and a connection 248 | 249 | 51 250 | 00:02:23.850 --> 00:02:26.259 251 | object between the circuit 252 | and the gateway allows you 253 | 254 | 52 255 | 00:02:26.270 --> 00:02:29.039 256 | to extend your corporate 257 | on-premise private network 258 | 259 | 53 260 | 00:02:29.050 --> 00:02:32.659 261 | into Azure and access your 262 | Azure resources directly 263 | 264 | 54 265 | 00:02:32.670 --> 00:02:34.289 266 | on this private data path. 267 | 268 | 55 269 | 00:02:34.450 --> 00:02:36.389 270 | Again, not using the Internet. 271 | 272 | 56 273 | 00:02:37.350 --> 00:02:39.439 274 | ExpressRoute enables you to 275 | connect multiple ExpressRoute 276 | 277 | 57 278 | 00:02:39.450 --> 00:02:41.969 279 | gateways in the same or 280 | different regions back 281 | 282 | 58 283 | 00:02:41.980 --> 00:02:42.739 284 | to the same circuit. 285 | 286 | 59 287 | 00:02:42.920 --> 00:02:45.249 288 | For our largest premium 289 | ExpressRoute circuit, 290 | 291 | 60 292 | 00:02:45.260 --> 00:02:48.189 293 | that could be up to 100 294 | ExpressRoute gateways in any 295 | 296 | 61 297 | 00:02:48.200 --> 00:02:51.279 298 | region in the world back to 299 | the same ExpressRoute circuit. 300 | 301 | 62 302 | 00:02:51.840 --> 00:02:54.849 303 | There's also an ExpressRoute 304 | direct port option, which 305 | 306 | 63 307 | 00:02:54.860 --> 00:02:57.259 308 | would replace the partner 309 | edge in the diagram. 310 | 311 | 64 312 | 00:02:57.800 --> 00:03:01.409 313 | This allows you to connect 314 | your edge router directly to 315 | 316 | 65 317 | 00:03:01.420 --> 00:03:05.229 318 | the Microsoft routers in a 319 | facility for direct connection 320 | 321 | 66 322 | 00:03:05.240 --> 00:03:06.599 323 | to the Microsoft network. 324 | 325 | 67 326 | 00:03:07.340 --> 00:03:10.429 327 | Also, for monitoring, we 328 | offer the ExpressRoute 329 | 330 | 68 331 | 00:03:10.440 --> 00:03:11.279 332 | Traffic Collector. 333 | 334 | 69 335 | 00:03:11.720 --> 00:03:14.169 336 | This feature can provide 337 | detailed flow data on your 338 | 339 | 70 340 | 00:03:14.180 --> 00:03:16.549 341 | circuits to be able to 342 | identify things like top 343 | 344 | 71 345 | 00:03:16.560 --> 00:03:19.639 346 | talkers or other traffic-based 347 | metrics and queries. 348 | 349 | 72 350 | 00:03:21.720 --> 00:03:23.809 351 | The final service I'll 352 | cover in the hybrid 353 | 354 | 73 355 | 00:03:23.820 --> 00:03:26.639 356 | connectivity pillar is 357 | our virtual WAN service. 358 | 359 | 74 360 | 00:03:28.970 --> 00:03:33.419 361 | As the diagram shows, Virtual 362 | WAN, also called vWAN, brings 363 | 364 | 75 365 | 00:03:33.430 --> 00:03:36.979 366 | together all of the features 367 | of ExpressRoute and VPN, 368 | 369 | 76 370 | 00:03:36.990 --> 00:03:39.539 371 | and then extends them for 372 | any-to-any connectivity 373 | 374 | 77 375 | 00:03:39.550 --> 00:03:41.789 376 | into and across Azure. 377 | 378 | 78 379 | 00:03:42.150 --> 00:03:44.879 380 | If you're familiar with a 381 | hub-and-spoke architecture, 382 | 383 | 79 384 | 00:03:44.890 --> 00:03:47.999 385 | a Virtual WAN implements this 386 | in a concise, single-object 387 | 388 | 80 389 | 00:03:48.010 --> 00:03:50.499 390 | structure to implement the 391 | hub-and-spoke scaffolding 392 | 393 | 81 394 | 00:03:50.510 --> 00:03:52.629 395 | much faster than you 396 | could build yourself. 397 | 398 | 82 399 | 00:03:52.840 --> 00:03:56.569 400 | If you use a vWAN-aware 401 | SDN hardware device on 402 | 403 | 83 404 | 00:03:56.580 --> 00:03:59.579 405 | your premise, you get 406 | large-scale VPN automation. 407 | 408 | 84 409 | 00:04:00.080 --> 00:04:02.489 410 | Just log into your on-prem 411 | device with your Azure 412 | 413 | 85 414 | 00:04:02.500 --> 00:04:05.589 415 | credentials, and it can 416 | auto-configure the device and 417 | 418 | 86 419 | 00:04:05.600 --> 00:04:08.819 420 | establish the IPsec connection 421 | back to your vWAN hub. 422 | 423 | 87 424 | 00:04:09.320 --> 00:04:11.629 425 | This is great if you 426 | have many branch offices 427 | 428 | 88 429 | 00:04:11.640 --> 00:04:14.929 430 | or retail outlets that 431 | need VPN connections to 432 | 433 | 89 434 | 00:04:14.940 --> 00:04:15.939 435 | your Azure workloads. 436 | 437 | 90 438 | 00:04:16.279 --> 00:04:20.069 439 | vWAN also integrates with 440 | Azure Firewall, but not just 441 | 442 | 91 443 | 00:04:20.079 --> 00:04:23.689 444 | Azure's firewall, but also 445 | to other popular firewalls 446 | 447 | 92 448 | 00:04:23.700 --> 00:04:26.449 449 | from the marketplace to turn 450 | your regular vWAN hub into 451 | 452 | 93 453 | 00:04:26.460 --> 00:04:28.299 454 | what we call a secure hub. 455 | 456 | 94 457 | 00:04:28.660 --> 00:04:31.409 458 | This allows you to use the 459 | firewall of your choice and 460 | 461 | 95 462 | 00:04:31.420 --> 00:04:34.459 463 | your unique security policies 464 | to make your WAN secure. 465 | 466 | 96 467 | 00:04:35.320 --> 00:04:37.749 468 | vWAN introduces many other 469 | routing features like route 470 | 471 | 97 472 | 00:04:37.760 --> 00:04:40.849 473 | maps, routing intent, and 474 | others to manage the flows 475 | 476 | 98 477 | 00:04:40.860 --> 00:04:42.339 478 | across the virtual WAN. 479 | 480 | 99 481 | 00:04:43.000 --> 00:04:47.009 482 | All of this together allows 483 | you to enable, secure, and 484 | 485 | 100 486 | 00:04:47.020 --> 00:04:50.489 487 | control your network traffic, 488 | making the Microsoft backbone 489 | 490 | 101 491 | 00:04:50.500 --> 00:04:52.859 492 | and Azure your corporate WAN. 493 | 494 | 102 495 | 00:04:54.800 --> 00:04:57.169 496 | Hopefully this provides 497 | some insight into the 498 | 499 | 103 500 | 00:04:57.180 --> 00:05:00.349 501 | three main services in our 502 | hybrid connectivity pillar, 503 | 504 | 104 505 | 00:05:00.360 --> 00:05:03.379 506 | Azure VPN, ExpressRoute, 507 | and Virtual WAN. 508 | 509 | -------------------------------------------------------------------------------- /ERPartnerDocs/ExpressRoute Partner Support.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/ERPartnerDocs/ExpressRoute Partner Support.pdf -------------------------------------------------------------------------------- /ERPartnerDocs/ExpressRoute_partner_docs.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/ERPartnerDocs/ExpressRoute_partner_docs.zip -------------------------------------------------------------------------------- /LAX-Migration/ExR Migration LA to LA2 Post.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure/NetworkMonitoring/546e37dc5190275fa228c635dcd9fe1564997f73/LAX-Migration/ExR Migration LA to LA2 Post.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Microsoft Azure 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![0] 2 | 3 | # NetworkMonitoring 4 | 5 | **Azure / NetworkMonitoring** is a repository for open source Azure network monitoring tools. Each tool or collection of tools lives in a folder under the main NetworkMonitoring repo. 6 | 7 | The current tools/tool-sets are: 8 | #### AzureCT 9 | The Azure Connectivity Toolkit ([AzureCT][AzureCT]) is a PowerShell module and collection of server side web pages will test, generate, collect, store, and display performance and availability statistics of the network between you and Azure. The two main areas of functionality are: 10 | - A network availability test (Get-AzureNetworkAvailability) that runs pings and traceroutes over an extended period of time to show end to end availability and hop latency. 11 | - A bandwidth and latency tester (Get-LinkPerformance) that runs a series of iPerf3 load tests while concurently doing a TCP ping to show latency under various loads. 12 | 13 | 14 | [0]: ./AzureCT/media/AzureNMT.png "Azure Network Monitoring Tools" 15 | 16 | 17 | [AzureCT]: https://github.com/Azure/NetworkMonitoring/tree/master/AzureCT "AzureCT tree" 18 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | --------------------------------------------------------------------------------