Powershell script calendar size issue - powershell

Trying to run the following script to get calendar size in Exchange 2016:
# Get-MailboxFolderSize.ps1 edit as required for folder you need stats on.
#$mailboxes = #(Get-Mailbox -ResultSize Unlimited)
$mailboxes = #(Get-MailboxServer | where-object {$_.AdminDisplayVersion.Major -eq 15} | Get-Mailbox -ResultSize Unlimited)
#$mailboxes = #(Get-MailboxServer | where-object {$_.AdminDisplayVersion.Major -eq 15} | Get-Mailbox)
#$mailboxes = #(Get-Mailbox hatfiemh)
$report = #()
foreach ($mailbox in $mailboxes)
{
$inboxstats = Get-MailboxFolderStatistics $mailbox -FolderScope Calendar | Where {$_.FolderPath -eq "/Calendar"}
$mbObj = New-Object PSObject
$mbObj | Add-Member -MemberType NoteProperty -Name "Display Name" -Value $mailbox.DisplayName
$mbObj | Add-Member -MemberType NoteProperty -Name "Calendar Size (gb)" -Value $inboxstats.FolderandSubFolderSize.ToGB()
$mbObj | Add-Member -MemberType NoteProperty -Name "Calendar Items" -Value $inboxstats.ItemsinFolderandSubfolders
$report += $mbObj
}
$report
I get the following error message:
You cannot call a method on a Null-valued expression.
at c:\Get-MailboxFolderSize.psi:13 char:5
$mbObj | Add-Member -MemberType NoteProperty -Name "inbox Size

Related

Powershell script to get all Azure AD group members AND group owner to CSV

