I have a csv-file with data like this:
"89216865";"89216865";"Alternator";"PowerMax";"4543"
"MG 149";"MG 149";"MAHLE Alternator";"MAHLE AM GmbH";"4543"
"MG 258";"MG 258";"MAHLE Alternator";"MAHLE AM GmbH";"4543"
"MS 222";"MS 222";"MAHLE Starter";"MAHLE AM GmbH";"4543"
"MS 241";"MS 241";"MAHLE Starter";"MAHLE AM GmbH";"4543"
"MS 29";"MS 29";"MAHLE Starter";"MAHLE AM GmbH";"4543"
"MS 386";"MS 386";"MAHLE Starter";"MAHLE AM GmbH";"4543"
"MS 645";"MS 645";"MAHLE Starter";"MAHLE AM GmbH";"4543"
"MS 230";"MS 230";"MAHLE Starter";"MAHLE AM GmbH";"4543"
"3300216";"3300216";"Alternator OE";"PowerMax";"4543"
"9213171";"9213171";"Alternator";"PowerMax";"4543"
"8212676";"8212676";"Starter";"PowerMax";"4543"
"9214266";"9214266";"Alternator";"PowerMax";"4543"
I need to replace the string "4543" with "287" in every row where "MAHLE AM GmbH" appears.
I have tried this.
Get-Content "C:\Users\SvcBI\Documents\Autodoc\Autodoc_Temp.csv" |
Foreach-Object ($_ -match "MAHLE AM GmbH") {-replace "4543", "287"} |
Set-Content C:\Users\SvcBI\Documents\Autodoc\POWERMAX_DK_2.csv
Please help /Kim
It looks like you are using Powershell.
One way to do it could be reading the lines, and if the line contains the value, the perform the replacement.
See this page for the meaning of $_
Get-Content "C:\Users\SvcBI\Documents\Autodoc\Autodoc_Temp.csv" | ForEach-Object {
if($_.Contains("MAHLE AM GmbH")) {
$_.Replace("4543", "287")
} else { $_ }
} | Set-Content C:\Users\SvcBI\Documents\Autodoc\POWERMAX_DK_2.csv
Related
When I use PowerShell, I only get one (Workbook3) of several window titles (Workbook1, Workbook2, Workbook3), but I want to get the entire list of all open Excel books. I am trying to use the following code:
[array]$Titles = Get-Process | Where-Object {$_.mainWindowTItle} |Foreach-Object {$_.mainwindowtitle}
ForEach ($item in $Titles){Write-Host $item}
UPD. (We get a list of books, but we don't see which ones only to read)
If I open the book in read-only mode, it will not be visible in the output of the program. In the Task Manager this mark is in the name of the window.
$excel = [Runtime.Interopservices.Marshal]::
GetActiveObject('Excel.Application')
ForEach ( $wkb in $excel.workbooks ) {
$wkb.Name
}
This seems to do the trick:
Clear-Host
$excel = [Runtime.Interopservices.Marshal]::
GetActiveObject('Excel.Application')
ForEach ( $wkb in $excel.workbooks ) {
$wkb.Name
}
Sample Output:
PERSONAL.xlsm
Cash Count.xls
Check Calc.xls
Coke Price Comparison Sheet.xls
PS>
HTH
So, my solution:
Clear-Host
Remove-Variable * -ErrorAction SilentlyContinue
$excel = [Runtime.Interopservices.Marshal]::GetActiveObject('Excel.Application')
$date = Get-Date -Format "d.MM.y HH:mm"
$person = $env:UserName
#arrays with books and status
ForEach ( $book in $excel.workbooks ) {$books_names = ,$book.Name + $books_names}
ForEach ( $book in $excel.workbooks ) {$books_reads = ,$book.ReadOnly + $books_reads}
#print
#ForEach ($item in $books_names){$item}
#ForEach ($item in $books_reads){$item}
#delete empty string
$books_names = $books_names[0..($books_names.Count-2)]
$books_reads = $books_reads[0..($books_reads.Count-2)]
#replace
$books_reads = $books_reads -replace "False" , "write."
$books_reads = $books_reads -replace "True" , "read"
# Table view
$t = $books_names |%{$i=0}{[PSCustomObject]#{person= $person; date= $date;book=$_; status=$books_reads[$i]};$i++}
#$t | ft
#$t | Out-GridView
# write to txt
Add-Content "C:\My\1.txt" $t | ft
#pause
1.txt looks like:
#{person=BelyaevKN; date=14.06.21 14:05; book=workbook1; status=write}
#{person=BelyaevKN; date=14.06.21 14:05; book=workbook2; status=read}
How do I convert files between CSV, XLS, XLSM, and XLSX to CSV, XLS, XLSX, and XML in Powershell without using Excel.Application? I would like to just use MICROSOFT.ACE.OLEDB.12.0.
I wrote this as a module first, but then prefer it as a ps1 to .include.
You could also pop it in the top of a file and call it underneath.
A note about creating excel spreadsheets without using excel: I am not very good at it. It seems to be working with the data I throw at it. If you have a better way of setting up the schema and writing into the file I would be game, but I only needed success, not elegance.
''''Powershell
<#
.SYNOPSIS
This function will take 2 filenames and use the excel application to convert from the first file to the second file.
.DESCRIPTION
This function allows you to use the full power of excel to open and save files. The infile can be any file that excel can open. The outfile can be xlsx, xls or csv. Also, there is an option to delete the destination file before runing the save operation to avoid prompts when overwriting, and to erase the origin file after the process has completed.
.EXAMPLE
Convert-OLEDB -infile 'Source.xls' -outfile 'destination.xlsx' -delete $true
Converts source.xls to xlsx file type.
Deletes source.xls when done.
Deletes destination.xlsx before it converts.
.EXAMPLE
Convert-OLEDB -infile 'Source.xlsx' -outfile 'destination.csv'
Converts xlsx to csv.
Leaves both files behind when done.
.EXAMPLE
Convert-OLEDB -infile 'Source.csv'
Converts infile Source.csv (or whatever format) to xlsx of the same name.
Leaves both behind when done.
.EXAMPLE
Convert-OLEDB -infile 'Source.xlsx' -Extension '.csv'
Converts xlsx to csv. By passing just the extension it will use the same base file name.
Leaves both files behind when done.
.EXAMPLE
dir *.xls | Sort-Object -Property LastWriteTime | Convert-OLEDB -Extension ".csv"
Similar to above but uses the pipeline to do multiple conversions.
If full outfile name is given, it will create just one file over and over again. In this example it would go in chronological order creating csv files.
.EXAMPLE
Dir *.xls | Convert-OLEDB -extension ".csv" -delete $True | Convert-OLEDB -extension ".xls"
That's just weird, but it might solve your problem, and it works.
.PARAMETER infile
Name of the origin file to use. If the full path is not given it will be opened from the context the script is running in.
.PARAMETER outfile (extension)
Name of the destination file to create. If the full path is not given it will save in the default destination of Excel.
.PARAMETER delete
If $true it will delete the target location file if it exists before conversion and the origin file after conversion. Functions like a move with clobber.
If anything else or blank it will leave origin in place and if destination exists it will prompt for overwrite.
#>
function Convert-OLEDB{
param(
[parameter(ValueFromPipeLineByPropertyName=$True,ValueFromPipeline=$True)]
[Alias('FullName')]
[string] $infile,
[Alias('Extension')]
[string] $outfile,
[bool] $delete
)
Begin {
$begin_outfile = $outfile
$oledb = (New-Object system.data.oledb.oledbenumerator).GetElements() | Sort -Property SOURCES_NAME | where {$_.SOURCES_NAME -like "Microsoft.ACE.OLEDB*"} | Select -Last 1
If ($oledb -eq $null) {
Write-Output "MICROSOFT.ACE.OLEDB does not seem to exist on this computer."
Write-Output "Please see https://www.microsoft.com/en-us/download/details.aspx?id=54920"
Write-Output "This can also happen if you have not installed the 32 or 64 bit version "
Write-Output "and you are running this script in the architecture that is missing it."
Write-Output "Solution is to do silent install on missing driver"
break
} else {
$Provider=$Oledb.SOURCES_NAME
Write-Verbose "Provider $Provider found on this computer"
}
}
Process{
#Check infile
if (-not($infile)) {
Write-Output "You must supply a value for -infile"
break
}
else {
Try {
$file = Get-Item $infile
$OleDbConn = New-Object "System.Data.OleDb.OleDbConnection";
$OleDbCmd = New-Object "System.Data.OleDb.OleDbCommand";
$OleDbAdapter = New-Object "System.Data.OleDb.OleDbDataAdapter";
$DataTable = New-Object "System.Data.DataTable";
$Source = $file.FullName
Switch($file.Extension){
".xls" {$OleDbConn.ConnectionString = "Provider=$Provider;Data Source=""$Source"";Extended Properties=""EXCEL 12.0;HDR=Yes;IMEX=1"";"}
".xlsx" {$OleDbConn.ConnectionString = "Provider=$Provider;Data Source=""$Source"";Extended Properties=""EXCEL 12.0 XML;HDR=Yes;IMEX=1"";"}
".xlsm" {$OleDbConn.ConnectionString = "Provider=$Provider;Data Source=""$Source"";Extended Properties=""EXCEL 12.0 MACRO;HDR=Yes;IMEX=1"";"}
Default {
$Source = $file.DirectoryName
$OleDbConn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=""$Source"";Extended Properties=""text;HDR=Yes;IMEX=1"";"
}
}
$OleDbCmd.Connection = $OleDbConn;
$OleDbConn.Open();
Switch($file.Extension){
{$_ -in (".xls", ".xlsx",".xlsm")} {$FirstSheet = $OleDbConn.getSchema("Tables")[0].Table_Name}
Default {$FirstSheet = $file.Name}
}
$OleDbCmd.CommandText = "select * from [$FirstSheet];”
$OleDbAdapter.SelectCommand = $OleDbCmd;
$RowsReturned = $OleDbAdapter.Fill($DataTable);
$OleDbConn.Close();
}
Catch {Write-Output "$infile does not seem to exist, or I can't get to it"; break}
}
#Check outfile
#Reset value for pipeline loop
$outfile = $begin_outfile
#If blank just presume xlsx
if (-not($outfile)) {
$outfile = $file.FullName -replace '\.[^.]+$',".xlsx"
Write-Verbose "No outfile supplied, setting outfile to $outfile"
}
#If startswith a dot, use as an extension.
If ($outfile.StartsWith(".")) {
$outfile = $file.FullName -replace '\.[^.]+$',$outfile
Write-Verbose "Extension supplied, setting outfile to $outfile"
}
if ($file.FullName -eq $outfile) {
#Nobody needs us to create a copy of an existing file.
write-verbose "Goal already achieved, moving on"
}
Else {
if(Test-Path ($outfile)){
#Avoid prompting to overwrite by removing an existing file of the same name
Remove-Item -path ($outfile)
}
Try {
#derive XlFileFormat from extension
if($outfile -cmatch '\.[^.]+$') {
$extens="" #Reset for pipeline loop
switch ($Matches[0])
{
".csv" {
#Out to CSV
$DataTable | Export-Csv "$outfile" -NoTypeInformation
}
".xml" {
#Simple, poorly formed:
#$DataTable.TableName = $FirstSheet
#$DataTable.WriteXml("$outfile")
#BetterForm, strongly Typed, empty/Null differentiation
Export-Clixml -Path "$outfile" -InputObject $DataTable
}
Default {
#Out to xlsx
$OleDbConnOut = New-Object "System.Data.OleDb.OleDbConnection";
$OleDbCmdOut = New-Object "System.Data.OleDb.OleDbCommand";
$OleDbAdapterOut = New-Object "System.Data.OleDb.OleDbDataAdapter";
$DataTable2 = New-Object "System.Data.DataTable";
If($Matches[0] -eq ".xls"){$ext_swap = ""}
If($Matches[0] -eq ".xlsx"){$ext_swap = " XML"}
$OleDbConnOut.ConnectionString = "Provider=$Provider;Data Source=""$outfile"";MODE=ReadWrite;Extended Properties=""Excel 12.0$ext_swap"";"
$OleDbCmdOut.Connection = $OleDbConnOut;
$OleDbConnOut.Open();
$Create = "CREATE TABLE [Sheet2] ("
$Stuff = "INSERT INTO [Sheet2] ("
$Stuff2 = "VALUES ("
$DataTable.Columns | % {
$name = $_.ColumnName.Replace("#",".")
$Type = $_.DataType
$Stuff += "[$name], "
$Stuff2 += "?, "
$Create += "[$name] $Type, "
$atname = "#" + $name
}
$Stuff = $Stuff.TrimEnd(", ") + ")"
$Stuff2 = $Stuff2.TrimEnd(", ") + ")"
$Create = $Create.TrimEnd(", ") + ")"
$OleDbCmdOut.CommandText = $Create
$UpdateCount = $OleDbCmdOut.ExecuteNonQuery()
$OleDbAdapterOut.InsertCommand = $Stuff + " " + $Stuff2
$DataTable | % {
$Insert = "INSERT INTO [Sheet2] VALUES ("
$_.ItemArray | % {
$val = $_
$Type = $_.GetType().Name
switch ($Type) {
"Double" {
#Write "$Type"
$Insert += "$val, "
}
"DBNull" {
#Write "$Type"
$Insert += "NULL, "
}
Default {
#Write "$Type"
$val = $val.Replace("""","""""")
$Insert += """$val"", "
}
}
}
$Insert = $Insert.TrimEnd(", ") + ")"
$OleDbCmdOut.CommandText = $Insert
Try {
Write-Verbose "Attempting to run this command: $Insert"
$updatedcount = $OleDbCmdOut.ExecuteNonQuery()
}
Catch{Write-Output "$Error[0] /nIt seems like there was a problem with this command: $Insert"}
}
$OleDbConnOut.Close();
}
}
}
else {
Write-Output "Unable to determine the output file extenstion, this really shouldn''t happen"
break #if it can't find an extension in regex
}
}
Catch {
Write-Host "Unable to convert file $file because powershell with OLEDB cannot open or save it without help"
break
}
if ($delete) {#If asked to delete
if(Test-Path ($outfile)){ #And a file now exists where outfile said it should be
if(Test-Path ($infile)){ #And there is a file at infile
Remove-Item -path ($infile) #Delete it
}
}
}
}
}
End{
#Cleanup
}
}
'''
I try to extract a computername from a txt file $pcliste using a string comparison to the MAC address of the local machine. the text file contains:
super-pc 00:15:5D:FF:0B:33
av-client4 00:15:5D:FF:0B:38
temp 00:15:5D:FF:0B:39
I use the following PowerShell code:
$macadresse = Get-WmiObject Win32_NetworkAdapterConfiguration | select macaddress
$macadresse = $macadresse.macaddress
$pcnamen = Get-Content -Path $pcliste
$computername = "TEMP-NAME"
for ($i=0; $i -lt $pcnamen.Length; $i++) {
$string = $pcnamen[$i]
if ($string -match $macadresse) {
write "MAC found!"
$index = $pcnamen[$i].IndexOf(" ")
$computername = $pcnamen[$i].substring(0, $index)
}
}
the MAC adress of my test VM is 00:15:5D:FF:0B:38, but the string comparison in the loop remains false.
For testing I already put the MAC in a string variable instead of extracting it using the Get-WmiObject, and this works.
I also tried to convert the extracted macadress to a string using [string]$macadress.
I assume it's some kind of datatype/objecttype problem that causes the -match to fail.
What about a hash table to put the MAC as key and pc name as value in.
$MyMACs = Get-WmiObject win32_networkadapterconfiguration|Select -Expand MacAddress
$MyMACs
$PcHash = #{}
ForEach ($Row in (Get-Content '.\pcliste.txt')) {
$PcHash.Add($Row.Split(' ')[1],$Row.Split(' ')[0])
}
ForEach($Mac in $MyMACs){
IF ($PcHash[$Mac]){
"Found {0} for MAC {1}" -f $PcHash[$Mac],$Mac
}
}
Or more basic
$MyMACs = Get-WmiObject win32_networkadapterconfiguration|Select -Expand MacAddress
ForEach($Mac in $MyMACs){
Select-String -Path '.\pcliste.txt' -Pattern $MAC|ForEach-Object{$_.Line}
}
try to modify like this:
$string = $pcnamen[$i] -split " "
if ($macadresse -contains $string[1]) {
you can simplify your code like this :
$pcnamen = import-csv $pcliste -Delimiter ' ' -Header Computer, Mac
Get-WmiObject Win32_NetworkAdapterConfiguration | %{
$Mac=$_.macaddress
$pcnamen | where Mac -eq $Mac
}
I have this PowerShell script that strips html tags and just leaves the text and have it display the word count for that html file when the script is executed. My question is when I execute:
function Html-ToText {
param([System.String] $html)
# remove line breaks, replace with spaces
$html = $html -replace "(`r|`n|`t)", " "
# write-verbose "removed line breaks: `n`n$html`n"
# remove invisible content
#('head', 'style', 'script', 'object', 'embed', 'applet', 'noframes', 'noscript', 'noembed') | % {
$html = $html -replace "<$_[^>]*?>.*?</$_>", ""
}
# write-verbose "removed invisible blocks: `n`n$html`n"
# Condense extra whitespace
$html = $html -replace "( )+", " "
# write-verbose "condensed whitespace: `n`n$html`n"
# Add line breaks
#('div','p','blockquote','h[1-9]') | % { $html = $html -replace "</?$_[^>]*?>.*?</$_>", ("`n" + '$0' )}
# Add line breaks for self-closing tags
#('div','p','blockquote','h[1-9]','br') | % { $html = $html -replace "<$_[^>]*?/>", ('$0' + "`n")}
# write-verbose "added line breaks: `n`n$html`n"
#strip tags
$html = $html -replace "<[^>]*?>", ""
# write-verbose "removed tags: `n`n$html`n"
# replace common entities
#(
#("•", " * "),
#("‹", "<"),
#("›", ">"),
#("&(rsquo|lsquo);", "'"),
#("&(quot|ldquo|rdquo);", '"'),
#("™", "(tm)"),
#("⁄", "/"),
#("&(quot|#34|#034|#x22);", '"'),
#('&(amp|#38|#038|#x26);', "&"),
#("&(lt|#60|#060|#x3c);", "<"),
#("&(gt|#62|#062|#x3e);", ">"),
#('&(copy|#169);', "(c)"),
#("&(reg|#174);", "(r)"),
#(" ", " "),
#("&(.{2,6});", "")
) | % { $html = $html -replace $_[0], $_[1] }
# write-verbose "replaced entities: `n`n$html`n"
return $html + $a | Measure-Object -word
}
And then run:
Html-ToText (new-object net.webclient).DownloadString("test.html")
it displays 4 words that are displayed in the output in PowerShell. How do I export that output from the PowerShell window into a an excel spreadsheet with the column words and the count 4?
The CSV you want just looks like this:
Words
4
it's easy enough to just write that to a text file, Excel will read it. But you're in luck, the output of Measure-Object is already an object with 'Words' as a property and '4' as a value, and you can feed that straight into Export-Csv. Use select-object to pick just the property you want:
$x = Html-ToText (new-object net.webclient).DownloadString("test.html")
# drop the Lines/Characters/etc fields, just export words
$x | select-Object Words | Export-Csv out.csv -NoTypeInformation
I'd be tempted to see if I could use
$x = Invoke-WebResponse http://www.google.com
$x.AllElements.InnerText
to get the words out of the HTML, before I tried stripping the content with replaces.
I figured it out. What I did was added
+ $a | Measure-Object -Word after the #html variable in the script and then ran:
Html-ToText (new-object net.webclient).DownloadString("test.html") + select-Object Words | Export-Csv out.csv -NoTypeInformation and it exported the word count – josh s 1 min ago
I want to compare 2 strings in PowerShell. One is the actual date and the other will be read from a file that contains a lot of rows. The row always will contain the same structure, then we can extract a substring for compare the date.
The file will be a plain text. The types of a date and the substring are the same.
MyProblem:
If I execute this code the program doesn't write anything, the Write-Host is not executing, even if the strings are the same. Can someone help me?
$list = Import-Csv C:\file.txt
#actual date
$date = Get-date -Format d
$day = $fecha.Substring(0,2)
$month = $fecha.Substring(3,2)
$year = $fecha.Substring(6,4)
$date = "$year$month$day"
#I do this because if I use $list will return me an pscustomobject object
$file = Get-Content -Path C:\file.txt
#Use a ForEach loop to process all lines in the source file
foreach ($row in $file) {
$sub = $entrada.Substring(7,7)
if ($date-like $sub) {Write-Host "They are equals"}
if ($sub -Match $date) {Write-Host "They are equals"}
if ($date.Equals($sub)) {Write-Host "They are equals"}
if ($date-eq $sub) {Write-Host "They are equals"}
if ($sub -contains $date) {Write-Host "They are equals"}
}
Your reference date string is 8 characters long, but the string you extract from the lines has only 7 characters, so it's unlikely you'll ever get a match. Particularly since you carefully chose your comparisons to avoid even accidental matches. ;) Also, as #arco444 pointed out in the comments to your question, your loop variable $row is never used anywhere inside the loop.
I would suggest to simplify the code to something like this:
$date = Get-Date -f 'yyyyMMdd'
Get-Content -Path 'C:\file.txt' | Where-Object { $_.Substring(7,8) -eq $date }
That would list only those lines from the input file that contain a matching date.
Another option would be to use the Contains() method on each line:
Get-Content -Path 'C:\file.txt' | Where-Object { $_.Contains($date) }
but that would find a matching date anywhere in a line, not just at the given position.
I'd avoid using wildcard (-like) or regular expression (-match) checks, since you want to compare a fixed value, not a pattern. And you can't use the -contains operator, because that one is for checking if an array contains a particular element.
It looks like "entrada" and "row" were intended to refer to the same data item.
Try it like this:
$list = Import-Csv C:\file.txt
#actual date
$date = Get-date -Format d
$day = $fecha.Substring(0,2)
$month = $fecha.Substring(3,2)
$year = $fecha.Substring(6,4)
$date = "$year$month$day"
#I do this because if I use $list will return me an pscustomobject object
$file = Get-Content -Path C:\file.txt
#Use a ForEach loop to process all lines in the source file
foreach ($entrada in $file) {
$sub = $entrada.Substring(7,7)
if ($date-like $sub) {Write-Host "They are equals"}
if ($sub -Match $date) {Write-Host "They are equals"}
if ($date.Equals($sub)) {Write-Host "They are equals"}
if ($date-eq $sub) {Write-Host "They are equals"}
if ($sub -contains $date) {Write-Host "They are equals"}
}