Powershell: Out-File with Headers/Columns - powershell

I am very close to what I am looking for, I have all of the correct data and it is just not formatting correctly. Currently it is all in one column, and what I would like is for the headers to be in a row, and then each entry to be in its own row as well. Here is my current code:
$servers = Get-ADComputer -Filter "Name -like 'f****p*'" | Sort-Object | Select -ExpandProperty Name
$servers | foreach {
$server = $_
$serverIP = Test-Connection -ComputerName $server -Count 1 | Select -ExpandProperty IPV4Address
$serverIPString = $serverIP.IPAddresstoString
$scope = Get-DhcpServerv4Scope -ComputerName $server
$options = Get-DhcpServerv4OptionValue -ComputerName $server
New-Object -TypeName psobject -Property #{
ServerName = $server
ServerIP = $serverIPString
ScopeName = $scope.Name | Out-String
StartIP = $scope.StartRange.IPAddressToString | Out-String
EndIP = $scope.EndRange.IPAddressToString | Out-String
SubnetMask = $scope.SubnetMask.IPAddressToString | Out-String
Duration = $scope.LeaseDuration.Days | Out-String
OptionName = $options.Name | Out-String
OptionID = $options.OptionID | Out-String
OptionValue = $options.Value | Out-String
}
} | Select-Object ServerName, ServerIP, ScopeName, StartIP, EndIP, SubnetMask, Duration, OptionName, OptionID, OptionValue | Out-File C:\temp\FPScopes.csv
Currently the output looks like this example (using Duration and Options as an example, as it has the most generic data to share):
What I am looking for would be to have each object type as a column header, and have the entries in a separate row underneath the header:
Etc....
Any assistance would be greatly appreciated.
Thank you! :)
Ry
My final code, after help from this forum:
Add-Content -Value "ServerName,ServerIP,ScopeName,StartRange,EndRange,SubnetMask,Duration,OptionName,OptionID,Value" -Path c:\temp\POSScopes.csv
Get-ADComputer -Filter {Name -like 'p****p01' -or Name -like 'p****p02' -or Name -like 'q****001' -or Name -like 'q****002'} | Sort-Object | Select -ExpandProperty Name | Out-File C:\Temp\POSServers.txt
$servers = Get-Content C:\Temp\POSServers.txt
$servers | foreach {
$server = $_
$serverIP = Test-Connection -ComputerName $server -Count 1 | Select -ExpandProperty IPV4Address
$serverIPString = $serverIP.IPAddresstoString
$scope = Get-DhcpServerv4Scope -ComputerName $server
$options = Get-DhcpServerv4OptionValue -ComputerName $server
New-Object -TypeName psobject -Property #{
ServerName = $server
ServerIP = $serverIPString
ScopeName = $scope.Name | Out-String
StartIP = $scope.StartRange.IPAddressToString | Out-String
EndIP = $scope.EndRange.IPAddressToString | Out-String
SubnetMask = $scope.SubnetMask.IPAddressToString | Out-String
Duration = $scope.LeaseDuration.Days | Out-String
OptionName = $options.Name | Out-String
OptionID = $options.OptionID | Out-String
OptionValue = $options.Value | Out-String
}
for ($i = ($Options.Count -1); $i -gt -1; $i--) {
Add-Content -Value "$($server),$($serverIPString),$($scope.Name),$($scope.StartRange.IPAddressToString),$($scope.EndRange.IPAddressToString),$($scope.SubnetMask.IPAddressToString),$($scope.LeaseDuration.Days),$($options[$i].Name),$($options[$i].OptionID),$($Options[$i].Value)" -Path C:\temp\POSScopes.csv
}
}

