I have a desktop application written in c#, and this application enables users to create the folder on their machine Hard drive . on windows 7 and 8, The App creates a shortcut for this folder under Favorit menu on the left side of windows Explorer window.
In windows 10 there is no Favorite menu, it was replaced by Quick access menu, and if you right click on the folder you can choose to Pin folder for quick access.
To do this programmatically from inside c# code, I found a .exe that can execute the Pin action as if the user clicked on the menu item to pin the folder
I got it from here http://www.maddogsw.com/cmdutils/
The problem is this exe does not contain an option for Unpin the folder from quick access so i will not be able to remove the shortcut from the quick access menu unless if I deleted it and I don't want to do that.
I tried to find the shortcut file and I found it in this path
%AppData%\Windows\Recent\AutomaticDestinations
but there is no mapping between this file shortcut and the file itself. and at the same time when I delete the files from this path, all the Pinned folders shortcut delete from the quick access not only my shortcut.
anyone can help in this ??
Do I need to know if there is any command that I can use it to Pin\Unpin folders to quick access from the command prompt?
I know it's a bit late, but I've found a way to do it and thought maybe someone could still use this.
So as was mentioned by Bradley Uffner, there is no API for this to avoid the constant abuse of such APIs. But there is still a (rather ugly) way to do it!
I'm no expert in PowerShell, but I found a way to do it using PowerShell:
# To add 'C:\path\to\folder' to quick access:
$qa = New-Object -ComObject shell.application
$qa.NameSpace('C:\path\to\folder').Self.InvokeVerb("pintohome")
# To remove 'C:\path\to\folder' from quick access:
($qa.Namespace("shell:::{679F85CB-0220-4080-B29B-5540CC05AAB6}").Items() | Where-Object { $_.Path -EQ 'C:\path\to\folder' }).InvokeVerb("unpinfromhome")
Which finally led me to the solution using C#:
using System.Management.Automation;
using System.Management.Automation.Runspaces
private static void AddFolderToQuickAccess(string pathToFolder)
{
using (var runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
var ps = PowerShell.Create();
var shellApplication =
ps.AddCommand("New-Object").AddParameter("ComObject", "shell.application").Invoke();
dynamic nameSpace = shellApplication.FirstOrDefault()?.Methods["NameSpace"].Invoke(pathToFolder);
nameSpace?.Self.InvokeVerb("pintohome");
}
}
private static void RemoveFolderFromQuickAccess(string pathToFolder)
{
using (var runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
var ps = PowerShell.Create();
var removeScript =
$"((New-Object -ComObject shell.application).Namespace(\"shell:::{{679f85cb-0220-4080-b29b-5540cc05aab6}}\").Items() | Where-Object {{ $_.Path -EQ \"{pathToFolder}\" }}).InvokeVerb(\"unpinfromhome\")";
ps.AddScript(removeScript);
ps.Invoke();
}
}
NOTE: For this to work, you need to add a reference to System.Management.Automation which can easily be obtained as a nuget.
Related
I am using OperationsManager module to work with SCOM, I need to find the somemanagementpack.mpb file information from SCOM which is already imported in SCOM an than need to delete the same somemanagementpack.mpb file locally based on the version
Below is the command I am using
Import-Module "OperationsManager"
New-SCOMManagementGroupConnection -ComputerName "DEVSCOM"
$mp = Get-SCManagementPack -BundleFile C:\Temp\somemanagementpack.mpb
$version = $mp.Version
$localVersion = "1.0.0.0"
if($version -gt $localVersion)
{
Remove-Item "C:\Temp\somemanagementpack.mpb" -Force
}
but when I am trying to remove it getting below error, I have also tried using Dispose method but nothing happens
The action can't be completed because the file is open
SCOM is locking the file. The only way to get it to stop is to kill the PowerShell process.
As a workaround I recommend making a copy of each file first to another directory. Have your script get the version from the copy. Then delete the original file that won't be locked if it matches your criteria. After you are done close the PowerShell window and delete the directory with all the copied files.
Import-Module "OperationsManager"
New-SCOMManagementGroupConnection -ComputerName "DEVSCOM"
Copy-Item C:\Temp\somemanagementpack.mpb C:\Temp\Copy\somemanagementpack.mpb
$mp = Get-SCManagementPack -BundleFile C:\Temp\Copy\somemanagementpack.mpb
$version = $mp.Version
$localVersion = "1.0.0.0"
if($version -gt $localVersion)
{
Remove-Item "C:\Temp\somemanagementpack.mpb" -Force
}
As you can see only the copy gets locked
If I create a file called "dir.exe" and run PowerShell command Get-Command dir -Type Application, I get and error because dir is not an application (although that file exists):
gcm : The term 'dir' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:2
+ (gcm dir -Type Application)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (dir:String) [Get-Command], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand
Suggestion [3,General]: The command dir was not found, but does exist in the current location. Windows PowerShell does not load commands from the current location by default. If you trust this command, instead type: ".\dir". See "get-help about_Command_Precedence" for more details.
Notice the Suggestion at the bottom: Suggestion [3,General]: The command dir was not found, but does exist in the current location. Windows PowerShell does not load commands from the current location by default. If you trust this command, instead type: ".\dir". See "get-help about_Command_Precedence" for more details.
I'm trying to catch that suggestion in my C# code:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Automation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Helpers.Tests {
[TestClass]
public class PowerShellRunner_Tests {
[TestMethod]
public void GetCommand_Test() {
// create file called "dir.exe" to see how PowerShell handles
// "Get-Command dir -Type Application":
File.Create("dir.exe").Dispose();
using (PowerShell powerShell = PowerShell.Create()) {
powerShell.AddCommand("get-command")
.AddArgument("dir")
.AddParameter("Type", CommandTypes.Application.ToString());
// run "Get-Command dir -Type Application":
CommandInfo commandInfo = powerShell.Invoke<CommandInfo>().FirstOrDefault();
// get the error:
ErrorRecord error = powerShell.Streams.Error.FirstOrDefault();
// emit the "Suggestion":
Trace.WriteLine(error.ErrorDetails.RecommendedAction);
}
}
}
}
However error.ErrorDetails is null. How can I get that Suggestion?
(I'm trying to get the behavior of where.exe but without the hassle of running a whole process for that).
Given that the end goal is to emulate where.exe's behavior, try the following:
(Get-Command -Type Application .\dir, dir -ErrorAction Ignore).Path
Note the use of -Type Application to limit results to executables and exclude PowerShell-internal commands such as function and aliases.
This will look in the current directory first, as where.exe does.
Give a mere name such as dir, Get-Command doesn't look in the current directory, because PowerShell does not permit invoking executables located in the current directory by name only - for security reasons; using relative path .\, however, makes Get-Command find such an executable.
From cmd.exe, however - whose behavior where.exe assumes - invoking a current-directory-only dir.exe with just dir (by name only) works fine.
If the output is just one path, and that path is a file in the current directory, you can infer that the dir executable exists only in the current directory, which is the condition under which PowerShell emits the suggestion to use an explicit path on invocation.
$fullPaths = (Get-Command -Type Application .\dir, dir -ErrorAction Ignore).Path
$emitSuggestion = $fullPaths.Count -eq 1 -and
(Test-Path ('.\' + (Split-Path -Leaf $fullPaths[0]))
Note: Strictly speaking, you'd also to have rule out the case where the current directory just so happens be one that is listed in $env:PATH:
$env:PATH -split ';' -ne '' -notcontains (Split-Path -Parent $fullPaths[0])
You can report that to your C# code by writing a custom version of the suggestion to the error stream via Write-Error, or, preferably, to the warning stream, with Write-Warning.
To use the above commands via the PowerShell SDK, it's simplest to use the .AddScript() method; e.g.:
powerShell.AddScript("(Get-Command -Type Application .\dir, dir -ErrorAction Ignore).Path");
As for capturing or silencing PowerShell's suggestions:
Unfortunately, you cannot gain access to suggestions programmatically (written as of Windows PowerShell v5.1 / PowerShell Core 6.1.0):
Using the PowerShell SDK, as you do, involves the PowerShell default host, which fundamentally doesn't emit suggestions.
It is only the console host, as used in console (terminal) windows that emits suggestions, but even there suggestions are printed directly to the screen, bypassing PowerShell's system of output streams.
In short: Suggestions only show in console windows (terminals), and can only be viewed, not captured there.
A quick demonstration of the behavior of suggestions in a console window (assumes Windows, with a file named dir.exe in the current dir and not also in $env:PATH):
PS> & { try { Get-Command dir.exe } catch {} } *>$null
Suggestion [3,General]: The command dir.exe was not found, but does exist in the current location. Windows PowerShell does not load commands from the current location by default. If you trust this command, instead type: ".\dir.exe". See "get-help about_Command_Precedence" for more details.
As you can see, despite the attempt to suppress all output (*>$null), the suggestion still printed to the screen, which also implies that you cannot capture suggestions.
However, there is a way to silence suggestions, namely with -ErrorAction Ignore (PSv3+); by contrast, with -ErrorAction SilentlyContinue the suggestion still prints(!):
PS> & { try { Get-Command dir.exe -ErrorAction Ignore } catch {} } *>$null
# no output
I want to execute the power shell logic using c#(web application) but i'm getting the issue
The term 'git' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
I have added the git path in environmental variables and able to execute the same powershell logic from powershell window without any issues.
My powershell script:
function CheckoutTheCode($checkoutRepoUrl, $checkoutDirectory, $checkoutBranch)
{
[hashtable]$Return = #{}
try
{
# Cloning
git clone --single-branch -b $checkoutBranch $checkoutRepoUrl $checkoutDirectory
$Return.Status = $true
$Return.Message = "Success"
}
catch
{
$Return.Message = $Error[0].Exception
$Return.Status = $false
}
Return $Return
}
$checkoutDirectory = "local directory for checkout"
$checkoutRepoUrl = "bit bucket repo url"
$checkoutBranch = "branch version"
CheckoutTheCode $checkoutRepoUrl $checkoutDirectory $checkoutBranch
My c# code:
using (PowerShell PowerShellInstance = PowerShell.Create())
{
PowerShellInstance.AddScript("PowerShell script");
Collection<PSObject> PSOutput = PowerShellInstance.Invoke();
}
In My case the issue is I have added the system environment variable after the c# web application is opened in visual studio.
When i have closed the visual studio and opened again, it's working fine.
I want a WPF button that will open explorer.exe in Windows 7|8 directly into the "Recycle Bin". This is because my app erases a lot of files, and I want to provide the user with a quick way to restore files. The command line arguments don't work, possibly because the "Recycle Bin" is a virtual directory. I have tried using "$Recycle Bin". Explorer.exe /root, where a is a virtual file fails. Trying to protect the space in Recycle\ Bin does not seem to work as well.
Here is working code from Scott Powell that I tested and am using.
Thank you Scott#
private void ExploreTrashBin ( )
{
String str_RecycleBinDir = String.Format(#"C:\$Recycle.Bin\{0}", UserPrincipal.Current.Sid);
Process . Start ( "explorer.exe" , str_RecycleBinDir );
}
private void TrashBin_Button_Click ( object sender , RoutedEventArgs e )
{
ExploreTrashBin ( );
}
You could execute following command in order to achieve this,
start shell:RecycleBinFolder
From your C# code you could use,
System.Diagnostics.Process.Start("explorer.exe", "shell:RecycleBinFolder");
It is already implemented in Microsoft.VisualBasic.FileIO.FileSystem class in .Net (so C# natively supports the use of this).
This way, you don't need run shell command : just delete files/folders programmatically as if done interactively with Windows Explorer!
using Microsoft.VisualBasic.FileIO;
FileSystem.DeleteFile(...)
FileSystem.DeleteDirectory(...)
Recycle Bin is located in a hidden directory named \$Recycle.Bin\%SID%, where %SID% is the SID of the user that performed the deletion.
So based off of this, we can do:
Add a .NET reference to System.DirectoryServices.AccountManagement
string str_RecycleBinDir = UserPrincipal.Current.Sid;
Process.Start("explorer.exe","C:\$Recycle.Bin\" + str_RecycleBinDir);
Should be able to now access the proper Recycle Bin directory based off user account that is running. Working in Windows 7 (tested).
In C#, How Could I go about checking for device and systems errors? Would it be simple to use PowerShell Scipts, or would that add to the complexity and difficulty?
For Windows 7 clients check out the Windows Troubleshooting Platform. Here is a download on it with more details. It uses PowerShell scripts to do exacty what you're talking about. This blog post shows how to author a troubleshooting pack - it's pretty easy.
I don't think WTP works on downlevel platforms. In this case, I would just write some PowerShell scripts to detect and fix root causes. If you want to wrap that up in a nice UI, check out PowerBoots - an easy way to create a WPF GUI on top of your script. If you want to host PowerShell in your on C#-based GUI it is very simple. Here's a code snippet from a Forms app:
private void button1_Click(object sender, EventArgs e)
{
string cmd = #"Get-ChildItem $home\Documents -recurse | " +
"Where {!$_.PSIsContainer -and " +
"($_.LastWriteTime -gt (Get-Date).AddDays(-7))} | " +
"Sort Fullname | Foreach {$_.Fullname}";
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
using (Pipeline pipeline = runspace.CreatePipeline(cmd))
{
this.Cursor = Cursors.WaitCursor;
pipeline.Commands.AddScript(cmd);
Collection<PSObject> results = pipeline.Invoke();
foreach (PSObject obj in results)
{
listBox1.Items.Add(obj);
}
this.Cursor = Cursors.Default;
}
}
}
You need to add a reference to the System.Management.Automation assembly. If you have installed the Windows/.NET SDK that should be in ProgramFiles\ReferenceAssemblies\Microsoft\WindowsPowerShell\v1.0. You will also need a couple of using statememets:
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;