Problem with PSCustomObject data collection - azure

I'm preparing a table with information about VM name and provision date of OS disk. I can easily retrieve that information from $VM.disks.statuses.time[0] command, if individual VM is assigned to $VM, but I when i try to collect data into table, I got an error:
Cannot index into a null array.
At line:4 char:1
+ [PSCustomObject]#{
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
This is my code:
$VMs = Get-AzVM -status
$vmOutput = $VMs | ForEach-Object {
[PSCustomObject]#{
"VM Name" = $_.Name
"Provision Date" = $_.disks.statuses.time[0].ToString()
}
}

I can reproduce your issue, the issue was caused by the outputs of Get-AzVM -status and Get-AzVM -ResourceGroupName <ResourceGroupName> -Name <Name> -Status are different.
The output of Get-AzVM -status will not has the disks property, but when you get individual VM status via Get-AzVM -ResourceGroupName <ResourceGroupName> -Name <Name> -Status, it will have the property, so you got the error.
Get-AzVM -status:
Get-AzVM -ResourceGroupName <ResourceGroupName> -Name <Name> -Status:
Solution:
To fix the issue, just to use Get-AzVM -ResourceGroupName <ResourceGroupName> -Name <Name> -Status in your script.
$VMs = Get-AzVM -status
$vmOutput = $VMs | ForEach-Object {
$VMstatus = Get-AzVM -ResourceGroupName $_.ResourceGroupName -Name $_.Name -Status
[PSCustomObject]#{
"VM Name" = $VMstatus.Name
"Provision Date" = $VMstatus.disks.statuses.time[0].ToString()
}
}

You can use the Get-AzDisk command to retrieve disk creation information.
$disks = Get-AzDisk | Where-Object { $_.Managedby }
$vmOutput = foreach ($disk in $disks) {
[pscustomobject]#{"VM Name" = ($disk.ManagedBy -split "/")[-1]
"Provisioned Date" = $disk.TimeCreated
}
}

The error says:
Cannot index into a null array.
So my guess is that something here $_.disks.statuses.time[0].ToString() is $null. Therefore you should add some $nullchecks:
$VMs = Get-AzVM -status
$vmOutput = $VMs | ForEach-Object {
if ($_.disks -and $_.disks.statuses -and $_.disks.statuses.time -and ($_.disks.statuses.time.Count -gt 0)){
[PSCustomObject]#{
"VM Name" = $_.Name
"Provision Date" = $_.disks.statuses.time[0].ToString()
}
}
}
Hope that helps.

Related

Azure: Get resource for azure automation

I have runbook in Azure that i want to use in different RG,
My code
$vms = Get-AzVM -ResourceGroupName RG-TEST
foreach($vm in $vms)
{
$statuscheck = Get-AzVM -ResourceGroupName RG-TEST -Name $vm.Name -Status
if($statuscheck.Statuses.DisplayStatus[1] -eq "VM running")
{
Write-Output "Stopping virtual machine...$($vm.Name)"
Stop-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Force
}
else
{
Write-output "Virtual machine $($vm.Name) is already in stopped state"
}
}
How can I update the code that the script will get the name of the RG where it's located,
So that the RG is not hard coded
Dont know how to do it
Do something like this
$rgs = $(Get-AzVM)
# Get Distinct RG Names
$rgs = $rgs | Select-Object -Property ResourceGroupName | Sort-Object -Unique
foreach($rg in $rgs){
$vms = Get-AzVM -ResourceGroupName $rg.ResourceGroupName
foreach($vm in $vms)
{
$statuscheck = Get-AzVM -ResourceGroupName $rg.ResourceGroupName -Name $vm.Name -Status
if($statuscheck.Statuses.DisplayStatus[1] -eq "VM running")
{
Write-Output "Stopping virtual machine...$($vm.Name)"
Stop-AzVM -ResourceGroupName $rg.ResourceGroupName -Name $vm.Name -Force
}
else
{
Write-output "Virtual machine $($vm.Name) is already in stopped state"
}
}
}

Get Azure VM details by filtering using tags in powershell

