Creating a directory shortcut in powershell - powershell

I'm writing my first powershell script and I'm having a little trouble.
Up to this point my system creates a directory tree and populates it with files. The final step is to put a shortcut on my desktop.
I've come up with the code below:
$ShortcutFile = "$home\Desktop\" + $protocol + ".lnk"
If ( (test-path -path "$ShortcutFile") -ne $true)
{
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
$Shortcut.TargetPath = $root_path
$Shortcut.Save()
}
This doesn't work as I'm sure any experienced powershell user knows. A file is created rather than a directory. I imagine the correct way to fix this is to change one of the object members in WScript.Shell which control's the file type. I have had no luck locating any resources on how to do this specifically, or any other way to go about doing it. I found the API on the MSDN website but there where only a few members listed. There must be more.
What is the best way to accomplish this?
Thanks

New-Item -itemtype symboliclink -Path "PathWhereYouWantToPutShortcut" -name "NameOfShortcut" -value "PathOfWhatYourTryingToLinkTo"
New-Item Documentation

Assuming that you mean the shortcut type is a File rather than a File folder then a workaround is to make an Application launcher instead, which always works.
I originally found this solution here.
$wsshell = New-Object -ComObject WScript.Shell
$lnk = $wsshell.CreateShortcut($ShortcutFile)
$lnk.WindowStyle = 1
$lnk.TargetPath = "explorer.exe"
$lnk.Arguments = $TargetPath
$lnk.IconLocation = "explorer.exe,0"
$lnk.save() # This will overwrite the previous link if it existed

I experienced this when creating a shortcut to a directory that didn't exist. If I simply created the directory ahead of time, then the shortcut worked correctly.

Related

ls into an extracted directory

Using PowerShell, I am downloading and extracting a file that has a directory and another file in it (it's basically from https://aka.ms/downloadazcopy-v10-windows). I'd like to be able to get into the directory after extraction.
So, in PS, I am at c:\AzCopyTest while downloading the file. It is being extracted at the same location. Here's the code for it:
$URL = "https://aka.ms/downloadazcopy-v10-windows"
New-Item -ItemType Directory -Path c:\AzCopyTest
$Destination = "c:\AzCopyTest\zzz.zip"
$WebClient = New-Object -TypeName System.Net.WebClient
$WebClient.DownloadFile($URL, $Destination).
$ExtractLocation = "c:\AzCopyTest"
$ExtractShell = New-Object -ComObject Shell.Application
$file = $ExtractShell.NameSpace($Destination).Items()
$ExtractShell.NameSpace($ExtractLocation).CopyHere($file)
How can I get into the folder after the extraction is done? FYI, I don't want to ls into it directly (or manually instead). I'd like to be able to list out the items in that directory and get the first directory. azcopy_windows_amd64_10.3.4 is what the directory called BTW. Now, when MS realease a new version (say 10.3.5), the directory will be renamed, and I do not want to go back in and manually change it. You get where I am going with this..
I know Get-ChildItem -Path ("$ExtractLocation") -Recurse will list the items in the directory and the sub-directories. But it does not server my purpose unfortunately.
Any help is greatly appreciated!
I tried this:
Get-ChildItem -Path $ExtractLocation -Recurse -Directory -Force -ErrorAction SilentlyContinue | Select-Object).Name and it worked.
FYI, at a later time, if MS decided to add another directory in the zipped file, you can simple do this:
Get-ChildItem -Path $ExtractLocation -Recurse -Directory -Force -ErrorAction SilentlyContinue | Select-Object).Name[<position_of_the_directory_starting_from_0]

Powershell FolderBrowserDialog Can't select external shares

So I have a working Windows.Forms.FolderBrowserDialog function for Folder selection in my Script.
I noticed Today that I can't any external Shares or even see them with it.
Is there another function for that or is there some special attribute I have to set to see external Shares?
How do you mean "external"? It will see mapped drives and anything in the "Network" folder, though bear in mind that local network discovery could be disabled in the OS and you'd have to enable this in Windows
If you run this with a UNC folder path it should open the browser in that folder:
$RootFolder = '\\myserver\myfoldername'
$FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog
$FolderBrowser.Description = 'Select a folder'
$FolderBrowser.ShowNewFolderButton = $false
$FolderBrowser.SelectedPath = $RootFolder
$result = $FolderBrowser.ShowDialog((New-Object System.Windows.Forms.Form -Property #{TopMost = $true }))

Working with shortcuts (ReleaseComObject?)

I have to mass-change shortcuts (.lnk) with PowerShell in an enterprise environment.
Users maybe have wrong shortcuts on their desktop. The desktop folder is located on our central storage. I need to correct them, if the shortcuts have wrong arguments. I am talking about 5.000 users.
My code is ready and working fine. It is based on some examples I found on Google.
In some examples I did see something like:
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ShortcutObject)
I don't know what this is for?
Broken down the relevant part of my code looks like this:
$UserShortcuts = Get-ChildItem -Path "MyFolder" -ChildPath "SmithJ\Desktop") -Filter *.lnk |
Where-Object Name -Match "MyShortcut"
foreach ($UserShortcut in $UserShortcuts) {
$sh = New-Object -ComObject WScript.Shell
$ShortcutObject = $sh.CreateShortcut($($UserShortcut.FullName))
$ShortcutObject.Arguments
# ...
}
What about the ReleaseComObject()?
Do I have to do this after every object?
It is working without. Do I have to use it?
EDIT:
With the information of Bill_Stewart I think it would be correct like this:
$UserShortcuts = Get-ChildItem -Path "MyFolder" -ChildPath "SmithJ\Desktop") -Filter *.lnk |
Where-Object Name -Match "MyShortcut"
$sh = New-Object -ComObject WScript.Shell
foreach ($UserShortcut in $UserShortcuts) {
$ShortcutObject = $sh.CreateShortcut($($UserShortcut.FullName))
$ShortcutObject.Arguments
# ...
}
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($sh)
According to the documentation:
Therefore, use the [sic] ReleaseComObject only if it is absolutely required.
Implicit in this sentence is that you have an understanding of the technical details of how managed code (in this case, PowerShell, which uses .NET) uses COM objects.
For PowerShell scripts calling scripting runtime COM objects (such as WshShell, WshShortcut, WshUrlShortcut, etc.), there is no need to use ReleaseComObject as the .NET runtime (CLR) will automatically release them when they are no longer in use.
This is not necessarily the case with all COM objects when automated from PowerShell, but for scripting runtime objects releasing is unnecessary.

