My boss has asked me to create a function/Script to download files off a website and place them in a folder:
Add-Type -AssemblyName Microsoft.Visualbasic
$url = "http://www.rarlab.com/rar/wrar521.exe"
$output = "C:\Users\****\Downloads\test\1"
$object = New-Object Net.WebClient
$object.DownloadFile($url, $output)
#######################################
$start_time = Get-Date
Write-Output "Time Taken((Get-Date).Subtract($start_time).Seconds) second(s)"
This is the current code I've got. Basically, what I need it to do is automatically name the file or resolve the name from the server with out me having to put $output = "C:\Users\****\Downloads\test\test.txt" or something.
Use Split-Path to split the filename from the URL, and Join-Path to join it to the folder path:
$url = 'http://www.rarlab.com/rar/wrar521.exe'
$filename = Split-Path -Leaf $url
$output = Join-Path 'C:\Users\****\Downloads\test\1' $filename
(New-Object Net.WebClient).DownloadFile($url, $output)
Related
I need to periodically scan a folder for new fontfiles to install and delete them afterwards using a powershell script.
During processing I want to skip already installed files and to achieve that I need to resolve the "real" fontname of the provided file.
I figured out everything and it seems to work everything but the file deletion.
The deletion did work until I added the font name resolution using this GlythTypeInterface Object. It seems like the invoked object does "file lock" the fontfile resulting in an UnauthorizedAccessException.
Thats why I tried some garbage collection stuff I found but I can't make it work.
My code so far:
Add-Type -AssemblyName PresentationCore
$FONTS = 0x14
$Path="C:\_fonts_to_install"
$FontItem = Get-Item -Path $Path
$FontList = Get-ChildItem -Path "$FontItem\*" -Include ('*.fon','*.otf','*.ttc','*.ttf')
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace($FONTS)
$Fontdir = dir $Path
$username = $env:UserName
foreach($File in $FontList) {
$try = $true
$installedFonts = #(Get-ChildItem C:\Users\$username\AppData\Local\Microsoft\Windows\Fonts | Where-Object {$_.PSIsContainer -eq $false} | Select-Object basename)
$fontObject = New-Object -TypeName Windows.Media.GlyphTypeface -ArgumentList $File.fullname
$fontName = $fontObject.Win32FamilyNames.Values
Write-Host $fontName
$fontObject = $null
Remove-Variable fontObject
foreach($font in $installedFonts)
{
if ($font -match $fontName)
{
$try = $false
}
}
if ($try)
{
$objFolder.CopyHere($File.fullname)
}
Write-Host $File
Remove-Item $File -Force -Verbose
}
I normally use a PowerShell script to download bulk CSV of images, but I have a new URL that displays the images very oddly. Could I modify this script to allow for these image URLs?
Example URLs:
https://www.example.com/core/media/media.nl?id=12&c=23&h=b944f2f81326d0bb
https://www.example.com/core/media/media.nl?id=15&c=42&h=7ed23c91f3574fc9
and the current script...
[Reflection.Assembly]::LoadFile(
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Web.dll') | Out-Null
$FileName = "C:\Temp\test.txt";
$Loc = "C:\Temp\Images\"
$ImageName = ""
$wc = New-Object System.Net.WebClient
$content = Get-Content $FileName
foreach ($line in $content) {
$Image = $Loc + $line.Substring($line.LastIndexOf("/") + 1)
$url = $line
Write-Host $url
Write-Host $Image
$wc.DownloadFile($url, $Image)
}
Write-Jost "Finished successfully."
A file name on Windows can't contain ?, *, ", \ characters, so filter them out:
$Image = $Loc + ($line.Substring($line.LastIndexOf("/") + 1) -replace '[?*"\\]', '_')
To get the real redirected file name from a dynamic URL process the Content-Disposition header:
$tmp = [IO.Path]::GetTempFileName()
$wc.DownloadFile($url, $tmp)
$Image = "$($wc.ResponseHeaders['Content-Disposition'])" -replace '^.*?filename=', ''
if (!$Image) {
$Image = $line.Substring($line.LastIndexOf("/") + 1) -replace '[?*"\\]', '_'
}
Move $tmp (Join-Path $Loc $Image)
I have a powershell script that will look for and compress log files then make a new .7zip file, however currently it has trouble compressing folder with dates e.g. application_logs_2016-07-14
1: The script works fine if there are folders with char's however if the containing folder has a date e.g. (application_logs_2016-07-14) nothing is archived.
2: I need a zip log files that are older than 5 days old, dump.log.341.log, dump.log.342.log and dump.log.343.log should be converted as dump.log.341.zip, dump.log.342.zip, dump.log.343.zip.
Here is the current code, if any powershell guru's could advise i'd be very happy. Thanks in advance.
# See if 7 zip is installed
if (-not (test-path "$env:ProgramFiles\7-Zip\7z.exe")) {throw "$env:ProgramFiles\7-Zip\7z.exe needed"}
set-alias sz "$env:ProgramFiles\7-Zip\7z.exe"
# Define log location and target directory
$Logfile = "D:\stuff\Software\dump files\Archive.log"
$newdirectory = "D:\stuff\compressedlogs"
# Write to log file - start of archive
$now = Get-date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content $Logfile -value "Archive started $now"
# Import what we want to back up from a list file
$List = Import-CSV "D:\stuff\Software\dump files\Compressionlist.txt"
ForEach ($Entry in $List){
$filepath = $($Entry.FilePath)
$Extension = $($Entry.Extension)
$Include = $($Entry.Include)
$Horizon = $($Entry.Horizon)
$Ext2Chg = $($Entry.Ext2Chg)
# Extract List of Files to process
$log = Get-ChildItem -Recurse -Path $filepath -Filter $Extension -Include $Include | Where-Object {$_.lastwriteTime -lt (((Get-Date).AddDays($Horizon)).date)}
# Archive each file found
ForEach ($file in $log) {
if ($file -ne $null) {
$name = $file.name
$newdate = $file.CreationTime | Get-Date -f "yyyy-MM-dd"
$newname = $file.BaseName + "___" + $newdate + $file.Extension
$directory = $file.DirectoryName
$zipfile = $newname.replace($Ext2Chg,".7z")
sz a -t7z "$newdirectory\$zipfile" "$directory\$name"
$now = Get-date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content $Logfile -value "File $directory\$name archived to folder\new filename $newdirectory\$newname at $now"
Remove-Item $file
}
}
}
# Write to log file - end of archive
$now = Get-date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content $Logfile -value "Archive completed $now"
# End
The script looks at a txt document to find what to archive
COMPRESSION LIST
Filepath,Extension,Include,Horizon,Ext2Chg
E:\APPLICATION\DUMP_logs_*,*.log,APP.dumps-currentlog.messages*,-5,.log
===============================================================
example folder structure
D:\application\server_log
(which will contain a log e.g. server_log_2016-07-14_00-00-00_0001.log) this will archive fine.
D:\application\application_log_2016-07-14
(which will contain a log e.g. APP.dumps-currentlog.messages.log) this will NOT archive.
Hope that make sense.
What I tried to do is searching a directory to output file path, name, version and last modified time into a txt file.
My code as below:
function Get-Version($filePath)
{
$name = #{Name="Name";Expression= {split-path -leaf $_.FileName}}
$path = #{Name="Path";Expression= {split-path $_.FileName}}
$time = #{Name="Last Modified"; Expression={Get-Date $_.LastWriteTime}}
dir -recurse -path $filePath | % { if ($_.Name -match "(.*exe)$") {$_.VersionInfo} } | select $path, $name,$time, FileVersion
}
Get-Version('E:\PS test') >> "version_info.txt"
However the output txt has name, path and version, but no last modified time.
Any hints?
Thanks!
It's because you're returning the .VersionInfo property from your ForEach-Object (%) call, and .LastWriteTime is a property of the file object, not the version info. Have a look at this:
function Get-Version($filePath)
{
$name = #{Name="Name";Expression= {split-path -leaf $_.VersionInfo.FileName}}
$path = #{Name="Path";Expression= {split-path $_.VersionInfo.FileName}}
$time = #{Name="Last Modified"; Expression={Get-Date $_.LastWriteTime}}
$version = #{Name="FileVersion"; Expression={$_.VersionInfo.FileVersion}}
dir -recurse -path $filePath | ? { $_.Name -match "(.*exe)$" } | select $path, $name,$time, $version
}
By Changing the defintiion of $name and $path to refer directly to the version info, you can operate on the original object. I also had $version to get at the FileVersion you were referring to in the select.
That makes the ForEach-Object redundant, since you'd only be passing along the input. Since you were only checking a condition in it anyway, easier to convert it to Where-Object (?).
Expanding your aliases makes it look like this:
function Get-Version($filePath)
{
$name = #{Name="Name";Expression= {Split-Path -Leaf $_.VersionInfo.FileName}}
$path = #{Name="Path";Expression= {Split-Path $_.VersionInfo.FileName}}
$time = #{Name="Last Modified"; Expression={Get-Date $_.LastWriteTime}}
$version = #{Name="FileVersion"; Expression={$_.VersionInfo.FileVersion}}
Get-ChildItem -Recurse -Path $filePath | Where-Object { $_.Name -match "(.*exe)$" } | Select-Object $path, $name,$time, $version
}
However I should also point out that you can filter the file names directly in dir (Get-ChildItem), making the Where-Object superfluous too:
function Get-Version($filePath)
{
$name = #{Name="Name";Expression= {Split-Path -Leaf $_.VersionInfo.FileName}}
$path = #{Name="Path";Expression= {Split-Path $_.VersionInfo.FileName}}
$time = #{Name="Last Modified"; Expression={Get-Date $_.LastWriteTime}}
$version = #{Name="FileVersion"; Expression={$_.VersionInfo.FileVersion}}
Get-ChildItem -Recurse -Path $filePath -Filter *.exe | Select-Object $path, $name,$time, $version
}
And then based on your comment, I realized it can be simplified even more:
function Get-Version($filePath)
{
$path = #{Name="Path";Expression= {$_.DirectoryName}}
$time = #{Name="Last Modified"; Expression={$_.LastWriteTime}}
$version = #{Name="FileVersion"; Expression={$_.VersionInfo.FileVersion}}
Get-ChildItem -Recurse -Path $filePath -Filter *.exe | Select-Object $path, Name,$time, $version
}
$name is not needed because the file object already has a property called .Name that has the file name.
$path can be simplified because $_.DirectoryName already has the path.
$time can be simplified because the .LastWriteTime property is already a [DateTime] so you don't need Get-Date.
The only reason you still need the name/expression hashes for those is to have the fields be named something other than the underlying property. If you don't care about that, you could do this:
function Get-Version($filePath)
{
$version = #{Name="FileVersion"; Expression={$_.VersionInfo.FileVersion}}
Get-ChildItem -Recurse -Path $filePath -Filter *.exe | Select-Object DirectoryName, Name, LastWriteTime, $version
}
I wrote this script to find all of the folders in a directory and for each folder, check inside a common file if some strings exist and if not add them. I needed to insert strings in particular places. Not really knowing how to do this, I opted for simpler find and replace where the strings needed to be inserted. Anyway this script takes almost an hour to work through 800 files. I'm hoping some experienced members can point out ways to make my task quicker as I have only been working with Powershell for two days. Many Thanks!!!
# First find and replace items.
$FindOne =
$ReplaceOneA =
$ReplaceOneB =
$ReplaceOneC =
# Second find and replace items.
$FindTwo =
$ReplaceTwo =
# Strings to test if exist.
# To avoid duplicate entries.
$PatternOne =
$PatternTwo =
$PatternThree =
$PatternFour =
# Gets window folder names.
$FilePath = "$ProjectPath\$Station\WINDOW"
$Folders = Get-ChildItem $FilePath | Where-Object {$_.mode -match "d"}
# Adds folder names to an array.
$FolderName = #()
$Folders | ForEach-Object { $FolderName += $_.name }
# Adds code to each builder file.
ForEach ($Name in $FolderName) {
$File = "$FilePath\$Name\main.xaml"
$Test = Test-Path $File
# First tests if file exists. If not, no action.
If ($Test -eq $True) {
$StringOne = Select-String -pattern $PatternOne -path $File
$StringTwo = Select-String -pattern $PatternTwo -path $File
$StringThree = Select-String -pattern $PatternThree -path $File
$StringFour = Select-String -pattern $PatternFour -path $File
$Content = Get-Content $File
# If namespaces or object don't exist, add them.
If ($StringOne -eq $null) {
$Content = $Content -Replace $FindOne, $ReplaceOneA
}
If ($StringTwo -eq $null) {
$Content = $Content -Replace $FindOne, $ReplaceOneB
}
If ($StringThree -eq $null) {
$Content = $Content -Replace $FindOne, $ReplaceOneC
}
If ($StringFour -eq $null) {
$Content = $Content -Replace $FindTwo, $ReplaceTwo
}
$Content | Set-Content $File
}
}
# End of program.
You could try writing to the file with a stream, like this
$stream = [System.IO.StreamWriter] $File
$stream.WriteLine($content)
$stream.close()