# EncryptedPIDL \[SOLVED\]

**URL:** <https://forums.powershell.org/t/encryptedpidl-solved/1108>\
**Category:** PowerShell Help\
**Created:** [December 31, 2011, 6:30pm UTC](https://forums.powershell.org/t/encryptedpidl-solved/1108 "2011-12-31T18:30:00Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![archives](https://avatars.discourse-cdn.com/v4/letter/a/bb73d2/32.png) [@archives](https://forums.powershell.org/u/archives)\
**Post date:** [December 31, 2011, 6:30pm UTC](https://forums.powershell.org/t/encryptedpidl-solved/1108/1 "2011-12-31T18:30:00Z")

</div>

by SalvaG at 2013-03-11 06:22:28

> Hi all,  
> I’m trying to create an script to modify the path of photo screensaver. The EncryptedPIDL key has the Base64 encrypted value of the PIDL, but I cannot decode it.  
> I’m using CryptBinaryToString and CryptStringToBinary to encrypt/decrypt the path, but it seems I’m doing something worng (I never used c#)  
>   
> AFAIK, I have to do this (source [http://www.ms-windows.info/Help/windows … 19334.aspx](http://www.ms-windows.info/Help/windows-photo-screensaver-settings-19334.aspx)):  
> For encrypting : Read Path -\> Get PIDL -\> use CryptBinaryToString   
> For decrypting : For encrypting : Use CryptStringToBinary -\> Get PIDL -\> Read Path   
>   
> For testing, I’m trying to decode an string to get the original path, but i’m crashing the ISE on every test …  
>   
> Anyone has do it before?  
>   
> Here is my code  
> `add-type -Language CSharp @"using System;using System.Diagnostics;using System.Runtime.InteropServices;public class CRYPT_STRING_FLAGS{ public const uint CRYPT_STRING_BASE64 = 1;}public class PIDLUtils {	//for encoding	[DllImport("Shell32.dll")]	public static extern long SHParseDisplayName (string szPath); //for decoding	[DllImport("Shell32.dll")]	public static extern string SHGetPathFromIDList (long pidl); //http://msdn.microsoft.com/en-us/library/aa380285&#40;v=vs.85&#41;.aspx	//BOOL WINAPI CryptStringToBinary	//(	// In LPCTSTR pszString,	// In DWORD cchString,	// In DWORD dwFlags,	// In BYTE pbBinary,	// Inout DWORD pcbBinary,	// Out DWORD pdwSkip,	// Out DWORD pdwFlags	//); [DllImport("crypt32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptStringToBinary([MarshalAs(UnmanagedType.LPWStr)] string pszString, uint cchString, uint dwFlags, out IntPtr pbBinary, ref uint pcbBinary, uint pdwSkip, uint pdwFlags); }"@try{	$encrypted = "FAAfUOBP0CDqOmkQotgIACswMJ0ZAC9DOlwAAAAAAAAAAAAAAAAAAAAAAAAASgAxAAAAAABcQkdmEAB0ZW1wAAA2AAgABADvvnk/sV1cQkdmKgAAAPuSAQAAAAgAAAAAAAAAAAAAAAAAAAB0AGUAbQBwAAAAFAAAAA=="	$notEncrypted = "C:\temp" $arrBytes = new-object System.IntPtr	$OK = [PIDLUtils]]]$arrBytes, [ref]$arrBytes.length, 0, 0)	if ($ok)	{ $arrBytes	}	else	{ "error"} break}catch{	$	break}`  
>   
> _Thanks_

_by MattG at 2013-03-12 03:52:03_

_> Are you asking how to convert Base64 (which is not encryption, btw :D) to a byte array? If that’s the case then you can convert all your code into a two-liner:  
> `$encoded = "FAAfUOBP0CDqOmkQotgIACswMJ0ZAC9DOlwAAAAAAAAAAAAAAAAAAAAAAAAASgAxAAAAAABcQkdmEAB0ZW1wAAA2AAgABADvvnk/sV1cQkdmKgAAAPuSAQAAAAgAAAAAAAAAAAAAAAAAAAB0AGUAbQBwAAAAFAAAAA=="$unencodedBytes = [Convert]::FromBase64String($encoded)# Optionally, print out the bytes# ($unencodedBytes | % { [Char]$`` }) -join ''`_

_by SalvaG at 2013-03-12 05:26:33_

_> Hi Matt  
>   
> what I’m trying to do is to be able from Powershell to change the Photo screen saver path. This path is encryted / must be encrypted using CryptBinaryToString or CryptStringToBinary functions.   
> For the example, $encoded value is what CryptBinaryToString returns from encoding the PIDL assigned to C:\temp, and YES : it is encrypted and encoded using Base64 without headers.  
>   
> How it works? I think it works like this :   
>   
> For encoding : Path in clear text (i.e. c:\temp) -\> PIDL = PathToPIDL (Path) ( using function ??) -\> EncryptedPath = CryptBinaryToString (PIDL)  
> For decoding : Encrypted path (i.e. the $encoded value) -\>PIDL = CryptStringToBinary (EncryptedPath) -\> Path in clear text = PIDLToPath (PIDL) (using SHGetPathFromIDList function?  
>   
> All of this I think have to be made using c# or any compatible language for using with add-type cmdlet, but no idea for doing it.  
> Any idea?  
>   
> Thanks!!!_

_by SalvaG at 2013-03-14 01:09:27_

_> A friend of mine helped me for getting this. Here i share the code for all, like me, who need it.  
>   
> `cls#That string is encoded in Base64, without headers. There is a Windows API that encrypt binary arrays (the PIDL) to Base64, CryptBinaryToString. The dwFlags parameter should be set to CRYPT_STRING_BASE64.#Our problem is the inverse, given a Base64 string (the encoded PIDL), get the decoded PIDL. There's an API for that, too!, CryptStringToBinary. The dwFlags parameter should also be set to CRYPT_STRING_BASE64.#I think it is not hard to write a small program that uses those API's (and some more to get a "readable" path from the PIDL); ask in the MSDN forums to get directions if you get stuck.#Félicitations ! Votre domaine a bien été créé chez OVHcloud !#http://msdn.microsoft.com/en-us/library/aa379887&#40;v=vs.85&#41;.aspx#BOOL WINAPI CryptBinaryToString(# In const BYTE pbBinary,# In DWORD cbBinary,# In DWORD dwFlags,# Out_opt LPTSTR pszString,# Inout DWORD pcchString#);#http://msdn.microsoft.com/en-us/library/aa380285&#40;v=vs.85&#41;.aspx#BOOL WINAPI CryptStringToBinary(# In LPCTSTR pszString,# In DWORD cchString,# In DWORD dwFlags,# In BYTE pbBinary,# Inout DWORD pcbBinary,# Out DWORD pdwSkip,# Out DWORD pdwFlags#);add-type -Language CSharp @"using System;using System.Text;using System.Runtime.InteropServices;using System.Text.RegularExpressions;public static class PIDLUtils{ // funciones [DllImport("shell32.dll")] public static extern Int32 SHGetDesktopFolder(out IShellFolder ppshf); [DllImport("shell32.dll")] public static extern bool SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath); [DllImport("crypt32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CryptBinaryToString(IntPtr pcbBinary, int cbBinary, uint dwFlags, StringBuilder pszString, ref int pcchString); [DllImport("crypt32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CryptStringToBinary(string pszString, int cchString, uint dwFlags, IntPtr pbBinary, ref int pcbBinary, ref int pdwSkip, ref int pdwFlags); // interfaces [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("000214E6-0000-0000-C000-000000000046")] public interface IShellFolder { Int32 ParseDisplayName(IntPtr hwnd, IntPtr pbc, String pszDisplayName, UInt32 pchEaten, out IntPtr ppidl, UInt32 pdwAttributes); Int32 EnumObjects(IntPtr hwnd, ESHCONTF grfFlags, out IntPtr ppenumIDList); Int32 BindToObject(IntPtr pidl, IntPtr pbc, [In]ref Guid riid, out IntPtr ppv); Int32 BindToStorage(IntPtr pidl, IntPtr pbc, [In]ref Guid riid, out IntPtr ppv); Int32 CompareIDs(Int32 lParam, IntPtr pidl1, IntPtr pidl2); Int32 CreateViewObject(IntPtr hwndOwner, [In] ref Guid riid, out IntPtr ppv); Int32 GetAttributesOf(UInt32 cidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]IntPtr[] apidl, ref ESFGAO rgfInOut); Int32 GetUIObjectOf(IntPtr hwndOwner, UInt32 cidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]IntPtr[] apidl, [In] ref Guid riid, UInt32 rgfReserved, out IntPtr ppv); Int32 GetDisplayNameOf(IntPtr pidl, ESHGDN uFlags, out ESTRRET pName); Int32 SetNameOf(IntPtr hwnd, IntPtr pidl, String pszName, ESHCONTF uFlags, out IntPtr ppidlOut); } // enumeraciones public enum ESHCONTF { SHCONTF_FOLDERS = 0x0020, SHCONTF_NONFOLDERS = 0x0040, SHCONTF_INCLUDEHIDDEN = 0x0080, SHCONTF_INIT_ON_FIRST_NEXT = 0x0100, SHCONTF_NETPRINTERSRCH = 0x0200, SHCONTF_SHAREABLE = 0x0400, SHCONTF_STORAGE = 0x0800 } public enum ESFGAO : uint { SFGAO_CANCOPY = 0x00000001, SFGAO_CANMOVE = 0x00000002, SFGAO_CANLINK = 0x00000004, SFGAO_LINK = 0x00010000, SFGAO_SHARE = 0x00020000, SFGAO_READONLY = 0x00040000, SFGAO_HIDDEN = 0x00080000, SFGAO_FOLDER = 0x20000000, SFGAO_FILESYSTEM = 0x40000000, SFGAO_HASSUBFOLDER = 0x80000000, } public enum ESHGDN { SHGDN_NORMAL = 0x0000, SHGDN_INFOLDER = 0x0001, SHGDN_FOREDITING = 0x1000, SHGDN_FORADDRESSBAR = 0x4000, SHGDN_FORPARSING = 0x8000, } public enum ESTRRET : int { eeRRET_WSTR = 0x0000, STRRET_OFFSET = 0x0001, STRRET_CSTR = 0x0002 } // constantes private const uint CRYPT_STRING_BASE64 = 1; //// // mis funciones public static string Encode(string myClearPath) { IShellFolder folder; IntPtr pidl; string Pathcodificado; Pathcodificado = "ERROR"; string myPathTextoPlano = myClearPath; // este es el folder del escritorio (raÃ­z del espacio de nombres del shell) if (SHGetDesktopFolder(out folder) == 0) { // pidl del archivo folder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, myPathTextoPlano, 0, out pidl, 0); // parseo el pidl para obtener sus tamaÃ±o int k = 0; short cb = 0; // ONLY WORKS WITH .NET FRAMEWORK 4 // while ((k = Marshal.ReadInt16(pidl + cb)) > 0) // // { // cb += (short)k; // } IntPtr tempIntPtr = new IntPtr(pidl.ToInt64() + cb); while ((k = Marshal.ReadInt16(tempIntPtr)) > 0) { cb += (short)k; tempIntPtr = new IntPtr(pidl.ToInt64() + cb); } cb += 2; // encripto el pidl StringBuilder sb = new StringBuilder(); int largo = 0; CryptBinaryToString(pidl, cb, CRYPT_STRING_BASE64, null, ref largo); sb.Capacity = largo; if (CryptBinaryToString(pidl, cb, CRYPT_STRING_BASE64, sb, ref largo)) { //Console.WriteLine(sb.ToString()); Pathcodificado = sb.ToString(); } Marshal.FreeCoTaskMem(pidl); } return Pathcodificado; } // ************************************************************************************************************************** public static string Decode (string myEncryptedPath) { IShellFolder folder; // IntPtr pidl; string PathDescodificado; PathDescodificado = "ERROR"; string mypathEncriptado = myEncryptedPath; // este es el folder del escritorio (raÃ­z del espacio de nombres del shell) if (SHGetDesktopFolder(out folder) == 0) { // Desencripto int a = 0; int b = 0; int largo = 0; //CryptStringToBinary(sb.ToString(), sb.Length, CRYPT_STRING_BASE64, IntPtr.Zero, ref largo, ref a, ref b); CryptStringToBinary(mypathEncriptado, mypathEncriptado.Length, CRYPT_STRING_BASE64, IntPtr.Zero, ref largo, ref a, ref b); // recreo el objeto IntPtr pidl2 = Marshal.AllocCoTaskMem(largo); StringBuilder sb = new StringBuilder(); if (CryptStringToBinary(mypathEncriptado, mypathEncriptado.Length, CRYPT_STRING_BASE64, pidl2, ref largo, ref a, ref b)) { // muestro el path proveyendo el pidl reconstruÃ­do //sb.Clear(); Only works with .NET 4 sb.Length = 0; sb.Capacity = 261; SHGetPathFromIDList(pidl2, sb); //Console.WriteLine(sb.ToString()); PathDescodificado = sb.ToString(); } // //Marshal.FreeCoTaskMem(pidl); Marshal.FreeCoTaskMem(pidl2); } return PathDescodificado; } }"@try{	$MyPath = "c:\Flashtool" $Encrypted = [PIDLUtils]::Encode($MyPath)	$Encrypted $notEncrypted = [PIDLUtils]::Decode($Encrypted) $notEncrypted	}catch{	$_	break}`  
>   
> Edit : Now will run on Windows XP too_

---

<div class="post-metadata">

**Author:** ![dotnVo](https://avatars.discourse-cdn.com/v4/letter/d/4af34b/32.png) [@dotnVo](https://forums.powershell.org/u/dotnVo)\
**Post date:** [May 16, 2024, 8:57pm UTC](https://forums.powershell.org/t/encryptedpidl-solved/1108/2 "2024-05-16T20:57:56Z")

</div>


