Catch errors when creating a Hyper-V VM with Powershell - powershell

Is there any way to catch an error when creating a new Hyper-V VM with Powershell?
New-VM -Name $vmname `
-MemoryStartupBytes $memorySize `
-Path D:\Hyper-V\ `
-NewVHDPath D:\Hyper-V\$vmname\$vmname.vhdx `
-NewVHDSizeBytes $diskSize `
-Generation 2 `
-SwitchName "vSwitch"
As far as I can see, there is no way to add -ErrorAction Stop to New-VM.
Errors can occur, for example, if the virtual switch does not exist. In this case no further tasks should be processed and the script should be terminated.

What you are saying is not error. You have to have a conditional check. I have given a rough skeleton for you to proceed along with error handling:
try ##runs everything in the try block to capture and error in the catch block
{
If(Get-VM -Name $vmname) ##checks if the VM is existing or not by fetching the VM information. It has further parameters. Kindly google about them for better understanding
{
"$vmname is already present"
}
else
{
## Only creates the VM when it doesnt exist
New-VM -Name $vmname `
-MemoryStartupBytes $memorySize `
-Path D:\Hyper-V\ `
-NewVHDPath D:\Hyper-V\$vmname\$vmname.vhdx `
-NewVHDSizeBytes $diskSize `
-Generation 2 `
-SwitchName "vSwitch"
}
}
catch
{
$_.Exception.Message ## Only captures the error exception message and not the entire error.
}
I have given explanations in the Comment block for you to understand it better.

Related

Powershell Script Just Returns with No Log Output

