I am looking for a way to populate a list box object with a dynamic list. Basically I want to write a Foreach loop that will go into a folder and pull out files and clean the names up and then list them for execution. i have a For Each Loop Below but it needs the .FullName to be able to execute. i would prefer to use .Name
$button18_Click = {
if($comboBox1.SelectedIndex -and $combobox2.SelectedIndex -eq -1 ){
$textbox5.BackColor = 'Red'
$textbox4.BackColor = 'Red'
$textbox4.Text= "Please Choose Driver"
$textBox5.Text="Please Choose Van"
}
Else{
$listbox1.Items.Clear()
$FileItem = GCI $textBox1.Text -Filter *.pdf
Foreach($File in $FileItem){
$ListBox1.Items.Add($File.Name)
$textbox4.Text= "Driver Selected"
$textBox5.Text="Van Selected"
$textbox4.BackColor = 'Info'
$textbox5.BackColor = 'Info'
$textBox12.Text = $comboBox1.SelectedItem + " - " + $comboBox2.SelectedItem + " - " + $dateTimePicker1.Text
}
}
}
Once Items are in the listbox1 i then have this code below to move the selected Items into listbox2
$listbox1_DoubleClick={
if ($listbox1.SelectedIndex -gt -1)
{
$listBox2.Items.Add($listBox1.SelectedItem);
Move-Item $listbox2.Items $textbox2.text
Get-ChildItem $textBox2.Text -Filter *.pdf | rename-item -NewName {((get-date).ToString("HH.mm.ss.")+,$_.name)}
$listBox1.Items.Remove($listBox1.SelectedItem);
$MJI3 = GCI $textBox2.Text -Filter *.pdf
Move-Item $MJI3.FullName $textBox3.Text
}
}
like is said if i have the .FullName this all works perfectly fine, but the appearance looks to messy. especially when my GUI is busy enough.
Related
I'm working on a script to compare two directories. There are two main things I want the script to show in the output--which files exist on one directory but not the other, and which files appear in both directories but have differences in them. Matching files don't need to show up.
I got some advice before on how to achieve this, but since I'm still pretty new to PS I'm having trouble executing it. What I'm trying to do is this:
I have Path #1. For each file in that path, I want to test for their existence on Path #2.
If the file exists in both paths, do a hash comparison between them. If there are differences, add the files to List A.
If the file appears in Path 1 but not Path 2, put them in List B.
This isn't as important, but would it also be possible to find files that exist in Path 2 but not Path 1? For work purposes that probably won't matter, but it will still be nice just in case.
Take the output and format it so that it can show something like: "The following files exist in Path 1 and not Path 2," and "The following files exist in both paths but have differences."
Basically, I don't just want an info dump of files to be the output and people end up having to puzzle through it. And like I said, I think the advice I received on how to do it will be good, I'm just having trouble making it work.
Here's the code I have so far:
$Source = #(Get-ChildItem -Recurse -Path \\SERVER\D$\PSTest)
foreach ($file in $Source){
If ($Target = Test-Path #(Get-ChildItem -Recurse -Path \\SERVER\D$\PSTest))
{
$HashResult = (Compare-Object -ReferenceObject $file -DifferenceObject
$Target -Property hash -PassThru).Path
}
else {
$Missing += $file
}
}
Write-Host 'These files have differences.' -ForegroundColor Green
$HashResult
Write-Host 'These files are missing from the target path.' -ForegroundColor
Green
$Missing
When I run that, I don't get any results (other than the text output). Where am I going wrong with this?
Made a few assumptions about the file names and their uniqueness down through the various depths of the source/target folders:
$SourceDir = "C:\\temptest";
$DestDir = "D:\\temptest";
$SourceFiles = #(Get-ChildItem -Recurse -Path $SourceDir);
$DestFiles = #(Get-ChildItem -Recurse -Path $DestDir);
$SourceFileNames = $SourceFiles | % { $_.Name };
$DestFileNames = $DestFiles | % { $_.Name };
$MissingFromDestination = #();
$MissingFromSource = #();
$DifferentFiles = #();
foreach($f in $SourceFiles) {
if (!$DestFileNames.Contains($f.Name)) {
$MissingFromDestination += $f;
} else {
$t = $DestFiles | Where { $_.Name -eq $f.Name };
if ((Get-FileHash $f.FullName).hash -ne (Get-FileHash $t.FullName).hash) {
$DifferentFiles += $f;
}
}
}
foreach($f in $DestFiles) {
if (!$SourceFileNames.Contains($f.Name)) {
$MissingFromSource += $f;
}
}
"
Missing from Destination: "
$MissingFromDestination | % { $_.FullName };
"
Missing from Source: "
$MissingFromSource | % { $_.FullName };
"
Source is Different: "
$DifferentFiles | % { $_.FullName };
This is a bit naive in its approach insofar as it is really only checking file names and ignoring subfolder tree structures. But, hopefully, it will give you enough of a leaping off point.
We have 1 main network share named the below, after the underscore there is 8 locations which are "abc$", "def$", "ghi$", "jkl$", "mno$", "pqr$", "stu$", "vwxyz$".
Depending on the users first letter in their username a folder is created with the which is the users home area.
Example username - AdamB will be put in Networkshare1_abc$.
Example 2 username - EdwardB will be put in Networkshare1_def$
Within this folder are the is a list of all users as a folder
Networkshare1_abc$
Networkshare1_def$
Networkshare1_ghi$
Networkshare1_jkl$
Networkshare1_mno$
Networkshare1_pqr$
Networkshare1_stu$
Networkshare1_vwxy$
I need a script that will
that will loop though only the top folder list the users
check to see if a text file exists and if it does delete it (have this working below)
$Wantedfile = "Networkshare1_stu$\user1\test.txt"
$timeStamp = (Get-Date -Format "dd-MM-yyyy-hh-mm")
$FileName = $timeStamp + ".txt"
if ((Test-Path $Wantedfile$FileName) -eq $false) {
Write-Host "file does not exists"
} elseif ((Test-Path $Wantedfile$FileName) -eq $true) {
Write-Host "file present..removing file"
Remove-Item $Wantedfile$FileName
}
The bit I am struggling with is the loop and how to get it to check each folder in the above locations as streamline as possible.
I am not sure if your files are really named like
"Networkshare1_stu$\user1\test.txt03-21-2017-19-41.txt"
but basically what you need is foreach loop. You need to get all the folders in the top folder. In $directories you will have abc$, def$ etc. folders. Then you will loop through each of them and search for the file using Where-Object.
$nameOfFile = "test.txt"
$fullPathFile = "\\Networkshare1_abc$\user1\test.txt"
$directories = Get-ChildItem "\\Networkshare1" -Directory
foreach($directory in $directories)
{
Write-Host "Searching in $directory.FullName ..."
$files = Get-ChildItem $directory -Recurse | Where-Object{$_.FullName -like "*$nameOfFile"}
# or to use fullPathFile
# $files = Get-ChildItem $directory -Recurse | Where-Object{$_.FullName -eq $fullPathFile}
foreach($file in $files)
{
Write-Host "Removing $file.FullName - continue?"
Read-Host ""
Remove-Item $file -Force
}
}
I am trying to get all files w/in a directory that have the extension ".rtf". I have a working script, but it takes a while, as there is a foreach loop w/in a foreach loop. Is there a faster way to handle this? The goal of the script is to get all files w/in a directory ending in .rtf and use MSWord to Open the file and save it as a ".DOC". The conversion functionality works fine. The issue is with the length of time to search through all of the folders.
Function Convert-Dir($path)
{
$subFolders = get-childitem $path -Recurse | Where-Object {$_.PSIsContainer -eq $True}
if($subFolders)
{
foreach($folder in $subFolders)
{
if($folder.PSisContainer)
{
$Files=Get-ChildItem $folder.fullname -Filter "*.rtf"
$Word=New-Object -ComObject WORD.APPLICATION
if($Files)
{
foreach ($File in $Files)
{
$Doc=$Word.Documents.Open($File.fullname)
$Name=($Doc.name).replace("rtf","doc")
if (Test-Path $Name)
{
} else
{
# Use WORD
$fullName = ($Doc.path + "\" + "Converted_" + $Name)
$Doc.saveas([ref] $fullName, [ref] 0)
$Doc.close()
$fileToRemove = $File.fullName
Remove-Item $fileToRemove
$Word.Quit()
}
}
}
}
}
}
}
I guess the performance is lost by creating a lot of word-instances by calling a word-process in each subfolder. You should should use only one instance of word all the time. Just move the line $Word=New-Object -ComObject WORD.APPLICATION to the top of your function and the line $word.quit() to the very end.
I have a question. I want to copy content of one directory into another and made some progress. But, at the moment I'm stuck because if I can define array of files to exclude I have a problem with array of folders. So the arrays looks like:
$excludeFiles = #('app.config', 'file.exe')
$excludeFolders = #('Logs', 'Reports', 'Backup', 'Output')
It works when there is only one item in $excludeFolders array, but if I add multiple items, it copies all folders without excluding them.
Script I have:
Get-ChildItem -Path $binSolutionFolder -Recurse -Exclude $excludeFiles |
where { $excludeFolders -eq $null -or $_.FullName.Replace($binSolutionFolder, "") -notmatch $excludeFolders } |
Copy-Item -Destination {
if ($_.PSIsContainer) {
Join-Path $deployFolderDir $_.Parent.FullName.Substring($binSolutionFolder.length -1)
}
else {
Join-Path $deployFolderDir $_.FullName.Substring($binSolutionFolder.length -1)
}
} -Force -Exclude $excludeFiles
Where $binSolutionFolder is source and $deployFolderDir is target.
Files work fine, but with folders I've run out of ideas.
-notmatch uses a regex-pattern and not a collection. To match against a collection of words you could use -notin $excludedfolders, but if the path includes 2+ level of folders or just a simple \ then the test would fail.
I would use -notmatch, but first create a regex-pattern that checks all folders at ones. Ex:
$excludeFiles = #('app.config', 'file.exe')
$excludeFolders = #('Logs', 'Reports', 'Backup', 'Output','Desktop')
$excludeFoldersRegex = $excludeFolders -join '|'
Get-ChildItem -Path $binSolutionFolder -Recurse -Exclude $excludeFiles |
where { $_.FullName.Replace($binSolutionFolder, "") -notmatch $excludeFoldersRegex } |
.....
I'm trying to optimize my Powershell Script a little.
I have a lot of log (text) files, that i need to search through the content of, for a specific text entry.
If the entry is found, I need the script to trigger with an inset to an sql databse.
This is what I have for now:
$tidnu = (Get-Date -f dd.MM.yyyy)
$Text = "ERROR MESSAGE STACK"
$PathArray = #()
$NodeName = "SomeName"
$Logfil = "SomeLogFile"
Get-ChildItem $Path -Filter "*ORA11*.log" |
Where-Object { $_.Attributes -ne "Directory"} |
ForEach-Object {
If (Get-Content $_.FullName | Select-String -Pattern $Text)
{
$PathArray += $_.FullName
$cmd.commandtext = "INSERT INTO ErrorTabel (Datotid, Nodename, Logfil, ErrorFound) VALUES('{0}','{1}','{2}','{3}')" -f $tidnu, $NodeName, $Logfil, "Yes"
$cmd.ExecuteNonQuery()
}
else
{
$cmd.commandtext = "INSERT INTO ErrorTabel (Datotid, Nodename, ErrorFound) VALUES('{0}','{1}','{2}')" -f $tidnu, $NodeName, "No"
$cmd.ExecuteNonQuery()
}
}
This is working okay, but when i need to move to another log file name, i have simply made the same code again with different inputs.
What i would like to do, is to use an Array, and a foreach loop, so i could specify all the log files in one array, like:
$LogArray = #(Log1.log, log2.log, log3.log)
And specify all the Nodenames like:
$NodeArray = #(Node1, Node2, Node3)
And then make a foreach loop that will go through the logfiles one by one and insert into the databse, with it's matching nodename every time the loop runs through.
Can someone help me to make this happen? I have the idea on how it should be done, but I can't figure out how to write the code. All help would be much appreciated.
EDIT:
Ok, this is what i have now then, but i'm not sure that it's correct put together. Its giving me some strange results.
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Data Source=PCDK03918;Initial Catalog=Rman;Integrated Security=SSPI;"
$conn.open()
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.connection = $conn
$tidnu = (Get-Date -f dd.MM.yyyy)
$Path = "C:\RMAN"
$Text = "ERROR MESSAGE STACK"
$nodes = #{
'NodeName1' = 'Node1log1.log', 'Node1log2.log', 'Node1log3.log'
'NodeName2' = 'Node2log1.log', 'Node2log2.log'
}
foreach ($NodeName in $nodes.Keys) {
foreach ($Logfil in $nodes[$NodeName]) {
Get-ChildItem $Path -Filter "*.log" |
ForEach-Object {
If (Get-Content $_.FullName | Select-String -Pattern $Text)
{
$cmd.commandtext = "INSERT INTO Error (Datotid, Nodename, Logfil, Error) VALUES('{0}','{1}','{2}','{3}')" -f $tidnu, $NodeName, $Logfil, "Yes"
$cmd.ExecuteNonQuery()
}
else
{
$cmd.commandtext = "INSERT INTO Error (Datotid, Nodename, Logfil, Error) VALUES('{0}','{1}','{2}','{3}')" -f $tidnu, $NodeName, $Logfil, "No"
$cmd.ExecuteNonQuery()
}
}
}
}
$conn.close()
I have created the log files mentioned in $nodes, in the folder, and put the "ERROR MESSAGE STACK" into Node1log1.log and Node1log2.log The rest of the log files are with no "ERROR MESSAGE STACK" inside.
But the result in the database is strange. It says Error = Yes to log files with no "ERROR MESSAGE STACK" inside, and it says Error = No to the same log files some rows down. Plus its inserting double rows and all in all its not doing as intended.
could it be because my
Get-ChildItem $Path -Filter "*.log" |
is wrong by using *.log ?
Or am I simply going completely wrong about this?
EDIT Once more:
Not sure what I was thinking yesterday, but I believe i have solved it now.
Get-ChildItem $Path -Filter "*.log" |
Will of course not work.
Get-ChildItem $Path -Filter $logfil |
Gives much more sense, and now my databse output is looking much more correct.
#Ansgar Wiechers - Thank you for pointing me in the right direction. I learned alot from this.
Consider using a hashtable for this:
$logs = #{
'Log1.log' = 'Node1'
'Log2.log' = 'Node2'
'Log3.log' = 'Node3'
}
That way you can iterate over the logs like this:
foreach ($Logfil in $logs.Keys) {
$NodeName = $logs[$Logfil]
...
}
If you have more than one log file per node name, it would be more efficient to reverse the mapping and store the log file names in an array:
$nodes = #{
'Node1' = 'Log1.log', 'Log2.log', 'Log3.log'
'Node2' = 'Log4.log', 'Log5.log'
}
Then you can process the logfiles with a nested loop like this:
foreach ($NodeName in $nodes.Keys) {
foreach ($Logfil in $nodes[$NodeName]) {
...
}
}
You should be able to fit your pipeline into either loop without further modifications.
Edit: As an optimization you could do something like this to avoid needlessly fetchin logs with each iteration of the outer loop:
$logs = Get-ChildItem $Path -Filter '*.log'
foreach ($NodeName in $nodes.Keys) {
$logs | ? { $nodes[$NodeName] -contains $_.Name } | % {
...
}
}