Add-Content -Value "ServerName,ServerIP,ScopeName,StartRange,EndRange,SubnetMask,Duration,OptionName,OptionID,Value" -Path c:\temp\POSScopes.csv
Get-ADComputer -Filter {Name -like 'p****p01' -or Name -like 'p****p02' -or Name -like 'q****001' -or Name -like 'q****002'} | Sort-Object | Select -ExpandProperty Name | Out-File C:\Temp\POSServers.txt
$servers = Get-Content C:\Temp\POSServers.txt
$servers | foreach {
$server = $_
$serverIP = Test-Connection -ComputerName $server -Count 1 | Select -ExpandProperty IPV4Address
$serverIPString = $serverIP.IPAddresstoString
$scope = Get-DhcpServerv4Scope -ComputerName $server
$options = Get-DhcpServerv4OptionValue -ComputerName $server
New-Object -TypeName psobject -Property #{
ServerName = $server
ServerIP = $serverIPString
ScopeName = $scope.Name | Out-String
StartIP = $scope.StartRange.IPAddressToString | Out-String
EndIP = $scope.EndRange.IPAddressToString | Out-String
SubnetMask = $scope.SubnetMask.IPAddressToString | Out-String
Duration = $scope.LeaseDuration.Days | Out-String
OptionName = $options.Name | Out-String
OptionID = $options.OptionID | Out-String
OptionValue = $options.Value | Out-String
}
for ($i = ($Options.Count -1); $i -gt -1; $i--) {
Add-Content -Value "$($server),$($serverIPString),$($scope.Name),$($scope.StartRange.IPAddressToString),$($scope.EndRange.IPAddressToString),$($scope.SubnetMask.IPAddressToString),$($scope.LeaseDuration.Days),$($options[$i].Name),$($options[$i].OptionID),$($Options[$i].Value)" -Path C:\temp\POSScopes.csv
}
}

Related

invoke command on all those servers to see which admin accounts are active on each server

