0

I am not able to load Icon when accessing from a network share drive in powershell

$IconPath =  $pwd.Path + "\Icons\InstallIcon-F.ico"
$HFForm.icon = [System.Drawing.Icon]::ExtractAssociatedIcon($IconPath) 

I am getting this error:

Exception calling "ExtractAssociatedIcon" with "1" argument(s): "The given path's format is not supported."
 $HFForm.icon = [System.Drawing.Icon]::ExtractAssociatedIcon <<<< ($IconPath)

  + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
  + FullyQualifiedErrorId : DotNetMethodException
BSAFH
  • 725
  • 3
  • 6
  • 19
swatish
  • 11
  • 1
  • 4
  • 1
    `System.Drawing.Icon.ExtractAssociatedIcon()` is not supposed to work for UNC paths like (\\server\path), but I'm getting a different error for using an UNC path: `\\server\path' is not valid for 'filePath'."`. It could be just a different message for a different PowerShell version, though. Are you sure that $pwd.Path is a valid path? Is it in UNC format? – PeterK Jul 18 '14 at 11:55
  • Yes I am sure the path is valid, I have checked the same number of times. I am getting this exception of "not valid 'filePath'." if I try to combine the $IconPath in a different way. But the issue is still the same as the from the network drive icon is not getting loaded. – swatish Jul 21 '14 at 03:44
  • Unfortunately, this is a limitation of the `ExtractAssociatedIcon()` method in the .NET framework. The thread at http://stackoverflow.com/questions/1842226/how-to-get-the-associated-icon-from-a-network-share-file suggests that you use P/Invoke to interface with the Windows Shell API directly as a workaround. You can import much of that example code without changes using inlined C# (see `Add-Type` and examples at http://technet.microsoft.com/en-us/library/hh849914.aspx). – PeterK Jul 21 '14 at 05:43

3 Answers3

0

My testing shows the same as PeterK's. If I use a drive letter its fine, but an unmapped network share is not.

I was able to make it work by mapping the network share to a drive letter. So:

 $something = [system.drawing.icon]::extractassociatedicon("c:\windows\system32\notepad.exe")

caused no errors. Neither did:

 $something = [system.drawing.icon]::extractassociatedicon(($test.fullname))

with $test.fullname just being a mapped network file path.

It is a good idea to expand out your variables too so we can see what you're actually passing in. Because if I browse to a network file share and expand $pwd.path:

Microsoft.PowerShell.Core\FileSystem::\\user-pc\users

You are almost certainly passing that in. So have a look. I haven't done much with how Powershell formats its display so I'm sure you can find the 'tty' equiv settings, but just in the meantime do this:

$IconPath =  $pwd.Path.split('::')[2] + "\Icons\InstallIcon-F.ico"
BSAFH
  • 725
  • 3
  • 6
  • 19
  • Mapping the network drive is solving the issue. But I can't do the same. On changing the $IconPath also, it is not getting fixed. Please let me know what else I can do in order to fix the same – swatish Jul 21 '14 at 03:41
  • Please show me the value of $IconPath. Make sure its the actual output not the output that you're expecting. At the end of my answer I pointed out that browsing a network share in powershell adds "Microsoft.PowerShell.Core\FileSystem::" into the $pwd variable. But that might not be the case for you. We wont know until we see the value of $IconPath. – BSAFH Jul 21 '14 at 04:51
0

Convert your icon to a base64 representation of it's binary data, then store it inside the script itself (as text).

Once it's encoded as base64, you can use this command to convert it back into an icon, bypassing the UNC path issue.

$HFForm.icon = [System.Convert]::FromBase64String('
AAABAAkAAAAAAAEAIABbfQEAlgAAAICAAAABACAAKAgBAPF9AQBgYAAAAQAgAKiUAAAZhgIASEgA
#
#  There will be hundreds rows depending on your icon's size.
#  
AMADAADAAwAA4AcAAPAPAADwDwAA+A8AAPgPAAD4DwAA/B8AAPwfAAA=')

BASE64 snippet.

#Be sure to edit the path to icon.
#
#Hint the result is copied to your clipboard - clip = clip.exe == google it.

$path = "A:\R2-D2-32x32.ico"
[convert]::ToBase64String((get-content $path -encoding byte)) | Clip

#After running the clip command, right click paste between the quotes

$HFForm.icon = [System.Convert]::FromBase64String('')
Knuckle-Dragger
  • 6,644
  • 4
  • 26
  • 41
  • ok..can you please let me know as to how can i convert .ico file to base64 representation of binary data – swatish Jul 22 '14 at 06:35
  • It is giving me an exception as Exception setting "Icon": "Cannot convert value "System.Byte[]" to type "System.Drawing.Icon". Error: "Argument 'picture' must be a picture that can be used as a Icon."" $HFForm. <<<< icon = [System.Convert]::FromBase64String($base64String) + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : PropertyAssignmentException – swatish Jul 24 '14 at 05:54
0

i have a solution for it.

At first you have to import the SHGetFileInfo Methode and create the structure SHFILEINFO.

$code = @"
using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace System
{
   [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct SHFILEINFO
        {
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
};
    public class SHGETFILEINFO
    {
     [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
     public static extern IntPtr SHGetFileInfo(string pszPath, uint     dwFileAttributes,ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
    }
}
"@

Add-Type -TypeDefinition $code 

Creates the structure object.

#Path to the exe.
$Path = \\test.de\tes
[System.SHFILEINFO]$FileinfoStruct = New-Object System.SHFILEINFO

Gets the size of the structure

$Size = [System.Runtime.InteropServices.Marshal]::SizeOf($FileinfoStruct)

Gets fills the structure Variable with the File infos.

[System.SHGETFILEINFO]::SHGetFileInfo($Path,0,    [ref]$FileinfoStruct,$Size,0x000000100)

Creates the icon.

$ICON = [System.Drawing.Icon]::FromHandle($FileinfoStruct.hIcon)
Jannik.M
  • 1
  • 5