How to loop through mulitple azure subscriptions parallelly - azure

I am trying with nested ForEach-Object -Parallel to loop through multiple azure subscriptions parallelly and get data from all VMs in one go. I am using below code:
$SubsJob = Get-AzSubscription -WarningAction SilentlyContinue | Where-Object {$_.Name -match 'abc'} | ForEach-Object -Parallel {
$Context = Set-AzContext -Tenant $_.TenantId -SubscriptionId $_.SubscriptionId
[System.String]$ScriptBlock = {Get-Process}
$VMsJob = Get-AzVM | ForEach-Object -Parallel {
$FileName = $using:Context.Subscription.Name + "_$($_.Name)_" + (Get-Random) + ".ps1"
Out-File -FilePath $FileName -InputObject $using:ScriptBlock -NoNewline
$Output = Invoke-AzVMRunCommand -Name $_.Name -ResourceGroupName $_.ResourceGroupName -CommandId 'RunPowerShellScript' -ScriptPath $FileName
$PSCustomObject = [PSCustomObject]#{Subscription = $using:Context.Subscription.Name; ServerName = $_.Name; Output = $Output}
#Remove-Item -Path $FileName -Force -ErrorAction SilentlyContinue
Write-Output $PSCustomObject
} -ThrottleLimit 200 -AsJob
Write-Output $VMsJob
} -ThrottleLimit 200 -AsJob
I am not able to get it work, not sure what is wrong. One thing I observed while debugging is that, Get-AzVM command is getting VMs list from all the subscriptions rather than specific subscription. I came to know that by looking at the Out-File -FilePath $FileName which are generated.
sub1_server1_980337551.ps1
sub2_server1_42701325.ps1
server1 is only present in sub1 but it is being picked in sub2 as well.

Related

How to split different values in powershell by a line

With this script i am able to fetch all the Tags that a VM has but i want that in output the each key and its value should be separated by a line in the way that each key and its value appears on different lines like this
reference image
# Sign into Azure Portal
connect-azaccount
# Fetch the Virtual Machines from the subscription
$azureVMDetails = get-azvm
# Fetch the NIC details from the subscription
$azureNICDetails = Get-AzNetworkInterface | ?{ $_.VirtualMachine -NE $null}
#Fetching Virtual Machine Details
$virtual_machine_object = $null
$virtual_machine_object = #()
#Iterating over the NIC Interfaces under the subscription
foreach($azureNICDetail in $azureNICDetails){
#Fetching the VM Name
$azureVMDetail = $azureVMDetails | ? -Property Id -eq $azureNICDetail.VirtualMachine.id
#Fetching the VM Tags
foreach($azureDetail in $azureVMDetails) {
$vm_tags = $azureVMDetail| Select-Object -Property (
#{name='Tags'; expression = {($_.tags.GetEnumerator().ForEach({ '{0} : {1}' -f $_.key, $_.value }) -join ';')}}
)
}
#VM Details export
$virtual_machine_object_temp = new-object PSObject
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "name" -Value $azureVMDetail.Name
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "comments" -Value ($vm_tags.Tags -join ';')
$virtual_machine_object += $virtual_machine_object_temp
}
#Report format and path
$virtual_machine_object | Export-Csv "C:\Users\JOHN\Desktop\Inventory\Final Scripts\VM_details_$(get-date -f dd.MM.yyyy).csv" -NoTypeInformation -Force
I tried to reproduce the same in my environment and got the results successfully by using the below PowerShell script:
$vmdeatil = Get-AzVm -Name testvm | Select -ExpandProperty Tags
$value = $vmdeatil
foreach($i in 0..($value.Count -1))
{
$ErrorActionPreference = ‘SilentlyContinue’
[array]$report += [pscustomobject] #{
key = $key[$i]
name = $value[$i]
}
}
$report | Export-Csv -Path "C:\Users\ruk1.csv" -NoTypeInformation
Response:
The output is successfully exported in the csv file like below:

Powershell If Statement not working - Posh-ACME