I have been fetching both direct members and groups inside local administrators group in our remote machines. I want to get an output like below.
Also , if there are GROUP members inside local admin group then I want to organize only GROUP members like below.
MACHINE01,User01,TRUE,GROUP01;GROUP02
output:
"Computername","Members"
"MACHINE01","contoso\User01 contoso\User02 contoso\GROUP01 contoso\GROUP02
desired output:
Computername,Direct Members,Account Status,Group Members
MACHINE01,User01,TRUE,GROUP01;GROUP02
MACHINE01,User02,FALSE
MACHINE02,User05,TRUE,GROUP04;GROUP05;GROUP12
MACHINE02,User08,FALSE
MACHINE02,User12,FALSE
MACHINE44,User07,TRUE
script :
$server_list = #()
Import-Csv C:\temp\server3.csv | ForEach-Object {$server_list += $_.name}
invoke-command {
$members = net localgroup administrators |
where {$_ -AND $_ -notmatch "command completed successfully"} |
select -skip 4
New-Object PSObject -Property #{
Computername = $env:COMPUTERNAME
Members=$members
}
} -computer $server_list -HideComputerName | Select * -ExcludeProperty RunspaceID, PSComputerName, PSShowComputerName | Export-CSV c:\temp\local_admins2.csv -NoTypeInformation
Get-ADComputer -Filter * -SearchBase "OU=Servers,DC=test,DC=local" | select
name | Export-Csv C:\data\servers3.csv
Output:
"ComputerName","Direct Members","Account Status","Group Members"
"machine01","user01","OK",""
"machine01","user02","Degraded",""
"machine02","user03","OK",""
"machine02","user04","Degraded",""
LASTLY UPDATE OUTPUT WMI:
ComputerName Direct Members Account Status Group Members
------------ -------------- -------------- -------------
**MACHINE01 Administrator Degraded Domain Admins;IT-Admins**
MACHINE01 Theo OK
MACHINE01 LocalAdmin OK
**MACHINE02 Administrator Degraded DBA Admins;Software-Admins**
MACHINE02 Theo OK
MACHINE02 LocalAdmin OK
net localgroup does not output anything that differentiates between users or groups, so if possible, use
Get-LocalGroupMember and Get-LocalUser:
$server_list = (Import-Csv -Path 'C:\temp\server3.csv').name
$result = Invoke-Command -ComputerName $server_list -ScriptBlock {
$members = Get-LocalGroupMember -Group "Administrators"
$groups = $members | Where-Object {$_.ObjectClass -eq 'Group'} | ForEach-Object {($_.Name -split '\\')[-1]}
$users = #($members | Where-Object {$_.ObjectClass -eq 'User'})
if ($users.Count) {
# now loop over the user objects
$users | ForEach-Object {
$name = ($_.Name -split '\\')[-1]
$user = if ($_.PrincipalSource -eq 'Local') {
Get-LocalUser -Name $name -ErrorAction SilentlyContinue
}
else {
Get-ADUser -Filter "SamAccountName -eq '$name'" -ErrorAction SilentlyContinue
}
# output an object
[PsCustomObject]#{
'ComputerName' = $env:COMPUTERNAME
'Direct Members' = $name
'Account Status' = $user.Enabled
'Group Members' = $groups -join ';'
}
# clear the $goups here because you only want to list them once per server
$groups = $null
}
}
else {
# no users, just groups
[PsCustomObject]#{
'ComputerName' = $env:COMPUTERNAME
'Direct Members' = $null
'Account Status' = $null
'Group Members' = $groups -join ';'
}
}
} | Select-Object * -ExcludeProperty PSComputerName, RunspaceId
$result | Export-Csv -Path 'c:\temp\local_admins2.csv' -NoTypeInformation
If module Microsoft.Powershell.LocalAccounts is not available to you, you can experiment with module localaccount, but I have no experience with that..
I don't have that old OSes, so you'll have to test this.
Below uses WMI to query the servers for the group memberships:
$server_list = (Import-Csv -Path 'C:\temp\server3.csv').name
$result = foreach ($server in $server_list) {
$query = "Associators of {Win32_Group.Domain='$server',Name='Administrators'} where Role=GroupComponent"
$members = Get-WmiObject -Query $query -ComputerName $server |
Where-Object { $_.__CLASS -match '(User|Group)' } |
Select-Object Name, Caption,
#{Name = 'ObjectClass'; Expression = {$matches[1]}},
#{Name = 'ComputerName'; Expression = {$_.__SERVER}},
Status, LocalAccount, SID, Domain
$groups = #($members | Where-Object {$_.ObjectClass -eq 'Group'})
$users = #($members | Where-Object {$_.ObjectClass -eq 'User'})
if ($users.Count) {
# now loop over the user objects
$users | ForEach-Object {
# output an object
[PsCustomObject]#{
'ComputerName' = $_.ComputerName
'Direct Members' = $_.Name
'Account Status' = $_.Status
'Group Members' = ($groups.Name | Sort-Object -Unique) -join ';'
}
# clear the $groups here because you only want to list them once per server
$groups = $null
}
}
elseif ($groups.Count) {
# no users, just groups
[PsCustomObject]#{
'ComputerName' = $groups[0].ComputerName
'Direct Members' = $null
'Account Status' = $null
'Group Members' = ($groups.Name | Sort-Object -Unique) -join ';'
}
}
}
$result | Export-Csv -Path 'c:\temp\local_admins2.csv' -NoTypeInformation
Another alternbative is to use [ADSI]:
$server_list = (Import-Csv -Path 'C:\temp\server3.csv').name
$group = 'Administrators'
$members = foreach ($server in $server_list) {
try {
([ADSI]"WinNT://$server/$group,group").psbase.Invoke('Members') | ForEach-Object {
# test if local or domain
$ADSPath = $_.GetType().InvokeMember("ADSPath", 'GetProperty', $null, $_, $null)
$local = ($ADSPath -like 'WinNT://*')
# get the object name
$name = $_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null)
# get object class
$class = $_.GetType().InvokeMember('Class', 'GetProperty', $null, $_, $null)
if ($class -eq 'User') {
if ($local) {
$flag = $_.GetType().InvokeMember("userflags", 'GetProperty', $null, $_, $null)
$enabled = !($flag -band 2) # ADS_UF_ACCOUNTDISABLE
}
else {
$enabled = (Get-ADUser -Filter "SamAccountName -eq '$name'" -ErrorAction SilentlyContinue).Enabled
}
}
else { $enabled = $null }
[PSCustomObject] #{
ComputerName = $server.ToUpper()
Group = $group
Name = $name
ObjectClass = $class
Enabled = $enabled
}
}
}
catch {
Write-Warning $_
}
}
$groups = #($members | Where-Object {$_.ObjectClass -eq 'Group'})
$users = #($members | Where-Object {$_.ObjectClass -eq 'User'})
$result = if ($users.Count) {
# now loop over the user objects
$users | ForEach-Object {
# output an object
[PsCustomObject]#{
'ComputerName' = $_.ComputerName
'Direct Members' = $_.Name
'Account Status' = $_.Enabled
'Group Members' = ($groups.Name | Sort-Object -Unique) -join ';'
}
# clear the $groups here because you only want to list them once per server
$groups = $null
}
}
elseif ($groups.Count) {
# no users, just groups
[PsCustomObject]#{
'ComputerName' = $_.ComputerName
'Direct Members' = $null
'Account Status' = $null
'Group Members' = ($groups.Name | Sort-Object -Unique) -join ';'
}
}
$result | Export-Csv -Path 'c:\temp\local_admins2.csv' -NoTypeInformation
Output from the above when testing
Result using Get-LocalGroupMember:
ComputerName Direct Members Account Status Group Members
------------ -------------- -------------- -------------
MACHINE01 Administrator False Domain Admins;IT-Admins
MACHINE01 LocalAdmin True
MACHINE01 Theo True
Result using WMI:
ComputerName Direct Members Account Status Group Members
------------ -------------- -------------- -------------
MACHINE01 Administrator Degraded Domain Admins;IT-Admins
MACHINE01 Theo OK
MACHINE01 LocalAdmin OK
Result using ADSI:
ComputerName Direct Members Account Status Group Members
------------ -------------- -------------- -------------
MACHINE01 Administrator False Domain Admins;IT-Admins
MACHINE01 Theo True
MACHINE01 LocalAdmin True

