I have a powershell script in which i can get information about my operating system (windows version, build...). However all that information is shown in the powershell console and I want them to be exported to a CSV or a XML file.
The script is :
Get-CimInstance Win32_OperatingSystem |
Select-Object Caption, CSDVersion, ServicePackMajorVersion, BuildNumber |
FL
Use Export-Csv cmdlet:
Get-CimInstance Win32_OperatingSystem | Select-Object Caption, CSDVersion, ServicePackMajorVersion, BuildNumber | Export-Csv -NoTypeInformation -Path .\OS_Info.csv
Result (OS_Info.csv):
"Caption","CSDVersion","ServicePackMajorVersion","BuildNumber"
"Microsoft Windows Server 2012 R2 Datacenter",,"0","9600"
Thank you it worked, the file is generated in the folder System32
As Rohin Sidharth mentioned, .\ prefix for the path will create file in the current dir ($PWD in PowerShell). You probably run PowerShell as administrator: in this case the default directory is %WinDir%\System32. Just use full path or GetFolderPath .Net method to get common folder path, like desktop:
... | Export-Csv -NoTypeInformation -Path 'C:\OS_Info.csv'
... | Export-Csv -NoTypeInformation -Path (Join-Path -Path [System.Environment]::GetFolderPath('Desktop') -ChildPath 'OS_Info.csv')
Can you also show me how to export many results in the same file ? for
example i have a script in which i can know all the update that are
installed :
Get-Hotfix | Select HotfixID,Description,InstalledOn | Sort InstalledOnfunction
and i want the results saves in the same CSV file
You can do this by using Select-Object's calculated properties:
# Get OS info
$OsInfo = Get-CimInstance -ClassName Win32_OperatingSystem
Get-Hotfix | # Get HotFixes
Sort-Object -Property InstalledOnfunction | # Sort them
Select-Object -Property #( # Select required fields
# Add Caption property from $OsInfo variable
#{
Name = 'Caption'
Expression = {$OsInfo.Caption}
}
# Add CSDVersion property from $OsInfo variable
#{
Name = 'CSDVersion'
Expression = {$OsInfo.CSDVersion}
}
# Add ServicePackMajorVersion property from $OsInfo variable
#{
Name = 'ServicePackMajorVersion'
Expression = {$OsInfo.ServicePackMajorVersion}
}
# Add BuildNumber property from $OsInfo variable
#{
Name = 'BuildNumber'
Expression = {$OsInfo.BuildNumber}
}
# Add other properties from original HotFix object
'HotfixID'
'Description'
'InstalledOn'
) | Export-Csv -NoTypeInformation -Path 'C:\OS_Info.csv'
You can also try to join objects using custom function.
Quick tip: Make sure you don't pipe to Format List (FL) then pipe to export-csv or you'll open the CSV file and your data will look like this.
ClassId2e4f51ef21dd47e99d3c952918aff9cd pageHeaderEntry pageFooterEntry
autosizeInfo shapeInfo groupingEntry
033ecb2bc07a4d43b5ef94ed5a35d280
Microsoft.PowerShell.Commands.Internal.Format.ListViewHeaderInfo
9e210fe47d09416682b841769c78b8a3
27c87ef9bbda4f709f6b4002fa4af63c
4ec4f0187cb04f4cb6973460dfe252df
cf522b78d86c486691226b40aa69e95c
Related
I am having a helluva time trying to understand why this script is not working as intended. It is a simple script in which I am attempting to import a CSV, select a few columns that I want, then export the CSV and copy over itself. (Basically we have archived data that I only need a few columns from for another project due to memory size constraints). This script is very simple, which apparently has an inverse relationship with how much frustration it causes when it doesn't work... Right now the end result is I end up with an empty csv instead of a csv containing only the columns I selected with Select-Object.
$RootPath = "D:\SomeFolder"
$csvFilePaths = Get-ChildItem $RootPath -Recurse -Include *.csv |
ForEach-Object{
Import-CSV $_ |
Select-Object Test_Name, Test_DataName, Device_Model, Device_FW, Data_Avg_ms, Data_StdDev |
Export-Csv $_.FullName -NoType -Force
}
Unless you read the input file into memory in full, up front, you cannot safely read from and write back to the same file in a given pipeline.
Specifically, a command such as Import-Csv file.csv | ... | Export-Csv file.csv will erase the content of file.csv.
The simplest solution is to enclose the command that reads the input file in (...), but note that:
The file's content (transformed into objects) must fit into memory as a whole.
There is a slight risk of data loss if the pipeline is interrupted before all (transformed) objects have been written back to the file.
Applied to your command:
$RootPath = "D:\SomeFolder"
Get-ChildItem $RootPath -Recurse -Include *.csv -OutVariable csvFiles |
ForEach-Object{
(Import-CSV $_.FullName) | # NOTE THE (...)
Select-Object Test_Name, Test_DataName, Device_Model, Device_FW,
Data_Avg_ms, Data_StdDev |
Export-Csv $_.FullName -NoType -Force
}
Note that I've used -OutVariable csvFiles in order to collect the CSV file-info objects in output variable $csvFiles. Your attempt to collect the file paths via $csvFilePaths = ... doesn't work, because it attempts to collects Export-Csv's output, but Export-Csv produces no output.
Also, to be safe, I've changed the Import-Csv argument from $_ to $_.FullName to ensure that Import-Csv finds the input file (because, regrettably, file-info object $_ is bound as a string, which sometimes expands to the mere file name).
A safer solution would be to output to a temporary file first, and (only) on successful completion replace the original file.
With either approach, the replacement file will have default file attributes and permissions; if the original file had special attributes and/or permissions that you want to preserve, you must recreate them explicitly.
As Matt commented, your last $PSItem ($_) not related to the Get-ChildItem anymore but for the Select-Object cmdlet which don't have a FullName Property
You can use differnt foreach approach:
$RootPath = "D:\SomeFolder"
$csvFilePaths = Get-ChildItem $RootPath -Recurse -Include *.csv
foreach ($csv in $csvFilePaths)
{
Import-CSV $csv.FullName |
Select-Object Test_Name,Test_DataName,Device_Model,Device_FW,Data_Avg_ms,Data_StdDev |
Export-Csv $csv.FullName -NoType -Force
}
Or keeping your code, add $CsvPath Variable containing the csv path and use it later on:
$RootPath = "D:\SomeFolder"
Get-ChildItem $RootPath -Recurse -Include *.csv | ForEach-Object{
$CsvPath = $_.FullName
Import-CSV $CsvPath |
Select-Object Test_Name,Test_DataName,Device_Model,Device_FW,Data_Avg_ms,Data_StdDev |
Export-Csv $CsvPath -NoType -Force
}
So I have figured it out. I was attempting to pipe through the Import-Csv cmdlet directly instead of declaring it as a variable in the o.g. code. Here is the code snippet that gets what I wanted to get done, done. I was trying to pipe in the Import-Csv cmdlet directly before, I simply had to declare a variable that uses the Import-Csv cmdlet as its definition and pipe that variable through to Select-Object then Export-Csv cmdlets. Thank you all for your assistance, I appreciate it!
$RootPath = "\someDirectory\"
$CsvFilePaths = #(Get-ChildItem $RootPath -Recurse -Include *.csv)
$ColumnsWanted = #('Test_Name','Test_DataName','Device_Model','Device_FW','Data_Avg_ms','Data_StdDev')
for($i=0;$i -lt $CsvFilePaths.Length; $i++){
$csvPath = $CsvFilePaths[$i]
Write-Host $csvPath
$importedCsv = Import-CSV $csvPath
$importedCsv | Select-Object $ColumnsWanted | Export-CSV $csvPath -NoTypeInformation
}
I have a problem with my Script.
I wanted to make a Script which makes a list of software which is found in a specific registry path
and see if this software equals installed software. and if so it should output me the uninstall string.
but right now it does not work as wanted. it never show me the output I wanted even if its similar. As Example i have the Program Git as Branding and in the software I got Git version 2.26.2 but it wont output the uninstall string when I selected git.
My code is:
$branding = Get-ChildItem "HKLM:\Software\DLR\Branding" | Get-ItemProperty | Select-Object -expandProperty ProgramName
$software = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Select-Object -ExpandProperty DisplayName
ForEach ($brandinglist in $branding) {
$objCombobox.Items.Add("$brandinglist")
}
$objComboBox_SelectedIndexChanged=
{
$selectme = $objCombobox.SelectedItem
Write-Host $selectme
if ("$selectme" -like "*$software*") {
$uninstall = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object {$_.DisplayName -match "$electme" } | Select-Object -Property UninstallString
Write-Host "$uninstall"
}
}
You are trying the -like comparison wrong, in which you compare the selected item to an array of displaynames which doesn't work that way.
Also, there is no reason to get the Uninstall strings and Displaynames using an almost identical code twice.
Try
# get a string array of program names
$branding = Get-ChildItem -Path 'HKLM:\Software\DLR\Branding' | Get-ItemProperty | Select-Object -ExpandProperty ProgramName
$regPaths = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall', 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
# get an object array of DisplayName and UninstallStrings
$software = Get-ChildItem -Path $regPaths | Get-ItemProperty | Select-Object DisplayName, UninstallString
# fill the combobox with the (string array) $branding
$objCombobox.Items.AddRange($branding)
$objComboBox.Add_SelectedIndexChanged ({
$selectme = $objCombobox.SelectedItem
Write-Host $selectme
# get the objects that have a displayname like the selected item and write out the matching Uninstall strings
$software | Where-Object {$_.DisplayName -like "*$selectme*" } | ForEach-Object {
Write-Host $_.UninstallString
}
})
When running the following line in PowerShell including the "Format-Table -AutoSize", an empty output file is generated:
Get-ChildItem -Recurse | select FullName,Length | Format-Table -AutoSize | Out-File filelist.txt
The reason I need the output file to be AutoSized is because longer filenames from the directoy are being trunacted. I am trying to pull all Filenames and File Sizes for all files within a folder and subfolders. When removing the -Autosize element, an output file is generated with truncated file names:
Get-ChildItem -Recurse | select FullName,Length | Out-File filelist.txt
Like AdminOfThings commented, use Export-CSV to get the untruncated values of your object.
Get-ChildItem -Recurse | select FullName,Length | Export-CSv -path $myPath -NoTypeInformation
I do not use Out-File much at all, and only use Format-Table/Format-List for interactive scripts. If I want to write data to a file, Select-Object Column1,Column2 | Sort-Object Column1| Export-CSV lets me select the properties of the object I am exporting that I want to export, and sort the records as needed. you can change the delimiter from a comma to tab/pipe/whatever else you may need.
While the other answer may address the issue, you may have other reasons for wanting to use Out-File. Out-File has a "Width" parameter. If this is not set, PowerShell defaults to 80 characters - hence your issue. This should do the trick:
Get-ChildItem -Recurse | select FullName,Length | Out-File filelist.txt -Width 250 (or any other value)
The Format-* commandlets in PowerShell are only intended to be used in the console. They do not actually produce output that can be piped to other commandlets.
The usual approach to get the data out is with Export-Csv. CSV files are easily imported into other scripts or spreadsheets.
If you really need to output a nicely formatted text file you can use .Net composite formatting with the -f (format) operator. This works similarly to printf() in C. Here is some sample code:
# Get the files for the report
$files = Get-ChildItem $baseDirectory -Recurse
# Path column width
$nameWidth = $files.FullName |
ForEach-Object { $_.Length } |
Measure-Object -Maximum |
Select-Object -ExpandProperty Maximum
# Size column width
$longestFileSize = $files |
ForEach-Object { $_.Length.tostring().Length } |
Measure-Object -Maximum |
Select-Object -ExpandProperty Maximum
# Have to consider that some directories will have no files with
# length strings longer than "Size (Bytes)"
$sizeWidth = [System.Math]::Max($longestFileSize, "Size (Bytes)".Length)
# Right-align paths, left-align file size
$formatString = "{0,-$nameWidth} {1,$sizeWidth}"
# Build the report and write it to a file
# ArrayList are much more efficient than using += with arrays
$lines = [System.Collections.ArrayList]::new($files.Length + 3)
# The [void] cast are just to prevent ArrayList.add() from cluttering the
# console with the returned indices
[void]$lines.Add($formatString -f ("Path", "Size (Bytes)"))
[void]$lines.Add($formatString -f ("----", "------------"))
foreach ($file in $files) {
[void]$lines.Add($formatString -f ($file.FullName, $file.Length.ToString()))
}
$lines | Out-File "Report.txt"
Im currently running the following commands, but im running them through a foreachloop. I can currently output them both to a csv as just a list for each machine, but ideally id like to output them to a csv of all the machines in the loop, that has the apps listed along the top, then below the computername, version, etc. so that i can append the csv and just have one big csv that i can sort and filter when opened in excel.
Aditionally id also like to be able to alert if app versions are differnt than my baseline, not sure where to start on this though.
$InstalledApps = gwmi Win32Reg_AddRemovePrograms64 | Select DisplayName, Publisher, Version
$InstalledApps +=
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -Command {gwmi Win32Reg_AddRemovePrograms | Select DisplayName, Publisher, Version}
$InstalledApps = $InstalledApps | sort displayname | Get-Unique -AsString
$InstalledApps| Select DisplayName, Publisher, Version | ogv -PassThru | export-csv .\apps.csv
Thanks
Powershell v3. and above.
Try to use CimInstance instead of WMI where possible.
#Define a Table Array
$MasterTable = #()
#Define computer list
$Computerlist = "computer1", "computer22"
#Run Foreach to retrieve data from each computer remotely
Foreach ($computer in $Computerlist) {
$MasterTable += Get-CimInstance win32_product -Computername $Computer |
Select-Object #{Name = "Computername"; Expression = {$Computer}},
#{Name = "SoftwareName"; Expression = {$_.Caption}},
#{Name = "Publisher"; Expression = {$_.Vendor}},
#{Name = "Version"; Expression = {$_.Version}}
}
$MasterTable | export-csv .\apps.csv -NoTypeInformation -Append
This should give you one CSV export with four columns containing all the information you require (incl the computername Get-CimInstance was run against).
You can do some additional logic with the MasterTable Variable if you like before exporting to CSV
Yes, this is also possible using WMI, however I would suggest you look at migrating WMI calls to CimInstance instead using Powershell v.3 and above as WMI is legacy and is not really firewall friendly as CimInstance is for example.
But here is the code for using WMI.
#Define a Table Array
$MasterTable = #()
#Define computer list
$Computerlist = "computer1", "computer2"
#Run Foreach to retrieve data from each computer remotely
Foreach ($computer in $Computerlist) {
$MasterTable += Get-WmiObject -Class Win32_Product -Computername $Computer |
Select-Object #{Name = "Computername"; Expression = {$Computer}},
#{Name = "SoftwareName"; Expression = {$_.Caption}},
#{Name = "Publisher"; Expression = {$_.Vendor}},
#{Name = "Version"; Expression = {$_.Version}}
}
$MasterTable | export-csv c:\temp\apps.csv -NoTypeInformation -Append
I want the greatest value (mailboxSize) at the top of the file. I have a cvs as inport.
When I do the following sort cmd:
Import-Csv import.csv| Sort-Object MailboxSize,DisplayName -Descending | Export-Csv SORT.csv
I get the following result:
"DisplayName","MailboxSize"
"persone6","9941"
"persone3","8484"
"persone1","7008"
"persone4","4322"
"persone5","3106"
"persone7","27536"
"persone10","24253"
"persone8","1961"
"persone9","17076"
"persone11","17012"
"persone2","15351"
"persone12","11795"
"persone14","1156"
"persone13","1008"
But I want this as a result!
"persone7","27536"
"persone10","24253"
"persone9","17076"
"persone11","17012"
"persone2","15351"
"persone12","11795"
"persone6","9941"
"persone3","8484"
"persone1","7008"
"persone4","4322"
"persone5","3106"
"persone14","1156"
"persone13","1008"
When importing a CSV-file, all properties are made string-type. You have to cast the MailboxSize to an int before you can sort it properly. Try:
Import-Csv import.csv |
Sort-Object {[int]$_.MailboxSize}, DisplayName -Descending |
Export-Csv SORT.csv
You should also use the -NoTypeInformation switch in Export-CSV to avoid the #TYPE ..... line (first line in an exported CSV-file).
Sample:
$data = #"
"DisplayName","MailboxSize"
"persone6","9941"
"persone3","8484"
"persone1","7008"
"persone4","4322"
"persone5","3106"
"persone7","27536"
"persone10","24253"
"persone8","1961"
"persone9","17076"
"persone11","17012"
"persone2","15351"
"persone12","11795"
"persone14","1156"
"persone13","1008"
"# | ConvertFrom-Csv
$data |
Sort-Object {[int]$_.MailboxSize}, DisplayName -Descending |
Export-Csv SORT.csv -NoTypeInformation
SORT.csv
"DisplayName","MailboxSize"
"persone7","27536"
"persone10","24253"
"persone9","17076"
"persone11","17012"
"persone2","15351"
"persone12","11795"
"persone6","9941"
"persone3","8484"
"persone1","7008"
"persone4","4322"
"persone5","3106"
"persone8","1961"
"persone14","1156"
"persone13","1008"
I'm guessing the usernames are fake, but be aware that the same issue goes for DisplayName if your usernames actually was personeXX where XX is an int. Like:
persone7 27536
persone20 27536
persone13 27536
To sort them probably, you'd have to create a scriptblock for Sort-Object or create your own function to split the value and sort them correctly.