{"id":53603,"date":"2009-06-02T23:39:00","date_gmt":"2009-06-02T23:39:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2009\/06\/02\/hey-scripting-guy-how-can-i-enable-and-disable-offline-files\/"},"modified":"2009-06-02T23:39:00","modified_gmt":"2009-06-02T23:39:00","slug":"hey-scripting-guy-how-can-i-enable-and-disable-offline-files","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-enable-and-disable-offline-files\/","title":{"rendered":"Hey, Scripting Guy! How Can I Enable and Disable Offline Files?"},"content":{"rendered":"<p><H2><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"> <\/H2>\n<P>Hey, Scripting Guy! The script you wrote yesterday to check the status of offline files was pretty cool. However, it does not help me if I want to enable or disable offline files on my computer. Do you have a script to allow me to actually dooooooooo something?<BR><BR>&#8211; LS<\/P><IMG border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"> \n<P>Hi LS,<\/P>\n<P>Doooooooooo we have a script that actually does something? Of course we do. We are outside playing Frisbee golf on the green lawn here on campus. Scripting Guy Ed Wilson is sitting under a tree, ostensibly watching us, but we suspect he is actually writing a script. This guy writes scripts in his sleep (or so we have been told). Hey, Ed, can you write a script to enable and disable offline files? LS, we will get back with you. It is our turn to putt (said in the whisper of Jim Nantz).<\/P>\n<P>Okay, we are back. Ed has cooked up a pretty good one today. He calls it the <B>EnableDisableOfflineFiles.ps1<\/B> script. He must be feeling creative. Here it is in its entirety.<\/P>\n<P><B>EnableDisableOfflineFiles.ps1<\/B><\/P><PRE class=\"codeSample\">param($computer=&#8221;localhost&#8221;, $a, $help)<\/p>\n<p>function funline ($strIN)\n{\n $num = $strIN.length\n for($i=1 ; $i -le $num ; $i++)\n  { $funline += &#8220;=&#8221; }\n    Write-Host -ForegroundColor yellow $strIN \n    Write-Host -ForegroundColor darkYellow $funline\n}<\/p>\n<p>function funHelp()\n{\n$helpText=@&#8221;\nDESCRIPTION:\nNAME: EnableDisableOffLineFiles.ps1 \nEnables or disables offline files on a local or remote machine.\nA reboot of the machine MAY be required. This information will\nbe displayed in the status message once the script is run.<\/p>\n<p>PARAMETERS: \n-computer Specifies name of the computer upon which to run the script\n-a(ction) &lt; e(nable), d(isable) &gt;\n-help     prints help file<\/p>\n<p>SYNTAX:\nEnableDisableOffLineFiles.ps1 -computer MunichServer -a e<\/p>\n<p>Enables offline files on a computer named MunichServer<\/p>\n<p>EnableDisableOffLineFiles.ps1 -a d<\/p>\n<p>Disables offline files on local computer<\/p>\n<p>EnableDisableOffLineFiles.ps1 -help ?<\/p>\n<p>Displays the help topic for the script<\/p>\n<p>&#8220;@\n$helpText\nexit\n}<\/p>\n<p>function funtranslatemethod($a)\n{\n switch($a)\n  {\n   &#8220;e&#8221; { $glogal:m = $true \n         $global:msg = &#8220;Enable offline files&#8221; \n       }\n   &#8220;d&#8221; { \n        $global:m = $false\n        $global:msg = &#8220;Disable offline files&#8221; \n       }\n  default{ \n          $global:msg = &#8220;$a is not an allowed response`n&#8221; \n }\n  }\n}<\/p>\n<p>if($help){ funline(&#8220;Obtaining help &#8230;&#8221;) ; funhelp }\nif(!$a)\n   {\n    $(throw &#8220;You must supply an action. try this:\nEnableDIsableOfflineFiles.ps1 -help ?&#8221;)\n   }\n$global:msg =$global:m = $null\nfuntranslatemethod($a)<\/p>\n<p>$objWMI = [wmiclass]&#8221;\\\\$computer\\root\\cimv2:win32_offlinefilescache&#8221;\nfunline(&#8220;Configure Offline files on $computer &#8230;&#8221;)\n$rtn = $objwmi.enable($m)\nif($rtn.returnvalue -eq 0)\n {\n  Write-Host -ForegroundColor green &#8220;$msg succeeded&#8221;\n }\nELSE\n {\n  Write-Host -ForegroundColor red &#8220;$msg failed with $($rtn.returnvalue) &#8221;\n }\nif($rtn.rebootrequired) \n  { Write-Host -ForegroundColor cyan &#8220;reboot required&#8221; }\n<\/PRE>\n<P>To enable or to disable the offline files feature on more than one machine or as part of a standard build process, you can use the <B>EnableDisableOfflineFiles.ps1<\/B> script. This script leverages the <B>WIN32_Offlinefilescache<\/B> WMI class. <\/P>\n<P>The <B>EnableDisableOfflineFiles.ps1<\/B> script begins with the <B>param<\/B> statement. The <B>param<\/B> statement is used to provide us with the ability to specify named arguments to the script when it runs. This gives the ability to control how the script executes without having to edit the script. The first parameter defined is the <B>\u2013computer<\/B> parameter. The <B>$computer<\/B> variable is automatically created to hold the data supplied when the script is run. However, we decided to set the variable to a default value of <B>localhost<\/B>. This allows us to run the script against the local machine without having to actually supply a value to use. We define two other parameters: <B>-a<\/B> and <B>\u2013help<\/B>. We do not assign default values to these variables. The <B>\u2013a<\/B> parameter will be used to specify the action to perform when the script is run. The <B>\u2013help<\/B> parameter determines whether or not the Help text is displayed. This line of code is seen here: <\/P><PRE class=\"codeSample\">param($computer=&#8221;localhost&#8221;, $a, $help)\n<\/PRE>\n<P>Next, we have the <B>funline<\/B> function. The <B>funline<\/B> function is used to underline the output from the script and to provide a visual reference point to make the output easier to read and to understand. We declare a single input statement to the function, which is called <B>$strIN<\/B>. The input string is whatever is passed to the <B>funline<\/B> function. We use the <B>length<\/B> property to determine the length of the line that was passed to the function. We store the length of the string in the <B>b<\/B> variable, and use it in the <B>for<\/B> loop. We begin counting at 1 and will continue looping until the value of <B>$i<\/B> (the counter variable) is less than or equal to the sum stored in the <B>$num<\/B> variable. We then increment the value of <B>$i<\/B> by 1 <B>($i++<\/B>). The code that is run as a result of the <B>for<\/B> loop is used to build up the variable <B>$funline<\/B> with a group of equal signs (\u201c<B>=<\/B>\u201d). We then use the <B>Write-Host<\/B> cmdlet to print out the input string. We specify the <B>\u2013foregroundcolor<\/B> parameter of <B>yellow<\/B>, and the line separator contained in the <B>$funline<\/B> function is printed out using the <B>\u2013foregroundcolor<\/B> parameter of <B>darkyellow<\/B>. This gives a nice visual effect to the line separator. This function is seen here:<\/P><PRE class=\"codeSample\">function funline ($strIN)\n{\n $num = $strIN.length\n for($i=1 ; $i -le $num ; $i++)\n  { $funline += &#8220;=&#8221; }\n    Write-Host -ForegroundColor yellow $strIN \n    Write-Host -ForegroundColor darkYellow $funline\n}\n<\/PRE>\n<P>Now we come to the <B>fun<\/B><B>H<\/B><B>elp<\/B> function. This function is used to display a Help message to the user when the script is run with the <B>\u2013help<\/B> parameter specified. There are no input parameters defined for this function. We begin the function by declaring the variable <B>$helpText<\/B> and opening a <B>here-string<\/B>. The <B>here-string<\/B> is opened by using the special character combination <B>@\u201d<\/B>. The <B>here-string<\/B> uses the same character combination in reverse <B>\u201c@<\/B> to end the <B>here-string<\/B>. The advantage of using the <B>here-string<\/B> is that it allows us to ignore quoting rules, and simply type the text as we wish it to appear in the output. In the <B>here-string<\/B>, we define sections of Help such as a general description of the script, the parameters the script requires, and several syntax examples. The <B>funHelp<\/B> function ends by displaying the contents of the <B>$helpText<\/B> variable and calling the exit statement. The entire <B>funHelp<\/B> function is seen here:<\/P><PRE class=\"codeSample\">function funHelp()\n{\n$helpText=@&#8221;\nDESCRIPTION:\nNAME: EnableDisableOffLineFiles.ps1 \nEnables or disables offline files on a local or remote machine.\nA reboot of the machine MAY be required. This information will\nbe displayed in the status message once the script is run.<\/p>\n<p>PARAMETERS: \n-computer Specifies name of the computer upon which to run the script\n-a(ction) &lt; e(nable), d(isable) &gt;\n-help     prints help file<\/p>\n<p>SYNTAX:\nEnableDisableOffLineFiles.ps1 -computer MunichServer -a e<\/p>\n<p>Enables offline files on a computer named MunichServer<\/p>\n<p>EnableDisableOffLineFiles.ps1 -a d<\/p>\n<p>Disables offline files on local computer<\/p>\n<p>EnableDisableOffLineFiles.ps1 -help ?<\/p>\n<p>Displays the help topic for the script<\/p>\n<p>&#8220;@\n$helpText\nexit\n}\n<\/PRE>\n<P>After we are finished with the <B>funhelp<\/B> function, we move on to declare an additional function\u2014the <B>funtranslatemethod<\/B> function. The <B>funtranslatemethod<\/B> function is used to translate the input parameter that is specified for the <B>\u2013a<\/B> (action) parameter. The value that will be contained in the <B>$a<\/B> variable is supplied when the script is run. In fact, this script will generate an error if the <B>\u2013a<\/B> parameter is missing when the script is run. This makes sense because you need to know if you want to either enable or disable offline files before you run the script. <\/P>\n<P>The <B>funtranslatemethod<\/B> function uses the <B>switch<\/B> statement to evaluate the value that was supplied to the <B>\u2013a<\/B> parameter. If the value contained in the <B>$a<\/B> variable is the letter <B>e<\/B>, we do two things inside the code block. We first assign the intrinsic variable <B>$true<\/B> to the global variable <B>$m<\/B>. The second thing we do is use the global variable <B>$msg<\/B> and store the string we will display to the user. We use the string \u201cEnable offline files\u201d to indicate the action we were trying to perform. <\/P>\n<P>The other action we have defined in the <B>funtranslatemethod<\/B> function is the <B>disable<\/B> action. If the user supplies the letter b to the script when it is run, we will use the global variable <B>$m<\/B> to hold the intrinsic variable <B>b<\/B>. This will be supplied to the <B>method<\/B> call in the main body of the script a little bit later. We also store a string\u2014\u201cDisable offline files\u201d\u2014in the global variable <B>$msg<\/B>. <\/P>\n<P>The default action of the <B>switch<\/B> statement is to store the string \u201cis not an allowed response\u201d in the global variable <B>$msg<\/B>. We also print out the value of the action that was contained in the <B>$a<\/B> variable, and use a special character \u201c`n\u201d to cause the string to be printed with a new line character at the end of the string. The complete <B>funtranslatemethod<\/B> function is seen here:<\/P><PRE class=\"codeSample\">function funtranslatemethod($a)\n{\n switch($a)\n  {\n   &#8220;e&#8221; { $global:m = $true \n         $global:msg = &#8220;Enable offline files&#8221; \n       }\n   &#8220;d&#8221; { \n        $global:m = $false\n        $global:msg = &#8220;Disable offline files&#8221; \n       }\n  default{ \n          $global:msg = &#8220;$a is not an allowed response`n&#8221; \n }\n  }\n}\n<\/PRE>\n<P>Now we need to check for the presence of a couple of variables. The first variable we want to check for is the <B>$help<\/B> variable. If it is present, it means the script was run with the <B>\u2013help<\/B> parameter, and we want to display the help text as a result. To do this, we use the <B>if<\/B> statement and look for the variable. If it is found, in our code block we call the <B>funline<\/B> function to display a string message, and then call the <B>funhelp<\/B> function. This line of code is seen here:<\/P><PRE class=\"codeSample\">if($help){ funline(&#8220;Obtaining help &#8230;&#8221;) ; funhelp }\n<\/PRE>\n<P>Next we look for the presence of the <B>$a<\/B> variable. If it is not present, it means the script was run without the <B>$a<\/B> parameter. We want this parameter to be a required parameter, and as a result, we use the <B>throw<\/B> statement to display a message. When we use the <B>throw<\/B> statement, it will halt execution of the script and display our message in red. This is similar to using the <B>raise<\/B> method of the <B>error<\/B> object in other programming languages.<\/P>\n<P>The string that we will \u201cthrow\u201d is used to indicate the error that occurred\u2014a value for the <B>\u2013a<\/B> parameter was not supplied. This error is shown here:<\/P><IMG border=\"0\" alt=\"Image of the error displayed by throwing a string\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/june\/hey0603\/hsg-06-03-09-01.jpg\" width=\"500\" height=\"148\"> \n<P>&nbsp;<\/P>\n<P>We then point the user to the Help file:<\/P><PRE class=\"codeSample\">if(!$a)\n   {\n    $(throw &#8220;You must supply an action. try this:\nEnableDIsableOfflineFiles.ps1 -help ?&#8221;)\n   }\n<\/PRE>\n<P>If the user does not want to see the <B>Help<\/B> file, and they have supplied a value for the <B>action<\/B> parameter, we declare a couple of global variables, set them to null, and then call the <B>funtranslatemethod<\/B> function to see which action we need to perform. These two lines of code are seen here: <\/P><PRE class=\"codeSample\">$global:msg = $global:m = $null\nfuntranslatemethod($a)\n<\/PRE>\n<P>It is now time to make the connection into WMI. To do this, we use the <B>[wmiclass]<\/B> type accelerator, which provides access to the <B>system.management.managementobject<\/B> .NET Framework class. This .NET Framework class provides access to the WMI methods that might not be available when using the <B>Get-Wmiobject<\/B> cmdlet. Luckily, we can use the <B>Get-Member<\/B> cmdlet and the Windows Software Development Kit (SDK) to provide additional information about calling the methods. The syntax to connect to a remote computer using this class is a bit strange as seen below. We incorporate the <B>$computer<\/B> variable that is supplied from the command line into the connection string to make it easy to target other computers. We store the <B>system.management.managementobject<\/B> that is created in the <B>$objWMI<\/B> variable. This line of code is seen here:<\/P><PRE class=\"codeSample\">$objWMI = [wmiclass]&#8221;\\\\$computer\\root\\cimv2:win32_offlinefilescache&#8221;\n<\/PRE>\n<P>Now we want to call the <B>enable<\/B> method, and either enable or disable the use of the offline files feature in Windows Server 2008 R2 or Windows Vista. We use the <B>funline<\/B> function to print out the status message, and then we call the <B>enable()<\/B> method. This code is seen here:<\/P><PRE class=\"codeSample\">funline(&#8220;Configure Offline files on $computer &#8230;&#8221;)\n$rtn = $objwmi.enable($m)\n<\/PRE>\n<P>Next, we want to evaluate the return code that came back from calling the <B>enable<\/B> method on the machine. If the <B>returnvalue<\/B> property of the return code is equal to 0, the call succeeded. Otherwise, we print out the return code and state the call was not successful. The problem with this WMI class is that it does not always supply a non-zero return value. However, the class always returns a 0 when it succeeds. This code is seen here:<\/P><PRE class=\"codeSample\">if($rtn.returnvalue -eq 0)\n {\n  Write-Host -ForegroundColor green &#8220;$msg succeeded&#8221;\n }\nELSE\n {\n  Write-Host -ForegroundColor red &#8220;$msg failed with $($rtn.returnvalue) &#8221;\n }\n<\/PRE>\n<P>We also need to check the <B>rebootrequired<\/B> property. When the <B>enable<\/B> method \u201cworks\u201d but detects that a reboot is required, it will set the <B>rebootrequired<\/B> property. We look for it and display that the reboot is required. This code is seen here:<\/P><PRE class=\"codeSample\">if($rtn.rebootrequired) \n  { Write-Host -ForegroundColor cyan &#8220;reboot required&#8221; }\n<\/PRE>\n<P>LS, we got a hole in one in our Frisbee golf game, and Ed appears to have scored a hole in one with the <B>EnableDisableOfflineFiles.ps1<\/B> script. Join us tomorrow as we continue Managing User Data Week. Hey, the Summer Scripting Games are nearly upon us. We will begin revealing the event scenarios next week. So stay tuned.<\/P>\n<P>&nbsp;<\/P>\n<P><B>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/B><\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! The script you wrote yesterday to check the status of offline files was pretty cool. However, it does not help me if I want to enable or disable offline files on my computer. Do you have a script to allow me to actually dooooooooo something?&#8211; LS Hi LS, Doooooooooo we have a [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[423,3,735,45],"class_list":["post-53603","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-backup-and-system-restore","tag-scripting-guy","tag-shadow-copy","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! The script you wrote yesterday to check the status of offline files was pretty cool. However, it does not help me if I want to enable or disable offline files on my computer. Do you have a script to allow me to actually dooooooooo something?&#8211; LS Hi LS, Doooooooooo we have a [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/53603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=53603"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/53603\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=53603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=53603"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=53603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}