Having some trouble trying to write a powershell script to out all AzureAD groups listing all members of the group with the group owners.
I am new to StackOverflow and new to powershell. Was hoping on some assistance?
Connect-AzureAD
$groups=Get-AzureADGroup -All $true
$resultsarray =#()
ForEach ($group in $groups){
$members = Get-AzureADGroupMember -ObjectId $group.ObjectId -All $true
ForEach ($member in $members){
$UserObject = new-object PSObject
$UserObject | add-member -membertype NoteProperty -name "Group Name" -Value $group.DisplayName
$UserObject | add-member -membertype NoteProperty -name "Member Name" -Value $member.DisplayName
$UserObject | add-member -membertype NoteProperty -name "ObjType" -Value $member.ObjectType
$UserObject | add-member -membertype NoteProperty -name "UserType" -Value $member.UserType
$UserObject | add-member -membertype NoteProperty -name "UserPrinicpalName" -Value $member.UserPrincipalName
$resultsarray += $UserObject
}
}
$resultsarray | Export-Csv -Encoding UTF8 -Path "D:\Script\test1234-Stack.csv" -NoTypeInformation
$array = #()
$Properties=#{}
$Properties.add("GroupDisplayName","1")
$Properties.add("OwnerObjectId","2")
$Properties.add("OwnerObjectType","3")
$Properties.add("OwnerUserType","4")
$Properties.add("OwnerUserPrincipalName","5")
$groups = Get-AzureADGroup -All $true
Foreach($group in $groups){
$Owners = Get-AzureADGroupOwner -ObjectId $group.ObjectId -All $true
$Properties.GroupDisplayName=$group.DisplayName
if($Owners -ne $null){
# group has owner
Foreach($Owner in $Owners){
$Properties.OwnerObjectId=$Owner.ObjectId
$Properties.OwnerObjectType=$Owner.ObjectType
$Properties.OwnerUserType=$Owner.UserType
$Properties.OwnerUserPrincipalName=$Owner.UserPrincipalName
$obj=New-Object PSObject -Property $Properties
$array +=$obj
}
}
else{
#group has no owner
$Properties.OwnerObjectId=$null
$Properties.OwnerObjectType=$null
$Properties.OwnerUserType=$null
$Properties.OwnerUserPrincipalName=$null
$obj=New-Object PSObject -Property $Properties
$array +=$obj
}
}
$array | Format-Table -AutoSize
$array | export-csv -Path D:\Script\GroupExportWithAZADOwner.csv -NoTypeInformation -Encoding UTF8
I have found two scripts to list Group Members and another to list all members. Is it possible to combine these?
The number of rows for owner and member are not the same. So some you can't combine all the columns together. Here is the best I can do. I changed syntax so the code is using the same objects.
$groups = Get-AzureADGroup -All $true
$resultsarray =#()
ForEach ($group in $groups){
$members = Get-AzureADGroupMember -ObjectId $group.ObjectId -All $true
$Owners = Get-AzureADGroupOwner -ObjectId $group.ObjectId -All $true
$Properties.GroupDisplayName=$group.DisplayName
ForEach ($member in $members){
$UserObject = new-object PSObject
$UserObject | add-member -membertype NoteProperty -name "Group Name" -Value $group.DisplayName
$UserObject | add-member -membertype NoteProperty -name "Member Name" -Value $member.DisplayName
$UserObject | add-member -membertype NoteProperty -name "ObjType" -Value $member.ObjectType
$UserObject | add-member -membertype NoteProperty -name "UserType" -Value $member.UserType
$UserObject | add-member -membertype NoteProperty -name "UserPrinicpalName" -Value $member.UserPrincipalName
$resultsarray += $UserObject
}
if($Owners -ne $null){
# group has owner
Foreach($Owner in $Owners){
$UserObject = new-object PSObject
$UserObject | add-member -membertype NoteProperty -name "Owner ID" -Value $Owner.ObjectId
$UserObject | add-member -membertype NoteProperty -name "Owner Type" -Value $Owner.ObjectType
$UserObject | add-member -membertype NoteProperty -name "Owner Type" -Value $Owner.UserType
$UserObject | add-member -membertype NoteProperty -name "Owner Principal Name" -Value $Owner.UserPrincipalName
$resultsarray += $UserObject
}
}
else{
$UserObject = new-object PSObject
#group has no owner
$UserObject | add-member -membertype NoteProperty -name "Owner ID" -Value $null
$UserObject | add-member -membertype NoteProperty -name "Owner Type" -Value $null
$UserObject | add-member -membertype NoteProperty -name "Owner Type" -Value $null
$UserObject | add-member -membertype NoteProperty -name "Owner Principal Name" -Value $null
$resultsarray += $UserObject
}
$resultsarray | Export-Csv -Encoding UTF8 -Path "D:\Script\test1234-Stack.csv" -NoTypeInformation
$groups=Get-AzureADGroup -All $true
$resultsarray =#()
ForEach ($group in $groups){
$members = Get-AzureADGroupMember -ObjectId $group.ObjectId -All $true
ForEach ($member in $members){
$UserObject = new-object PSObject
$UserObject | add-member -membertype NoteProperty -name "Member Name" -Value $member.DisplayName
$UserObject | add-member -membertype NoteProperty -name "UserPrinicpalName" -Value $member.UserPrincipalName
$resultsarray += $UserObject
$gName = $group.DisplayName
$resultsarray | Export-Csv -Encoding UTF8 -Path D:\Script\AzureAD\$gName.csv -NoTypeInformation
}
}

How to Capture Cluster info Remotely from a non-Clustered Node

I've been banging my head on this for a few days now, and I just can't figure out the best way to do it. I've got a script where I collect a bunch of data and output it to an html file (using PSWriteHTML Module, which is where the New-HTMLTable at the end comes from).
I've piecemealed the script together over time so I can gather the data from multiple servers at once, and for the most part, it all works great. As I've added data to the script to collect new info, there's a few parts that I just can't get to work right remotely. I know the piecemeal approach has left me with some redundant code, but I'm just trying to make it all work right before I re-write it again to clean it up, so my apologies for its current state.
The following code works great when I run the script from a server in a Windows Cluster, but I want things to work from any server, not necessarily a Cluster Node.
Here's orig code for this section:
try
{
$ClusterIPInfo = Invoke-command -computer $Computer {
Get-Cluster | Get-ClusterResource | %{
$_ | select Name,
#{ Name = "Address"; Expression = { $_ | Get-ClusterParameter -Name Address -ErrorAction SilentlyContinue | select -ExpandProperty Value } },
#{ Name = "SubnetMask"; Expression = { $_ | Get-ClusterParameter -Name SubnetMask -ErrorAction SilentlyContinue | select -ExpandProperty Value } }
}
} | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
$ClusterResourceInfo = Invoke-command -computer $Computer {
Get-ClusterResource | Select Cluster, Name, State, ResourceType, OwnerGroup, OwnerNode, ID, IsCoreResource, IsNetworkClassResource, IsStorageClassResource | Sort-Object -Property OwnerGroup, Name
} | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
$ResourceInfo = #()
foreach ($rec in $ClusterResourceInfo)
{
$Owner = (Get-ClusterResource | Sort-Object -Property OwnerGroup, Name | Get-ClusterOwnerNode | %{
$_ | select #{ Name = "Name"; Expression = { $_.ClusterObject } },
#{ Name = "PossibleOwners"; Expression = { $_.OwnerNodes } }
} | Where { $_.Name -eq $rec.Name }).PossibleOwners
$Dependency = (Get-ClusterResource | Sort-Object -Property OwnerGroup, Name | Get-ClusterResourceDependency | %{
$_ | select #{ Name = "Name"; Expression = { $_.Resource } },
#{ Name = "Dependency"; Expression = { $_ | Select-Object -ExpandProperty "DependencyExpression" } }
} | Where { $_.Name -eq $rec.Name }).Dependency
$address = ($ClusterIPInfo | Where { $_.Name -eq $rec.Name }).Address
$subnetmask = ($ClusterIPInfo | Where { $_.Name -eq $rec.Name }).SubnetMask
$recObj = New-Object PSObject
$recObj | Add-Member NoteProperty -Name "Cluster" -Value $rec.Cluster
$recObj | Add-Member NoteProperty -Name "Name" -Value $rec.Name
$recObj | Add-Member NoteProperty -Name "State" -Value $rec.State
$recObj | Add-Member NoteProperty -Name "Resource Type" -Value $rec.ResourceType
$recObj | Add-Member NoteProperty -Name "Owner Group" -Value $rec.OwnerGroup
$recObj | Add-Member NoteProperty -Name "Owner Node" -Value $rec.OwnerNode
$recObj | Add-Member NoteProperty -Name "Possible Owners" -Value $Owner
$recObj | Add-Member NoteProperty -Name "Dependency" -Value $Dependency
$recObj | Add-Member NoteProperty -Name "IP Address" -Value $address
$recObj | Add-Member NoteProperty -Name "Subnet Mask" -Value $subnetmask
$recObj | Add-Member NoteProperty -Name "Is Core Resource" -Value $rec.IsCoreResource
$recObj | Add-Member NoteProperty -Name "Is Network Resource" -Value $rec.IsNetworkClassResource
$recObj | Add-Member NoteProperty -Name "Is Storage Resource" -Value $rec.IsStorageClassResource
$ResourceInfo += $recObj
}
New-HTMLTable -DataTable $ResourceInfo -HideFooter -HideButtons -DisableSearch
The parts that don't work correctly remotely are the Dependency and PossibleOwners. I know the reason it doesn't work is because when the server running the script isn't a Cluster Node, it doesn't recognize the command under the Foreach loop Get-ClusterResource. But I just can't figure out how to make those pass correctly from within the Foreach loop, but still use the info from $ClusterResourceInfo.
I've re-written this a hundred different ways, i.e. make a single Invoke-command with basically one big Get-Cluster variable (couldn't get it to capture the Dependency/PossOwners, always $null), splitting up the Dependency and PossOwners to their own separate Invoke-Command (best I can get it to do is display System.Object[], or when I did get it to display, it captured ALL of the Dependencies for all objects and displayed on every line instead of splitting it up correctly).
I've tried every possible way I can think of or found online, but just can't get it to work correctly remotely.
Here's how the orig code above outputs (which is what I want, but I just want to fix it so it works remotely):
I am desperately hoping for some brilliance or guidance to set me on the right track. I tried so many ways, but just never quite got it where it needs to be, so any help is most appreciated and welcome. Thanks.
Couple of things i can suggest.
The "Get-ClusterResource" cmdlet fails because it is not installed on the server.
You may try to load the Failover cluster module using Import-Module, and if it fails (on a non-cluster Node), you can add the Failover Cluster Module for Windows PowerShell Feature, using the following PowerShell cmd:
Add-WindowsFeature RSAT-Clustering-PowerShell
You may try connecting to to the remote cluster node where the resource is hosted, using WMI ?
You have enough info about the resource to be able to write a filtered WMI query.
So the piecemeal approach is what got me in trouble. In trying to merge things together, I kept breaking it (mainly because I think had doubled up the %{}). So instead of merging, I just replicated the parts that were already working as intended.
Ultimately this code worked fine:
$ClusterInfo = Invoke-command -computer $Computer {
Get-Cluster | Get-ClusterResource | %{
$_ | select Name,
#{ Name = "Address"; Expression = { $_ | Get-ClusterParameter -Name Address -ErrorAction SilentlyContinue | select -ExpandProperty Value } },
#{ Name = "SubnetMask"; Expression = { $_ | Get-ClusterParameter -Name SubnetMask -ErrorAction SilentlyContinue | select -ExpandProperty Value } },
#{ Name = "PossibleOwners"; Expression = { $_ | Get-ClusterOwnerNode | select OwnerNodes | select -ExpandProperty OwnerNodes } },
#{ Name = "Dependency"; Expression = { $_ | Get-ClusterResourceDependency | select -ExpandProperty "DependencyExpression" } }
}
} | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
$ClusterResourceInfo = Invoke-command -computer $Computer {
Get-ClusterResource | Select Cluster, Name, State, ResourceType, OwnerGroup, OwnerNode, IsCoreResource, IsNetworkClassResource, IsStorageClassResource | Sort-Object -Property OwnerGroup, Name
} | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
$ResourceInfo = #()
foreach ($rec in $ClusterResourceInfo)
{
$Owner = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).PossibleOwners
$Dependency = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).Dependency
$address = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).Address
$subnetmask = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).SubnetMask
$recObj = New-Object PSObject
$recObj | Add-Member NoteProperty -Name "Cluster" -Value $rec.Cluster
$recObj | Add-Member NoteProperty -Name "Name" -Value $rec.Name
$recObj | Add-Member NoteProperty -Name "State" -Value $rec.State
$recObj | Add-Member NoteProperty -Name "Resource Type" -Value $rec.ResourceType
$recObj | Add-Member NoteProperty -Name "Owner Group" -Value $rec.OwnerGroup
$recObj | Add-Member NoteProperty -Name "Owner Node" -Value $rec.OwnerNode
$recObj | Add-Member NoteProperty -Name "Possible Owners" -Value $Owner
$recObj | Add-Member NoteProperty -Name "Dependency" -Value $Dependency
$recObj | Add-Member NoteProperty -Name "IP Address" -Value $address
$recObj | Add-Member NoteProperty -Name "Subnet Mask" -Value $subnetmask
$recObj | Add-Member NoteProperty -Name "Is Core Resource" -Value $rec.IsCoreResource
$recObj | Add-Member NoteProperty -Name "Is Network Resource" -Value $rec.IsNetworkClassResource
$recObj | Add-Member NoteProperty -Name "Is Storage Resource" -Value $rec.IsStorageClassResource
$ResourceInfo += $recObj
}
New-HTMLTable -DataTable $ResourceInfo -HideFooter -HideButtons -DisableSearch

