{"id":312,"date":"2021-03-24T05:49:00","date_gmt":"2021-03-24T12:49:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/powershell-community\/?p=312"},"modified":"2021-03-24T05:49:00","modified_gmt":"2021-03-24T12:49:00","slug":"can-i-enable-the-caps-lock-key","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell-community\/can-i-enable-the-caps-lock-key\/","title":{"rendered":"Can I Enable the Caps Lock Key?"},"content":{"rendered":"<p><strong>Q:<\/strong> I have a script where users enter some information. This information needs to be entered in all capital letters, so my instructions say, \u201cPlease make sure the Caps Lock key is on before entering the information.\u201d They don\u2019t always do that, however. Is there a way to turn the Caps Lock key on and off using a script?<\/p>\n<p><strong>A:<\/strong> I don&#8217;t know how to run the key off and on, but with PowerShell, there is a way to mimic the effect of turning on the Caps Lock key.<\/p>\n<h2>User Input Considered Harmful<\/h2>\n<p>Let&#8217;s start with the observation that all user input is harmful. One of my earliest IT heroes, Edsger Dijkstra, published a seminal letter <a href=\"https:\/\/homepages.cwi.nl\/~storm\/teaching\/reader\/Dijkstra68.pdf\">Go To Statement Considered Harmful<\/a> in 1968 which began the structured programming revolution. And this is one reason, by the way, why PowerShell has no goto statement. The phrase &#8220;Considered Harmful&#8221; is also a well-known phrase that has a Wikipedia entry at <a href=\"https:\/\/wikipedia.org\/wiki\/Considered_harmful#:~:text=Considered%20harmful%20was%20popularized%20among,the%20day%20and%20advocated%20structured\">Considered Harmful<\/a>. In general, I consider all user input potentially harmful, capable of doing damage until and unless you thoroughly validate it first.<\/p>\n<h2>Is User Input Really Harmful?<\/h2>\n<p>I was a verification programmer at university and got paid an hourly rate plus a bonus for finding bugs. I made far more than my hourly wage by simply testing conditions outside what the developers considered &#8220;normal&#8221;. In other words potentially harmful.<\/p>\n<p>If an instruction said, &#8220;Enter a number between 1 and 6&#8221;, I tried -124, 0, 7, 42, 999999, and so on. This approach inevitably led to several bugs (and several nice bug bounties). Ever since then, I have always taught my students never ever to accept user input unchecked. And that includes having all upper case input if that is what your application requires.<\/p>\n<p>Another example of unchecked user input being harmful is SQL injection attacks. You can read more about these attacks and how you can prevent it at <a href=\"https:\/\/www.acunetix.com\/websitesecurity\/sql-injection\/\">What is SQL Injection (SQLi) and How to Prevent It<\/a><\/p>\n<p>So, in general, you should never trust any user input without validating it first. Although you ask the user to type her name in all upper case, I&#8217;ll bet that many just won&#8217;t.<\/p>\n<p>So what does the Caps Lock actually do? When you type characters into a form or a console, you might type them like this:<\/p>\n<pre><code class=\"powershell-console\">this is my sentence.\n<\/code><\/pre>\n<p>If you switch on the Caps Lock key, the operating system and your hardware makes those characters appear like this:<\/p>\n<pre><code class=\"console\">THIS IS MY SENTENCE.\n<\/code><\/pre>\n<p>So how can we achieve that same effect in a script? Simple: we accept the input as the user typed it. Then we make sure it&#8217;s all upper case before using it.<\/p>\n<p>Let&#8217;s start with getting the user input in the first place.<\/p>\n<h2>Getting User Input<\/h2>\n<p>There are several ways to get user input from within a script. A common approach with PowerShell scripts is to use the <code>Read-Host<\/code> command. This cmdlet reads a line of input from the console and returns it to the script as a string. For more information on this cmdlet, see the <a href=\"https:\/\/docs.microsoft.com\/powershell\/module\/microsoft.powershell.utility\/read-host\">Read-Host help file<\/a>.<\/p>\n<p>There are other ways to get user input, such as using <a href=\"https:\/\/docs.microsoft.com\/powershell\/scripting\/samples\/creating-a-custom-input-box\">Windows Forms<\/a> or WPF. You might even use a legacy <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/microsoft.visualbasic.interaction.inputbox\">Visual Basic <code>Inputbox<\/code><\/a>. But with each of these methods, you still have the underlying issue of making sure the string the user enters is all upper-case before you use it further.<\/p>\n<p>Suppose you wanted to ask the user for their name (and you really need it to be upper case). You could ask for, accept, and then display user input like this:<\/p>\n<pre><code class=\"powershell-console\">PS C:\\Foo&gt; $Answer = Read-Host -Prompt 'Please Enter Your Name In ALL Upper case'\nPlease Enter Your Name In ALL Upper case: Thomas Lee\nPS C:\\Foo&gt; $Answer\nThomas Lee\n<\/code><\/pre>\n<p>But that is not in upper case, I hear you say. Yes, true &#8211; but there is just one more step. Be patient, grasshopper.<\/p>\n<h2>Converting a String to Upper Case<\/h2>\n<p>As I mentioned, when you use <code>Read-Host<\/code>, PowerShell returns the input to you as a string. Even if you enter a number (say 42) PowerShell still treats this as a string containing two characters, like this:<\/p>\n<pre><code class=\"powershell-console\">PS C:\\&gt; $Answer = Read-Host -Prompt \"Please Enter Your Name In ALL Upper case\"\nPlease Enter Your Name In ALL Upper case: 42\nPS C:\\&gt; $Answer.GetType().FullName\nSystem.String\n<\/code><\/pre>\n<p>This matters because the <code>System.String<\/code> .NET class has a very useful method, <code>ToUpper()<\/code>. The <code>ToUpper()<\/code> method converts the string to all upper case and returns a new, all upper case, string. So to convert the string you entered and stored in <code>$Answer<\/code>, you use the <code>ToUpper()<\/code> method like this:<\/p>\n<pre><code class=\"powershell-console\">PS C:\\&gt; $Answer = Read-Host -Prompt 'Enter Your Name In ALL Upper Case'\nEnter Your Name In ALL Upper Case: Thomas Lee\nPS C:\\&gt; $Answer\nThomas Lee\nPS C:\\&gt; $Answer = $Answer.ToUpper()  # convert to all upper case.\nPS C:\\&gt; $Answer\nTHOMAS LEE\n<\/code><\/pre>\n<h2>Strings are Immutable in .NET<\/h2>\n<p>In .NET and PowerShell, a string is immutable Once created, you can&#8217;t change a System.String in memory after you define it.<\/p>\n<p>If you assign a string variable a new value (the old value plus a character), .NET creates an all-new string with same name) and marks the older string as out of scope and available for garbage collection. This is generally not an issue in cases such as wanting to ensure user input is all upper-case.<\/p>\n<p>But if you have a script that makes a very large number of changes to any <code>System.String<\/code> object, you could encounter performance issues. In such cases, you can use the .NET <code>System.Text.StringBuilder<\/code> class representaing mutable string of characters. This class can provide significant performance gains in such scenarios. For more information on the <code>StringBuilder<\/code> class, see <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/system.text.stringbuilder\">StringBuilder Class documentation page<\/a> I plan to do another blog post on the differences.<\/p>\n<h2>Strings and Methods<\/h2>\n<p>.NET strings also have other methods, including <code>ToLower()<\/code> that change a string to all lower case. You can always discover the available methods of a string (or any other variable type) by piping the variable to <code>Get-Member<\/code>. Like this:<\/p>\n<pre><code class=\"powershell-console\">PS C:\\&gt; $Answer | Get-Member -MemberType Method\n\n   TypeName: System.String\n\nName                 MemberType Definition\n----                 ---------- ----------\nClone                Method     System.Object Clone(), System.Object ICloneable.Clone()\nCompareTo            Method     int CompareTo(System.Object value), int CompareTo(string strB), int IComparabl\u2026\nContains             Method     bool Contains(string value), bool Contains(string value, System.StringComparis\u2026\nCopyTo               Method     void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int cou\u2026\nEndsWith             Method     bool EndsWith(string value), bool EndsWith(string value, System.StringComparis\u2026\nEnumerateRunes       Method     System.Text.StringRuneEnumerator EnumerateRunes()\nEquals               Method     bool Equals(System.Object obj), bool Equals(string value), bool Equals(string \u2026\nGetEnumerator        Method     System.CharEnumerator GetEnumerator(), System.Collections.IEnumerator IEnumera\u2026\nGetHashCode          Method     int GetHashCode(), int GetHashCode(System.StringComparison comparisonType)\nGetPinnableReference Method     System.Char&, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, Public\u2026\nGetType              Method     type GetType()\nGetTypeCode          Method     System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTypeCode()\nIndexOf              Method     int IndexOf(char value), int IndexOf(char value, int startIndex), int IndexOf(\u2026\nIndexOfAny           Method     int IndexOfAny(char[] anyOf), int IndexOfAny(char[] anyOf, int startIndex), in\u2026\nInsert               Method     string Insert(int startIndex, string value)\nIsNormalized         Method     bool IsNormalized(), bool IsNormalized(System.Text.NormalizationForm normaliza\u2026\nLastIndexOf          Method     int LastIndexOf(char value), int LastIndexOf(char value, int startIndex), int \u2026\nLastIndexOfAny       Method     int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(char[] anyOf, int startIn\u2026\nNormalize            Method     string Normalize(), string Normalize(System.Text.NormalizationForm normalizati\u2026\nPadLeft              Method     string PadLeft(int totalWidth), string PadLeft(int totalWidth, char paddingCha\u2026\nPadRight             Method     string PadRight(int totalWidth), string PadRight(int totalWidth, char paddingC\u2026\nRemove               Method     string Remove(int startIndex, int count), string Remove(int startIndex)\nReplace              Method     string Replace(string oldValue, string newValue, bool ignoreCase, cultureinfo \u2026\nSplit                Method     string[] Split(char separator, System.StringSplitOptions options), string[] Sp\u2026\nStartsWith           Method     bool StartsWith(string value), bool StartsWith(string value, System.StringComp\u2026\nSubstring            Method     string Substring(int startIndex), string Substring(int startIndex, int length)\nToBoolean            Method     bool IConvertible.ToBoolean(System.IFormatProvider provider)\nToByte               Method     byte IConvertible.ToByte(System.IFormatProvider provider)\nToChar               Method     char IConvertible.ToChar(System.IFormatProvider provider)\nToCharArray          Method     char[] ToCharArray(), char[] ToCharArray(int startIndex, int length)\nToDateTime           Method     datetime IConvertible.ToDateTime(System.IFormatProvider provider)\nToDecimal            Method     decimal IConvertible.ToDecimal(System.IFormatProvider provider)\nToDouble             Method     double IConvertible.ToDouble(System.IFormatProvider provider)\nToInt16              Method     short IConvertible.ToInt16(System.IFormatProvider provider)\nToInt32              Method     int IConvertible.ToInt32(System.IFormatProvider provider)\nToInt64              Method     long IConvertible.ToInt64(System.IFormatProvider provider)\nToLower              Method     string ToLower(), string ToLower(cultureinfo culture)\nToLowerInvariant     Method     string ToLowerInvariant()\nToSByte              Method     sbyte IConvertible.ToSByte(System.IFormatProvider provider)\nToSingle             Method     float IConvertible.ToSingle(System.IFormatProvider provider)\nToString             Method     string ToString(), string ToString(System.IFormatProvider provider), string IC\u2026\nToType               Method     System.Object IConvertible.ToType(type conversionType, System.IFormatProvider \u2026\nToUInt16             Method     ushort IConvertible.ToUInt16(System.IFormatProvider provider)\nToUInt32             Method     uint IConvertible.ToUInt32(System.IFormatProvider provider)\nToUInt64             Method     ulong IConvertible.ToUInt64(System.IFormatProvider provider)\nToUpper              Method     string ToUpper(), string ToUpper(cultureinfo culture)\nToUpperInvariant     Method     string ToUpperInvariant()\nTrim                 Method     string Trim(), string Trim(char trimChar), string Trim(Params char[] trimChars)\nTrimEnd              Method     string TrimEnd(), string TrimEnd(char trimChar), string TrimEnd(Params char[] \u2026\nTrimStart            Method     string TrimStart(), string TrimStart(char trimChar), string TrimStart(Params c\u2026\n<\/code><\/pre>\n<p>If you look carefully at this list, you can see methods that convert a string to different kinds of numbers. These methods would help you convert the string of 2 characters (e.g. 42) into an integer number. That could well be the subject of another article that shows you how to achieve this.<\/p>\n<h2>Summary<\/h2>\n<p>Turning the Caps Lock key on is not something I know how to do. And if you did, it might confuse the user, for example if she sees the Caps Lock indicator light up on their keyboard. As well, you would need to turn it off afterwards.<\/p>\n<p>Rather then depending on any user to always do the right thing, you can always ensure that the input is indeed in all upper case. Never trust user input without validating it first.<\/p>\n<h2>Tip of the Hat<\/h2>\n<p>This article is based on an earlier article here: <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/can-i-enable-the-caps-lock-key\/\">Can I Enable the Caps Lock Key?<\/a>. I re-developed the article around PowerShell.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Q: I have a script where users enter some information. This information needs to be entered in all capital letters, so my instructions say, \u201cPlease make sure the Caps Lock key is on before entering the information.\u201d They don\u2019t always do that, however. Is there a way to turn the Caps Lock key on and [&hellip;]<\/p>\n","protected":false},"author":4034,"featured_media":77,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[13],"tags":[19,20,21],"class_list":["post-312","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","tag-caps-lock","tag-string","tag-toupper"],"acf":[],"blog_post_summary":"<p>Q: I have a script where users enter some information. This information needs to be entered in all capital letters, so my instructions say, \u201cPlease make sure the Caps Lock key is on before entering the information.\u201d They don\u2019t always do that, however. Is there a way to turn the Caps Lock key on and [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/posts\/312","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/users\/4034"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/comments?post=312"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/posts\/312\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/media\/77"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/media?parent=312"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/categories?post=312"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell-community\/wp-json\/wp\/v2\/tags?post=312"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}