I am having the below code to write the data to csv
$myVMs = #(Get-VM -Server $vc | where {$_.PowerState -eq 'PoweredOn'} | select -Unique)
foreach ($myVM in $myVMs){
$VMDKs = $myVM | get-HardDisk
$VMDISKMode = $myVM
foreach ($VMDK in $VMDKs) {
if ($VMDK -ne $null){
$Diskmode = $VMDK.Persistence
if($Diskmode -ne 'Persistent')
{
$Report = [PSCustomObject] #{
Name = $myVM.name
Server = $vc
PowerState = $myVM.PowerState
Disk = $VMDK.Name
DiskMode = $VMDK.Persistence
}
$Report | Export-CSV -NoTypeInformation $File -Append
}
}
}
}
}
the output i am getting
Name Server PowerState Disk DiskMode
171_A92SV095 192.168.1.5 PoweredOn Hard disk 6 IndependentPersistent
171_A92SV095 192.168.1.5 PoweredOn Hard disk 7 IndependentPersistent
171_A92SV095 192.168.1.5 PoweredOn Hard disk 8 IndependentPersistent
171_A92SV095 192.168.1.5 PoweredOn Hard disk 10 IndependentPersistent
171_A92SV096 192.168.1.5 PoweredOn Hard disk 5 IndependentPersistent
171_A92SV096 192.168.1.5 PoweredOn Hard disk 10 IndependentPersistent
want the data like below
Name Server PowerState Disk DiskMode
171_A92SV095 192.168.1.5 PoweredOn Hard disk 6 IndependentPersistent
Hard disk 7
Hard disk 8
Hard disk 10
171_A92SV096 192.168.1.5 PoweredOn Hard disk 5 IndependentPersistent
Hard disk 10
Please let me know what changes I need to make in the code.
Taking the csv file you created with your code, you can use that as a basis to get the output you need like this:
$data = Import-Csv -Path 'D:\Test\VMInfo.csv'
# first group the data on the Name property
$data | Group-Object Name | ForEach-Object {
$name = $_.Name
# next, group that on property PowerState
foreach ($groupPowerState in ($_.Group | Group-Object PowerState)) {
$powerState = $groupPowerState.Name
# finally, group that on property DiskMode
foreach ($groupDiskMode in ($groupPowerState.Group | Group-Object DiskMode)) {
[PsCustomObject]#{
Name = $name
Server = $groupDiskMode.Group[0].Server
PowerState = $powerState
Disk = $groupDiskMode.Group.Disk -join [environment]::NewLine
DiskMode = $groupDiskMode.Name
}
}
}
} | Export-Csv -Path 'D:\Test\GroupedVMInfo.csv' -UseCulture -NoTypeInformation
This should give you a new CSV file you can double-click to open in Excel
Using your example data this would open in Excel as:
Of course, you don't need to write the report out to CSV and then read it back in if you would capture the output in variable $data like this:
$data = foreach ($myVM in $myVMs) {
$VMDKs = $myVM | Get-HardDisk
$VMDISKMode = $myVM
foreach ($VMDK in $VMDKs) {
if ($VMDK -ne $null) {
$Diskmode = $VMDK.Persistence
if($Diskmode -ne 'Persistent') {
[PSCustomObject] #{
Name = $myVM.name
Server = $vc
PowerState = $myVM.PowerState
Disk = $VMDK.Name
DiskMode = $VMDK.Persistence
}
}
}
}
}
Have an odd situation where the PowerShell script below is showing two A records for each SRV record - when there should only be one A record per SRV record. Sample output:
If you're running Active Directory in your environment, simply run the PowerShell script below and you should get the same results. The output file will be on your Desktop. I've re-written this script multiple times and after many trials and errors, still getting the same results. Any idea why the A record is listed twice, and how to get it to show only once?
# Show Active Directory SRV records by Site
$logpath = "$ENV:UserProfile\Desktop\"
####################################################
#find date and convert to string
$date=((Get-Date).ToString('yyyy-MM-dd-HH-mm-ss'))
#defines the path where to find the log file of this script
$Logfile = $logpath+$date+".log"
#convert date and time to string
$date=((Get-Date).ToString('yyyy-MM-dd-HH-mm-ss'))
#get addomain
$domain = ((Get-WmiObject Win32_ComputerSystem).Domain)
#get all sites
$sites = (([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites).Name)
Function Write-Log
{
Param ([string]$logstring)
Add-content $Logfile -value $logstring
}
Write-Log "Domainname: $domain"
Write-Log "-------------"
foreach ($site in $sites){
$srv = (Resolve-DnsName -Type SRV _ldap._tcp.$site._sites.$domain | ft Name,Type,NameTarget,Port | Out-String)
Write-Log "Sitename: $site"
Write-Log "-------------"
Write-Log "$srv"
}
There might be some differences between the two A-Records, but you're missing them due to this lines here.
$srv = (Resolve-DnsName -Type SRV _ldap._tcp.$site._sites.$domain |
ft Name,Type,NameTarget,Port | Out-String)
The ft command here is an alias for Format-Table, and the default parameter is a list of which Columns to select. In that selection, you're only keeping these fields:
Name
Type
NameTarget
Port
Now, there might be a lot of other fields we're not seeing, and I expect one of them contains some unique different value. So I would suggest you run this to see how it's different. (Maybe this device has two network interfaces and they both have different IPs, and thus both get their own set of DNS settings back from DHCP)
Resolve-DnsName -Type SRV _ldap._tcp.$site._sites.$domain | format-list
That will show you all the fields, and you can figure out why you have two records.
After some trial and error, this gives me exactly what I need. Change:
$srv = (Resolve-DnsName -Type SRV _ldap._tcp.$site._sites.$domain | ft Name,Type,NameTarget,Port | Out-String)
to:
$srv = (Resolve-DnsName -Type SRV _ldap._tcp.$site._sites.$domain | select-object -First 2 | ft Name,Type,NameTarget,Port | Out-String)
Explanantion: The use of select-object allows one to trim off rows from a result object array.
Below is my data in text file
Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 Z DVD-ROM 0 B No Media
Volume 1 System Rese NTFS Partition 500 MB Healthy System
Volume 2 C SYS NTFS Partition 99 GB Healthy Boot
Volume 3 S SWAP NTFS Partition 6141 MB Healthy Pagefile
Volume 4 D DATA NTFS Partition 199 GB Healthy
Volume 5 E bit locker NTFS Partition 9 GB Healthy
Volume 6 F test NTFS Partition 10 GB Healthy
I have to write it in csv. tried below code but not able to handle to Blank values. e.g. for first row Label,Fs,Info values are blank
$data = get-content -Path "C:\d.txt"
$result = switch -Regex ($data) {
'^\s*Volume \d' {
$disk,$status,$Label,$Fs,$Type,$size,$Stat,$Info = $_.Trim() -split '\s{2,}'
[PsCustomObject]#{
'Server' = $server
'Volume ###' = $disk
'Ltr' = $status
'Label' = $Label
'Fs' = $Fs
'Type' = $Type
'Size' = $size
'Status' = $Stat
'Info' = $Info
}
}
}
# output on console screen
$result | Format-Table -AutoSize
# output to CSV file
$result | Export-Csv -Path "C:\$server.csv" -NoTypeInformation -Append
Output is coming like
Server Volume ### Ltr Label Fs Type Size Status Info
------ ---------- --- ----- -- ---- ---- ------ ----
AxxxxxxxxxxxxxP Volume 0 Z DVD-ROM 0 B No Media
AxxxxxxxxxxxxxP Volume 1 System Rese NTFS Partition 500 MB Healthy System
AxxxxxxxxxxxxxP Volume 2 C SYS NTFS Partition 99 GB Healthy Boot
AxxxxxxxxxxxxxP Volume 3 S SWAP NTFS Partition 6141 MB Healthy Pagefile
AxxxxxxxxxxxxxP Volume 4 D DATA NTFS Partition 199 GB Healthy
AxxxxxxxxxxxxxP Volume 5 E bit locker NTFS Partition 9 GB Healthy
AxxxxxxxxxxxxxP Volume 6 F test NTFS Partition 10 GB Healthy
Please let me know how to handle the spaces or any other way I can write it to csv
After executing #Mathias code
"Count","IsReadOnly","Keys","Values","IsFixedSize","SyncRoot","IsSynchronized"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
this is what I am trying to do
$server = $env:COMPUTERNAME
# Start by reading in the table
# Replace this statement with `
$lines = Get-Content "c:\d.txt"
$lines = $lines -split '\r?\n'
# Assign the first two lines to separate variables
$header, $guardRails, $lines = $lines
# Split the header into individual column names
$columnNames = #(
$header.Trim() -split '\s{2,}' |ForEach-Object Trim
)
# Use regex to match all the individual `---` sequences, grab their offset + length
$columnOffsets = #(
[regex]::Matches($guardRails, '(?<!-)-+(?!-)') |Select Index,Length
)
# Parse the data based on the offsets located above
foreach($line in $lines){
# Prepare a dictionary to hold the column values, add the Server property straight away
$properties = [ordered]#{
Server = $server
}
# Now we just need to iterate over the lists of column headers and extract the corresponding substring from the line
for($i = 0; $i -lt $columnNames.Length; $i++){
# Grab the column name and offset
$propertyName = $columnNames[$i]
$offset = $columnOffsets[$i]
# Grab the substring corresponding to the column
$propertyValue = $line.Substring($offset.Index, $offset.Length).Trim()
# Add the information to our property dictionary
$properties[$propertyName] = $propertyValue
}
# Output a new object based on the properties we grabbed from the column data
[pscustomobject]$properties
# output on console screen
$properties | Format-Table -AutoSize
# output to CSV file
$properties | Export-Csv -Path "C:\$server.csv" -NoTypeInformation -Append
}
Use the line below the header ( ---------- --- -----------...) to detect at which offsets to parse data for a specific column name:
# Start by reading in the table
# Replace this statement with `$lines = Get-Content .\path\to\file.txt` in your script
$lines = #'
Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 Z DVD-ROM 0 B No Media
Volume 1 System Rese NTFS Partition 500 MB Healthy System
Volume 2 C SYS NTFS Partition 99 GB Healthy Boot
Volume 3 S SWAP NTFS Partition 6141 MB Healthy Pagefile
Volume 4 D DATA NTFS Partition 199 GB Healthy
Volume 5 E bit locker NTFS Partition 9 GB Healthy
Volume 6 F test NTFS Partition 10 GB Healthy
'# -split '\r?\n'
# Assign the first two lines to separate variables
$header, $guardRails, $lines = $lines
# Split the header into individual column names
$columnNames = #(
$header.Trim() -split '\s{2,}' |ForEach-Object Trim
)
# Use regex to match all the individual `---` sequences, grab their offset + length
$columnOffsets = #(
[regex]::Matches($guardRails, '(?<!-)-+(?!-)') |Select Index,Length
)
# Parse the data based on the offsets located above
$volumeInfo = foreach($line in $lines){
# Prepare a dictionary to hold the column values, add the Server property straight away
$properties = [ordered]#{
Server = 'Server123'
}
# Now we just need to iterate over the lists of column headers and extract the corresponding substring from the line
for($i = 0; $i -lt $columnNames.Length; $i++){
# Grab the column name and offset
$propertyName = $columnNames[$i]
$offset = $columnOffsets[$i]
# Grab the substring corresponding to the column
$propertyValue = $line.Substring($offset.Index, $offset.Length).Trim()
# Add the information to our property dictionary
$properties[$propertyName] = $propertyValue
}
# Output a new object based on the properties we grabbed from the column data
[pscustomobject]$properties
}
$volumeInfo |Export-Csv path\to\output.csv -NoTypeInformation
Is it possible to get the actual hard disk usage of a virtual machine?
Measure-VM -Name * | select-object -property TotalDiskAllocation
The TotalDiskAllocation property gets the total disk space assigned to the VM and even though this is helpful I also need to know how much is really being used.
For example, if a VM has 150 GB of allocated memory and it only uses 50 GB, is there any Powershell command that will be able to extract the 50 GB? If yes, how will I be able to incorporate that script to the script above?
Based on your attempt to use Measure-VM, I assumed you are using Hyper-V. I use something similar to this in one of my Hyper-V scripts:
(Get-VM dechiro1).HardDrives | ForEach {
$GetVhd = Get-VHD -Path $_.Path
[pscustomobject]#{
Name = $_.Name
Type = $GetVhd.VhdType
ProvisionedGB = ($GetVhd.Size / 1GB)
CommittedGB = ($GetVhd.FileSize / 1GB)
}
}
Basically, for each of the virtual machine's hard drives, use Get-VHD to get the VHD details which includes the full size and what I refer to as the committed size (actual space on disk).
Example output:
Name Type ProvisionedGB CommittedGB
---- ---- ------------- -----------
Hard Drive on IDE controll... Dynamic 20 0.00390625
Hard Drive on IDE controll... Dynamic 40 0.00390625
Edit:
If you wanted to pull from every VM and include the VM name with the returned object and you prefer to use the pipeline form, this will work:
Get-VM | ForEach { $Vm = $_; $_.HardDrives } | ForEach {
$GetVhd = Get-VHD -Path $_.Path
[pscustomobject]#{
Vm = $Vm.Name
Name = $_.Name
Type = $GetVhd.VhdType
ProvisionedGB = ($GetVhd.Size / 1GB)
CommittedGB = ($GetVhd.FileSize / 1GB)
}
}
I'm trying to write a script that will take input from a .txt file of IP address. Do a reverse DNS lookup to get the hostname of the IP address and then export that data into .csv file.
Here is what I have so far.
# getting the IP's from the file
$IPADDR = Get-Content "C:\Users\douglasfrancis\Desktop\IP_Test.txt"
ForEach ($IPADDR in $IPADDR)
{
[System.Net.DNS]::GetHostbyAddress($IPADDR) | Add-Member -Name IP -Value $IPADDR - MemberType NoteProperty -PassThru | select IP, HostName | sort -property Hostname | export- csv "C:\Users\douglasfrancis\Desktop\ReverseLookup.csv"
}
How it is now the created CSV file will have the column heads that I assigned and the last IP address in the list with its hostname. So somehow its dropping everything else.
If I run it with the export-csv commented out then all the IP's are displayed in the console but are not sorted by hostname.
I've used this same basic pipe before with no issues so I'm kinda at a loss for what is going on here. Any help would be awesome.
Thanks,
You should put the result in an array before exporting it to CSV :
# getting the IP's from the file
$IPADDRS = Get-Content "C:\Users\douglasfrancis\Desktop\IP_Test.txt"
$result = #()
ForEach ($IPADDR in $IPADDRS)
{
$result += [System.Net.DNS]::GetHostbyAddress($IPADDR) | Add-Member -Name IP -Value $IPADDR -MemberType NoteProperty -PassThru | select IP, HostName
}
$result | sort -property Hostname | export-csv "C:\Users\douglasfrancis\Desktop\ReverseLookup.csv" -NoTypeInformation
#David Braban is true, this was not your trouble but I use $IPADDRS for the collection and $IPADDR for each value, this way it's much correct (en readable)/
In your code, I see:
ForEach ($IPADDR in $IPADDR)
That's very wrong: you use the same variable both as your collection and as the variable to iterate.
Use:
$ipaddr | %{ [System.Net.DNS]::GetHostbyAddress($_) } | ...