How do I check if the copy was successful before the script goes to the next command?
$src_dir_local = 'D:\temp\tobemoved\'
$dst_dir_local = 'D:\temp\moved\'
$log_dir = 'D:\temp\log\'
$log_file = 'backup.log'
$ofs_char = "`n"
$curr_date = Get-Date -UFormat '%Y-%m-%d'
$curr_date_time = Get-Date
$s3_bucket = 's3://mybucket/'
$s3_storage_class = 'STANDARD_IA'
$files = Get-ChildItem $src_dir_local
write-output $src_dir_local + $file + $curr_date
write-output $s3_command
aws s3 ls
write-output 'looping through files....'
foreach($f in $files){
$outputfilename = $f.Name
$s3_move_command = 'time aws s3 cp --quiet' + ($src_dir_local + $outputfilename + ' ' + $s3_bucket + $curr_date + '/' + $outputfilename + ' --storage-class ' + $s3_storage_class)
write-output $outputfile
write-output 'Start process'
Invoke-Expression $s3_move_command
move-item -path ($src_dir_local + $outputfilename) -destination ($dst_dir_local + '_mvd_' + $outputfilename) -whatif
write-output 'End process'
write-output 'Start moving process'
$log_message = ($ofs_char + 'File moved ' + $outputfile + ' ' + $((Get-Date).ToString()))
if(Test-Path ($log_dir + $log_file)){
Add-Content ($log_dir + $log_file) $log_message
}else{
New-Item -path $log_dir -name $log_file -type 'file' -value 'Initial log '
Add-Content ($log_dir + $log_file) $log_message
}
}
In general, you would write:
aws s3 cp $src $dst
If ($lastexitcode -eq 0) {
...
} Else {
...
}
See the docs here.
If you must use Invoke-Expression, then see the linked Stack Overflow answer.
Two issues I experience are,
It does the job but throws the error shown below.
The notification doesn't fire, the condition is not met at all.
gpg2.exe : gpg: encrypted with 2048-bit RSA key, ID D9A0AD5F, created
2017-07-04
At C:\Scripts\FinanceGPGDecryptor.ps1:24 char:5
+ & <<<< $gpg_prog --batch --yes --passphrase "$gpg_p" -r "$gpg_r" -o "$out_file" -d "$in_file"
+ CategoryInfo : NotSpecified: (gpg: encrypted ...ated 2017-07-04:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
"key_id>"
# Variables
$gpg_prog = "C:\Program Files (x86)\GNU\GnuPG\pub\gpg2.exe"
$sFolder = "J:\Receive\"
$dFolder = "J:\Receive\Decrypted\"
$aFolder = "J:\Receive\Archived\"
$Log = "J:\Receive\decrypt.log"
$gpg_p = "****"
$gpg_r = "key_id"
$recipients = #("alias#company.com")
$date = date;
Add-Content $Log $date;
Set-Location J:\
# gpg wrapper
function gpg_me {
$in_file = $sFolder + $args[0] + ".pgp"
$out_file = $dFolder + $args[0] + ".txt"
#Write-Host $in_file " | " $out_file
& $gpg_prog --batch --yes --passphrase "$gpg_p" -r "$gpg_r" -o "$out_file" -d "$in_file"
if (!$LastExitCode) {
Add-Content $Log "Inbound file: $in_file | Outbound file: $out_file";
Move-Item -Path $in_file -Destination $aFolder -force
#echo "all good" $LastExitCode
}
}
# Loop thru current directory.
$items = Get-ChildItem -Path $sFolder
foreach ($item in $items) {
#if the item is NOT a directory, then process it.
if ($item.Attributes -ne "Directory") {
#Write-Host "file found:" $item
if ($Output = $item -like "*.pgp") {
#Write-Host "Decrypting new file " $item "'" $Output
gpg_me $item.BaseName
} else {
# // File does not exist
# Write-Host $item.Name " is not a file for decrypting:"
}
}
}
Add-Content $Log "`n **********`n";
Write-Host "LastExitCode:" $LastExitCode
Write-Host "Output:" $Output
if ($Output -and !$LastExitCode) {
Send-MailMessage -From "noreply#compnay.com" -SmtpServer smtp.company.com -To "$recipients" -Subject "file received and decrypted" -Body "Decrypted file can be found at $dFolder" -Attachment $Log;
} else{
}
I'm working on a script to rename files based on EXIF data.
param([string]$path)
# http://blogs.technet.com/b/jamesone/archive/2007/07/13/exploring-photographic-exif-data-using-powershell-of-course.aspx
[reflection.assembly]::loadfile( "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Drawing.dll") | out-null
function MakeString {
$s=""
for ($i=0 ; $i -le $args[0].value.length; $i ++) {
$s = $s + [char]$args[0].value[$i]
}
return $s
}
$files = Get-ChildItem -Path $path
foreach ($file in $files) {
if ($file.Extension -ne ".jpg") { continue }
if ($file.Name -match "^(\d+)-(\d+)-(\d+)") { continue }
$exif = New-Object -TypeName system.drawing.bitmap -ArgumentList $file.FullName
$captureDate = MakeString $exif.GetPropertyItem(36867)
$captureDate = ($captureDate -replace ":", '-').Substring(0,19)
$newFilename = $captureDate + " " + $file.Name.Trim()
$file.Name + " -> " + $newFilename
$file |Rename-Item -NewName $newFilename
}
Reading the date from EXIF is no problem, but when I try to rename the file I get this error message:
Rename-Item : The process cannot access the file because it is being used by another process.
At D:\Norwegen\RenamePhotos.ps1:25 char:12
+ $file |Rename-Item -NewName $newFilename
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (D:\Norwegen\P1270465 (1920x1433).jpg:String) [Rename-Item], IOException
+ FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand
When I monitor the directory in ProcMon I can see that the files are closed rather late:
(look at the highlighted line, it's from an earlier file in the middle of the entries from the file currently being processed)
So, how can I close the file (which is probably still open from the EXIF read) so I can rename it?
What I already tried to close the open file:
Remove-Variable exif
$file.Close()
Since you only read from the the file, then a call to Dispose() should do the trick. Ex.
foreach ($file in $files) {
if ($file.Extension -ne ".jpg") { continue }
if ($file.Name -match "^(\d+)-(\d+)-(\d+)") { continue }
$exif = New-Object -TypeName system.drawing.bitmap -ArgumentList $file.FullName
$captureDate = MakeString $exif.GetPropertyItem(36867)
#Disposing object as soon as possible
$exif.Dispose()
$captureDate = ($captureDate -replace ":", '-').Substring(0,19)
$newFilename = $captureDate + " " + $file.Name.Trim()
$file.Name + " -> " + $newFilename
$file |Rename-Item -NewName $newFilename
}
I have a script that obtains that gathers information about a computer then outputs it to a csv file. You can see I have tried multiple approaches to this issue and cannot quite get any of them to work. A fix to this, or a completely different solution would be welcome.
#Objective is to create a csv file with
# "hostname of public IP","public IP","machine name",date,time-24hour
# for example: (note no header in file)
# "97-94-177-139.dhcp.ftwo.tx.charter.com","97.94.177.139","IT-BHOLLING",8/23/2014,06:52:35
# quotes around text fields are an optional objective (helps with some csv import engines)
# some approaches require that the path c:\IP\Working exists (or change lines 46 & 47
# Change line 61 to try each output method
#Variables
# I am defining website url in a variable
$url = "http://checkip.dyndns.com"
# Creating a new .Net Object names a System.Net.Webclient
$webclient = New-Object System.Net.WebClient
# In this new webdownlader object we are telling $webclient to download the url $url
#get public IP address
$Ip = $webclient.DownloadString($url)
# Just a simple text manuplation to get the ipadress form downloaded URL
# If you want to know what it contain try to see the variable $Ip
#$Ip2 = $Ip.ToString()
#$ip3 = $Ip2.Split(" ")
#$ip4 = $ip3[5]
#$ip5 = $ip4.replace("</body>","")
#-- or - do this
$FinalIPAddress = $Ip.ToString().Split(" ")[5].replace("</body>","").replace("</html>","")
#get machine name
$MNme = $env:computername
#Get Hostname from IP address
try {
$Resolved = [system.net.dns]::GetHostEntry($FinalIPAddress)
}
catch {
$Resolved = ((&nslookup $FinalIPAddress)|where {$_ -match "^Name:"}).split(':')[1].trim()
}
#$Qstring = "select * from win32_pingstatus where address=" + """$FinalIPAddress""" + " AND ResolveAddressNames=True"
#$Qstring = "'" + $Qstring + "'"
# $AName = Get-WmiObject -Query $Qstring |
# select ProtocolAddressResolved | ConvertTo-Csv
#$AName = Get-WMIObject -q 'select * from win32_pingstatus where address="97.93.177.138" AND ResolveAddressNames=True'|
# select ProtocolAddressResolved | ConvertTo-Csv
#$AName[2..2].ToString()
$FinalIPAddress = $FinalIPAddress.Replace("`r`n","")
#get date
$GDte = Get-Date -format("G")
$GTme = Get-Date -format("u")
$infile = "C:\IP\Working\" + $MNme + ".txt"
$outfile = "C:\IP\Working\" + $MNme + ".csv"
$Dsplit = $GDte.split(" ")
$Dte = $Dsplit[0]
$Tsplit = $GTme.split(" ")
$Tme = $Tsplit[1].replace("Z","")
#remove previous files
If (Test-Path $infile){
Remove-Item $infile
}
If (Test-Path $outfile){
Remove-Item $outfile
}
#Write accumulated data to a file; modify $CMethod to test each alternate approach to creating csv file
$CMethod = "D"
if ($CMethod -eq "A") {
#this method produces a file that works with Access but not with Excel. Excel sees it as unicode-text
$content = """$Resolved""" + "," + """$FinalIPAddress""" + "," + """$MNme""" + "," + $Dte + "," + $Tme
$content > $outfile
}
if ($CMethod -eq "B") {
#This method produces an empty csv file, with a few tweaks it procudes a file with Length info instead of results
#tried with quotes
$content = """$Resolved""" + " " + """$FinalIPAddress""" + " " + """$MNme""" + " " + $Dte + " " + $Tme
#also tried without quotes
#$content = $Resolved + " " + $FinalIPAddress + " " + $MNme + " " + $Dte + " " + $Tme
$content > $infile
import-csv $infile -delimiter " " | export-csv -NoTypeInformation $outfile
}
If ($CMethod -eq "C") {
$content = """$Resolved""" + " " + """$FinalIPAddress""" + " " + """$MNme""" + " " + $Dte + " " + $Tme
add-content $infile $content
import-csv $infile -delimiter " " | export-csv -NoTypeInformation $outfile
}
if ($CMethod -eq "D") {
#Yet another method, convert to object first
#$content = """$Resolved""" + " " + """$FinalIPAddress""" + " " + """$MNme""" + " " + $Dte + " " + $Tme
#$content = """$Resolved""" + "," + """$FinalIPAddress""" + "," + """$MNme""" + "," + $Dte + "," + $Tme
$content = $Resolved + "," + $FinalIPAddress + "," + $MNme + "," + $Dte + "," + $Tme
$psObject = $null
$psObject = New-Object psobject
$Csplit = $content.Split(",")
#alternate approaches to converting PSobjecdt to csv
foreach($o in $Csplit)
{
Add-Member -InputObject $psobject -MemberType noteproperty -Name $o -Value $o -PassThru
}
$psObject | Export-Csv $outfile -NoTypeInformation
#Add-Member -InputObject $psobject -MemberType noteproperty -Name $Csplit -Value $Csplit
#$psObject | Export-Csv $outfile -NoTypeInformation
}
#echo to console
"Mehtod Choosen = " + $CMethod
$content
$Csplit
"end of the script....."
You can use Add-Content -Path "FilePath" -Value "$Resolved,$FinalIPAddress,$MNme,$Dte,$Tme".
Then you have no header and the data seperated with ",".
I would suggest letting PowerShell do the CSV creation for you. All that you need to do for that is to create a custom object with the properties you're after, then you can use the Export-Csv or ConvertTo-Csv cmdlets. You can also control the encoding used since it sounds like you might be having some encoding issues with the programs that are consuming your CSV. I've modified your code below to create a PSObject. See if this works for you:
$url = "http://checkip.dyndns.com"
$Now = Get-Date
$webclient = New-Object System.Net.WebClient
$ErrorString = "<ERROR>"
$CsvEncoding = "ASCII" # Any encoding from [System.Text.Encoding] should work
$outfile = "C:\IP\Working\{0}.csv" -f $env:computername
If (Test-Path $outfile){
Remove-Item $outfile
}
try {
$Ip = $null
$Ip = $webclient.DownloadString($url)
}
catch {
Write-Warning ("Error getting IP address: {0}" -f $_.Exception.Message)
}
if ($Ip -match ".*IP Address:\s*((\d{1,3}\.){3}\d{1,3}).*") {
$FinalIpAddress = $matches[1]
#Get Hostname from IP address
try {
$Resolved = [system.net.dns]::GetHostEntry($FinalIpAddress) | select -ExpandProperty HostName
}
catch {
try {
$Resolved = ((&nslookup $FinalIpAddress)|where {$_ -match "^Name:"}).split(':')[1].trim()
}
catch {
$Resolved = $ErrorString
Write-Warning ("Error resolving IP address '$FinalIpAddress': {0}" -f $_.Exception.Message)
}
}
}
else {
$FinalIpAddress = $ErrorString
$Resolved = $ErrorString
}
# This won't work as is in PSv2, but a simple mod would fix it:
$ReturnObject = [PSCustomObject] #{
Resolved = $Resolved
FinalIpAddress = $FinalIpAddress
MNme = $env:computername
Dte = $Now.ToShortDateString()
Tme = $Now.ToString("HH:mm:ss")
}
# At this point, you can let PS do all of the work to create a CSV
# Create normal CSV with encoding defined above:
$ReturnObject | Export-Csv -Path $outfile -Encoding $CsvEncoding -NoTypeInformation
# Create a CSV w/o header (this line will actually append a second line to $outfile):
$ReturnObject | ConvertTo-Csv -NoTypeInformation | select -Skip 1 | Out-File -FilePath $outfile -Encoding $CsvEncoding -Append
I want to take a text file with usernames, and then search a specific location (UNC path) and return any matches found, outputting them to a log file:
#Searches target folder for all folders matching input
$start = (get-date -uformat "%Y-%m-%d_%H%M")
$defaultLogFileName = "folder_matcher" + $start + ".log"
#Log file header
$header = #()
$header += "=============================="
$header += "Search results"
$header += ""
$header += "Execution Start: " + (get-date -uformat "%Y-%m-%d %H%M") + ""
$header += ""
#Get the logfile location
do
{
$logdir = Read-Host "Enter log directory (or press Enter for default c:\)"
if ($logdir -eq "")
{$logfile = ("c:\" + $defaultLogFileName); break;}
if(Test-Path $logdir)
{$logfile += ($logdir + "\" + $defaultLogFileName); break;}
Write-Host -ForegroundColor Red "Directory does not exist"
} while (!(Test-Path $logfile))
$SourceFile = Read-Host "Enter file path"
$SearchValue = Read-host "Enter target directory to sweep"
$header | Out-File -FilePath $logfile
foreach($user in $sourcefile){
Get-ChildItem $SearchValue -filter $user | Out-file -Append -FilePath $logfile
}
When I attempt to use Get-ChildItem in this loop, this is the result:
Get-ChildItem : Second path fragment must not be a drive or UNC name.
Parameter name: path2
At \\erebus\erebus_users$\rraymond1\ps\searchandmatch.ps1:32 char:14
+ Get-ChildItem <<<< $SearchValue -filter $user | Out-file -Append -FilePath $logfile
+ CategoryInfo : InvalidArgument: (\\harvard\tsprofiles$:String)
[Get-ChildItem], ArgumentException + FullyQualifiedErrorId DirArgumentError,Microsoft.PowerShell.Commands.GetChildItemCommand
I have tried replacing the variables with fixed values (even mapping the UNC path locally and trying to run it that way), and the problem remains. How can I fix it?