I am struggling to get the last if statement to work.
I have a blob storage account which contains the directories mentioned and a certificate.
I want to import that certificate to the keyvault.
When I run the pipeline (which contains the below script), it just runs to where I have put the Write-host 'everything..'
Can someone please assist why it won't work, I have tried to separate to 3 if statements, remove the if statement nothing has worked.
param (
[string] $CertificateNames,
[string] $KeyVaultResourceId
)
# Split certificate names by comma or semi-colon
$certificateName = $CertificateNames.Replace(',', ';') -split ';' | ForEach-Object -Process { $_.Trim() } | Select-Object -First 1
# For wildcard certificates, Posh-ACME replaces * with ! in the directory name
$certificateName = $certificateName.Replace('*', '!')
# Set working directory
$workingDirectory = Join-Path -Path "." -ChildPath "pa"
# Set Posh-ACME working directory
$env:POSHACME_HOME = $workingDirectory
Import-Module -Name Posh-ACME -Force
# Resolve the details of the certificate
$currentServerName = ((Get-PAServer).location) -split "/" | Where-Object -FilterScript { $_ } | Select-Object -Skip 1 -First 1
$currentAccountName = (Get-PAAccount).id
# Determine paths to resources
$orderDirectoryPath = Join-Path -Path $workingDirectory -ChildPath $currentServerName | Join-Path -ChildPath $currentAccountName | Join-Path -ChildPath $certificateName
$orderDataPath = Join-Path -Path $orderDirectoryPath -ChildPath "order.json"
$pfxFilePath = Join-Path -Path $orderDirectoryPath -ChildPath "fullchain.pfx"
Write-Host 'everything works up until here.. then breaks'
# If we have a order and certificate available
if ((Test-Path -Path $orderDirectoryPath) -and (Test-Path -Path $orderDataPath) -and (Test-Path -Path $pfxFilePath)) {
Write-Host 'check paths are ok'
$pfxPass = (Get-PAOrder $certificateName).PfxPass
# Load PFX
$certificate = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $pfxFilePath, $pfxPass, 'EphemeralKeySet'
# Get the current certificate from key vault (if any)
$azureKeyVaultCertificateName = $certificateName.Replace(".", "-").Replace("!", "wildcard")
$keyVaultResource = Get-AzResource -ResourceId $KeyVaultResourceId
$azureKeyVaultCertificate = Get-AzKeyVaultCertificate -VaultName $keyVaultResource.Name -Name $azureKeyVaultCertificateName -ErrorAction SilentlyContinue
Write-Host 'check if certificate is in kv'
# If we have a different certificate, import it
If (-not $azureKeyVaultCertificate -or $azureKeyVaultCertificate.Thumbprint -ne $certificate.Thumbprint) {
Import-AzKeyVaultCertificate -VaultName $keyVaultResource.Name -Name $azureKeyVaultCertificateName -FilePath $pfxFilePath -Password (ConvertTo-SecureString -String $pfxPass -AsPlainText -Force) | Out-Null
}
Write-Host 'check if upload is success'
}
When the pipeline is run, it breaks and there is no errors:
see screenshot here
Resolved this, the issue was the file paths didn't exist so the if statement couldn't check against an invalid file path.
As there was no errors, this was a bit harder to find the reason, instead I removed the if statement and added Write-Host "test" to see where things were broken in the code.

Remove-AzAutomationSchedule needs confirmation, even with confirm parameter

I got a code collecting and deleting expired azure automation schedules
Connect-AzAccount -SubscriptionId "guidstuff"
$schedules = Get-AzAutomationSchedule -ResourceGroupName "resgrp" -AutomationAccountName "automationacc" | ?{$_.name -like "schedule1*" -and $_.expirytime -lt (get-date)}
$cache = Get-AzAutomationSchedule -ResourceGroupName "resgrp" -AutomationAccountName "automationacc" | ?{$_.name -like "schedule2*" -and $_.expirytime -lt (get-date)}
if($cache.count -ne 0){
$schedules += $cache
}
foreach($schedule in $schedules){
Remove-AzAutomationSchedule -Confirm:$false -AutomationAccountName $schedule.AutomationAccountName -ResourceGroupName $schedule.ResourceGroupName -Name $schedule.name
}
Its asking deletion-confirmation for every schedule, am I or is the CMDlet wrong ?
Its asking deletion-confirmation for every schedule, am I or is the CMDlet wrong ?
As suggested by #theo, we reproduced in our local environment by using the below cmdlet:
By default, -Confirm value is set to false only.
Remove-AzAutomationSchedule -AutomationAccountName 'tstautmation'-ResourceGroupName 'test-rg' -Name 'terer' -Confirm:$false -Force
Now, it will not ask for deletion-confirmation every time when we run the above command.
Refer this document for more information.