having issues recording error in export-csv

I have powershell script to pull down hotfixID, installedon, lastbootuptime and freespace in C drive. (I googled around and changed couple of things I need.) when the Pc is not reachable it will
Write-Warning "$_ cannot be reached, skipping."
I also want to capture the computer name of the failed PC to my CSV. I tried
| Export-Csv C:\test\computerDetails.csv -NoTypeInformation
or append but seems like its not working. can someone please help? below is my whole script.
(Get-Content C:\test\serverlist.txt).Trim() | ForEach {
If (Test-Connection -ComputerName $_ -Count 1 -Quiet)
{
$update = Get-CimInstance Win32_QuickFixEngineering -ComputerName $_ | Sort-Object InstalledOn -Descending | Select-Object -First 1
$os = Get-CimInstance win32_operatingsystem -ComputerName $_
$disk = Get-WmiObject Win32_LogicalDisk -ComputerName $_ -Filter "DeviceID='C:'"
$props = #{
ComputerName = $_
HotFixID = $update.HotFixID
InstalledOn = $update.InstalledOn
lastbootuptime = $os.LastBootUpTime
FreeSpace_GB = $disk.FreeSpace / 1GB
}
New-Object PsObject -Property $props
}
Else {
Write-Warning "$_ cannot be reached, skipping." | Export-Csv C:\test\computerDetails.csv -NoTypeInformation
}
} | Sort ComputerName |
Select ComputerName,HotFixID,InstalledOn,lastbootuptime,FreeSpace_GB |
Export-Csv C:\test\computerDetails.csv -NoTypeInformation
Main problem with adding it to the CSV is that it is a string. If you treat the erroneous machines the same as successful ones, then you can throw them in the same CSV.
I have added an ArrayList there as the storage variable and then for each computer it creates a temp PSObject to store your results in, overwriting the variable each loop but not before dumping the variable into the ArrayList for export at the end.
$Errors = New-Object System.Collections.ArrayList
(Get-Content C:\test\serverlist.txt).Trim() | ForEach {
$Temp = New-Object -TypeName PSObject
If (Test-Connection -ComputerName $_ -Count 1 -Quiet) {
$update = Get-CimInstance Win32_QuickFixEngineering -ComputerName $_ | Sort-Object InstalledOn -Descending | Select-Object -First 1
$os = Get-CimInstance win32_operatingsystem -ComputerName $_
$disk = Get-WmiObject Win32_LogicalDisk -ComputerName $_ -Filter "DeviceID='C:'"
$props = [ordered]#{
ComputerName = $_
HotFixID = $update.HotFixID
InstalledOn = $update.InstalledOn
lastbootuptime = $os.LastBootUpTime
FreeSpace_GB = $disk.FreeSpace / 1GB
Error = "Success"
}
$Temp | Add-Member -NotePropertyMembers $props -TypeName temp
} Else {
$props = [ordered]#{
ComputerName = $_
Error = "Cannot be reached"
}
$Temp | Add-Member -NotePropertyMembers $props -TypeName temp
Write-Warning "$_ cannot be reached, skipping."
}
$Errors.Add($Temp) > $null
}
$Errors | Export-Csv C:\temp\computerDetails.csv -NoTypeInformation -Append

