Inventory Out-File with a new row - windows

I have an Inventory Powershell script that I am trying to output into a csv. My goal is to output each execution of the script in a separate row going down their columns.
I've tried Export-Csv, but since i'm using variables, the csv displays (i'g guessing) metadata.
$ComputerName = Get-WmiObject Win32_OperatingSystem | select -ExpandProperty CSName
$OS_Name = Get-WmiObject Win32_OperatingSystem | Select-Object -ExpandProperty Caption
$OS_Architecture = Get-WmiObject Win32_OperatingSystem | select -ExpandProperty OSArchitecture
$System_Manufacturer = Get-WmiObject win32_computersystem | select -ExpandProperty Manufacturer
$Model = Get-WmiObject win32_computersystem | select -ExpandProperty Model
$CPU_Manufacturer = Get-WmiObject Win32_Processor | select -ExpandProperty Name
$Disk_Size_GB = Get-WmiObject win32_diskDrive | Measure-Object -Property Size -Sum | % {[math]::round(($_.sum /1GB),2)}
$Physical_Memory_GB = Get-WMIObject -class Win32_PhysicalMemory | Measure-Object -Property capacity -Sum | % {[Math]::Round(($_.sum / 1GB),2)}
$Version=(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseId
$InstallDate= systeminfo | find /I “Install Date”
$Assettag=(Get-WmiObject -Class Win32_SystemEnclosure | Select-Object SMBiosAssetTag).SMBiosAssetTag
$SerialNumber = (Get-WmiObject -Class Win32_BIOS | Select-Object SerialNumber).SerialNumber
($Assettag, $ComputerName, $System_Manufacturer, $Model, $OS_Name, $Version, $SerialNumber | Format-Table | Out-File C:\Users\1\Desktop\Newinvent.csv )
I expect each row to be filled with each execution
Thanks

If you want to use Export-Csv, you need to have an object with properties that contain the names and values you want to export. One way to do this is to create a [PSCustomObject] with all of your properties defined in a hash table. You can pipe that custom object to the Export-Csv command.
[PSCustomObject]#{"ComputerName" = $ComputerName
"OS_Name" = $OS_Name
"OS_Architecture" = $OS_Architecture
"System_Manufacturer" = $System_Manufacturer
"Model" = $Model
"CPU_Manufacturer" = $CPU_Manufacturer
"Disk_Size_GB" = $Disk_Size_GB
"Physical_Memory_GB" = $Physical_Memory_GB
"Version" = $Version
"InstallDate" = $InstallDate
"Assettag" = $Assettag
"SerialNumber" = $SerialNumber
} | Export-Csv -Path file.csv -NoTypeInformation -Append

And try to look at the result from Get-ComputerInfo - most of your needs are satisfied there.

I'd avoid the time consuming Systeminfo
> (Measure-Command {$systeminfo=(systeminfo) 2>$NULL}).Totalseconds
3,0428012
As well as Get-ComputerInfo
$OldProgressPreference = $ProgressPreference
$ProgressPreference = 'SilentlyContinue'
(Measure-Command {$ComputerInfo = Get-ComputerInfo}).Totalseconds
3,1837208
$ProgressPreference = $OldProgressPreference
And use an optimized version of your script which gets/converts InstallDate from registry:
> (Measure-Command{Q:\Test\2019\06\03\SO_56429703.ps1}).TotalSeconds
1,635074
Get-Content file.csv
## Q:\Test\2019\06\03\SO_56429703.ps1
function RoundGB($Size){
[math]::round(($Size/1GB),2)
}
$Win32OS = Get-WmiObject Win32_OperatingSystem
$Win32CS = Get-WmiObject Win32_ComputerSystem
$CurrVer = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
$InstDate= [timezone]::CurrentTimeZone.ToLocalTime([datetime]'1/1/1970').AddSeconds(
(Get-ItemProperty $CurrVer).InstallDate)
$inventory = [PSCustomObject]#{
ComputerName = $Win32OS.CSName
OSName = $Win32OS.Caption
OSArchitecture = $Win32OS.OSArchitecture
SystemManufacturer= $Win32CS.Manufacturer
Model = $Win32CS.Model
CPUManufacturer = (Get-WmiObject Win32_Processor).Name
DiskSizeGB = RoundGB (Get-WmiObject Win32_DiskDrive | Measure-Object Size -Sum).Sum
PhysicalMemoryGB = RoundGB (Get-WMIObject Win32_PhysicalMemory | Measure-Object capacity -Sum).Sum
Version = (Get-ItemProperty -Path $CurrVer -Name ReleaseId).ReleaseId
InstallDate = $InstDate
Assettag = (Get-WmiObject Win32_SystemEnclosure).SMBiosAssetTag
SerialNumber = (Get-WmiObject Win32_BIOS).SerialNumber
}
$Inventory | Export-Csv -Path file.csv -NoTypeInformation -Append

