I've used a hash table to calculate some values for my VMWare inventory script, but now when I output the data, it records it as a key/value pair. I'd like to dump just the value. When I simply take what I'm handed that works fine, but when I get picky PS starts to stonewall me. :-)
Here is the relevant part of the script.
foreach ($machine in $vmList) {
$vmname = $machine.Name
$properties = #{
'Name'=Get-VM $vmname | Select -ExpandProperty Name
'RAM'=Get-VM $vmname | Select -ExpandProperty MemoryGB
'CpuCount'=Get-VM $vmname | Select -ExpandProperty NumCpu
'UsedDiskGB'=Get-VM $vmname | Select-Object #{n="UsedDiskGB"; e={[math]::Round( $_.UsedSpaceGB, 3 )}}
'TotalDiskGB'=Get-VM $vmname | Select-Object #{n="TotalDiskGB"; e={[math]::Round((Get-HardDisk -vm $_ | Measure-Object -Sum CapacityGB).Sum)}}
'Networks'=Get-VM $vmname | Select-Object #{n="Networks"; e={(Get-NetworkAdapter -VM $_ |Sort-Object NetworkName |Select -Unique -Expand NetworkName) -join '; '}}
'OS'=(Get-VM -Name $vmname | Get-View).summary.config.guestFullName
}
$object=New-Object -TypeName PSObject -Prop $properties
Export-Csv -Path $WorkDir\vms.csv -Append -Encoding UTF8 -InputObject $Object
Write-Output $Object
}
How do I get UsedDiskGB, Networks and TotalDiskGB to display just the value instead of something like '#{TotalDiskGB=80}'? Ram, OS, CpuCount and Name work exactly as desired already.
Also, suggestions on doing this in a faster way are welcome. I'm sure all these calls can be done better. I had it done in a single line, but then they asked for OS to be added and that changed everything.
Easy, but bad way:
In the expression pipe to |Select -ExpandProperty <property name> to get just the value. Such as:
'TotalDiskGB'=Get-VM $vmname | Select-Object #{n="TotalDiskGB"; e={[math]::Round((Get-HardDisk -vm $_ | Measure-Object -Sum CapacityGB).Sum)}}|select -expand totaldiskgb
The better way:
Structure your properties better to start with. Try this:
'TotalDiskGB'= [math]::Round((Get-HardDisk -vm (Get-VM $vmname) | Measure-Object -Sum CapacityGB).Sum)
The reason you're having issues is because you are creating a PSCustomObject with your Select, and Totaldiskgb is a property of that object. You don't want to make an object, you just want the value of that property.
Edit: Thank you to #briantist for pointing out that Get-VM $vmname should be called once, and stored as an object to be used later, rather than called for each time it is needed for a member of $Properties. For example:
foreach ($machine in $vmList) {
$vmname = $machine.Name
$vmobject = Get-VM $vmname
$properties = #{
'Name'=$vmobject | Select -ExpandProperty Name
'RAM'=$vmobject | Select -ExpandProperty MemoryGB
'CpuCount'=$vmobject | Select -ExpandProperty NumCpu
'UsedDiskGB'=[math]::Round( $vmobject.UsedSpaceGB, 3 )
'TotalDiskGB'=[math]::Round((Get-HardDisk -vm $vmobject | Measure-Object -Sum CapacityGB).Sum)
'Networks'=(Get-NetworkAdapter -VM $vmobject |Sort-Object NetworkName |Select -Unique -Expand NetworkName) -join '; '
'OS'=($vmobject | Get-View).summary.config.guestFullName
}
$object=New-Object -TypeName PSObject -Prop $properties
Export-Csv -Path $WorkDir\vms.csv -Append -Encoding UTF8 -InputObject $Object
Write-Output $Object
}
Related
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:
Azure: Extend Psh command with two columns resource type & name
I am trying to write a Azure Psh command with two columns resource type & name and query the RBAC assignments for a user.
I have these two tables, is there a way to merge the following two tables?
Following is my current progress with the command:
Get-AzRoleAssignment -SignInName A12345#abc.com | Select-Object -Property RoleDefinitionName, {Get-AzResource -ResourceId $_.RoleAssignmentID | Select-Object -Property Name,ResourceType} | Format-Table;
Get-AzRoleAssignment -SignInName A12345#abc.com | Select-Object -Property RoleDefinitionName, {Get-AzResource -ResourceId $_.Scope | Select-Object -Property Name, ResourceType} | Format-Table
You can use the below command to directly get the two information in one line :
Get-AzRoleAssignment -SignInName ansuman#xyz.com | Select-Object -Property RoleDefinitionName, {Get-AzResource -ResourceId $_.RoleAssignmentID | Select-Object -Property Name,ResourceType} , {Get-AzResource -ResourceId $_.Scope | Select-Object -Property Name, ResourceType} | Format-Table
Update:
To prettify the Headers you can use this :
Get-AzRoleAssignment -SignInName ans#xyz.com | Select-Object -Property RoleDefinitionName, #{N='RoleDetails';E={Get-AzResource -ResourceId $_.RoleAssignmentID | Select-Object -Property Name,ResourceType}} , #{L='ScopeDetails';E={Get-AzResource -ResourceId $_.Scope | Select-Object -Property Name, ResourceType}}
Output:
So i want to know how many devices a user has enrolled in azure. the script give me what i want but im having 2 problems:
i want to display every command on a different column( the user name - number of devices)
im not able to import all to a csv file.
$usuarios = Get-Content .\usersid.csv
ForEach ($usuario in $usuarios){
Get-AzureADUser -ObjectId $usuario | select userprincipalname
(Get-AzureADUserRegisteredDevice -ObjectId $usuario).count | Export-Csv -append.\cuenta.csv
}
Like #theMadTechnician mentioned, the only thing being passed to Export-CSV is the count of the devices.
You could create a Custom PS Object, build values (array of username and Devices) in the custom object and export them as a CSV.
$usuarios = Get-Content .\usersid.csv
$items = #()
ForEach ($usuario in $usuarios)
{
$username = (Get-AzureADUser -ObjectId $usuario).userprincipalname
$count = (Get-AzureADUserRegisteredDevice -ObjectId $usuario).count
$item = New-Object PSCustomObject
$item | Add-Member -NotePropertyName "UserName" -NotePropertyValue $username
$item | Add-Member -NotePropertyName "Count" -NotePropertyValue $count
$items += $item
}
$items | Export-Csv -Path D:\DevicesCount.csv -Append -NoTypeInformation
I am looking to recursively grab a list of recently modified files under two network drives, sort them in descending date order, and make some edits to the CSV file to tidy the list for Excel
I have cobbled the code below from a number of sources (I am a powershell beginner) and it is now doing what I need (i.e. producing a list).
I need help in going a step further, I cannot sort the resultant CSV file by file last write time date, is this because my array is expecting text rather than a numeric field?
I also am returning the domain name as well as the file owner with ((Get-ACL $_.FullName).Owner). I tried using Replace to cut down the string, but had no luck with this approach.
$arr = #()
$days_to_check=$(Get-Date).AddDays(-28)
$items = #(Get-ChildItem '\\ND\dir 1\*.*' -Recurse -ErrorAction SilentlyContinue | where { $_.LastWriteTime -gt $days_to_check})
$items += #(Get-ChildItem '\\ND\dir 1\*.*' -Recurse -ErrorAction SilentlyContinue |
where { $_.LastWriteTime -gt $days_to_check})
$items | Foreach {
$obj = New-Object PSObject -prop $hash
$obj | Add-Member NoteProperty FullName $_.FullName
$obj | Add-Member NoteProperty Directory $_.Directory
$obj | Add-Member NoteProperty Name $_.Name
$obj | Add-Member NoteProperty LastTime $_.LastWriteTime
$obj | Add-Member NoteProperty Owner ((Get-ACL $_.FullName).Owner)
$arr += $obj
}
$arr | Format-List
$arr | Sort-Object -Property LastTime -Descending
$arr | Export-CSV -notypeinformation C:\temp\filenamesFO.csv
CSV file sorted by date field
You did sort your array in the output but that's all you did.
If you want to actually export it that way, you have to assign the sort to $arr
Replace
$arr | Sort-Object -Property LastTime -Descending
with
$arr = $arr | Sort-Object -Property LastTime -Descending
You can remove the Owner domain using the following Replace -replace '(.*\\)(.*)','$2'
Here's a complete example implementing the changes mentionned above.
$arr = new-object -TypeName 'System.Collections.Generic.List[PSObject]'
$days_to_check=$(Get-Date).AddDays(-28)
$items = #(Get-ChildItem '\\ND\dir 1\*.*' -Recurse -ErrorAction SilentlyContinue | where { $_.LastWriteTime -gt $days_to_check})
$items += #(Get-ChildItem '\\ND\dir 1\*.*' -Recurse -ErrorAction SilentlyContinue |
where { $_.LastWriteTime -gt $days_to_check})
Foreach ($item in $items) {
$obj = [PSCustomObject]#{
FullName = $item.FullName
Directory = $item.Directory
Name = $item.Name
LastTime = $item.LastWriteTime
Owner = (Get-ACL $item.FullName).Owner -replace '(.*\\)(.*)','$2'
}
$arr.add($obj)
}
$arr = $arr | Sort-Object -Property LastTime -Descending
#$arr | Format-List
$arr | Export-CSV -notypeinformation C:\temp\filenamesFO.csv
I made some additional changes:
Instead of using an array, I used a List of PSObject. If you have a lot of files, the processing time will be improved in comparison with an array.
I used the PSCustomObject declaration just to show an alternative to all those Add-member. I find it cleaner but it is up to you in the end.
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.