Optimal way of creating object from two objects

I built this, which is working fine, it takes about 7-9 seconds to run and display.
I'm wondering, is there a faster/optimal way of building this custom object?
As you can see, I want all the drivers information from Win32_PNPsigneddriver but to that, I add two other properties from Win32_PNPentity (configmanagererrorcode and status) based on the DeviceID.
This way, the final object contains all drivers and shows if there is an error for the device using that driver.
$poste = "COMPUTER1234"
$DriversUp = Get-WmiObject -computername $poste Win32_PNPsigneddriver |
Where-Object {$_.DeviceName -ne $null}
$Devices = Get-WmiObject -computername $poste Win32_PNPentity
$DriversDevices = foreach ($driver in $DriversUp) {
$driver |
  Select-Object DeviceClass, Manufacturer, DeviceName,
FriendlyName, DriverName, InfName,
#{name='Status';expression={$Devices | Where-Object {$_.DeviceID -eq "$($driver.DeviceID)"} | Select-Object -ExpandProperty status}},
#{name='ConfigManagerErrorCode';expression={$Devices | Where-Object {$_.DeviceID -eq "$($driver.DeviceID)"} | Select-Object -ExpandProperty ConfigManagerErrorCode}},
#{name='DriverDate';expression={[DateTime]::ParseExact(($_.DriverDate).Split('.')[0], "yyyyMMddHHmmss", [System.Globalization.CultureInfo]::InvariantCulture)}},
DriverVersion
}
$DriversDevices |
Sort-Object DeviceClass |
 Out-GridView -Title "$poste - Drivers utilisés"
