What I like to do is pass the $sContractNumbers variable to the loop I have below which essentially pieces two csv files together based on the SQL queries.
I'm using the block below to get a value from an excel spreadsheet. Something that will be updated by a different user. The cell will always be static but the data in the cell will change in size so I have to use the IN clause.
My variable value looks like so.
$sContractNumbers = 'abc123','abc456','abc789','abc112','abc345'
$xl = New-Object -COM "Excel.Application"
$xl.Visible = $true
$wb = $xl.Workbooks.Open("C:\Dev\Blah\ManualContracts.xlsx")
$ws = $wb.Sheets.Item(1)
#Looking up a value in one column and assigning the corresponding value from another column to a variable could be done like this:
for ($i = 0; $i -le 1; $i++) {
if ( $ws.Cells.Item(1, 2).Text -eq $ColumnHeader ) {
$i = $i++;
$sContractNumbers = $ws.Cells.Item(2, 2).Value
#$sContractNumber
break
}
}
$wb.Close()
$xl.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
$sContractNumbers
Prior to adding this piece I was just copying and pasting my list of contracts in both queries.
Currently the error I'm getting is the following. I don't believe the loop is picking up on the variable. I've tried using AddWithValue but I don't think I'm placing it correctly, which is why its not listed. Fairly new to powershell but know a little bit of T-SQL. I think its a simple question but I cannot fully understand what I need to correct it since I'm noob. Be gentle...
$DetailContent[1] = "{0}`r`n{1}" -f $HeadeDetail, $DetailContent[1]
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot index into a null array.
Function Run-Query
{
param([string[]]$queries,[string[]]$sheetnames)
Begin
{
$SQLServer = 'server'
$Database = 'warehouse'
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $SQLServer; Database = $Database; Integrated Security = True"
$FileNameDate = Get-Date -f 'yyyyMMdd'
}#End Begin
Process
{
# Loop through each query
For($i = 0; $i -lt $queries.count; $i++)
{
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
$SqlCmd.CommandText = $queries[$i]
$SqlCmd.Connection = $SqlConnection
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$DataSet.Tables[0] | Export-CSV -NoTypeInformation -Path "C:\Dev\blah\HeaderDetail\$($sheetnames[$i])_$FileNameDate-000.csv" -Delimiter '|'
}
}#End Process
End
{
$SqlConnection.Close()
}
}#End function run-query.
$queries = #()
$queries += #'
SET NOCOUNT ON
SET ANSI_WARNINGS OFF
/*FE Header*/
SELECT [sContractNumber] as ContractNumber,
into #Temp
FROM C
INNER JOIN D ON C.Id=D.iId
WHERE c.sContractNumber in ('$sContractNumbers')
order by sContractNumber
declare #TotalNewContracts int = 0
declare #TotalCanContracts int = 0
declare #TotalExpContracts int = 0
set #TotalNewContracts = (select COUNT(fe.ContractNumber) from #temp fe where Record_Type = 'P')
set #TotalCanContracts = (select COUNT(fe.ContractNumber) from #temp fe where Record_Type = 'C')
select
count(contractnumber) as 'Total Number of All Contracts',
FROM #temp ;
drop table #Temp;
'#
$queries += #'
SET NOCOUNT ON
SET ANSI_WARNINGS OFF
/*FE Header*/
SELECT [sContractNumber] as ContractNumber,
into #Table
FROM [pcmi_warranty_custom_twsi].[dbo].[Contract_Header] C
INNER JOIN [pcmi_warranty_custom_twsi].[dbo].[Dealer_Header] D ON C.iDealerId=D.iId
WHERE c.sContractNumber in ('$sContractNumbers')
order by sContractNumber
SELECT ContractNumber,
FROM #temp FE;
drop table #Temp;
'#
$sheetnames = #()
$sheetnames += 'Header'
$sheetnames += 'Details'
#FileName
$FileNameDate = Get-Date -f 'yyyyMMdd'
Run-Query -queries $queries -sheetnames $sheetnames
#Removes Double Quotes from File
(Get-Content C:\Dev\blah\HeaderDetail\Header_$FileNameDate-000.csv) | % {$_ -replace '"', ''} | out-file -FilePath C:\Dev\blah\Header\Header_$FileNameDate-000.csv -Force -Encoding ascii
(Get-Content C:\Dev\blah\HeaderDetail\Details_$FileNameDate-000.csv) | % {$_ -replace '"', ''} | out-file -FilePath C:\Dev\blah\Detail\Details_$FileNameDate-000.csv -Force -Encoding ascii
#Add Double Pipes as Delimter
(Get-Content C:\Dev\blah\Header\Header_$FileNameDate-000.csv) | % {$_ -replace "\|", "||"} | out-file -FilePath C:\Dev\blah\Header\Header_$FileNameDate-000.csv -Force -Encoding ascii
(Get-Content C:\Dev\blah\Detail\Details_$FileNameDate-000.csv) | % {$_ -replace "\|", "||"} | out-file -FilePath C:\Dev\blah\Detail\Details_$FileNameDate-000.csv -Force -Encoding ascii
#Add Header Detail Row to Detail File
#Header Path
$HeaderPath = "C:\Dev\blah\Header\Header_$FileNameDate-000.csv"
#Detail Path
$DetailsPath = "C:\Dev\blah\Detail\Details_$FileNameDate-000.csv"
#Gets second row of header file and sets it as a varaible
$HeadeDetail = Get-Content $HeaderPath -TotalCount 2 | Select-Object -Last 1;
#print the header detail row
$HeadeDetail
#Get Detail File content
$DetailContent = Get-Content -Path $DetailsPath
#Add Header Detail row to Detail file
$DetailContent[1] = "{0}`r`n{1}" -f $HeadeDetail, $DetailContent[1]
#Save Detail File
$DetailContent | Set-Content "C:\Dev\blah\blah$FileNameDate-000.csv" -Force -Encoding ascii
#Set the file name
$SourceFile = "C:\Dev\blah\blah$FileNameDate-000.csv"
$DestinationFolder = 'C:\Dev\blah'
$HeaderFile = "C:\Dev\blah\Header\Header_$FileNameDate-000.csv"
$DetailFile = "C:\Dev\blah\Detail\Details_$FileNameDate-000.csv"
$HDestinationFolder = 'C:\Dev\blah\Header'
$DDestinationFolder = 'C:\Dev\blah\Detail'
if (Test-Path $SourceFile)
{
$latest = Get-ChildItem -Path $DestinationFolder| Sort-Object Name -Descending | Select-Object -First 1
#split the latest filename, increment the number, then re-assemble new filename:
$newFileName = $latest.BaseName.Split('-')[0] + "-" + ([int]$latest.BaseName.Split('-')[1] + 1).ToString().PadLeft(3,"0") + $latest.Extension
Move-Item -path $SourceFile -destination $DestinationFolder"\"$newFileName
}
if (Test-Path $HeaderFile)
{
$latest = Get-ChildItem -Path $HDestinationFolder| Sort-Object Name -Descending | Select-Object -First 1
#split the latest filename, increment the number, then re-assemble new filename:
$newFileName = $latest.BaseName.Split('-')[0] + "-" + ([int]$latest.BaseName.Split('-')[1] + 1).ToString().PadLeft(3,"0") + $latest.Extension
Move-Item -path $HeaderFile -destination $HDestinationFolder"\"$newFileName
}
if (Test-Path $DetailFile)
{
$latest = Get-ChildItem -Path $DDestinationFolder| Sort-Object Name -Descending | Select-Object -First 1
#split the latest filename, increment the number, then re-assemble new filename:
$newFileName = $latest.BaseName.Split('-')[0] + "-" + ([int]$latest.BaseName.Split('-')[1] + 1).ToString().PadLeft(3,"0") + $latest.Extension
Move-Item -path $DetailFile -destination $DDestinationFolder"\"$newFileName
}
#Creates backup folder with corresponding date and places the file
$FolderName = Get-Date -f 'MMdd'
$FolderToCreate = "C:\Dev\blah\$FolderName"
if (!(Test-Path $FolderToCreate -PathType Container)) {
New-Item -ItemType Directory -Force -Path $FolderToCreate
}
Copy-Item -Path "$DestinationFolder\TWFE*.csv" -Destination $FoldertoCreate -force;
$ODrive = 'O:\blah\blah\blah'
$FolderToCopy = "O:\blah\blah\blah\$FolderName"
$LatestFile = Get-ChildItem -Path "$DestinationFolder\$FolderName" -Name TWFE*.csv | Sort-Object -Descending | Select-Object -First 1
if (!(Test-Path $FolderToCopy -PathType Container)) {
Copy-Item -Path "$DestinationFolder\$FolderName" -Destination $FolderToCopy -Recurse -Force -ErrorAction Continue
}
if ((Test-Path $FolderToCopy -PathType Container)) {
Copy-Item -Path $LatestFile -Destination $FolderToCopy -Recurse -Force -ErrorAction Continue
}
Related
I have a list of .txt files inside a folder with the following naming: firstname[dot]lastname[underscore]nationality[underscore]date.txt
Examples:
charles.pearson_FR_08-11-2021.txt
lena.smith_GB_11-12-2019.txt
paul.miller_XX_08-03-2017.txt
I would like to replace the filenames of the files that have a 'XX' as nationality by the nationality coming from a lookup table.
What I have tried so far:
$sqlcn = New-Object System.Data.SqlClient.SqlConnection
$sqlcn.ConnectionString = "MyData; MyCatalog;"
$sqlcn.Open()
$sqlcmd = $sqlcn.CreateCommand()
$query = "select username, nationality from mytable"
$sqlcmd.CommandText = $query
$adp = New-Object System.Data.SqlClient.SqlDataAdapter $sqlcmd
$data = New-Object System.Data.DataSet
$adp.Fill($data) | Out-Null
# create a lookup Hashtable
$lookup = #{}
# build up the $lookup hash
foreach ($item in $data.Tables) {
$lookup[$item.username] = $item.nationality
}
[string]$rootPathForFiles = Join-Path -Path $env:USERPROFILE -ChildPath 'Desktop\testFolder'
[string[]]$listOfFilesToRename = Get-ChildItem -Path $rootPathForFiles -Filter '*_XX_*.txt' | Select-Object -ExpandProperty FullName
$listOfFilesToRename | ForEach-Object {
#get the filename without the directory
[string]$newName = Split-Path -Path $_ -Leaf
#NEEDED: Lookup on the hashtable and rename the file
}
It correctly lists all .txt files that have _XX_ in the name but I miss the lookup on the hashtable and the renaming.
For information, $data looks like this:
username nationality
-------- -----------
lena.jeankins
paul.mirabel GB
mickael.mudik GB
paul.miller FR
...
What you can do here is to not just select the files FullName, but instead keep the complete FileInfo object and use the .BaseName and .Extensions properties like this:
$rootPathForFiles = Join-Path -Path $env:USERPROFILE -ChildPath 'Desktop\testFolder'
(Get-ChildItem -Path $rootPathForFiles -Filter '*.*_XX_*.txt' -File) | ForEach-Object {
$userName,$nationality,$date = $_.BaseName -split '_'
if ($lookup.ContainsKey($userName)) {
$newName = '{0}_{1}_{2}{3}' -f $userName, $lookup[$username], $date, $_.Extension
$_ | Rename-Item -NewName $newName
}
else {
Write-Warning "Could not retrieve nationality for user $userName"
}
}
The purpose of this code is to transfer files from one location to another and to log whether the transfer was a success or a failure.
Everything works except I am having issues with the log. I want the log to be in CSV format and there to be 3 columns: success/failure, from location, and to location. This is outputting the results all into rows with one column.
I've tried the Export-Csv option but that looks for objects/properties so only displays the length(I have strings too). Add-content works but there is only one column. Any suggestions?
#LOCATION OF CSV
$csv = Import-Csv C:\test2.csv
#SPECIFY DATE (EXAMPLE-DELETE FILES > 7 YEARS. 7 YEARS=2555 DAYS SO YOU WOULD ENTER "-2555" BELOW)
$Daysback = "-1"
#FILE DESTINATION
$storagedestination = "C:\Users\mark\Documents\Test2"
#LOG LOCATION
$loglocation = "C:\Users\mark\Documents\filetransferlog.csv"
$s = "SUCCESS"
$f = "FAIL"
$CurrentDate = Get-Date
foreach ($line in $csv) {
$Path = $line | Select-Object -ExpandProperty FullName
$DatetoDelete = $CurrentDate.AddDays($DaysBack)
$objects = Get-ChildItem $Path -Recurse | Select-Object FullName, CreationTime, LastWriteTime, LastAccessTime | Where-Object { $_.LastWriteTime -lt $DatetoDelete }
foreach ($object in $objects) {
try
{
$sourceRoot = $object | Select-Object -ExpandProperty FullName
Copy-Item -Path $sourceRoot -Recurse -Destination $storagedestination
Remove-Item -Path $sourceRoot -Force -Recurse
$temp = $s, $sourceRoot, $storagedestination
$temp | add-content $loglocation
}
catch
{
$temp2 = $f, $sourceRoot, $storagedestination
$temp2 | add-content $loglocation
}
}
}
All your | Select-Object -ExpandProperty are superfluous, simply attach the property name to the variable name => $Path = $line.FullName
Why calculate $DatetoDelete inside the foreach every time?
Output the success/fail to a [PSCustomObject] and gather them in a variable assigned directly to the foreach.
Untested:
$csv = Import-Csv C:\test2.csv
$Daysback = "-1"
$destination = "C:\Users\mark\Documents\Test2"
$loglocation = "C:\Users\mark\Documents\filetransferlog.csv"
$s = "SUCCESS"
$f = "FAIL"
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.Date.AddDays($DaysBack)
$Log = foreach ($line in $csv) {
$objects = Get-ChildItem $line.FullName -Rec |
Where-Object LastWriteTime -lt $DatetoDelete
foreach ($object in $objects) {
$Result = $s
$sourceRoot = $object.FullName
try {
Copy-Item -Path $sourceRoot -Recurse -Destination $destination
Remove-Item -Path $sourceRoot -Recurse -Force
} catch {
$Result = $f
}
[PSCustomObject]#{
'Success/Fail' = $Result
Source = $sourceRoot
Destination = $destination
}
}
}
$Log | Export-Csv $loglocation -NoTypeInformation
Afternoon All,
I need to run a search across all of our servers.
I have the list of servers in a text document and a list of keywords in another
$Servers = get-content -path 'C:\support\Server Search\Server Test.txt'
$Keywords = get-content -path "C:\Support\Server Search\Keyword Test.txt"
Foreach ($Server in $Servers){
Foreach ($Keyword in $Keywords){
Get-ChildItem "$Server" -Recurse | Where-Object {$_.Name -like "$Keyword"}
$i++
Write-Host "$found: $i - Current $ $_"
New-Object -TypeName PSCustomObject -Property #{
Directory = $_.Directory
Name = $_.Name
Length = $_.Length /1024
CreationTime = $_.CreationTime
LastWriteTime = $_.LastWriteTime
LastAccessTime = $_.LastAccessTime}|
select Directory,Name,Length,CreationTime,LastWriteTime,LastAccessTime |
Export-Csv "C:\support\server search\$Server.csv" -Append -NoTypeInformation
}}
$i = 0
Is there a way to indicate when a Keyword has been located and total keywords found? I feel like I need to change this Line but I cannot fathom what I would actually put, I've tried $Keywords but that just changes keyword everytime the directory changes
$i++
Write-Host "$found: $i - Current $ $_"
I'm assuming your $server is set up something like "\\servername\c$\"
when a Keyword has been located and total keywords found:
$Servers = get-content -path 'C:\support\Server Search\Server Test.txt'
$Keywords = get-content -path "C:\Support\Server Search\Keyword Test.txt"
$num = 0 #Total Keyword files Found
Foreach ($Server in $Servers){
Foreach ($Keyword in $Keywords){
#Keyword found Check
$Found = Get-ChildItem -Path "$Server" -Recurse -Include "$Keyword"
if($Found){
Foreach($File in $Found){
$num++ #increment num of keyword files found by 1
Write-Host "found: $num - $File"
New-Object -TypeName PSCustomObject -Property #{
Directory = $File.Directory
Name = $File.Name
Length = $File.Length /1024
CreationTime = $File.CreationTime
LastWriteTime = $File.LastWriteTime
LastAccessTime = $File.LastAccessTime}|
select Directory,Name,Length,CreationTime,LastWriteTime,LastAccessTime |
Export-Csv "C:\support\server search\$Server.csv" -Append -NoTypeInformation
}
}
}
}
Please let me know if this helps you progress. I can assist further if requested.
Got this script running. Nearly completed my mission to print attachments from it that land in a specific subfolder of outlook
$OutputFolder = 'C:\tests';
$outlook = New-Object -ComObject Outlook.Application;
$olFolderInbox = 6;
$ns = $outlook.GetNameSpace("MAPI");
$inbox = $ns.GetDefaultFolder($olFolderInbox);
$inbox.Folders `
| ? Name -eq 'colour' `
| % Items `
| % Attachments `
| % {
$OutputFileName = Join-Path -Path $OutputFolder -ChildPath $_.FileName;
if (Test-Path $OutputFileName) {
$FileDirectoryName = [System.IO.Path]::GetDirectoryName($OutputFileName);
$FileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($OutputFileName);
$FileExtension = [System.IO.Path]::GetExtension($OutputFileName);
for ($i = 2; Test-Path $OutputFileName; $i++) {
$OutputFileName = "{0} ({1}){2}" -f (Join-Path -Path $FileDirectoryName -ChildPath $FileNameWithoutExtension), $i, $FileExtension;
}
}
Write-Host $OutputFileName;
$_.SaveAsFile($OutputFileName)
}
Remove-Item -Path C:\tests\*.jpg
Dir C:\tests\ | Out-Printer -name xerox-b8
Remove-Item -Path C:\tests\*.*
when i try to pipe the objects to print i am getting XML printing out, or just the directory contents
I have tried:
select-object (wrong)
get-childitem (wrong)
DIR C:\tests\*.* (only returns directory listing printout)
These either return a load of XML rubbish or just a directory listing,
How can i pipe the contents of a folder to a printer using powershell, surely this can be done
I am working on a PS script to unzip all files in a directory, then create a .CSV index file based on the full file path of each file, and keywords pulled from the parts of the file name.
E.g.
Directory contains: file1.zip, file2.zip, etc.
Extract all to a single directory: file1_server_20150830,
file1_server2_20150831, file2_server_20150829 etc.
Files are binary (file type shows "File" in Windows, no extension)
Create index.csv using full path and parts of file names. File names use underscores as shown:
x:\folder\file1_server_20150830,server,20150830
x:\folder\file1_server2_20150831,server2,20150831
x:\folder\file2_server_20150829,server,20150831 ...
I am a novice PS scripter, so what I have so far is below, commented lines are what I have been swapping in and out and tweaking to try and build my index file.
$path = "X:\backup\test\source"
$dest = “X:\backup\test\import”
$shell_app= New-Object -com shell.application
$files = Get-ChildItem -Path $path -filter *.zip -recurse
foreach($file in $files) {
$zip_file = $shell_app.namespace($file.FullName)
$copyHere = $shell_app.namespace($dest)
$copyHere.Copyhere($zip_file.items())
}
Get-ChildItem -Path $dest | Get-ChildItem -Path $dest | ForEach-Object { $_.BaseName -Replace '[_]', ',' -Replace ' ', '' -Replace 'index', '' } |
Out-File 'X:\backup\test\import\index.txt'
#Get-childItem 'X:\backup\test\import\index.txt' | ForEach {
#(Get-Content $_ | ForEach {$_ -replace '21148965A', 'X:\backup\test\import\21148965A'}) | Set-Content $_}
#$index2 = {Get-ChildItem -Path $dest | ForEach-Object { $_.BaseName -Replace '[_]', ',' -Replace ' ', '' -Replace 'import', '' }}
#Get-ChildItem -Path $dest | Select-Object DirectoryName, $index2 | Export-Csv -Path 'X:\backup\test\import\index.txt' -NoTypeInformation
#Out-File 'X:\backup\test\import\index.txt'
#Get-ChildItem -Path $dest | ForEach-Object { $_.BaseName -Replace '[_]', ',' -Replace ' ', '' -Replace 'import', '' } | Out-File 'X:\backup\test\import\index.txt'
Great suggestion from another forum, seems to be working for what I need:
$path = 'X:\backup\test\source'
$dest = 'X:\backup\test\import'
$shell_app= New-Object -com shell.application
$files = Get-ChildItem -Path $path -filter *.zip -recurse
foreach($file in $files) {
$zip_file = $shell_app.namespace($file.FullName)
$copyHere = $shell_app.namespace($dest)
$copyHere.Copyhere($zip_file.items())
}
$tabName = "Results"
$table = New-Object system.Data.DataTable “$tabName”
$col1 = New-Object system.Data.DataColumn Folder,([string])
$col2 = New-Object system.Data.DataColumn FileName, ([string])
$table.columns.add($col1)
$table.columns.add($col2)
gci $dest | % {
$base=$_.BaseName -replace '[_]', ',' -Replace ' ', '' -Replace 'index', ''
$folder = $_.DirectoryName
$row = $table.NewRow()
$row.Folder = $folder
$row.FileName = $base
$table.Rows.Add($row)
}
$table | export-csv $dest\index.csv -noType