Related

Inventory script

Noob here, I need to extract some data from a cim interrogation of a list of servers, however the csv output is just the same reiteration of the local server, with the sum total equaling the number of lines in the input file. I think I'm doing something wrong with the array but Ive been beating my head. Help?
$ErrorActionPreference = 'SilentlyContinue'
#Define Some Variables
$importpath = "c:\directory1"
$workingpath = "c:\directory2"
#Do Some Filtering
Import-CSV -Path "$importpath\somefile.csv" | where {$_.Powerstate -ne "PoweredOff"} | where Guest -notlike *somestring* | Export-Csv "$workingPath\PRODUCTION.csv" -NoTypeInformation
Import-csv -Path "$workingPath\PRODUCTION.csv" | Select-Object -Property Name | Export-Csv -Path "$workingpath\SERVERS.csv" -NoTypeInformation
#Create final input foreach routine
Import-CSV -Path "$workingpath\SERVERS.csv" | Out-file $workingpath\SERVERS.txt
$servers = Get-Content -path "$workingpath\SERVERS.txt"
$results = foreach ($server in $servers) {
Get-CimInstance -ClassName win32_OperatingSystem -ErrorAction SilentlyContinue | Select-Object *
}
$results | Export-Csv -Path "$workingPath\PRODUCTIONRESULTS.csv" -NoTypeInformation -Append
Try including the computername when you run the Get-CimInstance command
$results = foreach ($server in $servers) {
Get-CimInstance -ComputerName $server -ClassName win32_OperatingSystem -ErrorAction SilentlyContinue | Select-Object *
}

Reduce memory consumption by Powershell script