Like I said everything works fine already. However, I'm curious to know if there's a faster way!
Starting in PowerShell 3.0, the Get-WmiObject cmdlet has been superseded by Get-CimInstance.
$poste = "COMPUTER1234"
$cimses = New-CimSession -ComputerName $poste
$p = & {$args} DeviceClass Manufacturer DeviceName FriendlyName DriverName `
InfName DriverVersion DeviceID DriverDate
Get-CimInstance -CimSession $cimses -ClassName Win32_PnPSignedDriver `
-Property $p -Filter 'DeviceName != NULL' |
ForEach-Object {
$dev = Get-CimInstance -CimSession $cimses -ClassName Win32_PnPEntity `
-Property Status, ConfigManagerErrorCode `
-Filter "PNPDeviceID='$($_.DeviceID.Replace('\', '\\'))'"
[pscustomobject]#{
DeviceClass = $_.DeviceClass
Manufacturer = $_.Manufacturer
DeviceName = $_.DeviceName
FriendlyName = $_.FriendlyName
DriverName = $_.DriverName
InfName = $_.InfName
Status = $dev.Status
ConfigManagerErrorCode = $dev.ConfigManagerErrorCode
DriverDate = '{0:yyyyMMddHHmmss}' -f $_.DriverDate
DriverVersion = $_.DriverVersion
}
} | Sort-Object DeviceClass | Out-GridView -Title "$poste - Drivers utilisés"
Remove-CimSession -CimSession $cimses
On my machine, the type of the Win32_PnPSignedDriver.DriverDate member is DateTime.
Get-CimClass -ClassName Win32_PnPSignedDriver |
Select-Object -ExpandProperty CimClassProperties |
Where-Object Name -eq 'DriverDate' |
Select-Object CimType | Format-Table -AutoSize
CimType
-------
DateTime
The bottleneck is searching for a device every time using Where-Object.
The following code uses Group-Object to solve the issue.
$poste = "COMPUTER1234"
$DriversUp = Get-WmiObject -ComputerName $poste Win32_PnPSignedDriver -Filter "DeviceName != NULL"
$Devices = Get-WmiObject -ComputerName $poste Win32_PnPEntity -Property DeviceID,Status,ConfigManagerErrorCode
#($DriversUp; $Devices) | Group-Object DeviceID | Where-Object Count -eq 2 | ForEach-Object {
$driver, $device = $_.Group
[pscustomobject]#{
DeviceClass = $driver.DeviceClass
Manufacturer = $driver.Manufacturer
DeviceName = $driver.DeviceName
FriendlyName = $driver.FriendlyName
DriverName = $driver.DriverName
InfName = $driver.InfName
Status = $device.Status
ConfigManagerErrorCode = $device.ConfigManagerErrorCode
DriverDate = [datetime]::ParseExact($driver.DriverDate.Substring(0, 14), "yyyyMMddHHmmss", $null)
DriverVersion = $driver.DriverVersion
}
} | Sort-Object DeviceClass | Out-GridView -Title "$poste - Drivers utilisés"
This is how I would do it, not big difference in performance, but more clear IMO:
Used an ArrayList for the results, also replaced the Where-Object on the Get-WmiObject with -Filter, it's a bit faster...
$poste = "COMPUTER1234"
$DriversUp = Get-WmiObject -computername $poste Win32_PNPsigneddriver -Filter "DeviceName != NULL"
$Devices = Get-WmiObject -computername $poste Win32_PNPentity
$DriversDevices = New-Object System.Collections.ArrayList
foreach ($driver in $DriversUp) {
$row = "" | Select DeviceClass,Manufacturer,DeviceName,FriendlyName,DriverName,
InfName,Status,ConfigManagerErrorCode,DriverDate,DriverVersion
$row.DeviceClass = $driver.DeviceClass
$row.Manufacturer = $driver.Manufacturer
$row.DeviceName = $driver.DeviceName
$row.DriverName = $driver.DriverName
$row.InfName = $driver.InfName
$row.Status = ($Devices | ? {$_.DeviceID -eq $driver.DeviceID}).Status
$row.ConfigManagerErrorCode = ($Devices | ? {$_.DeviceID -eq $driver.DeviceID}).ConfigManagerErrorCode
$row.DriverDate = [datetime]::ParseExact(($driver.DriverDate.Split('.')[0]),"yyyyMMddHHmmss",$null)
$row.DriverVersion = $driver.DriverVersion
[void]$DriversDevices.Add($row)
}
$DriversDevices | Sort-Object DeviceClass | Out-GridView -Title "$poste - Drivers utilisés"

How to extract server information

