I found this script to download Javax64 and it really works, but I had some problems.
The first is that the command I would put would be inside an XML file that a powershell script calls it, so putting it directly like this, it gave some errors because where it shows "<a" the XML understood that this was part of it and not of something that only PowerShell would make use of.
The second is "New-Object -ComObject "InternetExplorer.Application" where this is not working on my Windows Server and it is recommended not to use it for ie it is being discontinued soon. It still works on Windows 10 normally but on Windows Server it gets stuck in a loop and won't get out.
How would I convert this script to an Invoke-WebRequest, is this possible? Because then I would just need to put the complete string of the Invoke-WebResquest in my XML file and PowerShell would read it normally, I think.
$ie = New-Object -ComObject "InternetExplorer.Application"
# Navigate to the requested page
$ie.Navigate2("https://www.java.com/en/download/manual.jsp")
$anchor = $null
while($anchor -eq $null -or $anchor -eq "")
{
#wait 1 second for the page to load
start-sleep -m 1000
#get the html of the page
$html = $ie.document.body.innerHTML
#apply your regex to identify the anchar with the download link
$anchor = [regex]::Match($html, '(?:<a title="Download Java software for Windows \(64-bit\)" href=")(.*)(?:">)').Groups[1] .Value
}
#regex doesn't return the link correctly, that's why I made the substring to get the link
$url_download = $anchor.Substring(0,$anchor.IndexOf(""""))
$url_download
Edit: There is the same situation but to download Edge?
Note: Neither Invoke-WebRequest or the built-in .NET clients for obtaining files over HTTP seem to support rendering the full DOM, and so JavaScript cannot be executed. JavaScript is required to access those downloads links and use the site in general. You have two choices:
Use static links as I have outlined in my original answer below; or
Automate Edge using WebDriver, which is how Microsoft recommends you automate MS Edge. There is no COM functionality for controlling the Edge browser.
Unfortunately, I cannot help with the latter as I have no experience using WebDriver.
Looking at the oraclejdk Chocolatey package installation script, the URL is
https://download.oracle.com/java/17/archive/jdk-17.0.2_windows-x64_bin.msi. Since you're already familiar with Chocolatey from another environment, I would figure the version you need, see if there is a Chocolatey package for it, and get the direct URL from that package version's installation script.
You could also attempt to templatize the URL like so:
https://download.oracle.com/java/MAJOR_VERSION/archive/jdk-MAJOR_VERSION.MINOR_VERSION.PATCH_windows-x64_bin.msi
where MAJOR_VERSION, MINOR_VERSION, and PATCH are pieces of the Java version. However, I have not tested that all Java MSI URLs follow this pattern.
Regardless, once you have the URL, it's as simple as:
# Work around performance issue with iwr and the progress bar
$ProgressPreference = 'SilentlyContinue'
$MSI_URL = 'https://download.oracle.com/java/17/archive/jdk-17.0.2_windows-x64_bin.msi'
Invoke-WebRequest -UseBasicParsing $MSI_URL -Outfile 'jdk-17.0.2_windows-x64_bin.msi'
Related
I'm getting the list of installed Microsoft Store apps with this command:
Get-AppxPackage -AllUsers
And then I try to open an app:
powershell -Command "Start-Process 'C:\Program Files\WindowsApps\Microsoft.Windows.Photos_2021.21070.22007.0_x64__8wekyb3d8bbwe\Microsoft.Photos.exe' -Verb runAs"
I get an access error:
This command cannot be run due to the error: Access is denied.
# Use the URI scheme of the Microsoft.Photos application.
# Note: Unfortunately, -Wait does *not* work in this case.
Start-Process ms-photos:
# Wait for the process to exit (from what I can tell there's only ever 1
# Microsoft.Photos process).
# The relevant process name was obtained with: Get-Process *Photos*
(Get-Process Microsoft.Photos).WaitForExit()
Note: That Start-Process -Wait (and -PassThru) cannot be used with at least some Microsoft Store applications is unfortunate; the problem has been reported in GitHub issue #10996.
Using a URI protocol scheme such as ms-photos: is the simplest approach, although discovering a given Microsoft Store's application's protocol(s) is non-trivial - see this answer, which provides a helper function, Get-AppXUriProtocol, which builds on the standard
Get-AppXPackage cmdlet; e.g.:
# Note:
# * Requires custom function Get-AppXUriProtocol from the linked answer.
# * Must be run in *Windows PowerShell*, because the AppX module
# isn't supported in PowerShell (Core), as of v7.1.
PS> Get-AppXUriProtocol *Photos* | Format-List
PackageFullName : Microsoft.Windows.Photos_2021.21070.22007.0_x64__8wekyb3d8bbwe
Protocols : {ms-wcrv, ms-wpdrmv, ms-photos, microsoft.windows.photos.crop...}
As you can see, the Microsoft Photos application has several protocol schemes associated with it, but the obvious candidate for simply launching the application is ms-photos:, which indeed works.
Launching Microsoft Store applications that do not have a URI protocol scheme defined:
If a given application doesn't define a URI protocol scheme, you must - somewhat obscurely - launch it via its AppId (application ID), and the general shell: URI protocol scheme and the virtual AppsFolder shell folder; e.g., to launch Calculator:
Start-Process shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
Finding an application's AppID:
In Windows 10 and above, you can now use the Get-StartApps cmdlet to list all installed AppX applications or search by (part of) their display name, which reports their AppIDs. Thus, if you know an application's full display name, e.g., Photos, you can launch it as follows:
Start-Process "shell:AppsFolder\$((Get-StartApps Photos | Select-Object -First 1).AppId)"
Note: The reason for Select-Object -First 1 is that even specifying the exact display name can result in multiple results, such as for Microsoft Edge.
If you're unsure of the full display name, you can use a substring to find matching applications; e.g.. Get-StartApps edge
In older versions, you must determine the AppID manually, which is quite cumbersome, unfortunately: read on.
The AppID is composed of the family package name (e.g. Microsoft.MicrosoftEdge_8wekyb3d8bbwe) followed by ! and a package-internal identifier, which is typically - but not always !App; two notable exceptions:
Spotify requires !Spotify (as you've discovered yourself).
Microsoft Edge uses !MicrosoftEdge (note, however, that Edge does have a URI protocol for lauching, microsoft-edge: and that there's also a simpler AppID, MSEdge, though it doesn't support passing arguments (see below)).
As you have discovered yourself, the suffix is the package-internal application ID, which is defined in an application's manifest file, appxmanifest.xml, located in the app-specific subfolder underneath $env:Programfiles\WindowsApps; note that a manifest can contain multiple application IDs, as is indeed the case for Microsoft Photos:
# Run in *Windows PowerShell*.
# For Microsoft Photos, the following application IDs are reported:
# 'App', 'SecondaryEntry'
$appManifestPath = (Get-AppxPackage *Photos*)[-1].InstallLocation + '\appxmanifest.xml'
(
Select-Xml '//ns:Application' $appManifestPath `
-Namespace #{ ns='http://schemas.microsoft.com/appx/manifest/foundation/windows10' }
).Node.Id
It's fair to assume for launching the application interactively that the first entry must be used, though I'm not clear on whether there are official rules.
To demonstrate the technique using Microsoft Photos:
# Get the package family name (the assumption here is that only *1* package matches).
# Note: While you must run the Get-AppXPackage from *Windows PowerShell*
# you can use the resulting package name to launch the application
# from PowerShell (Core) too.
$packageFamilyName = (Get-AppXPackage *Photos*).PackageFamilyName
Start-Process "shell:AppsFolder\$packageFamilyName!App"
Note that since the executable is then launched indirectly, the actual target process (Microsoft.Photos in this case) isn't guaranteed to exist yet when Start-Process returns, so more work is needed to first wait for it to come into existence, and then wait for it to exit.
In the simplest - but not fully robust - case, insert a Start-Sleep command, to sleep as long as you would expect creation of the target process to take at most (the actual timing varies with system load):
Start-Process "shell:AppsFolder\$packageFamilyName!App"
Start-Sleep -Seconds 5 # Wait for the Microsoft.Photos process to be created.
(Get-Process Microsoft.Photos).WaitForExit()
A fully robust approach would require more work.
Passing arguments to Microsoft Store applications:
With the general "shell:AppsFolder\$appId" approach, you can seemingly pass argument as usual, via Start-Process' -ArgumentList (-Args) parameter; e.g., with Microsoft Edge (run from Windows PowerShell - if you have an older Edge version, replace !App with `!MicrosoftEdge:
# Starts Microsoft Edge and opens the specified URLs.
# Note: Curiously, this does NOT work with the simpler "MSEdge" AppID.
Start-Process `
shell:AppsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge `
-Args 'http://example.org https://wikipedia.org'
With the app-specific URI-scheme approach, argument(s) must be passed as part of the URI (-ArgumentList is ignored):
Caveat: It is unclear to me how you can pass multiple arguments and, generally, whether there is a standardized method across applications to embed arguments in the URI.
For instance, Microsoft Edge seems to accept only one argument: the URL of a site to open. Anything after that one URL is seemingly interpreted as a part of that one URL:
# Starts Microsoft Edge an opens the specified URL.
Start-Process 'microsoft-edge:https://en.wikipedia.org?search=wikipedia'
In windows 10, if you right click on an image, you will find an option called "Share".
Clicking this opens up a dialog box where you can share the image via email, one note e.t.c.
Does anyone know how I can call this up from CMD or PowerShell? as I would like to add this feature to my app.
I have gotten to this point but get an invalid window handle error:
$Target = "C:\Users\igweo\OneDrive\Pictures\wallpapers\luca-zanon-26595-unsplash.jpg"
$KeyPath1 = "HKCU:\SOFTWARE\Classes"
$KeyPath2 = "*"
$KeyPath3 = "shell"
$KeyPath4 = "{:}"
$ValueName = "ExplorerCommandHandler"
$ValueData = (Get-ItemProperty("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\" +
"Explorer\CommandStore\shell\Windows.ModernShare")).ExplorerCommandHandler
$Key2 = (Get-Item $KeyPath1).OpenSubKey($KeyPath2, $true)
$Key3 = $Key2.CreateSubKey($KeyPath3, $true)
$Key4 = $Key3.CreateSubKey($KeyPath4, $true)
$Key4.SetValue($ValueName, $ValueData)
$Shell = New-Object -ComObject "Shell.Application"
$Folder = $Shell.Namespace((Get-Item $Target).DirectoryName)
$Item = $Folder.ParseName((Get-Item $Target).Name)
$Item.InvokeVerb("{:}")
$Key3.DeleteSubKey($KeyPath4)
if ($Key3.SubKeyCount -eq 0 -and $Key3.ValueCount -eq 0) {
$Key2.DeleteSubKey($KeyPath3)
}
Also, using RUNDLL doesn't work either:
RUNDLL32.EXE NTSHRUI.DLL,ShowShareFolderUI C:\Users\igweo\OneDrive\Pictures\wallpapers\luca-zanon-26595-unsplash.jpg
Thanks to #Simon Mourier for pointing me to the answer.
The solution can be found on https://github.com/daibatzu/electron-sharing
Using visual studio you can build an exe file, I have included instructions in the readme.txt
The generated exe is WindowsFormsApp2.exe
You can then share files by using:
WindowsFormsApp2.exe "C:\Projects\Javascript\photos\celeste.png" "C:\Projects\Javascript\photos\Silvercoins.jpg"
You can test this by opening a cmd prompt, navigating to the folder containing WindowsFormsApp2.exe and passing filenames as parameters.
Clicking outside the share dialog will close WindowsFormsApp2.exe
You will need to use visual studio to change the icon for this app unfortunately
I have included a release just in case you do not know visual studio or C#. You will need 7-zip (free download) to unzip it.
Once again, thanks to Simon.
This took way longer than I imagined.
EDIT
problems with github so zip file is here: https://drive.google.com/file/d/1jyBqO6jmGo5dSxw32LXa5lej1J3ElD34/view?usp=sharing
What I am trying to do is download 2 images from URL's and open them after download. Here's what I have:
#echo off
set files='https://cdn.suwalls.com/wallpapers/cars/mclaren-f1-gtr-42852-400x250.jpg','http://www.dubmagazine.com/home/media/k2/galleries/9012/GTR_0006_EM-2014-12-21_04_GTR_007.jpg'
powershell "(%files%)|foreach{$fileName='%TEMP%'+(Split-Path -Path $_ -Leaf);(new-object System.Net.WebClient).DownloadFile($_,$fileName);Invoke-Item $fileName;}"
Im getting 'Cannot find drive' A drive with the name 'https' cannot be found.
It's the Split-path command that is having problems but cant seem to find a solution.
You could get away with basic string manipulation but, if the option is available, I would opt for using anything else that is data aware. In your case you could use the [uri] type accelerator to help with these. I would also just opt for pure PowerShell instead of splitting between batch and PS.
$urls = 'https://cdn.suwalls.com/wallpapers/cars/mclaren-f1-gtr-42852-400x250.jpg',
'http://www.dubmagazine.com/home/media/k2/galleries/9012/GTR_0006_EM-2014-12-21_04_GTR_007.jpg'
$urls | ForEach-Object{
$uri = [uri]$_
Invoke-WebRequest $_ -OutFile ([io.path]::combine($env:TEMP,$uri.Segments[-1]))
}
Segments will get you the last portion of the url which is a proper file name in your case. Combine() will build the target destination path for you. Feel free to add you invoke item logic of course.
This also lacks error handling if the url cannot be accessed or what not. So be aware of that possibility. The code above was meant to be brief to give direction.
I want to block (not unblock) a file with Powershell. I want to cause Windows to believe that a file on disk was downloaded from the internet, or whatever other scenario exists such that files become blocked. I need this to test how some software I'm developing behaves in the presence of a blocked file.
If you're just trying to add the zone identifier you could try something like this:
$data = "[ZoneTransfer]
ZoneId=3"
Set-Content example.txt -Stream "Zone.Identifier" -Value $data
Problem: I'm working on making a PowerShell script that will download the sites source code, find all the file targets, and then download said targets. I'm alright for authentication for the moment, so on my test website, I enabled anonymous authentication, enabled directory browsing, and disabled all other default pages, so all I get is a list of files on my site. What I have so far is this:
$source = "http://testsite/testfolder/"
$webclient = New-Object system.net.webclient
$destination = "c:/users/administrator/desktop/test/"
$webclient.downloadstring($source)
The $webclient.downloadstring will return basically the source code of my site, and I can see the files I want wrapped in the rest of the code. My question to you guys is what is the best and/or easiest ways of isolating the links I want so I can do a foreach command to download all of them?
Also, for extra credit, how would I go about adding in code to download folders and the files within those folders from my site? I can at least make seperate scripts to pull the files from each subfolder, but obviously it would be much nicer to get it all in one script.
If you are on PowerShell v3 the Invoke-WebRequest cmdlet may be of help.
To get an object representing the website:
Invoke-WebRequest "http://stackoverflow.com/search?tab=newest&q=powershell"
To get all the links in that website:
Invoke-WebRequest "http://stackoverflow.com/search?tab=newest&q=powershell" | select -ExpandProperty Links
And to just get a list of the href elements:
Invoke-WebRequest "http://stackoverflow.com/search?tab=newest&q=powershell" | select -ExpandProperty Links | select href
If you are on PowerShell v2 or earlier you'll have to create an InternetExplorer.Application COM object and use that to navigate the page:
$ie = new-object -com "InternetExplorer.Application"
# sleep for a second while IE launches
Start-Sleep -Seconds 1
$ie.Navigate("http://stackoverflow.com/search?tab=newest&q=powershell")
# sleep for a second while IE opens the page
Start-Sleep -Seconds 1
$ie.Document.Links | select IHTMLAnchorElement_href
# quit IE
$ie.Application.Quit()
Thanks to this blog post where I learnt about Invoke-WebRequest.
Update:
One could also download the website source like you posted and then extract the links from the source. Something like this:
$webclient.downloadstring($source) -split "<a\s+" | %{ [void]($_ -match "^href=[`'`"]([^`'`">\s]*)"); $matches[1] }
The -split part splits the source along lines that start with <a followed by one or more spaces. The output is placed in an array which I then pipe through a foreach-object block. Here I match each line on the regexp which extracts the links part and outputs it.
If you want to do more with the output you can pipe it further through another block which does something with it.