├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── doc-azure-resrouces-dedicated-subnet
└── README.md
├── doc-azure-training
├── Data_and_AI_Training.md
├── IoT_Training.md
├── MicrosoftAcademy.md
├── MicrosoftLearn.md
├── OtherResources.md
├── README.md
└── files
│ ├── image005.png
│ ├── image006.png
│ ├── image007.png
│ ├── image008.jpg
│ ├── image009.png
│ ├── image010.png
│ ├── image011.jpg
│ ├── image012.png
│ ├── image013.jpg
│ ├── image014.png
│ ├── image015.jpg
│ ├── image016.png
│ ├── image017.png
│ ├── image018.jpg
│ ├── image019.png
│ ├── image020.png
│ ├── image021.png
│ ├── image022.jpg
│ ├── image023.png
│ ├── image024.jpg
│ ├── image025.png
│ ├── image026.jpg
│ ├── image027.png
│ └── image028.jpg
├── psh-B2B-two-tenant-sync
├── B2BSync-MyVars.ps1
├── B2BSync.ps1
├── B2BSync_CustomAttributes.ps1
├── B2BSync_DestSetup.ps1
├── B2BSync_SourceSetup.ps1
└── README.md
├── psh-BlobDataSync-Workflow
├── BlobSync.ps1
└── README.md
├── psh-GetArmLimitsViaAPI
├── GetArmLimits.ps1
└── README.md
├── psh-ManagedDiskUtils
├── CopyDiskImage_verified.ps1
├── ManagedDiskCopy.ps1
├── README.md
└── RemoveOrphanedDisks.ps1
├── psh-RBAC-CopyPaste
├── ApplyRBAC.ps1
├── CreateDestSPs.ps1
├── ExtractRBAC.ps1
├── Utils.ps1
├── readme.md
└── settings.json
├── psh-aad-b2b-batch-invite
├── B2BBatchPSH.ps1
└── README.md
├── psh-b2c-custom-attributes
├── B2C_CustomAttributes.ps1
└── README.md
├── psh-exo-encrypted-mailsend-script
├── Files
│ └── mail-flow-rules.png
├── README.md
├── SendEXOMailTest1.ps1
└── SendEXOMailTest2.ps1
├── psh-poison-queue
├── README.md
└── StorageQueueMovePoison.ps1
├── psh-sql-update-firewall
├── UpdateAllSqlFirewall.ps1
└── readme.md
├── sa-dsml-many-models
├── LICENSE
├── README.md
├── code
│ ├── aml_prs
│ │ ├── Data_Preparation.ipynb
│ │ ├── model_train.py
│ │ ├── prediction.py
│ │ └── prs_many_models.ipynb
│ ├── deployment
│ │ ├── 1-sai-create-endpoint.yml
│ │ ├── azureml_cli.txt
│ │ ├── conda.yml
│ │ ├── custom_role.json
│ │ ├── main_deployment.ipynb
│ │ ├── many_model.yml
│ │ ├── prs_1000_dominicks
│ │ ├── score.py
│ │ ├── test_data.csv
│ │ ├── test_data_1000_dominicks.csv
│ │ ├── test_data_1002_tropicana.csv
│ │ └── test_deployment.ipynb
│ ├── spark
│ │ └── many_models_spark.ipynb
│ ├── swagger.json
│ └── util
│ │ └── timeseries_utilities.py
└── images
│ ├── aml_many_models_arch.png
│ ├── pandas_udf.png
│ └── spark_many_models_arch.png
├── sample-AzGuardRails-Governance
├── AzurePolicy
│ ├── audit
│ │ ├── Audit-Managed-Disks.json
│ │ ├── Audit-PublicIP.json
│ │ └── Audit-Resource-Tag.json
│ └── deny
│ │ ├── Allowed-Locations.json
│ │ ├── Prevent-Unmanaged-Disk-Creation.json
│ │ └── denyPIP.json
├── CustomRBAC
│ ├── JsonExamples
│ │ ├── businessAnalysts.json
│ │ ├── cloudDevelopers.json
│ │ ├── cloudOpsAdmins.json
│ │ ├── cloudOpsEngLead.json
│ │ ├── digitalSecurity.json
│ │ ├── networkAdmins.json
│ │ └── suppReaderTickets.json
│ ├── PowerShell
│ │ ├── AzResourceProviderOperations.ps1
│ │ ├── Built-InRoles.ps1
│ │ ├── CustomRoleAssignment.ps1
│ │ ├── New-AzureRmDef-w-JSON.ps1
│ │ └── RoleTemplate.ps1
│ └── PowerShellRoleExamples
│ │ ├── RBACBASA.ps1
│ │ ├── RBACCloudOpsLead.ps1
│ │ ├── RBACCloudOpsNonLead.ps1
│ │ ├── RBACDeveloper.ps1
│ │ ├── RBACDigitalSecurity.ps1
│ │ ├── RBACNetworking.ps1
│ │ └── README.md
└── README.md
├── sample-EasyAuth-ClassicASP
├── EasyAuthClassicASP
│ ├── default.asp
│ ├── dockerfile
│ ├── global.asa
│ ├── inc
│ │ ├── 500-100.asp
│ │ └── EasyAuthASP.asp
│ └── web.config
└── README.md
├── sample-Python-KeyVault-Function
├── README.md
├── init-manual-service-principal.py
├── init-with-msi.py
└── requirements.txt
├── sample-UpdateManagement
├── Kusto
│ ├── Compliance
│ │ ├── NotAssessedHosts.csl
│ │ └── UncompliantHosts.csl
│ ├── Post Analysis
│ │ ├── Host-w-PatchAmountApplied.csl
│ │ └── LinWin-PostAnalysis.csl
│ ├── Pre-Analysis
│ │ ├── Linux-PreAnalysis.csl
│ │ └── Windows-PreAnalysis.csl
│ └── README.md
├── PowerShell
│ ├── ADDS
│ │ ├── 01-InitialTask-ADDSSecurityGroups.ps1
│ │ ├── 02-SchedTask-ADDSSecurityGroups.ps1
│ │ └── README.md
│ ├── AutomatedComplianceReporting
│ │ ├── 01-BearerToken.ps1
│ │ ├── 02-PostAnalysisAutomation.ps1
│ │ ├── 03-PreAnalysisAutomation-Linux.ps1
│ │ ├── 04-PreAnalysisAutomation-Windows.ps1
│ │ └── README.md
│ ├── AzureAutomationRunbooks
│ │ ├── 3rdPartyPatching
│ │ │ ├── 7Zip.ps1
│ │ │ ├── JRE.ps1
│ │ │ ├── VNC.ps1
│ │ │ ├── WinZip.ps1
│ │ │ └── Wireshark.ps1
│ │ ├── Export-RunAsCertificateToHybridWorker.ps1
│ │ ├── README.md
│ │ └── RollbackPatches
│ │ │ ├── WindowsRollback.ps1
│ │ │ └── linRollBack.py
│ ├── GroupSchedule
│ │ ├── 01-SvrGrping.ps1
│ │ ├── 02-WinSvrSched.ps1
│ │ ├── 03-LinuxSvrSched.ps1
│ │ └── README.md
│ └── UpdateAgentReadiness
│ │ ├── 01-BearerToken.ps1
│ │ ├── 02-UpdateAgentReadiness.ps1
│ │ └── README.md
├── README.md
└── WSUS Deployment
│ ├── README.md
│ ├── WSUS30SP2DeployGuide.doc
│ └── WSUS30SP2DeployGuide.pdf
├── sample-VMSS-DomainJoin-Arm
├── README.md
├── WindowsVirtualMachineScaleSet.parameters.json
└── WindowsVirtualMachineScaleSet_DomainJoin.json
└── sample-k8sRefArch
├── README.md
├── apim-appGw
├── README.md
├── aksDeploy.json
├── aksParams.json
├── appGwApimDeploy.json
├── appGwApimParams.json
├── helm-rbac.yaml
├── ingress-internal.yaml
└── kubectl-helm-commands.md
├── appGw
├── README.md
├── aksDeploy.json
├── aksParams.json
├── appGwDeploy.json
├── appGwParams.json
├── echo-api.yaml
├── helm-rbac.yaml
├── ingress-internal.yaml
└── kubectl-helm-commands.md
├── k8s
├── README.md
├── aksDeploy.json
├── aksParams.json
├── helm-rbac.yaml
├── ingress-internal.yaml
└── kubectl-helm-commands.md
├── keyVault
├── PoSH
│ ├── createKeyVault.ps1
│ └── generateSecret.ps1
├── README.md
└── armTemplate
│ ├── createKeyVault.json
│ └── createKeyVaultParams.json
└── setup
├── README.md
├── envSetup.md
└── generateSshKeys.md
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
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 | ## CSA Miscellaneous Utilities
2 |
3 | This repo contains a variety of small projects, utilities, and documents. Naming conventions:
4 | * "doc-": A help article or how-to
5 | * "psh-": A PowerShell script
6 | * "util-": A small utility project
7 | * "sample-": A small sample or PoC
8 | * "sa-": A solution accelerator project
9 |
10 | ## Contributing
11 |
12 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
13 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
14 | the rights to use your contribution. For details, visit https://cla.microsoft.com.
15 |
16 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
17 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
18 | provided by the bot. You will only need to do this once across all repos using our CLA.
19 |
20 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
21 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
22 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
23 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/doc-azure-resrouces-dedicated-subnet/README.md:
--------------------------------------------------------------------------------
1 |
List of Azure Services that require a dedicated subnet
2 | The following services can be deployed on a VNet but require a Subnet that cannot have any other Azure resource consiming the subnet private IPs. The minimum size for a Subnet in Azure is /29 which provides 8 IP Addresses. However, Azure reserves some IP addresses within each subnet. The first and last IP addresses of each subnet are reserved for protocol conformance, along with the x.x.x.1-x.x.x.3 addresses of each subnet, which are used for Azure services.
3 |
4 |
5 | Service
6 | Subnet Size
7 | Documentation
8 |
9 |
10 | VPN and ExpressRoute Gateways
11 | /27
12 | https://docs.microsoft.com/en-us/azure/vpn-gateway/vpn-gateway-vpn-faq
13 | https://docs.microsoft.com/en-us/azure/expressroute/expressroute-howto-add-gateway-portal-resource-manager
14 |
15 |
16 | App Gateway
17 | /28
18 | This size gives you 11 usable IP addresses. If your application load requires more than 10 IP addresses, consider a /27 or /26 subnet size.
19 | https://docs.microsoft.com/en-us/azure/application-gateway/configuration-overview#size-of-the-subnet
20 |
21 |
22 | Azure Firewall
23 | /26
24 | https://docs.microsoft.com/en-us/azure/firewall/tutorial-firewall-deploy-portal
25 |
26 |
27 |
28 | App Service Environment
29 | /24
30 | https://docs.microsoft.com/en-us/azure/app-service/environment/network-info
31 |
32 |
33 | Redis Cache
34 | /27
35 | Each Redis instance in the subnet uses two IP addresses per shard and one additional IP address for the load balancer. A non-clustered cache is considered to have one shard.
36 | https://docs.microsoft.com/en-us/azure/azure-cache-for-redis/cache-how-to-premium-vnet
37 |
38 |
39 |
40 | API Management
41 | /27
42 | https://docs.microsoft.com/en-us/azure/api-management/api-management-faq
43 |
44 |
45 | SQL Server Managed Instance
46 |
47 | /27
48 | https://docs.microsoft.com/en-us/azure/sql-database/sql-database-managed-instance-connectivity-architecture#network-requirements
49 |
50 |
51 |
52 | Integration Service Environment
53 | /27
54 | https://docs.microsoft.com/en-us/azure/logic-apps/connect-virtual-network-vnet-isolated-environment#create-subnet
55 |
56 |
57 |
--------------------------------------------------------------------------------
/doc-azure-training/Data_and_AI_Training.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/Data_and_AI_Training.md
--------------------------------------------------------------------------------
/doc-azure-training/IoT_Training.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/IoT_Training.md
--------------------------------------------------------------------------------
/doc-azure-training/MicrosoftLearn.md:
--------------------------------------------------------------------------------
1 |
2 | ### Microsoft Learn
3 |
4 | Welcome to the Microsoft Learn Step by Step guide to getting started. We are still working on the steps. Hang tight. We should be done very soon.
5 |
6 | In the mean time look around the rest of the pages.
7 |
8 | - [Data and AI Training](./Data_and_AI_Training.md#)
9 | - [Microsoft AI School](./Data_and_AI_Training.md#aischool)
10 | - [Cloud AI Bootcamp](./Data_and_AI_Training.md#learnaibootcamp)
11 | - [IoT Training](./IoT_Training.md#iottraining)
12 | - [Microsoft IoT School](./IoT_Training.md#iotschool)
13 | - [Other Learning Resources](./OtherResources.md#)
14 |
--------------------------------------------------------------------------------
/doc-azure-training/OtherResources.md:
--------------------------------------------------------------------------------
1 | ## Other Learning Resources
2 |
3 | ### Quick Start Azure Training
4 |
5 | ### Azure Essentials (Pluralsight)
6 |
7 | Link to [Azure Essentials](https://aka.ms/Hvyrqt)
8 |
9 | #### Description
10 |
11 | The simplest way to learn Azure
12 | - Watch, Learn, and Try with Microsoft Azure Essentials
13 | - Jump start your Azure learning. With Azure Essentials, you can:
14 | - Learn Azure technologies in under an hour
15 | - Access free Pluralsight courses and Quickstarts
16 | - Track your learning progress
17 | - Master the skills you need for cloud roles
18 |
19 | ### Channel 9 Shows
20 |
21 | ### Azure Friday
22 |
23 | Link to [Azure Friday](https://channel9.msdn.com/Shows/Azure-Friday)
24 |
25 | #### Description
26 |
27 | This is the longest running video blog on Azure and has a very large audience. It's great for "what's new and cool" kind of content.
28 |
29 | ### Microsoft Youtube Channels
30 |
31 | ### Cloud Simplified
32 |
33 | Link to [Cloud Simplfied](https://www.youtube.com/channel/UCwDoMq6rNGsU4aIQYhCnWpA)
34 |
35 | ##### Description From Channel
36 |
37 | So why another site devoted to cloud computing in Azure? There are many dedicated sites, YouTube channels and blogs devoted to specific capabilities in Azure such as using Premium Storage with your VMs to allow them to have higher throughput and using vnet peering to connect two virtual networks in Azure but we decided to take a different approach — focusing on _how_ to use these features to practically solve business problems!
38 |
39 | In our role at Microsoft as Cloud Solution Architects (CSA) serving customers all across the US, we have a unique perspective on what customers need to accomplish in the cloud and we work to help them complete their journey successfully meeting their performance, budgetary and reliability requirements. We decided to take that tribal knowledge and provide meaningful content to the community on how we addressed specific requirements to bring workloads to the cloud after all, Knowledge is Power!
40 |
41 |
42 | ### Guy in a Cube
43 |
44 | Link to [Guy in a Cube](https://www.youtube.com/channel/UCFp1vaKzpfvoGai0vE5VJ0w)
45 |
46 | ##### Description From Channel
47 |
48 | Guy in a Cube is all about helping you master business analytics on the Microsoft Business analytics stack to allow you to drive business growth. We are just two guys that do the work.
49 |
50 | We look at how to leverage Microsoft Business Analytics to allow you to gain knowledge that is needed to shape the data your business cares about. This includes Power BI, Reporting Services, Analysis Services and Excel. If you work with our business analytics products or services, be sure to subscribe and join in the discussion with our weekly content.
51 |
52 | MONDAY: Information round up and occasional Q&A with folks in the organization.
53 |
54 | TUESDAY & WEDNESDAY: Tech videos relating to Power BI and other products and services.
55 |
56 | *** Adam Saxton and Patrick LeBlanc are Microsoft Employees ***
57 |
--------------------------------------------------------------------------------
/doc-azure-training/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Azure Online Training
2 |
3 | __Contents__
4 |
5 | - [Introduction](#intro)
6 | - [Microsoft Learn](./MicrosoftLearn.md#)
7 | - [Data and AI Training](./Data_and_AI_Training.md#)
8 | - [Microsoft AI School](./Data_and_AI_Training.md#aischool)
9 | - [Cloud AI Bootcamp](./Data_and_AI_Training.md#learnaibootcamp)
10 | - [IoT Training](./IoT_Training.md#iottraining)
11 | - [Microsoft IoT School](./IoT_Training.md#iotschool)
12 | - [Other Learning Resources](./OtherResources.md#)
13 |
14 |
15 | __Introduction__
16 |
17 | Welcome to the updated "Getting Started with Azure Online Training" repo. This repo is designed to help you get started training on Azure fast. This is not a comprensive list. The courses listed here are what we see customer looking for as part of their digitial transformation.
18 |
19 | The prior version of this repo targeted Microsoft Academy. On January 31, 2019, Microsoft Academy will be shut down.
20 |
21 | The good news we have a much better replacement. [Microsoft Learn](https://docs.microsoft.com/en-us/learn/)
22 |
23 | [Microsoft Learn](https://docs.microsoft.com/en-us/learn/) fills in a couple of the gaps this repo and Microsoft Academy possessed.
24 | 1. __Learning Paths__. Learning Path are a pre-defined group of modules. If you are new to Azure or want to learn the basics we have an Azure 101. If you are looking to build a MEAN stack or bot we have paths for both.
25 | 2. __Role Based__ Micrsoft Learn also has role based learning paths. This has been requested by many customers for this site but was not something I was able to accomplish. Now Microsoft Learn has 5 roles for learning Azure. Each area is targeted to learning the services and configureations you may interact with in your role.
26 | 1. Administrator
27 | 2. Business Analyst
28 | 3. Business User
29 | 4. Developer
30 | 5. Solution Architect
31 |
32 | 3. __Hands-on__ Microsoft Learn has hands-on modules designed for trying something new in Azure.
33 |
34 | We still have the growing list of other learning and training resources. Take a look at our Data, IoT and Other pages for more information.
35 |
36 | Another new annoucement is Ask an Azure Advisor on Slack. This is a place where fellow Azure professional can interact. This is much like a 24/7 Virtual User Group. Visit https://askazure.io/ to get started.
37 |
38 | We encourage you to watch or star this repo as more content/ training offerings will be added overtime. Feel free to even fork this repo for your own organization's github.
39 |
40 | Let us know in the issues area if there are other trainings or content you would like to see.
41 |
42 | Finally, we do have a short URL for sharing this site with others: [aka.ms/AzureTrainingSites](https://aka.ms/AzureTrainingSites)
43 |
44 |
45 |
46 | __Disclaimer__
47 |
48 | This document is to assist with getting started on Azure Online Training. This is not a comprehensive list of all Azure Trainings available. It is a subset for getting started quickly. This is also not an endorsement of any one vendor or partner. All course costs and Azure resourse costs are the responsibility of the person taking the course.
49 |
--------------------------------------------------------------------------------
/doc-azure-training/files/image005.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image005.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image006.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image006.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image007.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image007.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image008.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image008.jpg
--------------------------------------------------------------------------------
/doc-azure-training/files/image009.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image009.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image010.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image010.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image011.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image011.jpg
--------------------------------------------------------------------------------
/doc-azure-training/files/image012.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image012.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image013.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image013.jpg
--------------------------------------------------------------------------------
/doc-azure-training/files/image014.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image014.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image015.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image015.jpg
--------------------------------------------------------------------------------
/doc-azure-training/files/image016.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image016.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image017.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image017.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image018.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image018.jpg
--------------------------------------------------------------------------------
/doc-azure-training/files/image019.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image019.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image020.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image020.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image021.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image021.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image022.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image022.jpg
--------------------------------------------------------------------------------
/doc-azure-training/files/image023.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image023.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image024.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image024.jpg
--------------------------------------------------------------------------------
/doc-azure-training/files/image025.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image025.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image026.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image026.jpg
--------------------------------------------------------------------------------
/doc-azure-training/files/image027.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image027.png
--------------------------------------------------------------------------------
/doc-azure-training/files/image028.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/doc-azure-training/files/image028.jpg
--------------------------------------------------------------------------------
/psh-B2B-two-tenant-sync/B2BSync-MyVars.ps1:
--------------------------------------------------------------------------------
1 | #CREDS
2 | # objectIds
3 | $SourceTenantId = "[Replace with tenantid of source tenant 2]"
4 | $SourceGroupId = "[Replace with groupid of members to be synced from source tenant 2]"
5 | $DestTenantId = "[Replace with tenantid of destination tenant 1]"
6 | $DestGroupId = "[Replace with groupid of members that have been synced from source tenant 2 to this dest tenant]"
7 |
8 | # Create in Destination tenant - requires Azure AD configuration (refer to docs)
9 | $appID = "[appid that will be facilitating all of this - see readme]"
10 | $appSecret = "[secret for that appid]"
11 | $appReplyUrl = "[reply URL for that appid]"
12 |
13 | #if guest user is removed from the source group, also remove guest user from dest tenant?
14 | $RemoveGuest = $false
15 |
16 | $CustomOIDAttributeName = "CustomOID"
--------------------------------------------------------------------------------
/psh-B2B-two-tenant-sync/B2BSync_DestSetup.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Configure DESTINATION site - one-time, add appropriate roles to the DEST site service principal
3 | MUST BE RUN AND LOGGED IN BY DESTINATION TENANT GLOBAL ADMIN
4 | See README.txt for details
5 | #IMPORTANT: edit "B2BSync-MyVars.ps1 and fill in your variables - see README
6 | #>
7 |
8 | # Dot-sourcing variables - update "B2BSync-Myvars.ps1 and use that file name
9 | . "$PSScriptRoot\B2BSync-MyVars.ps1"
10 | . "$PSScriptRoot\B2BSync_CustomAttributes.ps1"
11 |
12 | # Global Admin login to destination tenant
13 | Connect-AzureAD -TenantId $DestTenantId
14 |
15 | $RolesToEnable = @("Guest Inviter")
16 | $sp = Get-AzureADServicePrincipal -Filter "AppId eq `'$appID`'"
17 |
18 | foreach($rolename in $RolesToEnable){
19 | Write-Host "Enabling role $Rolename for Service Principal $($sp.DisplayName)"
20 | $roleId = (Get-AzureADDirectoryRole | where { $_.DisplayName -eq $roleName }).ObjectId
21 | Add-AzureADDirectoryRoleMember -ObjectId $roleId -RefObjectId $sp.ObjectId
22 | }
23 |
24 | $aadapp = Get-AzureADApplication -Filter "DisplayName eq '$($sp.AppDisplayName)'" -ErrorAction Stop
25 |
26 | #add custom attribute to app and tenant
27 | New-AppExtAttrFromSettings -AppObjId $aadapp.ObjectId
--------------------------------------------------------------------------------
/psh-B2B-two-tenant-sync/B2BSync_SourceSetup.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Configure SOURCE site - one-time, requires tenant admin to consent to the DEST site service principal
3 | See README.txt for details
4 | #IMPORTANT: edit "B2BSync-MyVars.ps1 and fill in your variables - see README
5 | #>
6 |
7 | # Dot-sourcing variables - update "B2BSync-Myvars.ps1 and use that file name
8 | . "$PSScriptRoot\B2BSync-MyVars.ps1"
9 |
10 | #consent URL (admin loads in browser)
11 | $consentUrl = "https://login.microsoftonline.com/$($SourceTenantId)/oauth2/authorize?response_type=id_token&client_id=$($appID)&redirect_uri=$appReplyUrl&response_mode=form_post&nonce=a4014117-28aa-47ec-abfb-f377be1d3cf6&resource=https://graph.windows.net&prompt=admin_consent"
12 | start $consentUrl
13 |
14 | Write-Host "If you successfully consented, you can now run B2BSync.ps1"
15 |
16 |
--------------------------------------------------------------------------------
/psh-GetArmLimitsViaAPI/GetArmLimits.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 |
4 | There are limits to the number of read/write operations that can be performed against the Azure Resource manager proviers in Azure.
5 | When this limit is reached there will be an HTTP 429 error returned. The documentation below outlines the specific REST call but
6 | does not provide a complete example
7 |
8 | https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-request-limits
9 |
10 | .DESCRIPTION
11 |
12 | This script creates the proper bearer token to invoke the REST API on the number of remaining Read Operations allowed against a specific
13 | subscription. The function Get-AzureCachedAccessToken provides the logic to pull the access token required to pass into the REST API
14 |
15 | #>
16 |
17 |
18 | function Get-AzureRmCachedAccessToken()
19 | {
20 | $ErrorActionPreference = 'Stop'
21 |
22 | if(-not (Get-Module AzureRm.Profile)) {
23 | Import-Module AzureRm.Profile
24 | }
25 | $azureRmProfileModuleVersion = (Get-Module AzureRm.Profile).Version
26 | # refactoring performed in AzureRm.Profile v3.0 or later
27 | if($azureRmProfileModuleVersion.Major -ge 3) {
28 | $azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
29 | if(-not $azureRmProfile.Accounts.Count) {
30 | Write-Error "Ensure you have logged in before calling this function."
31 | }
32 | } else {
33 | # AzureRm.Profile < v3.0
34 | $azureRmProfile = [Microsoft.WindowsAzure.Commands.Common.AzureRmProfileProvider]::Instance.Profile
35 | if(-not $azureRmProfile.Context.Account.Count) {
36 | Write-Error "Ensure you have logged in before calling this function."
37 | }
38 | }
39 |
40 | $currentAzureContext = Get-AzureRmContext
41 | $profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azureRmProfile)
42 | Write-Debug ("Getting access token for tenant" + $currentAzureContext.Subscription.TenantId)
43 | $token = $profileClient.AcquireAccessToken($currentAzureContext.Subscription.TenantId)
44 | $token.AccessToken
45 |
46 | }
47 |
48 |
49 | Write-Host "Log in to your Azure subscription..." -ForegroundColor Green
50 | #Login-AzureRmAccount
51 | #Get-AzureRmSubscription -SubscriptionName $SubscriptionName | Select-AzureRmSubscription
52 |
53 | $token = Get-AzureRmCachedAccessToken
54 | $currentAzureContext = Get-AzureRmContext
55 | Write-Host ("Getting access ARM Throttle Limits for Subscription: " + $currentAzureContext.Subscription)
56 |
57 |
58 | $requestHeader = @{
59 | "Authorization" = "Bearer " + $token
60 | "Content-Type" = "application/json"
61 | }
62 |
63 | $Uri = "https://management.azure.com/subscriptions/" + $currentAzureContext.Subscription + "/resourcegroups?api-version=2016-09-01"
64 | $r = Invoke-WebRequest -Uri $Uri -Method GET -Headers $requestHeader
65 | write-host("Remaining Read Operations: " + $r.Headers["x-ms-ratelimit-remaining-subscription-reads"])
--------------------------------------------------------------------------------
/psh-GetArmLimitsViaAPI/README.md:
--------------------------------------------------------------------------------
1 | ## Check ARM Limits for a Given Subscription
2 |
3 | There are limits to the number of read/write operations that can be performed against the Azure Resource manager providers in Azure. When this limit is reached there will be an HTTP 429 error returned. The documentation below outlines the specific REST call but does not provide a complete example.
4 |
5 | * [Details on Per-Subscription ARM Limits](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-request-limits).
6 |
--------------------------------------------------------------------------------
/psh-ManagedDiskUtils/CopyDiskImage_verified.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 |
4 | Managed disks in Azure have no direct facilitites to access the underlying URL/path the disk resides in since
5 | they are placed into storage accounts under the hood by Azure. Often times there's a desire to take a generalized VM
6 | image from one region and move to another region -- this script provides a mechanism to do this.
7 |
8 | .DESCRIPTION
9 |
10 | This script will require you to populate the source resource group and image name followed by details of a storage account
11 | existing or newly created storage account in the destination region to be used as an intermediate storage location. Once the disk
12 | is copied, we then create an image (Windows OS based in the script) pointed at the newly copied VHD
13 |
14 | This script takes advantage of the Grant-AzureRmDiskAccess provding a temporary SAS token to a managed disk.
15 |
16 | It does also require the specified container exist
17 |
18 | #>
19 |
20 |
21 | $sourceResourceGroupName='SourceResourceGroupName'
22 | $sourceImageName='NameOfSourceImageToCopy'
23 |
24 | $destconainer = 'containerindestinationstorageaccount'
25 | $destVHDName = 'destinationdisk.vhd'
26 | $destLocation = 'eastus'
27 | $destImageName = 'NewEmageEastUS'
28 | $destResourceGroup = 'DestResourceGroup'
29 | $destStorageAccount = 'destStorageAccountName'
30 | $destStorageAccountKey ='key'
31 |
32 | #Validation to ensure container name is lower case
33 | $destconainer = $destconainer.ToLower()
34 |
35 | $sas = Grant-AzureRmDiskAccess -ResourceGroupName $sourceResourceGroupName -DiskName $sourceImageName -DurationInSecond 3600 -Access Read
36 | $destContext = New-AzureStorageContext –StorageAccountName $destStorageAccount -StorageAccountKey $destStorageAccountKey
37 | Start-AzureStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $destconainer -DestContext $destContext -DestBlob $destVHDName -ConcurrentTaskCount 150
38 | Get-AzureStorageBlobCopyState -Container $destconainer -Blob $destVHDName -Context $destContext -WaitForComplete
39 |
40 | #build URI to new VHD
41 | $VHDPath=$destContext.StorageAccount.BlobStorageUri.PrimaryUri.AbsoluteUri
42 | $VHDPath=$VHDPath + $destconainer + "/" + $destVHDName
43 |
44 | #create image in destination based on copied VHD
45 | $imageConfig = New-AzureRmImageConfig -Location $destLocation
46 | $imageConfig = Set-AzureRmImageOsDisk -Image $imageConfig -OsType Windows -OsState Generalized -BlobUri $VHDPath
47 | $image = New-AzureRmImage -ImageName $destImageName -ResourceGroupName $destResourceGroup -Image $imageConfig
48 |
49 | #clean up the copied VHD
50 | Remove-AzureStorageBlob -Blob $destVHDName -Container $destconainer -Context $destContext
51 |
52 |
--------------------------------------------------------------------------------
/psh-ManagedDiskUtils/README.md:
--------------------------------------------------------------------------------
1 | # Azure Managed Disk and Image PowerShell Utilities
2 |
3 | This is a collection of various managed disk PowerShell scripts to perform actions in an automated manner.
4 |
5 | * [Copy Managed Image to Another Region](./CopyDiskImage_verified.ps1).
6 | Managed images in Azure have no direct facilities to access the underlying URL/path the disk resides in since they are placed into storage accounts under the hood by Azure. Often times there's a desire to take a generalized VM (image) from one region and move to another region. This script provides a mechanism to do this - UPDATE! Azure now has a native means to do this via a feature called [Shared Image Gallery](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/shared-image-galleries). The benefit of this feature is that Microsoft will copy the images to your target regions automatically allowing you to build a 'private' marketplace of sorts
7 |
8 | * [Copy Managed Disk to Another Region](./ManagedDiskCopy.ps1).
9 | Managed disks in Azure have no direct facilities to access the underlying URL/path the disk resides in since they are placed into storage accounts under the hood by Azure. Often times there's a desire to take a managed disk attached to a VM from one region and move to another region where you can create a NEW VM and attach the copied disk effectively cloning the VM int the destination region. This script provides a mechanism to do this outside of native features in Azure that allow you to move resources from one region to another (requiring the entire virtual network and related VMs be moved as well) or using the Azure Site Recovery feature to replicate to another region and fail-over. This is a simple means to copy raw disks to a destination region of your choice.
10 |
11 | * [Remove Orphaned VHDs](./RemoveOrphanedDisks.ps1).
12 | Managed disks linger when the source VM is removed in the event you wish to attach them to another VM. This PowerShell script will walk through storage accounts in the subscription specified or the susbcription(s) you have access to locating any disks that are not attached to a VM
13 |
--------------------------------------------------------------------------------
/psh-RBAC-CopyPaste/CreateDestSPs.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | IMPORTANT: this script doesn't attempt to replicate any API permissions, reply urls, or any other attributes of the
3 | application. It only recreates it in the destination tenant using the same name. If other settings are required,
4 | you'll need to update what's happening in "CreateSP" or manually update the app after it's created by reviewing
5 | the settings of the source object.
6 | #>
7 |
8 | # Load settings
9 | $Settings = Get-Content -Path "$PSScriptRoot\settings.json" | ConvertFrom-Json
10 | . "$PSScriptRoot\Utils.ps1"
11 |
12 | # Login
13 | Clear-AzureRmContext -Force
14 | $ctx = Connect-AzureRmAccount `
15 | -Force `
16 | -Tenant $Settings.DestTenantID `
17 | -ErrorAction Stop
18 | LoginToAAD
19 |
20 | # Load source SPs
21 | $SourceSPs = Get-Content -Path "$($PSScriptRoot)\SourceSPs.json" | ConvertFrom-Json
22 |
23 | $newSPList = @()
24 | foreach($sp in $SourceSPs) {
25 | $servicePrincipal = CreateSP `
26 | -DisplayName $sp.AppDisplayName `
27 | -Tenant $settings.DestTenant
28 |
29 | $newSPList += @{
30 | "AppId" = $servicePrincipal.App.AppId
31 | "DisplayName" = $servicePrincipal.App.DisplayName
32 | "SPObjectId" = $servicePrincipal.SP.ObjectId
33 | "AppObjectId" = $servicePrincipal.App.ObjectId
34 | "ServicePrincipalNames" = $servicePrincipal.SP.ServicePrincipalNames
35 | "ClearPassword" = $servicePrincipal.ClearPW
36 | "SourceAppId" = $sp.AppId
37 | "SourceObjectId" = $sp.ObjectId
38 | }
39 | $count++
40 | }
41 |
42 | $newSPList | format-list
43 | $newSPList | ConvertTo-Json | Out-File "$($PSScriptRoot)\NewServicePrincipals.json"
44 |
--------------------------------------------------------------------------------
/psh-RBAC-CopyPaste/ExtractRBAC.ps1:
--------------------------------------------------------------------------------
1 | # Load settings
2 | $Settings = Get-Content -Path "$PSScriptRoot\settings.json" | ConvertFrom-Json
3 | . "$PSScriptRoot\Utils.ps1"
4 |
5 | # Login
6 | Clear-AzureRmContext -Force
7 | $ctx = Connect-AzureRmAccount -Force `
8 | -Tenant $Settings.SourceTenantId `
9 | -Subscription $Settings.SubscriptionId `
10 | -ErrorAction Stop
11 | LoginToAAD
12 |
13 | # Find currently assigned roles in the entire subscription
14 | $RoleAssignments = Get-AzureRmRoleAssignment
15 |
16 | # Get all user principals from the tenant
17 | $SourceUsers = Get-AzureADUser -All $true | Select ObjectId, ImmutableId, MailNickName, ObjectType, DisplayName, Mail, UserPrincipalName, UserType
18 | # Get all service principals from the tenant
19 | $SourceSPs = Get-AzureADServicePrincipal -All $true | Select ObjectId, ObjectType, DisplayName, AppDisplayName, AppId
20 |
21 | # Clean up the lists
22 | $AssignedSPs = @()
23 | $AssignedUsers = @()
24 |
25 | # Filter to find only the SPs that have RBAC assignments
26 | foreach($sp in $SourceSPs) {
27 | foreach($assigned in $RoleAssignments) {
28 | if ($sp.ObjectId -eq $assigned.ObjectId) {
29 | $hasRecord = $AssignedSps | Where { $_.ObjectId -eq $sp.ObjectId }
30 | if (!$hasRecord) {
31 | $AssignedSPs += $sp
32 | }
33 | }
34 | }
35 | }
36 |
37 | # IMPORTANT - verify that all DisplayNames are UNIQUE - it's all we have to key on
38 | $DupeTest = HasDuplicates -ArrayToTest $AssignedSPs
39 | if ($DupeTest.hasDupes) {
40 | Write-Warning $DupeTest.dupItems | format-list
41 | throw "Ensure that all service principles/applications to be migrated have unique display names"
42 | }
43 |
44 | # Filter to find only users that have RBAC assignments
45 | foreach($user in $SourceUsers) {
46 | foreach($assigned in $RoleAssignments) {
47 | if ($user.ObjectId -eq $assigned.ObjectId) {
48 | $hasRecord = $AssignedUsers | Where { $_.ObjectId -eq $user.ObjectId }
49 | if (!$hasRecord) {
50 | $AssignedUsers += $user
51 | }
52 | }
53 | }
54 | }
55 |
56 | # Write the lists to the file system for later import
57 | $AssignedSPs | ConvertTo-Json | Out-File "$($PSScriptRoot)\SourceSPs.json"
58 | $AssignedUsers | ConvertTo-Json | Out-File "$($PSScriptRoot)\SourceUsers.json"
59 | $RoleAssignments | ConvertTo-Json | Out-File "$($PSScriptRoot)\SourceRoleAssignments.json"
60 |
--------------------------------------------------------------------------------
/psh-RBAC-CopyPaste/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "SubscriptionName": "[Subscription name]",
3 | "SubscriptionId": "[Subscription ID]",
4 | "SourceTenant": "[Source tenant name, like contoso.onmicrosoft.com]",
5 | "SourceTenantID": "[Source tenant ID]",
6 | "DestTenant": "[Destination tenant name, like fabrikam.onmicrosoft.com]",
7 | "DestTenantID": "[Destination tenant ID]"
8 | }
9 |
10 |
--------------------------------------------------------------------------------
/psh-aad-b2b-batch-invite/B2BBatchPSH.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | A guest, with "Guest Inviter" privileges, may invite other users from her home tenant to the guest tenant
3 | https://docs.microsoft.com/en-us/azure/active-directory/b2b/delegate-invitations
4 | https://docs.microsoft.com/en-us/azure/active-directory/b2b/add-user-without-invite
5 | https://docs.microsoft.com/en-us/azure/active-directory/active-directory-b2b-redemption-experience
6 |
7 | The scenario here is a newly acquired company, Fabrikam, has it's own AAD tenant. Contoso, the new
8 | parent company, wants to add a number of Contoso users as guests in the Fabrikam tenant. A Contoso admin
9 | is added as a guest in Fabrikam, then that admin is granted the "Guest Inviter" role in Fabrikam. The
10 | admin then runs this script, authenticates to Contoso, then sets the focus to Fabrikam (guest tenant id), and
11 | invites an array of Contoso users to Fabrikam. Since the admin is inviting users from his own tenant into
12 | the tenant where he's a guest, those users are automatically added. As the new guests don't need to
13 | consent to the invitation, no invitation email will be sent.
14 | #>
15 |
16 | $guestTenantId = "[acquired company tenant, eg fabrikam.com]"
17 |
18 | #sign in using your home (HQ, acquiring company, like Contoso) credentials, but focused on the tenant where you're a guest
19 | Connect-AzureAD -TenantId $guestTenantId
20 |
21 | #list of users from your home tenant that you want to be automatically invited to this tenant
22 | $userList = @("bob@contoso.com","mary@contoso.com","jane@contoso.onmicrosoft.com")
23 |
24 | #optional - load list of users from a CSV file
25 | #$userList = (get-content "c:\temp\userlist.csv").Split(',')
26 |
27 | #spin through these users and send each an invitation
28 | ForEach($user in $userList) {
29 | AzureAD\New-AzureADMSInvitation -InvitedUserEmailAddress $user -SendInvitationMessage $false -InviteRedirectUrl "https://myapps.microsoft.com/$guestTenantId"
30 | }
31 |
--------------------------------------------------------------------------------
/psh-aad-b2b-batch-invite/README.md:
--------------------------------------------------------------------------------
1 | A guest, with "Guest Inviter" privileges, may invite other users from her home tenant to the guest tenant.
2 | https://docs.microsoft.com/en-us/azure/active-directory/b2b/delegate-invitations
3 | https://docs.microsoft.com/en-us/azure/active-directory/b2b/add-user-without-invite
4 | https://docs.microsoft.com/en-us/azure/active-directory/active-directory-b2b-redemption-experience
5 |
6 | The scenario here is a newly acquired company, Fabrikam, has it's own AAD tenant. Contoso, the new
7 | parent company, wants to add a number of Contoso users as guests in the Fabrikam tenant. A Contoso admin
8 | is added as a guest in Fabrikam, then that admin is granted the "Guest Inviter" role in Fabrikam. The
9 | admin then runs this script, authenticates to Contoso, then sets the focus to Fabrikam (guest tenant id), and
10 | invites an array of Contoso users to Fabrikam. Since the admin is inviting users from his own tenant into
11 | the tenant where he's a guest, those users are automatically added. As the new guests don't need to
12 | consent to the invitation, no invitation email will be sent.
13 |
--------------------------------------------------------------------------------
/psh-b2c-custom-attributes/README.md:
--------------------------------------------------------------------------------
1 | ## Work With B2C Custom Attributes via REST
2 |
3 | When you create a custom attribute in Azure AD B2C, like "ShoeSize", it gets saved with a funky long name. This script includes
4 | a REST call that will retrieve the collection of custom attributes and store them in memory, then refer to that list to
5 | create the correct REST url for updating that attribute.
6 |
7 | You'll need to have your access token populated in $token, and put your tenant name in $Tenant. There are sample calls commented at the bottom of the file.
8 |
9 | NOTE: This is using the Azure AD Graph API.
10 |
11 | Here’s the REST reference:
12 | https://msdn.microsoft.com/en-us/library/azure/ad/graph/api/functions-and-actions#getAvailableExtensionProperties
13 |
14 |
--------------------------------------------------------------------------------
/psh-exo-encrypted-mailsend-script/Files/mail-flow-rules.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/psh-exo-encrypted-mailsend-script/Files/mail-flow-rules.png
--------------------------------------------------------------------------------
/psh-exo-encrypted-mailsend-script/README.md:
--------------------------------------------------------------------------------
1 | ## Sending Encrypted Mail From a Script
2 |
3 | Eventually, you're going to want to send an email from a script. This is really straightforward using Exchange Online and the Microsoft Graph API. But what if you want those emails to be encrypted? Sometimes, log information may be put in an email, and there may be something sensitive in that log.
4 |
5 | Azure Information Protection enables encryption, and it's also easy. But how to activate it from a script? There’s no apparent way to specify encryption in the Graph call, but you CAN setup default rules as an Exchange admin, that apply to a given user account. So the API call is over TLS, and once it gets to EXO through Graph, EXO will encrypt it before storing it or sending it.
6 |
7 | There are two approaches to accomplishing this:
8 |
9 | * In both cases:
10 |
11 | 1. Create a new user account and assign it a mailbox in EXO (limit its permissions all you want, as long as it can send email)
12 |
13 | 2. Create an app registration. Get the AppID and create an app secret.
14 |
15 | * Case A – Sending on behalf of this user
16 |
17 | 1. Assign it Application permissions to the Microsoft Graph API, allowing it to send email impersonating anyone in the org (this requires GA approval)
18 |
19 | 2. The script authenticates as the application, using the client_credential grant type. It calls https://graph.microsoft.com/v1.0/users/{0}/sendMail, filling in the UPN of the sending account mailbox.
20 |
21 | * Case B – Sending AS the user
22 |
23 | 1. Assign it delegated permissions to the Microsoft Graph API, allowing it to send on behalf of the logged-in user (doesn’t require admin approval)
24 |
25 | 2. The script authenticates as the user, using the password grant type. It calls https://graph.microsoft.com/v1.0/me/sendMail
26 |
27 | Setting up the mail flow rules requires someone to access the Exchange Admin console. Here's an example of a resulting encryption rule:
28 | 
29 |
30 |
31 | Here’s the REST reference:
32 | https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/user_sendmail
33 |
34 | Here’s the EXO mail flow encryption doc:
35 | https://docs.microsoft.com/en-us/office365/securitycompliance/define-mail-flow-rules-to-encrypt-email
36 |
37 |
--------------------------------------------------------------------------------
/psh-exo-encrypted-mailsend-script/SendEXOMailTest2.ps1:
--------------------------------------------------------------------------------
1 | function getAuthHeader() {
2 | Param(
3 | [Parameter(Mandatory=$true, Position=0)]
4 | [string]$ClientID,
5 | [Parameter(Mandatory=$true, Position=1)]
6 | [string]$ClientKey,
7 | [Parameter(Mandatory=$true, Position=2)]
8 | [string]$TenantID
9 | )
10 |
11 | $AADURI = "https://login.microsoftonline.com/$TenantID/oauth2/token"
12 | $GrantBody = "grant_type=client_credentials&client_id=$ClientID&client_secret=$ClientKey&resource=https://graph.microsoft.com"
13 |
14 | $AADTokenResponse = Invoke-RestMethod -Uri $AADURI -ContentType "application/x-www-form-urlencoded" -Body $GrantBody -Method Post
15 | return $AADTokenResponse.access_token
16 | }
17 |
18 | function SendMessage(){
19 | Param(
20 | [Parameter(Mandatory=$true, Position=0)]
21 | [string]$Subject,
22 | [Parameter(Mandatory=$true, Position=1)]
23 | [string]$Body,
24 | [Parameter(Mandatory=$true, Position=2)]
25 | [string]$Recipient,
26 | [Parameter(Mandatory=$true, Position=3)]
27 | [string]$ClientID,
28 | [Parameter(Mandatory=$true, Position=4)]
29 | [string]$ClientKey,
30 | [Parameter(Mandatory=$true, Position=5)]
31 | [string]$TenantID,
32 | [Parameter(Mandatory=$true, Position=6)]
33 | [string]$SenderEmail
34 | )
35 |
36 | $AADToken=getAuthHeader -ClientID $ClientID -ClientKey $ClientKey -TenantID $TenantID
37 | $Headers = @{Authorization = "Bearer $AADToken"}
38 |
39 | $message = @{
40 | "message" = @{
41 | "subject" = $Subject;
42 | "body" = @{
43 | "contentType" = "text";
44 | "content" = $Body;
45 | };
46 | "toRecipients" = @(
47 | @{
48 | "emailAddress" = @{
49 | "address" = $Recipient;
50 | };
51 | };
52 | );
53 | };
54 | "savedToSentItems" = "false"
55 | }
56 | $message.message.toRecipients
57 | $body = ConvertTo-Json $message -Depth 5
58 | $SendMail="https://graph.microsoft.com/v1.0/users/{0}/sendMail" -f [uri]::EscapeDataString($senderAccountName)
59 | $res = Invoke-WebRequest -Uri $SendMail -Method Post -Headers $Headers -Body $body -ContentType "application/json"
60 | }
61 |
62 | #variables
63 | $SenderAccountName = "[Sending Account Email]"
64 | $ClientID = "[Azure AD App Registration]"
65 | $ClientKey = "[App Registration Secret]"
66 | $TenantID = "[Azure AD Tenant ID]"
67 | $Recipient = "[Email Recipient]"
68 |
69 | #execute
70 | SendMessage `
71 | -Subject "Testing Encryption" `
72 | -Body "Sending this from Powershell via EXO, using a service principal with app permissions to send behalf of, and specifying an email account I created in my demo O365 subscription." `
73 | -Recipient $Recipient `
74 | -ClientID $ClientID `
75 | -ClientKey $ClientKey `
76 | -TenantID $TenantID `
77 | -SenderEmail $SenderAccountName
78 |
79 |
--------------------------------------------------------------------------------
/psh-poison-queue/README.md:
--------------------------------------------------------------------------------
1 | Azure Storage Queue will move a failed queue entry to the poison queue after a set number of failures.
2 | Once the failure is corrected, it may be useful to move the items from the poison queue back into the main queue.
3 | This PowerShell script uses the Azure Storage SDK to make this easy - useful while developing a solution.
--------------------------------------------------------------------------------
/psh-poison-queue/StorageQueueMovePoison.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Purpose: restore Azure Storage Queue messages from a poison queue back into a primary queue
3 | Date: 1/3/2019
4 | Author: Brett Hacker
5 | #>
6 |
7 | #Settings
8 | $connectionStr = "[Storage account connection string]"
9 | $destQueueName = "[queue name]"
10 | $srcQueueName = "$destQueueName-poison"
11 |
12 | #Path to the "Microsoft.WindowsAzure.Storage" dll (from NuGet)
13 | $storageLibPath = "[local-path-to]\Microsoft.WindowsAzure.Storage.dll"
14 |
15 | #Dot-sourced variable override (optional, comment out if not using)
16 | if (Test-Path "$($env:PSH_Settings_Files)StorageQueueMovePoison.ps1") {
17 | . "$($env:PSH_Settings_Files)StorageQueueMovePoison.ps1"
18 | }
19 |
20 | #do not alter below here
21 | [System.Reflection.Assembly]::LoadFrom($storageLibPath) | Out-Null
22 | $storageAccount = [Microsoft.WindowsAzure.Storage.CloudStorageAccount]::Parse($connectionStr);
23 | $client = $storageAccount.CreateCloudQueueClient();
24 | $sourceQ = $client.GetQueueReference($srcQueueName)
25 | $destQ = $client.GetQueueReference($destQueueName)
26 | $count = 0
27 | $toProcess = [int]$sourceQ.ApproximateMessageCount
28 | $donepercent = 0
29 |
30 | while ($true) {
31 | $srcMsg = $sourceQ.GetMessage()
32 | if ($srcMsg -eq $null) {
33 | break;
34 | }
35 | $destMsg = [Microsoft.WindowsAzure.Storage.Queue.CloudQueueMessage]::new($srcMsg.AsString)
36 | $destQ.AddMessage($destMsg)
37 | $sourceQ.DeleteMessage($srcMsg)
38 | $count++
39 | $donepercent = [int](($count / $toProcess) * 100)
40 | Write-Progress -Activity "Moving items..." -PercentComplete $donepercent -Status "$($donepercent)% complete ($count of $toProcess)" -ErrorAction Ignore
41 | }
42 | ""
43 | "$count messages restored"
--------------------------------------------------------------------------------
/psh-sql-update-firewall/UpdateAllSqlFirewall.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Reset all accessible Azure SQL server firewall to allow access from local IP address.
3 | An AAD SP is used here and needs at least 'SQL SECURITY MANAGER' role for the managed SQL server instance
4 | 7/19/2018, Brett Hacker
5 | #>
6 |
7 | #Settings
8 | $appid = "[SP AppID]"
9 | $appSecret = '[SP secret]'
10 | $tenantId = "[SP tenant]"
11 | #default rule name
12 | $defaultRuleName="[Name of your default rule, like 'HomeLab']"
13 |
14 | #dot-source local file to override variables above
15 | if (test-path 'C:\users\brhacke\OneDrive - Microsoft\Documents\WindowsPowerShell\UpdateAllSqlFirewall-mySettings.ps1') {
16 | . 'C:\users\brhacke\OneDrive - Microsoft\Documents\WindowsPowerShell\UpdateAllSqlFirewall-mySettings.ps1'
17 | }
18 |
19 | #-----------------------
20 | #authenticate SP
21 | $SecPw = ConvertTo-SecureString $appSecret -AsPlainText -Force -ErrorAction Stop
22 | $cred = New-Object PSCredential ($appid, $SecPw)
23 | Connect-AzureRmAccount -ServicePrincipal -Credential $cred -TenantId $tenantId
24 |
25 | #get list of subscriptions for this SP
26 | $subs = (Get-AzureRmSubscription).Name
27 |
28 | #Get current Local IP (free site I'm hosting)
29 | $web = New-Object Net.WebClient
30 | $MyIp = $web.DownloadString("http://pingip.azurewebsites.net/")
31 | $web.Dispose()
32 |
33 | #loop the subs
34 | foreach($sub in $subs) {
35 | Write-Output "Updating SQL Servers in $sub..."
36 |
37 | Set-AzureRMContext -Subscription "$sub"
38 | $servers = Get-AzureRmSqlServer
39 | foreach($server in $servers) {
40 | Write-Output "Updating $server..."
41 |
42 | $rules = Get-AzureRmSqlServerFirewallRule `
43 | -ResourceGroupName $server.ResourceGroupName `
44 | -ServerName $server.ServerName
45 |
46 | if (($rules | where { $_.FirewallRuleName -eq $defaultRuleName }).length -eq 0) {
47 | Write-Output "Adding $defaultRuleName rule..."
48 | New-AzureRmSqlServerFirewallRule `
49 | -EndIpAddress $MyIp `
50 | -FirewallRuleName $defaultRuleName `
51 | -ResourceGroupName $server.ResourceGroupName `
52 | -ServerName $server.ServerName `
53 | -StartIpAddress $MyIp
54 | } else {
55 | Write-Output "Updating $defaultRuleName rule..."
56 | Set-AzureRmSqlServerFirewallRule `
57 | -EndIpAddress $MyIp `
58 | -FirewallRuleName $defaultRuleName `
59 | -ResourceGroupName $server.ResourceGroupName `
60 | -ServerName $server.ServerName `
61 | -StartIpAddress $MyIp
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/psh-sql-update-firewall/readme.md:
--------------------------------------------------------------------------------
1 | My ISP has kept my home IP pretty stable until it reset it 3 times in the last month. I'd already written a script to check and update my S2S VPN gateway IP, but I kept getting knocked out of connections to Azure SQL. So I wrote this script and added a call to it from my other scheduled job. It gets the public IP from wherever you're running it, then uses a service principal that has rights to SQL servers - in one or more subscriptions in the same tenant - spins through each subscription, finds all SQL Servers, gets all firewall rules, checks to see if a matching rule exists and updates or creates it with the new IP address. Peachy!
2 |
--------------------------------------------------------------------------------
/sa-dsml-many-models/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 James Nguyen
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 |
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/aml_prs/Data_Preparation.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": null,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": []
9 | }
10 | ],
11 | "metadata": {
12 | "interpreter": {
13 | "hash": "f7f364c9551711cd4699acda32e0312c3edab483ae246bf330de758088cecccb"
14 | },
15 | "kernelspec": {
16 | "display_name": "Python 3.8.5 64-bit ('dlresearch': conda)",
17 | "name": "python3"
18 | },
19 | "language_info": {
20 | "name": "python",
21 | "version": ""
22 | },
23 | "orig_nbformat": 4
24 | },
25 | "nbformat": 4,
26 | "nbformat_minor": 2
27 | }
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/aml_prs/model_train.py:
--------------------------------------------------------------------------------
1 | # Licensed under the MIT license.
2 |
3 | import os
4 | from azureml.core import Run, Model
5 | import joblib
6 | from util.timeseries_utilities import ColumnDropper, SimpleLagger, SimpleCalendarFeaturizer, SimpleForecaster
7 | from sklearn.metrics import mean_squared_error, mean_absolute_error
8 | from sklearn.linear_model import LinearRegression
9 | import numpy as np
10 | import pandas as pd
11 | def init():
12 | global ws
13 | current_run = Run.get_context()
14 | ws = current_run.experiment.workspace
15 |
16 | print("Init complete")
17 |
18 |
19 | def run(mini_batch):
20 | print(f'run method start: {__file__}, run({mini_batch})')
21 | target_column= 'Quantity'
22 | timestamp_column= 'WeekStarting'
23 | drop_columns=['Revenue', 'Store', 'Brand']
24 | #Get the store and brand. They are unique from the group so just the first value is sufficient
25 | store = str(mini_batch['Store'].iloc[0])
26 | brand = str(mini_batch['Brand'].iloc[0])
27 |
28 | model_name="prs_"+store+"_"+brand
29 | test_size=20
30 | # 1.0 Format the input data from group by, put the time in the index
31 | data = mini_batch \
32 | .set_index('WeekStarting') \
33 | .sort_index(ascending=True)
34 |
35 | # 2.0 Split the data into train and test sets
36 | train = data[:-test_size]
37 | test = data[-test_size:]
38 |
39 | # 3.0 Create and fit the forecasting pipeline
40 | # The pipeline will drop unhelpful features, make a calendar feature, and make lag features
41 | lagger = SimpleLagger(target_column, lag_orders=[1, 2, 3, 4])
42 | transform_steps = [('column_dropper', ColumnDropper(drop_columns)),
43 | ('calendar_featurizer', SimpleCalendarFeaturizer()), ('lagger', lagger)]
44 | forecaster = SimpleForecaster(transform_steps, LinearRegression(), target_column, timestamp_column)
45 | forecaster.fit(train)
46 |
47 | # 4.0 Get predictions on test set
48 | forecasts = forecaster.forecast(test)
49 | compare_data = test.assign(forecasts=forecasts).dropna()
50 |
51 | # 5.0 Calculate accuracy metrics for the fit
52 | mse = mean_squared_error(compare_data[target_column], compare_data['forecasts'])
53 | rmse = np.sqrt(mse)
54 | mae = mean_absolute_error(compare_data[target_column], compare_data['forecasts'])
55 | actuals = compare_data[target_column].values
56 | preds = compare_data['forecasts'].values
57 | mape = np.mean(np.abs((actuals - preds) / actuals) * 100)
58 |
59 | # 7.0 Train model with full dataset
60 | forecaster.fit(data)
61 |
62 | # 8.0 Save the pipeline and register model to AML
63 | joblib.dump(forecaster, model_name)#
64 | model = Model.register(workspace=ws, model_name=model_name, model_path=model_name, tags={'mse':str(mse), 'mape': str(mape), 'rmse': str(rmse)})
65 | result =pd.DataFrame({'Store':[store],'Brand':[brand], 'mse':[mse], 'mape': [mape], 'rmse': [rmse], 'model_name':[model_name]})
66 |
67 | return result
68 |
69 |
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/aml_prs/prediction.py:
--------------------------------------------------------------------------------
1 | # Licensed under the MIT license.
2 |
3 | import os
4 | from azureml.core import Run, Model
5 | import joblib
6 | import util.timeseries_utilities
7 |
8 | def init():
9 | global ws
10 | current_run = Run.get_context()
11 | ws = current_run.experiment.workspace
12 |
13 | print("Init complete")
14 |
15 |
16 | def run(mini_batch):
17 | print(f'run method start: {__file__}, run({mini_batch})')
18 |
19 | timestamp_column= 'WeekStarting'
20 |
21 | timeseries_id_columns= [ 'Store', 'Brand']
22 | data = mini_batch \
23 | .set_index(timestamp_column) \
24 | .sort_index(ascending=True)
25 | #Prepare loading model from Azure ML, get the latest model by default
26 | model_name="prs_"+str(data['Store'].iloc[0])+"_"+str(data['Brand'].iloc[0])
27 | model = Model(ws, model_name)
28 | model.download(exist_ok =True)
29 | forecaster = joblib.load(model_name)
30 |
31 | # Get predictions
32 | #This is to append the store and brand column to the result
33 | ts_id_dict = {id_col: str(data[id_col].iloc[0]) for id_col in timeseries_id_columns}
34 | forecasts=forecaster.forecast(data)
35 | prediction_df = forecasts.to_frame(name='Prediction')
36 | prediction_df =prediction_df.reset_index().assign(**ts_id_dict)
37 |
38 |
39 | return prediction_df
40 |
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/1-sai-create-endpoint.yml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://azuremlsdk2.blob.core.windows.net/latest/managedOnlineEndpoint.schema.json
2 | name: my-sai-endpoint
3 | type: online
4 | auth_mode: key
5 | traffic:
6 | blue: 80
7 |
8 | deployments:
9 | #blue deployment
10 | - name: blue
11 | code_configuration:
12 | code:
13 | local_path: ../
14 | scoring_script: deployment/score.py
15 | environment:
16 | name: many_models_environment
17 | version: 2
18 | path: .
19 | conda_file: file:./conda.yml
20 | docker:
21 | image: mcr.microsoft.com/azureml/openmpi3.1.2-ubuntu18.04:20210301.v1
22 |
23 | instance_type: Standard_F2s_v2
24 | scale_settings:
25 | scale_type: manual
26 | instance_count: 1
27 | min_instances: 1
28 | max_instances: 2
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/azureml_cli.txt:
--------------------------------------------------------------------------------
1 |
2 | az account set --subscription 0e9bace8-7a81-4922-83b5-d995ff706507
3 | az configure --defaults workspace=ws01ent group=azureml
4 |
5 | set ENDPOINT_NAME=many_model
6 | set WORKSPACE=ws01ent
7 | set LOCATION=westus2
8 | set ENDPOINT_NAME=many-model-sal
9 | az ml endpoint create --name %ENDPOINT_NAME% -f 1-sai-create-endpoint.yml
10 |
11 | az ml endpoint show --name %ENDPOINT_NAME%
12 | SET system_identity=8c7f9ce7-3ca3-4c56-bbfc-1746e0409564
13 | az ml endpoint show --name %ENDPOINT_NAME% --query "identity.principal_id" -o tsv
14 | set WS_ID=/subscriptions/0e9bace8-7a81-4922-83b5-d995ff706507/resourceGroups/azureml/providers/Microsoft.MachineLearningServices/workspaces/ws01ent
15 | az role assignment create --assignee %system_identity% --role "Reader" --scope %WS_ID%
16 |
17 |
18 | az ml endpoint update -n %ENDPOINT_NAME% -f 1-sai-create-endpoint.yml
19 |
20 | #Creating a custom role
21 | az role definition update --role-definition custom_role.json --subscription 0e9bace8-7a81-4922-83b5-d995ff706507
22 |
23 | az role definition list --subscription 0e9bace8-7a81-4922-83b5-d995ff706507 --custom-role-only true
24 | az role assignment create --assignee %system_identity% --role "AML SAL" --scope %WS_ID%
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/conda.yml:
--------------------------------------------------------------------------------
1 | name: many_models_environment
2 | channels:
3 | - conda-forge
4 | dependencies:
5 | - python=3.7
6 | - numpy
7 | - pip
8 | - scikit-learn==0.24.2
9 | - pandas
10 | - pip:
11 | - azureml-defaults
12 | - inference-schema[numpy-support]
13 | - joblib
14 | - numpy
15 | - adal
16 |
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/custom_role.json:
--------------------------------------------------------------------------------
1 | {
2 | "Name": "AML SAL",
3 | "IsCustom": true,
4 | "Description": "Can obtain scoring token.",
5 | "Actions": [
6 |
7 | "Microsoft.MachineLearningServices/workspaces/onlineEndpoints/score/action",
8 | "Microsoft.MachineLearningServices/workspaces/onlineEndpoints/token/action",
9 | "Microsoft.MachineLearningServices/workspaces/onlineEndpoints/listkeys/action"
10 | ],
11 | "NotActions": [
12 | "Microsoft.MachineLearningServices/workspaces/*/delete",
13 | "Microsoft.MachineLearningServices/workspaces/write",
14 | "Microsoft.MachineLearningServices/workspaces/computes/*/write",
15 | "Microsoft.MachineLearningServices/workspaces/computes/*/delete",
16 | "Microsoft.Authorization/*/write"
17 |
18 | ],
19 | "AssignableScopes": [
20 | "/subscriptions/0e9bace8-7a81-4922-83b5-d995ff706507/resourceGroups/azureml",
21 | "/subscriptions/0e9bace8-7a81-4922-83b5-d995ff706507/resourceGroups/azureml/providers/Microsoft.MachineLearningServices/workspaces/ws01ent"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/main_deployment.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "source": [
6 | "Follow the steps in https://docs.microsoft.com/en-us/azure/machine-learning/how-to-deploy-managed-online-endpoints to deploy the scoring function to Azure.\r\n",
7 | "This scoring is on demand, i.e. it only loads the model when the client requests."
8 | ],
9 | "metadata": {}
10 | },
11 | {
12 | "cell_type": "code",
13 | "execution_count": 1,
14 | "source": [
15 | "import urllib.request\r\n",
16 | "import requests\r\n",
17 | "import pandas as pd\r\n",
18 | "import json\r\n",
19 | "for file_name in ['test_data_1000_dominicks.csv','test_data_1002_tropicana.csv']:\r\n",
20 | " sample_data= pd.read_csv(file_name)\r\n",
21 | " sample_data.drop(['Unnamed: 0'], axis=1, inplace=True)\r\n",
22 | " #Use the below version of URL and header in case you test with remote web service (AKS)\r\n",
23 | " url ='https://many-model.westus2.inference.ml.azure.com/score'\r\n",
24 | " api_key = 'K8It9Dq12BpQu8ryt6VRXZB1AmCzfsZu' # Replace this with the API key for the web service\r\n",
25 | " headers = {'Content-Type':'application/json', 'Authorization':('Bearer '+ api_key)}\r\n",
26 | "\r\n",
27 | "\r\n",
28 | "\r\n",
29 | " data = {\"Inputs\":sample_data.to_json() }\r\n",
30 | " body = str.encode(json.dumps(data))\r\n",
31 | " resp = requests.post(url, data=body, headers=headers)\r\n",
32 | " print(resp.text)\r\n"
33 | ],
34 | "outputs": [
35 | {
36 | "output_type": "stream",
37 | "name": "stderr",
38 | "text": [
39 | "C:\\Users\\janguy\\Anaconda3\\envs\\dlresearch\\lib\\site-packages\\numpy\\_distributor_init.py:30: UserWarning: loaded more than 1 DLL from .libs:\n",
40 | "C:\\Users\\janguy\\Anaconda3\\envs\\dlresearch\\lib\\site-packages\\numpy\\.libs\\libopenblas.NOIJJG62EMASZI6NYURL6JBKM4EVBGM7.gfortran-win_amd64.dll\n",
41 | "C:\\Users\\janguy\\Anaconda3\\envs\\dlresearch\\lib\\site-packages\\numpy\\.libs\\libopenblas.PYQHXLVVQ7VESDPUVUADXEVJOBGHJPAY.gfortran-win_amd64.dll\n",
42 | " warnings.warn(\"loaded more than 1 DLL from .libs:\\n%s\" %\n"
43 | ]
44 | },
45 | {
46 | "output_type": "stream",
47 | "name": "stdout",
48 | "text": [
49 | "key_auth_access_denied\n",
50 | "key_auth_access_denied\n"
51 | ]
52 | }
53 | ],
54 | "metadata": {}
55 | },
56 | {
57 | "cell_type": "code",
58 | "execution_count": null,
59 | "source": [],
60 | "outputs": [],
61 | "metadata": {}
62 | }
63 | ],
64 | "metadata": {
65 | "interpreter": {
66 | "hash": "f7f364c9551711cd4699acda32e0312c3edab483ae246bf330de758088cecccb"
67 | },
68 | "kernelspec": {
69 | "name": "python3",
70 | "display_name": "Python 3.8.5 64-bit ('dlresearch': conda)"
71 | },
72 | "language_info": {
73 | "codemirror_mode": {
74 | "name": "ipython",
75 | "version": 3
76 | },
77 | "file_extension": ".py",
78 | "mimetype": "text/x-python",
79 | "name": "python",
80 | "nbconvert_exporter": "python",
81 | "pygments_lexer": "ipython3",
82 | "version": "3.8.5"
83 | },
84 | "orig_nbformat": 4
85 | },
86 | "nbformat": 4,
87 | "nbformat_minor": 2
88 | }
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/many_model.yml:
--------------------------------------------------------------------------------
1 | $schema: https://azuremlsdk2.blob.core.windows.net/latest/managedOnlineEndpoint.schema.json
2 | name: my-endpoint
3 | type: online
4 | auth_mode: key
5 | traffic:
6 | blue: 80
7 | green:20
8 |
9 | deployments:
10 | #blue deployment
11 | - name: blue
12 | code_configuration:
13 | code:
14 | local_path: ../
15 | scoring_script: deployment/score.py
16 | environment:
17 | name: many_models_environment
18 | version: 2
19 | path: .
20 | conda_file: file:./conda.yml
21 | docker:
22 | image: mcr.microsoft.com/azureml/openmpi3.1.2-ubuntu18.04:20210301.v1
23 |
24 | instance_type: Standard_F2s_v2
25 | scale_settings:
26 | scale_type: manual
27 | instance_count: 1
28 | min_instances: 1
29 | max_instances: 2
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/prs_1000_dominicks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/sa-dsml-many-models/code/deployment/prs_1000_dominicks
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/test_data.csv:
--------------------------------------------------------------------------------
1 | ,WeekStarting,Store,Brand,Quantity,Advert,Price,Revenue
2 | 0,1990-06-14,1000,dominicks,12003,1,2.59,31087.769999999997
3 | 1,1990-06-21,1000,dominicks,10239,1,2.39,24471.210000000003
4 | 2,1990-06-28,1000,dominicks,17917,1,2.48,44434.159999999996
5 | 3,1990-07-05,1000,dominicks,14218,1,2.33,33127.94
6 | 4,1990-07-12,1000,dominicks,15925,1,2.01,32009.249999999996
7 | 5,1990-07-19,1000,dominicks,17850,1,2.17,38734.5
8 | 6,1990-07-26,1000,dominicks,10576,1,1.97,20834.72
9 | 7,1990-08-02,1000,dominicks,9912,1,2.26,22401.12
10 | 8,1990-08-09,1000,dominicks,9571,1,2.11,20194.809999999998
11 | 9,1990-08-16,1000,dominicks,15748,1,2.42,38110.159999999996
12 |
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/test_data_1000_dominicks.csv:
--------------------------------------------------------------------------------
1 | ,WeekStarting,Store,Brand,Quantity,Advert,Price,Revenue
2 | 0,1990-06-14,1000,dominicks,12003,1,2.59,31087.769999999997
3 | 1,1990-06-21,1000,dominicks,10239,1,2.39,24471.210000000003
4 | 2,1990-06-28,1000,dominicks,17917,1,2.48,44434.159999999996
5 | 3,1990-07-05,1000,dominicks,14218,1,2.33,33127.94
6 | 4,1990-07-12,1000,dominicks,15925,1,2.01,32009.249999999996
7 | 5,1990-07-19,1000,dominicks,17850,1,2.17,38734.5
8 | 6,1990-07-26,1000,dominicks,10576,1,1.97,20834.72
9 | 7,1990-08-02,1000,dominicks,9912,1,2.26,22401.12
10 | 8,1990-08-09,1000,dominicks,9571,1,2.11,20194.809999999998
11 | 9,1990-08-16,1000,dominicks,15748,1,2.42,38110.159999999996
12 |
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/test_data_1002_tropicana.csv:
--------------------------------------------------------------------------------
1 | ,WeekStarting,Store,Brand,Quantity,Advert,Price,Revenue
2 | 0,1991-01-24,1002,tropicana,9715,1,2.16,20984.4
3 | 1,1991-01-31,1002,tropicana,18991,1,2.27,43109.57
4 | 2,1991-02-07,1002,tropicana,13250,1,2.42,32065.0
5 | 3,1991-02-14,1002,tropicana,11520,1,2.6,29952.0
6 | 4,1991-02-21,1002,tropicana,16200,1,2.09,33858.0
7 | 5,1991-02-28,1002,tropicana,19683,1,2.63,51766.29
8 | 6,1991-03-07,1002,tropicana,11195,1,2.21,24740.95
9 | 7,1991-03-14,1002,tropicana,16313,1,2.38,38824.939999999995
10 | 8,1991-03-21,1002,tropicana,9924,1,2.55,25306.199999999997
11 | 9,1991-03-28,1002,tropicana,11892,1,2.19,26043.48
12 | 10,1991-04-04,1002,tropicana,9783,1,2.59,25337.969999999998
13 | 11,1991-04-11,1002,tropicana,14064,1,2.06,28971.84
14 | 12,1991-04-18,1002,tropicana,12070,1,2.36,28485.199999999997
15 | 13,1991-04-25,1002,tropicana,12416,1,2.08,25825.280000000002
16 | 14,1991-05-02,1002,tropicana,11680,1,2.03,23710.399999999998
17 | 15,1991-05-09,1002,tropicana,17474,1,2.25,39316.5
18 | 16,1991-05-16,1002,tropicana,19523,1,2.02,39436.46
19 | 17,1991-05-23,1002,tropicana,14042,1,2.16,30330.72
20 | 18,1991-05-30,1002,tropicana,13203,1,2.6,34327.8
21 | 19,1991-06-06,1002,tropicana,13242,1,1.94,25689.48
22 |
--------------------------------------------------------------------------------
/sa-dsml-many-models/code/deployment/test_deployment.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 159,
6 | "metadata": {},
7 | "outputs": [
8 | {
9 | "name": "stdout",
10 | "output_type": "stream",
11 | "text": [
12 | "upstream connect error or disconnect/reset before headers. reset reason: connection failure\n"
13 | ]
14 | }
15 | ],
16 | "source": [
17 | "import urllib.request\r\n",
18 | "import requests\r\n",
19 | "import pandas as pd\r\n",
20 | "import json\r\n",
21 | "for file_name in ['test_data_1000_dominicks.csv','test_data_1002_tropicana.csv']:\r\n",
22 | " sample_data= pd.read_csv(file_name)\r\n",
23 | " sample_data.drop(['Unnamed: 0'], axis=1, inplace=True)\r\n",
24 | " #Use the below version of URL and header in case you test with remote web service (AKS)\r\n",
25 | " url ='https://many-model2.westus2.inference.ml.azure.com/score'\r\n",
26 | " api_key = '9Qnjp0tSwMUrFJtMk4q8fqbDprq9fUsv' # Replace this with the API key for the web service\r\n",
27 | " headers = {'Content-Type':'application/json', 'Authorization':('Bearer '+ api_key)}\r\n",
28 | "\r\n",
29 | "\r\n",
30 | "\r\n",
31 | " data = {\"Inputs\":sample_data.to_json() }\r\n",
32 | " body = str.encode(json.dumps(data))\r\n",
33 | " resp = requests.post(url, data=body, headers=headers)\r\n",
34 | " print(resp.text)\r\n"
35 | ]
36 | },
37 | {
38 | "cell_type": "code",
39 | "execution_count": null,
40 | "metadata": {},
41 | "outputs": [],
42 | "source": []
43 | }
44 | ],
45 | "metadata": {
46 | "interpreter": {
47 | "hash": "01395c2bf5351d89929a188eaee14092f5abeb2f2ed0be057aa3ed6e35212c40"
48 | },
49 | "kernelspec": {
50 | "display_name": "Python 3.6.12 64-bit ('mlflow-1a43b1fcadd2a32c00a1972c5464ff374bda3f6b': conda)",
51 | "name": "python3"
52 | },
53 | "language_info": {
54 | "codemirror_mode": {
55 | "name": "ipython",
56 | "version": 3
57 | },
58 | "file_extension": ".py",
59 | "mimetype": "text/x-python",
60 | "name": "python",
61 | "nbconvert_exporter": "python",
62 | "pygments_lexer": "ipython3",
63 | "version": "3.8.5"
64 | },
65 | "orig_nbformat": 4
66 | },
67 | "nbformat": 4,
68 | "nbformat_minor": 2
69 | }
--------------------------------------------------------------------------------
/sa-dsml-many-models/images/aml_many_models_arch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/sa-dsml-many-models/images/aml_many_models_arch.png
--------------------------------------------------------------------------------
/sa-dsml-many-models/images/pandas_udf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/sa-dsml-many-models/images/pandas_udf.png
--------------------------------------------------------------------------------
/sa-dsml-many-models/images/spark_many_models_arch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/sa-dsml-many-models/images/spark_many_models_arch.png
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/AzurePolicy/audit/Audit-Managed-Disks.json:
--------------------------------------------------------------------------------
1 | {
2 | "policyRule": {
3 | "if": {
4 | "anyOf": [
5 | {
6 | "allOf": [
7 | {
8 | "field": "type",
9 | "equals": "Microsoft.Compute/virtualMachines"
10 | },
11 | {
12 | "field": "Microsoft.Compute/virtualMachines/osDisk.uri",
13 | "exists": true
14 | }
15 | ]
16 | },
17 | {
18 | "allOf": [
19 | {
20 | "field": "type",
21 | "equals": "Microsoft.Compute/VirtualMachineScaleSets"
22 | },
23 | {
24 | "anyOf": [
25 | {
26 | "field": "Microsoft.Compute/VirtualMachineScaleSets/osDisk.vhdContainers",
27 | "exists": true
28 | },
29 | {
30 | "field": "Microsoft.Compute/VirtualMachineScaleSets/osdisk.imageUrl",
31 | "exists": true
32 | }
33 | ]
34 | }
35 | ]
36 | }
37 | ]
38 | },
39 | "then": {
40 | "effect": "audit"
41 | }
42 | },
43 | "parameters": {},
44 | "metadata": {
45 | "category": "Compute"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/AzurePolicy/audit/Audit-PublicIP.json:
--------------------------------------------------------------------------------
1 | {
2 | "policyRule": {
3 | "if": {
4 | "anyOf": [
5 | {
6 | "source": "action",
7 | "like": "Microsoft.Network/PublicIPAddresses/*"
8 | }
9 | ]
10 | },
11 | "then": {
12 | "effect": "audit"
13 | }
14 | },
15 | "parameters": {},
16 | "metadata": {
17 | "category": "Network"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/AzurePolicy/audit/Audit-Resource-Tag.json:
--------------------------------------------------------------------------------
1 | {
2 | "if": {
3 | "not": {
4 | "field": "tags",
5 | "containsKey": "costCenter"
6 | }
7 | },
8 | "then": {
9 | "effect": "audit"
10 | }
11 | }
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/AzurePolicy/deny/Allowed-Locations.json:
--------------------------------------------------------------------------------
1 | {
2 | "policyRule": {
3 | "if": {
4 | "not": {
5 | "field": "location",
6 | "in": [
7 | "eastus",
8 | "eastus2",
9 | "westus",
10 | "westus2",
11 | "westeurope"
12 | ]
13 | }
14 | },
15 | "then": {
16 | "effect": "deny"
17 | }
18 | },
19 | "parameters": {},
20 | "metadata": {
21 | "category": "Build"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/AzurePolicy/deny/Prevent-Unmanaged-Disk-Creation.json:
--------------------------------------------------------------------------------
1 | {
2 | "policyRule": {
3 | "if": {
4 | "anyOf": [
5 | {
6 | "allOf": [
7 | {
8 | "field": "type",
9 | "equals": "Microsoft.Compute/virtualMachines"
10 | },
11 | {
12 | "field": "Microsoft.Compute/virtualMachines/osDisk.uri",
13 | "exists": true
14 | }
15 | ]
16 | },
17 | {
18 | "allOf": [
19 | {
20 | "field": "type",
21 | "equals": "Microsoft.Compute/VirtualMachineScaleSets"
22 | },
23 | {
24 | "anyOf": [
25 | {
26 | "field": "Microsoft.Compute/VirtualMachineScaleSets/osDisk.vhdContainers",
27 | "exists": true
28 | },
29 | {
30 | "field": "Microsoft.Compute/VirtualMachineScaleSets/osdisk.imageUrl",
31 | "exists": true
32 | }
33 | ]
34 | }
35 | ]
36 | }
37 | ]
38 | },
39 | "then": {
40 | "effect": "deny"
41 | }
42 | },
43 | "parameters": {},
44 | "metadata": {
45 | "category": "Compute"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/AzurePolicy/deny/denyPIP.json:
--------------------------------------------------------------------------------
1 | "policyRule": {
2 | "if": {
3 | "allOf": [
4 | {
5 | "field": "type",
6 | "equals": "Microsoft.Network/networkInterfaces"
7 | },
8 | {
9 | "field": "Microsoft.Network/networkInterfaces/ipconfigurations[*].publicIpAddress.id",
10 | "exists": true
11 | }
12 | ]
13 | },
14 | "then": {
15 | "effect": "deny"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/JsonExamples/businessAnalysts.json:
--------------------------------------------------------------------------------
1 | {
2 | "Name": "Business Analysts",
3 | "IsCustom": true,
4 | "Description": "Allows for a number of read operations + a few operations roles that allow business analysts to perform job duties.",
5 | "Actions": [
6 | "Microsoft.Resources/subscriptions/resourceGroups/read",
7 | "Microsoft.Storage/storageAccounts/read",
8 | "Microsoft.Network/virtualNetworks/read",
9 | "Microsoft.ResourceHealth/availabilityStatuses/read",
10 | "Microsoft.Network/virtualNetworks/subnets/read",
11 | "Microsoft.Resources/subscriptions/resourceGroups/read",
12 | "Microsoft.resources/deployments/*",
13 | "Microsoft.Compute/*/read",
14 | "Microsoft.Compute/virtualMachines/restart/action",
15 | "Microsoft.Compute/virtualMachineScaleSets/restart/action",
16 | "Microsoft.Compute/virtualMachineScaleSets/virtualMachines/restart/action",
17 | "Microsoft.Sql/*/read"
18 | ],
19 | "NotActions": [
20 |
21 | ],
22 | "DataActions": [
23 |
24 | ],
25 | "NotDataActions": [
26 |
27 | ],
28 | "AssignableScopes": [
29 | "/subscriptions/00000000-0000-0000-0000-000000000000"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/JsonExamples/cloudDevelopers.json:
--------------------------------------------------------------------------------
1 | {
2 | "Name": "Cloud Developers",
3 | "IsCustom": true,
4 | "Description": "Allows for developer permissions within an Azure environment.",
5 | "Actions": [
6 | "Microsoft.Resources/subscriptions/resourceGroups/write",
7 | "Microsoft.Resources/subscriptions/resourceGroups/read",
8 | "Microsoft.Storage/storageaccounts/write",
9 | "Microsoft.Storage/storageAccounts/read",
10 | "Microsoft.Network/virtualNetworks/read",
11 | "Microsoft.Network/virtualNetworks/subnets/read",
12 | "Microsoft.Network/virtualNetworks/subnets/join/action",
13 | "Microsoft.Network/networkInterfaces/*",
14 | "Microsoft.resources/deployments/*",
15 | "Microsoft.Compute/*",
16 | "Microsoft.Sql/*",
17 | "Microsoft.Web/sites/*",
18 | "Microsoft.Insights/*"
19 | ],
20 | "NotActions": [
21 |
22 | ],
23 | "DataActions": [
24 |
25 | ],
26 | "NotDataActions": [
27 |
28 | ],
29 | "AssignableScopes": [
30 | "/subscriptions/00000000-0000-0000-0000-000000000000"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/JsonExamples/cloudOpsAdmins.json:
--------------------------------------------------------------------------------
1 | {
2 | "Name": "Cloud Ops Administrators",
3 | "IsCustom": true,
4 | "Description": "Allows for administrator permissions within an Azure environment.",
5 | "Actions": [
6 | "Microsoft.Resources/subscriptions/resourceGroups/write",
7 | "Microsoft.Resources/subscriptions/resourceGroups/read",
8 | "Microsoft.Storage/storageaccounts/write",
9 | "Microsoft.Storage/storageAccounts/read",
10 | "Microsoft.Network/virtualNetworks/read",
11 | "Microsoft.Network/virtualNetworks/subnets/read",
12 | "Microsoft.Network/virtualNetworks/subnets/join/action",
13 | "Microsoft.Network/networkInterfaces/*",
14 | "Microsoft.resources/deployments/*",
15 | "Microsoft.Compute/*",
16 | "Microsoft.Sql/*"
17 | ],
18 | "NotActions": [
19 |
20 | ],
21 | "DataActions": [
22 |
23 | ],
24 | "NotDataActions": [
25 |
26 | ],
27 | "AssignableScopes": [
28 | "/subscriptions/00000000-0000-0000-0000-000000000000"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/JsonExamples/cloudOpsEngLead.json:
--------------------------------------------------------------------------------
1 | {
2 | "Name": "Cloud Ops Engineering Lead",
3 | "IsCustom": true,
4 | "Description": "Allows for a lot of control over Azure environments. Does not allow ability to delete or create virtual networks",
5 | "Actions": [
6 | "*"
7 | ],
8 | "NotActions": [
9 | "Microsoft.Network/*/delete",
10 | "Microsoft.Network/*/write"
11 | ],
12 | "DataActions": [
13 |
14 | ],
15 | "NotDataActions": [
16 |
17 | ],
18 | "AssignableScopes": [
19 | "/subscriptions/00000000-0000-0000-0000-000000000000"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/JsonExamples/digitalSecurity.json:
--------------------------------------------------------------------------------
1 | {
2 | "Name": "Digital Security",
3 | "IsCustom": true,
4 | "Description": "Allows for security engineering functions related to Azure environments.",
5 | "Actions": [
6 | "*/read",
7 | "Microsoft.Resources/subscriptions/resourceGroups/write",
8 | "Microsoft.Storage/storageaccounts/write",
9 | "Microsoft.resources/deployments/*",
10 | "Microsoft.EventHub/namespaces/eventhubs/*"
11 | ],
12 | "NotActions": [
13 |
14 | ],
15 | "DataActions": [
16 |
17 | ],
18 | "NotDataActions": [
19 |
20 | ],
21 | "AssignableScopes": [
22 | "/subscriptions/00000000-0000-0000-0000-000000000000"
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/JsonExamples/networkAdmins.json:
--------------------------------------------------------------------------------
1 | {
2 | "Name": "Network Administrators",
3 | "IsCustom": true,
4 | "Description": "Allows for networking functions related to Azure environments.",
5 | "Actions": [
6 | "*/read",
7 | "Microsoft.Network/*",
8 | "Microsoft.Resources/subscriptions/resourceGroups/write",
9 | "Microsoft.Storage/storageaccounts/write",
10 | "Microsoft.Storage/storageAccounts/read",
11 | "Microsoft.resources/deployments/*"
12 | ],
13 | "NotActions": [
14 |
15 | ],
16 | "DataActions": [
17 |
18 | ],
19 | "NotDataActions": [
20 |
21 | ],
22 | "AssignableScopes": [
23 | "/subscriptions/00000000-0000-0000-0000-000000000000"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/JsonExamples/suppReaderTickets.json:
--------------------------------------------------------------------------------
1 | {
2 | "Name": "Reader Support Tickets",
3 | "IsCustom": true,
4 | "Description": "View everything in the subscription and also open support tickets.",
5 | "Actions": [
6 | "*/read",
7 | "Microsoft.Support/*"
8 | ],
9 | "NotActions": [],
10 | "DataActions": [],
11 | "NotDataActions": [],
12 | "AssignableScopes": [
13 | "/subscriptions/00000000-0000-0000-0000-000000000000"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShell/AzResourceProviderOperations.ps1:
--------------------------------------------------------------------------------
1 | # Exports a list of all Azure Provider Operations to a CSV file.
2 | Get-AzResourceProviderOperation -OperationSearchString * | Select Operation,OperationName,ProviderNamespace,Description `
3 | | Export-Csv c:\Scripts\CustomRBAC\resourceprovideractions.csv -nti
4 |
5 | # Working examples to drill deeper into specific provider namespaces.
6 | Get-AzResourceProvider | Select ProviderNameSpace | Export-Csv C:\Scripts\CustomRBAC\ResourceProviders.csv -nti
7 |
8 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.Automation/* `
9 | | Select Operation,OperationName,Description | Export-Csv C:\Scripts\CustomRBAC\Automation.csv -nti
10 |
11 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.Compute/* `
12 | | Select Operation,OperationName,Description | Export-Csv C:\Scripts\CustomRBAC\Compute.csv -nti
13 |
14 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.HDInsight/* `
15 | | Select Operation,OperationName,Description | Export-Csv CC:\Scripts\CustomRBAC\HDInsight.csv -nti
16 |
17 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.insights/* `
18 | | Select Operation,OperationName,Description | Export-Csv C:\Scripts\CustomRBAC\insights.csv -nti
19 |
20 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.Network/* `
21 | | Select Operation,OperationName,Description | Export-Csv C:\Scripts\CustomRBAC\Network.csv -nti
22 |
23 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.OperationalInsights/* `
24 | | Select Operation,OperationName,Description | Export-Csv C:\Scripts\CustomRBAC\OpsInsights.csv -nti
25 |
26 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.OperationsManagement/* `
27 | | Select Operation,OperationName,Description | Export-Csv CC:\Scripts\CustomRBAC\OpsMgmt.csv -nti
28 |
29 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.Sql/* `
30 | | Select Operation,OperationName,Description | Export-Csv C:\Scripts\CustomRBAC\SQL.csv -nti
31 |
32 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.Storage/* `
33 | | Select Operation,OperationName.Description | Export-Csv C:\Scripts\CustomRBAC\Storage.csv -nti
34 |
35 | Get-AzResourceProviderOperation -OperationSearchString Microsoft.Resources/* `
36 | | Select Operation,OperationName,Description | Export-Csv C:\Scripts\CustomRBAC\Resources.csv -nti
37 |
38 | Get-AzResourceProviderOperation -OperationSearchString '*' | ? { $_.Operation -like 'Microsoft.Network/*' } `
39 | | select Operation,OperationName,Description | Out-File azure-network-permissions.txt
40 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShell/Built-InRoles.ps1:
--------------------------------------------------------------------------------
1 | # Grabs all Azure Resource Manager builtin role definitions, selects the name + description, then exports the results as a csv.
2 | Get-AzRoleDefinition | Select-Object Name, Description | Export-Csv c:\Scripts\allArmRoles.csv -NTI
3 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShell/CustomRoleAssignment.ps1:
--------------------------------------------------------------------------------
1 | # Retrieve the role definition for the "Virtual Machine Contributor" built-in role
2 | $role = Get-AzRoleDefinition "Virtual Machine Contributor"
3 | # Set the role Id to null as this will be automatically generated when creating a custom role
4 | $role.Id = $null
5 | # Give the role a name and description
6 | $role.Name = "Limited VM Operator"
7 | $role.Description = "Users can monitor, stop, deallocate, and restart virtual machines."
8 | # Remove all actions in this case as we want to start fresh
9 | # If you wanted to grant the default permissions for this role and add new permissions, this step can be skipped.
10 | $role.Actions.Clear()
11 |
12 | $role.Actions.Add("Microsoft.Authorization/*/read")
13 | $role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/read")
14 | $role.Actions.Add("Microsoft.Compute/*/read")
15 | $role.Actions.Add("Microsoft.Compute/virtualMachines/start/action")
16 | $role.Actions.Add("Microsoft.Compute/virtualMachines/restart/action")
17 | $role.Actions.Add("Microsoft.Compute/virtualMachines/powerOff/action")
18 | $role.Actions.Add("Microsoft.Compute/virtualMachines/deallocate/action")
19 | $role.Actions.Add("Microsoft.Network/networkInterfaces/read")
20 | $role.Actions.Add("Microsoft.Compute/disks/read")
21 | $role.Actions.Add("Microsoft.Insights/alertRules/read")
22 | $role.Actions.Add("Microsoft.Insights/diagnosticSettings/read")
23 |
24 | # Clear the scopes that this applies to
25 | $role.AssignableScopes.Clear()
26 | # Apply it to a specific resource group, note you would need to replace with the actual subscription id
27 | $role.AssignableScopes.Add("/subscriptions/subscriptions/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx/resourceGroups/MyResourceGroup")
28 |
29 | New-AzRoleDefinition -Role $role
30 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShell/New-AzureRmDef-w-JSON.ps1:
--------------------------------------------------------------------------------
1 | # Creates a new Azure Resource Manager custom role based upon an input file.
2 | New-AzRoleDefinition -InputFile C:\Users\flore\Desktop\CustomRole.json
3 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShell/RoleTemplate.ps1:
--------------------------------------------------------------------------------
1 | # Provides a baseline template to work off with an existing builtin role for the custom role.
2 | Get-AzRoleDefinition -Name "Network Contributor" | ConvertTo-Json | Out-File "C:\ScriptOutputs\NetworkContributor.json"
3 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShellRoleExamples/RBACBASA.ps1:
--------------------------------------------------------------------------------
1 | $ADGroup = "Business Analysts"
2 | $ADGroupSearch = Get-AzADGroup -SearchString $ADGroup
3 |
4 | #Scope should be subscription ID in the form of "subscriptions/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" :
5 | #Can only add one subscription in this form
6 |
7 | $scope = ""
8 |
9 | $role = Get-AzRoleDefinition "Reader"
10 | $role.id = $null
11 | $role.name = "BA SA"
12 | $role.Description = "Business Analyst Role"
13 | $role.Actions.Clear()
14 | $role.NotActions.Clear()
15 | $role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/read")
16 | $role.Actions.Add("Microsoft.Storage/storageAccounts/read")
17 | $role.Actions.Add("Microsoft.Network/virtualNetworks/read")
18 | $role.Actions.Add("Microsoft.Network/virtualNetworks/subnets/read")
19 | $role.Actions.Add("Microsoft.resources/deployments/*")
20 | $role.Actions.Add("Microsoft.Compute/*/read")
21 | $role.Actions.Add("Microsoft.Compute/virtualMachines/restart/action")
22 | $role.Actions.Add("Microsoft.Compute/virtualMachineScaleSets/restart/action")
23 | $role.Actions.Add("Microsoft.Compute/virtualMachineScaleSets/virtualMachines/restart/action")
24 | $role.Actions.Add("Microsoft.Sql/*/read")
25 | $role.AssignableScopes.Clear()
26 | $role.AssignableScopes.Add($scope)
27 |
28 | New-AzRoleDefinition -Role $role
29 |
30 | New-AzRoleAssignment -ObjectId $ADGroupSearch.Id.Guid -RoleDefinitionName $role.name -Scope $scope
31 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShellRoleExamples/RBACCloudOpsLead.ps1:
--------------------------------------------------------------------------------
1 | $ADGroup = "Engineering"
2 | $ADGroupSearch = Get-AzureRmADGroup -SearchString $ADGroup
3 |
4 | #Scope should be subscription ID in the form of "subscriptions/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" :
5 | #Can only add one subscription in this form
6 |
7 | $scope = ""
8 |
9 | $role = Get-AzRoleDefinition "Reader"
10 | $role.id = $null
11 | $role.name = "CloudOps Lead"
12 | $role.Description = "Cloud Engineering Lead"
13 | $role.Actions.Clear()
14 | $role.NotActions.Clear()
15 | $role.Actions.Add("*")
16 | $role.NotActions.Add("Microsoft.Network/*/delete")
17 | $role.NotActions.Add("Microsoft.Network/*/write")
18 | $role.AssignableScopes.Clear()
19 | $role.AssignableScopes.Add($scope)
20 |
21 | New-AzureRmRoleDefinition -Role $role
22 |
23 | New-AzureRmRoleAssignment -ObjectId $ADGroupSearch.Id.Guid -RoleDefinitionName $role.name -Scope $scope
24 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShellRoleExamples/RBACCloudOpsNonLead.ps1:
--------------------------------------------------------------------------------
1 | $ADGroup = "Administrators"
2 | $ADGroupSearch = Get-AzADGroup -SearchString $ADGroup
3 |
4 | #Scope should be subscription ID in form of "subscriptions/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" :
5 | #Can only add one subscription in this form
6 |
7 | $scope = ""
8 |
9 | $role = Get-AzRoleDefinition "Reader"
10 | $role.id = $null
11 | $role.name = "CloudOps Administrators"
12 | $role.Description = "Cloud Administrators"
13 | $role.Actions.Clear()
14 | $role.NotActions.Clear()
15 | $role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/write")
16 | $role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/read")
17 | $role.Actions.Add("Microsoft.Storage/storageaccounts/write")
18 | $role.Actions.Add("Microsoft.Storage/storageAccounts/read")
19 | $role.Actions.Add("Microsoft.Network/virtualNetworks/read")
20 | $role.Actions.Add("Microsoft.Network/virtualNetworks/subnets/read")
21 | $role.Actions.Add("Microsoft.Network/virtualNetworks/subnets/join/action")
22 | $role.Actions.Add("Microsoft.Network/networkInterfaces/*")
23 | $role.Actions.Add("Microsoft.resources/deployments/*")
24 | $role.Actions.Add("Microsoft.Compute/*")
25 | $role.Actions.Add("Microsoft.Sql/*")
26 | $role.AssignableScopes.Clear()
27 | $role.AssignableScopes.Add($scope)
28 |
29 | New-AzRoleDefinition -Role $role
30 |
31 | New-AzRoleAssignment -ObjectId $ADGroupSearch.Id.Guid -RoleDefinitionName $role.name -Scope $scope
32 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShellRoleExamples/RBACDeveloper.ps1:
--------------------------------------------------------------------------------
1 | $ADGroup = "Developers"
2 | $ADGroupSearch = Get-AzADGroup -SearchString $ADGroup
3 |
4 | #Scope should be subscription ID in form of "subscriptions/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" :
5 | #Can only add one subscription in this form
6 |
7 | $scope = ""
8 |
9 | $role = Get-AzRoleDefinition "Reader"
10 | $role.id = $null
11 | $role.name = "Developer"
12 | $role.Description = "Cloud Developer Role"
13 | $role.Actions.Clear()
14 | $role.NotActions.Clear()
15 | $role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/write")
16 | $role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/read")
17 | $role.Actions.Add("Microsoft.Storage/storageaccounts/write")
18 | $role.Actions.Add("Microsoft.Storage/storageAccounts/read")
19 | $role.Actions.Add("Microsoft.Network/virtualNetworks/read")
20 | $role.Actions.Add("Microsoft.Network/virtualNetworks/subnets/read")
21 | $role.Actions.Add("Microsoft.Network/virtualNetworks/subnets/join/action")
22 | $role.Actions.Add("Microsoft.Network/networkInterfaces/*")
23 | $role.Actions.Add("Microsoft.resources/deployments/*")
24 | $role.Actions.Add("Microsoft.Compute/*")
25 | $role.Actions.Add("Microsoft.Sql/*")
26 | $role.Actions.Add("Microsoft.Web/sites/*")
27 | $role.Actions.Add("Microsoft.Insights/*")
28 | $role.AssignableScopes.Clear()
29 | $role.AssignableScopes.Add($scope)
30 |
31 | New-AzRoleDefinition -Role $role
32 |
33 | New-AzRoleAssignment -ObjectId $ADGroupSearch.Id.Guid -RoleDefinitionName $role.name -Scope $scope
34 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShellRoleExamples/RBACDigitalSecurity.ps1:
--------------------------------------------------------------------------------
1 | $ADGroup = "Digital Security"
2 | $ADGroupSearch = Get-AzADGroup -SearchString $ADGroup
3 |
4 | #Scope should be subscription ID in form of "subscriptions/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" :
5 | #Can only add one subscription in this form
6 |
7 | $scope = ""
8 |
9 | $role = Get-AzRoleDefinition "Reader"
10 | $role.id = $null
11 | $role.name = "Digital Security"
12 | $role.Description = "Digital Security Role"
13 | $role.Actions.Clear()
14 | $role.NotActions.Clear()
15 | $role.Actions.Add("*/read")
16 | $role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/write")
17 | $role.Actions.Add("Microsoft.Storage/storageaccounts/write")
18 | $role.Actions.Add("Microsoft.resources/deployments/*")
19 | $role.Actions.Add("Microsoft.EventHub/namespaces/eventhubs/*")
20 | $role.AssignableScopes.Clear()
21 | $role.AssignableScopes.Add($scope)
22 |
23 | New-AzRoleDefinition -Role $role
24 |
25 | New-AzRoleAssignment -ObjectId $ADGroupSearch.Id.Guid -RoleDefinitionName $role.name -Scope $scope
26 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShellRoleExamples/RBACNetworking.ps1:
--------------------------------------------------------------------------------
1 | $ADGroup = "NetworkAdmins"
2 | $ADGroupSearch = Get-AzADGroup -SearchString $ADGroup
3 |
4 | #Scope should be subscription ID in form of "subscriptions/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx" :
5 | #Can only add one subscription in this form
6 |
7 | $scope = ""
8 |
9 | $role = Get-AzRoleDefinition "Reader"
10 | $role.id = $null
11 | $role.name = "NetworkingTest"
12 | $role.Description = "Networking Role"
13 | $role.Actions.Clear()
14 | $role.NotActions.Clear()
15 | $role.Actions.Add("*/read")
16 | $role.Actions.Add("Microsoft.Network/*")
17 | $role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/write")
18 | $role.Actions.Add("Microsoft.Storage/storageaccounts/write")
19 | $role.Actions.Add("Microsoft.Storage/storageAccounts/read")
20 | $role.Actions.Add("Microsoft.resources/deployments/*")
21 | $role.AssignableScopes.Clear()
22 | $role.AssignableScopes.Add($scope)
23 |
24 | New-AzRoleDefinition -Role $role
25 |
26 | New-AzRoleAssignment -ObjectId $ADGroupSearch.Id.Guid -RoleDefinitionName $role.name -Scope $scope
27 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/CustomRBAC/PowerShellRoleExamples/README.md:
--------------------------------------------------------------------------------
1 | # PowerShell Role Examples:
2 | These provide PoSH role templates to use for custom RBAC assignments in Azure.
3 |
--------------------------------------------------------------------------------
/sample-AzGuardRails-Governance/README.md:
--------------------------------------------------------------------------------
1 | # AzGuardRails
2 |
3 | Azure Policy, PowerShell, and JSON Examples of guard rails for Azure environments.
4 |
5 | © 2019 Microsoft Corporation.
6 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
7 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
8 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
9 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
10 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
11 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
12 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
13 | documentation, even if Microsoft has been advised of the possibility of such damages.
14 |
--------------------------------------------------------------------------------
/sample-EasyAuth-ClassicASP/EasyAuthClassicASP/default.asp:
--------------------------------------------------------------------------------
1 | <% @ language="VBScript" %>
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Classic ASP Auth Test
10 |
11 |
24 |
25 |
26 |
57 |
58 |
Session:
59 |
60 | <%For Each X in Session.Contents%>
61 |
62 | <%=X%>
63 | <%=Session.Contents(x)%>
64 |
65 | <%Next%>
66 |
67 |
68 | <% 'WriteServerVariables() %>
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/sample-EasyAuth-ClassicASP/EasyAuthClassicASP/dockerfile:
--------------------------------------------------------------------------------
1 | # escape=`
2 |
3 | FROM mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
4 | SHELL ["powershell", "-command"]
5 |
6 | RUN Install-WindowsFeature Web-ASP; `
7 | Install-WindowsFeature Web-CGI; `
8 | Install-WindowsFeature Web-ISAPI-Ext; `
9 | Install-WindowsFeature Web-ISAPI-Filter; `
10 | Install-WindowsFeature Web-Includes; `
11 | Install-WindowsFeature Web-HTTP-Errors; `
12 | Install-WindowsFeature Web-Common-HTTP; `
13 | Install-WindowsFeature Web-Performance; `
14 | Install-WindowsFeature WAS; `
15 | Import-module IISAdministration;
16 |
17 | RUN md c:/msi;
18 |
19 | RUN Invoke-WebRequest 'https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi' -OutFile c:/msi/urlrewrite2.msi; `
20 | Start-Process 'c:/msi/urlrewrite2.msi' '/qn' -PassThru | Wait-Process;
21 |
22 | EXPOSE 80
23 |
24 | RUN Remove-Website -Name 'Default Web Site'; `
25 | md c:\mywebsite; `
26 | New-IISSite -Name "mywebsite" `
27 | -PhysicalPath 'c:\mywebsite' `
28 | -BindingInformation "*:80:";
29 |
30 | RUN & c:\windows\system32\inetsrv\appcmd.exe `
31 | unlock config `
32 | /section:system.webServer/asp
33 |
34 | RUN & c:\windows\system32\inetsrv\appcmd.exe `
35 | unlock config `
36 | /section:system.webServer/handlers
37 |
38 | RUN & c:\windows\system32\inetsrv\appcmd.exe `
39 | unlock config `
40 | /section:system.webServer/modules
41 |
42 |
43 | ADD . c:\mywebsite
--------------------------------------------------------------------------------
/sample-EasyAuth-ClassicASP/EasyAuthClassicASP/global.asa:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/sample-EasyAuth-ClassicASP/EasyAuthClassicASP/web.config:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/sample-EasyAuth-ClassicASP/README.md:
--------------------------------------------------------------------------------
1 | ## Easy Auth for Classic ASP
2 |
3 | This is a hacked-up PoC showing how Classic ASP can take advantage of the Easy Auth feature of Azure App Services.
4 | Easy Auth makes the id_token from Azure AD available in a header after authentication; this parses the token
5 | (App Services will have already validated it and logged you in), and sets the claims in session state.
6 |
7 | If you are interested in deploying this in a Windows Container in App Service, a dockerfile is also
8 | available in the solution directory.
9 |
10 | ## Contributing
11 |
12 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
13 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
14 | the rights to use your contribution. For details, visit https://cla.microsoft.com.
15 |
16 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
17 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
18 | provided by the bot. You will only need to do this once across all repos using our CLA.
19 |
20 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
21 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
22 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
23 |
--------------------------------------------------------------------------------
/sample-Python-KeyVault-Function/README.md:
--------------------------------------------------------------------------------
1 | A simple example - accessing Key Vault from a [python http triggered function](https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-python). Originally wanted to do this with MSI, but sadly, [no MSI support just yet](https://github.com/Azure/Azure-Functions/issues/1066). When MSI is available it should look something like [this](https://github.com/Microsoft/csa-misc-utils/blob/master/sample-Python-KeyVault-Function/init-with-msi.py). I don't do much python so if looking at this makes your insides hurt, please let me know [Twitter](https://twitter.com/azureandchill) [GitHub](https://github.com/jpda).
2 |
3 | ## to publish:
4 | because certain dependencies are binary, you have to build in a docker container - `--build-native-deps` does this for you during publish
5 |
6 | to create a service principal for rbac assignment to KV secrets, use `az ad sp create-for-rbac --name 'a-recognizable-name' --skip-assignment`
7 |
8 | to publish from local, login to azure cli `az login` and set your subscription to the one containing your function, then
9 |
10 | `func azure functionapp publish --build-native-deps`
11 |
--------------------------------------------------------------------------------
/sample-Python-KeyVault-Function/init-manual-service-principal.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import azure.functions as func
3 |
4 | from azure.keyvault import KeyVaultClient, KeyVaultAuthentication
5 | from azure.common.credentials import ServicePrincipalCredentials
6 | # see https://docs.microsoft.com/en-us/python/api/overview/azure/key-vault?view=azure-python
7 |
8 | def auth_callback(server, resource, scope):
9 | credentials = ServicePrincipalCredentials(
10 | client_id = '',
11 | secret = '',
12 | tenant = '',
13 | resource = "https://vault.azure.net"
14 | )
15 | token = credentials.token
16 | return token['token_type'], token['access_token']
17 |
18 | client = KeyVaultClient(KeyVaultAuthentication(auth_callback))
19 |
20 | def main(req: func.HttpRequest) -> func.HttpResponse:
21 | logging.info('Python HTTP trigger function processed a request.')
22 | secret_bundle = client.get_secret("https://.vault.azure.net/", "", "")
23 | return func.HttpResponse(f"{secret_bundle.value}!")
--------------------------------------------------------------------------------
/sample-Python-KeyVault-Function/init-with-msi.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import azure.functions as func
3 | from azure.keyvault import KeyVaultClient
4 | from msrestazure.azure_active_directory import MSIAuthentication, ServicePrincipalCredentials
5 |
6 | credentials = MSIAuthentication(
7 | resource='https://vault.azure.net'
8 | )
9 | client = KeyVaultClient(
10 | credentials
11 | )
12 |
13 | def main(req: func.HttpRequest) -> func.HttpResponse:
14 | logging.info('Python HTTP trigger function processed a request.')
15 | secret_bundle = client.get_secret("https://.vault.azure.net/", "", "")
16 | return func.HttpResponse(f"{secret_bundle.value}!")
--------------------------------------------------------------------------------
/sample-Python-KeyVault-Function/requirements.txt:
--------------------------------------------------------------------------------
1 | adal==1.2.1
2 | asn1crypto==0.24.0
3 | astroid==2.1.0
4 | azure-common==1.1.17
5 | azure-functions==1.0.0a5
6 | azure-functions-worker==1.0.0a6
7 | azure-keyvault==1.1.0
8 | azure-nspkg==3.0.2
9 | certifi==2023.7.22
10 | cffi==1.11.5
11 | chardet==3.0.4
12 | colorama==0.4.1
13 | cryptography==41.0.6
14 | grpcio==1.53.0
15 | grpcio-tools==1.14.2
16 | idna==2.8
17 | isodate==0.6.0
18 | isort==4.3.4
19 | lazy-object-proxy==1.3.1
20 | mccabe==0.6.1
21 | msrest==0.6.4
22 | msrestazure==0.6.0
23 | oauthlib==3.0.1
24 | protobuf==3.18.3
25 | pycparser==2.19
26 | PyJWT==2.4.0
27 | pylint==2.2.2
28 | python-dateutil==2.7.5
29 | requests==2.31.0
30 | requests-oauthlib==1.2.0
31 | six==1.12.0
32 | typed-ast==1.2.0
33 | urllib3>=1.24.2
34 | wrapt==1.11.1
--------------------------------------------------------------------------------
/sample-UpdateManagement/Kusto/Compliance/UncompliantHosts.csl:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------------
2 | // Created
3 | // 2018.12.05
4 | // Shannon Kuehn
5 | // Last Updated
6 | //
7 | // © 2018 Microsoft Corporation.
8 | // All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
9 | // or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
10 | // warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular
11 | // purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
12 | // In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts
13 | // be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business
14 | // interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the
15 | // sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
16 | //
17 | // Update Management
18 | //
19 | // Uncompliant Servers - Lists all servers that are not compliant via Update Management.
20 | //-----------------------------------------------------------------------------------
21 |
22 | Update
23 | | where UpdateState == "Needed" and (Classification == "Security Updates" or Classification == "Critical Updates")
24 | | summarize count() by Computer
25 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/Kusto/Post Analysis/Host-w-PatchAmountApplied.csl:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------------
2 | // Created
3 | // 2019.01.16
4 | // Shannon Kuehn
5 | // Last Updated
6 | //
7 | // © 2018 Microsoft Corporation.
8 | // All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
9 | // or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
10 | // warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular
11 | // purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
12 | // In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts
13 | // be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business
14 | // interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the
15 | // sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
16 | //-----------------------------------------------------------------------------------
17 |
18 | UpdateRunProgress
19 | | where InstallationStatus == 'Succeeded'
20 | | where TimeGenerated > now(-30d)
21 | | distinct Computer
22 | , Title
23 | | summarize count(Title) by Computer
24 | | sort by Computer asc
25 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/Kusto/Post Analysis/LinWin-PostAnalysis.csl:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------------
2 | // Created
3 | // 2018.11.20
4 | // Shannon Kuehn
5 | // Last Updated
6 | //
7 | // © 2018 Microsoft Corporation.
8 | // All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
9 | // or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
10 | // warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular
11 | // purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
12 | // In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts
13 | // be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business
14 | // interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the
15 | // sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
16 | //
17 | // Update Management
18 | //
19 | // Patching post-analysis query sample - Windows and Linux VMs
20 | //
21 | // Grabs patch details for patch group and builds a post analysis report for regulatory compliance.
22 | //-----------------------------------------------------------------------------------
23 |
24 | let group1 = dynamic (['hostname1','hostname2','hostname3','hostname4','hostname5','hostname6','hostname7','hostname8']);
25 | UpdateRunProgress
26 | | where UpdateRunName == "group1"
27 | | where InstallationStatus == 'Succeeded'
28 | | where TimeGenerated > now(-60d)
29 | | project Computer
30 | , TimeGenerated
31 | , SourceComputerId
32 | , InstallationStatus
33 | , Product
34 | , Title
35 | , KBID
36 | , UpdateId
37 | , ErrorResult
38 | , UpdateRunName
39 | | sort by Computer asc
40 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/Kusto/Pre-Analysis/Linux-PreAnalysis.csl:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------------
2 | // Created
3 | // 2018.11.06
4 | // Shannon Kuehn
5 | // Last Updated
6 | //
7 | // © 2018 Microsoft Corporation.
8 | // All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
9 | // or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
10 | // warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular
11 | // purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
12 | // In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts
13 | // be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business
14 | // interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the
15 | // sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
16 | //
17 | // Update Management
18 | //
19 | // Patching pre-analysis query sample - Linux VMs
20 | //
21 | // Grabs patch details for patch group and builds a pre-analysis report for regulatory compliance.
22 | //-----------------------------------------------------------------------------------
23 |
24 | let group1 = dynamic (['hostname1','hostname2','hostname3','hostname4','hostname5','hostname6','hostname7','hostname8']);
25 | Update
26 | | where Computer in (group1)
27 | | where TimeGenerated>ago(30d) and OSType=="Linux" and SourceComputerId in ((Heartbeat
28 | | where TimeGenerated>ago(30d) and OSType=="Linux" and notempty(Computer)
29 | | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId
30 | | where Solutions has "updates"
31 | | distinct SourceComputerId))
32 | | summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, Product, ProductArch
33 | | where UpdateState=~"Needed"
34 | | where Classification=~"Critical Updates"
35 | | project Computer
36 | , TimeGenerated
37 | , Product
38 | , Classification
39 | , UpdateState
40 | , OSType
41 | , PackageRepository
42 | , OSName
43 | , OSVersion
44 | | sort by Computer asc
45 | , Product asc
46 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/Kusto/Pre-Analysis/Windows-PreAnalysis.csl:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------------
2 | // Created
3 | // 2018.11.06
4 | // Shannon Kuehn
5 | // Last Updated
6 | //
7 | // © 2018 Microsoft Corporation.
8 | // All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
9 | // or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
10 | // warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular
11 | // purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
12 | // In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts
13 | // be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business
14 | // interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the
15 | // sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
16 | //
17 | // Update Management
18 | //
19 | // Patching pre-analysis query sample - Windows VMs
20 | //
21 | // Grabs patch details for patch group and builds a pre-analysis report for regulatory compliance.
22 | //-----------------------------------------------------------------------------------
23 |
24 | let group1 = dynamic (['hostname1','hostname2','hostname3','hostname4','hostname5','hostname6','hostname7','hostname8']);
25 | Update
26 | | where Computer in (group1)
27 | | where TimeGenerated>ago(30d) and OSType!="Linux" and (Optional==false or Classification has "Critical" or Classification has "Security") and SourceComputerId in ((Heartbeat
28 | | where TimeGenerated>ago(30d) and OSType=~"Windows" and notempty(Computer)
29 | | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId
30 | | where Solutions has "updates"
31 | | distinct SourceComputerId))
32 | | summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID
33 | | where UpdateState=~"Needed" and Approved!=false
34 | | project Computer
35 | , TimeGenerated
36 | , PublishedDate
37 | , KBID
38 | , Product
39 | , Title
40 | , UpdateState
41 | , Optional
42 | , RebootBehavior
43 | | sort by Computer asc
44 | , PublishedDate
45 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/Kusto/README.md:
--------------------------------------------------------------------------------
1 | Kusto Queries - Detailed Explanations:
2 | 1) CVE Numbers are only listed for Linux within the underlying database engine for Kusto, except not every Linux server
3 | patch contains a CVE Number.
4 | 2) For the pre and post analysis queries, TimeGenerated refers to when the patch applies. In order to ensure you grab
5 | data for the past month, the TimeGenerated needs to be in the initial part of the Kusto query.
6 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/ADDS/01-InitialTask-ADDSSecurityGroups.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2018.08.24
4 | Shannon Kuehn
5 | Last Updated
6 |
7 | © 2018 Microsoft Corporation.
8 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
9 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
10 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
11 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
12 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
13 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
14 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
15 | documentation, even if Microsoft has been advised of the possibility of such damages.
16 | #>
17 |
18 |
19 | ## Initial Security Group Assignment #
20 | #########################################################################################################
21 | ##
22 | ## Script performs the following tasks:
23 | ## 1) Imports ActiveDirectory PoSH module.
24 | ## 2) Stores all AD DS computers as a variable to loop through.
25 | ## 3) Loops through each recently created server to determine if a metadata json file is on the server.
26 | ## 4) If server has a json file saved, server name will be stored as a variable.
27 | ## 5) Loops through server name and extracts SamAccountName. SamAccountName is necessary for AD Security
28 | ## Group assignment.
29 | ## 6) Formulates a patch schedule based upon json file for each server.
30 | ## Notes:
31 | ## a. Run on server with AD DS role installed or on a server with RSAT tools.
32 | ## b. Test permissions to run (best with a service account): requires permissions to query server
33 | ## objects in AD DS and ability to assign servers to Security Groups.
34 | #########################################################################################################
35 |
36 | Import-Module ActiveDirectory
37 | $servers = Get-ADComputer -Filter * | Select-Object -ExpandProperty Name
38 | ForEach($server in $servers){
39 | $path = Test-Path "\\$server\C$\filepath\base.json"
40 | If($path -eq $true){
41 | $patchSchedule = Get-Content -Raw -Path "\\$server\c$\filepath\base.json" | ConvertFrom-Json | Select-Object -ExpandProperty patch_schedule
42 | $SAMAccountName = Get-ADComputer -Identity $server | Select-Object -ExpandProperty SamAccountName
43 | $patchScheduleName = ""
44 | Switch ($patchSchedule){
45 | '01'{$patchScheduleName = "patch_schedule_01"}
46 | '02'{$patchScheduleName = "patch_schedule_02"}
47 | '03'{$patchScheduleName = "patch_schedule_03"}
48 | '04'{$patchScheduleName = "patch_schedule_04"}
49 | }
50 | Add-ADGroupMember -Identity $patchScheduleName -Members $SAMAccountName
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/ADDS/README.md:
--------------------------------------------------------------------------------
1 | PowerShell Scripts - Explained
2 | 1) 01-InitialTask-ADDSSecurityGroups.ps1 - Initially imports ActiveDirectory PowerShell module, iterates through
3 | all servers that are domain joined, and groups based upon a patch schedule listed inside a json file sitting in a
4 | specific directory.
5 | 2) 02-SchedTask-ADDSSecurityGroups.ps1 - As a scheduled task, imports ActiveDirectory PowerShell module, iterates through
6 | new servers that are domin joined, and groups based upon a patch schedule listed inside a json file sitting in a specific
7 | directory.
8 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AutomatedComplianceReporting/01-BearerToken.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2018.12.20
4 | Shannon Kuehn
5 | Last Updated
6 | © 2018 Microsoft Corporation.
7 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
8 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
9 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
10 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
11 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
12 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
13 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
14 | documentation, even if Microsoft has been advised of the possibility of such damages.
15 | #>
16 | # Adapted from:
17 | # https://www.codeisahighway.com/how-to-easily-and-silently-obtain-accesstoken-bearer-from-an-existing-azure-powershell-session/
18 |
19 | function Get-AzureRmCachedAccessToken()
20 | {
21 | $ErrorActionPreference = 'Stop'
22 |
23 | if(-not (Get-Module AzureRm.Profile)) {
24 | Import-Module AzureRm.Profile
25 | }
26 | $azureRmProfileModuleVersion = (Get-Module AzureRm.Profile).Version
27 | # refactoring performed in AzureRm.Profile v3.0 or later
28 | if($azureRmProfileModuleVersion.Major -ge 3) {
29 | $azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
30 | if(-not $azureRmProfile.Accounts.Count) {
31 | Write-Error "Ensure you have logged in before calling this function."
32 | }
33 | } else {
34 | # AzureRm.Profile < v3.0
35 | $azureRmProfile = [Microsoft.WindowsAzure.Commands.Common.AzureRmProfileProvider]::Instance.Profile
36 | if(-not $azureRmProfile.Context.Account.Count) {
37 | Write-Error "Ensure you have logged in before calling this function."
38 | }
39 | }
40 |
41 | $currentAzureContext = Get-AzureRmContext
42 | $profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azureRmProfile)
43 | Write-Debug ("Getting access token for tenant" + $currentAzureContext.Subscription.TenantId)
44 | $token = $profileClient.AcquireAccessToken($currentAzureContext.Subscription.TenantId)
45 | $token.AccessToken
46 | }
47 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AutomatedComplianceReporting/02-PostAnalysisAutomation.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2019.01.25
4 | Shannon Kuehn
5 | Last Updated
6 |
7 | © 2019 Microsoft Corporation.
8 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
9 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
10 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
11 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
12 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
13 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
14 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
15 | documentation, even if Microsoft has been advised of the possibility of such damages.
16 | #>
17 |
18 | #Required parameters
19 | param(
20 | [Parameter(Mandatory=$true)]
21 | [string]$subscriptionId,
22 | [Parameter(Mandatory=$true)]
23 | [array]$rG,
24 | [Parameter(Mandatory=$true)]
25 | [string]$workspaceName
26 | )
27 |
28 | #Generate bearer token and use token + header for the API call. Ensure the header has more information to grab the records
29 | #correctly. The body needs to be passed as shown below in order to run a successful Kusto Query against the environment.
30 | $bearer = Get-AzCachedAccessToken
31 | $header = @{"Authorization"="Bearer $bearer";"Content-Type"="application/json";"Prefer"="response-v1=true"}
32 | $apiCall = "https://management.azure.com/subscriptions/"+$subscriptionId+"/resourceGroups/"+$rG+"/providers/Microsoft.OperationalInsights/workspaces/"+$workspaceName+"/api/query?api-version=2017-01-01-preview"
33 | $body = @"
34 | {"query": "UpdateRunProgress | where InstallationStatus == 'Succeeded' | where TimeGenerated > now(-30d) | project Computer , TimeGenerated , SourceComputerId , InstallationStatus , Product , Title , KBID , UpdateId , ErrorResult , UpdateRunName | sort by Computer asc"}
35 | "@
36 |
37 | #Run the script, which extracts columns and rows as objects, then adds them to a data table, which can be extracted as a csv.
38 | $response = Invoke-WebRequest -Uri $apiCall -Headers $header -Method Post -Body $body
39 | $jsonResponses = $response.Content | ConvertFrom-Json
40 | $ScriptBlock = .{
41 | $tableObj = New-Object System.Data.DataTable "Post-Analysis"
42 | $jsonResponse.tables.columns | ForEach {
43 | $newcol = New-Object System.Data.DataColumn
44 | $newcol.ColumnName=$_.Name
45 | $newcol.DataType=$_.Type
46 | $tableObj.Columns.Add($newcol)
47 | }
48 |
49 | $jsonResponse.tables.rows | ForEach {
50 | $tableObj.Rows.Add($_)
51 | }
52 |
53 | $tableObj | Export-Csv \\server\share\ComplianceReporting\PostAnalysis_2019-01-19.csv -NTI
54 | }
55 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AutomatedComplianceReporting/04-PreAnalysisAutomation-Windows.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2019.01.25
4 | Shannon Kuehn
5 | Last Updated
6 |
7 | © 2019 Microsoft Corporation.
8 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
9 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
10 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
11 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
12 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
13 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
14 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
15 | documentation, even if Microsoft has been advised of the possibility of such damages.
16 | #>
17 |
18 | #Required parameters.
19 | param(
20 | [Parameter(Mandatory=$true)]
21 | [string]$subscriptionId,
22 | [Parameter(Mandatory=$true)]
23 | [array]$rG,
24 | [Parameter(Mandatory=$true)]
25 | [string]$workspaceName
26 | )
27 |
28 | #Generate bearer token and use token + header for the API call. Ensure the header has more information to grab the records.
29 | $bearer = Get-AzureRmCachedAccessToken
30 | $header = @{"Authorization"="Bearer $bearer";"Content-Type"="application/json";"Prefer"="response-v1=true"}
31 | $apiCall = "https://management.azure.com/subscriptions/"+$subscriptionId+"/resourceGroups/"+$rG+"/providers/Microsoft.OperationalInsights/workspaces/"+$workspaceName+"/api/query?api-version=2017-01-01-preview"
32 | $body = @"
33 | {"query": "Update | where TimeGenerated>ago(30d) and OSType!='Linux' and (Optional==false or Classification has 'Critical' or Classification has 'Security') and SourceComputerId in ((Heartbeat | where TimeGenerated>ago(30d) and OSType=~'Windows' and notempty(Computer) | summarize arg_max(TimeGenerated, Solutions) by SourceComputerId | where Solutions has 'updates' | distinct SourceComputerId)) | summarize hint.strategy=partitioned arg_max(TimeGenerated, *) by Computer, SourceComputerId, UpdateID | where UpdateState=~'Needed' and Approved!=false | project Computer , TimeGenerated , PublishedDate , KBID , Product , Title , UpdateState , Optional , RebootBehavior | sort by Computer asc , PublishedDate"}
34 | "@
35 |
36 | #Run the script, which extracts columns and rows as objects, then adds them to a data table, which can be extracted as a csv.
37 | $response = Invoke-WebRequest -Uri $apiCall -Headers $header -Method Post -Body $body
38 | $jsonResponses = $response.Content | ConvertFrom-Json
39 | $ScriptBlock = .{
40 | $tableObj = New-Object System.Data.DataTable "Post-Analysis"
41 | $jsonResponse.tables.columns | ForEach {
42 | $newcol = New-Object System.Data.DataColumn
43 | $newcol.ColumnName=$_.Name
44 | $newcol.DataType=$_.Type
45 | $tableObj.Columns.Add($newcol)
46 | }
47 |
48 | $jsonResponse.tables.rows | ForEach {
49 | $tableObj.Rows.Add($_)
50 | }
51 |
52 | $tableObj | Export-Csv \\server\share\ComplianceReporting\PreAnalysisWindows_2019-01-19.csv -NTI
53 | }
54 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AutomatedComplianceReporting/README.md:
--------------------------------------------------------------------------------
1 | Automated Compliance Reporting:
2 | 1) Run the 01-BearerToken.ps1 while logged into Azure PowerShell, with an active account pointed at the working sub.
3 | 2) The 01-BearerToken.ps1 script loads the actual Bearer Token into memory. This token gets called upon in the each of the automation scripts by way of using the Get-AzureRmCachedAccessToken function. The bearer token allows the logged in user to hit the API directly to query information.
4 | 3) Each script will run a Log Analytics query against the Update Management environment, whether it be for pre-analysis or post analysis.
5 | 4) In addition, the output of each script will export to a csv file that can be used for regulatory records of patch compliance.
6 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AzureAutomationRunbooks/3rdPartyPatching/7Zip.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2019.02.07
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2019 Microsoft Corporation.
10 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
11 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
12 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
13 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
14 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
15 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
16 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
17 | documentation, even if Microsoft has been advised of the possibility of such damages.
18 | #>
19 |
20 | #Required parameters to run on a schedule or on-demand.
21 | param(
22 | [Parameter(Mandatory = $true)]
23 | [string]$sourcePath,
24 | [Parameter(Mandatory = $true)]
25 | [string]$workspaceId,
26 | [Parameter(Mandatory = $true)]
27 | [string]$query
28 | )
29 |
30 | #Specify the Azure Automation connection.
31 | $Conn = Get-AutomationConnection -Name AzureRunAsConnection
32 | Connect-AzAccount -ServicePrincipal -Tenant $Conn.TenantID `
33 | -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
34 | Set-AzContext -SubscriptionId $Conn.SubscriptionID
35 |
36 | #Required Parameters to test with AzureAutomationAuthoringToolkit. Comment out with # if running inside Azure on a schedule.
37 | $sourcePath = '\\server\share\AppPatching\7-Zip\'
38 | $workspaceId = "Log Analytics workspace ID goes here"
39 | $query = "ConfigurationData | where ConfigDataType == 'Software' | where SoftwareName == '7-Zip 18.01' | distinct Computer"
40 | $queryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspaceId -Query $query
41 | $computername = $queryResults.Results | Select-Object -ExpandProperty Computer
42 |
43 | #Run the installation script.
44 | ForEach($computer in $computername){
45 | Copy-Item -Path $sourcePath -Destination \\$computer\c$\ -Recurse -Force
46 | $session = New-PSSession -ComputerName $computer
47 | Invoke-Command -Session $session -ScriptBlock {
48 | $process = New-Object System.Diagnostics.Process
49 | $process.StartInfo.FileName = "C:\7-Zip\7z1806-x64.exe"
50 | $process.StartInfo.Arguments = " /s"
51 | $process.StartInfo.Verb = "RunAs"
52 | $process.Start()
53 | }
54 | Enter-PSSession -Session $session
55 | Exit-PSSession
56 | }
57 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AzureAutomationRunbooks/3rdPartyPatching/JRE.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2019.02.07
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2019 Microsoft Corporation.
10 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
11 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
12 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
13 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
14 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
15 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
16 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
17 | documentation, even if Microsoft has been advised of the possibility of such damages.
18 | #>
19 |
20 | #Required parameters to run on a schedule or on-demand.
21 | param(
22 | [Parameter(Mandatory = $true)]
23 | [string]$sourcePath,
24 | [Parameter(Mandatory = $true)]
25 | [string]$workspaceId,
26 | [Parameter(Mandatory = $true)]
27 | [string]$query
28 | )
29 |
30 | #Specify the Azure Automation connection.
31 | $Conn = Get-AutomationConnection -Name AzureRunAsConnection
32 | Connect-AzAccount -ServicePrincipal -Tenant $Conn.TenantID `
33 | -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
34 | Set-AzContext -SubscriptionId $Conn.SubscriptionID
35 |
36 | #Required Parameters to test with AzureAutomationAuthoringToolkit. Comment out with # if running inside Azure on a schedule.
37 | $sourcePath = '\\server\share\AppPatching\Java\'
38 | $workspaceId = "Log Analytics workspace goes here"
39 | $query = 'ConfigurationData | where ConfigDataType == "Software" | where SoftwareName == "Java 8 Update 201 (64-bit)" | distinct Computer'
40 | $queryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspaceId -Query $query
41 | $computername = $queryResults.Results | Select-Object -ExpandProperty Computer
42 |
43 | #Run the installation script.
44 | ForEach($computer in $computername){
45 | Copy-Item -Path $sourcePath -Destination \\$computer\c$\ -Recurse -Force
46 | $session = New-PSSession -ComputerName $computer
47 | Invoke-Command -Session $session -ScriptBlock {
48 | $process = New-Object System.Diagnostics.Process
49 | $process.StartInfo.FileName = "C:\java\jre-8u202-windows-x64.exe"
50 | $process.StartInfo.Arguments = " /s"
51 | $process.StartInfo.Verb = "RunAs"
52 | $process.Start()
53 | }
54 | Enter-PSSession -Session $session
55 | Exit-PSSession
56 | }
57 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AzureAutomationRunbooks/3rdPartyPatching/VNC.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2019.02.07
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2019 Microsoft Corporation.
10 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
11 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
12 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
13 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
14 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
15 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
16 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
17 | documentation, even if Microsoft has been advised of the possibility of such damages.
18 | #>
19 |
20 | #Required parameters to run on a schedule or on-demand.
21 | param(
22 | [Parameter(Mandatory = $true)]
23 | [string]$sourcePath,
24 | [Parameter(Mandatory = $true)]
25 | [string]$workspaceId,
26 | [Parameter(Mandatory = $true)]
27 | [string]$query
28 | )
29 |
30 | #Specify the Azure Automation connection.
31 | $Conn = Get-AutomationConnection -Name AzureRunAsConnection
32 | Connect-AzAccount -ServicePrincipal -Tenant $Conn.TenantID `
33 | -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
34 | Set-AzContext -SubscriptionId $Conn.SubscriptionID
35 |
36 | #Required Parameters to test with AzureAutomationAuthoringToolkit. Comment out with # if running inside Azure on a schedule.
37 | $sourcePath = '\\server\share\AppPatching\RealVNC\'
38 | $workspaceId = "Log Analytics workspace ID goes here"
39 | $query = 'ConfigurationData | where ConfigDataType == "Software" | where SoftwareName == "VNC Server 6.0.0" | distinct Computer'
40 | $queryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspaceId -Query $query
41 | $computername = $queryResults.Results | Select-Object -ExpandProperty Computer
42 |
43 | #Run the installation script.
44 | ForEach($computer in $computername){
45 | Copy-Item -Path $sourcePath -Destination \\$computer\c$\ -Recurse -Force
46 | $session = New-PSSession -ComputerName $computer
47 | Invoke-Command -Session $session -ScriptBlock {
48 | $process = New-Object System.Diagnostics.Process
49 | $process.StartInfo.FileName = "msiexec"
50 | $process.StartInfo.Arguments = " /i `"C:\RealVNC\VNC-Server-6.4.0-Windows-en-64bit.msi`" /qn"
51 | $process.StartInfo.Verb = "RunAs"
52 | $process.Start()
53 | }
54 | Enter-PSSession -Session $session
55 | Exit-PSSession
56 | }
57 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AzureAutomationRunbooks/3rdPartyPatching/WinZip.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2019.02.07
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2019 Microsoft Corporation.
10 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
11 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
12 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
13 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
14 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
15 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
16 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
17 | documentation, even if Microsoft has been advised of the possibility of such damages.
18 | #>
19 |
20 | #Required parameters to run on a schedule or on-demand.
21 | param(
22 | [Parameter(Mandatory = $true)]
23 | [string]$sourcePath,
24 | [Parameter(Mandatory = $true)]
25 | [string]$workspaceId,
26 | [Parameter(Mandatory = $true)]
27 | [string]$query
28 | )
29 |
30 | #Specify the Azure Automation connection.
31 | $Conn = Get-AutomationConnection -Name AzureRunAsConnection
32 | Connect-AzAccount -ServicePrincipal -Tenant $Conn.TenantID `
33 | -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
34 | Set-AzContext -SubscriptionId $Conn.SubscriptionID
35 |
36 | #Required Parameters to test with AzureAutomationAuthoringToolkit. Comment out with # if running inside Azure on a schedule.
37 | $sourcePath = '\\server\share\AppPatching\WinZip\'
38 | $workspaceId = "Log Analytics workspace ID goes here"
39 | $query = 'ConfigurationData | where ConfigDataType == "Software" | where SoftwareName == "WinZip 21.0" | distinct Computer'
40 | $queryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspaceId -Query $query
41 | $computername = $queryResults.Results | Select-Object -ExpandProperty Computer
42 |
43 | #Run the installation script.
44 | ForEach($computer in $computername){
45 | Copy-Item -Path $sourcePath -Destination \\$computer\c$\ -Recurse -Force
46 | $session = New-PSSession -ComputerName $computer
47 | Invoke-Command -Session $session -ScriptBlock {
48 | $process = New-Object System.Diagnostics.Process
49 | $process.StartInfo.FileName = "msiexec"
50 | $process.StartInfo.Arguments = " /i `"C:\WinZip\winzip230-64.msi`" /qn"
51 | $process.StartInfo.Verb = "RunAs"
52 | $process.Start()
53 | }
54 | Enter-PSSession -Session $session
55 | Exit-PSSession
56 | }
57 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AzureAutomationRunbooks/3rdPartyPatching/Wireshark.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2019.02.07
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2019 Microsoft Corporation.
10 |
11 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
12 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
13 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
14 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
15 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
16 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
17 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
18 | documentation, even if Microsoft has been advised of the possibility of such damages.
19 | #>
20 |
21 | #Required parameters to run on a schedule or on-demand.
22 | param(
23 | [Parameter(Mandatory = $true)]
24 | [string]$sourcePath,
25 | [Parameter(Mandatory = $true)]
26 | [string]$workspaceId,
27 | [Parameter(Mandatory = $true)]
28 | [string]$query
29 | )
30 |
31 | #Specify the Azure Automation connection.
32 | $Conn = Get-AutomationConnection -Name AzureRunAsConnection
33 | Connect-AzAccount -ServicePrincipal -Tenant $Conn.TenantID `
34 | -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
35 | Set-AzContext -SubscriptionId $Conn.SubscriptionID
36 |
37 | #Required Parameters to test with AzureAutomationAuthoringToolkit. Comment out with # if running inside Azure on a schedule.
38 | $sourcePath = '\\server\share\AppPatching\Wireshark'
39 | $workspaceId = "Log Analytics workspace ID goes here"
40 | $query = "ConfigurationData | where ConfigDataType == 'Software' | where SoftwareName == 'Wireshark 2.6.3 64-bit' | distinct Computer"
41 | $queryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspaceId -Query $query
42 | $computername = $queryResults.Results | Select-Object -ExpandProperty Computer
43 |
44 | #Run the installation script.
45 | ForEach($computer in $computername){
46 | Copy-Item -Path $sourcePath -Destination \\$computer\c$\ -Recurse -Force
47 | $session = New-PSSession -ComputerName $computer
48 | Invoke-Command -Session $session -ScriptBlock {
49 | $process = New-Object System.Diagnostics.Process
50 | $process.StartInfo.FileName = "C:\Wireshark\Wireshark-win64-2.6.5.exe"
51 | $process.StartInfo.Arguments = " /S"
52 | $process.StartInfo.Verb = "RunAs"
53 | $process.Start()
54 | }
55 | Enter-PSSession -Session $session
56 | Exit-PSSession
57 | }
58 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AzureAutomationRunbooks/Export-RunAsCertificateToHybridWorker.ps1:
--------------------------------------------------------------------------------
1 | <#PSScriptInfo
2 | https://www.powershellgallery.com/packages/Export-RunAsCertificateToHybridWorker/1.0/Content/Export-RunAsCertificateToHybridWorker.ps1
3 |
4 | .VERSION 1.0
5 | .GUID 3a796b9a-623d-499d-86c8-c249f10a6986
6 | .AUTHOR Azure Automation Team
7 | .COMPANYNAME Microsoft
8 | .COPYRIGHT
9 | .TAGS Azure Automation
10 | .LICENSEURI
11 | .PROJECTURI
12 | .ICONURI
13 | .EXTERNALMODULEDEPENDENCIES
14 | .REQUIREDSCRIPTS
15 | .EXTERNALSCRIPTDEPENDENCIES
16 | .RELEASENOTES
17 | #>
18 |
19 | <#
20 | .SYNOPSIS
21 | Exports the Run As certificate from an Azure Automation account to a hybrid worker in that account.
22 |
23 | .DESCRIPTION
24 | This runbook exports the Run As certificate from an Azure Automation account to a hybrid worker in that account.
25 | Run this runbook in the hybrid worker where you want the certificate installed.
26 | This allows the use of the AzureRunAsConnection to authenticate to Azure and manage Azure resources from runbooks running in the hybrid worker.
27 |
28 | .EXAMPLE
29 | .\Export-RunAsCertificateToHybridWorker
30 |
31 | .NOTES
32 | AUTHOR: Azure Automation Team
33 | LASTEDIT: 2016.10.13
34 | #>
35 |
36 | [OutputType([string])]
37 |
38 | # Set the password used for this certificate
39 | $Password = "YourStrongPasswordForTheCert"
40 |
41 | # Stop on errors
42 | $ErrorActionPreference = 'stop'
43 |
44 | # Get the management certificate that will be used to make calls into Azure Service Management resources
45 | $RunAsCert = Get-AutomationCertificate -Name "AzureRunAsCertificate"
46 |
47 | # location to store temporary certificate in the Automation service host
48 | $CertPath = Join-Path $env:temp "AzureRunAsCertificate.pfx"
49 |
50 | # Save the certificate
51 | $Cert = $RunAsCert.Export("pfx",$Password)
52 | Set-Content -Value $Cert -Path $CertPath -Force -Encoding Byte | Write-Verbose
53 |
54 | Write-Output ("Importing certificate into local machine root store from " + $CertPath)
55 | $SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force
56 | Import-PfxCertificate -FilePath $CertPath -CertStoreLocation Cert:\LocalMachine\My -Password $SecurePassword -Exportable | Write-Verbose
57 |
58 | # Test that authentication to Azure ARM is working
59 | $RunAsConnection = Get-AutomationConnection -Name "AzureRunAsConnection"
60 |
61 | Add-AzureRmAccount `
62 | -ServicePrincipal `
63 | -TenantId $RunAsConnection.TenantId `
64 | -ApplicationId $RunAsConnection.ApplicationId `
65 | -CertificateThumbprint $RunAsConnection.CertificateThumbprint | Write-Verbose
66 |
67 | Select-AzureRmSubscription -SubscriptionId $RunAsConnection.SubscriptionID | Write-Verbose
68 |
69 | # List automation accounts to confirm ARM calls are working
70 | Get-AzureRmAutomationAccount | Select AutomationAccountName
71 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AzureAutomationRunbooks/README.md:
--------------------------------------------------------------------------------
1 | Get-AutomationConnection Explained:
2 | Get-AutomationConnection is an internal cmdlet to Azure Automation that allows you to get a relative connection
3 | from the automation account without going through the Azure Resource Manager APIs. Note that the cmdlet is not
4 | Get-AzureAutomationConnection (which is the old service management cmdlet) or Get-AzureRMAutomationConnection
5 | (which is the newer resource manager cmdlet). This interal cmdlet is necessary to ensure you can get a Run As
6 | Connection to pass to the Connect-AzureRMAccount cmdlet to authenticate to Azure and manage other resources.
7 | There are other internal cmdlets that are used to retrieve assets, like Get-AutomationVariable, etc.
8 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AzureAutomationRunbooks/RollbackPatches/WindowsRollback.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2019.01.25
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2019 Microsoft Corporation.
10 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
11 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
12 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
13 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
14 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
15 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
16 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
17 | documentation, even if Microsoft has been advised of the possibility of such damages.
18 | #>
19 |
20 | #Required parameters to run on a schedule or on-demand.
21 | param(
22 | [Parameter(Mandatory=$true)]
23 | [string]$query,
24 | [Parameter(Mandatory = $true)]
25 | [string]$workspaceId,
26 | [Parameter(Mandatory = $true)]
27 | [string]$KB
28 | )
29 |
30 | #Specify the Azure Automation connection.
31 | $RunAsConnection = Get-AutomationConnection -Name AzureRunAsConnection
32 | Connect-AzAccount -CertificateThumbprint $RunAsConnection.CertificateThumbprint `
33 | -ApplicationId $RunAsConnection.ApplicationID -Tenant $RunAsConnection.TenantID -ServicePrincipal
34 | Set-AzContext -SubscriptionId $RunAsConnection.SubscriptionID
35 |
36 | #Required Parameters to test with AzureAutomationAuthoringToolkit. Comment out with # if running inside Azure on a schedule.
37 | $workspaceId = "Log Analytics workspace ID goes here"
38 | $KB = 'List KB to uninstall with just numbers, no KB in front'
39 | $query = 'ConfigurationData | where ConfigDataType == "Software" | where SoftwareName == "Security Update for Windows Server 2012 R2 (KB3177186)" | project Computer | distinct Computer'
40 |
41 | #Azure Automation Runbook script.
42 | $queryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspaceId -Query $query
43 | $computers = $queryResults.Results | Select-Object -ExpandProperty Computer
44 | foreach ($computer in $computers)
45 | {
46 | Invoke-Command -ComputerName $computer -ScriptBlock {C:\Windows\System32\wusa.exe /kb:$KB /uninstall /quiet /norestart} -Verbose
47 | }
48 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/AzureAutomationRunbooks/RollbackPatches/linRollBack.py:
--------------------------------------------------------------------------------
1 | #
2 | # Created
3 | # 2019.02.27
4 | # Shannon Kuehn
5 | # Last Updated
6 | #
7 | # © 2019 Microsoft Corporation.
8 | # All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
9 | # or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
10 | # warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
11 | # The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
12 | # shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
13 | # any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
14 | # business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
15 | # documentation, even if Microsoft has been advised of the possibility of such damages.
16 |
17 |
18 | import os
19 | from azure.mgmt.compute import ComputeManagementClient
20 | import azure.mgmt.resource
21 | import automationassets
22 |
23 | def get_automation_runas_credential(runas_connection):
24 | from OpenSSL import crypto
25 | import binascii
26 | from msrestazure import azure_active_directory
27 | import adal
28 |
29 | # Get the Azure Automation RunAs service principal certificate
30 | cert = automationassets.get_automation_certificate("AzureRunAsCertificate")
31 | pks12_cert = crypto.load_pkcs12(cert)
32 | pem_pkey = crypto.dump_privatekey(crypto.FILETYPE_PEM,pks12_cert.get_privatekey())
33 |
34 | # Get run as connection information for the Azure Automation service principal
35 | application_id = runas_connection["ApplicationId"]
36 | thumbprint = runas_connection["CertificateThumbprint"]
37 | tenant_id = runas_connection["TenantId"]
38 |
39 | # Authenticate with service principal certificate
40 | resource ="https://management.core.windows.net/"
41 | authority_url = ("https://login.microsoftonline.com/"+tenant_id)
42 | context = adal.AuthenticationContext(authority_url)
43 | return azure_active_directory.AdalAuthentication(
44 | lambda: context.acquire_token_with_client_certificate(
45 | resource,
46 | application_id,
47 | pem_pkey,
48 | thumbprint)
49 | )
50 |
51 | # Authenticate to Azure using the Azure Automation RunAs service principal
52 | runas_connection = automationassets.get_automation_connection("AzureRunAsConnection")
53 | azure_credential = get_automation_runas_credential(runas_connection)
54 |
55 | # Initialize the compute management client with the RunAs credential and specify the subscription to work against.
56 | compute_client = ComputeManagementClient(
57 | azure_credential,
58 | str(runas_connection["SubscriptionId"])
59 | )
60 |
61 | list_of_servers = ["host1", "host2", "host3", "host4", "host5"]
62 |
63 | for server in list_of_servers:
64 | subprocess.call(['yum remove package_name'], shell=True)
65 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/GroupSchedule/01-SvrGrping.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2018.11.26
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2018 Microsoft Corporation.
10 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
11 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
12 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
13 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
14 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
15 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
16 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
17 | documentation, even if Microsoft has been advised of the possibility of such damages.
18 | #>
19 |
20 | $workspaceId = "Log Analytics workspace ID goes here"
21 | $scriptBlock = .{
22 | $serverinfo = Get-Content -Path "C:\temp\servergrouping.csv" | ConvertFrom-Csv
23 | $query = "Heartbeat | summarize arg_max(TimeGenerated, *) by SourceComputerId | top 500000 by Computer asc"
24 | $queryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $workspaceId -Query $query
25 | $queryResults.Results
26 | $servers = $queryResults.Results | Select-Object -ExpandProperty Computer
27 | }
28 | $group1 = @()
29 | $group2 = @()
30 | $group3 = @()
31 |
32 | ForEach($server in $serverinfo)
33 | {
34 | Switch ($server.patchSchedule){
35 | 'patch_schedule01' {
36 | $new1 = $servers | ? {$_ -eq $server.servername} | Select-Object -First 1
37 | $group1+=$new1
38 | }
39 | 'patch_schedule02' {
40 | $new2 = $servers | ? {$_ -eq $server.servername} | Select-Object -First 1
41 | $group2+=$new2
42 | }
43 | 'patch_schedule03' {
44 | $new3 = $servers | ? {$_ -eq $server.servername} | Select-Object -First 1
45 | $group3+=$new3
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/GroupSchedule/02-WinSvrSched.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2018.11.26
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2018 Microsoft Corporation.
10 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
11 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
12 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
13 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
14 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
15 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
16 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
17 | documentation, even if Microsoft has been advised of the possibility of such damages.
18 | #>
19 |
20 | function SetSchedule {
21 | param(
22 | [Parameter(Mandatory=$true)]
23 | [string]$startTime,
24 | [Parameter(Mandatory=$true)]
25 | [array]$group,
26 | [Parameter(Mandatory=$true)]
27 | [string]$resourceGroup,
28 | [Parameter(Mandatory=$true)]
29 | [string]$automationAccount,
30 | [Parameter(Mandatory=$true)]
31 | [string]$DaysofMonth,
32 | [Parameter(Mandatory=$true)]
33 | [int]$durationHours,
34 | [Parameter(Mandatory=$false)]
35 | [int]$monthInterval,
36 | [Parameter(Mandatory=$true)]
37 | [string]$scheduleName
38 | )
39 |
40 | $duration = New-TimeSpan -Hours $durationHours
41 | $schedule = New-AzAutomationSchedule -ResourceGroupName $resourceGroup `
42 | -AutomationAccountName $automationAccount `
43 | -Name $scheduleName `
44 | -StartTime $startTime `
45 | -DaysOfMonth $DaysofMonth `
46 | -MonthInterval $monthInterval `
47 | -ForUpdateConfiguration
48 |
49 | New-AzAutomationSoftwareUpdateConfiguration -ResourceGroupName $resourceGroup `
50 | -AutomationAccountName $automationAccount `
51 | -Schedule $schedule `
52 | -Windows `
53 | -NonAzureComputer $group `
54 | -IncludedUpdateClassification Critical `
55 | -Duration $duration
56 | }
57 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/GroupSchedule/03-LinuxSvrSched.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2018.11.26
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2018 Microsoft Corporation.
10 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
11 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
12 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
13 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
14 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
15 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
16 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
17 | documentation, even if Microsoft has been advised of the possibility of such damages.
18 | #>
19 |
20 | function SetSchedule {
21 | param(
22 | [Parameter(Mandatory=$true)]
23 | [string]$startTime,
24 | [Parameter(Mandatory=$true)]
25 | [array]$group,
26 | [Parameter(Mandatory=$true)]
27 | [string]$resourceGroup,
28 | [Parameter(Mandatory=$true)]
29 | [string]$automationAccount,
30 | [Parameter(Mandatory=$true)]
31 | [string]$DaysofMonth,
32 | [Parameter(Mandatory=$true)]
33 | [int]$durationHours,
34 | [Parameter(Mandatory=$false)]
35 | [int]$monthInterval,
36 | [Parameter(Mandatory=$true)]
37 | [string]$scheduleName
38 | )
39 |
40 | $duration = New-TimeSpan -Hours $durationHours
41 | $schedule = New-AzAutomationSchedule -ResourceGroupName $resourceGroup `
42 | -AutomationAccountName $automationAccount `
43 | -Name $scheduleName `
44 | -StartTime $startTime `
45 | -DaysOfMonth $DaysofMonth `
46 | -MonthInterval $monthInterval `
47 | -ForUpdateConfiguration
48 |
49 | New-AzAutomationSoftwareUpdateConfiguration -ResourceGroupName $resourceGroup `
50 | -AutomationAccountName $automationAccount `
51 | -Schedule $schedule `
52 | -Linux `
53 | -NonAzureComputer $group `
54 | -IncludedPackageClassification Critical `
55 | -Duration $duration
56 | }
57 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/GroupSchedule/README.md:
--------------------------------------------------------------------------------
1 | PowerShell Scripts - Explained
2 | 1) 01-SvrGrping.ps1 - An example script of how to group servers based upon a .csv input. Potentially helpful in the event
3 | of a company not using WSUS or ADDS for server grouping.
4 | 2) 02-WinSvrSched.ps1 - Using variables from the 01-SvrGrping.ps1 script, schedule an Azure Automation runbook job with a
5 | corresponding patch schedule for Windows Servers using the new PowerShell preview cmdlets
6 | (New-AzureRmAutomationSoftwareUpdateConfiguration).
7 | 3) 03-LinuxSvrSched.ps1 - Using variables from the 01-SvrGrping.ps1 script, schedule an Azure Automation runbook job with a
8 | corresponding patch schedule for Linux servers, using the new PowerShell preview cmdlets
9 | (New-AzureRmAutomationSoftwareUpdateConfiguration).
10 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/UpdateAgentReadiness/01-BearerToken.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2018.12.20
4 | Shannon Kuehn
5 | Last Updated
6 | © 2018 Microsoft Corporation.
7 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
8 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
9 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
10 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
11 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
12 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
13 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
14 | documentation, even if Microsoft has been advised of the possibility of such damages.
15 | #>
16 | # Adapted from:
17 | # https://www.codeisahighway.com/how-to-easily-and-silently-obtain-accesstoken-bearer-from-an-existing-azure-powershell-session/
18 |
19 | function Get-AzureRmCachedAccessToken()
20 | {
21 | $ErrorActionPreference = 'Stop'
22 |
23 | if(-not (Get-Module AzureRm.Profile)) {
24 | Import-Module AzureRm.Profile
25 | }
26 | $azureRmProfileModuleVersion = (Get-Module AzureRm.Profile).Version
27 | # refactoring performed in AzureRm.Profile v3.0 or later
28 | if($azureRmProfileModuleVersion.Major -ge 3) {
29 | $azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
30 | if(-not $azureRmProfile.Accounts.Count) {
31 | Write-Error "Ensure you have logged in before calling this function."
32 | }
33 | } else {
34 | # AzureRm.Profile < v3.0
35 | $azureRmProfile = [Microsoft.WindowsAzure.Commands.Common.AzureRmProfileProvider]::Instance.Profile
36 | if(-not $azureRmProfile.Context.Account.Count) {
37 | Write-Error "Ensure you have logged in before calling this function."
38 | }
39 | }
40 |
41 | $currentAzureContext = Get-AzureRmContext
42 | $profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azureRmProfile)
43 | Write-Debug ("Getting access token for tenant" + $currentAzureContext.Subscription.TenantId)
44 | $token = $profileClient.AcquireAccessToken($currentAzureContext.Subscription.TenantId)
45 | $token.AccessToken
46 | }
47 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/UpdateAgentReadiness/02-UpdateAgentReadiness.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | Created
3 | 2018.12.20
4 | Shannon Kuehn
5 |
6 | Last Updated
7 | 2019.07.08
8 |
9 | © 2018 Microsoft Corporation.
10 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
11 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
12 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
13 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
14 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
15 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
16 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
17 | documentation, even if Microsoft has been advised of the possibility of such damages.
18 | #>
19 |
20 | # Fill in local path, Azure subscription ID, resource group, and automation account.
21 | $path = "Local or server file path goes here"
22 | $subId = "Azure subscription ID goes here"
23 | $rg = "Resource Group name goes here"
24 | $automationAccount = "{automation account}"
25 | $bearer = Get-AzureRmCachedAccessToken
26 | $header = @{"Authorization"="Bearer $bearer"}
27 | $hybridWorkerGroups = Get-AzureRmAutomationHybridWorkerGroup -ResourceGroupName $rg -AutomationAccountName $automationAccount
28 | $csv = "MachineName,State,LastSeenTime`r`n"
29 | $file = New-Object -ComObject Scripting.FileSystemObject
30 | $csvFile = $file.CreateTextFile($path,$true)
31 | $csvFile.Write($csv)
32 | $csvFile.Close()
33 |
34 | ForEach($hybridworkerGroup in $hybridWorkerGroups){
35 | $apiCall = "https://management.azure.com/subscriptions/"+$subId+"/resourceGroups/"+$rg+"/providers/Microsoft.Automation/automationAccounts/"+$automationAccount+"/hybridRunbookWorkerGroups/"+$hybridWorkerGroup.Name+"?api-version=2015-10-31"
36 | $invokeStatus = (Invoke-WebRequest -Uri $apiCall -Headers $header -Method Get)
37 | $state = ""
38 | $lastSeenTime = ""
39 | if($invokeStatus.StatusCode -eq 200)
40 | {
41 | $invokeVar = Invoke-RestMethod -Uri $apiCall -Headers $header -Method Get
42 | $lastSeenDate = Get-Date -Date $invokeVar.hybridRunbookWorkers[0].lastSeenDateTime
43 | $diffTimeSpan = (Get-Date) - $lastSeenDate
44 | if($diffTimeSpan.Hours -gt 1)
45 | {
46 | $state = "disconnected"
47 | }
48 | else {
49 | $state = "ready"
50 | }
51 | }
52 | elseif($invokeStatus.StatusCode -eq 404)
53 | {
54 | $state = "not configured"
55 | }
56 | else
57 | {
58 | $state = "error"
59 | }
60 | $lastSeenTime = $hybridworkerGroup.RunbookWorker.LastSeenDateTime.LocalDateTime.ToShortDateString()+ " " + $hybridworkerGroup.RunbookWorker.LastSeenDateTime.LocalDateTime.ToLongTimeString()
61 | Add-Content $path "$($hybridworkerGroup.RunbookWorker.Name),$state,$lastSeenTime"
62 | }
63 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/PowerShell/UpdateAgentReadiness/README.md:
--------------------------------------------------------------------------------
1 | Update Agent Readiness - Explained:
2 | In the portal, the Update Agent Readiness column data is lazy-loaded. Azure checks readiness of every machine individually using the following REST API .
3 | Update Agent Readiness - GET Calls:
4 | The update readiness metric solely checks if the patch agent (System HybridWorker) is registered and actively pinging. Each response code (Ready, Disconnected, Not configured) denotes a specific readiness state within the column.
5 | 1) Not Configured - the GET call resolves to 404.
6 | 2) Disconnected - The GET call resolves to 200, but lastSeen property value (related to ping time) is older than an hour ago.
7 | 3) Ready - The GET call resolves to 200 and the lastSeen property is less than an hour ago.
8 | UpdateAgentReadiness Instructions:
9 | 1) Run the 01-BearerToken.ps1 while logged into Azure PowerShell with an active account and pointed at the working sub.
10 | 2) The 01-BearerToken.ps1 loads the actual Bearer Token into memory. This gets called upon in the UpdateAgentReadiness.ps1
11 | script by way of using Get-AzureRmCachedAccessToken.
12 | 3) The 02-UpdateAgentReadiness.ps1 script will output all servers checked into Update Management inside 1 .csv file. Having
13 | this information will be helpful if grouping servers within a patch group. If the server reports as "Not configured" or
14 | "Disconnected," the patching fails.
15 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/README.md:
--------------------------------------------------------------------------------
1 | # Update Management
2 |
3 | Sample Code and Documentation to Assist Deployment and Management of On-Premises and AWS Servers
4 |
5 | Microsoft Documentation :
6 | Azure Rm Automation Schedule
7 | Azure Rm Automation Software Update Configuration
8 | General Troubleshooting : 1) Ensure Azure Az PowerShell module is completely up to date. 2) Troubleshoot Update Agent Readiness: Not Configured
9 | Troubleshooting MMA Agent :
10 | Windows Troubleshooting
11 | Linux Troubleshooting
12 | Troubleshoot Hybrid Runbook Worker
13 | Windows Troubleshooter Tool
14 | Linux Troubleshooter Tool
15 | General Information :
16 | 1) As of January 2019, patch groups are limited to 500 servers. If there are more than 500 servers, customers will need to divide into multiple groups.
17 | 2) If WSUS is involved with the deployment, Windows looks to WSUS as the control plane with excluded and included patches.
18 | 3) Standalone WSUS works well, even if there is a substantial amount of Windows machines.
19 | 4) Pay attention to the total number of nodes if using an OMS Gateway. If servers cannot be assessed in the portal underneath Update Management and telneting to the machines over appropriate ports (default is 8081) does not work, plan to build out another OMS Gateway and use a load balancer. The easiest way to course correct is to assign a new static IP address to the first OMS Gateway, assign a new static IP address to the second OMS Gateway, and use the static IP of the first OMS Gateway as your VIP on the load balancer. You will not need to adjust the deployment on all servers' MMA configurations this way.
20 |
21 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/WSUS Deployment/README.md:
--------------------------------------------------------------------------------
1 | Additional WSUS Deployment Reference Documentation :
2 | Deploy Windows Server Update Services
3 | Plan Your WSUS Deployment
4 |
--------------------------------------------------------------------------------
/sample-UpdateManagement/WSUS Deployment/WSUS30SP2DeployGuide.doc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/sample-UpdateManagement/WSUS Deployment/WSUS30SP2DeployGuide.doc
--------------------------------------------------------------------------------
/sample-UpdateManagement/WSUS Deployment/WSUS30SP2DeployGuide.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/csa-misc-utils/6108d2fcbc9025555929d8ff4dde36b9ebd44d96/sample-UpdateManagement/WSUS Deployment/WSUS30SP2DeployGuide.pdf
--------------------------------------------------------------------------------
/sample-VMSS-DomainJoin-Arm/README.md:
--------------------------------------------------------------------------------
1 | ## Azure ARM Samples -- VMSS with a domain join
2 |
3 | I was recently working with a customer who needed to create VMs on-demand that were domain joined to complete HPC compute operations. This is an example template highlighting how to create VM Scale Set instances from a template pointing to a 'golden image' as a source and domain joining each VM spun up.
4 |
5 | Note: The source image must reside in the same region as the VM Scale Sets for this to function. The source image can reside in a different resource group; as there are parameters for both the source image and resource group as well as the name of an existing Virtual Network and subnet to deploy each instance into.
6 |
7 |
8 | * [VMSS Example](./WindowsVirtualMachineScaleSet_DomainJoin.json).
9 | The example ARM template
10 |
11 |
--------------------------------------------------------------------------------
/sample-VMSS-DomainJoin-Arm/WindowsVirtualMachineScaleSet.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "vmssName": {
6 | "value": null
7 | },
8 | "instanceCount": {
9 | "value": 1
10 | },
11 | "adminUsername": {
12 | "value": "user"
13 | },
14 | "adminPassword": {
15 | "value": "Pass"
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/sample-k8sRefArch/README.md:
--------------------------------------------------------------------------------
1 | Created
2 | 2019.07.05
3 | Shannon Kuehn
4 |
5 | © 2019 Microsoft Corporation.
6 | All rights reserved. Sample scripts/code provided herein are not supported under any Microsoft standard support program
7 | or service. The sample scripts/code are provided AS IS without warranty of any kind. Microsoft disclaims all implied
8 | warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
9 | The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event
10 | shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for
11 | any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of
12 | business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or
13 | documentation, even if Microsoft has been advised of the possibility of such damages.
14 |
15 | # Infrastructure as Code
16 | Reference Architecture
17 | Azure Kubernetes Service (AKS) - Azure CNI Plugin
18 | Files/Folders for this Repository:
19 | 1) **README.md** - markdown file that contains all information for repo (files, folders, steps).
20 | 2) **setup folder** - general setup information (Azure CLI, PowerShell, generating ssh keys, setting up Service Principal)
21 | 3) **keyVault folder** - code to set up a Key Vault for public SSH keys, Service Principal secret, and SSL cert password.
22 | 4) **k8s folder** - base template and yaml files for secure, managed K8s cluster on Azure.
23 | 5) **appGw folder** - takes the k8s configuration files and adds an Application Gateway.
24 | 6) **apim-appGw folder** - takes the k8s configuration files and adds an API Management Gateway + Application Gateway.
25 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/apim-appGw/README.md:
--------------------------------------------------------------------------------
1 | # Application Gateway and API Management Gateway
2 | Getting to this folder means you started with the setup, keyVault, and k8s folders. By the point you reach this folder, you should have a public SSH key stored in Key Vault, a Service Principal with it's secret stored in Key Vault, a VNet, and a K8s cluster with an internal ingress controller. In the event you do not have that set up, please ensure you start with the setup and keyVault folders. The K8s template and yaml files within this folder will also generate the same AKS setup so you can add an API Management Gateway and Application Gateway. The API Management Gateway will publish a health check API that serves as an echo service to itself so the Application Gateway backend health can report as "healthy."
3 |
4 | **Deployment Notes**
5 | There are a few additional files in this folder:
6 | 1) **appGwApimDeploy.json** - this is the deployment ARM template for both the Application Gateway and the API Management Gateway. The APIM is set as internal and the healthcheck API code is configured as an API, an API operation, and an API policy. The end configuration has a custom healthcheck API exposed on the APIM that allows the Application Gateway's backends to report as healthy.
7 | 2) **appGwApimParams.json** - these are the parameters for the Application Gateway and APIM deployment.
8 |
9 | **Information on K8s Configuration**
10 | Within this folder, you will find the following files:
11 |
12 | 1) **aksDeploy.json** - ARM template that deploys the Kubernetes cluster. This file declares all the Kubernetes cluster, which comprises of deploying nodes (VMs), nics, the Availability Set, and the NSG. Additional comments:
13 | - This deployment does not deploy a public load balancer.
14 | - This deployment reports to an existing Log Analytics workspace.
15 |
16 | 2) **aksParams.json** - this is the parameters file for the ARM template deployment. Future deployments can be conducted by editing these parameters first adn re-deploying.
17 |
18 | 3) **kubectl-helm-commands.md** - this file guides you on how to connect to your Kubernetes cluster, create a namespace, create a Tiller service account for helm, install helm, and create an internal ingress controller for your Kubernetes cluster.
19 |
20 | 4) **helm-rbac.yaml** - this is the file to run while connected to your Kubernetes cluster so you can create the Tiller service account for helm.
21 |
22 | 5) **ingress-internal.yaml** - this is the file to use for your larger helm command to install an nginx internal ingress controller.
23 |
24 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/apim-appGw/aksParams.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "spAppId": {
6 | "value": "e1ce23e5-4c4e-4aa0-ad39-7d945f6695c3"
7 | },
8 | "spObjectId": {
9 | "value": "eb8e6c40-2735-43a7-a68e-0e127a14d80b"
10 | },
11 | "spSecret": {
12 | "reference": {
13 | "keyVault": {
14 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
15 | },
16 | "secretName": "spPw"
17 | }
18 | },
19 | "rgName": {
20 | "value": "k8s"
21 | },
22 | "vnetName": {
23 | "value": "k8sVnet"
24 | },
25 | "vnetTag": {
26 | "value": "AKS vNet"
27 | },
28 | "vnetAddrPrefix": {
29 | "value": "10.10.0.0/16"
30 | },
31 | "sub1Name": {
32 | "value": "k8sCluster"
33 | },
34 | "sub1Prefix": {
35 | "value": "10.10.1.0/24"
36 | },
37 | "sub2Name": {
38 | "value": "k8sServices"
39 | },
40 | "sub2Prefix": {
41 | "value": "10.10.2.0/24"
42 | },
43 | "logAnalyticsWorkspaceId": {
44 | "value": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourcegroups/sbk-la/providers/microsoft.operationalinsights/workspaces/sbk-log-analytics-25924"
45 | },
46 | "aksClusterName": {
47 | "value": "k8s"
48 | },
49 | "dnsPrefix": {
50 | "value": "k8ssbk"
51 | },
52 | "k8sVersion": {
53 | "value": "1.12.8"
54 | },
55 | "nodeCount": {
56 | "value": 3
57 | },
58 | "nodeVmSize": {
59 | "value": "Standard_DS1_v2"
60 | },
61 | "osType": {
62 | "value": "Linux"
63 | },
64 | "osAdminUser": {
65 | "value": "sbkadmin"
66 | },
67 | "sshPubKey": {
68 | "reference": {
69 | "keyVault": {
70 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
71 | },
72 | "secretName": "k8sSsh"
73 | }
74 | },
75 | "maxPods": {
76 | "value": 31
77 | },
78 | "enableHttpApplicationRouting": {
79 | "value": false
80 | },
81 | "networkPlugin": {
82 | "value": "azure"
83 | },
84 | "enableRBAC": {
85 | "value": true
86 | },
87 | "serviceCidr": {
88 | "value": "10.0.0.0/16"
89 | },
90 | "dnsServiceIP": {
91 | "value": "10.0.0.10"
92 | },
93 | "dockerBridgeCidr": {
94 | "value": "172.17.0.1/16"
95 | },
96 | "aksEnv": {
97 | "value": "k8s"
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/apim-appGw/appGwApimParams.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "existingVNETName": {
6 | "value": "k8sVnet"
7 | },
8 | "newSubnetName1": {
9 | "value": "appGw"
10 | },
11 | "newSubnetAddressPrefix1": {
12 | "value": "10.10.3.0/24"
13 | },
14 | "newSubnetName2": {
15 | "value": "apim"
16 | },
17 | "newSubnetAddressPrefix2": {
18 | "value": "10.10.4.0/24"
19 | },
20 | "publisherEmail": {
21 | "value": "Shannon.Kuehn@microsoft.com"
22 | },
23 | "publisherName": {
24 | "value": "Microsoft"
25 | },
26 | "frontendCertData": {
27 | "reference": {
28 | "keyVault": {
29 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
30 | },
31 | "secretName": "wildcardsslcert"
32 | }
33 | },
34 | "sslCertificatePassword": {
35 | "reference": {
36 | "keyVault": {
37 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
38 | },
39 | "secretName": "sslcertpw"
40 | }
41 | },
42 | "appGtwyName": {
43 | "value": "k8s"
44 | },
45 | "appGtwySize": {
46 | "value": "WAF_Medium"
47 | },
48 | "appGtwyCapacity": {
49 | "value": 1
50 | },
51 | "appGatewayRuleName1": {
52 | "value": "appGwRule1"
53 | },
54 | "appGatewayRuleName2": {
55 | "value": "appGwRule2"
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/apim-appGw/helm-rbac.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: tiller
5 | namespace: kube-system
6 | ---
7 | apiVersion: rbac.authorization.k8s.io/v1
8 | kind: ClusterRoleBinding
9 | metadata:
10 | name: tiller
11 | roleRef:
12 | apiGroup: rbac.authorization.k8s.io
13 | kind: ClusterRole
14 | name: cluster-admin
15 | subjects:
16 | - kind: ServiceAccount
17 | name: tiller
18 | namespace: kube-system
19 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/apim-appGw/ingress-internal.yaml:
--------------------------------------------------------------------------------
1 | controller:
2 | service:
3 | loadBalancerIP: 10.10.1.200
4 | annotations:
5 | service.beta.kubernetes.io/azure-load-balancer-internal: "true"
6 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/apim-appGw/kubectl-helm-commands.md:
--------------------------------------------------------------------------------
1 | ## kubectl and helm commands
2 |
3 |
4 | Connect and Configure Internal Ingress Controller for K8s:
5 |
6 | az aks get-credentials --name k8sSecure --resource-group k8sSecure
7 | Merged "k8sSecure" as current context in /Users/username/.kube/config
8 |
9 | kubectl apply -f ingress-internal-l.yaml
10 | kubectl get service secure-k8s
11 |
12 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
13 | internal-app LoadBalancer 10.0.248.59 10.10.1.200 80:30555/TCP 2m
14 |
15 | Create namespace internal-ingress
16 |
17 | kubectl create namespace internal-ingress
18 |
19 | Install Helm Locally or via Cloud Shell (then use helm-rbac.yaml file from repo for next step)
20 |
21 | kubectl apply -f helm-rbac.yaml
22 | helm init \
23 | --service-account tiller \
24 | --node-selectors "beta.kubernetes.io/os"="linux"
25 |
26 | Use Helm to Deploy a NGINX Ingress Controller (use ingress-internal.yaml file in repo)
27 |
28 | helm install stable/nginx-ingress \
29 | --namespace internal-ingress \
30 | -f ingress-internal.yaml \
31 | --set controller.replicaCount=2 \
32 | --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \
33 | --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux
34 |
35 | kubectl get service -l app=nginx-ingress --namespace internal-ingress
36 |
37 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORTS AGE
38 | alternating-coral-nginx-ingress-controller LoadBalancer 10.0.248.59 10.10.1.200 80:31507/TCP,443:30707/TCP 1m
39 | alternating-coral-nginx-ingress-default-backend ClusterIP 10.0.134.66 80/TCP 1m
40 |
41 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/appGw/README.md:
--------------------------------------------------------------------------------
1 | # Application Gateway
2 | Getting to this folder means you started with the setup, keyVault, and k8s folders. By the point you reach this folder, you should have a public SSH key stored in Key Vault, a Service Principal with secret stored in Key Vault, a VNet, and a K8s cluster with an internal ingress controller. In the event you do not have that set up, please ensure you start with the setup and keyVault folders. The files K8s within this folder will also generate the same AKS setup so you can add an Application Gateway. The difference between this folder and the k8s folder is you will create an echo api service on your cluster.
3 |
4 | **Deployment Notes**
5 | There are a few additional files in this folder:
6 | 1) **echo-api.yaml** - once the K8s cluster is deployed, apply this yaml file to the K8s cluster by running kubectl apply -f echo-api.yaml (as is, no adjustments). The yaml file has already been adjusted from an internal ingress GitHub sample repo, located here . The major tweaks to this yaml file are related to removing the auth headers from the original. Deploying the echo service allows the Application Gateway to use a custom probe for backend health reporting.
7 | 2) **appGwDeploy.json** - this is the ARM template that adds an Application Gateway to the final deployment. The SSL cert password needs to be passed as a string vs. a secure string. There is a custom probe that leans on an echo service you deploy prior to deploying the Application Gateway.
8 | 3) **appGwParams.json** - this is the parameters file for the ARM template deployment.
9 | Deploying all 3 files will add an Application Gateway to your existing internal K8s cluster. The Application Gateway will have a public IP address, have WAF enabled, and WAF rules are configured for deployment. All configurations can be adjusted to fit your deployment requirements.
10 |
11 | **Information on K8s Configuration**
12 | Within this folder, you will find the following files:
13 |
14 | 1) **aksDeploy.json** - ARM template that deploys the Kubernetes cluster. This file declares all the Kubernetes cluster, which comprises of deploying nodes (VMs), nics, the Availability Set, and the NSG. Additional comments:
15 | - This deployment does not deploy a public load balancer.
16 | - This deployment reports to an existing Log Analytics workspace.
17 |
18 | 2) **aksParams.json** - this is the parameters file for the ARM template deployment. Future deployments can be conducted by editing these parameters first adn re-deploying.
19 |
20 | 3) **kubectl-helm-commands.md** - this file guides you on how to connect to your Kubernetes cluster, create a namespace, create a Tiller service account for helm, install helm, and create an internal ingress controller for your Kubernetes cluster.
21 |
22 | 4) **helm-rbac.yaml** - this is the file to run while connected to your Kubernetes cluster so you can create the Tiller service account for helm.
23 |
24 | 5) **ingress-internal.yaml** - this is the file to use for your larger helm command to install an nginx internal ingress controller.
25 |
26 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/appGw/aksParams.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "spAppId": {
6 | "value": "e1ce23e5-4c4e-4aa0-ad39-7d945f6695c3"
7 | },
8 | "spObjectId": {
9 | "value": "eb8e6c40-2735-43a7-a68e-0e127a14d80b"
10 | },
11 | "spSecret": {
12 | "reference": {
13 | "keyVault": {
14 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
15 | },
16 | "secretName": "spPw"
17 | }
18 | },
19 | "rgName": {
20 | "value": "k8s"
21 | },
22 | "vnetName": {
23 | "value": "k8sVnet"
24 | },
25 | "vnetTag": {
26 | "value": "AKS vNet"
27 | },
28 | "vnetAddrPrefix": {
29 | "value": "10.10.0.0/16"
30 | },
31 | "sub1Name": {
32 | "value": "k8sCluster"
33 | },
34 | "sub1Prefix": {
35 | "value": "10.10.1.0/24"
36 | },
37 | "sub2Name": {
38 | "value": "k8sServices"
39 | },
40 | "sub2Prefix": {
41 | "value": "10.10.2.0/24"
42 | },
43 | "logAnalyticsWorkspaceId": {
44 | "value": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourcegroups/sbk-la/providers/microsoft.operationalinsights/workspaces/sbk-log-analytics-25924"
45 | },
46 | "aksClusterName": {
47 | "value": "k8s"
48 | },
49 | "dnsPrefix": {
50 | "value": "k8ssbk"
51 | },
52 | "k8sVersion": {
53 | "value": "1.12.8"
54 | },
55 | "nodeCount": {
56 | "value": 3
57 | },
58 | "nodeVmSize": {
59 | "value": "Standard_DS1_v2"
60 | },
61 | "osType": {
62 | "value": "Linux"
63 | },
64 | "osAdminUser": {
65 | "value": "sbkadmin"
66 | },
67 | "sshPubKey": {
68 | "reference": {
69 | "keyVault": {
70 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
71 | },
72 | "secretName": "k8sSsh"
73 | }
74 | },
75 | "maxPods": {
76 | "value": 31
77 | },
78 | "enableHttpApplicationRouting": {
79 | "value": false
80 | },
81 | "networkPlugin": {
82 | "value": "azure"
83 | },
84 | "enableRBAC": {
85 | "value": true
86 | },
87 | "serviceCidr": {
88 | "value": "10.0.0.0/16"
89 | },
90 | "dnsServiceIP": {
91 | "value": "10.0.0.10"
92 | },
93 | "dockerBridgeCidr": {
94 | "value": "172.17.0.1/16"
95 | },
96 | "aksEnv": {
97 | "value": "k8s"
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/appGw/appGwParams.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "existingVNETName": {
6 | "value": "k8sVnet"
7 | },
8 | "newSubnetName": {
9 | "value": "appGw"
10 | },
11 | "newSubnetAddressPrefix": {
12 | "value": "10.10.3.0/24"
13 | },
14 | "frontendCertData": {
15 | "reference": {
16 | "keyVault": {
17 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
18 | },
19 | "secretName": "wildcardsslcert"
20 | }
21 | },
22 | "sslCertificatePassword": {
23 | "reference": {
24 | "keyVault": {
25 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
26 | },
27 | "secretName": "sslcertpw"
28 | }
29 | },
30 | "appGtwyName": {
31 | "value": "k8s"
32 | },
33 | "appGtwySize": {
34 | "value": "WAF_Medium"
35 | },
36 | "appGtwyCapacity": {
37 | "value": 1
38 | },
39 | "appGatewayRuleName1": {
40 | "value": "appGwRule1"
41 | },
42 | "appGatewayRuleName2": {
43 | "value": "appGwRule2"
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/appGw/echo-api.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: extensions/v1beta1
2 | kind: Deployment
3 | metadata:
4 | name: demo-echo-service
5 | labels:
6 | k8s-app: demo-echo-service
7 | namespace: default
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | k8s-app: demo-echo-service
13 | template:
14 | metadata:
15 | labels:
16 | k8s-app: demo-echo-service
17 | spec:
18 | terminationGracePeriodSeconds: 60
19 | containers:
20 | - name: echo-service
21 | image: electroma/ingress-demo-echosvc-amd64:0.1
22 | ports:
23 | - containerPort: 8080
24 | resources:
25 | limits:
26 | cpu: 10m
27 | memory: 20Mi
28 | requests:
29 | cpu: 10m
30 | memory: 20Mi
31 | ---
32 | apiVersion: v1
33 | kind: Service
34 | metadata:
35 | name: demo-echo-service
36 | labels:
37 | k8s-app: demo-echo-service
38 | namespace: default
39 | spec:
40 | ports:
41 | - port: 80
42 | targetPort: 8080
43 | selector:
44 | k8s-app: demo-echo-service
45 | ---
46 | apiVersion: extensions/v1beta1
47 | kind: Ingress
48 | metadata:
49 | name: public-demo-echo-service
50 | namespace: default
51 | spec:
52 | rules:
53 | - host: public-demo-echo-service.kube.local
54 | http:
55 | paths:
56 | - backend:
57 | serviceName: demo-echo-service
58 | servicePort: 80
59 | path: /
60 | ---
61 | apiVersion: extensions/v1beta1
62 | kind: Ingress
63 | metadata:
64 | name: secure-demo-echo-service
65 | namespace: default
66 | spec:
67 | rules:
68 | - host: secure-demo-echo-service.kube.local
69 | http:
70 | paths:
71 | - backend:
72 | serviceName: demo-echo-service
73 | servicePort: 80
74 | path: /
75 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/appGw/helm-rbac.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: tiller
5 | namespace: kube-system
6 | ---
7 | apiVersion: rbac.authorization.k8s.io/v1
8 | kind: ClusterRoleBinding
9 | metadata:
10 | name: tiller
11 | roleRef:
12 | apiGroup: rbac.authorization.k8s.io
13 | kind: ClusterRole
14 | name: cluster-admin
15 | subjects:
16 | - kind: ServiceAccount
17 | name: tiller
18 | namespace: kube-system
19 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/appGw/ingress-internal.yaml:
--------------------------------------------------------------------------------
1 | controller:
2 | service:
3 | loadBalancerIP: 10.10.1.200
4 | annotations:
5 | service.beta.kubernetes.io/azure-load-balancer-internal: "true"
6 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/appGw/kubectl-helm-commands.md:
--------------------------------------------------------------------------------
1 | ## kubectl and helm commands
2 |
3 |
4 | Connect and Configure Internal Ingress Controller for K8s:
5 |
6 | az aks get-credentials --name k8sSecure --resource-group k8sSecure
7 | Merged "k8sSecure" as current context in /Users/username/.kube/config
8 |
9 | kubectl apply -f ingress-internal-l.yaml
10 | kubectl get service secure-k8s
11 |
12 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
13 | internal-app LoadBalancer 10.0.248.59 10.10.1.200 80:30555/TCP 2m
14 |
15 | Create namespace internal-ingress
16 |
17 | kubectl create namespace internal-ingress
18 |
19 | Install Helm Locally or via Cloud Shell (then use helm-rbac.yaml file from repo for next step)
20 |
21 | kubectl apply -f helm-rbac.yaml
22 | helm init \
23 | --service-account tiller \
24 | --node-selectors "beta.kubernetes.io/os"="linux"
25 |
26 | Use Helm to Deploy a NGINX Ingress Controller (use ingress-internal.yaml file in repo)
27 |
28 | helm install stable/nginx-ingress \
29 | --namespace internal-ingress \
30 | -f ingress-internal.yaml \
31 | --set controller.replicaCount=2 \
32 | --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux
33 | --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux
34 |
35 | kubectl get service -l app=nginx-ingress --namespace internal-ingress
36 |
37 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORTS AGE
38 | alternating-coral-nginx-ingress-controller LoadBalancer 10.0.248.59 10.10.1.200 80:31507/TCP,443:30707/TCP 1m
39 | alternating-coral-nginx-ingress-default-backend ClusterIP 10.0.134.66 80/TCP 1m
40 |
41 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/k8s/README.md:
--------------------------------------------------------------------------------
1 | # Deploying a Kubernetes Cluster in Azure
2 | Getting to this folder means you started with the setup and keyVault folders. In order to deploy this cluster, you need a service principal in AAD and a public SSH key. Between the setup and keyVault folder, you should have generated a service principal, generated a public SSH key, created a Key Vault, and stored both of those secrets to reference within the template.
3 |
4 | **Information on K8s Configuration**
5 | Within this folder, you will find the following files:
6 |
7 | 1) **aksDeploy.json** - ARM template that deploys the Kubernetes cluster. This file declares all the Kubernetes cluster, which comprises of deploying nodes (VMs), nics, the Availability Set, and the NSG. Additional comments:
8 | - This deployment deploys a private load balancer as an nginx ingress controller.
9 | - This deployment reports to an existing Log Analytics workspace.
10 |
11 | 2) **aksParams.json** - this is the parameters file for the ARM template deployment. Future deployments can be conducted by editing these parameters first and then re-deploying.
12 |
13 | 3) **kubectl-helm-commands.md** - this file guides you on how to connect to your Kubernetes cluster, create a namespace, create a Tiller service account for helm, install helm, and create an internal ingress controller for your Kubernetes cluster.
14 |
15 | 4) **helm-rbac.yaml** - this is the file to run while connected to your Kubernetes cluster so you can create the Tiller service account for helm.
16 |
17 | 5) **ingress-internal.yaml** - this is the file to use for your larger helm command to install an nginx internal ingress controller.
18 |
19 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/k8s/aksParams.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "spAppId": {
6 | "value": "e1ce23e5-4c4e-4aa0-ad39-7d945f6695c3"
7 | },
8 | "spObjectId": {
9 | "value": "eb8e6c40-2735-43a7-a68e-0e127a14d80b"
10 | },
11 | "spSecret": {
12 | "reference": {
13 | "keyVault": {
14 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
15 | },
16 | "secretName": "spPw"
17 | }
18 | },
19 | "rgName": {
20 | "value": "k8s"
21 | },
22 | "vnetName": {
23 | "value": "k8sVnet"
24 | },
25 | "vnetTag": {
26 | "value": "AKS vNet"
27 | },
28 | "vnetAddrPrefix": {
29 | "value": "10.10.0.0/16"
30 | },
31 | "sub1Name": {
32 | "value": "k8sCluster"
33 | },
34 | "sub1Prefix": {
35 | "value": "10.10.1.0/24"
36 | },
37 | "sub2Name": {
38 | "value": "k8sServices"
39 | },
40 | "sub2Prefix": {
41 | "value": "10.10.2.0/24"
42 | },
43 | "logAnalyticsWorkspaceId": {
44 | "value": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourcegroups/sbk-la/providers/microsoft.operationalinsights/workspaces/sbk-log-analytics-25924"
45 | },
46 | "aksClusterName": {
47 | "value": "k8s"
48 | },
49 | "dnsPrefix": {
50 | "value": "k8ssbk"
51 | },
52 | "k8sVersion": {
53 | "value": "1.12.8"
54 | },
55 | "nodeCount": {
56 | "value": 3
57 | },
58 | "nodeVmSize": {
59 | "value": "Standard_DS1_v2"
60 | },
61 | "osType": {
62 | "value": "Linux"
63 | },
64 | "osAdminUser": {
65 | "value": "sbkadmin"
66 | },
67 | "sshPubKey": {
68 | "reference": {
69 | "keyVault": {
70 | "id": "/subscriptions/9c29eddd-8897-46b5-b8ca-503e7ba5b463/resourceGroups/keyVault/providers/Microsoft.KeyVault/vaults/kv-6e6dnpt2p5fxi"
71 | },
72 | "secretName": "k8sSsh"
73 | }
74 | },
75 | "maxPods": {
76 | "value": 31
77 | },
78 | "enableHttpApplicationRouting": {
79 | "value": false
80 | },
81 | "networkPlugin": {
82 | "value": "azure"
83 | },
84 | "enableRBAC": {
85 | "value": true
86 | },
87 | "serviceCidr": {
88 | "value": "10.0.0.0/16"
89 | },
90 | "dnsServiceIP": {
91 | "value": "10.0.0.10"
92 | },
93 | "dockerBridgeCidr": {
94 | "value": "172.17.0.1/16"
95 | },
96 | "aksEnv": {
97 | "value": "k8s"
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/k8s/helm-rbac.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: tiller
5 | namespace: kube-system
6 | ---
7 | apiVersion: rbac.authorization.k8s.io/v1
8 | kind: ClusterRoleBinding
9 | metadata:
10 | name: tiller
11 | roleRef:
12 | apiGroup: rbac.authorization.k8s.io
13 | kind: ClusterRole
14 | name: cluster-admin
15 | subjects:
16 | - kind: ServiceAccount
17 | name: tiller
18 | namespace: kube-system
19 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/k8s/ingress-internal.yaml:
--------------------------------------------------------------------------------
1 | controller:
2 | service:
3 | loadBalancerIP: 10.10.1.200
4 | annotations:
5 | service.beta.kubernetes.io/azure-load-balancer-internal: "true"
6 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/k8s/kubectl-helm-commands.md:
--------------------------------------------------------------------------------
1 | ## kubectl and helm commands
2 |
3 |
4 | Connect and Configure Internal Ingress Controller for K8s:
5 |
6 | az aks get-credentials --name k8sSecure --resource-group k8sSecure
7 | Merged "k8sSecure" as current context in /Users/username/.kube/config
8 |
9 | kubectl apply -f ingress-internal-l.yaml
10 | kubectl get service secure-k8s
11 |
12 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
13 | internal-app LoadBalancer 10.0.248.59 10.10.1.200 80:30555/TCP 2m
14 |
15 | Create namespace internal-ingress
16 |
17 | kubectl create namespace internal-ingress
18 |
19 | Install Helm Locally or via Cloud Shell (then use helm-rbac.yaml file from repo for next step)
20 |
21 | kubectl apply -f helm-rbac.yaml
22 | helm init \
23 | --service-account tiller \
24 | --node-selectors "beta.kubernetes.io/os"="linux"
25 |
26 | Use Helm to Deploy a NGINX Ingress Controller (use ingress-internal.yaml file in repo)
27 |
28 | helm install stable/nginx-ingress \
29 | --namespace internal-ingress \
30 | -f ingress-internal.yaml \
31 | --set controller.replicaCount=2 \
32 | --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux
33 | --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux
34 |
35 | kubectl get service -l app=nginx-ingress --namespace internal-ingress
36 |
37 | NAME TYPE CLUSTER-IP EXTERNAL-IP PORTS AGE
38 | alternating-coral-nginx-ingress-controller LoadBalancer 10.0.248.59 10.10.1.200 80:31507/TCP,443:30707/TCP 1m
39 | alternating-coral-nginx-ingress-default-backend ClusterIP 10.0.134.66 80/TCP 1m
40 |
41 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/keyVault/PoSH/createKeyVault.ps1:
--------------------------------------------------------------------------------
1 | # Script Notes
2 | # $subscriptionName is the name of the Azure subscription to install the Key Vault into
3 | # $resourceGroupName is the resource group that will contain the Key Vault to create to contain Key Vault secrets, passwords, and certificates
4 | # $keyVaultName is the name of the Key Vault you are deploying
5 | # $location is the region your Key Vault is deploying to
6 | # $keyVaultAdminUser - Azure AD users or groups that have access to Key Vault
7 |
8 | param(
9 | [Parameter(Mandatory=$true)]
10 | [string] $subscriptionName,
11 | [Parameter(Mandatory=$true)]
12 | [string] $resourceGroupName,
13 | [Parameter(Mandatory=$true)]
14 | [string] $keyVaultName,
15 | [Parameter(Mandatory=$true)]
16 | [string] $location,
17 | [Parameter(Mandatory=$true)]
18 | [string] $keyVaultAdminUser
19 | )
20 |
21 | # Login to Azure
22 | Login-AzAccount
23 |
24 | # Select the appropriate subscription
25 | Select-AzSubscription -SubscriptionName $subscriptionName
26 |
27 | # Make the Key Vault provider is available (commented out - if not registered, uncomment the line below and run in PowerShell):
28 | # Register-AzureRmResourceProvider -ProviderNamespace Microsoft.KeyVault
29 |
30 | # Create the Resource Group
31 | New-AzResourceGroup -Name $resourceGroupName -Location $location
32 |
33 | # Create the Key Vault (enabling it for Disk Encryption, Deployment and Template Deployment)
34 | New-AzKeyVault -VaultName $keyVaultName -ResourceGroupName $resourceGroupName -Location $location `
35 | -EnabledForDiskEncryption -EnabledForDeployment -EnabledForTemplateDeployment
36 |
37 | # Add the Administrator policies to the Key Vault
38 | $ObjectId = (Get-AzADUser -UserPrincipalName $keyVaultAdminUser).Id
39 |
40 | # Set access policy for Key Vault
41 | Set-AzKeyVaultAccessPolicy -VaultName $keyVaultName -ResourceGroupName $resourceGroupName -ObjectId $ObjectId `
42 | -PermissionsToKeys decrypt,encrypt,unwrapKey,wrapKey,verify,sign,get,list,update,create,import,delete,backup,restore,recover,purge `
43 | –PermissionsToSecrets get,list,set,delete,backup,restore,recover,purge `
44 | –PermissionsToCertificates get,list,delete,create,import,update,managecontacts,getissuers,listissuers,setissuers,deleteissuers,manageissuers,recover,purge,backup,restore `
45 | -PermissionsToStorage get,list,delete,set,update,regeneratekey,getsas,listsas,deletesas,setsas,recover,backup,restore,purge
46 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/keyVault/PoSH/generateSecret.ps1:
--------------------------------------------------------------------------------
1 | # Adds an individual secret to Key Vault
2 |
3 | param(
4 | [Parameter(Mandatory=$true)]
5 | [string] $keyVaultName
6 | [Parameter(Mandatory=$true)]
7 | [string] $secretName
8 | )
9 |
10 | Set-AzKeyVaultSecret -VaultName $keyVaultName -Name $secretName -SecretValue (Get-Credential).Password
11 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/keyVault/README.md:
--------------------------------------------------------------------------------
1 | # Key Vault Folder Read Me
2 | The files in these folders walk you through how to set up a Key Vault, either through PowerShel or an ARM Template. In addition, the PoSH folder contains code on how to place a secret into your Key Vault. The purpose of these files is to stand up a Key Vault and add the public SSH key (K8s cluster), Service Principal password, and the SSL cert password (Application Gateway). Building a Key Vault means you are not storing credentials in code and is best practice for any development team.
3 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/keyVault/armTemplate/createKeyVaultParams.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "keyVaultSku": {
6 | "value": "Standard"
7 | },
8 | "enabledForDeployment": {
9 | "value": true
10 | },
11 | "enabledForTemplateDeployment": {
12 | "value": true
13 | },
14 | "enabledForDiskEncryption": {
15 | "value": true
16 | },
17 | "keyPermissions": {
18 | "value": [
19 | "get",
20 | "list",
21 | "update",
22 | "create",
23 | "import",
24 | "delete",
25 | "recover",
26 | "backup",
27 | "restore",
28 | "decrypt",
29 | "encrypt",
30 | "unwrapKey",
31 | "wrapKey",
32 | "verify",
33 | "sign",
34 | "purge"
35 | ]
36 | },
37 | "secretPermissions": {
38 | "value": [
39 | "get",
40 | "list",
41 | "set",
42 | "delete",
43 | "recover",
44 | "backup",
45 | "restore",
46 | "purge"
47 | ]
48 | },
49 | "certificatePermissions": {
50 | "value": [
51 | "get",
52 | "list",
53 | "set",
54 | "delete",
55 | "recover",
56 | "backup",
57 | "restore",
58 | "purge"
59 | ]
60 | },
61 | "tenantId": {
62 | "value": "72f988bf-86f1-41af-91ab-2d7cd011db47"
63 | },
64 | "objectId": {
65 | "value": "67a00545-bee5-4a8e-85ec-9a6595f7f0e0"
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/setup/README.md:
--------------------------------------------------------------------------------
1 | # Setup Folder Read Me
2 | The files in this folder correlate to the overall setup that preps a Kubernetes cluster build. You will walk through how to
3 | generate a Service Principal and generate a public SSH key to build the K8s cluster securely.
4 |
--------------------------------------------------------------------------------
/sample-k8sRefArch/setup/generateSshKeys.md:
--------------------------------------------------------------------------------
1 | **Mac Instructions:**
2 |
3 | Type the following at a terminal prompt:
4 |
5 | ssh-keykgen -t rsa -b 2048
6 |
7 | This starts the key generation process. When you execute this command, the ssh-keygen utility prompts you to indicate where
8 | to store the key. Press the ENTER key to accept the default location. The ssh-keygen utility prompts you for a passphrase. Type in a passphrase. You can also hit the ENTER key to accept the default (no passphrase). However, this is not recommended.
9 |
10 | Your identification has been saved in /Users/yourmacusername/.ssh/id_rsa.
11 | Your public key has been saved in /Users/yourmacusername/.ssh/id_rsa.pub.
12 | The key fingerprint is:
13 | ae:89:72:0b:85:da:5a:f4:7c:1f:c2:43:fd:c6:44:38 yourmacusername@yourmac.local
14 | The key's randomart image is:
15 | +--[ RSA 2048]----+
16 | | |
17 | | . |
18 | | E . |
19 | | . . o |
20 | | o . . S . |
21 | | + + o . + |
22 | |. + o = o + |
23 | | o...o * o |
24 | |. oo.o . |
25 | +-----------------+
26 |
27 | Access your public SSH key by running the following command:
28 |
29 | cat ~/.ssh/id_rsa.pub
30 |
31 | You will save this public SSH key into your Key Vault and use at the time of deployment for your K8s cluster.
32 |
33 | **Windows Instructions:**
34 |
35 | 1) Download PuTTYgen: https://www.ssh.com/ssh/putty/windows/puttygen
36 | 2) Open the PuTTYgen program.
37 | 3) For Type of key to generate, select SSH-2 RSA.
38 | 4) Click the Generate button.
39 | 5) Move your mouse in the area below the progress bar. When the progress bar is full, PuTTYgen generates your key pair.
40 | 6) Type a passphrase in the Key passphrase field. Type the same passphrase in the Confirm passphrase field. You can use a key without a passphrase, but this is not recommended.
41 | 7) Right-click in the text field labeled Public key for pasting into OpenSSH authorized_keys file and choose Select All.
42 | 8) Right-click again in the same text field and choose Copy.
43 | 9) Save this into your Key Vault to use at the time of deployment for your K8s cluster.
44 |
--------------------------------------------------------------------------------