PSA: First time I've used PowerShell, my go-to is Bash or Python, sorry if it looks weird.
I have created a Powershell script that, if our Windows 2019 Server reboots (powercut for example), it'll check to see if Get-HnsNetwork | ? Name -eq "l2bridge" returns. If there is nothing returned, it then calls the function Create-Hns which creates an External and l2bridge interface which is then used with docker and kubernetes. Below is the code tha I have so far.
function Write-Log {
param (
[Parameter(Mandatory=$False, Position=0)]
[String]$Entry
)
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff') $Entry" | Out-File -FilePath $LogFilePath -Append
}
Function Create-Hns {
Write-Log -Entry "Starting to create the HnsNetwork..."
Try {
ipmo c:\k\SDN\windows\helper.psm1 -force
ipmo c:\k\SDN\windows\hns.psm1 -force
if(!(Get-HnsNetwork | ? Name -eq "External")) {
New-HNSNetwork `
-Name "External" `
-Type NAT `
-AddressPrefix "192.168.x.x/30" `
-Gateway "192.168.x.x" `
-Verbose
}
if(!(Get-HnsNetwork | ? Name -eq "l2bridge")) {
New-HNSNetwork `
-Name l2bridge `
-Type L2Bridge `
-AddressPrefix "192.168.x.x/24" `
-Gateway "192.168.x.x" `
-Verbose
}
$hnsNetwork = Get-HnsNetwork | ? Name -eq l2bridge
$hnsEndpoint = New-HnsEndpoint `
-NetworkId ($hnsNetwork).Id `
-Name "l2bridge" `
-IPAddress "192.168.x.x" `
-Gateway "0.0.0.0" `
-Verbose Attach-HnsHostEndpoint `
-EndpointID ($hnsEndpoint).Id `
-CompartmentID 1
} Catch {
Write-Log -Entry "An error occured"
Write-Log -Entry $_
Break
}
If ($?) {
Write-Log -Entry "VERIFY HERE"
Wrtie-Log -Entry $_
}
}
$LogFilePath = "C:\k\CreateHns.log"
$sFetch = (Get-HnsNetwork | ? Name -eq "l2bridge")
If (!$sFetch) {
Write-Log -Entry "Didn't get any info on l2bridge, we need to create one."
Create-Hns
Else {
Write-Log -Entry "Got information for the l2bridge, nothing needs creating."
Write-Log -Entry "Nothing to do"
}
}
When I run the script with ./Check-HnsNetwork.ps1 in Powershell, it just returns and doesn't log out to the log file. According to VS code, it's formatted correctly.
Is there something I'm doing wrong with the above code block? Any advice would be appreciated.
As long as scoping is not an issue here, there are some errors in the posted code that need to be fixed. If $sFetch never evaluates to $false or $null, the errors do not present themselves at runtime. Consider the following:
The entry Wrtie-Log -Entry $_ needs to be changed to Write-Log -Entry $_
If (!$sFetch) {
Write-Log -Entry "Didn't get any info on l2bridge, we need to create one."
Create-Hns is missing the closing }

Azure power shell Virtual machine creation issue

I am new to Azure power shell world. I am trying to create power shell script to automate VM creation. All my script running well, VM is getting created as well, but it’s getting hanged on its last line. So even though the virtual machine gets created my power shell script is keep on running. Please advise me how to address this issue.
Write-Verbose 'Creating VM...'
$result = New-AzureRmVM -ResourceGroupName $resourceGroupName -Location $location -VM $vm
if($result.Status -eq 'Succeeded') {
Write-Verbose $result.Status
Write-Verbose ('VM named ''{0}'' is now ready, you can connect using username: {1} and password: {2}' -f $vmName, $adminUsername, $adminPassword)
}
else {
Write-Error 'Virtual machine was not created successfully.'
}
you can take another way, to verify the state of the VM
New-AzureRmVM -ResourceGroupName $resourceGroupName -Location $location -VM $vm
if((Get-AzureRmVM -Name $vmName).Status -eq "ReadyRole"){
#Do something awesome here :)
}
and have a look at: https://4sysops.com/archives/how-to-create-an-azure-vm-with-powershell/
return type of $result will be a psobject. After successful VM creation the output will be in below format
$result[0] = "Provisioning succeeded"
$result[1] = "VM running"
So, try this-
if($result.ProvisioningState -eq "Succeeded")
{
Write-Verbose ('VM named ''{0}'' is now ready, you can connect using username: {1} and password: {2}' -f $VMName, $username, $password)
}
else
{
Write-Error 'Virtual machine was not created successfully.'
}

Check If Azure Resource Group Exist - Azure Powershell

I'm trying to verify if ResourceGroup exist or not so i thought that following code should return true or false, but it doesn't output anything.
$RSGtest = Find-AzureRmResource | Format-List ResourceGroupName | get-unique
$RSGtest -Match "$myResourceGroupName"
Why am I not getting any output?
Update:
You should use the Get-AzResourceGroup cmdlet from the new cross-plattform AZ PowerShell Module now. :
Get-AzResourceGroup -Name $myResourceGroupName -ErrorVariable notPresent -ErrorAction SilentlyContinue
if ($notPresent)
{
# ResourceGroup doesn't exist
}
else
{
# ResourceGroup exist
}
Original Answer:
There is a Get-AzureRmResourceGroup cmdlet:
Get-AzureRmResourceGroup -Name $myResourceGroupName -ErrorVariable notPresent -ErrorAction SilentlyContinue
if ($notPresent)
{
# ResourceGroup doesn't exist
}
else
{
# ResourceGroup exist
}
try this
$ResourceGroupName = Read-Host "Resource group name"
Find-AzureRmResourceGroup | where {$_.name -EQ $ResourceGroupName}
I am a PS newbie and I was looking for a solution to this question.
Instead of searching directly on SO I tried to investigate on my own using PS help (to get more experience on PS) and I came up with a working solution.
Then I searched SO to see how I compared to experts answers.
I guess my solution is less elegant but more compact. I report it here so others can give their opinions:
if (!(Get-AzResourceGroup $rgname -ErrorAction SilentlyContinue))
{ "not found"}
else
{"found"}
Explanation of my logic: I analyzed the Get-AzResourceGroup output and saw it's either an array with found Resource groups elements or null if no group is found. I chose the not (!) form which is a bit longer but allows to skip the else condition. Most frequently we just need to create the resource group if it doesn't exist and do nothing if it exists already.
I was also looking for the same thing but there was a additional condition in my scenario.
So I figured it out like this. To get the scenario details follow
$rg="myrg"
$Subscriptions = Get-AzSubscription
$Rglist=#()
foreach ($Subscription in $Subscriptions){
$Rglist +=(Get-AzResourceGroup).ResourceGroupName
}
$rgfinal=$rg
$i=1
while($rgfinal -in $Rglist){
$rgfinal=$rg +"0" + $i++
}
Write-Output $rgfinal
Set-AzContext -Subscription "Subscription Name"
$createrg= New-AzResourceGroup -Name $rgfinal -Location "location"
Had a similar challenge, I solved it using the script below:
$blobs = Get-AzureStorageBlob -Container "dummycontainer" -Context $blobContext -ErrorAction SilentlyContinue
## Loop through all the blobs
foreach ($blob in $blobs) {
write-host -Foregroundcolor Yellow $blob.Name
if ($blob.Name -ne "dummyblobname" ) {
Write-Host "Blob Not Found"
}
else {
Write-Host "bLOB already exist"
}
}

Start-AzureStorageBlobCopy error in Automation runbook

I'm following this guide to automate backups of Linux VMs in Azure Automation. Everything goes well in testing on initial run, but the second and all subsequent tests return the following error:
11/26/2014 11:03:45 AM, Error: Start-AzureStorageBlobCopy : One or more errors occurred.
At LinuxVMBackup:40 char:40
+
+ CategoryInfo : CloseError: (:) [Start-AzureStorageBlobCopy], AggregateException
+ FullyQualifiedErrorId :
AggregateException,Microsoft.WindowsAzure.Commands.Storage.Blob.Cmdlet.StartAzureStorageBlobCopy
Here is the runbook:
workflow LinuxVMBackup
{
param (
[Parameter(Mandatory=$true)]
[PSCredential]
$Cred,
[Parameter(Mandatory=$true)]
[string]
$subName,
[Parameter(Mandatory=$true)]
[string]
$serviceName,
[Parameter(Mandatory=$true)]
[string]
$vmName
)
# Login and get VM
$null = Add-AzureAccount -Credential $Cred
$null = Select-AzureSubscription -SubscriptionName $subName
$vm = Get-AzureVM -ServiceName $serviceName -Name $vmName
# Stop VM
$vm | Stop-AzureVM -StayProvisioned
# Get OS and Data Disks
$vmOSDisk = Get-AzureOSDisk -VM (Get-AzureVM -ServiceName $serviceName -Name $vmName)
$vmDataDisks = Get-AzureDataDisk -VM (Get-AzureVM -ServiceName $serviceName -Name $vmName)
# Get and set storage name
$StorageAccountName = $vmOSDisk.MediaLink.Host.Split('.')[0]
Set-AzureSubscription -CurrentStorageAccount $StorageAccountName -SubscriptionName $subName
$backupContainerName = "backups"
if (!(Get-AzureStorageContainer -Name $backupContainerName -ErrorAction SilentlyContinue)) {
New-AzureStorageContainer -Name $backupContainerName -Permission Off
}
# Snapshot OS Disk
$vmOSBlobName = $vmOSDisk.MediaLink.Segments[-1]
$vmOSContainerName = $vmOSDisk.MediaLink.Segments[-2].Split('/')[0]
#Error on this line
Start-AzureStorageBlobCopy -SrcContainer $vmOSContainerName -SrcBlob $vmOSBlobName -DestContainer $backupContainerName
#Error on this line
Get-AzureStorageBlobCopyState -Container $backupContainerName -Blob $vmOSBlobName -WaitForComplete
#Snapshot Data Disks
ForEach ($vmDataDisk in $vmDataDisks) {
$vmDataBlobName = $vmDataDisk.MediaLink.Segments[-1]
$vmDataContainerName = $vmDataDisk.MediaLink.Segments[-2].Split('/')[0]
Start-AzureStorageBlobCopy -SrcContainer $vmDataContainerName -SrcBlob $vmDataBlobName -DestContainer $backupContainerName -Force
Get-AzureStorageBlobCopyState -Container $backupContainerName -Blob $vmDataBlobName -WaitForComplete
}
#Get blobs in storage and output
$insertedBlobs = Get-AzureStorageBlob -Container $backupContainerName
Write-Output $insertedBlobs
$vm | Start-AzureVM
}
I couldn't find anything online, save an answer on Microsoft forums for a similar error stating that the VM needs to be stopped, so I thought maybe the VM is not fully stopped when Start-AzureStorageBlobCopy is initiated. I tried testing with a stopped VM and still got the error.
Thanks for your help.
Given the error only happens after the first successful copy, what is probably happening is the Start-AzureStorageBlobCopy cmdlet is trying to request user confirmation for the operation, since it would overwrite existing data. Since Azure Automation runs runbooks in a non-interactive session, user confirmation cannot be asked, so the command is failing.
Adding -Force should "force" user confirmation for the cmdlet and fix the issue. You have this parameter on the second instance of Start-AzureStorageBlobCopy, but not the first.
PS - You should put this runbook in our runbook gallery so others can take advantage of it!

Azure: How to check storage account exists in Azure with Get-AzureStorageAccount

I am building a power shell script to automate the setup of a website environment in Azure. This web uses an account storage. I want to the script not to create the account storage if exists.
I thought that using Get-AzureStorageAccount this way may work but it does not:
Write-Verbose "[Start] creating $Name storage account $Location location"
$storageAcct = Get-AzureStorageAccount –StorageAccountName $Name
if (!$storageAcct)
{
$storageAcct = New-AzureStorageAccount -StorageAccountName $Name -Location $Location -Verbose
if ($storageAcct)
{
Write-Verbose "[Finish] creating $Name storage account in $Location location"
}
else
{
throw "Failed to create a Windows Azure storage account. Failure in New-AzureStorage.ps1"
}
}
else
{
Write-Verbose "$Name storage account in $Location location already exists, skipping creation"
}
The issue is I don't know how to handle the return of Get-AzureStorageAccount.
Thank you very much in advance!
I would suggest using the Test-AzureName cmdlet to determine if it exists. So, something like this.
if (!(Test-AzureName -Storage $Name))
{
Write-Host "Creating Storage Account $Name"
New-AzureStorageAccount -StorageAccountName $Name -Location $Location
}
You can use Test-AzureName for other services too, such as Cloud Services, WebSites, and ServiceBus. It returns True if it exists, False otherwise.
Get-AzureRmStorageAccountNameAvailability -Name "accountname"
Try this:
$Name = "myStorageAccount"
$Location = "myLocation"
Write-Host "[Start] creating $Name storage account $Location location"
try{
Get-AzureStorageAccount –StorageAccountName $Name -ErrorAction Stop | Out-Null
Write-Host "$Name storage account in $Location location already exists, skipping creation"
}
catch{
Write-Host "[Finish] creating $Name storage account in $Location location"
New-AzureStorageAccount -StorageAccountName $Name -Location $Location -Verbose
}
Test-AzureName didn't work with our build agents and we already had a try/catch in code so a second one would require building it out as a function. I opted for that standard get and check if null, use -ErrorAction Ignore to stop it throwing an exception
# Check for storage account and create if not found
$StorageAccount = Get-AzureRmStorageAccount -Name $StorageAccountName -ResourceGroupName $StorageAccountRG -ErrorAction Ignore
if ($StorageAccount -eq $null)
{
New-AzureRmStorageAccount -Location "West Europe" -Name $StorageAccountName -ResourceGroupName $StorageAccountRG -SkuName Standard_LRS -Kind Storage
$StorageAccount = Get-AzureRmStorageAccount -Name $StorageAccountName -ResourceGroupName $StorageAccountRG
}
#Rick Rainey's solution works if you're logged in using Add-AzureAccount. However, Azure and powershell have a conflicting and confusing suite of login accounts (Windows Live versus AD) and login mechanisms (Classic: Add-AzureAccount; Resource manager: Login-AzureRmAccount). Some Azure powershell cmdlets require a specific login; further, some require a specific account type!
To clear through this thicket of complicated, undocumented, and confusing permission issues, we always use an AD account, logging in via Login-AzureRmAccount. We also use Azure resource manager (ARM) resources and cmdlets, following Microsoft's movement to ARM as its recommended and strategic approach. However, #RIck's solution is one which the ARM login doesn't work with. :-( So you need another approach, which is #Darren's (for storage). However, for a generic replacement for Test-AzureName I'd suggest Find-AzureRmResource. In the case of storage
$StorageObject = Find-AzureRmResource -ResourceType "Microsoft.Storage/storageAccounts" | Where-Object {$_.Name -eq $storageName}
if ( !$StorageObject ) {
$storageLocation = (Get-AzureRmResourceGroup -ResourceGroupName $resourceGroup).Location
$storageType = "Standard_LRS"
New-AzureRmStorageAccount -ResourceGroupName $resourceGroup -Name $storageName -Location $storageLocation -Type $storageType
}
You should use the latest Powershell module Az.
if ($(Get-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName) -eq $null)
{
# does not exist
}
With the current Az module for PowerShell Version 7, the Get-AzStorageAccountNameAvailability cmdlet might offer a more efficient solution as it was designed specifically for this task. Here is an example:
# ... declare variables and specify values ...
$checkNameAvail = (Get-AzStorageAccountNameAvailability -Name $storageAccountName) | `
Select-Object NameAvailable
if ($checkNameAvail.NameAvailable)
{
Write-Host 'Account name available! Please wait while your resource is being created'
# Create account. Variables used in this example would have been declared earlier in the script.
$storageAccount = (New-AzStorageAccount -ResourceGroupName $resourceGroupName `
-AccountName $storageAccountName `
-Location $location `
-SkuName $skuType `
-AllowBlobPublicAccess $false -EnableHttpsTrafficOnly $true)
# ...
}
else
{
# This section of the script executes if the name is not available
Write-Host "The name <$storageAccountName> is not available. Suggest a new globally unique name!"
}
The condition above will return False, and execute the else statement because the boolean value returned by the cmdlet is in [0] as shown in the PowerShell command-line test below. The availability information (boolean) can thus be stripped from the object returned by the cmdlet and (as in this example) used as a condition in the rest of the script.
PS C:\> Get-AzStorageAccountNameAvailability -Name testaccount1
NameAvailable Reason Message
------------- ------ -------
False AlreadyExists The storage account named testaccount1 is already taken.
Use the error variable
Get-AzStorageAccount -ResourceGroupName 'RG-QA-TEST' -Name 'staccountfor12334ff' -ErrorVariable ev1 -ErrorAction SilentlyContinue
if ($ev1) {
Write-Host "-------------------------- Creating OEM Storage"
//create storage account
}
I had this challenge when setting up Azure storage accounts for Static website hosting using Powershell in Octopus Deploy.
Here's how I fixed it:
Using the Az module for Azure Powershell I did the following:
# Define Variables
$RESOURCE_GROUP_NAME = my-resource-group
$LOCATION = northeurope
$STORAGE_ACCOUNT_NAME = myapplication
$SKU_NAME = Standard_GRS
$STORAGE_KIND = StorageV2
# Check Storage Account and Create if not Found
$STORAGE_ACCOUNT = Get-AzStorageAccount -ResourceGroupName $RESOURCE_GROUP_NAME -Name $STORAGE_ACCOUNT_NAME -ErrorAction Ignore
if ($STORAGE_ACCOUNT -eq $null) {
Write-Host 'Creating storage account'
New-AzStorageAccount -ResourceGroupName $RESOURCE_GROUP_NAME -AccountName $STORAGE_ACCOUNT_NAME -Location $LOCATION -SkuName $SKU_NAME -Kind $STORAGE_KIND
Write-Host "$STORAGE_ACCOUNT_NAME storage account successfully created"
}
else {
Write-Host "$STORAGE_ACCOUNT_NAME storage account already exists"
}
Note:
-ErrorAction Ignore - This ignores the exception that would arise if the storage account does not exist
Write-Host " " - Double quotes were used to allow for string interpolation since we are connecting strings and variables.
That's all.
I hope this helps