Issue with foreach loop (Combining Commands)

The script below works out great for identifying licensing for each individual host across multiple vCenters. What I am trying to include is the tag for each host as well. When I run the command individually it works fine, however when I run it as part of the code it is not functioning correctly. I highlighted the section if anyone can please take a look thanks. The line of code with the issue is commented out within the script below.
I attempted pushing this into a variable outside and insideof the foreach loop but I am receiving either 0 output, or the same output across each object.
Below is the actual command I put inside the foreach loop which is not functional.
(Get-VMhost | where{$_.Category -like "*Host*"})
$sw = [Diagnostics.Stopwatch]::StartNew()
# Declare our list of vCenters
[array]$vclistall = "vcenter01"
# Ensure were not connected to any vcenters
if ($DefaultVIServer.Count -gt 0) {
Disconnect-VIServer * -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Force:$true > $null
}
[array]$report = $null
foreach ($ScriptVCInstance in $vclistall) {
$connection = Connect-VIServer $ScriptVCInstance -ErrorAction SilentlyContinue
if ($connection) {
Write-Host "Collecting License Assets on vCenter $($ScriptVCInstance)"
# Get the license manager assets
$LicenseManager = Get-view LicenseManager
$LicenseAssignmentManager = Get-View $LicenseManager.LicenseAssignmentManager
$licenses = $LicenseAssignmentManager.GetType().GetMethod("QueryAssignedLicenses").Invoke($LicenseAssignmentManager, #($null))
#Format the asset into an object
foreach ($license in $Licenses) {
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name "vCenter" -Value $($connection.name)
$object | Add-Member -MemberType NoteProperty -Name "Entity" -Value $($license.EntityDisplayName)
$object | Add-Member -MemberType NoteProperty -Name "Display Name" -Value $($license.Properties | where{$_.Key -eq 'ProductName'} | select -ExpandProperty Value)
$object | Add-Member -MemberType NoteProperty -Name "Product Version" -Calue $($License.Properties | where{$_.Key -eq 'FileVersion'} | select -ExpandProperty Value)
$object | Add-Member -MemberType NoteProperty -Name "License" -Value $($license.AssignedLicense.LicenseKey)
$object | Add-Member -MemberType NoteProperty -Name "License Name" -Value $($license.AssignedLicense.Name)
$object | Add-Member -MemberType NoteProperty -Name "Cost Unit" -Value $($license.Properties | where{$_.Key -eq 'CostUnit'} | select -ExpandProperty Value)
$object | Add-Member -MemberType NoteProperty -Name "Used License" -Value $($license.Properties | where{$_.Key -eq 'EntityCost'} | select -ExpandProperty Value)
$object | Add-Member -MemberType NoteProperty -Name "Total Licenses" -Value $($license.AssignedLicense.Total)
# Issue--> $object | Add-Member -MemberType NoteProperty -Name "Tag" -Value $(Get-VMhost | where{$_.Category -like "*Host*"})
$report += $object
if ($DefaultVIServer.Count -gt 0) {
Disconnect-VIServer * -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Force:$true > $null
}
} #end foreach $license
} else { # Else for if $connection
Write-warning "Not connected to vCenter $($ScriptVCInstance)"
} # endif $connection
} # End foreach $ScriptVCInstance
# write-out as a CSV file
Write-host "Exporting CSV $($env:USERPROFILE)\Licensed-Assets.csv"
$report | Sort-object "vCenter","License","Entity" | Export-csv "$($env:USERPROFILE)\Licensed-Assets.csv" -NoTypeInformation -UseCulture
$sw.Stop()
$sw.Elapsed

Adding data from a second Invoke-WebRequest import into an existing array

I am fairly new to powershell and am having a problem with my script adding data from a second Invoke-WebRequest into an existing array $arr1.
The second import into variable $annotations works fine. I then need to match where $vm.Name = $annotations.Name in order for final ForEach($vm in $vms) to work and pull in the annotations data as well but am stuck.
My code is as follows. Please help
$StorageSystemName = "storageName"
$StoragePoolName = "storagepool"
$ReportName = "~\Reports\ServerList_$((Get-Date).ToString('yyyy-MM-dd')).xlsx"
Invoke-WebRequest -Uri http://srv1/location/Report_volume_storage.csv -OutFile .\Report_volume_storage.csv
$luns = Import-Csv .\Report_volume_storage.csv -Delimiter ";" |
Where-Object {$_.'Storage System name' -eq $StorageSystemName -and $_.'Storage Pool Name' -eq $StoragePoolName -and $_.'Volume Name'} |
Sort-Object "Storage Pool Name", "Volume Name"
Invoke-WebRequest -Uri http://srv2/addmdata/addmdata.csv -OutFile .\addmdata.csv
$annotations = Import-Csv .\addmdata.csv -Delimiter "," |
Select #{n='Name';e={$_.name.Split('.')[0]}}, * -Exclude Name,
#{n="Annotationserverdescription";e={$_.'Server Description'}},
#{n="Annotationapowner";e={$_.'Annotationapowner (Annotationappowner)'}},
#{n="Annotationclient";e={$_.'Client'}}
Sort-Object Name
$arr1 = #()
ForEach($lun in $luns)
{
$dsnaa = $lun.'LUN UID'
$dsnaa = "*$dsnaa*"
$datastore = Get-Datastore |
Where {($_.ExtensionData.Info.Vmfs.Extent).DiskName -like $dsnaa}
$VMs = #()
$datastore | ForEach-Object {
$dstore = $_.name
$VMs += get-VM -datastore $dstore | Where {$_.PowerState -eq "PoweredOn"} | Select #{n="Name";e={$_.name}}, #{n="PowerState";e={$_.PowerState}}, #{n="Datastore_Name";e={$dstore}}
}
ForEach($vm in $vms)
{
$data = New-Object System.Object
$data | Add-Member -MemberType NoteProperty -Name "Name" -Value $vm.Name
$data | Add-Member -MemberType NoteProperty -Name "PowerState" -Value $vm.PowerState
$data | Add-Member -MemberType NoteProperty -Name "Annotationserverdescription" -Value $annotation.'Server Description'
$data | Add-Member -MemberType NoteProperty -Name "Annotationapowner" -Value $annotation.'Annotationapowner (Annotationappowner)'
$data | Add-Member -MemberType NoteProperty -Name "Annotationclient" -Value $annotation.Client
$data | Add-Member -MemberType NoteProperty -Name "Volume Name" -Value $lun.'Volume Name'
$data | Add-Member -MemberType NoteProperty -Name "LUN UID" -Value $lun.'LUN UID'
$data | Add-Member -MemberType NoteProperty -Name "Capacity (GiB)" -Value $lun.'Capacity (GiB)'
$data | Add-Member -MemberType NoteProperty -Name "Storage Pool Name" -Value $lun.'Storage Pool Name'
$data | Add-Member -MemberType NoteProperty -Name "Storage System name" -Value $lun.'Storage System name'
$data | Add-Member -MemberType NoteProperty -Name "Storage Tier" -Value $lun.'Storage Tier'
$arr1 += $data
}
}
$arr1 | Export-Excel $ReportName
You could do something like the following:
$StorageSystemName = "storageName"
$StoragePoolName = "storagepool"
$ReportName = "~\Reports\ServerList_$((Get-Date).ToString('yyyy-MM-dd')).xlsx"
Invoke-WebRequest -Uri http://srv1/location/Report_volume_storage.csv -OutFile .\Report_volume_storage.csv
$luns = Import-Csv .\Report_volume_storage.csv -Delimiter ";" |
Where-Object {$_.'Storage System name' -eq $StorageSystemName -and $_.'Storage Pool Name' -eq $StoragePoolName -and $_.'Volume Name'} |
Sort-Object "Storage Pool Name", "Volume Name"
Invoke-WebRequest -Uri http://srv2/addmdata/addmdata.csv -OutFile .\addmdata.csv
$annotations = Import-Csv .\addmdata.csv -Delimiter "," |
Select #{n='Name';e={$_.name.Split('.')[0]}}, * -Exclude Name,
#{n="Annotationserverdescription";e={$_.'Server Description'}},
#{n="Annotationapowner";e={$_.'Annotationapowner (Annotationappowner)'}},
#{n="Annotationclient";e={$_.'Client'}}
Sort-Object Name
$arr1 = #()
ForEach($lun in $luns)
{
$dsnaa = $lun.'LUN UID'
$dsnaa = "*$dsnaa*"
$datastore = Get-Datastore |
Where {($_.ExtensionData.Info.Vmfs.Extent).DiskName -like $dsnaa}
$VMs = #()
$datastore | ForEach-Object {
$dstore = $_.name
$VMs += get-VM -datastore $dstore | Where {$_.PowerState -eq "PoweredOn"} | Select #{n="Name";e={$_.name}}, #{n="PowerState";e={$_.PowerState}}, #{n="Datastore_Name";e={$dstore}}
}
ForEach($vm in $vms)
{
$ActiveAnnotation = $null
$ActiveAnnotation = $annotations | where-object {$_.name -eq $vm.name}
$data = New-Object System.Object
$data | Add-Member -MemberType NoteProperty -Name "Name" -Value $vm.Name
$data | Add-Member -MemberType NoteProperty -Name "PowerState" -Value $vm.PowerState
$data | Add-Member -MemberType NoteProperty -Name "Annotationserverdescription" -Value $ActiveAnnotation.'Server Description'
$data | Add-Member -MemberType NoteProperty -Name "Annotationapowner" -Value $ActiveAnnotation.'Annotationapowner (Annotationappowner)'
$data | Add-Member -MemberType NoteProperty -Name "Annotationclient" -Value $ActiveAnnotation.Client
$data | Add-Member -MemberType NoteProperty -Name "Volume Name" -Value $lun.'Volume Name'
$data | Add-Member -MemberType NoteProperty -Name "LUN UID" -Value $lun.'LUN UID'
$data | Add-Member -MemberType NoteProperty -Name "Capacity (GiB)" -Value $lun.'Capacity (GiB)'
$data | Add-Member -MemberType NoteProperty -Name "Storage Pool Name" -Value $lun.'Storage Pool Name'
$data | Add-Member -MemberType NoteProperty -Name "Storage System name" -Value $lun.'Storage System name'
$data | Add-Member -MemberType NoteProperty -Name "Storage Tier" -Value $lun.'Storage Tier'
$arr1 += $data
}
}
$arr1 | Export-Excel $ReportName
I added the $ActiveAnnotation variable inside of your VMs loop to find the annotation match each time through the loop.

Powershell: Cannot index into a null array error

I am writing a script to import a LUN list which contain fields "Volume Name", "LUN UID", "Capacity (GiB)", "Storage Pool Name", "Storage System name", "Storage Tier" and "Host Mappings" in variable $luns.
Then I need to match the "LUN UID" in the $luns variable to another variable $dsnaa created to store the datastore naa.
The idea to get a list of all virtual machines residing on the datastores which match the Storage Volume/ LUN ID in the imported excel file.
Error:
Cannot index into a null array.
At C:\Users\troyh\Documents\WindowsPowerShell\ServerList_from_LUN_List.ps1:18 char:40
+ ... re | where {($_.ExtensionData.Info.Vmfs.Extent[0]).DiskName -like $ds ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
Script:
$luns = Import-Excel ~\Documents\WindowsPowerShell\Imports\LUN_Import.xlsx
$arr1 = #()
foreach($lun in $luns)
{
$dsnaa = $lun.'LUN UID'
$dsnaa = "*$dsnaa*"
$datastore = Get-Datastore | where {($_.ExtensionData.Info.Vmfs.Extent[0]).DiskName -like $dsnaa}
$vms = Get-Datastore $datastore.Name | Get-VM
foreach($vm in $vms)
{
$data = New-Object System.Object
$data | Add-Member -MemberType NoteProperty -Name "Name" -Value $vm.Name
$data | Add-Member -MemberType NoteProperty -Name "Datastore" -Value $datastore.'Name'
$data | Add-Member -MemberType NoteProperty -Name "naa" -Value $lun.'LUN UID'
$data | Add-Member -MemberType NoteProperty -Name "Storage Pool Name" -Value $lun.'Storage Pool Name'
$data | Add-Member -MemberType NoteProperty -Name "Storage System Name" -Value $luns.'Storage System name'
$arr1 += $data
}
}
$arr1 | Export-Excel ~\Documents\WindowsPowerShell\Exports\ServerList_$(Get-Date -Format 'yyyy-MM-dd_H"H"mm').xlsx –Show
This line is the problem:
$datastore = Get-Datastore | where {($_.ExtensionData.Info.Vmfs.Extent[0]).DiskName -like $dsnaa}
You need to remove the index:
$datastore = Get-Datastore | where {($_.ExtensionData.Info.Vmfs.Extent).DiskName -like $dsnaa}
The line above will get all datastores that match the criteria that used your -like operator. If you are only interested in getting the first datastore in the list, then index the datastore variable like so in the next line.
$datastore = Get-Datastore | where {($_.ExtensionData.Info.Vmfs.Extent).DiskName -like $dsnaa}
$vms = Get-Datastore $datastore[0].Name | Get-VM
The Get-VM cmdlet does take an array of datastores if you want to grab everything at once.
I have made a few more edits to try to accomplish what you are trying. The problem here besides the indexing is putting the datastore name into the data object. Here is a rewrite using a lot of your code:
$luns = Import-Excel ~\Documents\WindowsPowerShell\Imports\LUN_Import.xlsx
$arr1 = #()
foreach($lun in $luns)
{
$dsnaa = $lun.'LUN UID'
$dsnaa = "*$dsnaa*"
$datastore = Get-Datastore | where {($_.ExtensionData.Info.Vmfs.Extent).DiskName -like $dsnaa}
$VMs = #()
$datastore | foreach-object {
$dstore = $_.name
$VMs += get-VM -datastore $dstore | select #{n="Name";e={$_.name}},#{n="Datastore_Name";e={$dstore}}
}
foreach($vm in $vms)
{
$data = New-Object System.Object
$data | Add-Member -MemberType NoteProperty -Name "Name" -Value $vm.Name
$data | Add-Member -MemberType NoteProperty -Name "Datastore" -Value $vm.'Datastore_Name'
$data | Add-Member -MemberType NoteProperty -Name "naa" -Value $lun.'LUN UID'
$data | Add-Member -MemberType NoteProperty -Name "Storage Pool Name" -Value $lun.'Storage Pool Name'
$data | Add-Member -MemberType NoteProperty -Name "Storage System Name" -Value $luns.'Storage System name'
$arr1 += $data
}
}
$arr1 | Export-Excel ~\Documents\WindowsPowerShell\Exports\ServerList_$(Get-Date -Format 'yyyy-MM-dd_H"H"mm').xlsx –Show