Objective: How to extract server information?
For each server name listed in servers.txt, I would like to get the following information (in this format):
Server name, IP Address, OS name, Total Physical Memory, Processors, each drive letter and size, System Model
Comma separated and new line for each server.
Below is my PowerShell code. Can your guys give a hint on why this does not work? Also why I get an error with New-Object statement?
foreach ($ComputerName in (Get-Content -Path .\servers.txt)) {
$HashProps = #{
'tHostname' = Get-WmiObject Win32_Computersystem -ComputerName $ComputerName | Select-Object -ExpandProperty Name
'tIP' = [System.Net.Dns]::GetHostAddresses($computername)
'tOS' = Get-WmiObject -ComputerName $ComputerName -Class Win32_OperatingSystem | Select-Object -ExpandProperty Caption
'tMemory' = Get-WmiObject Win32_PhysicalMemory | Measure-Object -Property capacity -Sum | foreach { "$("{0:n2}" -f ( $_.Sum/1GB ) )" }
'tcpu' = Get-WmiObject Win32_processor | Select-Object name, numberofcores
'tDisks' = Get-WmiObject Win32_LogicalDisk | foreach { "$($_.DeviceID) $("{0:n2}" -f ( $_.Size/ 1GB ) )" }
'tsysmodel' = Get-Wmiobject Win32_computersystem | Select-Object model
}
New-Object -TypeName psObject -Property $HashProps |
ConvertTo-Csv -NoTypeInformation | Out-File -Append .\output.csv
}
I am open for a other approach, if this is easier.
Have you verified that each of those lines actually return what you want?
I just threw this into the ISE and it works fine:
$f = gwmi win32_computersystem | select name,model,totalphysicalmemory
$hash = #{
'name' = $f.name
'model' = $f.model
'memory' = $("{0:n2}" -f ( $f.totalphysicalmemory/1GB ) )
}
New-Object -TypeName psobject -Property $hash | ConvertTo-Csv -NoTypeInformation | Out-File -Append .\test.csv
Also, if you want the properties to appear in a specific order in the CSV, it will take some additional magic, otherwise they're put in alphabetically.
A little bit pimped, maybe this will help you:
$Servers = Foreach ($ComputerName in (Get-Content -Path .\Servers.txt)) {
$CS = Get-WmiObject Win32_ComputerSystem -ComputerName $ComputerName
$OS = Get-WmiObject Win32_OperatingSystem -ComputerName $ComputerName
$PM = Get-WmiObject Win32_PhysicalMemory -ComputerName $ComputerName
$PR = Get-WmiObject Win32_processor -ComputerName $ComputerName
$LD = Get-WmiObject Win32_LogicalDisk -ComputerName $ComputerName
$IP = [System.Net.Dns]::GetHostAddresses($ComputerName)
[PSCustomObject]#{
ServerName = $CS | Select-Object -ExpandProperty Name
IPAddress = $IP | Select-Object -ExpandProperty IPAddressToString
OS = $OS | Select-Object -ExpandProperty Caption
Memory = $PM | Measure-Object -Property Capacity -Sum | foreach { "$("{0:n2}" -f ( $_.Sum/1GB ) )" }
CPU = $PR | Select-Object Name, NumberOfCores
Disks = $LD | foreach { "$($_.DeviceID) $("{0:n2}" -f ( $_.Size/ 1GB ) )" }
Model = $CS | Select-Object -ExpandProperty Model
}
}
$File = Join-Path $env:TEMP 'Ouptut.csv'
$Servers | Export-Csv -Path $File -NoTypeInformation -Delimiter ';'
Start-Process $File

Changing the Export-CSV output output format

I am working on a PowerShell script that will output a list od system admins to a CSV file using the Export-Csv command. The portion of the script that gets the data is:
Foreach ($Computer in $Computers){
$Online = Test-Connection -ComputerName $Computer -Quiet
if ($Online -eq "True"){
$GroupName = Get-WmiObject win32_group -ComputerName $Computer | ? {$_.SID -eq 'S-1-5-32-544'} | Select-Object name -ExpandProperty name
$LocalGroup =[ADSI]"WinNT://$Computer/$GroupName"
$GroupMembers = #($LocalGroup.psbase.Invoke("Members"))
$Members = $GroupMembers | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
foreach ($Member in $Members){
$obj = New-Object System.Object
$obj | Add-Member -MemberType NoteProperty -Name "Computer" -Value $Computer
$obj | Add-Member -MemberType NoteProperty -Name "AdminGroupMembers" -Value $Member
$obj
}
}
}
}
Get-Admins | Export-Csv -NoTypeInformation c:\scripts\adm.csv -Encoding UTF8
The current output is formatted looks like this:
"Computer1", "Admin1"
"Computer1", "Admin2"
"Computer1", "Admin3"
"Computer1", "Admin4"
"Computer2", "Admin1"
"Computer2", "Admin2"
"Computer3", "Admin1"
I am trying to get the output to look like this:
"Computer1", "Admin1" , "Admin2" , "Admin3" , "Admin4"
"Computer2", "Admin1" , "Admin2"
"Computer3", "Admin1" , "Admin2" , "Admin3"
Any Ideas?
Your output format is not CSV, so Export-Csv is not a suitable tool for you. Try this instead:
Get-Admins | group { $_.Computer } | % {
'{0},{1}' -f #($_.Group.Computer)[0], ($_.Group.AdminGroupMembers -join ',')
} | Out-File 'output.csv'
For PowerShell v2 you'll need to manually expand the group properties:
Get-Admins | group { $_.Computer } | % {
$computer = #($_.Group | select -Expand Computer)[0]
$admins = ($_.Group | select -Expand AdminGroupMembers) -join ','
'{0},{1}' -f $computer, $admins
} | Out-File 'output.csv'