I'm using this Powershell script to retrieve info of remote servers from a central server.
In this case, there are about 150 servers on Active Directory:
$Servers = Get-ADComputer -Filter 'Name -like "...*"' | Select-Object -ExpandProperty Name
foreach ($computer in $Servers)
{
try
{
$ping = Test-Connection -ComputerName $computer -count 1 -ErrorAction Stop
$IP = ($ping.IPV4Address).IPAddressToString
$hardware = Get-CimInstance -Class Win32_ComputerSystem -ComputerName $computer -ErrorAction Stop
$totalMemory = (Get-CimInstance Win32_PhysicalMemory -ComputerName $computer | Measure-Object -Property capacity -Sum).sum /1gb
$os = Get-CimInstance -Class Win32_OperatingSystem -ComputerName $computer
$cpu = Get-CimInstance -Class Win32_processor -ComputerName $computer | Group-Object -Property Name |
Select-Object -Property Name,
#{Name = 'TotalSockets'; Expression = {$_.Count}},
#{Name = 'TotalCores'; Expression = {($_.Group | Measure-Object -Property NumberOfCores -Sum).Sum}},
#{Name = 'TotalLogicalProcessors'; Expression = {($_.Group | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum}}
#$disks = Get-WmiObject Win32_Volume -ComputerName $computer -Filter "DriveType='3'" | Sort-Object Name
# create new custom object to keep adding store information to it
$Result = New-Object -TypeName PSCustomObject -Property #{
ComputerName = $computer.ToUpper()
IPAddress = $IP
Manufacturer = $hardware.Manufacturer
Model = $hardware.Model
ADDescription = (Get-ADComputer -Identity $computer -Properties Description).Description -join ';'
ProductName = $os.Caption
OSVersion = $os.version
BuildNumber = $os.BuildNumber
OSArchitecture = $os.OSArchitecture
Domain = $hardware.Domain
'RAM (GB)' = $totalMemory
CPU = $cpu.Name
CPUTotalSockets = $cpu.TotalSockets
CPUTotalCores = $cpu.TotalCores
CPUTotalLogicalProcessors = $cpu.TotalLogicalProcessors
CPUVirtualizationFirmwareEnabled = (Get-CimInstance -Class Win32_processor -ComputerName $computer).VirtualizationFirmwareEnabled -join ','
}
# Column ordering, re-order if you like
<#$colOrder = 'ComputerName', 'IPAddress', 'Manufacturer', 'Model', 'ADDescription',
'ProductName', 'OSVersion', 'BuildNumber', 'OSArchitecture',
'Domain', 'RAM (GB)', 'CPU', 'CPUTotalSockets', 'CPUTotalCores',
'CPUTotalLogicalProcessors', 'CPUVirtualizationFirmwareEnabled'#>
# Return all your results
#$Result | Select-Object -Property $colOrder
$Result | Select-Object "ComputerName", "IPAddress", "Manufacturer", "Model", "ADDescription", "ProductName", "OSVersion", "BuildNumber",
"OSArchitecture", "RAM (GB)", "CPU", "CPUTotalSockets", "CPUTotalCores", "CPUTotalLogicalProcessors", "CPUVirtualizationFirmwareEnabled", "Domain" |
Export-Csv -Path "C:\SQL\Get-Inventory.csv" -Delimiter '|' -Append -NoTypeInformation
#$disks | Format-Table DriveLetter, Label, #{Name='Size(GB)'; Expression={[decimal]('{0:N0}' -f($_.Capacity/1gb))}}, #{Name='FreeSpace(GB)'; Expression={[decimal]('{0:N0}' -f($_.FreeSpace/1gb))}}
}
catch
{ Write-Output "--- $computer ---" $Error[0] `n | Add-Content -Path C:\SQL\UnreachableServers.txt }
}
The Powershell's process uses an average of 50/75 Mb of RAM. It's possible to reduce the RAM usage?
I accept any kind of advice given my little experience on Powershell :)
Thanks in advance.
Alessandro

Export-CSV - (Powershell)

So i have the bottom scriptblock:
Import-csv C:\file_location.csv | foreach-object {
Get-WmiObject -computername $_.computername -class Win32_ComputerSystem | select username} | `
Select-Object computername, username | Export-CSV C:\file_location.csv -notypeinformation
the exported csv shows the Computer Name header but no actual computer and the username header is just fine. What and where am I missing something from?
Thank You!
select (which is an alias for Select-Object) returns an object with only the properties you specify. So when you did your first select username you got an object with just the username; all other properties were discarded, so when the second Select-Object call runs, there is no computername for it to return.
The first select seems completely unnecessary there; just take it out and I think everything will work as expected.
EDIT: I see now that computername is not a property of the returned WMI object; it came from the CSV. Your ForEach-Object is only returning the WMI object, so the CSV row object is being discarded.
What you need to do is add the computername from the CSV to the WMI object, which you can do with Select-Object (with a computed column) or Add-Member:
Import-csv C:\file_location.csv |
ForEach-Object {
Get-WmiObject -computername $_.computername -class Win32_ComputerSystem |
Select-Object #{Name='ComputerName';Expression={$_.computername}},username
} |
Export-CSV C:\file_location.csv -notypeinformation
Or:
Import-csv C:\file_location.csv |
ForEach-Object {
Get-WmiObject -computername $_.computername -class Win32_ComputerSystem |
Add-Member -NotePropertyName computername -NotePropertyValue $_.computername -Force -PassThru
} |
Select-Object computername, username
Export-CSV C:\file_location.csv -notypeinformation

Obtain a list of non-admin file shares from multiple Windows servers

GOAL: Obtain a CSV file with the following information:
Computer Name
Share Name
Share Path
Share Description
for all non-admin (type 0) SMB shares on all servers from a list (txt file).
INITIAL CODE:
param (
[Parameter(Mandatory=$true,Position=0)]
[ValidateNotNullOrEmpty()]
[String]
$path
)
$computers = Get-Content $path
$shareInfo = #()
ForEach ($computer in $computers) {
$shares = gwmi -Computer $computer -Class Win32_Share -filter "Type = 0" | Select Name,Path,Description
$shares | % {
$ShareName = $_.Name
$Props = [ordered]#{
Computer = $computer
ShareName = $_.Name
Path = $shares.Path
Description = $shares.Description
}
}
$ShareInfo += New-Object -TypeName PSObject -Property $Props
}
$shareInfo | Export-CSV -Path .\shares.csv -NoType
CODE OUTPUT:
"Computer","ShareName","Path","Description"
"SERVER1","SHARE1","System.Object[]","System.Object[]"
"SERVER2","SHARE12","System.Object[]","System.Object[]"
"SERVER3","SHARE3","System.Object[]","System.Object[]"
PROBLEM:
While the code provides output for each server, it seems to not include all shares from the servers. Furthermore, the Path and Description fields are not populated with good information.
ADDITIONAL INFO:
The code:
$shares = gwmi -Computer $computer -Class Win32_Share -filter "Type = 0" | Select Name,Path,Description
Produces good information as below:
Name Path Description
---- ---- -----------
print$ C:\WINDOWS\system32\spool\drivers Printer Drivers
Share D:\Share
SHARE2 D:\SHARE2
Software C:\Software The Software
$shares | % {
$ShareName = $_.Name
$Props = [ordered]#{
Computer = $computer
ShareName = $_.Name
Path = $shares.Path
Description = $shares.Description
}
}
You're using $shares instead of $_ for the Path and Description properties, so each of these properties is assigned a list of the values of the respective property of each element of the $shares collection.
Also, why are you building custom objects in the first place when you just need to filter the WMI query results? The computer name can be obtained from the __SERVER (or PSMachineName) property. Plus, type 0 means a shared disk drive, not an administrative share. You need to filter the latter by other criteria (usually description and/or share name).
$filter = "Type = 0 And Description != 'Default Share' And " +
"Name != 'ADMIN$' And Name != 'IPC$'"
$computers |
ForEach-Object { Get-WmiObject -Computer $_ -Class Win32_Share -Filter $filter } |
Select-Object #{n='Computer';e={$_.__SERVER}}, Name, Path, Description |
Export-Csv -Path .\shares.csv -NoType

