├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── SUPPORT.md └── mde-api-gui.ps1 /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 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 | # GUI for MDE API sample app 2 | Simple PowerShell GUI for Microsoft Defender for Endpoint API machine actions. 3 | ![image](https://user-images.githubusercontent.com/25099900/195406810-55511f50-d1c7-4e80-94e1-945cfca2a219.png) 4 | ## Get started 5 | 1. Create Azure AD application as described here: https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/apis-intro?view=o365-worldwide 6 | 2. Grant the following API permissions to the application: 7 | 8 | | Permission | Description | 9 | |-------------------------|----------------------| 10 | | AdvancedQuery.Read.All | Run advanced queries | 11 | | Machine.Isolate | Isolate machine | 12 | | Machine.ReadWrite.All | Read and write all machine information (used for tagging) | 13 | | Machine.Scan | Scan machine | 14 | 15 | 3. Create application secret. 16 | ## Usage 17 | 1. **Connect** with AAD Tenant ID, Application Id and Application Secret of the application created earlier. 18 | 2. **Get Devices** that you want to perform actions on, using one of the following methods: 19 | * Advanced Hunting query (query result should contain DeviceName and DeviceId fields) 20 | * CSV file (single Name column with machine FQDNs) 21 | * Devices list separated with commas 22 | 3. Confirm selection in PowerShell forms pop-up. 23 | 4. Choose action that you want to perform on **Selected Devices**, the following actions are currently available: 24 | * Specify device tag in text box and **Apply tag**. 25 | * Run **AV Scan**. 26 | * **Isolate**/Release device. 27 | 5. Verify actions result with **Logs** text box. 28 | 29 | ## Contributing 30 | 31 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 32 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 33 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 34 | 35 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 36 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 37 | provided by the bot. You will only need to do this once across all repos using our CLA. 38 | 39 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 40 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 41 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 42 | 43 | ## Trademarks 44 | 45 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 46 | trademarks or logos is subject to and must follow 47 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 48 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 49 | Any use of third-party trademarks or logos are subject to those third-party's policies. 50 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 6 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 7 | feature request as a new Issue. 8 | 9 | ## Microsoft Support Policy 10 | 11 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 12 | -------------------------------------------------------------------------------- /mde-api-gui.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Simple PowerShell GUI for Microsoft Defender for Endpoint API machine actions. 4 | 5 | .DESCRIPTION 6 | Sample response tool that benefits from APIs and are using PowerShell as the tool of choice to perform actions in bulk. It doesn't require installation and can easily be adapted by anyone with some scripting experience. The tool currently accepts advanced hunting queries, computer names, and CSVs as device input methods. Once devices are selected, three types of actions can be performed: 7 | 8 | - Tagging devices 9 | - Performing Quick/Full AV scan, and 10 | - Performing Isolation/Release from Isolation 11 | 12 | An Azure AD AppID and Secret is required to connect to API and the tool needs the following App Permissions: 13 | 14 | - AdvancedQuery.Read.All 15 | - Machine.Isolate 16 | - Machine.ReadWrite.All 17 | - Machine.Scan 18 | 19 | #> 20 | 21 | 22 | #===========================================================[Classes]=========================================================== 23 | 24 | Add-Type -AssemblyName System.Windows.Forms 25 | Add-Type -AssemblyName System.Drawing 26 | Add-Type -TypeDefinition @' 27 | using System.Runtime.InteropServices; 28 | public class ProcessDPI { 29 | [DllImport("user32.dll", SetLastError=true)] 30 | public static extern bool SetProcessDPIAware(); 31 | } 32 | '@ 33 | $null = [ProcessDPI]::SetProcessDPIAware() 34 | 35 | 36 | #===========================================================[Variables]=========================================================== 37 | 38 | 39 | $script:selectedmachines = @{} 40 | $credspath = 'c:\temp\mdeuicreds.txt' 41 | $helpQueryBox = " 42 | AH Query: Specify advanced hunting query that will return DeviceId and DeviceName, e.g.: 'DeviceInfo | distinct DeviceId, DeviceName'`r`n 43 | Computer Name(s): Specify one o more FQDN computer names, e.g.: 'computer1.contoso.com, computer2.contoso.com'`r`n 44 | CSV: Specify path to CSV file with computer names, e.g.: 'C:\temp\Computers.csv'" 45 | 46 | $UnclickableColour = "#8d8989" 47 | $ClickableColour = "#ff7b00" 48 | $TextBoxFont = 'Microsoft Sans Serif,10' 49 | 50 | #===========================================================[WinForm]=========================================================== 51 | 52 | 53 | [System.Windows.Forms.Application]::EnableVisualStyles() 54 | 55 | 56 | $MainForm = New-Object system.Windows.Forms.Form 57 | $MainForm.SuspendLayout() 58 | $MainForm.AutoScaleDimensions = New-Object System.Drawing.SizeF(96, 96) 59 | $MainForm.AutoScaleMode = [System.Windows.Forms.AutoScaleMode]::Dpi 60 | $MainForm.ClientSize = '950,800' 61 | $MainForm.text = "MDE API GUI" 62 | $MainForm.BackColor = "#ffffff" 63 | $MainForm.TopMost = $false 64 | 65 | $Title = New-Object system.Windows.Forms.Label 66 | $Title.text = "1 - Connect with MDE API Credentials" 67 | $Title.AutoSize = $true 68 | $Title.width = 25 69 | $Title.height = 10 70 | $Title.location = New-Object System.Drawing.Point(20, 20) 71 | $Title.Font = 'Microsoft Sans Serif,12,style=Bold' 72 | 73 | $AppIdBoxLabel = New-Object system.Windows.Forms.Label 74 | $AppIdBoxLabel.text = "App Id:" 75 | $AppIdBoxLabel.AutoSize = $true 76 | $AppIdBoxLabel.width = 25 77 | $AppIdBoxLabel.height = 10 78 | $AppIdBoxLabel.location = New-Object System.Drawing.Point(20, 50) 79 | $AppIdBoxLabel.Font = 'Microsoft Sans Serif,10,style=Bold' 80 | 81 | $AppIdBox = New-Object system.Windows.Forms.TextBox 82 | $AppIdBox.multiline = $false 83 | $AppIdBox.width = 314 84 | $AppIdBox.height = 20 85 | $AppIdBox.location = New-Object System.Drawing.Point(100, 50) 86 | $AppIdBox.Font = $TextBoxFont 87 | $AppIdBox.Visible = $true 88 | 89 | $AppSecretBoxLabel = New-Object system.Windows.Forms.Label 90 | $AppSecretBoxLabel.text = "App Secret:" 91 | $AppSecretBoxLabel.AutoSize = $true 92 | $AppSecretBoxLabel.width = 25 93 | $AppSecretBoxLabel.height = 10 94 | $AppSecretBoxLabel.location = New-Object System.Drawing.Point(20, 75) 95 | $AppSecretBoxLabel.Font = 'Microsoft Sans Serif,10,style=Bold' 96 | 97 | $AppSecretBox = New-Object system.Windows.Forms.TextBox 98 | $AppSecretBox.multiline = $false 99 | $AppSecretBox.width = 314 100 | $AppSecretBox.height = 20 101 | $AppSecretBox.location = New-Object System.Drawing.Point(100, 75) 102 | $AppSecretBox.Font = $TextBoxFont 103 | $AppSecretBox.Visible = $true 104 | $AppSecretBox.PasswordChar = '*' 105 | 106 | $TenantIdBoxLabel = New-Object system.Windows.Forms.Label 107 | $TenantIdBoxLabel.text = "Tenant Id:" 108 | $TenantIdBoxLabel.AutoSize = $true 109 | $TenantIdBoxLabel.width = 25 110 | $TenantIdBoxLabel.height = 10 111 | $TenantIdBoxLabel.location = New-Object System.Drawing.Point(20, 100) 112 | $TenantIdBoxLabel.Font = 'Microsoft Sans Serif,10,style=Bold' 113 | 114 | $TenantIdBox = New-Object system.Windows.Forms.TextBox 115 | $TenantIdBox.multiline = $false 116 | $TenantIdBox.width = 314 117 | $TenantIdBox.height = 20 118 | $TenantIdBox.location = New-Object System.Drawing.Point(100, 100) 119 | $TenantIdBox.Font = $TextBoxFont 120 | $TenantIdBox.Visible = $true 121 | 122 | $ConnectionStatusLabel = New-Object system.Windows.Forms.Label 123 | $ConnectionStatusLabel.text = "Status:" 124 | $ConnectionStatusLabel.AutoSize = $true 125 | $ConnectionStatusLabel.width = 25 126 | $ConnectionStatusLabel.height = 10 127 | $ConnectionStatusLabel.location = New-Object System.Drawing.Point(20, 135) 128 | $ConnectionStatusLabel.Font = 'Microsoft Sans Serif,10,style=Bold' 129 | 130 | $ConnectionStatus = New-Object system.Windows.Forms.Label 131 | $ConnectionStatus.text = "Not Connected" 132 | $ConnectionStatus.AutoSize = $true 133 | $ConnectionStatus.width = 25 134 | $ConnectionStatus.height = 10 135 | $ConnectionStatus.location = New-Object System.Drawing.Point(100, 135) 136 | $ConnectionStatus.Font = 'Microsoft Sans Serif,10' 137 | 138 | $SaveCredCheckbox = new-object System.Windows.Forms.checkbox 139 | $SaveCredCheckbox.Location = New-Object System.Drawing.Point(200, 135) 140 | $SaveCredCheckbox.AutoSize = $true 141 | $SaveCredCheckbox.width = 60 142 | $SaveCredCheckbox.height = 10 143 | $SaveCredCheckbox.Text = "Save Credentials" 144 | $SaveCredCheckbox.Font = 'Microsoft Sans Serif,10' 145 | $SaveCredCheckbox.Checked = $false 146 | 147 | $ConnectBtn = New-Object system.Windows.Forms.Button 148 | $ConnectBtn.BackColor = "#ff7b00" 149 | $ConnectBtn.text = "Connect" 150 | $ConnectBtn.width = 90 151 | $ConnectBtn.height = 30 152 | $ConnectBtn.location = New-Object System.Drawing.Point(325, 130) 153 | $ConnectBtn.Font = 'Microsoft Sans Serif,10' 154 | $ConnectBtn.ForeColor = "#ffffff" 155 | $ConnectBtn.Visible = $True 156 | 157 | $TitleActions = New-Object system.Windows.Forms.Label 158 | $TitleActions.text = "3 - Perform Action on selected devices" 159 | $TitleActions.AutoSize = $true 160 | $TitleActions.width = 25 161 | $TitleActions.height = 10 162 | $TitleActions.location = New-Object System.Drawing.Point(500, 20) 163 | $TitleActions.Font = 'Microsoft Sans Serif,12,style=Bold' 164 | 165 | $TagDeviceGroupBox = New-Object System.Windows.Forms.GroupBox 166 | $TagDeviceGroupBox.Location = New-Object System.Drawing.Point(500,40) 167 | $TagDeviceGroupBox.width = 400 168 | $TagDeviceGroupBox.height = 50 169 | $TagDeviceGroupBox.Text = "Device tag" 170 | $TagDeviceGroupBox.Font = 'Microsoft Sans Serif,10,style=Bold' 171 | 172 | $DeviceTag = New-Object system.Windows.Forms.TextBox 173 | $Devicetag.multiline = $false 174 | $DeviceTag.width = 200 175 | $DeviceTag.height = 25 176 | $DeviceTag.location = New-Object System.Drawing.Point(20, 20) 177 | $Devicetag.Font = 'Microsoft Sans Serif,10' 178 | $DeviceTag.Visible = $true 179 | $Devicetag.Enabled = $false 180 | 181 | $TagDeviceBtn = New-Object system.Windows.Forms.Button 182 | $TagDeviceBtn.BackColor = $UnclickableColour 183 | $TagDeviceBtn.text = "Apply Tag" 184 | $TagDeviceBtn.width = 110 185 | $TagDeviceBtn.height = 30 186 | $TagDeviceBtn.location = New-Object System.Drawing.Point(280, 15) 187 | $TagDeviceBtn.Font = 'Microsoft Sans Serif,10' 188 | $TagDeviceBtn.ForeColor = "#ffffff" 189 | $TagDeviceBtn.Visible = $true 190 | 191 | $TagDeviceGroupBox.Controls.AddRange(@($DeviceTag, $TagDeviceBtn)) 192 | 193 | $ScanGroupBox = New-Object System.Windows.Forms.GroupBox 194 | $ScanGroupBox.Location = New-Object System.Drawing.Point(500,105) 195 | $ScanGroupBox.width = 400 196 | $ScanGroupBox.height = 50 197 | $ScanGroupBox.Text = "Scan mode" 198 | $ScanGroupBox.Font = 'Microsoft Sans Serif,10,style=Bold' 199 | 200 | $ScanRadioButton1 = New-Object System.Windows.Forms.RadioButton 201 | $ScanRadioButton1.Width = 80 202 | $ScanRadioButton1.Height = 20 203 | $ScanRadioButton1.location = New-Object System.Drawing.Point(20, 20) 204 | $ScanRadioButton1.Checked = $false 205 | $ScanRadioButton1.Enabled = $false 206 | $ScanRadioButton1.Text = "Full Scan" 207 | $ScanRadioButton1.Font = 'Microsoft Sans Serif,8' 208 | 209 | $ScanRadioButton2 = New-Object System.Windows.Forms.RadioButton 210 | $ScanRadioButton2.Width = 80 211 | $ScanRadioButton2.Height = 20 212 | $ScanRadioButton2.location = New-Object System.Drawing.Point(120, 20) 213 | $ScanRadioButton2.Checked = $true 214 | $ScanRadioButton2.Enabled = $false 215 | $ScanRadioButton2.Text = "Quick Scan" 216 | $ScanRadioButton2.Font = 'Microsoft Sans Serif,8' 217 | 218 | $ScanDeviceBtn = New-Object system.Windows.Forms.Button 219 | $ScanDeviceBtn.BackColor = $UnclickableColour 220 | $ScanDeviceBtn.text = "AV Scan" 221 | $ScanDeviceBtn.width = 110 222 | $ScanDeviceBtn.height = 30 223 | $ScanDeviceBtn.location = New-Object System.Drawing.Point(280, 15) 224 | $ScanDeviceBtn.Font = 'Microsoft Sans Serif,10' 225 | $ScanDeviceBtn.ForeColor = "#ffffff" 226 | $ScanDeviceBtn.Visible = $true 227 | 228 | $ScanGroupBox.Controls.AddRange(@($ScanRadioButton1, $ScanRadioButton2, $ScanDeviceBtn)) 229 | 230 | $IsolateGroupBox = New-Object System.Windows.Forms.GroupBox 231 | $IsolateGroupBox.Location = '500,165' 232 | $IsolateGroupBox.Width = 400 233 | $IsolateGroupBox.height = 90 234 | $IsolateGroupBox.text = "Isolation" 235 | $IsolateGroupBox.Font = 'Microsoft Sans Serif,10,style=Bold' 236 | 237 | $IsolateRadioButton1 = New-Object System.Windows.Forms.RadioButton 238 | $IsolateRadioButton1.width = 60 239 | $IsolateRadioButton1.height = 20 240 | $IsolateRadioButton1.location = New-Object System.Drawing.Point(20, 20) 241 | $IsolateRadioButton1.Checked = $false 242 | $IsolateRadioButton1.Enabled = $false 243 | $IsolateRadioButton1.Text = "Full" 244 | $IsolateRadioButton1.Font = 'Microsoft Sans Serif,8' 245 | 246 | $IsolateRadioButton2 = New-Object System.Windows.Forms.RadioButton 247 | $IsolateRadioButton2.width = 120 248 | $IsolateRadioButton2.height = 20 249 | $IsolateRadioButton2.location = New-Object System.Drawing.Point(120, 20) 250 | $IsolateRadioButton2.Checked = $true 251 | $IsolateRadioButton2.Enabled = $false 252 | $IsolateRadioButton2.Text = "Selective" 253 | $IsolateRadioButton2.Font = 'Microsoft Sans Serif,8' 254 | 255 | $IsolateDeviceBtn = New-Object system.Windows.Forms.Button 256 | $IsolateDeviceBtn.BackColor = $UnclickableColour 257 | $IsolateDeviceBtn.text = "Isolate Device" 258 | $IsolateDeviceBtn.width = 110 259 | $IsolateDeviceBtn.height = 30 260 | $IsolateDeviceBtn.location = New-Object System.Drawing.Point(280, 15) 261 | $IsolateDeviceBtn.Font = 'Microsoft Sans Serif,10' 262 | $IsolateDeviceBtn.ForeColor = "#ffffff" 263 | $IsolateDeviceBtn.Visible = $true 264 | 265 | $ReleaseFromIsolationBtn = New-Object system.Windows.Forms.Button 266 | $ReleaseFromIsolationBtn.BackColor = $UnclickableColour 267 | $ReleaseFromIsolationBtn.text = "Release Device" 268 | $ReleaseFromIsolationBtn.width = 110 269 | $ReleaseFromIsolationBtn.height = 30 270 | $ReleaseFromIsolationBtn.location = New-Object System.Drawing.Point(280, 50) 271 | $ReleaseFromIsolationBtn.Font = 'Microsoft Sans Serif,10' 272 | $ReleaseFromIsolationBtn.ForeColor = "#ffffff" 273 | $ReleaseFromIsolationBtn.Visible = $true 274 | 275 | $IsolateGroupBox.Controls.AddRange(@($IsolateRadioButton1, $IsolateRadioButton2, $IsolateDeviceBtn, $ReleaseFromIsolationBtn)) 276 | 277 | $InputRadioBox = New-Object System.Windows.Forms.GroupBox 278 | $InputRadioBox.width = 880 279 | $InputRadioBox.height = 240 280 | $InputRadioBox.location = New-Object System.Drawing.Point(20, 290) 281 | $InputRadioBox.text = "2 - Select devices to perform action on" 282 | $InputRadioBox.Font = 'Microsoft Sans Serif,12,style=Bold' 283 | 284 | $InputRadioButton1 = New-Object System.Windows.Forms.RadioButton 285 | $InputRadioButton1.width = 90 286 | $InputRadioButton1.height = 20 287 | $InputRadioButton1.location = New-Object System.Drawing.Point(20, 25) 288 | $InputRadioButton1.Checked = $true 289 | $InputRadioButton1.Enabled = $false 290 | $InputRadioButton1.Text = "AH Query" 291 | $InputRadioButton1.Font = 'Microsoft Sans Serif,10' 292 | 293 | $InputRadioButton2 = New-Object System.Windows.Forms.RadioButton 294 | $InputRadioButton2.width = 140 295 | $InputRadioButton2.height = 20 296 | $InputRadioButton2.location = New-Object System.Drawing.Point(110, 25) 297 | $InputRadioButton2.Checked = $false 298 | $InputRadioButton2.Enabled = $false 299 | $InputRadioButton2.Text = "Computer Name(s)" 300 | $InputRadioButton2.Font = 'Microsoft Sans Serif,10' 301 | 302 | $InputRadioButton3 = New-Object System.Windows.Forms.RadioButton 303 | $InputRadioButton3.width = 60 304 | $InputRadioButton3.height = 20 305 | $InputRadioButton3.location = New-Object System.Drawing.Point(265, 25) 306 | $InputRadioButton3.Checked = $false 307 | $InputRadioButton3.Enabled = $false 308 | $InputRadioButton3.Text = "CSV" 309 | $InputRadioButton3.Font = 'Microsoft Sans Serif,10' 310 | 311 | $QueryBox = New-Object system.Windows.Forms.TextBox 312 | $QueryBox.multiline = $true 313 | $QueryBox.text = $helpQueryBox 314 | $QueryBox.width = 850 315 | $QueryBox.height = 120 316 | $QueryBox.location = New-Object System.Drawing.Point(20, 60) 317 | $QueryBox.ScrollBars = 'Vertical' 318 | $QueryBox.Font = $TextBoxFont 319 | $QueryBox.Visible = $true 320 | $QueryBox.Enabled = $false 321 | 322 | $RunQueryBtn = New-Object system.Windows.Forms.Button 323 | $RunQueryBtn.BackColor = $UnclickableColour 324 | $RunQueryBtn.text = "Run Query" 325 | $RunQueryBtn.width = 90 326 | $RunQueryBtn.height = 30 327 | $RunQueryBtn.location = New-Object System.Drawing.Point(20, 190) 328 | $RunQueryBtn.Font = 'Microsoft Sans Serif,10' 329 | $RunQueryBtn.ForeColor = "#ffffff" 330 | $RunQueryBtn.Visible = $true 331 | 332 | $GetDevicesFromQueryBtn = New-Object System.Windows.Forms.Button 333 | $GetDevicesFromQueryBtn.BackColor = $UnclickableColour 334 | $GetDevicesFromQueryBtn.text = "Get Devices" 335 | $GetDevicesFromQueryBtn.width = 180 336 | $GetDevicesFromQueryBtn.height = 30 337 | $GetDevicesFromQueryBtn.location = New-Object System.Drawing.Point(690, 190) 338 | $GetDevicesFromQueryBtn.Font = 'Microsoft Sans Serif,10' 339 | $GetDevicesFromQueryBtn.ForeColor = "#ffffff" 340 | $GetDevicesFromQueryBtn.Visible = $true 341 | 342 | $SelectedDevicesBtn = New-Object system.Windows.Forms.Button 343 | $SelectedDevicesBtn.BackColor = $UnclickableColour 344 | $SelectedDevicesBtn.text = "Selected Devices (" + $script:selectedmachines.Keys.count + ")" 345 | $SelectedDevicesBtn.width = 150 346 | $SelectedDevicesBtn.height = 30 347 | $SelectedDevicesBtn.location = New-Object System.Drawing.Point(530, 190) 348 | $SelectedDevicesBtn.Font = 'Microsoft Sans Serif,10' 349 | $SelectedDevicesBtn.ForeColor = "#ffffff" 350 | $SelectedDevicesBtn.Visible = $false 351 | 352 | $ClearSelectedDevicesBtn = New-Object system.Windows.Forms.Button 353 | $ClearSelectedDevicesBtn.BackColor = $UnclickableColour 354 | $ClearSelectedDevicesBtn.text = "Clear Selection" 355 | $ClearSelectedDevicesBtn.width = 150 356 | $ClearSelectedDevicesBtn.height = 30 357 | $ClearSelectedDevicesBtn.location = New-Object System.Drawing.Point(370, 190) 358 | $ClearSelectedDevicesBtn.Font = 'Microsoft Sans Serif,10' 359 | $ClearSelectedDevicesBtn.ForeColor = "#ffffff" 360 | $ClearSelectedDevicesBtn.Visible = $false 361 | 362 | $InputRadioBox.Controls.AddRange(@($InputRadioButton1, $InputRadioButton2, $InputRadioButton3, $QueryBox, $RunQueryBtn, $GetDevicesFromQueryBtn, $SelectedDevicesBtn, $ClearSelectedDevicesBtn)) 363 | 364 | $LogBoxLabel = New-Object system.Windows.Forms.Label 365 | $LogBoxLabel.text = "4 - Logs:" 366 | $LogBoxLabel.width = 394 367 | $LogBoxLabel.height = 20 368 | $LogBoxLabel.location = New-Object System.Drawing.Point(20, 600) 369 | $LogBoxLabel.Font = 'Microsoft Sans Serif,12,style=Bold' 370 | $LogBoxLabel.Visible = $true 371 | 372 | $LogBox = New-Object system.Windows.Forms.TextBox 373 | $LogBox.multiline = $true 374 | $LogBox.width = 880 375 | $LogBox.height = 100 376 | $LogBox.location = New-Object System.Drawing.Point(20, 630) 377 | $LogBox.ScrollBars = 'Vertical' 378 | $LogBox.Font = $TextBoxFont 379 | $LogBox.Visible = $true 380 | 381 | $ExportLogBtn = New-Object system.Windows.Forms.Button 382 | $ExportLogBtn.BackColor = '#FFF0F8FF' 383 | $ExportLogBtn.text = "Export Logs" 384 | $ExportLogBtn.width = 90 385 | $ExportLogBtn.height = 30 386 | $ExportLogBtn.location = New-Object System.Drawing.Point(20, 750) 387 | $ExportLogBtn.Font = 'Microsoft Sans Serif,10' 388 | $ExportLogBtn.ForeColor = "#ff000000" 389 | $ExportLogBtn.Visible = $true 390 | 391 | $GetActionsHistoryBtn = New-Object system.Windows.Forms.Button 392 | $GetActionsHistoryBtn.BackColor = $UnclickableColour 393 | $GetActionsHistoryBtn.text = "Get Actions History" 394 | $GetActionsHistoryBtn.width = 150 395 | $GetActionsHistoryBtn.height = 30 396 | $GetActionsHistoryBtn.location = New-Object System.Drawing.Point(130, 750) 397 | $GetActionsHistoryBtn.Font = 'Microsoft Sans Serif,10' 398 | $GetActionsHistoryBtn.ForeColor = "#ffffff" 399 | $GetActionsHistoryBtn.Visible = $true 400 | 401 | $ExportActionsHistoryBtn = New-Object system.Windows.Forms.Button 402 | $ExportActionsHistoryBtn.BackColor = $UnclickableColour 403 | $ExportActionsHistoryBtn.text = "Export Actions History" 404 | $ExportActionsHistoryBtn.width = 150 405 | $ExportActionsHistoryBtn.height = 30 406 | $ExportActionsHistoryBtn.location = New-Object System.Drawing.Point(300, 750) 407 | $ExportActionsHistoryBtn.Font = 'Microsoft Sans Serif,10' 408 | $ExportActionsHistoryBtn.ForeColor = "#ffffff" 409 | $ExportActionsHistoryBtn.Visible = $true 410 | 411 | $cancelBtn = New-Object system.Windows.Forms.Button 412 | $cancelBtn.BackColor = '#FFF0F8FF' 413 | $cancelBtn.text = "Cancel" 414 | $cancelBtn.width = 90 415 | $cancelBtn.height = 30 416 | $cancelBtn.location = New-Object System.Drawing.Point(810, 750) 417 | $cancelBtn.Font = 'Microsoft Sans Serif,10' 418 | $cancelBtn.ForeColor = "#ff000000" 419 | $cancelBtn.DialogResult = [System.Windows.Forms.DialogResult]::Cancel 420 | $MainForm.CancelButton = $cancelBtn 421 | $MainForm.Controls.Add($cancelBtn) 422 | 423 | #$MainForm.AutoScaleMode = 'dpi' 424 | 425 | $MainForm.controls.AddRange(@($Title, 426 | $Description, 427 | $ConnectionStatusLabel, 428 | $ConnectionStatus, 429 | $cancelBtn, 430 | $AppIdBox, 431 | $AppSecretBox, 432 | $TenantIdBox, 433 | $AppIdBoxLabel, 434 | $AppSecretBoxLabel, 435 | $TenantIdBoxLabel, 436 | $ConnectBtn, 437 | $TitleActions, 438 | $LogBoxLabel, 439 | $LogBox, 440 | $QueryBoxLabel, 441 | $IsolateGroupBox, 442 | $SaveCredCheckbox, 443 | $ScanGroupBox, 444 | $InputRadioBox, 445 | $TagDeviceGroupBox, 446 | $ExportLogBtn, 447 | $GetActionsHistoryBtn, 448 | $ExportActionsHistoryBtn)) 449 | 450 | 451 | #===========================================================[Functions]=========================================================== 452 | 453 | 454 | #Authentication 455 | 456 | function GetToken { 457 | $ConnectionStatus.ForeColor = "#000000" 458 | $ConnectionStatus.Text = 'Connecting...' 459 | $tenantId = $TenantIdBox.Text 460 | $appId = $AppIdBox.Text 461 | $appSecret = $AppSecretBox.Text 462 | $resourceAppIdUri = 'https://api.securitycenter.windows.com' 463 | $oAuthUri = "https://login.windows.net/$TenantId/oauth2/token" 464 | $authBody = [Ordered] @{ 465 | resource = "$resourceAppIdUri" 466 | client_id = "$appId" 467 | client_secret = "$appSecret" 468 | grant_type = 'client_credentials' 469 | } 470 | 471 | $authResponse = Invoke-RestMethod -Method Post -Uri $oAuthUri -Body $authBody -ErrorAction Stop 472 | $token = $authResponse.access_token 473 | $script:headers = @{ 474 | 'Content-Type' = 'application/json' 475 | Accept = 'application/json' 476 | Authorization = "Bearer $token" 477 | } 478 | 479 | if ($authresponse) { 480 | $ConnectionStatus.text = "Connected" 481 | $ConnectionStatus.ForeColor = "#7ed321" 482 | $LogBox.AppendText((get-date).ToString() + " Successfully connected to Tenant ID: " + $tenantId + [Environment]::NewLine) 483 | ChangeButtonColours -Buttons $GetDevicesFromQueryBtn, $SelectedDevicesBtn, $ClearSelectedDevicesBtn, $RunQueryBtn, $ExportActionsHistoryBtn, $GetActionsHistoryBtn 484 | EnableRadioButtons 485 | SaveCreds 486 | $Devicetag.Enabled = $true 487 | $QueryBox.Enabled = $true 488 | return $headers 489 | } 490 | else { 491 | $ConnectionStatus.text = "Connection Failed" 492 | [System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $Error[0] , "Error") 493 | $ConnectionStatus.ForeColor = "#D0021B" 494 | $cancelBtn.text = "Close" 495 | } 496 | 497 | } 498 | 499 | function SaveCreds{ 500 | if($SaveCredCheckbox.Checked){ 501 | $securespassword = $AppSecretBox.Text | ConvertTo-SecureString -AsPlainText -Force 502 | $securestring = $securespassword | ConvertFrom-SecureString 503 | $creds = @($TenantIdBox.Text, $AppIdBox.Text, $securestring) 504 | $creds | Out-File $credspath 505 | } 506 | } 507 | 508 | function ChangeButtonColours { 509 | [CmdletBinding()] 510 | Param ( 511 | [Parameter(Mandatory=$True)] 512 | $Buttons 513 | ) 514 | $ButtonsToChangeColour = $Buttons 515 | 516 | foreach( $Button in $ButtonsToChangeColour) { 517 | $Button.BackColor = $ClickableColour 518 | } 519 | } 520 | 521 | function EnableRadioButtons { 522 | $ButtonsToEnable = $ScanRadioButton1, $ScanRadioButton2, $IsolateRadioButton1, $IsolateRadioButton2, $InputRadioButton1, 523 | $InputRadioButton2, $InputRadioButton3 524 | 525 | foreach( $Button in $ButtonsToEnable) { 526 | $Button.Enabled = $true 527 | } 528 | } 529 | 530 | function GetDevice { 531 | $machines = $QueryBox.Text 532 | $machines = $machines.Split(",") 533 | $machines = $machines.replace(' ','') 534 | $script:selectedmachines = @{} 535 | foreach($machine in $machines){ 536 | Start-Sleep -Seconds 2 537 | $MachineName = $machine 538 | $url = "https://api.securitycenter.windows.com/api/machines/$MachineName" 539 | $webResponse = Invoke-RestMethod -Method Get -Uri $url -Headers $headers -ErrorAction Stop 540 | $MachineId = $webResponse.id 541 | if (-not $script:selectedmachines.contains($machine)) { 542 | $script:selectedmachines.Add($MachineName, $MachineId) 543 | } 544 | } 545 | $filtermachines = $script:selectedmachines | Out-GridView -Title "Select devices to perform action on:" -PassThru 546 | $script:selectedmachines.clear() 547 | foreach ($machine in $filtermachines) { 548 | $script:selectedmachines.Add($machine.Name, $machine.Value) 549 | } 550 | if ($script:selectedmachines.Keys.Count -gt 0) { 551 | ChangeButtonColours -Buttons $TagDeviceBtn, $ScanDeviceBtn, $IsolateDeviceBtn, $ReleaseFromIsolationBtn, $ExportActionsHistoryBtn, $GetActionsHistoryBtn 552 | $SelectedDevicesBtn.Visible = $true 553 | $SelectedDevicesBtn.text = "Selected Devices (" + $script:selectedmachines.Keys.count + ")" 554 | $ClearSelectedDevicesBtn.Visible = $true 555 | } 556 | $LogBox.AppendText((get-date).ToString() + " Devices selected count: " + ($script:selectedmachines.Keys.count -join [Environment]::NewLine) + [Environment]::NewLine + ($script:selectedmachines.Keys -join [Environment]::NewLine) + [Environment]::NewLine) 557 | } 558 | 559 | 560 | function TagDevice { 561 | $script:selectedmachines.GetEnumerator() | foreach-object { 562 | Start-Sleep -Seconds 2 563 | $MachineId = $_.value 564 | $MachineTag = $DeviceTag.Text 565 | $body = @{ 566 | "Value" = $MachineTag; 567 | "Action" = "Add"; 568 | } 569 | 570 | $url = "https://api.securitycenter.windows.com/api/machines/$MachineId/tags" 571 | try { $webResponse = Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop } 572 | Catch { 573 | if ($_.ErrorDetails.Message) { 574 | [System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $_.ErrorDetails.Message , "Error") 575 | } 576 | else { 577 | [System.Windows.Forms.MessageBox]::Show("Status: " + $webResponse.StatusCode) 578 | } 579 | } 580 | if ($null -ne $webResponse.statuscode) { 581 | $LogBox.AppendText((get-date).ToString() + " Applying machine tag: " + $MachineTag + " Machine Name: " + $_.Key + " Status code: " + $webResponse.statuscode + [Environment]::NewLine) } 582 | 583 | } 584 | } 585 | 586 | 587 | 588 | function ScanDevice { 589 | $script:selectedmachines.GetEnumerator() | foreach-object { 590 | Start-Sleep -Seconds 2 591 | $machineid = $_.Value 592 | if ($ScanRadioButton1.Checked) { $ScanMode = 'Full' } else { $ScanMode = 'Quick' } 593 | $body = @{ 594 | "Comment" = "AV Scan"; 595 | "ScanType" = $ScanMode; 596 | } 597 | $url = "https://api.securitycenter.windows.com/api/machines/$machineid/runAntiVirusScan" 598 | try { $webResponse = Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop } 599 | Catch { 600 | if ($_.ErrorDetails.Message) { 601 | [System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $_.ErrorDetails.Message , "Error") 602 | } 603 | else { 604 | [System.Windows.Forms.MessageBox]::Show("Status: " + $webResponse.StatusCode) 605 | } 606 | } 607 | if ($null -ne $webResponse.statuscode) { $LogBox.AppendText((get-date).ToString() + " " + $ScanMode + " AV Scan on Machine Name: " + $_.Key + " Status code: " + $webResponse.statuscode + [Environment]::NewLine) } 608 | } 609 | } 610 | 611 | function IsolateDevice { 612 | $script:selectedmachines.GetEnumerator() | foreach-object { 613 | Start-Sleep -Seconds 2 614 | $machineid = $_.Value 615 | $IsolationType = 'Selective' 616 | if ($IsolateRadioButton1.Checked) { $IsolationType = 'Full' } 617 | $body = @{ 618 | "Comment" = "Isolating device"; 619 | "IsolationType" = $IsolationType; 620 | } 621 | $url = "https://api.securitycenter.windows.com/api/machines/$machineid/isolate" 622 | try { $webResponse = Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop } 623 | Catch { 624 | if ($_.ErrorDetails.Message) { 625 | #[System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $_.ErrorDetails.Message + $_.ErrorDetails, "Error") 626 | $LogBox.AppendText((get-date).ToString() + " ErrorMessage: " + $_.ErrorDetails.Message + $_.Exception.Response.StatusCode + [Environment]::NewLine) 627 | 628 | } 629 | else { 630 | [System.Windows.Forms.MessageBox]::Show("Status: " + $webResponse.StatusCode) 631 | } 632 | } 633 | if ($null -ne $webResponse.statuscode) { $LogBox.AppendText((get-date).ToString() + " " + $IsolationType + " Isolation on: " + " Machine Name: " + $_.Key + " Status code: " + $webResponse.statuscode + [Environment]::NewLine) } 634 | } 635 | } 636 | 637 | function ReleaseFromIsolation { 638 | $script:selectedmachines.GetEnumerator() | foreach-object { 639 | Start-Sleep -Seconds 2 640 | $machineid = $_.Value 641 | $body = @{ 642 | "Comment" = "Releasing device from isolation"; 643 | } 644 | $url = "https://api.securitycenter.windows.com/api/machines/$machineid/unisolate" 645 | try { $webResponse = Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop } 646 | Catch { 647 | if ($_.ErrorDetails.Message) { 648 | #[System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $_.ErrorDetails.Message + $_.ErrorDetails, "Error") 649 | $LogBox.AppendText("ErrorMessage: " + $_.ErrorDetails.Message + $_.Exception.Response.StatusCode + [Environment]::NewLine) 650 | 651 | } 652 | else { 653 | [System.Windows.Forms.MessageBox]::Show("Status: " + $webResponse.StatusCode) 654 | } 655 | } 656 | if ($null -ne $webResponse.statuscode) { $LogBox.AppendText($IsolationType + " Releasing isolation on: " + " Machine Name: " + $_.Key + " Status code: " + $webResponse.statuscode + [Environment]::NewLine) } 657 | } 658 | } 659 | 660 | 661 | # This function is not present in GUI to avoid any unwanted changes to the environments 662 | function OffboardDevice { 663 | $script:selectedmachines.GetEnumerator() | foreach-object { 664 | Start-Sleep -Seconds 2 665 | $machineid = $_.Value 666 | $body = @{ 667 | "Comment" = "Offboarding machine using API"; 668 | } 669 | $url = "https://api.securitycenter.windows.com/api/machines/$machineid/offboard" 670 | try { $webResponse = Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop } 671 | Catch { 672 | if ($_.ErrorDetails.Message) { 673 | #[System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $_.ErrorDetails.Message + $_.ErrorDetails, "Error") 674 | $LogBox.AppendText("ErrorMessage: " + $_.ErrorDetails.Message + $_.Exception.Response.StatusCode + [Environment]::NewLine) 675 | 676 | } 677 | else { 678 | [System.Windows.Forms.MessageBox]::Show("Status: " + $webResponse.StatusCode) 679 | } 680 | } 681 | if ($null -ne $webResponse.statuscode) { $LogBox.AppendText("Offboarding machine: " + [Environment]::NewLine + " Machine Name: " + $_.Key + " Status code: " + $webResponse.statuscode + [Environment]::NewLine) } 682 | } 683 | } 684 | 685 | 686 | function RunQuery { 687 | Start-Sleep -Seconds 2 688 | $url = "https://api.securitycenter.windows.com/api/advancedqueries/run" 689 | $body = @{ 690 | "Query" = $QueryBox.Text; 691 | } 692 | try { $webResponse = Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop } 693 | Catch { 694 | if ($_.ErrorDetails.Message) { 695 | [System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $_.ErrorDetails.Message , "Error") 696 | } 697 | else { 698 | $LogBox.AppendText((get-date).ToString() + " Status: " + $webResponse.StatusCode) 699 | } 700 | } 701 | $LogBox.AppendText((get-date).ToString() + " Query Results: " + $webresponse + [Environment]::NewLine) 702 | } 703 | 704 | function GetDevicesFromQuery { 705 | if($InputRadioButton1.Checked -and (-not (($QueryBox.Text).contains('distinct') -and ($QueryBox.Text).contains('DeviceId')))){ 706 | $QueryBox.Text = $QueryBox.Text + [Environment]::NewLine + "| distinct DeviceName, DeviceId" 707 | [System.Windows.Forms.MessageBox]::Show("Query should return DeviceName and DeviceId. `nAppending `"| distinct DeviceName, DeviceId`" to the query.", "Warning") 708 | } 709 | $url = "https://api.securitycenter.windows.com/api/advancedqueries/run" 710 | $body = @{ 711 | "Query" = $QueryBox.Text; 712 | } 713 | $LogBox.AppendText((get-date).ToString() + " Executing query: " + $QueryBox.Text + [Environment]::NewLine) 714 | try { $webResponse = Invoke-WebRequest -Method Post -Uri $url -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json" -ErrorAction Stop } 715 | Catch { 716 | if ($_.ErrorDetails.Message) { 717 | [System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $_.ErrorDetails.Message , "Error") 718 | } 719 | else { 720 | $LogBox.AppendText((get-date).ToString() + " Status: " + $webResponse.StatusCode) 721 | } 722 | } 723 | $results = ($webResponse | ConvertFrom-Json).Results 724 | $LogBox.AppendText("Query results returned: " + $results.count + [Environment]::NewLine) 725 | $script:selectedmachines = @{} 726 | foreach ($result in $results) { 727 | if (-not $script:selectedmachines.contains($result.DeviceName)) { 728 | $script:selectedmachines.Add($result.DeviceName, $result.DeviceId) 729 | } 730 | } 731 | $filtermachines = $script:selectedmachines | Out-GridView -Title "Select devices to perform action on:" -PassThru 732 | $script:selectedmachines.clear() 733 | foreach ($machine in $filtermachines) { 734 | $script:selectedmachines.Add($machine.Name, $machine.Value) 735 | } 736 | if ($script:selectedmachines.Keys.Count -gt 0) { 737 | ChangeButtonColours -Buttons $TagDeviceBtn, $ScanDeviceBtn, $IsolateDeviceBtn, $ReleaseFromIsolationBtn, $ExportActionsHistoryBtn, $GetActionsHistoryBtn 738 | $SelectedDevicesBtn.Visible = $true 739 | $SelectedDevicesBtn.text = "Selected Devices (" + $script:selectedmachines.Keys.count + ")" 740 | $ClearSelectedDevicesBtn.Visible = $true 741 | } 742 | $LogBox.AppendText((get-date).ToString() + " Devices selected count: " + ($script:selectedmachines.Keys.count -join [Environment]::NewLine) + [Environment]::NewLine + ($script:selectedmachines.Keys -join [Environment]::NewLine) + [Environment]::NewLine) 743 | } 744 | 745 | function ViewSelectedDevices { 746 | $filtermachines = $script:selectedmachines | Out-GridView -Title "Select devices to perform action on:" -PassThru 747 | $script:selectedmachines.clear() 748 | foreach ($machine in $filtermachines) { 749 | $script:selectedmachines.Add($machine.Name, $machine.Value) 750 | } 751 | $SelectedDevicesBtn.text = "Selected Devices (" + $script:selectedmachines.Keys.count + ")" 752 | if ($null -eq $script:selectedmachines.Keys.Count) { 753 | $SelectedDevicesBtn.Visible = $false 754 | $SelectedDevicesBtn.text = "Selected Devices (" + $script:selectedmachines.Keys.count + ")" 755 | $ClearSelectedDevicesBtn.Visible = $false 756 | } 757 | $LogBox.AppendText((get-date).ToString() + " Devices selected count: " + ($script:selectedmachines.Keys.count -join [Environment]::NewLine) + [Environment]::NewLine + ($script:selectedmachines.Keys -join [Environment]::NewLine) + [Environment]::NewLine) 758 | } 759 | 760 | function ClearSelectedDevices { 761 | $script:selectedmachines = @{} 762 | $ClearSelectedDevicesBtn.Visible = $false 763 | $SelectedDevicesBtn.Visible = $false 764 | $LogBox.AppendText((get-date).ToString() + " Devices selected count: " + $script:selectedmachines.Keys.count + [Environment]::NewLine) 765 | } 766 | 767 | 768 | function GetDevicesFromCsv { 769 | if((Test-Path $QueryBox.Text) -and ($QueryBox.Text).EndsWith(".csv")) { 770 | $machines = Import-Csv -Path $QueryBox.Text 771 | $script:selectedmachines = @{} 772 | $LogBox.AppendText("Quering " + $machines.count + " machines from CSV file." + [Environment]::NewLine) 773 | foreach($machine in $machines){ 774 | Start-Sleep -Seconds 2 775 | $MachineName = $machine.Name 776 | $url = "https://api.securitycenter.windows.com/api/machines/$MachineName" 777 | $webResponse = Invoke-RestMethod -Method Get -Uri $url -Headers $headers -ErrorAction Stop 778 | $MachineId = $webResponse.id 779 | if (-not $script:selectedmachines.contains($machine.Name)) { 780 | $script:selectedmachines.Add($machine.Name, $MachineId) 781 | } 782 | } 783 | $filtermachines = $script:selectedmachines | Out-GridView -Title "Select devices to perform action on:" -PassThru 784 | $script:selectedmachines.clear() 785 | foreach ($machine in $filtermachines) { 786 | $script:selectedmachines.Add($machine.Name, $machine.Value) 787 | } 788 | if ($script:selectedmachines.Keys.Count -gt 0) { 789 | ChangeButtonColours -Buttons $TagDeviceBtn, $ScanDeviceBtn, $IsolateDeviceBtn, $ReleaseFromIsolationBtn 790 | $SelectedDevicesBtn.Visible = $true 791 | $SelectedDevicesBtn.text = "Selected Devices (" + $script:selectedmachines.Keys.count + ")" 792 | $ClearSelectedDevicesBtn.Visible = $true 793 | } 794 | $LogBox.AppendText((get-date).ToString() + " Devices selected count: " + ($script:selectedmachines.Keys.count -join [Environment]::NewLine) + [Environment]::NewLine + ($script:selectedmachines.Keys -join [Environment]::NewLine) + [Environment]::NewLine) 795 | } 796 | else { 797 | [System.Windows.Forms.MessageBox]::Show($QueryBox.Text + " is not a valid CSV path." , "Error") 798 | } 799 | } 800 | 801 | 802 | function GetActionsHistory { 803 | $LogBox.AppendText("Getting machine actions list.." + [Environment]::NewLine) 804 | $url = "https://api-us.securitycenter.windows.com/api/machineactions" 805 | try { $webResponse = Invoke-WebRequest -Method Get -Uri $url -Headers $headers -ErrorAction Stop } 806 | Catch { 807 | if ($_.ErrorDetails.Message) { 808 | [System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $_.ErrorDetails.Message , "Error") 809 | } 810 | else { 811 | $LogBox.AppendText((get-date).ToString() + " Status: " + $webResponse.StatusCode) 812 | } 813 | } 814 | $results = ($webResponse.Content | Convertfrom-json).value 815 | $LogBox.AppendText((get-date).ToString() + " Status: " + $webResponse.StatusCode + " Machine actions count: " + $results.count + [Environment]::NewLine) 816 | $LogBox.AppendText((get-date).ToString() + " Last 10 machine actions: " + ($results | Select-Object type,computerDnsName,status -First 10 | Out-string) + [Environment]::NewLine) 817 | $results | Out-GridView -Title "Actions History" -PassThru 818 | } 819 | 820 | function ExportActionsHistory { 821 | $LogBox.AppendText("Getting machine actions list.." + [Environment]::NewLine) 822 | $url = "https://api-us.securitycenter.windows.com/api/machineactions" 823 | try { $webResponse = Invoke-WebRequest -Method Get -Uri $url -Headers $headers -ErrorAction Stop } 824 | Catch { 825 | if ($_.ErrorDetails.Message) { 826 | [System.Windows.Forms.MessageBox]::Show("ErrorMessage: " + $_.ErrorDetails.Message , "Error") 827 | } 828 | else { 829 | $LogBox.AppendText((get-date).ToString() + " Status: " + $webResponse.StatusCode) 830 | } 831 | } 832 | $results = ($webResponse.Content | Convertfrom-json).value 833 | $LogBox.AppendText((get-date).ToString() + " Status: " + $webResponse.StatusCode + " Machine actions count: " + $results.count + [Environment]::NewLine) 834 | $results | Export-Csv -Path .\Response_Actions.csv -NoTypeInformation 835 | $LogBox.AppendText((get-date).ToString() + " Export file created: " + (Get-Item .\Response_Actions.csv).FullName + [Environment]::NewLine) 836 | } 837 | 838 | 839 | function ExportLog{ 840 | $LogBox.Text | Out-file .\mde_ui_log.txt 841 | $LogBox.AppendText((get-date).ToString() + " Log file created: " + (Get-Item .\mde_ui_log.txt).FullName + [Environment]::NewLine) 842 | } 843 | 844 | #===========================================================[Script]=========================================================== 845 | 846 | 847 | if(test-path $credspath){ 848 | $creds = Get-Content $credspath 849 | $pass = $creds[2] | ConvertTo-SecureString 850 | $unsecurePassword = [PSCredential]::new(0, $pass).GetNetworkCredential().Password 851 | $TenantIdBox.Text = $creds[0] 852 | $AppIdBox.Text = $creds[1] 853 | $AppSecretBox.Text = $unsecurePassword 854 | } 855 | 856 | 857 | $ConnectBtn.Add_Click({ GetToken }) 858 | 859 | $TagDeviceBtn.Add_Click({ TagDevice }) 860 | 861 | $ScanDeviceBtn.Add_Click({ ScanDevice }) 862 | 863 | $IsolateDeviceBtn.Add_Click({ IsolateDevice }) 864 | 865 | $ReleaseFromIsolationBtn.Add_Click({ ReleaseFromIsolation }) 866 | 867 | $RunQueryBtn.Add_Click({ RunQuery }) 868 | 869 | $GetDevicesFromQueryBtn.Add_Click({ 870 | if ($InputRadioButton1.Checked){ 871 | GetDevicesFromQuery } 872 | elseif ($InputRadioButton2.Checked){ 873 | GetDevice } 874 | elseif ($InputRadioButton3.Checked){ 875 | GetDevicesFromCsv } 876 | }) 877 | 878 | $SelectedDevicesBtn.Add_Click({ ViewSelectedDevices }) 879 | 880 | $ClearSelectedDevicesBtn.Add_Click({ ClearSelectedDevices }) 881 | 882 | $ExportLogBtn.Add_Click({ ExportLog }) 883 | 884 | $GetActionsHistoryBtn.Add_Click({ getActionsHistory }) 885 | 886 | $ExportActionsHistoryBtn.Add_Click({ ExportActionsHistory }) 887 | 888 | $MainForm.ResumeLayout() 889 | [void]$MainForm.ShowDialog() --------------------------------------------------------------------------------