I will like to use the Get-AzVm command to get list of VMs having a specific tag.
I have tried Get-AzVM | Where-Object {$_.Tags['Resource'] -eq "test"}
Still does not return VMS with the tag "Resource:test"
The output of get-azvm doesn't produce Tags for VM. But, Get-AzVM -ResourceGroupName ResourceGroupName -Name VMName does that.
So you need to loop through VMs, store the VM tag in a hashtable and then enumerate through the hastable to check your desired tag with value is there. Here goes the code-
$VMs = get-azvm
foreach ($VM in $VMs)
{
[Hashtable]$VMTag = (Get-AzVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name).Tags
foreach ($h in $VMTag.GetEnumerator()) {
if (($h.Name -eq "Resource") -and ($h.value -eq "test"))
{
Write-host "VM with tags Resource:test are" $VM.Name
}
}
}

Azure-DevOps Run powershell Getting Error while running

I have below command which is used for change vm size on azure:
Install-PackageProvider -name nuget -MinimumVersion 2.8.5.201 -Force
IF(!(Get-InstalledModule PSExcel -ErrorAction SilentlyContinue)){
Install-Module -Name PSExcel -ErrorAction SilentlyContinue -Force
Import-Module PSExcel -Force
}
IF(!(Get-InstalledModule ImportExcel -ErrorAction SilentlyContinue)){
Install-Module -Name ImportExcel -ErrorAction SilentlyContinue -Force
Import-Module ImportExcel -Force
}
IF(!(Get-InstalledModule az -ErrorAction SilentlyContinue)){
Install-Module -Name az -ErrorAction SilentlyContinue -Force
Import-Module az -Force
}
Import-Module PSExcel -Force
Import-Module ImportExcel -Force
$ExcelFile = "D:\test-data (3).xlsx"
$objExcel = New-Excel -Path $ExcelFile
$WorkBook = $objExcel | Get-Workbook
$NewExcelFile ="D:\test-data1.xlsx"
copy-item $ExcelFile -Destination $NewExcelFile
$sheetName = "Sheet2"
$newExcel = New-Object -ComObject Excel.Application
$newwb = $newExcel.Workbooks.Open($NewExcelFile)
$WorkSheet = $newwb.sheets.item($sheetName)
$WorksheetRange = $workSheet.UsedRange
$RowCount = $WorksheetRange.Rows.Count
$sheet=$newwb.Worksheets.Item(1)
$q=$RowCount
write-host 260
$q1="R"+$q
$r1 = $sheet.Range("R2:$q1")
$r1.cut()
$i1="I"+$q
$r2 = $sheet.Range("I2:$i1")
$sheet.Paste($r2)
$newwb.Close($true)
$newExcel.Quit()
#Import-Module az -Force
#Connect-AzAccount
Write-Host 273
#Loop through all items in the excel
ForEach($Worksheet in #($Workbook.Worksheets))
{
$totalNoOfRecords = $Worksheet.Dimension.Rows
$totalNoOfItems = $totalNoOfRecords - 1
# Declaring starting positions first row and column names
$rowNo, $Instance_Type_Current = 1, 9
$rowNo, $Instance_Type_Recommended = 1, 18
$rowNo, $Resource_Group= 1,42
$rowNo, $Resource_Name = 1,2
$rowNo, $osname = 1,8
if ($totalNoOfRecords -gt 1)
{
#Loop to get values from excel file
for ($i = 1; $i -le $totalNoOfRecords - 1; $i++)
{
$newvmsize = $WorkSheet.Cells.Item($rowNo + $i, $Instance_Type_Recommended).text
$vmName = $WorkSheet.Cells.Item($rowNo + $i, $Resource_Name).text
$resourceGroup = $WorkSheet.Cells.Item($rowNo + $i, $Resource_Group).text
$currentvmsize = $WorkSheet.Cells.Item($rowNo + $i, $Instance_Type_Current).text
$Checkwindowsos = $WorkSheet.Cells.Item($rowNo + $i, $osname).text
$currentsizefromazure = (Get-AzVM -ResourceGroupName $resourceGroup -VMName $vmName -ErrorAction SilentlyContinue).HardwareProfile.VmSize
#If only windows OS then VM size will update on azure
IF($Checkwindowsos -match 'windows'){
IF($currentvmsize -eq $currentsizefromazure) {
Stop-AzVM -ResourceGroupName $resourceGroup -Name $vmName -Force
$vm = Get-AzVM -ResourceGroupName $resourceGroup -VMName $vmName -ErrorAction SilentlyContinue
$vm.HardwareProfile.VmSize = $newvmsize
Write-Host 304
$vmstatus = $null
while($vmstatus -notmatch 'deallocated'){
$vmstatus=((get-azvm -Name $VmName -ResourceGroupName $resourceGroup -Status).Statuses[1]).code
}
#Start VM Snapshot(Backup)
$vm1 = get-azvm -Name $VmName -ResourceGroupName $resourceGroup
write-host $VmName
$snapshotdisk = $vm1.StorageProfile
$vmlocation =$vm1.location
#backup OS DISK
$OSDiskSnapshotConfig = New-AzSnapshotConfig -SourceUri $snapshotdisk.OsDisk.ManagedDisk.id -CreateOption Copy -Location $vmlocation -OsType Windows
$snapshotNameOS = "$($snapshotdisk.OsDisk.Name)_snapshot_$(Get-Date -Format ddMMyy)"
New-AzSnapshot -ResourceGroupName $resourceGroup -SnapshotName $snapshotNameOS -Snapshot $OSDiskSnapshotConfig
Write-Output "VM-Name $($vm1.name) OS Disk Snapshot End & Snapshot name is $snapshotNameOS"
Write-Host 319
#backup Data DISK
$dataDisks = ($snapshotdisk.DataDisks).name
IF($dataDisks -ne $null){
foreach ($datadisk in $datadisks) {
$dataDisk = Get-AzDisk -ResourceGroupName $vm1.ResourceGroupName -DiskName $datadisk
Write-Output "VM $($vm1.name) data Disk Name $($datadisk.Name) Snapshot Begin"
$DataDiskSnapshotConfig = New-AzSnapshotConfig -SourceUri $dataDisk.Id -CreateOption Copy -Location $vmlocation
$snapshotNameData = "$($datadisk.name)_snapshot_$(Get-Date -Format ddMMyy)"
New-AzSnapshot -ResourceGroupName $resourceGroup -SnapshotName $snapshotNameData -Snapshot $DataDiskSnapshotConfig
Write-Output "VM $($vm1.name) data Disk $($datadisk.Name) Snapshot End"
}}
Update-AzVM -VM $vm -ResourceGroupName $resourceGroup -ErrorAction SilentlyContinue
Start-AzVM -ResourceGroupName $resourceGroup -Name $vmName -ErrorAction SilentlyContinue
$vmstatus = $null
while($vmstatus -notmatch 'running'){
$vmstatus=((get-azvm -Name $VmName -ResourceGroupName $resourceGroup -Status).Statuses[1]).code
}
Write-Host Your VM name $vmName is started and changed size from $currentvmsize changed to $newvmsize
}
elseif($currentsizefromazure -eq $newvmsize) { Write-host Your VM $vmName is already Upgraded}
else{Write-host VM current size is mismatched from azure size}
}
}
}
}
Giving below error while running this script on azure devops:
Please help to resolve error.
Unable to get the Open property of the Workbooks class
At C:\Users\azureadmin\Downloads\vsts-agent-win-x64-2.195.2\_work\1\s\Automatic VM backup.ps1:28 char:1
+ $newwb = $newExcel.Workbooks.Open($NewExcelFile)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
Note: Script is running on self hosted agent and this script is running when normal ISE also azconnection through devops azure
p.s. This script is change vm size and get backup

How to get specifi list of Virtual Machine Status from Azure using powershell from Excel sheet

I am pretty much new to PowerShell and we have customer requirement that they will share Azure VM details in Excel sheet with below columns.
we have to get VM Status details from all the subscriptions & ResourceGroup using the Powershell script.
Outuput:
I am able to perform for single RSG and VM values by using the below code
$SubscriptionName = Get-AzSubscription -SubscriptionId $subscriptionId
$RG = "rgp-use2-prd-bioportalbiopeople1"
$RSGName = Get-AzResourceGroup -Name $RG
$VMs = Get-AzVM -Name "vmbppapiv1prd02"
$VMState = (Get-AzVM -Name $VM -ResourceGroupName $RG -Status).Statuses
$vmOutput = $VMs | ForEach-Object {
[PSCustomObject]#{
"Resource Group Name" = $RSGName.ResourceGroupName
"Subscription Name" = $SubscriptionName.Name
"VM Name" = $_.Name
"VM Type" = $_.StorageProfile.osDisk.osType
"VM Statss" = ($VMState | where code -Like 'PowerState/*')[0].DisplayStatus
}
}
$vmOutput | Format-Table -AutoSize
$vmOutput | export-csv C:\Projects\data.csv
I can't test this myself, but you will have to create nested loops to get the details for all subscriptions and resourcegroups.
Something like this:
$subscriptions = Get-AzSubscription -TenantId "aaaa-aaaa-aaaa-aaaa" # enter the tenant ID here
$VMs = Get-AzVM -Name "vmbppapiv1prd02"
$vmOutput = foreach ($vm in $VMs) {
foreach ($subscription in $subscriptions) {
Set-AzContext -SubscriptionId $subscription.Id
(Get-AzResourceGroup).ResourceGroupName | ForEach-Object {
$vmState = (Get-AzVM -Name $vm.Name -ResourceGroupName $_ -Status).Statuses
[PSCustomObject]#{
"Resource Group Name" = $_
"Subscription Name" = $Subscription.Name
"VM Name" = $vm.Name
"VM Type" = $vm.StorageProfile.osDisk.osType
"VM Status" = ($vmState | where code -Like 'PowerState/*')[0].DisplayStatus
}
}
}
}
$vmOutput | Format-Table -AutoSize
$vmOutput | Export-Csv -Path 'C:\Projects\data.csv' -NoTypeInformation