Starting vms in batches of 5 in parallel

I have a set if VM in Azure and needs to start the VMS in a batch in parallel. For example I have 100 vm, I need a batch of 1-5 vm first start in parallel, then the next from 6-10, and so forth. I am able to start all the vms in parallel - but I can't find a way of adding limits in the foreach statement
foreach ($vm in ($vms | Select-Object 5))
Any suggestion of how I can do that?
$vms = Get-azvm -ResourceGroupName "VmList"
#$jobs = #()
foreach ($vm in ($vms | Select-Object 5))
{
$params = #($vm.Name)
$job = Start-Job -ScriptBlock {
param($ComputerName)
start-Azvm -Name $ComputerName -ResourceGroupName "VmList"
} -ArgumentList $params
}
# Wait for it all to complete
Wait-Job -Job $job
# Getting the information back from the jobs
Get-Job | Receive-Job
If you want to keep track yourself you could use splatting on Select-Object. Starting with -Skip 0 -First 5, increment skip so the next loop would be -Skip 5 -First 5 and so on.
$vms = Get-azvm -ResourceGroupName "VmList"
$batch = #{
Skip = 0
First = 5
}
Do
{
foreach ($vm in ($vms | Select-Object #batch))
{
$params = #($vm.Name)
$job = Start-Job -ScriptBlock {
param($ComputerName)
start-Azvm -Name $ComputerName -ResourceGroupName "VmList"
} -ArgumentList $params
}
# Wait for it all to complete
Wait-Job -Job $job
# Getting the information back from the jobs
Get-Job | Receive-Job
$batch.Skip += 5
}
until($batch.skip -ge $vms.count)

Read from txt file and convert to managed disks

I've got a list of virtua machines in Azure which I'm trying to convert to managed disks.
I have a list of vm's, I read from the list and export to csv capturing resourcegroupname and vm name, however I seem to get vms from the whole subscription.
Also when I attempt to import the csv, when I run $comps it returns the correct information in the csv, however I can't seem to pass them through to the next lines.
CSV format is
ResouceGroupName Name
RG-01 vm-01
RG-01 vm-02
RG-01 vm-03
RG-01 vm-04
The code I'm trying is
Login-AzureRmAccount
$sub = Get-AzureRmSubscription | ogv -PassThru
Select-AzureSubscription -SubscriptionId $sub
$virtualmachines = Get-Content C:\temp\vm.txt | % {
Get-Azurermvm | select ResourceGroupName,Name | export-csv c:\temp\vm.csv -NoClobber -NoTypeInformation -Append
}
$comps = Import-Csv c:\temp\Vm.csv |
foreach ($Comp in $comps)
{
Stop-AzureRmVM -ResourceGroupName $_.ResourceGroupName -Name $_.Name -Force
ConvertTo-AzureRmVMManagedDisk -ResourceGroupName $_.ResourceGroupName -VMName $_.Name
}
Thanks in advance..
For your issue, you export the virtual machines in a csv file and use it in the foreach code. So, it's unneccesary to use command:
$virtualmachines = Get-Content C:\temp\vm.txt | % {
Get-Azurermvm | select ResourceGroupName,Name | export-csv c:\temp\vm.csv -NoClobber -NoTypeInformation -Append
}
And your VMs all in a resourcegroup, you can get them with ResourceGroupName directly.
For the pipeline in foreach, it's unneccesary. You can use the following code that I make a little change with your code and it works well.
Login-AzureRmAccount
$sub = Get-AzureRmSubscription | ogv -PassThru
Select-AzureRmSubscription -Subscription $sub
Get-Azurermvm –ResourceGroupName RG-01 | select ResourceGroupName,Name | export-csv c:\temp\vm.csv -NoClobber -NoTypeInformation -Append
$comps = Import-Csv c:\temp\Vm.csv
foreach ($Comp in $comps)
{
Stop-AzureRmVM -ResourceGroupName $Comp.ResourceGroupName -Name $Comp.Name -Force
ConvertTo-AzureRmVMManagedDisk -ResourceGroupName $Comp.ResourceGroupName -VMName $Comp.Name
}
This is the screenshot of my result.

Resources