Good morning!
I have made it to the last (and rather pivotal) stage in my script, which is looping to delete files from a directory. I'm not going to pretend I'm knowledgeable at Powershell (far from it), so I'm sort-of chopping up blocks of code I find on the net, improvising and hoping it works.
I'm hoping someone can decipher what I'm trying to do here and see what I'm doing wrong!
# Clear FTP Directory
$DelLoop=1
$server = "www.newsbase.com"
$dir = "/usr/local/tomcat/webapps/newsbasearchive/monitors/asiaelec/"
"open $server
user Canttell Youthis
binary
cd $dir
" +(
For ($DelLoop=1; $DelLoop -le 5; 5)
{
$FileList[$DelLoop] | %{ "delete ""$_""`n" }
$DelLoop++
})| ftp -i -in
I know that the 'Open Connection' portion works, it's just the loop. It just keeps complaining about misplaced operators, and when I fix those, it doesn't throw up any errors - but it doesn't do anything either.
I spent the best part of 4 hours researching this yesterday, and I'm hoping one of you guys can help me.
Thanks in advance!
ADDENDUM:
Here is more of the code, as requested:
# Clear existing .htm file to avoid duplication
Get-ChildItem -path ".\" -recurse -include index.jsp | ForEach-Object {
Clear-Content "index.jsp"
}
# Set first part of .JSP Body
$HTMLPart1="</br><tr><td colspan=9 align=center><p style=""font-family:Arial"">Here are the links to the last 3 AsiaElec PDFs:</br><ul>"
# Recurse through directory, looking for 3 most recent .PDF files 3 times
$Directory="C:\PDFs"
$HTMLLinePrefix="<li><a style=""font-family:Arial""href="""
$HTMLLineSuffix="</a></li>"
$HTMLLine=#(1,2,3,4)
$Loop=1
$PDF=#(1,2,3,4)
Get-ChildItem -path $Directory -recurse -include *.pdf | sort-object -Property LastWriteTime -Descending | select-object -First 3 | ForEach-Object {
$PDF[$Loop]=$_.name
$HTMLLine[$Loop]=$HTMLLinePrefix + $_.name + """>" + $_.name + $HTMLLineSuffix
$Loop++
}
# Final .JSP File Assembly
Get-Content "header.html" >> "index.jsp"
$HTMLPart1 >> "index.jsp"
$LineParse=""
$Loop2=1
For ($Loop2=1; $Loop2 -le 3; 3)
{
$HTMLLine[$Loop2] >> "index.jsp"
$Loop2++
}
Get-Content "tail.html" >> "index.jsp"
# Prepare File List
$FileList=#(1,2,3,4,5)
$FileList[2]=$PDF[2]
$FileList[3]=$PDF[3]
$FileList[4]="index.jsp"
# Clear FTP Directory
$DelLoop=1
$server = "www.newsbase.com"
$dir = "/usr/local/tomcat/webapps/newsbasearchive/monitors/asiaelec/"
"open $server
user derek bland1ne
binary
cd $dir
" +(
For ($DelLoop=1; $DelLoop -le 5; 5)
{
$FileList[$DelLoop] | %{ "delete ""$_""`n" }
$DelLoop++
})| ftp -i -in
This isn't all of it, but I believe it contains all the relevant info.
Your $dir path looks like you're on a unix system so this may be a little different, but all you need to do is change your final loop a little bit:
For ($DelLoop=1; $DelLoop -le 5; $DelLoop++)
{
$FileList[$DelLoop] | % { rm $FileList[$DelLoop] }
}
This is assuming that $FileList contains the files you want to delete and not only (what I'm guessing are dummy) numbers. I also suggest that you download the Module that #Graimer mentions and then put it in WindowsPowerShell > Modules > %ModuleFolder% > %Module.psm1% and import it from your profile.
You can then just use PS> Remove-FTPItem -Path "/myFolder" -Recurse to remove your FTP stuff. Making your life easier.
Tweaking the solution to this post may also help Upload files with FTP using PowerShell
e.g:
Using $ftp.Method = [System.Net.WebRequestMethods+Ftp]::DeleteFile to delete the file,
and $response = $ftp.GetResponse() to find out if things went smoothly.
EDIT
Wrote this function after doing a little bit of research from here http://social.msdn.microsoft.com/forums/en-US/netfxnetcom/thread/17a3abbc-6144-433b-aadd-1f776c042bd5 and adapting the code from the Accepted Answer in the above link as well as the module #Graimer talked about.
function deleteFTPSide
{
Param(
[String] $ftpUserName = "muUserName",
[String] $ftpDomain = "ftp.place.com", # Normal domains begin with "ftp" here
[String] $ftpPassword = "myPassword",
[String] $ftpPort = 21, # Leave as the default FTP port
[String] $fileToDelete = "folder.domain.com/subfolder/file.txt"
)
# Create the direct path to the file you want to delete
[String] $ftpPath = "ftp://"+"$ftpUserName"+":"+"$ftpPassword#$ftpDomain"+":"+"$ftpPort/$fileToDelete"
# create the FtpWebRequest and configure it
$ftp = [System.Net.FtpWebRequest]::Create($ftpPath)
$ftp.Method = [System.Net.WebRequestMethods+Ftp]::DeleteFile
$ftp.Credentials = new-object System.Net.NetworkCredential($ftpUserName,$ftpPassword)
$ftp.UseBinary = $true
$ftp.UsePassive = $true
$response = [System.Net.FtpWebResponse]$ftp.GetResponse()
$response.Close()
}
While, admittedly, not one of the most elegant solutions written, I've tested it and it works at deleting a specified file off an FTP server.
Related
I use a simple function to download files and return the path to me when updating computers for simplicity.
I was stuck on why it was not working then realized that the proxy is appending a random number to the filename so instead of it being 12345.zip it is actually 8493830_12345.zip.
I have tried to find the file using the "_" as a split but while there are no errors, the file is not being returned and I have checked it is there manually.
function FileCheck {
$fileName.Split("_")[1]
$fileName = "{0}.zip" -f 12345
Download -ZipFileName $($fileName) -OutputDirectory $env:temp
$SleepTime = 300
$sleepElapsed = 0
$sleepInterval = 20
Start-Sleep $sleepInterval
$file = Get-ChildItem -Path $env:temp -Filter "$fileName*"
if ($file -ne $null) {
return $file[0].FullName
}
Start-Sleep($sleepInterval)
$sleepElapsed += $sleepInterval
if (($SleepTime) -le $sleepElapsed){
# Check for file with given prefix
$file = Get-ChildItem -Path $env:temp -Filter "$fileName*"
if ($file -eq $null) {
Write-Error 'file not found'
return $null
}
return $file[0].FullName
}
}
I am guessing the split is not working but googling and moving the filename.split has not worked for me. Any help is appreciated
Well, your split is doing nothing at all. You haven't defined $filename, but if you had, and it had an underscore, then $filename.split('_') would return two or more strings, depending on how many underscores were in the original string, but you never capture the result. I think the real problem here is the filter you are applying to Get-ChildItem later in your function.
$file = Get-ChildItem -Path $env:temp -Filter "$fileName*"
That will look for files beginning with $fileName, which you define on line 4 to be "12345.zip". That is exactly the opposite of what you want to be looking for. You need to move the asterisk to before $fileName, so it looks like this:
$file = Get-ChildItem -Path $env:temp -Filter "*$fileName"
That will return all files that end with "12345.zip", which would include things like:
myfuzzyhippo12345.zip
learn-to-count-12345.zip
8493830_12345.zip
Basically anything that ends in 12345.zip. Also, it appears that you are under the impression that executing a return $file[0].fullname or return $null will stop the function. That's a mistake. A function runs to completion unless exited early by something like a break command. Also, everything not explicitly captured or redirected will be passed back from the function, so reading through your function people are likely to get the output of your $filename.split('_') line, then possibly $null or $filename[0].fullname.
Lastly, it appears that you're trying to look for the file, if you don't find it to wait a bit, and try again, until $sleepElapsed is greater than $sleepTime. What you want here is a While or a Do/While loop. Here's what I'd do...
function FileCheck {
Param(
$fileName = '12345.zip',
$SleepTime = 300,
$sleepElapsed = 0,
$sleepInterval = 20
)
Download -ZipFileName $($fileName) -OutputDirectory $env:temp
Do{
Start-Sleep $sleepInterval
$sleepElapsed = $sleepElapsed + $sleepInterval
$file = Get-ChildItem -Path $env:temp -Filter "*$fileName"|Select -First 1
}While(!$file -and $sleepElapsed -le $sleepTime)
$file.FullName
}
That lets you define things like sleep settings at runtime if you want, or just let it default to what you were using, same with the file name. Then it downloads the file, and looks for it, pausing between attempts, until either it finds the file, or it runs out of time. Then it returns $file.FullName which is either the path to the file if it found one, or nothing if it didn't find a file.
Personally I'd have it return the file object, and just utilize the .FullName property if that's all I wanted later. Usually (not always, but usually) more info returned from a function is better than less info. Like what if the download fails and it's a zero byte file? Just returning only the path doesn't tell you that.
I'm trying to apply a hash function to all the files inside a folder as some kind of version control. The idea is to make a testfile that lists the name of the file and the generated checksum. Digging online I found some code that should do the trick (in theory):
$list = Get-ChildItem 'C:\users\public\documents\folder' -Filter *.cab
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
foreach ($file in $list) {
$return = "" | Select Name, Hash
$returnname = $file.Name
$returnhash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($file.Name)))
$return = "$returnname,$returnhash"
Out-File -FilePath .\mylist.txt -Encoding Default -InputObject ($return) -Append
}
When I run it however, I get an error because it tries to read the files from c:\users\me\, the folder where I'm running the script. And the file c:\users\me\aa.cab does not exist and hence can't be reached.
I've tried everything that I could think of, but no luck. I'm using Windows 7 with Powershell 2.0, if that helps in any way.
Try with .FullName instead of just .Name.
$returnhash = [System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($file.FullName)))
I've been given 14K CAB files each containing 200 files which need to be unzipped into their original locations.
Unfortunately it's not as easy as all of them being extracted to the same location :-(
I've decided to use PowerShell and have generated a list of individual file locations for each file using SQL and can extract the CABs, unfortunately they all extract to the current location.
I am trying to move them to their respective locations, but am struggling.
Here's the code, I've got so far
$shell_app=new-object -com shell.application
$CABfilename= Import-CSV "CABFileList.csv" -Header CABfilename | Foreach-object {
$zip_file = $shell_app.namespace((Get-Location).Path + "\$CABfilename")
$destination = $shell_app.namespace((Get-Location).Path)
$destination.Copyhere($zip_file.items())
$dvs = Import-csv "CABFileList.csv" -Header Path, DVSFilename |
Foreach-object{
Move-item $_.DVSFilename* $_.Path
}
This is an old question, but someone might find the answer useful anyway. I have adapted one I made today to download all WSPs from a farm and extract their contents.
$CABfilename = Import-CSV "CABFileList.csv" -Header CABfilename | Foreach-object {
# Grab the Solution
$Path = $SaveLocation + $CABfilename
# Check the path is ok
$Path
# Make a copy with extension '.cab' for extraction
$DotCab = $CABfilename + ".cab"
$SolutionDir = $Dotcab -replace '.wsp.cab'
mkdir $SolutionDir
copy-item $CABfilename $DotCab
# Now extract it, assuming you have expand.exe in the filsystem (should be in everything post Server 2008 / Vista)
if(C:\Windows\System32\expand.exe) {
try { cmd.exe /c "C:\Windows\System32\expand.exe -F:* $Dotcab $SolutionDir"}
catch { Write-host "Nope, don't have that, soz."}
}}
I'm trying to get a script to query files on an IIS website, then download those files automatically. So far, I have this:
$webclient = New-Object System.Net.webclient
$source = "http://testsite:8005/"
$destination = "C:\users\administrator\desktop\testfolder\"
#The following line returns the links in the webpage
$testcode1 = $webclient.downloadstring($source) -split "<a\s+" | %{ [void]($_ -match "^href=['"]([^'">\s]*)"); $matches[1] }
foreach ($line in $test2) {
$webclient.downloadfile($source + $line, $destination + $line)
}
I'm not that good at PowerShell yet, and I get some errors, but I manage to get a couple test files I threw into my wwwroot folder (the web.config file seems undownloadable, so I'd imagine thats one of my errors). When I tried to change my $source value to a subfolder on my site that had some test text files(example = http://testsite:8005/subfolder/, I get errors and no downloads at all. Running my $testcode1 will give me the following links in my subfolder:
/subfolder/test2/txt
/
/subfolder/test1.txt
/subfolder/test2.txt
I don't know why it lists the test2 file twice. I figured my problem was that since it was returning the subfolder/file format, that I was getting errors because I was trying to download $source + $line, which would essentially be http://testsite:8005/subfolder/subfolder/test1.txt, but when I tried to remedy that by adding in a $root value that was the root directory of my site and do a foreach($line in $testcode1) { $webclient.downloadfile($root + $line, $destination + $line) }, I still get errors.
If some of you high speed gurus can help show me the error of my ways, I'd be grateful. I am looking to download all the files in each subfolder on my site, which I know would involve use of some recursive action, but again, I currently do not have the skill level myself to do that. Thank you in advance on helping me out!
Best way to download files from a website is to use
Invoke-WebRequest –Uri $url
Once you are able to get hold of the html you can parse the content for the links.
$result = (((Invoke-WebRequest –Uri $url).Links | Where-Object {$_.href -like “http*”} ) | select href).href
Give it a try. Its simpler than $webclient = New-Object System.Net.webclient
This is to augment A_N's answer with two examples.
Download this Stackoverflow question to C:/temp/question.htm.
Invoke-RestMethod -Uri stackoverflow.com/q/19572091/1108891 -OutFile C:/temp/question.htm
Download a simple text document to C:/temp/rfc2616.txt.
Invoke-RestMethod -Uri tools.ietf.org/html/rfc2616 -OutFile C:/temp/rfc2616.txt
I made a simple Powershell script to clone an openbsd package repo. It probably would work / could be implemented in other ways/use cases for similar things.
GitHub link
# Quick and dirty script to clone a package repo. Only tested against OpenBSD.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$share = "\\172.16.10.99\wmfbshare\obsd_repo\"
$url = "https://ftp3.usa.openbsd.org/pub/OpenBSD/snapshots/packages/amd64/"
cd $share
$packages = Invoke-WebRequest -Uri $url -UseBasicParsing $url
$dlfolder = "\\172.16.10.99\wmfbshare\obsd_repo\"
foreach ($package in $packages.links.href){
if ((get-item $package -ErrorAction SilentlyContinue)){
write-host "$package already downloaded"
} else {
write-host "Downlading $package"
wget "$url/$package" -outfile "$dlfolder\$package"
}
}
I would try this:
$webclient = New-Object System.Net.webclient
$source = "http://testsite:8005/"
$destination = "C:\users\administrator\desktop\testfolder\"
#The following line returns the links in the webpage
$testcode1 = $webclient.downloadstring($source) -split "<a\s+" | %{ [void]($_ -match "^href=['"]([^'">\s]*)"); $matches[1] }
foreach ($line in $testcode1) {
$Destination = "$destination\$line"
#Create a new directory if it doesn't exist
if (!(Test-Path $Destination)){
New-Item $Destination -type directory -Force
}
$webclient.downloadfile($source + $line, $destination + $line)
}
I think your only issue here is that you were grabbing a new file from a new directory, and putting it into a folder that didn't exist yet (I could be mistaken).
You can do some additional troubleshooting if that doesn't fix your problem:
Copy each line individually into your powershell window and run them up to the foreach loop. Then type out your variable holding all the gold:
$testcode1
When you enter that into the console, it should spit out exactly what's in there. Then you can do additional troubleshooting like this:
"Attempting to copy $Source$line to $Destination$line"
And see if it looks the way it should all the way on down. You might have to adjust my code a bit.
-Dale Harris
I would really appreciate your help with this
I should first mention that I have been unable to find any specific solutions and I am very new to programming with powershell, hence my request
I wish to write (and later schedule) a script in powershell that looks for a file with a specific name - RFUNNEL and then renames this to R0000001. There will only be one of such 'RFUNELL' files in the folder at any time. However when next the script is run and finds a new RFUNNEL file I will this to be renamed to R0000002 and so on and so forth
I have struggled with this for some weeks now and the seemingly similar solutions that I have come across have not been of much help - perhaps because of my admittedly limited experience with powershell.
Others might be able to do this with less syntax, but try this:
$rootpath = "C:\derp"
if (Test-Path "$rootpath\RFUNNEL.txt")
{ $maxfile = Get-ChildItem $rootpath | ?{$_.BaseName -like "R[0-9][0-9][0-9][0-9][0-9][0-9][0-9]"} | Sort BaseName -Descending | Select -First 1 -Expand BaseName;
if (!$maxfile) { $maxfile = "R0000000" }
[int32]$filenumberint = $maxfile.substring(1); $filenumberint++
[string]$filenumberstring = ($filenumberint).ToString("0000000");
[string]$newName = ("R" + $filenumberstring + ".txt");
Rename-Item "$rootpath\RFUNNEL.txt" $newName;
}
Here's an alternative using regex:
[cmdletbinding()]
param()
$triggerFile = "RFUNNEL.txt"
$searchPattern = "R*.txt"
$nextAvailable = 0
# If the trigger file exists
if (Test-Path -Path $triggerFile)
{
# Get a list of files matching search pattern
$files = Get-ChildItem "$searchPattern" -exclude "$triggerFile"
if ($files)
{
# store the filenames in a simple array
$files = $files | select -expandProperty Name
$files | Write-Verbose
# Get next available file by carrying out a
# regex replace to extract the numeric part of the file and get the maximum number
$nextAvailable = ($files -replace '([a-z])(.*).txt', '$2' | measure-object -max).Maximum
}
# Add one to either the max or zero
$nextAvailable++
# Format the resulting string with leading zeros
$nextAvailableFileName = 'R{0:000000#}.txt' -f $nextAvailable
Write-Verbose "Next Available File: $nextAvailableFileName"
# rename the file
Rename-Item -Path $triggerFile -NewName $nextAvailableFileName
}