{"cells":[{"cell_type":"markdown","source":["# A Getting Started Guide for Azure Sentinel notebooks with C Sharp\r\n","**Notebook Version:** 1.0
\r\n","\r\n"," **Platforms Supported**:\r\n"," - Azure Machine Learning (AML) Notebooks \r\n","\r\n","**Data Sources Required**:\r\n"," - No\r\n","\r\n","**.Net Interactive installation is required! **:\r\n"," - To use this notebook, you will first need to install .Net Interactive. Instructions are located in this article ->[Azure Sentinel Notebooks + Powershell](https://aka.ms/sentinel/pwsh-notebooks).\r\n","\r\n","** About this notebook **: \r\n","\r\n","This notebook takes you through the basics needed to get started with C# notebooks that leverage Azure Sentinel data and APIs. It uses Azure Sentinel watchlist as an example to illustrate how to call REST APIs in C#.\r\n","\r\n","Lastly, don't forget to install .Net Interactive to use this notebook!"],"metadata":{"nteract":{"transient":{"deleting":false}}}},{"cell_type":"code","source":["// Try your .NET Interactive - C# kernel\r\n","Console.WriteLine(\"I am in C# land!\")"],"outputs":[],"execution_count":null,"metadata":{"gather":{"logged":1600820739567}}},{"cell_type":"code","source":["// If you want to reference a library from Nuget\r\n","#r \"nuget:Octokit, 0.32.0\"\r\n","#r \"nuget:NodaTime, 2.4.6\"\r\n","using Octokit;\r\n","using NodaTime;\r\n","using NodaTime.Extensions;\r\n","using XPlot.Plotly;"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820742947}}},{"cell_type":"code","source":["// Get AAD access token using AZ CLI\r\n","#!pwsh\r\n","#Change the default colors \r\n","$Host.PrivateData.WarningBackgroundColor = \"White\"\r\n","$Host.PrivateData.WarningForegroundColor = \"Black\"\r\n","\r\n","$accessPass = az account get-access-token\r\n","$passJson = $accessPass | ConvertFrom-Json\r\n","$accessToken = $passJson[0].accessToken"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820745683}}},{"cell_type":"code","source":["// Transfer $accessToken in PowerShell to C# variable\r\n","#!csharp\r\n","#!share --from pwsh accessToken\r\n","string token = accessToken;"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820747843}}},{"cell_type":"code","source":["// class to read Sentinel workspace configuration: config.json in the directory\r\n","using System.IO;\r\n","using Newtonsoft.Json;\r\n","using Newtonsoft.Json.Linq;\r\n","\r\n","public class SentinelConfiguration\r\n","{\r\n"," public string TenantId { get; set; }\r\n"," public string SubscriptionId { get; set; }\r\n"," public string ResourceGroup { get; set; }\r\n"," public string WorkspaceId { get; set; }\r\n"," public string WorkspaceName { get; set; }\r\n","\r\n"," public SentinelConfiguration ReadConfiguration()\r\n"," {\r\n"," var config = new SentinelConfiguration();\r\n"," using (StreamReader reader = new StreamReader(\"config.json\"))\r\n"," {\r\n"," string json = reader.ReadToEnd();\r\n"," var jsonObj = JObject.Parse(json);\r\n","\r\n"," config.TenantId = (string)jsonObj[\"tenant_id\"];\r\n"," config.SubscriptionId = (string)jsonObj[\"subscription_id\"];\r\n"," config.ResourceGroup = (string)jsonObj[\"resource_group\"];\r\n"," config.WorkspaceId = (string)jsonObj[\"workspace_id\"];\r\n"," config.WorkspaceName = (string)jsonObj[\"workspace_name\"]; \r\n"," }\r\n","\r\n"," return config;\r\n"," }\r\n","}"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820750201}}},{"cell_type":"code","source":["// Define a class as Azure REST API Helper\r\n","using System.Net.Http;\r\n","\r\n","public class AzureResourceApiHelper\r\n","{\r\n"," public const string BaseUrl = \"https://management.azure.com\";\r\n"," public string AccessTokenTemplate = \"Bearer {0}\";\r\n","\r\n"," public string BuildResourceUrl(string azureResourceId)\r\n"," {\r\n"," return BaseUrl + azureResourceId;\r\n"," }\r\n","\r\n"," public HttpResponseMessage HttpGet(string token, string url)\r\n"," {\r\n"," HttpClient client = new HttpClient();\r\n"," client.DefaultRequestHeaders.Add(\"Authorization\", token);\r\n","\r\n"," HttpResponseMessage response = client.GetAsync(url).GetAwaiter().GetResult();\r\n"," return response;\r\n"," }\r\n","}"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820753177}}},{"cell_type":"code","source":["// Derfine a C# class for Azure Sentinel Watchlist\r\n","public class SentinelWatchlist\r\n","{\r\n"," private string watchlistsTemplate = \"/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.OperationalInsights/workspaces/{2}/providers/Microsoft.SecurityInsights/watchlists?api-version=2019-01-01-preview\";\r\n"," private string watchlistTemplate = \"/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.OperationalInsights/workspaces/{2}/providers/Microsoft.SecurityInsights/watchlists/{3}?api-version=2019-01-01-preview\";\r\n","\r\n"," // Get the watchlist by watchlist alias\r\n"," public HttpResponseMessage GetWatchlist(string accessToken, string watchlistAlias)\r\n"," {\r\n"," // Read config\r\n"," SentinelConfiguration config = new SentinelConfiguration();\r\n"," config = config.ReadConfiguration();\r\n","\r\n"," // call API\r\n"," AzureResourceApiHelper helper = new AzureResourceApiHelper();\r\n"," string resourceId = string.Format(watchlistTemplate, config.SubscriptionId, config.ResourceGroup,config.WorkspaceName, watchlistAlias);\r\n"," string url = helper.BuildResourceUrl(resourceId);\r\n"," string token = string.Format(helper.AccessTokenTemplate, accessToken);\r\n","\r\n"," return helper.HttpGet(token, url);\r\n"," }\r\n","\r\n"," // Get all watchlists\r\n"," public HttpResponseMessage GetAllWatchlists(string accessToken)\r\n"," {\r\n"," // Read config\r\n"," SentinelConfiguration config = new SentinelConfiguration();\r\n"," config = config.ReadConfiguration();\r\n","\r\n"," // call API\r\n"," AzureResourceApiHelper helper = new AzureResourceApiHelper();\r\n"," string resourceId = string.Format(watchlistsTemplate, config.SubscriptionId, config.ResourceGroup,config.WorkspaceName);\r\n"," string url = helper.BuildResourceUrl(resourceId);\r\n"," string token = string.Format(helper.AccessTokenTemplate, accessToken);\r\n","\r\n"," return helper.HttpGet(token, url);\r\n"," }\r\n","}"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820756386}}},{"cell_type":"code","source":["// Utils class\r\n","using System.Text.Json;\r\n","using Microsoft.AspNetCore.Html;\r\n","\r\n","public class Utils\r\n","{\r\n"," // Format json for readability\r\n"," public static string PrettyJson(string rawJson)\r\n"," {\r\n"," var options = new JsonSerializerOptions()\r\n"," {\r\n"," WriteIndented = true\r\n"," };\r\n","\r\n"," var jsonElement = System.Text.Json.JsonSerializer.Deserialize(rawJson);\r\n"," return System.Text.Json.JsonSerializer.Serialize(jsonElement, options);\r\n"," }\r\n","\r\n"," public static void TableDisplay()\r\n"," {\r\n"," Microsoft.DotNet.Interactive.Formatting.Formatter.Register>((dict, writter) =>\r\n"," {\r\n"," var headers = new List();\r\n"," headers.Add(th(\"Watchlist Alias\"));\r\n"," headers.Add(th(\"Updated Date\"));\r\n"," var rows = new List>();\r\n"," foreach (var pair in dict)\r\n"," {\r\n"," var cells = new List();\r\n"," cells.Add(td(pair.Key));\r\n"," cells.Add(td(pair.Value));\r\n"," rows.Add(cells);\r\n"," }\r\n"," \r\n"," var t = table(\r\n"," thead(headers),\r\n"," tbody(rows.Select(r => tr(r)))\r\n"," );\r\n","\r\n"," writter.Write(t);\r\n"," }, \"text/html\");\r\n"," }\r\n","}"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820759480}}},{"cell_type":"code","source":["// Get all watchlists, display alias\r\n","var wl = new SentinelWatchlist();\r\n","var responseMsg = wl.GetAllWatchlists(token);\r\n","string content = responseMsg.Content.ReadAsStringAsync().GetAwaiter().GetResult();\r\n","//Console.WriteLine(content);\r\n","dynamic x = Newtonsoft.Json.JsonConvert.DeserializeObject(content);\r\n","var allLists = x.value;\r\n","int index = 0;\r\n","var allWatchlist = new Dictionary();\r\n","\r\n","foreach(var watchlist in allLists)\r\n","{\r\n"," allWatchlist.Add(watchlist.properties.watchlistAlias.ToString(), watchlist.properties.updated.ToString());\r\n","}"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820764004}}},{"cell_type":"code","source":["// Display data in HTML table\r\n","Utils.TableDisplay();\r\n","allWatchlist"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820767444}}},{"cell_type":"code","source":["// if you have watchlist, then you may get a specific watchlist\r\n","if (allLists.Count > 0)\r\n","{\r\n"," // I set the index = 0, but you may select any index that is in the range of index\r\n"," var wlAlias = allWatchlist.Keys.FirstOrDefault();\r\n"," var responseMsg = wl.GetWatchlist(token, wlAlias);\r\n"," string content = responseMsg.Content.ReadAsStringAsync().GetAwaiter().GetResult();\r\n"," Console.WriteLine(Utils.PrettyJson(content));\r\n","}"],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}},"gather":{"logged":1600820771448}}},{"cell_type":"code","source":[],"outputs":[],"execution_count":null,"metadata":{"collapsed":true,"jupyter":{"source_hidden":false,"outputs_hidden":false},"nteract":{"transient":{"deleting":false}}}}],"metadata":{"kernelspec":{"name":".net-csharp","language":"C#","display_name":".NET (C#)"},"language_info":{"name":"C#","version":"8.0","mimetype":"text/x-csharp","file_extension":".cs","pygments_lexer":"csharp"},"kernel_info":{"name":".net-csharp"},"nteract":{"version":"nteract-front-end@1.0.0"}},"nbformat":4,"nbformat_minor":2}