Outlook Signature Script not showing

I have a script that creates a .htm and .txt file in the %appdata%\Microsoft\Signatures folder.
I set the signature via registry using:
NEW-ITEMPROPERTY HKCU:'\Software\Microsoft\Office\15.0\Common\MailSettings' -Name 'NewSignature' -Value $SignatureName -PropertyType 'String' -Force
NEW-ITEMPROPERTY HKCU:'\Software\Microsoft\Office\15.0\Common\MailSettings' -Name 'ReplySignature' -Value $SignatureName -PropertyType 'String' -Force
Everything appears to work except the signature does not show in the compose window by default. It will let me add it manually.
If I open up the signature settings area within Outlook, make zero changes (I couldn't if I wanted as it is greyed out) and then close it, the signature starts showing automatically in emails again.
What am I missing? What does opening then closing the signature window do?
You can use functions within Word to set default signature for new e-mails and replies. Try this:
$Word = New-Object -ComObject Word.Application
$EmailOptions = $Word.EmailOptions
$Signature = $EmailOptions.EmailSignature
$Signature.NewMessageSignature = $SignatureName
$Signature.ReplyMessageSignature = $SignatureName
$Word.Quit()
Should anyone else come into this issue it was solved by deleting a registry entry.
REMOVE-ITEMPROPERTY -path "HKCU:\Software\Microsoft\Office\15.0\Outlook\Setup\" -name "First-Run"
Adding this in and having it run while Outlook is closed fixed the issue

Use PowerShell to generate a list of files and directories

I'm writing a PowerShell script to make several directories and copy a bunch of files together to "compile" some technical documentation. I'd like to generate a manifest of the files and directories as part of the readme file, and I'd like PowerShell to do this, since I'm already working in PowerShell to do the "compiling".
I've done some searching already, and it seems that I need to use the cmdlet "Get-ChildItem", but it's giving me too much data, and I'm not clear on how to format and prune out what I don't want to get my desired results.
I would like an output similar to this:
Directory
file
file
file
Directory
file
file
file
Subdirectory
file
file
file
or maybe something like this:
+---FinGen
| \---doc
+---testVBFilter
| \---html
\---winzip
In other words, some kind of basic visual ASCII representation of the tree structure with the directory and file names and nothing else. I have seen programs that do this, but I am not sure if PowerShell can do this.
Can PowerShell do this? If so, would Get-ChildItem be the right cmdlet?
In your particular case what you want is Tree /f. You have a comment asking how to strip out the part at the front talking about the volume, serial number, and drive letter. That is possible filtering the output before you send it to file.
$Path = "C:\temp"
Tree $Path /F | Select-Object -Skip 2 | Set-Content C:\temp\output.tkt
Tree's output in the above example is a System.Array which we can manipulate. Select-Object -Skip 2 will remove the first 2 lines containing that data. Also, If Keith Hill was around he would also recommend the PowerShell Community Extensions(PSCX) that contain the cmdlet Show-Tree. Download from here if you are curious. Lots of powerful stuff there.
The following script will show the tree as a window, it can be added to any form present in the script
function tree {
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
# create Window
$Form = New-Object System.Windows.Forms.Form
$Form.Text = "Files"
$Form.Size = New-Object System.Drawing.Size(390, 390)
# create Treeview-Object
$TreeView = New-Object System.Windows.Forms.TreeView
$TreeView.Location = New-Object System.Drawing.Point(48, 12)
$TreeView.Size = New-Object System.Drawing.Size(290, 322)
$Form.Controls.Add($TreeView)
###### Add Nodes to Treeview
$rootnode = New-Object System.Windows.Forms.TreeNode
$rootnode.text = "Root"
$rootnode.name = "Root"
[void]$TreeView.Nodes.Add($rootnode)
#here i'm going to import the csv file into an array
$array=#(Get-ChildItem -Path D:\personalWorkspace\node)
Write-Host $array
foreach ( $obj in $array ) {
Write-Host $obj
$subnode = New-Object System.Windows.Forms.TreeNode
$subnode.text = $obj
[void]$rootnode.Nodes.Add($subnode)
}
# Show Form // this always needs to be at the bottom of the script!
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
}
tree
In Windows, navigate to the directory of interest
Shift+ right click mouse -> Open PowerShell window here
Get-ChildItem | tree /f > tree.log
The best and clear way for me is:
PS P:\> Start-Transcript -path C:\structure.txt -Append
PS P:\> tree c:\test /F
PS P:\> Stop-Transcript
You can use command Get-ChildItem -Path <yourDir> | tree >> myfile.txt this will output tree-like structure of a directory and write it to "myfile.txt"