<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://powershell.com/cs/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Dreaming in PowerShell : prompt</title><link>http://powershell.com/cs/blogs/tobias/archive/tags/prompt/default.aspx</link><description>Tags: prompt</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 (Build: 30929.2835)</generator><item><title>Shorten Path Names (and using Low Level API functions)</title><link>http://powershell.com/cs/blogs/tobias/archive/2012/04/11/shorten-path-names-and-using-low-level-api-functions.aspx</link><pubDate>Wed, 11 Apr 2012 07:22:00 GMT</pubDate><guid isPermaLink="false">f421715f-7aba-45f0-8a8d-44de5318a3a7:15906</guid><dc:creator>Tobias</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://powershell.com/cs/blogs/tobias/rsscomments.aspx?PostID=15906</wfw:commentRss><comments>http://powershell.com/cs/blogs/tobias/archive/2012/04/11/shorten-path-names-and-using-low-level-api-functions.aspx#comments</comments><description>&lt;p&gt;Path names can grow large, and sometimes there is just not enough room to display the entire path.&amp;nbsp; There is no cmdlet either that would shorten the path for you. So let&amp;#39;s take a look today at how you can &lt;strong&gt;access low-level Windows API functions from PowerShell&lt;/strong&gt; to add this feature,&lt;/p&gt;
&lt;p&gt;As an immediate benefit, after you read this article you can optimize your PowerShell prompt and make it shorter while keeping the current path meaningful.&lt;/p&gt;
&lt;h3&gt;Mission Target: Compacting a Path&lt;/h3&gt;
&lt;p&gt;What exactly is meant by &amp;quot;shorten a path name&amp;quot;? I am not talking about turning a &amp;quot;long&amp;quot; file path into the old 8.3 file path. That&amp;#39;s a different ball game - the 8.3 path would be shorter but at the same time completely unreadable.&lt;/p&gt;
&lt;p&gt;What I want is to shorten a path in a &lt;strong&gt;human readable format&lt;/strong&gt;, keeping as much meaningful information as possible. And while there is no PowerShell cmdlet for this, there is a low level Windows API function called &lt;strong&gt;PathCompactPathEx()&lt;/strong&gt; which lives in the system file&lt;strong&gt; shlwapi.dll&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;In pre-PowerShell-times, low level API functions were only available to developers. With PowerShell, everyone can access them. And here&amp;#39;s how.&lt;/p&gt;
&lt;h3&gt;Accessing Low Level API Functions&lt;/h3&gt;
&lt;p&gt;To access a low level API function, you need its &amp;quot;&lt;strong&gt;signature&lt;/strong&gt;&amp;quot; which describes where the function lives and how it needs to be called (its parameters and data types). Typically, the signature is defined in a language like&lt;strong&gt; c#&lt;/strong&gt;, but you could as well use signatures defined in any other language that is supported by the .NET framework, like &lt;strong&gt;VB.NET&lt;/strong&gt;. There are plenty of web sites that list API signatures, like &lt;strong&gt;pinvoke.net&lt;/strong&gt;. Here&amp;#39;s the signature for &lt;strong&gt;PathCompactPathEx() &lt;/strong&gt;in c#:&lt;/p&gt;
&lt;div class="pscode"&gt;[DllImport(&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;quot;shlwapi.dll&amp;quot;&lt;/span&gt;&lt;/span&gt;, CharSet &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;CharSet.Auto&lt;/span&gt;&lt;/span&gt;, SetLastError &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; true)] public static extern &lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&lt;/span&gt; PathCompactPathEx(&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.Text.StringBuilder&lt;/span&gt;&lt;/span&gt; pszOut, &lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;&lt;/span&gt; pszSrc, Int32 cchMax, Int32 dwFlags);&lt;/div&gt;
&lt;p&gt;Let&amp;#39;s try and &lt;strong&gt;decipher it&lt;/strong&gt; (you can skip this part if your hair is on fire and you just want results): &lt;/p&gt;
&lt;p&gt;It tells you that there is a function called &lt;strong&gt;PathCompactPathEx()&lt;/strong&gt; which resides in the system file &lt;strong&gt;shlwapi.dll&lt;/strong&gt; and takes &lt;strong&gt;four input parameters&lt;/strong&gt; and returns a Boolean value. The four parameters needed to run the function have &lt;strong&gt;different data types&lt;/strong&gt;. The first one is a &lt;strong&gt;StringBuilder&lt;/strong&gt; type, the second one is a &lt;strong&gt;String&lt;/strong&gt; (text), and the remainder are &lt;strong&gt;Int32&lt;/strong&gt; (32bit whole numbers). The signature also states that this is a &amp;quot;&lt;strong&gt;static&lt;/strong&gt;&amp;quot; function. Static functions will later become a part of a data type, so the keyword &amp;quot;static&amp;quot; is an important piece of information once you are ready to call your API function from PowerShell.&lt;br /&gt;And this is how you feed a signature into PowerShell to gain access to that function:&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$sig&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; @&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;[DllImport(&amp;quot;shlwapi.dll&amp;quot;, CharSet = CharSet.Auto, SetLastError = true)]&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;public static extern bool PathCompactPathEx(&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;System.Text.StringBuilder pszOut, string pszSrc, Int32 cchMax, &lt;/span&gt;&lt;br /&gt;&lt;span class="string"&gt;Int32 dwFlags); &lt;/span&gt;&lt;br /&gt;&lt;span class="string"&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;@&lt;br /&gt;&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Add-Type&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-MemberDefinition&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$sig&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Namespace&lt;/span&gt;&lt;/span&gt; Win32 &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Name&lt;/span&gt;&lt;/span&gt; StringFunctions&lt;/div&gt;
&lt;p&gt;The secret really is to feed that signature code to the cmdlet &lt;strong&gt;Add-Type&lt;/strong&gt;. This cmdlet then creates a new type (which you can assign any name you want; in this example the type is called Win32.StringFunctions), and you can use the new type then to access the function.&lt;/p&gt;
&lt;p&gt;Two things are worth mentioning here: &lt;/p&gt;
&lt;p&gt;First, I am submitting the signature as a &amp;quot;&lt;strong&gt;Here-String&lt;/strong&gt;&amp;quot;, which is a multiline text delimited by @&amp;#39;&amp;hellip;&amp;#39;@. For Here-Strings to work, it is of &lt;strong&gt;utmost importance&lt;/strong&gt; that no text whatsoever (including whitespace) follows the opening tag (@&amp;#39;), and that no text (including whitespace) preceeds the closing tag (&amp;#39;@). &lt;/p&gt;
&lt;p&gt;Second, &lt;strong&gt;Add-Type&lt;/strong&gt; is actually taking the c# signature source code and is compiling a DLL in memory which then is loaded. If your signature is written in a different language (like VB.NET), you need to specify the language by adding the parameter &lt;strong&gt;-Language&lt;/strong&gt;. Valid languages currently are &lt;strong&gt;CSharp&lt;/strong&gt;, &lt;strong&gt;CSharpVersion3&lt;/strong&gt;, &lt;strong&gt;CSharpVersion2&lt;/strong&gt;, &lt;strong&gt;VisualBasic&lt;/strong&gt;, and &lt;strong&gt;Jscript&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;After running &lt;strong&gt;Add-Type&lt;/strong&gt;, you actually get a new type as the name suggests. The name of this type was set by the parameters &lt;strong&gt;-Namespace&lt;/strong&gt; and &lt;strong&gt;-Name&lt;/strong&gt;, so in our example the name of the new type is &lt;strong&gt;Win32.StringFunctions&lt;/strong&gt;. To check out which functions are available in this type, use this line:&lt;/p&gt;
&lt;p&gt;PS&amp;gt; [&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;Win32.StringFunctions&lt;/span&gt;&lt;/span&gt;] | &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Member&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#5f9ea0;"&gt;&lt;span class="modifier"&gt;-Static&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;TypeName: &lt;span style="color:#8b4513;"&gt;&lt;span class="namespace"&gt;Win32.StringFunctions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Name MemberType Definition&lt;br /&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;----&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;----------&lt;/span&gt;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;&lt;span class="op"&gt;----------&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;Equals Method static &lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&lt;/span&gt; Equals(&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.Object&lt;/span&gt;&lt;/span&gt; objA, &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.Object&lt;/span&gt;&lt;/span&gt; objB)&lt;br /&gt;PathCompactPathEx Method static &lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&lt;/span&gt; PathCompactPathEx(&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.Text.StringBuilder&lt;/span&gt;&lt;/span&gt; p...&lt;br /&gt;ReferenceEquals Method static &lt;span class="datatype"&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;&lt;/span&gt; ReferenceEquals(&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.Object&lt;/span&gt;&lt;/span&gt; objA, &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.Ob&lt;/span&gt;&lt;/span&gt;...&lt;/p&gt;
&lt;p&gt;And there is our new API function &lt;strong&gt;PathCompactPathEx()&lt;/strong&gt;! Don&amp;#39;t worry about the other two, &lt;strong&gt;Equals()&lt;/strong&gt; and &lt;strong&gt;ReferenceEquals()&lt;/strong&gt;, these are default functions provided by every type.&lt;/p&gt;
&lt;h3&gt;Turning Low-Level Functions Into Civilized Functions&lt;/h3&gt;
&lt;p&gt;Accessing our low level function is still not a piece of cake, however, because as the term &amp;quot;low level&amp;quot; suggests, these API functions work in a very basic fashion and require you to pay attention to the required data types and containers. That&amp;#39;s why it is a &lt;strong&gt;best practice to turn a hard-to-use low level function into an easy-to-use PowerShell function&lt;/strong&gt; before you actually start using it in your scripts.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the result (which you can also download here: &lt;a target="_blank" href="http://powershell.com/cs/media/p/15905.aspx"&gt;http://powershell.com/cs/media/p/15905.aspx&lt;/a&gt;):&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Compress-Path&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Path&lt;/span&gt;&lt;/span&gt;, &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Length&lt;/span&gt;&lt;/span&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt;20) {&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$sig&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; @&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;[DllImport(&amp;quot;shlwapi.dll&amp;quot;, CharSet = CharSet.Auto, SetLastError = true)]&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;public static extern bool PathCompactPathEx(&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;System.Text.StringBuilder pszOut, string pszSrc, Int32 cchMax, &lt;/span&gt;&lt;br /&gt;&lt;span class="string"&gt;Int32 dwFlags); &lt;/span&gt;&lt;br /&gt;&lt;span class="string"&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;@&lt;br /&gt;&lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Add-Type&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-MemberDefinition&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$sig&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-name&lt;/span&gt;&lt;/span&gt; StringFunctions &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-namespace&lt;/span&gt;&lt;/span&gt; Win32&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$sb&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Object&lt;/span&gt;&lt;/span&gt; &lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;System.Text.StringBuilder&lt;/span&gt;&lt;/span&gt;(260)&lt;br /&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; ([&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;Win32.StringFunctions&lt;/span&gt;&lt;/span&gt;]::&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;PathCompactPathEx&lt;/span&gt;&lt;/span&gt;(&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$sb&lt;/span&gt;&lt;/span&gt; , &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Path&lt;/span&gt;&lt;/span&gt; , &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$Length&lt;/span&gt;&lt;/span&gt;&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;+&lt;/span&gt;&lt;/span&gt;1, 0)) {&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$sb&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;ToString&lt;/span&gt;&lt;/span&gt;()&lt;br /&gt;} &lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;&lt;/span&gt; {&lt;br /&gt;Throw &lt;span style="color:#800000;"&gt;&lt;span class="string"&gt;&amp;quot;Unable to compact path&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;}&lt;br /&gt;}&lt;/div&gt;
&lt;p&gt;Now, to compact a path all you need to do is call Compress-Path and tell the function how much room you have:&lt;/p&gt;
&lt;p&gt;PS&amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Compress-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$env:temp&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Length&lt;/span&gt;&lt;/span&gt; 30&lt;br /&gt;C:\Users\Tobias\AppDat...\Temp&lt;br /&gt;PS&amp;gt;&lt;br /&gt;PS&amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Compress-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Len&lt;/span&gt;&lt;/span&gt; 16&lt;br /&gt;HKL...\Uninstall&lt;br /&gt;PS&amp;gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Compress-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall&amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Len&lt;/span&gt;&lt;/span&gt; 30&lt;br /&gt;HKLM:\Software\Mi...\Uninstall&lt;/p&gt;
&lt;h3&gt;A better PowerShell prompt&lt;/h3&gt;
&lt;p&gt;One first use of &lt;strong&gt;Compress-Path&lt;/strong&gt; could be an improved &lt;strong&gt;prompt&lt;/strong&gt; function. By default, the PowerShell prompt always displays the complete path you are in, often wasting a lot of real estate in your console or editor.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an improved prompt function that displays a compressed path, still giving you a good indication of where your current folder is, and displays the complete path in your window title bar.&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;/span&gt; prompt {&lt;br /&gt;&lt;span class="string"&gt;&lt;span style="color:#800000;"&gt;&amp;#39;PS {0}&amp;gt; &amp;#39;&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;-f&lt;/span&gt;&lt;/span&gt; (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Compress-Path&lt;/span&gt;&lt;/span&gt; (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Location&lt;/span&gt;&lt;/span&gt;) 15)&lt;br /&gt;&lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$host&lt;/span&gt;&lt;/span&gt;.&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;UI.RawUI.WindowTitle&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; (&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Get-Location&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;}&lt;/div&gt;
&lt;p&gt;To permanently use this prompt, just make sure you add both the function &lt;strong&gt;Compress-Path&lt;/strong&gt; and the function &lt;strong&gt;prompt&lt;/strong&gt; into your profile script so PowerShell loads both functions automatically at startup (both functions can be downloaded here: &lt;a target="_blank" href="http://powershell.com/cs/media/p/15905.aspx"&gt;http://powershell.com/cs/media/p/15905.aspx&lt;/a&gt;). The profile script is located here:&lt;/p&gt;
&lt;div class="pscode"&gt;PS C:\Us...\Tobias&amp;gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$profile&lt;/span&gt;&lt;/span&gt;.&lt;span style="color:#8b4513;"&gt;&lt;span class="method"&gt;CurrentUserAllHosts&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;C:\Users\Tobias\Documents\WindowsPowerShell\&lt;span class="namespace"&gt;&lt;span style="color:#8b4513;"&gt;profile.ps1&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;And here&amp;#39;s some code that opens the profile script for you (and creates it if it does not yet exist):&lt;/p&gt;
&lt;div class="pscode"&gt;&lt;span class="keyword"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;!&lt;/span&gt;&lt;/span&gt;(&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Test-Path&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$profile&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;CurrentUserAllHosts&lt;/span&gt;&lt;/span&gt;)) &lt;br /&gt;{ &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$null&lt;/span&gt;&lt;/span&gt; &lt;span class="op"&gt;&lt;span style="color:#ff0000;"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;New-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$profile&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;CurrentUserAllHosts&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-Force&lt;/span&gt;&lt;/span&gt; &lt;span class="modifier"&gt;&lt;span style="color:#5f9ea0;"&gt;-ItemType&lt;/span&gt;&lt;/span&gt; File }; &lt;br /&gt;&lt;span class="verbnoun"&gt;&lt;span style="color:#5f9ea0;"&gt;Invoke-Item&lt;/span&gt;&lt;/span&gt; &lt;span class="var"&gt;&lt;span style="color:#800080;"&gt;$profile&lt;/span&gt;&lt;/span&gt;.&lt;span class="method"&gt;&lt;span style="color:#8b4513;"&gt;CurrentUserAllHosts&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;I hope you had fun! You can now take this concept and wrap all kinds of low-level API functions in the same way. Stay tuned...!&lt;/p&gt;
&lt;p&gt;Tobias&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Microsoft MVP PowerShell Germany&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P.S.&lt;br /&gt;If you live in Germany or other parts of Europe and your company would like to set up a truly great PowerShell training, just contact me! I regularly train mid- to large-size companies. Trainings are always a blast with tons of real-world-examples and solutions. Here&amp;#39;s how to get in touch with me: &lt;a href="mailto:tobias.weltner@scriptinternals.de"&gt;&lt;span style="color:#3366cc;"&gt;tobias.weltner@scriptinternals.de&lt;/span&gt;&lt;/a&gt; &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://powershell.com/cs/aggbug.aspx?PostID=15906" width="1" height="1"&gt;</description><category domain="http://powershell.com/cs/blogs/tobias/archive/tags/API/default.aspx">API</category><category domain="http://powershell.com/cs/blogs/tobias/archive/tags/Here-String/default.aspx">Here-String</category><category domain="http://powershell.com/cs/blogs/tobias/archive/tags/PathCompactPathEx/default.aspx">PathCompactPathEx</category><category domain="http://powershell.com/cs/blogs/tobias/archive/tags/prompt/default.aspx">prompt</category><category domain="http://powershell.com/cs/blogs/tobias/archive/tags/Add-Type/default.aspx">Add-Type</category></item></channel></rss>