<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DevOps &#8211; Haikos Blog</title>
	<atom:link href="https://www.hertes.net/category/devops/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.hertes.net</link>
	<description>Blog von Haiko Hertes zu allen Themen rund um Microsoft, Cloud und Datacenter</description>
	<lastBuildDate>Tue, 30 Mar 2021 03:20:59 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Deploy multiple ARM templates to Azure using PowerShell and GitHub Actions</title>
		<link>https://www.hertes.net/2020/06/deploy-multiple-arm-templates-to-azure-using-powershell-and-github-actions/</link>
					<comments>https://www.hertes.net/2020/06/deploy-multiple-arm-templates-to-azure-using-powershell-and-github-actions/#respond</comments>
		
		<dc:creator><![CDATA[Haiko]]></dc:creator>
		<pubDate>Thu, 04 Jun 2020 16:23:00 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Actions]]></category>
		<category><![CDATA[ARM]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Pipeline]]></category>
		<category><![CDATA[Script]]></category>
		<category><![CDATA[Template]]></category>
		<category><![CDATA[Workflow]]></category>
		<guid isPermaLink="false">https://www.hertes.net/?p=3929</guid>

					<description><![CDATA[This is kind of an experiment. Usually, I produce all my content in German language, but to see if englisch content is of higher use for the community, I will give it a try&#8230; In the last days, I dealt a lot with GitHub Actions to find out, how it can be used to deploy Azure ARM templates to the cloud. My last &#8222;evolution&#8220; step now &#8211; I was working on this because of the very valuable hint of a collegue &#8211; is able to deploy ARM templates to all 4 available scope levels: Tenant level Management Group level Subscription&#8230;]]></description>
										<content:encoded><![CDATA[
<p><em>This is kind of an experiment. Usually, I produce all my content in German language, but to see if englisch content is of higher use for the community, I will give it a try&#8230;</em></p>



<p>In the last days, I dealt a lot with GitHub Actions to find out, how it can be used to deploy Azure ARM templates to the cloud. My last &#8222;evolution&#8220; step now &#8211; I was working on this because of the very valuable hint of a collegue &#8211; is able to deploy ARM templates to all 4 available scope levels:</p>



<ul class="wp-block-list"><li>Tenant level</li><li>Management Group level</li><li>Subscription level</li><li>Resource Group level</li></ul>



<p>And it also could be used, even when you don&#8217;t use GitHub Actions! But let&#8217;s start from the beginning&#8230;</p>



<span id="more-3929"></span>



<h2 class="wp-block-heading">A brief history of evolution</h2>



<p>In my first appraoch, I have used a simple PowerShell script (based on a Script by Sarah Lean, <a href="https://gist.github.com/weeyin83/81e7a7bf3caf3d0bce787db5d562b47e">https://gist.github.com/weeyin83/81e7a7bf3caf3d0bce787db5d562b47e</a>) to just deploy something to Azure using GitHub Actions. This is fast &amp; simple, but not very flexible.</p>



<p>My second approach took me to the new Azure PowerShell Action, where you can just run PowerShell code from within the GitHub Action:</p>



<p><a href="https://github.com/HaikoHertes/ActionsDemo/blob/master/.github/workflows/DeployARMtoAzure.yml">https://github.com/HaikoHertes/ActionsDemo/blob/master/.github/workflows/DeployARMtoAzure.yml</a></p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="637" src="https://www.hertes.net/wp-content/uploads/2020/06/image-3-1024x637.png" alt="" class="wp-image-3930" srcset="https://www.hertes.net/wp-content/uploads/2020/06/image-3-1024x637.png 1024w, https://www.hertes.net/wp-content/uploads/2020/06/image-3-300x187.png 300w, https://www.hertes.net/wp-content/uploads/2020/06/image-3-768x477.png 768w, https://www.hertes.net/wp-content/uploads/2020/06/image-3.png 1475w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>So I used some small code to deploy an ARM template with its parameters file that both reside in an GitHub repo. This is even more easy to use, but still not very flexible, especially, when it comes to multiple ARM templates. <br><br>You can still find the code and stuff here:<br><a href="https://github.com/HaikoHertes/ActionsDemo">https://github.com/HaikoHertes/ActionsDemo</a></p>



<p>Next step was to deploy just a bunch of Templates with their parameters from a repository to become more flexible. Here I wrote a PowerShell script that does the main work:<br><a href="https://github.com/HaikoHertes/ActionsDemo.v2/blob/master/DeployARMtoAzure.ps1">https://github.com/HaikoHertes/ActionsDemo.v2/blob/master/DeployARMtoAzure.ps1</a><br>This script is then just called from within the GitHub Action:</p>



<p><a href="https://github.com/HaikoHertes/ActionsDemo.v2/blob/master/.github/workflows/DeployARMtoAzure.yml#L27">https://github.com/HaikoHertes/ActionsDemo.v2/blob/master/.github/workflows/DeployARMtoAzure.yml#L27</a></p>



<p>This allready does a good job, so you can fetch everything from here:<br><a href="https://github.com/HaikoHertes/ActionsDemo.v2">https://github.com/HaikoHertes/ActionsDemo.v2</a></p>



<h2 class="wp-block-heading">The final solution</h2>



<p>But then, a colleague of mine gave me an hint on some new options to not just deploy to Resource Group level, but to higher levels as well. And so I spent a day to investigate and re-write my PowerShell script. And now I can offer a script, that does the job! Let me show you&#8230;</p>



<p>You can pick up the script from here:<br><a href="https://github.com/HaikoHertes/ActionsDemo.v3/blob/master/DeployARMtoAzure.ps1">https://github.com/HaikoHertes/ActionsDemo.v3/blob/master/DeployARMtoAzure.ps1</a></p>



<h2 class="wp-block-heading">How the script works</h2>



<p>As it is a little more complex, I want to explain what it does and how it works. The script is divided into 5 major parts:</p>



<ul class="wp-block-list"><li>Setting the variables and defining the functions</li><li>Deploying to Tenant level</li><li>Deploying to Management Group level</li><li>Deploying to Subscription level</li><li>Deploying to Resource Group level</li></ul>



<p>If there are no templates for one of these levels or if their folder does not exist, it will just be skipped.</p>



<p>The script expects a defined folder structure:<br></p>



<figure class="wp-block-image size-large"><img decoding="async" width="455" height="603" src="https://www.hertes.net/wp-content/uploads/2020/06/image-4.png" alt="" class="wp-image-3931" srcset="https://www.hertes.net/wp-content/uploads/2020/06/image-4.png 455w, https://www.hertes.net/wp-content/uploads/2020/06/image-4-226x300.png 226w" sizes="(max-width: 455px) 100vw, 455px" /></figure>



<p>The names of folders and files can be adjusted in the PowerShell Script:<br></p>



<figure class="wp-block-image size-large"><img decoding="async" width="811" height="272" src="https://www.hertes.net/wp-content/uploads/2020/06/image-6.png" alt="" class="wp-image-3933" srcset="https://www.hertes.net/wp-content/uploads/2020/06/image-6.png 811w, https://www.hertes.net/wp-content/uploads/2020/06/image-6-300x101.png 300w, https://www.hertes.net/wp-content/uploads/2020/06/image-6-768x258.png 768w" sizes="(max-width: 811px) 100vw, 811px" /></figure>



<p>After all the variables are set, two functions are declared: GetLocation and GetScop. They are made to fetch the location / region from a given directory&#8217;s location file or return the default location and to fetch the scope of the deployment either from a scope file or the folder name. Both functions will be used in the later deployments. All files allow the usage of comments that start with the hashtag symbol &#8218;#&#8216;.<br></p>



<p>The 4 major parts for the different deployment levels are mostly very similar just with slight differences, thats why I just explain how any of them works.</p>



<p>They first grab all JSON files, that are not in the naming format *parameters.json in any subdirectory (so you can organize your templates by topic or something else and group them into folders). If an order file is given, it will fetch the sorting order from the file (allowing sorting by foldername and filename (default) or filename-only) or just sort by the default order. That way, you can define a deployment order by using proper names for your templates.</p>



<p>Now it will run through the list of templates, getting the scope and location of that templates folder, fetching the tags if any given and then trigger the deployment with any of these Cmdlets, whatever is sufficient for the scope / level:</p>



<ul class="wp-block-list"><li>New-AzTenantDeployment</li><li>New-AzManagementGroupDeployment</li><li>New-AzSubscriptionDeployment</li><li>New-AzResourceGroupDeployment</li></ul>



<p>For a given template ABC.json , it allways expects a ABC.parameters.json file next to the template with the parameters. If no parameters are needed, just provide an empty file.</p>



<p>At the end, all templates in all of the 4 levels are deployed <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h2 class="wp-block-heading">How to use the script</h2>



<p>The script was made to be used with GitHub Actions:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="656" src="https://www.hertes.net/wp-content/uploads/2020/06/image-7-1024x656.png" alt="" class="wp-image-3934" srcset="https://www.hertes.net/wp-content/uploads/2020/06/image-7-1024x656.png 1024w, https://www.hertes.net/wp-content/uploads/2020/06/image-7-300x192.png 300w, https://www.hertes.net/wp-content/uploads/2020/06/image-7-768x492.png 768w, https://www.hertes.net/wp-content/uploads/2020/06/image-7.png 1475w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Here it is just called after repo checkout and Azure login. You can get the stuff from here:<br><a href="https://github.com/HaikoHertes/ActionsDemo.v3/blob/master/.github/workflows/DeployARMtoAzure.yml">https://github.com/HaikoHertes/ActionsDemo.v3/blob/master/.github/workflows/DeployARMtoAzure.yml</a><br><a href="https://github.com/HaikoHertes/ActionsDemo.v3">https://github.com/HaikoHertes/ActionsDemo.v3</a><br><br>It expects the ARM templates in a subfolder &#8222;arm&#8220; within the same repo where the GitHub Action resides.</p>



<p>Be aware that as of today, you need to use ubuntu-20.04 and AzPS 4.1.0 (This is needed for the latest version of the deployment Cmdlets above, and AzPS 4.1.0 is only included in the ubuntu-20.04 container image used by GitHub Actions.</p>



<p>The other option would be to use the script without GitHub Actions and even without any repository. You could just run it locally with a given local folder structure containing the templates and other files. You would just need to add something like</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Connect-AzAccount</p></blockquote>



<p>to do the login. Be aware that you still need Az PS Module version 4.1.0 or higher, which you can install with</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>Install-Module -Name Az -AllowClobber -MinimumVersion 4.1.0</p></blockquote>



<h2 class="wp-block-heading">Setting the proper rights on Azure</h2>



<p>To be able to deploy to Azure, you need a user with proper rights. Especially when using GitHub Actions, it is not recommended to use a regular named user, but service principals. In my video (German language, but it shows eveything on english UI) on YouTube, you can see how to do this:</p>



<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Microsoft Azure ?? Mit GitHub Actions ARM Templates ausrollen" width="500" height="281" src="https://www.youtube.com/embed/TRBw1RyRo_I?start=1238&#038;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption>Start at 20:38 to just see the user account part&#8230;</figcaption></figure>



<p>You will need something like this:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>az ad sp create-for-rbac &#8211;name &#8222;github&#8220; &#8211;role contributor &#8211;scopes /subscriptions/YOUR_SUB_ID &#8211;sdk-auth</p></blockquote>



<p>To be able to deploy to Tenant level, you will need the proper rights on root level. Some types of template also need owner rights, especially wheny you want to deploy role assignments or such. Either adjust the above command or (especially, when the user allready exists), extend the rights with somthing like this:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>az role assignment create &#8211;role &#8222;Owner&#8220; &#8211;assignee &#8222;[USERID]&#8220; &#8211;scope &#8222;/&#8220;</p></blockquote>



<h2 class="wp-block-heading">About the different files that can be used</h2>



<p>There is several files that can be used to control how the script works:</p>



<h4 class="wp-block-heading">arm/DefaultLocation.txt</h4>



<p>This file defines the default location for any deployment, that needs a location to be set outside the ARM template. It also includes a list of all available location names. Treat this file as mandatory.</p>



<h4 class="wp-block-heading">arm/ANY_LEVEL/order.txt</h4>



<p>This file defines the sorting order and therefor the deployment order within that given level. There is two options:<br></p>



<ul class="wp-block-list"><li>SortByFolderName = Sorting by foldernames and then by filenames (default)</li><li>SortByFileName = Folder names are ignored, sorting just by templates filenames</li></ul>



<p>The file is optional; if no order is given through a file, the default order will be by foldername first and then by templates filename.</p>



<h4 class="wp-block-heading">scope.txt next to any template JSON</h4>



<p>By default, the deployment scope (i.e. Subscription ID) is fetched from the templates folder ANY_DEPLOYMENT. If needed (i.e. when you want to deploy multiple folders as seperate groups, but into the same scop), you can provide a scope.txt file instead. In here, give ID or name of the scope, both would work.</p>



<h4 class="wp-block-heading">tags.txt next to any template JSON</h4>



<p>You can provide a tags.txt file with the content like</p>



<p>KEY = VALUE</p>



<p>pairs to set tags right on the deployment.</p>



<h4 class="wp-block-heading">location.txt next to any template JSON</h4>



<p>Next to a template file, you can provide a location.txt file that will set the location for the deployment, if needed. If the template itself sets a location, then templates location will be used. If neither template nor location.txt provide a location, but one is needed, the defaultLocation will be used.</p>



<p>(The names are given as they would be with the parameters I provide with my script; they can be changed)</p>



<h2 class="wp-block-heading">Copyright / legal notice</h2>



<p><strong>Copyright 2020 Haiko Hertes</strong></p>



<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &#8222;Software&#8220;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>



<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>



<p>THE SOFTWARE IS PROVIDED &#8222;AS IS&#8220;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.hertes.net/2020/06/deploy-multiple-arm-templates-to-azure-using-powershell-and-github-actions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Azure Regions / Locations auflisten</title>
		<link>https://www.hertes.net/2020/06/azure-regions-locations-auflisten/</link>
					<comments>https://www.hertes.net/2020/06/azure-regions-locations-auflisten/#respond</comments>
		
		<dc:creator><![CDATA[Haiko]]></dc:creator>
		<pubDate>Wed, 03 Jun 2020 12:42:50 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[CLI]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Location]]></category>
		<category><![CDATA[Region]]></category>
		<category><![CDATA[Regionen]]></category>
		<category><![CDATA[Shell]]></category>
		<guid isPermaLink="false">https://www.hertes.net/?p=3926</guid>

					<description><![CDATA[Immer wieder begegnet mir das Problem, dass ich z.B. für ARM Templates den &#8222;internen&#8220; Namen für eine Azure Region (dann als &#8222;Location&#8220; bezeichnet) brauche. Und immer wieder liefern Suchmaschinen-Anfragen nur die &#8222;Sprechenden Namen&#8220;. Daher hier für mich und den Rest der Welt als kleiner Cheat: Man kann die für den eigenen Tenant verfügbaren Regionen recht leicht mit Hilfe der Azure CLI (z.B. über Azure CloudShell) abfragen: az account list-locations --query "[].{Name:name, DisplayName:displayName}" -o table Regionen und Verfügbarkeitszonen in Azure &#124; Microsoft Docs]]></description>
										<content:encoded><![CDATA[
<p>Immer wieder begegnet mir das Problem, dass ich z.B. für ARM Templates den &#8222;internen&#8220; Namen für eine Azure Region (dann als &#8222;Location&#8220; bezeichnet) brauche. Und immer wieder liefern Suchmaschinen-Anfragen nur die &#8222;Sprechenden Namen&#8220;. Daher hier für mich und den Rest der Welt als kleiner Cheat:</p>


<p><span id="more-3926"></span></p>


<p>Man kann die für den eigenen Tenant verfügbaren Regionen recht leicht mit Hilfe der Azure CLI (z.B. über Azure CloudShell) abfragen:</p>


<pre lang="PowerShell" line="1">az account list-locations --query "[].{Name:name, DisplayName:displayName}" -o table</pre>


<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="830" height="498" src="https://www.hertes.net/wp-content/uploads/2020/06/image-2.png" alt="" class="wp-image-3927" srcset="https://www.hertes.net/wp-content/uploads/2020/06/image-2.png 830w, https://www.hertes.net/wp-content/uploads/2020/06/image-2-300x180.png 300w, https://www.hertes.net/wp-content/uploads/2020/06/image-2-768x461.png 768w" sizes="auto, (max-width: 830px) 100vw, 830px" /></figure>



<p><a href="https://docs.microsoft.com/de-de/azure/availability-zones/az-overview?WT.mc_id=AZ-MVP-5001882#regions">Regionen und Verfügbarkeitszonen in Azure | Microsoft Docs</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.hertes.net/2020/06/azure-regions-locations-auflisten/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Azure ARM Templates mit GitHub Actions deployen</title>
		<link>https://www.hertes.net/2020/06/azure-arm-templates-mit-github-actions-deployen/</link>
					<comments>https://www.hertes.net/2020/06/azure-arm-templates-mit-github-actions-deployen/#respond</comments>
		
		<dc:creator><![CDATA[Haiko]]></dc:creator>
		<pubDate>Tue, 02 Jun 2020 18:02:33 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Actions]]></category>
		<category><![CDATA[ARM]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Deploy]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[IaC]]></category>
		<category><![CDATA[Pipeline]]></category>
		<category><![CDATA[Script]]></category>
		<category><![CDATA[Skript]]></category>
		<category><![CDATA[Template]]></category>
		<category><![CDATA[Templates]]></category>
		<guid isPermaLink="false">https://www.hertes.net/?p=3922</guid>

					<description><![CDATA[Geht es um den Aufbau automatisierter CI/CD Pipelines für Azure, so denken die meisten wohl eher an Azure DevOps. Aber auch mit GitHub lässt sich so etwas erreichen &#8211; und zwar völlig kostenlos. Das Werkzeug dazu heißt GitHub Actions. Zu GitHub Actions selbst will ich hier gar nicht so viel schreiben &#8211; es gibt bereits einige Blogartikel und co. dazu. Ich verweise aber gerne auf mein Video, welches ich dazu gemacht habe: Nun kam von einem meiner geschätzten Kollegen zu Recht die Frage, wie man denn in dieser (ersten, im Video gezeigten) Variante mehrere ARM Templates bereitstellen kann. Und dazu&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Geht es um den Aufbau automatisierter CI/CD Pipelines für Azure, so denken die meisten wohl eher an Azure DevOps. Aber auch mit GitHub lässt sich so etwas erreichen &#8211; und zwar völlig kostenlos. Das Werkzeug dazu heißt GitHub Actions. Zu GitHub Actions selbst will ich hier gar nicht so viel schreiben &#8211; es gibt bereits einige Blogartikel und co. dazu. Ich verweise aber gerne auf mein Video, welches ich dazu gemacht habe:</p>



<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Microsoft Azure ?? Mit GitHub Actions ARM Templates ausrollen" width="500" height="281" src="https://www.youtube.com/embed/TRBw1RyRo_I?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption>Mein YouTube Video zu GitHub Actions</figcaption></figure>



<p>Nun kam von einem meiner geschätzten Kollegen zu Recht die Frage, wie man denn in dieser (ersten, im Video gezeigten) Variante mehrere ARM Templates bereitstellen kann. Und dazu möchte ich hier die passende Antwort liefern&#8230;</p>



<span id="more-3922"></span>



<p>Eine Variante wäre sicherlich, in diesem Skript </p>



<p><a href="https://github.com/HaikoHertes/ActionsDemo/blob/master/.github/workflows/DeployARMtoAzure.yml#L23">https://github.com/HaikoHertes/ActionsDemo/blob/master/.github/workflows/DeployARMtoAzure.yml#L23</a></p>



<p>mehrfach das &#8222;az deployment group create&#8220; aufzurufen &#8211; aber dann müssten man wissen, wie viele Templates es sind und das Skript würde auch schnell sehr lang.</p>



<p>Als aus meiner Sicht bessere Lösung habe ich ein PowerShell Skript geschrieben, dass in der Verzeichnisstruktur des Repositories einen Ordner &#8222;arm\&#8220; erwartet und darin Unterordner mit den Namen der gewünschten Resource Groups. Diese werden falls nötig vom Skript angelegt. Außerdem sucht das Skript Templates im Format XYZ.json und dazugehörige Parameter-Files im Format XYZ.parameters.json. Diese Templates werden nun alphabetisch geordnet mittels ARM bereitgestellt &#8211; egal, wie viele es sind. Dabei werden aus einer Datei &#8222;tags.txt&#8220; falls gewünscht die Tages im Format</p>



<p>Tag = Wert</p>



<p>geladen und bei der Bereitstellung der RGs und Ressourcen mit angewendet. Die zu verwendende Location (nur eine pro RG ist erlaubt, aber das entspricht weitgehend dem üblichen Vorgehen) wird ebenfalls aus einer TXT-Datei location.txt gelesen.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="501" height="308" src="https://www.hertes.net/wp-content/uploads/2020/06/image-1.png" alt="" class="wp-image-3924" srcset="https://www.hertes.net/wp-content/uploads/2020/06/image-1.png 501w, https://www.hertes.net/wp-content/uploads/2020/06/image-1-300x184.png 300w" sizes="auto, (max-width: 501px) 100vw, 501px" /><figcaption>Der erwartete Verzeichnisbaum</figcaption></figure>



<p>Im GitHub Repo müssen zwei Secrets hinterlegt werden:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="473" src="https://www.hertes.net/wp-content/uploads/2020/06/image-1024x473.png" alt="" class="wp-image-3923" srcset="https://www.hertes.net/wp-content/uploads/2020/06/image-1024x473.png 1024w, https://www.hertes.net/wp-content/uploads/2020/06/image-300x139.png 300w, https://www.hertes.net/wp-content/uploads/2020/06/image-768x355.png 768w, https://www.hertes.net/wp-content/uploads/2020/06/image.png 1148w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Screenshot der GitHub Secrets</figcaption></figure>



<p>Einmal ein Secret für die Credentials (wie man die anlegt zeige ich im <a rel="noreferrer noopener" href="https://youtu.be/TRBw1RyRo_I?t=1227" target="_blank">Video ab 20:27</a>) und einmal die Subscription ID der zu verwendenden Subscription. Ergo ist ein Repo pro Subscription nötig&#8230;</p>



<p>Das PowerShell Script selbst könnt ihr hier herunterladen:</p>



<p><a href="https://github.com/HaikoHertes/ActionsDemo.v2/blob/master/DeployARMtoAzure.ps1">https://github.com/HaikoHertes/ActionsDemo.v2/blob/master/DeployARMtoAzure.ps1</a></p>



<p>Alternativ könnt ihr gleich mein ganzes Demo Repo auf GitHub clonen:</p>



<p><a rel="noreferrer noopener" href="https://github.com/HaikoHertes/ActionsDemo.v2" target="_blank">https://github.com/HaikoHertes/ActionsDemo.v2</a> bzw<br><a rel="noreferrer noopener" href="https://github.com/HaikoHertes/ActionsDemo.v2.git" target="_blank">https://github.com/HaikoHertes/ActionsDemo.v2.git</a> <br><br>Wichtig: Damit mit -Tag bzw. -Tags auch die tags gleich mit bereitgestellt werden können braucht man das Az Modul in Version 4.1.0 und das wiederum ist derzeit nur im Ubuntu-20.04 Image auf GitHub enthalten. Siehe dazu auch hier:</p>



<p><a href="https://github.com/marketplace/actions/azure-powershell-action">https://github.com/marketplace/actions/azure-powershell-action</a><br><a href="https://github.com/actions/virtual-environments/blob/master/images/linux/Ubuntu2004-README.md">https://github.com/actions/virtual-environments/blob/master/images/linux/Ubuntu2004-README.md</a><br><a href="https://github.com/actions/virtual-environments/tree/master/images">https://github.com/actions/virtual-environments/tree/master/images</a></p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.hertes.net/2020/06/azure-arm-templates-mit-github-actions-deployen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Global Azure Bootcamp 2019 &#8211; Slides und Recording meiner Session</title>
		<link>https://www.hertes.net/2019/04/global-azure-bootcamp-2019-slides-und-recording-meiner-session/</link>
					<comments>https://www.hertes.net/2019/04/global-azure-bootcamp-2019-slides-und-recording-meiner-session/#respond</comments>
		
		<dc:creator><![CDATA[Haiko]]></dc:creator>
		<pubDate>Sun, 28 Apr 2019 15:05:22 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Veranstaltungen]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Global Azure Bootcamp]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[OpenSource]]></category>
		<category><![CDATA[Veranstaltung]]></category>
		<guid isPermaLink="false">https://www.hertes.net/?p=3782</guid>

					<description><![CDATA[Für alle Interessierten gibt es hier die Slides und das Recording meiner gestrigen Session zu &#8222;DevOps mit OpenSource Tools&#8220; auf dem Global Azure Bootcamp 2019: Recording auf YouTube: Die URL dazu ist https://youtu.be/gqAKGJWeDVY Slides: https://1drv.ms/b/s!ArnVhBG12m2DmO8XqGRXX36qns7GvQ]]></description>
										<content:encoded><![CDATA[
<p>Für alle Interessierten gibt es hier die Slides und das Recording meiner gestrigen Session zu &#8222;DevOps mit OpenSource Tools&#8220; auf dem Global Azure Bootcamp 2019:</p>



<p>Recording auf YouTube:</p>



<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Microsoft Azure - OpenSource DevOps Lösungen für CI/CD - Vortrag von MVP auf Global Azure Bootcamp" width="500" height="281" src="https://www.youtube.com/embed/gqAKGJWeDVY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>Die URL dazu ist https://youtu.be/gqAKGJWeDVY</p>



<p>Slides:</p>



<p><a href="https://1drv.ms/b/s!ArnVhBG12m2DmO8XqGRXX36qns7GvQ">https://1drv.ms/b/s!ArnVhBG12m2DmO8XqGRXX36qns7GvQ</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.hertes.net/2019/04/global-azure-bootcamp-2019-slides-und-recording-meiner-session/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Azure / PowerShell – Azure SQL Performance Empfehlungen per PowerShell abholen und verteilen</title>
		<link>https://www.hertes.net/2019/03/azure-powershell-azure-sql-performance-empfehlungen-per-powershell-abholen-und-verteilen/</link>
					<comments>https://www.hertes.net/2019/03/azure-powershell-azure-sql-performance-empfehlungen-per-powershell-abholen-und-verteilen/#respond</comments>
		
		<dc:creator><![CDATA[Haiko]]></dc:creator>
		<pubDate>Wed, 27 Mar 2019 18:10:15 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Automatisierung]]></category>
		<category><![CDATA[Azure SQL]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Tuning]]></category>
		<guid isPermaLink="false">https://www.hertes.net/?p=3755</guid>

					<description><![CDATA[Azure und insbesondere Azure SQL ist klasse &#8211; es nimmt einem viele Dinge der täglichen Verwaltung ab, einiges davon sogar automatisch. Klar, das hat seinen Preis, immerhin ist Azure SQL nicht ganz billig, aber wenn man es schon bezahlt, dann kann man auch seine Fähigkeiten nutzen. Eine davon ist, automatisch anhand der Nutzung einer Datenbank Empfehlungen für die Leistungsoptimierung zu geben. Diese kann man sich im UI bzw. dem Azure Portal anschauen. Dazu öffnet man entweder links im Blade den Punkt &#8222;Recommondations&#8220; unterhalb von &#8222;Intelligent Performance&#8220; oder den Punkt &#8222;Performance&#8220; auf der Main-Page bei den Notifications: Dort sieht man dann&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Azure und insbesondere Azure SQL ist klasse &#8211; es nimmt einem viele Dinge der täglichen Verwaltung ab, einiges davon sogar automatisch. Klar, das hat seinen Preis, immerhin ist Azure SQL nicht ganz billig, aber wenn man es schon bezahlt, dann kann man auch seine Fähigkeiten nutzen. Eine davon ist, automatisch anhand der Nutzung einer Datenbank Empfehlungen für die Leistungsoptimierung zu geben. Diese kann man sich im UI bzw. dem Azure Portal anschauen. Dazu öffnet man entweder links im Blade den Punkt &#8222;Recommondations&#8220; unterhalb von &#8222;Intelligent Performance&#8220; oder den Punkt &#8222;Performance&#8220; auf der Main-Page bei den Notifications:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="501" src="https://www.hertes.net/wp-content/uploads/2019/03/image-1024x501.png" alt="" class="wp-image-3756" srcset="https://www.hertes.net/wp-content/uploads/2019/03/image-1024x501.png 1024w, https://www.hertes.net/wp-content/uploads/2019/03/image-300x147.png 300w, https://www.hertes.net/wp-content/uploads/2019/03/image-768x375.png 768w, https://www.hertes.net/wp-content/uploads/2019/03/image.png 1921w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Dort sieht man dann einige Empfehlungen aufgeführt (vorausgesetzt, Azure hat etwas gefunden, was wiederum eine regelmäßige Nutzung der Datenbank voraussetzt):</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="482" src="https://www.hertes.net/wp-content/uploads/2019/03/image-2-1024x482.png" alt="" class="wp-image-3758" srcset="https://www.hertes.net/wp-content/uploads/2019/03/image-2-1024x482.png 1024w, https://www.hertes.net/wp-content/uploads/2019/03/image-2-300x141.png 300w, https://www.hertes.net/wp-content/uploads/2019/03/image-2-768x361.png 768w, https://www.hertes.net/wp-content/uploads/2019/03/image-2.png 1721w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Diese Daten kann man sich auch automatisch abrufen und auf Wunsch dann z.B. an die Entwickler verteilen. Dazu bediene ich mich einfach der PowerShell:</p>



<pre lang="PowerShell" line="1">
$ErrorActionPreference = "Stop"
$SubscriptionId = "YOUR_SUBSCRIPTION_ID"

function Get-SQLServerRecommendations()
{
    # Define the resource types
    $resourceTypes = ("Microsoft.Sql/servers/databases")
    $advisors = ("CreateIndex", "DropIndex","DbParameterization","SchemaIssue");
    $results = @()

    # Loop through all subscriptions
   
    $rgs = Get-AzureRmResourceGroup

    # Loop through all resource groups
    foreach($rg in $rgs) {
        $rgname = $rg.ResourceGroupName;

        # Loop through all resource types
        foreach($resourceType in $resourceTypes) {
            $resources = Get-AzureRmResource -ResourceGroupName $rgname -ResourceType $resourceType

            # Loop through all databases
            # Extract resource groups, servers and databases
            foreach ($resource in $resources) {
                $resourceId = $resource.ResourceId
                if ($resourceId -match ".*RESOURCEGROUPS/(?<content>.*)/PROVIDERS.*") {
                    $ResourceGroupName = $matches['content']
                } else {
                    continue
                }
                if ($resourceId -match ".*SERVERS/(?<content>.*)/DATABASES.*") {
                    $ServerName = $matches['content']
                } else {
                    continue
                }
                if ($resourceId -match ".*/DATABASES/(?<content>.*)") {
                    $DatabaseName = $matches['content']
                } else {
                    continue
                }

                # Skip if master
                if ($DatabaseName -eq "master") {
                    continue
                }

                # Loop through all Automatic tuning recommendation types
                foreach ($advisor in ($advisors -notmatch "SchemaIssue")) {
                    $recs = Get-AzureRmSqlDatabaseRecommendedAction -ResourceGroupName $ResourceGroupName -ServerName $ServerName  -DatabaseName $DatabaseName -AdvisorName $advisor
                    foreach ($r in $recs) {
                        if ($r.State.CurrentValue -eq "Active") {
                            $object = New-Object -TypeName PSObject
                            $object | Add-Member -Name 'SubscriptionId' -MemberType Noteproperty -Value $subscriptionId
                            $object | Add-Member -Name 'ResourceGroupName' -MemberType Noteproperty -Value $r.ResourceGroupName
                            $object | Add-Member -Name 'ServerName' -MemberType Noteproperty -Value $r.ServerName
                            $object | Add-Member -Name 'DatabaseName' -MemberType Noteproperty -Value $r.DatabaseName
                            $object | Add-Member -Name 'Advisor' -MemberType Noteproperty -Value $advisor
                            $object | Add-Member -Name 'Script' -MemberType Noteproperty -Value $r.ImplementationDetails.Script
                            $results += $object
                        }
                    }
                }
            }
        }
    }
    Return $results
}

$AzurePasswordSecure = ConvertTo-SecureString "$($YOUR_AZURE_PASSWORD)" -AsPlainText -Force
$AzureCredentials = New-Object System.Management.Automation.PSCredential ("$YOUR_AZURE_USER", $AzurePasswordSecure)
Connect-AzureRmAccount -Credential $AzureCredentials | Out-Null
Select-AzureRmSubscription -Subscription $SubscriptionId | Out-Null

$Recommendations = Get-SQLServerRecommendations
$table = $Recommendations | Sort-Object DatabaseName,Advisor | Format-Table Databasename,Advisor,Script -AutoSize -Wrap
Write-Output $table

$head = "<style>
td {background-color:lightgrey;}
table {width:100%;}
th {font-size:14pt;background-color:lightblue;}
</style>
<title>SQL Server performance recommendations</title>"

[string]$html = $Recommendations | ConvertTo-Html -Property Databasename,Advisor,Script -Body "<h1>Azure SQL Server automatic tuning recommendations for $stage</h1>Auto-generated by PUT_SOMETHING_HERE<br><br>" -Head $head

Send-MailMessage -Body $html -SmtpServer YOUR.SMTPSERVER.COM -From sender@domain.com -To recipient@domain.com -Subject "MS SQL Recommendations - $(Get-Date -Format "yyyy-dd-MM HH:mm:ss")" -BodyAsHtml
</pre>



<p></p>



<p>Dieses Script wiederum kann man dann z.B. per Jenkins regelmäßig auslösen. Oder alternativ ein Azure Automation Runbook dafür anlegen&#8230; Viel Spaß beim Ausprobieren!</p>



<p>Die Mails sehen dann in etwa so aus:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="802" height="896" src="https://www.hertes.net/wp-content/uploads/2019/03/image-3.png" alt="" class="wp-image-3760" srcset="https://www.hertes.net/wp-content/uploads/2019/03/image-3.png 802w, https://www.hertes.net/wp-content/uploads/2019/03/image-3-269x300.png 269w, https://www.hertes.net/wp-content/uploads/2019/03/image-3-768x858.png 768w" sizes="auto, (max-width: 802px) 100vw, 802px" /></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://www.hertes.net/2019/03/azure-powershell-azure-sql-performance-empfehlungen-per-powershell-abholen-und-verteilen/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Azure / PowerShell &#8211; App Settings von einer Web App zur anderen kopieren</title>
		<link>https://www.hertes.net/2018/11/azure-powershell-app-settings-von-einer-web-app-zur-anderen-kopieren/</link>
					<comments>https://www.hertes.net/2018/11/azure-powershell-app-settings-von-einer-web-app-zur-anderen-kopieren/#respond</comments>
		
		<dc:creator><![CDATA[Haiko]]></dc:creator>
		<pubDate>Wed, 14 Nov 2018 21:36:34 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[App Settings]]></category>
		<category><![CDATA[Web App]]></category>
		<guid isPermaLink="false">https://www.hertes.net/?p=3723</guid>

					<description><![CDATA[Insbesondere, wenn man viele App Settings (Umgebungsvariablen für eine Web App) in Azure verwendet und die Web App ein zweites Mal benötigt, z.B. um eine Test- oder Entwicklungs-Stage abzubilden, kann es sehr mühselig sein, die Settings zu übertragen. Hier bietet es sich an, diese per PowerShell zu kopieren.  Voraussetzung dazu ist nur das Azure PowerShell RM Modul, welches man auf diesem Weg installieren kann: Install-Module -Name AzureRM -AllowClobber Dabei muss ggf. ein Sicherheitshinweis bestätigt werden. Wer das Modul schon installiert hat, muss natürlich nichts tun. Zum Kopieren der Settings kann dann dieses Skript verwendet werden: # Adjust theese as needed&#8230;]]></description>
										<content:encoded><![CDATA[<p>Insbesondere, wenn man viele App Settings (Umgebungsvariablen für eine Web App) in Azure verwendet und die Web App ein zweites Mal benötigt, z.B. um eine Test- oder Entwicklungs-Stage abzubilden, kann es sehr mühselig sein, die Settings zu übertragen. Hier bietet es sich an, diese per PowerShell zu kopieren.  Voraussetzung dazu ist nur das Azure PowerShell RM Modul, welches man auf diesem Weg installieren kann:</p>
<p><span class="hljs-pscommand">Install-Module</span><span class="hljs-parameter"> -Name</span> AzureRM<span class="hljs-parameter"> -AllowClobber</span></p>
<p>Dabei muss ggf. ein Sicherheitshinweis bestätigt werden. Wer das Modul schon installiert hat, muss natürlich nichts tun.</p>
<p>Zum Kopieren der Settings kann dann dieses Skript verwendet werden:</p>
<pre lang="PowerShell" line="1">
# Adjust theese as needed

$SubscriptionId = "123456-7890-1234-12132"

$ResourceGroupSource = "RG-Source"
$ResourceGroupTarget = "RG-Target"

$WebAppSource = "WebApp-Source"
$WebAppTarget = "WebApp-Target"

### no changes needed below ###

Connect-AzureRmAccount -Subscription $SubscriptionId -Scope Process
Set-AzureRmContext -SubscriptionId $SubscriptionId

$webAppSource = Get-AzureRmWebApp -ResourceGroupName $ResourceGroupSource -Name $WebAppSource 

# Get reference to the source app settings
$AppSettingsSource = $WebAppSource.SiteConfig.AppSettings

# Create empty Hash table variable for App Settings
$AppSettingsTarget = @{}

# Copy over all existing App Settings to the Hash table
ForEach ($AppSettingSource in $AppSettingsSource) {
    $AppSettingsTarget[$AppSettingSource.Name] = $AppSettingSource.Value
}

# Save strings to target Web App
Set-AzureRmWebApp -ResourceGroupName $ResourceGroupTarget -Name $WebAppTarget -AppSettings $AppSettingsTarget</pre>
<p>Viel Spaß beim Ausprobieren &#8211; mir spart das immer wieder viel Arbeit!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.hertes.net/2018/11/azure-powershell-app-settings-von-einer-web-app-zur-anderen-kopieren/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Azure &#8211; Application Settings von einem App Service zu einem anderen Kopieren</title>
		<link>https://www.hertes.net/2018/06/azure-application-settings-von-einem-app-service-zu-einem-anderen-kopieren/</link>
					<comments>https://www.hertes.net/2018/06/azure-application-settings-von-einem-app-service-zu-einem-anderen-kopieren/#respond</comments>
		
		<dc:creator><![CDATA[Haiko]]></dc:creator>
		<pubDate>Mon, 11 Jun 2018 19:16:14 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[App Service]]></category>
		<category><![CDATA[App Settings]]></category>
		<category><![CDATA[Application Settings]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Parameter]]></category>
		<category><![CDATA[Settings]]></category>
		<category><![CDATA[Web App]]></category>
		<guid isPermaLink="false">https://www.hertes.net/?p=3676</guid>

					<description><![CDATA[Wenn man beispielsweise für Entwicklung, Test und andere Zwecke Kopien einer Azure Web App benötigt oder zumindest initial die Settings übernehmen will, kann das, bei einer längeren Liste von Settings, ein recht hoher manueller Aufwand werden. Um diesen zu umgehen, habe ich ein entsprechendes PowerShell-Skript geschrieben. Dieses kopiert alle Settings und deren Werte von einer benannten Web App auf eine andere. Dabei sind die Ressource Groups und die Namen der Web Apps anzugeben. Hier das Skript im Textlaut: # Adjust theese as needed $SubscriptionId = "FILLINSUBSCRIPTIONID" $ResourceGroupSource = "FILLINRGOFSOURCEWEBAPP" $ResourceGroupTarget = "FILLINRGOFDESTWEBAPP" $WebAppSource = "FILLINSOURCEWEBAPP" $WebAppTarget = "FILLINDESTWEBAPP" ### no&#8230;]]></description>
										<content:encoded><![CDATA[<p>Wenn man beispielsweise für Entwicklung, Test und andere Zwecke Kopien einer Azure Web App benötigt oder zumindest initial die Settings übernehmen will, kann das, bei einer längeren Liste von Settings, ein recht hoher manueller Aufwand werden. Um diesen zu umgehen, habe ich ein entsprechendes PowerShell-Skript geschrieben. Dieses kopiert alle Settings und deren Werte von einer benannten Web App auf eine andere. Dabei sind die Ressource Groups und die Namen der Web Apps anzugeben.</p>
<p>Hier das Skript im Textlaut:</p>
<pre lang="PowerShell" line="1"># Adjust theese as needed

$SubscriptionId = "FILLINSUBSCRIPTIONID"

$ResourceGroupSource = "FILLINRGOFSOURCEWEBAPP"
$ResourceGroupTarget = "FILLINRGOFDESTWEBAPP"

$WebAppSource = "FILLINSOURCEWEBAPP"
$WebAppTarget = "FILLINDESTWEBAPP"

### no changes needed below ###

Connect-AzureRmAccount -Subscription $SubscriptionId
Set-AzureRmContext -SubscriptionId $SubscriptionId

$webAppSource = Get-AzureRmWebApp -ResourceGroupName $ResourceGroupSource -Name $WebAppSource 

# Get reference to the source app settings
$AppSettingsSource = $WebAppSource.SiteConfig.AppSettings

# Create empty Hash table variable for App Settings
$AppSettingsTarget = @{}

# Copy over all Existing App Settings to the Hash table
ForEach ($AppSettingSource in $AppSettingsSource) {
    $AppSettingsTarget[$AppSettingSource.Name] = $AppSettingSource.Value
}

# Save Connection Strings to Target Web App
Set-AzureRmWebApp -ResourceGroupName $ResourceGroupTarget -Name $WebAppTarget -AppSettings $AppSettingsTarget
Write-Host "Done!"
</pre>
<p>Viel Spaß damit!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.hertes.net/2018/06/azure-application-settings-von-einem-app-service-zu-einem-anderen-kopieren/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PowerShell Core und Jenkins &#8211; Continuous Integration f&#252;r PowerShell auf Linux</title>
		<link>https://www.hertes.net/2018/03/powershell-core-und-jenkins-continuous-integration-fr-powershell-auf-linux/</link>
					<comments>https://www.hertes.net/2018/03/powershell-core-und-jenkins-continuous-integration-fr-powershell-auf-linux/#respond</comments>
		
		<dc:creator><![CDATA[Haiko]]></dc:creator>
		<pubDate>Mon, 12 Mar 2018 15:02:00 +0000</pubDate>
				<category><![CDATA[Bash]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Linux/Unix]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[PowerShell Core]]></category>
		<category><![CDATA[CI]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://www.hertes.net/?p=3590</guid>

					<description><![CDATA[In letzter Zeit beschäftige ich mich immer mal wieder mit DevOps-Themen. Eines davon ist Continuous Integration und das dafür gemachte Jenkins. Einige meiner Erfahrungen hierzu möchte ich gerne teilen. Dieser Artikel beschäftigt sich mit PowerShell Core und Jenkins. In einem vorherigen Artikel habe ich in Kurzform erläutert, wie man Jenkins unter Debian Linux installiert. Das ist für diesen Artikel eine Art Voraussetzung. Auch ohne PS Core kann Jenkins PowerShell-Code und –Skripte ausführen – allerdings braucht es dazu immer einen sogenannten “Build Slave” (also einen weiteren Jenkins-Knoten) mit Windows als Betriebssystem, Mit der Verfügbarkeit von PowerShell Core für Linux ist es&#8230;]]></description>
										<content:encoded><![CDATA[<p>In letzter Zeit beschäftige ich mich immer mal wieder mit DevOps-Themen. Eines davon ist Continuous Integration und das dafür gemachte Jenkins. Einige meiner Erfahrungen hierzu möchte ich gerne teilen.</p>
<p>Dieser Artikel beschäftigt sich mit PowerShell Core und Jenkins. In einem <a href="/?p=3600">vorherigen Artikel</a> habe ich in Kurzform erläutert, wie man Jenkins unter Debian Linux installiert. Das ist für diesen Artikel eine Art Voraussetzung.</p>
<p>Auch ohne PS Core kann Jenkins PowerShell-Code und –Skripte ausführen – allerdings braucht es dazu immer einen sogenannten “Build Slave” (also einen weiteren Jenkins-Knoten) mit Windows als Betriebssystem,</p>
<p>Mit der Verfügbarkeit von PowerShell Core für Linux ist es künftig nicht mehr zwingend nötig, einen Windows Buildslave zu verwenden, wenn man PowerShell benutzen möchte. Was leider NICHT funktioniert (zumindest mit Stand Heute), ist das PowerShell-Plugin für Jenkins. Dieses ruft den Code in einer Art und Weise auf, wie es nur unter Windows funktioniert. Selbst wenn man den dort verwendeten Aufruf “powershell.exe” mittels symbolic Link oder Alias auf pwsh mappt, wird es nicht funktionieren.</p>
<p>Ein möglicher Weg führt aber über den Einsatz eines Batch-Skriptes. Und das könnte so aussehen:</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins9.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins9" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins9_thumb.jpg" alt="jenkins9" width="640" height="359" border="0" /></a><br />
<a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins10.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins10" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins10_thumb.jpg" alt="jenkins10" width="640" height="359" border="0" /></a></p>
<p>Mit Hilfe von Parametern kann später flexibler mit dem Build Job umgegangen werden (siehe weiter unten):</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins11.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins11" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins11_thumb.jpg" alt="jenkins11" width="640" height="359" border="0" /></a></p>
<p>Der Einfachheit halber sollte der Parametername keine Leer- oder Sonderzeichen enthalten.</p>
<p>Für den eigentlichen Build (also die Aktionen, die durch den Job auszuführen sind), muss man hier nun auf “Shell ausführen” zurückgreifen. Der Menüpunkt “Windows PowerShell” wird nicht funktionieren (er steht auch nur zur Verfügung, wenn das Plugin bereits installiert ist).</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins12.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins12" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins12_thumb.jpg" alt="jenkins12" width="640" height="359" border="0" /></a></p>
<p>Mein Aufruf für die Shell lautet hier beispielhaft:</p>
<blockquote><p>pwsh -command &#8222;(Get-Variable -Name ${VariableName}).Value&#8220;</p></blockquote>
<p>Mit ${PARAMETER} kann man auf den oben definierten Parameter zurückgreifen.</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins17.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins17" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins17_thumb.jpg" alt="jenkins17" width="640" height="359" border="0" /></a></p>
<p>Anschließend kann man den Buildjob über “Bauen mit Parametern” aufrufen. Dabei kann man dann den Wert des/der Parameter definieren (oder, falls man Defaultwerte definiert hat, diese einfach beibehalten):</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins18.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins18" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins18_thumb.jpg" alt="jenkins18" width="640" height="359" border="0" /></a></p>
<p>Anschließend kann man mit einem Klick auf den kleinen Pfeil neben dem Buildjob unten bei “Build-Verlauf” die “Konsolenausgabe” aufrufen:</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins19.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins19" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins19_thumb.jpg" alt="jenkins19" width="640" height="359" border="0" /></a></p>
<p>Dort sieht man dann entweder den/die Fehler, falls welche aufgetreten sind, oder eben die Ausgabe des Jobs:</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins20.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins20" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins20_thumb.jpg" alt="jenkins20" width="640" height="359" border="0" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.hertes.net/2018/03/powershell-core-und-jenkins-continuous-integration-fr-powershell-auf-linux/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Jenkins auf Linux für Continuous Integration</title>
		<link>https://www.hertes.net/2018/03/jenkins-auf-linux-fr-continuous-integration/</link>
					<comments>https://www.hertes.net/2018/03/jenkins-auf-linux-fr-continuous-integration/#respond</comments>
		
		<dc:creator><![CDATA[Haiko]]></dc:creator>
		<pubDate>Fri, 09 Mar 2018 22:30:00 +0000</pubDate>
				<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Linux/Unix]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://www.hertes.net/?p=3600</guid>

					<description><![CDATA[In letzter Zeit beschäftige ich mich immer mal wieder mit DevOps-Themen. Eines davon ist Continuous Integration und das dafür gemachte Jenkins. Einige meiner Erfahrungen hierzu möchte ich gerne teilen. In diesem Artikel möchte ich kurz beleuchten, wie man Jenkins auf Debian 9 “Stretch” installieren kann. Es gibt sicherlich einige andere Wege, aber dieser hier funktioniert sehr schnell und zuverlässig. Als erstes braucht ihr natürlich eine Debian Maschine. Ich nutze dafür gerne Hyper-V oder Azure, aber jede andere Plattform wird ebenso funktionieren. Wichtig ist am Ende eigentlich nur, dass die Maschine Internetzugriff hat. Als nächstes braucht man die passenden Keys und&#8230;]]></description>
										<content:encoded><![CDATA[<p>In letzter Zeit beschäftige ich mich immer mal wieder mit DevOps-Themen. Eines davon ist Continuous Integration und das dafür gemachte Jenkins. Einige meiner Erfahrungen hierzu möchte ich gerne teilen.</p>
<p>In diesem Artikel möchte ich kurz beleuchten, wie man Jenkins auf Debian 9 “Stretch” installieren kann. Es gibt sicherlich einige andere Wege, aber dieser hier funktioniert sehr schnell und zuverlässig.</p>
<p>Als erstes braucht ihr natürlich eine Debian Maschine. Ich nutze dafür gerne Hyper-V oder Azure, aber jede andere Plattform wird ebenso funktionieren. Wichtig ist am Ende eigentlich nur, dass die Maschine Internetzugriff hat.</p>
<p>Als nächstes braucht man die passenden Keys und eine Quelle für APT:</p>
<pre lang="bash" line="1">wget -q -O - http://pkg.jenkins-ci.org/debian-stable/jenkins-ci.org.key | sudo apt-key add
echo "deb http://pkg.jenkins-ci.org/debian-stable binary/" | sudo tee /etc/apt/sources.list.d/jenkins.list</pre>
<p>Nach einem anschließenden “apt-get update” kann man nun Jenkins installieren:</p>
<pre lang="bash" line="1">sudo apt-get update
sudo apt-get install jenkins -y
sudo cat /var/lib/jenkins/secrets/initialAdminPassword</pre>
<p>Der letzte Aufruf gibt das Initialpasswort aus, welches man anschließend für die Einrichtung benötigt.</p>
<p>Nun kann man unter</p>
<p>http://HOSTNAME:8080</p>
<p>den frisch installierten Jenkins aufrufen und einrichten:</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins1.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins1" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins1_thumb.jpg" alt="jenkins1" width="640" height="359" border="0" /></a></p>
<p>Hier wird nun also der vorhin ausgelesene Key benötigt.</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins2.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins2" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins2_thumb.jpg" alt="jenkins2" width="640" height="359" border="0" /></a></p>
<p>Bei den Plugins kann man im Zweifel erstmal mit den “suggested plugins” beginnen, aber ich bevorzuge es, einige nicht benötigte Plugins gar nicht erst zu installieren und wähle daher “Select plugins to install”. Meine konkrete Auswahl kann man in Teilen unten sehen:</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins3.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins3" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins3_thumb.jpg" alt="jenkins3" width="640" height="359" border="0" /></a></p>
<p>Nun muss man noch ein Admin-Konto anlegen und dann kann es auch schon losgehen…</p>
<p><a href="https://www.hertes.net/wp-content/uploads/2018/03/jenkins4.jpg"><img loading="lazy" decoding="async" style="margin: 0px auto; border: 0px currentcolor; float: none; display: block; background-image: none;" title="jenkins4" src="https://www.hertes.net/wp-content/uploads/2018/03/jenkins4_thumb.jpg" alt="jenkins4" width="640" height="359" border="0" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.hertes.net/2018/03/jenkins-auf-linux-fr-continuous-integration/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
