{"id":78624,"date":"2018-04-30T19:39:58","date_gmt":"2018-04-30T19:39:58","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=78624"},"modified":"2021-04-27T13:55:25","modified_gmt":"2021-04-27T13:55:25","slug":"create-azure-vms-powershell-part-2","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/create-azure-vms-powershell-part-2\/","title":{"rendered":"Create Azure VMs with PowerShell Part 2"},"content":{"rendered":"<p>My previous article, <a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/create-azure-vms-powershell-part-1\/\">Create VMs In Azure Part 1<\/a>, described the process of creating virtual machines in Azure using PowerShell. It covered foundational information, such as making Azure logins from PowerShell easier, and determining what images are available to create VMs with on Azure. This included extracting the exact values needed for parameters when creating your VM. Virtual networking was covered next. This included not just creating the network but the security group to allow traffic through the firewall, such as HTTP and RDP. Finally, the article demonstrated the creation of a virtual NIC, or Network Interface Card, the object that handles communication between the virtual machine and the network.<\/p>\n<p>All of this was done using the <a href=\"https:\/\/github.com\/arcanecode\/PowerShell\/tree\/master\/PSAzure_Module\">PSAzure module<\/a>, a new project available on my GitHub site.<\/p>\n<p>The previous article goes more into the details on the module, so if you haven\u2019t read it yet you\u2019re missing out on a lot of fun! (If you want to go read it now, go ahead. I\u2019ll wait.) You do need to have the module installed and the Azure objects created from the previous article if you wish to follow along with this article.<\/p>\n<p>This article will continue the journey. You\u2019ll create the virtual machine itself, then discuss some management techniques for your VM. Mom always taught me to clean up after myself, so at the end you\u2019ll see how to remove all the objects created in these articles.<\/p>\n<h2>Creating the VM<\/h2>\n<p>We\u2019ll assume you are picking up where we left off in the last article. You are in the Create-AzureVM.ps1 sample script, have logged in, created the resource group, storage, and virtual network. As a reminder, here are some of the variables from that part of the article you\u2019ll be using when you create the VM.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  $resourceGroup = 'AzurePSTestRG'\r\n  $storageAccount = 'azurepsteststorageacct'\r\n  $location = 'southcentralus'\r\n  $nicName = 'ArcanePSTestNIC'<\/pre>\n<p>If it\u2019s been awhile since you read the first article and don\u2019t remember the values you used, just locate the resource group in the Azure Portal and view the objects in the <em>Overview<\/em> page. Alternatively, you can run this command to see the objects in PowerShell.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-AzureRmResourceGroup -Name @resourceGroup  <\/pre>\n<p>To continue the process, you\u2019ll need to layout a few more variables. You\u2019ll start by providing the machine name, the name for its primary disk, along with the administrator login and password.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  $vmName = 'AzurePSTestVM'\r\n  $adminName = 'ArcaneCode'\r\n  $adminPW = 'mySuperStr0ngP@ssword'\r\n  $diskName = 'AzurePSTestDisk'<\/pre>\n<p>Many of the standards around passwords for real computers also exist in Azure. They should be between 8 and 123 characters in length and must include characters from at least three of the following: an uppercase character, a lowercase character, a number, and a special character. Note that control characters, such as the ENTER key, are not allowed.<\/p>\n<p>Next, define variables that dictate the image you want to use to create the VM, as well as the size of the machine.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  $vmSize = 'Basic_A3'\r\n  $vmPublisher = 'MicrosoftSQLServer' \r\n  $vmOffer = 'SQL2016SP1-WS2016' \r\n  $vmSKU = 'SQLDEV' \r\n  # By default it uses the latest version for a SKU<\/pre>\n<p>Where did these values come from? In the previous article, the section <em>Knowing Your VM Options<\/em> explored how to determine what images are available for building a VM. You can think of an image as a virtual ISO or DVD that you\u2019d use to install an operating system and software on a new computer. The first variable, $vmSize, indicates the virtualized hardware platform. How many CPUs, cores, RAM, disk space and the like.<\/p>\n<p>At this point, you are ready to create your new virtual machine in Azure. If you followed along in the last article, you have the network created, set the firewall rules, and established the virtual NIC for the VM to use. As seen above, you have the information needed to indicate what image to use and how much hardware to allocate to the machine. Now all that\u2019s left is to simply call the PSAzure module\u2019s New-PSAzureVM function.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  New-PSAzureVM `\r\n     -ResourceGroupName $resourceGroup `\r\n     -VMName $vmName `\r\n     -VMAdminName $adminName `\r\n     -VMAdminPassword $adminPW `\r\n     -VMSize $vmSize `\r\n     -Publisher $vmPublisher `\r\n     -Offer $vmOffer `\r\n     -SKU $vmSKU `\r\n     -StorageAccountName $storageAccount `\r\n     -DiskName $diskName `\r\n     -NICName $nicName `\r\n     -Location $location `\r\n     -Verbose<\/pre>\n<p>\u2018Simply\u2019 is a bit misleading, there\u2019s actually a lot going on inside the function. Here\u2019s what needs to be done.<\/p>\n<ol>\n<li>Make sure the VM doesn\u2019t already exist; if it does just quit the function.<\/li>\n<li>Create the administrator credentials.<\/li>\n<li>Generate an Azure RM configuration object.<\/li>\n<li>Specify the base operating system (Windows or Linux)<\/li>\n<li>Indicate which image to use to build the VM, in other words the specific operating system and software.<\/li>\n<li>Add the virtual NIC to the configuration.<\/li>\n<li>Designate which storage account should be used to save the VM.<\/li>\n<li>Get the URI for the virtual disk and add that to the VM configuration.<\/li>\n<li>Create the VM!<\/li>\n<\/ol>\n<h3>Step 1 \u2013 Does the VM already exist?<\/h3>\n<p>It starts like almost every other function in the PSAzure module, by checking to see if the VM already exists.<\/p>\n<p><strong>NOTE: The code shown in these steps is from the module, so you will not run them.<\/strong><\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  $exists = Test-PSAzureVM -ResourceGroupName $ResourceGroupName -VMName $VMName<\/pre>\n<p>The Test-PSAzureVM function is pretty simple. It starts with a check to see if the virtual machine exists:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  $exists = <strong>Get-AzureRmVm<\/strong> -ResourceGroupName $ResourceGroupName |\r\n               <strong>Where-Object<\/strong> Name -eq $VMName<\/pre>\n<p>It then returns either true or false. Back in the New-PSAzureVM function, it checks this result at the beginning of an if statement. Should the VM not exist the code in the if, consisting of the remaining steps, will be executed.<\/p>\n<h3>Step 2 \u2013 Administrator Credentials<\/h3>\n<p>Like any other computer, real or virtual, the VM will need an administrator account. The first order of business then is to take the password and convert it to a secure string. With that you can create a credential object.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      $password = $VMAdminPassword |\r\n        <strong>ConvertTo-SecureString<\/strong> -AsPlainText -Force\r\n      $cred = <strong>New-Object<\/strong> PSCredential ($VMAdminName, $password)<\/pre>\n<h3>Step 3 \u2013 Create the VM Configuration Object<\/h3>\n<p>The next step is to begin creating an Azure VM configuration object. A shopping list is a good analogy for a VM configuration object. The configuration object is the shopping list itself, and it\u2019s created like this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">    $vm = <strong>New-AzureRmVMConfig<\/strong> -VMName $VMName -VMSize $VMSize<\/pre>\n<p>In addition to creating the \u2018shopping list\u2019, you also indicated what you want to name the list ($VMName), and how big the shopping cart should be ($VMSize). Now you just start adding items to the \u2018shopping list\u2019. Of course, in this case you are actually going to continue to add more information to the configuration in order to tell Azure what you want the finished VM to look like.<\/p>\n<h3>Step 4 \u2013 Base Operating System<\/h3>\n<p>The next step is to indicate what operating system you want, at a high level. The two choices, at least at the time of this writing, are Windows and Linux.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      $vm = Set-AzureRmVMOperatingSystem -VM $vm `\r\n                                         -Windows `\r\n                                         -ComputerName $VMName `\r\n                                         -Credential $cred `\r\n                                         -ProvisionVMAgent `\r\n                                         -EnableAutoUpdate<\/pre>\n<p>The syntax may look a bit odd here. In the -VM parameter, you pass in the $vm configuration. But then you return that back to the $vm variable. Technically, you are simply replacing whatever had been in the $vm variable with the result returned from Set-AzureRmVMOperatingSystem. Conceptually though, you are continuing to build enough information into a variable to create a virtual machine.<\/p>\n<h3>Step 5 \u2013 Set the Image to Use<\/h3>\n<p>At this point the $vm variable has information about the base configuration as well as which operating system to run. Next is to indicate the image you want.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      $vm = Set-AzureRmVMSourceImage -VM $vm `\r\n                                     -PublisherName $Publisher `\r\n                                     -Offer $Offer `\r\n                                     -Skus $SKU `\r\n                                     -Version $Version<\/pre>\n<p>You pass in the $vm variable built so far, along with the publisher, offer, SKU, and version. This adds to the VM configuration telling not only that you want Windows, but specifically which operating system and software as well. A note about the $version variable. When you called the New-PSAzureVM function, you didn\u2019t pass in a version parameter. In the parameter list at the top of the function you\u2019ll see that the $Version parameter defaults to \u2018latest\u2019.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">   [string]$Version = 'latest'<\/pre>\n<p>You could have course overridden this if you needed a specific version.<\/p>\n<h3>Step 6 \u2013 Adding the NIC<\/h3>\n<p>The next thing you need is an object variable for the virtual NIC. However, only the name of the NIC was passed in. That\u2019s where the PSAzure module\u2019s <strong>Get-PSAzureVirtualNIC<\/strong> function comes in handy.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      $nic = Get-PSAzureVirtualNIC -ResourceGroupName $ResourceGroupName `\r\n                                   -NICName $NICName<\/pre>\n<p>The <strong>Get-PSAzureVirtualNIC<\/strong> function uses the <strong>Get-AzureRmNetworkInterface<\/strong> cmdlet to get a NIC object based on just the name of the NIC and its resource group. The critical thing you need from the NIC object is its Id property. Once you have the NIC Id, you are ready to add the NIC to the configuration.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      $vm = <strong>Add-AzureRmVMNetworkInterface<\/strong> -VM $vm -Id $nic.Id<\/pre>\n<h3>Step 7 \u2013 Where to Store the VM<\/h3>\n<p>At this point you now know what you want to create but haven\u2019t yet said where to store it. That\u2019s where the next step comes in. You will need to have a reference to the storage account created (in the previous article) for this purpose.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      $storageAccount = Get-AzureRMStorageAccount `\r\n                          -ResourceGroupName $ResourceGroupName `\r\n                          -Name $StorageAccountName <\/pre>\n<p>Just to be clear, what you will actually be storing is the disk for the VM. In this step you now have a reference to the Azure storage account. This will be used in the next step to get the disk URI.<\/p>\n<h3>Step 8 \u2013 Get the Disk URI and Add to The Configuration<\/h3>\n<p>In this step you get the URI, or Uniform Resource Indicator, for the disk object. A URI is similar to a URL, except it doesn\u2019t point to a web page but instead to an object. You begin composing the URI by first accessing the endpoint of the storage account.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      $diskURI = $storageAccount.PrimaryEndpoints.Blob.ToString() `\r\n                   + 'vhds\/' + $DiskName + '.vhd'<\/pre>\n<p>After accessing the primary endpoint of the blob and converting that to a string, you then compose a file name by adding the disk name with a VHD extension. By prepending the disk name with vhds\/ you create what is in essence a virtual folder. This makes it easy to group the virtual disks together within this storage account. For example, you may want to come back later and add a second virtual drive to your VM, using this method would allow them to be grouped together.<\/p>\n<p>Once you have the URI, you can then add that to the VM configuration.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      $vm = <strong>Set-AzureRmVMOSDisk<\/strong> -VM $vm `\r\n                                -Name $DiskName `\r\n                                -VhdUri $diskURI `\r\n                                -CreateOption FromImage<\/pre>\n<p>Now the configuration is complete, and you can finally create your VM!<\/p>\n<h3>Step 9 \u2013 Create the VM!<\/h3>\n<p>That was a lot of work to get to the final step, calling the <strong>New-AzureRmVm<\/strong> cmdlet to create your virtual machine. In it you pass in the resource group, location, and configuration you so lovingly built.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      <strong>New-AzureRmVm<\/strong> -ResourceGroupName $ResourceGroupName `\r\n                    -Location $Location `\r\n                    -VM $vm<\/pre>\n<p>If you are following along at home, and call the <strong>New-PSAzureVM<\/strong> function, it can take several minutes for Azure to generate your virtual machine, so be patient. On average the time is between 3 and 5 minutes, although it has taken as long as 20 during what must have been a heavy load time for Azure. Again, be patient, this can be an excellent time to get some coffee.<\/p>\n<h2>Did It Work?<\/h2>\n<p>So, the <strong>New-PSAzureVM<\/strong> function completed without errors. How can you validate that it worked? Well, of course you could login to the Azure web portal, and look at your list of virtual machines.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1334\" height=\"328\" class=\"wp-image-78625\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/04\/word-image-256.png\" \/><\/p>\n<p>You can also run the following function, built into the PSAzure module, as shown in the <em>Create-AzureVM.ps1<\/em> example script.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  Get-PSAzureVMStatus -ResourceGroupName $resourceGroup `\r\n                      -VMName $vmName<\/pre>\n<p>It returns the following letting you know it is indeed there, and that it is running.<\/p>\n<pre class=\"theme:powershell-ise lang:ps decode:true \">VM running<\/pre>\n<p>The next step would be to access the new Azure VM. To do so, there\u2019s another function in PSAzure that will create an RDP file for you.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  $rdpFile = \"$($dir)\\$($vmName).rdp\"\r\n  New-PSAzureVMRDP -ResourceGroupName $resourceGroup `\r\n                   -VMName $vmName `\r\n                   -Path $rdpFile `\r\n                   -Verbose<\/pre>\n<p>The <strong>$rdpFile<\/strong> variable contains the path and name to give the RDP file. The $dir variable was set at the top of the <em>Create-AzureVM.ps1<\/em> script. The output should be an RDP file on your drive.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"616\" height=\"243\" class=\"wp-image-78626\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/04\/word-image-257.png\" \/><\/p>\n<p>You can either double click on the RDP file and run it from an explorer window, or you can launch it right inside PowerShell.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  Invoke-Item $rdpFile<\/pre>\n<p>In either case, you will then login to your VM using the admin name and password you setup. In this example, it was <strong>ArcaneCode<\/strong> and <strong>mySuperStr0ngP@ssword<\/strong>.<\/p>\n<h1><img loading=\"lazy\" decoding=\"async\" width=\"641\" height=\"400\" class=\"wp-image-78627\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/04\/word-image-258.png\" \/><\/h1>\n<h2>Managing Your Money \u2013 Stopping and Starting Azure VMs<\/h2>\n<p>There\u2019s no doubt, Azure is not an inexpensive proposition, although in many cases much cheaper than setting up physical computers. The PSAzure module has two functions for starting and stopping your VMs, <strong>Stop-PSAzureVM<\/strong> and <strong>Start-PSAzureVM<\/strong>. These are shown in the corresponding example scripts <em>Stop-AzureVM.ps1<\/em> and <em>Start-AzureVM.ps1<\/em>.<\/p>\n<p>After validating the VM exists, the <strong>Start-PSAzureVM<\/strong> function checks to see if the state of the VM is something other than <em>VM running<\/em>. If so, it uses the <strong>Start-AzureRmVm<\/strong> cmdlet to start it.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      <strong>Start-AzureRmVM<\/strong> -ResourceGroupName $ResourceGroup `\r\n                        -Name $VMName <\/pre>\n<p>The <strong>Stop-PSAzureRmVm<\/strong> is similar. After it validates the VM exists, it checks the status. If it is in a state <em>VM running<\/em>, it then attempts to stop it.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">      <strong>Stop-AzureRmVM<\/strong> -ResourceGroupName $ResourceGroup `\r\n                       -Name $VMName `\r\n                       -Force<\/pre>\n<p>Note that there are actually two types of \u2018stopped\u2019 states for a VM. In the first state the VM is <em>stopped<\/em>, in other words turned off. This is similar, but not exactly like, putting a physical computer into a hibernate state. The VM can be started again, and quickly. The down side is you still incur costs for the VM in this state. While not as much as when it is running, there is still a cost. This is what happens when you are inside the virtual machine and use the <em>Shut Down<\/em> option from the Start menu. Within the Azure portal, the VM will show its status as <em>Stopped<\/em>.<\/p>\n<p>The second option is to <em>deallocate<\/em> the VM, which is the method the <strong>Stop-PSAzureRmVm<\/strong> function uses. It turns off the VM completely. While deallocated, there is no cost to the VM (other than the storage space), the downside is it can take a little bit longer to restart the VM. If you are in the portal and pick <em>Stop<\/em> on a VM, it goes to a <em>Stopped (deallocated)<\/em> status (whether the machine had been in a Running or Stopped status).<\/p>\n<p>To be clear, in both cases there are costs to store the VM within the storage account. In addition to storage account costs, in a stopped state the VM will still incur further minimal charges. In a deallocated state, there is no additional charge, at least at the time of this writing.<\/p>\n<h2>Putting Away Your Toys<\/h2>\n<p>When I was young, mom always taught me to put away my toys. In this case it means removing any objects created during this series, including the virtual machine, storage, networks and resource group. The example script <em>Remove-AzureVM.ps1<\/em> found in the <em>PSAzure-Examples<\/em> folder from the PSAzure module downloaded from the first article demonstrates these methods.<\/p>\n<p>First, if all you want to do is delete the virtual machine itself, you can use the <strong>Remove-PSAzureVM<\/strong> function in the PSAzure module.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  Remove-PSAzureVM -ResourceGroupName $resourceGroup `\r\n                   -VMName $vmName  <\/pre>\n<p>This function does several things. First, it verifies the VM exists. If it does, it calls the <strong>Stop-PSAzureRmVm<\/strong> which stops the VM if it is running. Finally, it uses the Azure cmdlet <strong>Remove-AzureRmVm<\/strong> to delete it. This is yet another example that demonstrates the usefulness of writing your own functions to combine cmdlets typically called together. Here I\u2019ve combined three common tasks into one function. Checking to see if the VM exists, and only proceeding if it does, as opposed to giving an error. Then it checks to see if the VM is running and if so stops it, again to avoid an error. Finally, it removes the VM.<\/p>\n<p>After you remove the VM you\u2019ll likely want to remove the virtual NIC, unless of course you plan to reuse it.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  Remove-PSAzureVirtualNIC -ResourceGroupName $resourceGroup `\r\n                           -NICName $nicName `\r\n                           -Verbose<\/pre>\n<p>With the NIC gone, you can proceed to remove the virtual network (often abbreviated vnet). Note if there is a NIC attached to the vnet, removing it will result in an error.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\"> Remove-PSAzureVirtualNetwork -ResourceGroupName $resourceGroup `\r\n                               -VirtualNetworkName $networkName <\/pre>\n<p>It should be obvious at this point, but if you have other machines using this vnet you are going to have issues.<\/p>\n<p>If the VM is gone, you may not need the storage account. Assume you are not using it for other tasks, you could delete it as well.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  Remove-PsAzureStorageAccount -ResourceGroupName $resourceGroup `\r\n                               -StorageAccountName $storageAccount `\r\n                               -Verbose<\/pre>\n<p>All of these removal functions assume you know what you are doing, and don\u2019t waste your time with \u201cAre you sure?\u201d warnings or asking you to confirm. They assume you are an adult and are taking responsibility for your code. Suppressing these is also important should you be running your scripts in an automated fashion. There won\u2019t be anyone around to hit &#8216;yes&#8217; when the script is run automatically.<\/p>\n<p>These are listed individually, so you can pick and choose. For example, you may wish to just delete a VM, but reuse the network for other virtual machines. Having individual functions for each object allows you flexibility in removing the things you no longer need but retaining those you do want.<\/p>\n<p>There is one final function you can use to obliterate everything with one fell swoop. (If this article was a movie, this is the point where the scary music starts playing.) The PSAzure module has <strong>Remove-PsAzureResourceGroup<\/strong>, which deletes a resource group, and <em><strong>everything in it<\/strong><\/em>. Everything. It\u2019s all gone. So, to make this perfectly clear:<\/p>\n<p><strong>USE AT YOUR OWN RISK!<\/strong><\/p>\n<pre class=\"lang:ps theme:powershell-ise \">  Remove-PsAzureResourceGroup -ResourceGroupName $resourceGroup\r\n   <\/pre>\n<p>Like the other functions in PSAzure, it doesn\u2019t ask \u201cAre You Sure\u201d questions. Once you run this, everything gets wiped out, just like the dinosaurs when that big meteor hit a few (million) years back. However, it can be a great way to clean up everything you created during this series with a single line of code.<\/p>\n<h2>Summary<\/h2>\n<p>In this two-part series you learned how to create virtual machines using functions in the freely available PSAzure module. Creating wrapper functions for many Azure tasks and bundling them in a module offers many advantages, as outlined in a previous article <a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/powershell-functions-reusability-restartability-azure\/\">PowerShell Functions for Reusablity and Restartability in Azure<\/a>.<\/p>\n<p>Each function was examined, detailing the cmdlets in the AzureRM module that they called. This was especially true with the <strong>New-PSAzureVM<\/strong> function, as there were multiple steps that needed to be called, in a specific order, to create the new Azure VM. Wrapping these steps into a function ensures that all the prerequisites were handled so the VM could be created successfully.<\/p>\n<p>You can download the complete <a href=\"https:\/\/github.com\/arcanecode\/PowerShell\/tree\/master\/PSAzure_Module\">PSAzure module code<\/a>, along with samples of using it, on GitHub.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The ability to quickly spin up a virtual machine is one of the great things about Azure. In this article, Robert Cain describes the steps to set up a VM using PowerShell using his PSAzure module. &hellip;<\/p>\n","protected":false},"author":316962,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143513,35],"tags":[95506],"coauthors":[52865],"class_list":["post-78624","post","type-post","status-publish","format-standard","hentry","category-containers-and-virtualization","category-powershell","tag-automate"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/78624","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/316962"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=78624"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/78624\/revisions"}],"predecessor-version":[{"id":78629,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/78624\/revisions\/78629"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=78624"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=78624"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=78624"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=78624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}