How To fix "add-member : Cannot add a member with the name "" because a member with that name already exists"

I need to list multiple FTP connexion on LogicApp service and export this list on csv file. This export is use for see if the SSL protocol connexion is activate or not. My script generate this error.
add-member : Cannot add a member with the name "FTP" because a member with that name already exists. To overwrite the member anyway, add the Force parameter to your command.
LogicApp FTP connexion :
https://learn.microsoft.com/en-us/azure/connectors/connectors-create-api-ftp
I need to add these FTP connections in this format on excel :
format need
$LogicApp_temp = $null
$LogicApp_obj = #()
$LogicApp_temp = new-object PSObject
$FTPAll = Get-AzResource -ResourceGroupName $RG -ResourceType Microsoft.Web/connections
foreach ( $FTPAlls in $FTPAll ) {
$FTPName = $FTPAlls.name
$FTPName1 = Get-AzResource -ResourceGroupName $RG -ResourceType Microsoft.Web/connections -Name $FTPName
foreach ($FTPName2 in $FTPName1) {
$FTPcheckType = $FTPName2.Properties.api.name
if ( $FTPcheckType -eq "ftp") {
$FTPSSL1 = $FTPName1.Properties.parameterValues.isSSL
}
else {
}
$LogicApp_temp | add-member -MemberType NoteProperty -Name "FTP" -Value "$FTPName2.Properties.displayName $FTPSSL1"
}
}
$LogicApp_obj += $LogicApp_temp
Write-Output "LogicApp Name : $Name Ressource Group : $RG OK"
# CSV Exports :
$LogicApp_obj | Export-Csv $csvPath -Append -NoTypeInformation
thank you in advance for your help
Because the PSObject property just could be set one value at one time, if you use the -Force, it will overwrite the value before.
If you want to get the .csv file like the format you provided, we could just append every string like joyftp True first.
My working sample:
$RG = "<resource group name>"
$LogicApp_obj = #()
$value = ""
$FTPAll = Get-AzResource -ResourceGroupName $RG -ResourceType Microsoft.Web/connections
foreach ( $FTPAlls in $FTPAll ) {
$FTPName = $FTPAlls.name
$FTPName1 = Get-AzResource -ResourceGroupName $RG -ResourceType Microsoft.Web/connections -Name $FTPName
foreach ($FTPName2 in $FTPName1) {
$FTPcheckType = $FTPName2.Properties.api.name
$displayname = $FTPName2.Properties.displayName
$LogicApp_temp = New-Object -TypeName PSObject
if ( $FTPcheckType -eq "ftp") {
$FTPSSL1 = $FTPName1.Properties.parameterValues.isSSL
$value += "$displayname $FTPSSL1 | "
$LogicApp_temp | add-member -MemberType NoteProperty -Name "FTP" -Value "$value" -Force
}
}
}
Write-Output "LogicApp Name : $Name Ressource Group : $RG OK"
# CSV Exports :
$LogicApp_temp | Export-Csv -Path "C:\Users\joyw\Desktop\ftp.csv" -NoTypeInformation
The .csv file:

Resources