Get Size, location and name of each shared folder

I have this code that generates a list of all the shares and the size however can not generate a txt with this information or the shared location
$servers = #("servername")
$sizes = #()
foreach($server in $servers) {
write-host "Server: $server"
(gwmi -class Win32_Share -ComputerName $server -filter "Type = 0" |
% {
write-host " share: $($_.Name)"
$s = gci \\$server\$($_.Name) -recurse -force | Measure-Object -Property length -Sum
New-Object PSObject -property #{Name=$_.Name; Server=$server; TotalSize=$s.Sum }
})
}
And this not only shows me the size and generates txt size and can generate txt
Get-WmiObject Win32_share -computer server01 | FT "server01", path, name > ServerShares.txt
Get-WmiObject Win32_share -computer server02 | FT "server02", path, name >> ServerShares.txt
Someone could help me to create only one that does everything
In your New-Object you just need to add additional properties to get the information you want:
If you're not running PowerShell v3, remove [Ordered]
$servers = #("servername")
$sizes = #()
foreach($server in $servers)
{
write-host "Server: $server"
# Get all shares
$shares = Get-WmiObject -class Win32_Share -ComputerName $server -filter "Type = 0"
# go through each share
foreach($share in $shares)
{
write-host " share: $($share.Name)"
# Get size of share
$size = Get-ChildItem -Path "\\$server\$($_.Name)" -recurse -force | Measure-Object -Property length -Sum
# Create a new object to store information
New-Object PSObject -property ([ordered]#{
# Name of share
Name = $share.Name
# Share path
Path = $share.path
# What server share is on
Server = $server
# Total size of share
TotalSize = $size.Sum
# Change this path to where you want the file to be saved to
}) | Export-Csv -Path C:\ShareDetails.csv -NoTypeInformation -Append
}
}
I made a small revision to #Bluecakes response in order to use COM instead of .NET to capture the size information. This overcomes the path-length issues.
# Get size of share
# $size = Get-ChildItem -Path "$($share.Name)" -recurse -force | Measure-Object -Property length -Sum
$objFSO = New-Object -com Scripting.FileSystemObject
$size = "{0:N2}" -f (($objFSO.GetFolder("$($share.Name)").Size) / 1MB)
Then you also need to remove ".sum"
# Total size of share
TotalSize = $size

Resources