PowerShell Get-AdvertisedShortcut - powershell

After I found out that sometimes shortcut targets cannot be queried by WScript.Shell object, but in case of advertised shortcuts need to be queried by WindowsInstaller.Installer object, I searched the web and found the promising solution below.
But either the solution is outdated or written for another version of Windows (I use PowerShell 5.1 on 64-bit Windows 10). It gives me only the following error message for advertised shortcuts like %AppData%\Microsoft\Windows\Start Menu\Programs\System Tools*.lnk:
Ausnahme beim Aufrufen von "InvokeMember" mit 5 Argument(en): "ShortcutTarget"
which literally translates to:
Exception while calling "InvokeMember" with 5 arguments: "ShortcutTarget"
In addition, I see the following lines with no additional information for me:
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : COMException
Unfortunately, I do not know where to lookup the correct syntax and have found nothing else than the code below for solving the original issue of getting the target of an advertised shortcut.
Any ideas where I can look next?
Code from https://www.alkanesolutions.co.uk/2020/06/03/use-powershell-to-find-an-advertised-shortcut-target:
function Get-AdvertisedShortcut {
param([string]$pathToLnk)
$shortcutTarget = ""
if ($pathToLnk -ne $null -and (test-path $pathToLnk)) {
$windowsInstaller = New-Object -ComObject WindowsInstaller.Installer
$lnkTarget = $WindowsInstaller.GetType().InvokeMember("ShortcutTarget","GetProperty",$null,$windowsInstaller,$pathToLnk)
$productCode = $lnkTarget.GetType().InvokeMember("StringData","GetProperty",$null,$lnkTarget,1)
$componentCode = $lnkTarget.GetType().InvokeMember("StringData","GetProperty",$null,$lnkTarget,3)
$shortcutTarget = $WindowsInstaller.GetType().InvokeMember("ComponentPath","GetProperty",$null,$WindowsInstaller,#($productCode,$componentCode))
}
return $shortcutTarget
}

Related

PowerShell: Auto Login to a website using MS Edge instead of IE throws errors

Courtesy of this post, the following code auto-logs into a URL using MS IE and works great. The first two lines are the most important here. See below for what happens when I change them. I want to make it clear That I am not a professional web developer. I am only a system administrator forced to hack my way along when it comes to coding.
Working code when PowerShell calls IE:
$ie = New-Object -ComObject 'internetExplorer.Application'
$ie.Visible= $true # Make it visible
$username="myname"
$RSAPIN="mypin"
$password="mypassword"
$ie.Navigate("https://www.tibia.com/mmorpg/free-multiplayer-online-role-playing-game.php")
While ($ie.Busy -eq $true) {Start-Sleep -Seconds 3;}
$usernamefield = $ie.document.getElementByID('username')
$usernamefield.value = "$username"
$RSAPINfield = $ie.document.getElementByID('password_input')
$RSAPINfield.value = "$RSAPIN"
$passwordfield = $ie.document.getElementByID('secondary_password_input')
$passwordfield.value = "$password"
Non-working code is shown below; If I change the code to call MS Edge instead, I get a raft of errors and I think it's because PowerShell New-Object doesn't support MS Edge?
$msedge = New-Object -ComObject 'internetExplorer.Application'
$msedge.Visible= $true # Make it visible
$username="myname"
$RSAPIN="mypin"
$password="mypassword"
$msedge.Navigate("https://www.tibia.com/mmorpg/free-multiplayer-online-role-playing-game.php")
While ($ie.Busy -eq $true) {Start-Sleep -Seconds 3;}
$usernamefield = $msedge.document.getElementByID('username')
$usernamefield.value = "$username"
$RSAPINfield = $msedge.document.getElementByID('password_input')
$RSAPINfield.value = "$RSAPIN"
$passwordfield = $msedge.document.getElementByID('secondary_password_input')
$passwordfield.value = "$password"
Errors seen when calling MS Edge instead of IE:
New-Object : Retrieving the COM class factory for component with CLSID
{00000000-0000-0000-0000-000000000000} failed due to the following
error: 80040154 Class not registered (Exception from HRESULT:
0x80040154 (REGDB_E_CLASSNOTREG)). At
C:\Scripts\msedge.ps1:3
char:11
$msedge = New-Object -ComObject 'msedge.Application'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : ResourceUnavailable: (:) [New-Object], COMException
FullyQualifiedErrorId : NoCOMClassIdentified,Microsoft.PowerShell.Commands.NewObjectCommand
The property 'Visible' cannot be found on this object. Verify that the
property exists and can be set. At
C:\Scripts\msedge.ps1:4
char:1
$msedge.Visible= $true # Make it visible
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound You cannot call a method on a null-valued expression. At
C:\Scripts\msedge.ps1:8
char:1
$msedge.Navigate("myurl")
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull You cannot call a method on a null-valued expression. At
C:\Scripts\msedge.ps1:12
char:1
$usernamefield = $msedge.document.getElementByID('username')
I am at a loss here. According to this post, PowerShell New-Object only supports IE's COM Automation.
You can't automate the Edge Chromium browser like what you do with IE using PowerShell script. The COM automation interface are for IE, so it doesn't work with Edge. Besides, Edge doesn't have such interface.
It's recommended to use Selenium WebDriver to automate Edge. Selenium web driver supports many developing languages, you can choose the desired language.
You can also refer to the official doc of Selenium to learn how to get start with Selenium and refer to the code sample of different languages.

Script works in ISE and not SOME powershell CLI

$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("********Please Select the SOURCE Directory********",0,"Directory Selecter 5000",0x1)
Function Get-Folder($initialDirectory)
{
$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.rootfolder = "MyComputer"
if($foldername.ShowDialog() -eq "OK")
{
$folder += $foldername.SelectedPath
}
return $folder
}
$a = Get-Folder
$wshellb = New-Object -ComObject Wscript.Shell
$wshellb.Popup("********Please Select the DESTINATION Directory********",0,"Directory Selecter 5000",0x1)
Function Get-Folder($initialDirectory)
{
$foldername = New-Object System.Windows.Forms.FolderBrowserDialog
$foldername.rootfolder = "MyComputer"
if($foldername.ShowDialog() -eq "OK")
{
$folder += $foldername.SelectedPath
}
return $folder
}
$b = Get-Folder
Set-Content -Path "C:\script\scripts\script data.txt" -Value "$a" -Force
Set-Content -Path "C:\script\scripts\script data2.txt" -Value "$b" -Force
So this script works in ISE and if I copy/paste it into a CLI and that's it. If I navigate to the folder in the powershell CLI and run it from there it gives me this error:
New-Object : Cannot find type
[System.Windows.Forms.FolderBrowserDialog]: verify that the assembly
containing this type is loaded. At
C:\script\scripts\pathingworking.ps1:8 char:19
+ $foldername = New-Object System.Windows.Forms.FolderBrowserDialog
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
The property 'rootfolder' cannot be found on this object. Verify that
the property exists and can be set. At
C:\script\scripts\pathingworking.ps1:9 char:5
+ $foldername.rootfolder = "MyComputer"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
You cannot call a method on a null-valued expression. At
C:\script\scripts\pathingworking.ps1:11 char:8
+ if($foldername.ShowDialog() -eq "OK")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
This error comes back twice, once for each instance of the folder selection window that is supposed to pop up.
I have tried -STA from run dialogue, shortcuts, and even from the CLI and it always gives me that error. I have verified using [System.Threading.Thread]::CurrentThread.GetApartmentState() that the open instance of powershell is STA. I can open a powershell CLI and navigate to the folder where the script is, invoke the script, it will give me the error, then I can copy\paste it in the same exact CLI and it works without issue. I have also right-clicked the file in Explorer and selected "run with powershell" and it also gives me the error. I have elevated the CLI to see if that helped with no success.
I fear this is some small oversight and hopefully someone can give me a hand.
using v1.0
windows 10
Cannot find type [System.Windows.Forms.FolderBrowserDialog] is due to the assembly not being loaded.
load the assembly with
Add-Type -AssemblyName "System.Windows.Forms"
rerun's answer solves the errors, but doesn't do a whole lot of explaining. Designing a script in the ISE (which is what I do almost exclusively) is convenient because it will automatically load types and modules for you. If you plan on running the script from another CLI (Command Line Interpreter) you should make it a habit of explicitly loading needed modules and assemblies early on in the script, so that when those things are called upon later PowerShell will know what you're asking for.
Unfortunately there's no easy way to tell what you will need to do that for when it comes to what types are going to be inherently available, but a little trial and error usually points it out rather quickly, or if you look at your script and see that you are making a new object with System.Kitchen.Pasta, then you probably need to load the assembly for System.Kitchen first, so that it has the Pasta type available when you want it, so you could just include a call to load that assembly near the top of the script with no harm done.
In your specific case, as has already been pointed out, you will need to load the assembly that contains the FolderBrowserDialog box that you want to display. Adding the following as the first line of your script will resolve the errors that you are seeing:
Add-Type -AssemblyName "System.Windows.Forms"

PowerShell - Process multiple word docs (office 2010)

I am trying to write a PowerShell script to perform steps on multiple Word docs. I have Word 2010 installed on my machine, but I can't seem to get the script to open the docs. Here is the script
$path = "C:\MyPath"
Add-Type -AssemblyName Microsoft.Office.Interop.Word
$wordFiles = Get-ChildItem -Path $path -include *.doc, *.docx -recurse
$objWord = New-Object -ComObject "word.application"
$objWord.visible = $false
foreach($wd in $wordFiles)
{
$doc = $objWord.documents.open($wd.fullname)
#InsertProcessingFunctionsHere
$doc.Save()
$objWord.Documents.Close()
}
$objWord.Quit()
I try and run this, and the error I get back from PowerShell is:
Exception calling "Open" with "1" argument(s): "Command failed"
At C:\Scripts\Process-WordDocs.ps1:10 char:31
+ $doc = $objWord.documents.open <<<< ($wd.fullname)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
You cannot call a method on a null-valued expression.
At C:\Scripts\Process-WordDocs.ps1:13 char:10
+ $doc.Save <<<< ()
+ CategoryInfo : InvalidOperation: (Save:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Exception calling "Close" with "0" argument(s): "This method or property is not available because a document window is not active."
At C:\Scripts\Process-WordDocs.ps1:14 char:25
+ $objWord.Documents.Close <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
MSDN states that documents.open only requires 1 argument, and the rest are optional. However, a C# example I have seen on the net, showed passing a "ReadOnly: False" parameter to documents.open. Stepping through the script in the ISE Debugger, I can see $wd.fullname is there and points to a valid file, so I am completely unclear why it is not opening. At first, I thought this was because I was using a 64-bit version of the OS (32-bit version of Office), but attempting the script from a 32-bit PowerShell Session resulted in the same error. Anyone have any insight here as to why this may be happening, and how I can fix it? I would prefer all the processing to happen invisible to the user. Any help would be greatly appreciated. Thank you in advance for your time.
I think you want to close the document using $doc.close() instead of $objWord.Documents.Close()

Can we use SQLTransaction in Windows Powershell ISE?

I tried using SQLDataAdapter Object in Powershell ISE and its methods like below
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
and used its method like below
$SqlAdapter.Fill($DataSet)
Its working for me. But when I am trying like below
$trans= New-Object System.Data.SqlClient.SqlTransaction
and using its method like this
$trans = $connection.BeginTransaction("SampleTransaction")
where
$connection= New-Object System.Data.SqlClient.SqlConnection
Its giving me error
Exception calling "BeginTransaction" with "1" argument(s): "Invalid
operation. The connection is closed." At line:1 char:41
+ $trans = $SqlConnection.BeginTransaction <<<< ("SampleTransaction")
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Anybody having any idea on this??
It seems that you haven't opened the connection.
Are you simply missing:
$connection.Open();
That would be my first guess.
I agree with Gisli on opening a connection. Where's the rest of your code? Another approach is to use a command object and assign the command transaction property to the command:
$cmd=new-object system.Data.SqlClient.SqlCommand($sql,$conn)
$cmd.Transaction = $transaction
This is what we do in the adolib module which is part of SQL Server Powershell Extensions. Check out Modules\adolib\adolib.psm1.

Exception automating Excel 2007 with Powershell when calling Workbooks.Add()

The following code throws an exception in Powershell V1 (Excel 2007):
$E = New-Object -COM "Excel.Application"
$E.Visible = $True
$wb = $E.Workbooks.Add() #<<<Exception here
The error says that the format might be old or that the type library is not valid (translated from Spanish). A similar script for Word works just fine.
Office interop assemblies seem to have this problem when the current culture is not en-US. The obvious workaround is to set the culture.
It's important to run the whole thing as a single command on the interactive console, since PowerShell V1 always creates a new thread for each command invocation.
PS C:\Users\jachymko> $e = new-object -com excel.application
PS C:\Users\jachymko> $e.workbooks.add()
Exception calling "Add" with "0" argument(s): "Old format or invalid type library. (Exception from HRESULT: 0x80028018 (TYPE_E_INVDATAREAD))"
At line:1 char:17
+ $e.workbooks.add <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
PS C:\Users\jachymko> & {
>> [threading.thread]::CurrentThread.CurrentCulture = 'en-US'
>> $e = new-object -com excel.application
>> $e.workbooks.add()
>> $e.visible=1
>> }
>>
Adapted to Powershell from one of the solutions proposed in MS Help and Support Article 320369.
$ci = new-object system.globalization.cultureinfo "en-US"
$e = New-Object -COM "Excel.Application"
$e.Visible = $True
$e.UserControl= $True
$books = $e.Workbooks
$books.PSBase.GetType().InvokeMember( `
"Add", `
[system.reflection.bindingflags]::InvokeMethod, `
$null, $books, $null, $ci)
From the same article:
When you use one of these workarounds for a computer where the regional settings
do not match the current language version of Office, you should be familiar with
how Excel behaves and how Excel will interpret data that might be formatted for
a specific locale.
I had this issue when trying to open a workbook. I added this line:
[threading.thread]::CurrentThread.CurrentCulture = 'en-US'