{"id":51523,"date":"2010-01-20T00:01:00","date_gmt":"2010-01-20T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2010\/01\/20\/hey-scripting-guy-how-do-i-work-with-windows-powershell-module-paths\/"},"modified":"2010-01-20T00:01:00","modified_gmt":"2010-01-20T00:01:00","slug":"hey-scripting-guy-how-do-i-work-with-windows-powershell-module-paths","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-do-i-work-with-windows-powershell-module-paths\/","title":{"rendered":"Hey, Scripting Guy! How Do I Work with Windows PowerShell Module Paths?"},"content":{"rendered":"<p><a class=\"addthis_button\" href=\"http:\/\/www.addthis.com\/bookmark.php?v=250&amp;pub=scriptingguys\"><img decoding=\"async\" alt=\"Bookmark and Share\" src=\"http:\/\/s7.addthis.com\/static\/btn\/v2\/lg-share-en.gif\" width=\"125\" height=\"16\"><\/a><\/p>\n<p>&nbsp;\n<font size=\"2\"><img decoding=\"async\" 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\"><\/font><\/p>\n<p class=\"MsoNormal\">Hey, Scripting Guy! I have been reading your articles about Windows PowerShell modules this week, but I am still a bit confused about where they go, how to get them there, and the best practice for dealing with them. Do you have any insight about how to actually work with Windows PowerShell module paths?<\/p>\n<p class=\"MsoNormal\">&#8212; KG<\/p>\n<p class=\"MsoNormal\">\n<p>&nbsp;<\/p>\n<p class=\"MsoNormal\"><img decoding=\"async\" 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\">Hello KG, <\/p>\n<p class=\"MsoNormal\">Microsoft Scripting Guy Ed Wilson here. I am drinking espresso this afternoon because I am answering the <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\"><font face=\"Segoe\">scripter@microsoft.com<\/font><\/a> e-mail. I have a small stovetop espresso machine I picked up in Naples, Italy, many years ago that I use to brew the espresso. I was up late last night reading <a href=\"http:\/\/en.wikipedia.org\/wiki\/David_Copperfield_(novel)\"><font face=\"Segoe\">David Copperfield<\/font><\/a> (Scripting Guys do not read only technical books), and I need an extra kick-start. I do not use any sugar in my coffee or espresso; instead, I place a cinnamon stick in the cup, a trick I picked up in Lisbon. As I sit staring blankly at my computer monitor, my mind wanders back to a similar time when I sat drinking espresso. Instead of being bundled up and freezing, however, I was wearing short sleeves and relishing a cool gentle breeze. The sky was an incredible cobalt blue, and I was at peace with the world. I snapped the following photo as I mellowed out in a sidewalk caf&eacute; in Buenos Aires. <\/p>\n<p class=\"Fig-Graphic\"><img decoding=\"async\" title=\"Image of beautiful day in Buenos Aires\" alt=\"Image of beautiful day in Buenos Aires\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2010\/january\/hey0120\/hsg-01-20-10-01.jpg\" width=\"600\" height=\"450\"><\/p>\n<p class=\"MsoNormal\">&nbsp;<\/p>\n<p class=\"MsoNormal\">I was in Buenos Aires teaching a VBScript class at the Microsoft offices down there, and as I sat sipping my espresso, I was the happiest guy in the world&mdash;awesome friends, excellent coffee, fantastic weather. What more could one want? <\/p>\n<p class=\"MsoNormal\">KG, it is amazing how powerful certain memories can be, and how quickly they can be triggered. Maybe because <a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2009\/09\/08\/hey-scripting-guy-september-8-2009.aspx\"><font face=\"Segoe\">I seldom drink coffee<\/font><\/a>, I can remember nearly every cup I ever drank and the occasion for it. The cup of espresso in Buenos Aires is high on my top 10 list of favorite cups of coffee.<\/p>\n<p class=\"MsoNormal\">Enough daydreaming. Let&rsquo;s get back to work. The path that will be used to store the module is stored in the <b>$modulepath<\/b> variable. This path includes the path to the users&#8217; modules folder plus a child folder that is the same name as the module itself. To create the new path, it is a best practice to use the <b>Join-Path<\/b> cmdlet instead of doing string concatenation and attempting to manually build the path to the new folder. The <b>Join-Path<\/b> cmdlet will put together a parent path and a child path to create a new path. This is seen here: <\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">$ModulePath = Join-Path -path $userPath `<br \/><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>-childpath (Get-Item -path $name).basename<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">To Windows PowerShell 2.0, the Windows PowerShell team added a script property called <b>basename<\/b> to the <b>System.Io.FileInfo<\/b> class. This makes it easy to retrieve the name of a file without the file extension. Before Windows PowerShell 2.0, it was common to use the <b>split<\/b><i> <\/i>method or some other string manipulation technique to remote the extension from the file name. Use of the <b>basename<\/b> property is shown here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">PS C:&gt; (Get-Item -Path C:fsoHelloWorld.psm1).basename<br \/>HelloWorld<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The last step that needs to be accomplished is to create the subdirectory that will hold the module and to copy the module files into the directory. To avoid cluttering the display with the returned information from the <b>New-Item<\/b> and <b>Copy-Item<\/b> cmdlets, the results are pipelined to the <b>Out-Null<\/b> cmdlet:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">New-Item -path $modulePath -itemtype directory | Out-Null<br \/>Copy-item -path $name -destination $ModulePath | Out-Null<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The entry point to the Copy-Modules.ps1 script calls the <b>Test-ModulePath<\/b> function to determine if the users&#8217; modules folder exists. It then uses the <b>Get-ChildItem<\/b> cmdlet to retrieve a listing of all the module files in a particular folder. The <b>&ndash;Recurse<\/b> parameter is used retrieve all the module files in the path. The resulting <b>FileInfo<\/b> objects are pipelined to the <b>ForEach-Object<\/b> cmdlet. The <b>fullname<\/b> property of each <b>FileInfo<\/b> object is passed to the <b>Copy-Module<\/b> function. This is shown here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">Test-ModulePath<br \/>Get-ChildItem -Path C:fso -Include *.psm1,*.psd1 -Recurse |<br \/>Foreach-Object { Copy-Module -name $_.fullName }<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The complete Copy-Modules.ps1 script is seen here. <\/p>\n<p class=\"MsoNormal\"><b>Copy-Modules.ps1<\/p>\n<p><\/b><\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">\nFunction Get-OperatingSystemVersion<br \/>{<br \/><span>&nbsp;<\/span>(Get-WmiObject -Class Win32_OperatingSystem).Version<br \/>} #end Get-OperatingSystemVersion<\/p>\n<p>Function Test-ModulePath<br \/>{<br \/><span>&nbsp;<\/span>$VistaPath = &#8220;$env:userProfiledocumentsWindowsPowerShellModules&#8221;<br \/><span>&nbsp;<\/span>$XPPath =<span>&nbsp; <\/span>&#8220;$env:Userprofilemy documentsWindowsPowerShellModules&#8221; <br \/><span>&nbsp;<\/span>if ([int](Get-OperatingSystemVersion).substring(0,1) -ge 6) <br \/><span>&nbsp;&nbsp; <\/span>{ <br \/><span>&nbsp;&nbsp;&nbsp;&nbsp; <\/span>if(-not(Test-Path -path $VistaPath))<br \/><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>{<br \/><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>New-Item -Path $VistaPath -itemtype directory | Out-Null<br \/><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>} #end if<br \/><span>&nbsp;&nbsp; <\/span>} #end if<br \/><span>&nbsp;<\/span>Else <br \/><span>&nbsp;&nbsp; <\/span>{<span>&nbsp; <\/span><br \/><span>&nbsp; <\/span><span>&nbsp;&nbsp;&nbsp;<\/span>if(-not(Test-Path -path $XPPath))<br \/><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>{<br \/><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>New-Item -path $XPPath -itemtype directory | Out-Null<br \/><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>} #end if<br \/><span>&nbsp;&nbsp; <\/span>} #end else<br \/>} #end Test-ModulePath<\/p>\n<p>Function Copy-Module([string]$name)<br \/>{<br \/><span>&nbsp;<\/span>$UserPath = $env:PSModulePath.split(&#8220;;&#8221;)[0]<br \/><span>&nbsp;<\/span>$ModulePath = Join-Path -path $userPath `<br \/><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>-childpath (Get-Item -path $name).basename<br \/><span>&nbsp;<\/span>New-Item -path $modulePath -itemtype directory | Out-Null<br \/><span>&nbsp;<\/span>Copy-item -path $name -destination $ModulePath | Out-Null<br \/>}<\/p>\n<p># *** Entry Point to Script *** <br \/>Test-ModulePath<br \/>Get-ChildItem -Path C:fso -Include *.psm1,*.psd1 -Recurse |<br \/>Foreach-Object { Copy-Module -name $_.fullName }<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Readeraidonly\">Note: Scripting support does not need to be enabled in Windows PowerShell to use modules. However, to run the Copy-Modules.ps1 to install modules to the users profile, you will need script support. To enable scripting support in Windows PowerShell, use the <b>Set-ExecutionPolicy<\/b> cmdlet. You could also use Xcopy to copy modules to the user&#8217; modules folder. <\/p>\n<p class=\"MsoNormal\">An easy way to work with modules is to create a couple of Windows PowerShell drives using the <b>filesystem<\/b> provider. Because the modules live in a location that is not easily navigated to from the command line, and because the <b>$PSModulePath<\/b> returns a string that contains the path to both the users&#8217; and the system modules folders, it makes sense to provide an easier way to work with the modules location. To create a Windows PowerShell drive for the user module location, you use <b>New-PSDrive<\/b> cmdlet, specify a name such as <b>mymods<\/b>, use the <b>filesystem<\/b> provider, and obtain the root location from the <b>$PSModulePath<\/b> environmental variable by using the <b>split<\/b> method from the .NET Framework string class. For the users&#8217; modules folder, you use the first element from the returned array. This is shown here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">PS C:&gt; New-PSDrive -Name mymods -PSProvider filesystem -Root `<br \/>(($env:PSModulePath).Split(&#8220;;&#8221;)[0])<\/p>\n<p>WARNING: column &#8220;CurrentLocation&#8221; does not fit into the display and was removed<br \/>.<\/p>\n<p>Name<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Used (GB)<span>&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Free (GB) Provider<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Root<br \/>&#8212;-<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>&#8212;&#8212;&#8212;<span>&nbsp;&nbsp;&nbsp;&nbsp; <\/span>&#8212;&#8212;&#8212; &#8212;&#8212;&#8211;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>&#8212;-<br \/>mymods<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>47.62 FileSystem<span>&nbsp;&nbsp;&nbsp; <\/span>C:Usersadministrator&#8230;.<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">The command to create a Windows PowerShell drive for the system module location is exactly the same as the one used to create a Windows PowerShell drive for the user module location, with the exception of specifying a different name such as <b>sysmods<\/b> and choosing the second element from the array you obtain by using the <b>split<\/b> method from on the <b>$PSModulePath<\/b> variable. This command is seen here:<\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">PS C:&gt; New-PSDrive -Name sysmods -PSProvider filesystem -Root `<br \/>(($env:PSModulePath).Split(&#8220;;&#8221;)[1])<\/p>\n<p>WARNING: column &#8220;CurrentLocation&#8221; does not fit into the display and was removed<br \/>.<\/p>\n<p>Name<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Used (GB)<span>&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Free (GB) Provider<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Root<br \/>&#8212;-<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span>&#8212;&#8212;&#8212;<span>&nbsp;&nbsp;&nbsp;&nbsp; <\/span>&#8212;&#8212;&#8212; &#8212;&#8212;&#8211;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>&#8212;-<br \/>sysmods<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>47.62 FileSystem<span>&nbsp;&nbsp;&nbsp; <\/span>C:WindowsSystem32Win&#8230;<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"Readeraidonly\">Note: I like to create my Windows PowerShell drives for the two module locations in my personal profile. In this way, the drives are always available when I need to utilize them.<\/p>\n<p class=\"MsoNormal\">You can also write a script that creates Windows PowerShell drives for each of the two module locations. To do this, you first create an array of names for the Windows PowerShell drives. You then use a <b>for<\/b> statement to walk through the array of Windows PowerShell drive names, and call the <b>New-PSDrive<\/b> cmdlet. Because you are running the commands inside a script, it means the new Windows PowerShell drives by default would live wit\nhin the script scope. After the script ends, the script scope goes away. This means the Windows PowerShell drives would not be available after the script ended, which would defeat our purposes in creating them in the first place. To combat this scoping issue, you need to create the Windows PowerShell drives within the <b>Global<\/b> scope, which means they will be available in the Windows PowerShell console after the script has completed running. To avoid displaying confirmation messages when creating the Windows PowerShell drives, you pipe the results to the <b>Out-Null<\/b> cmdlet. <\/p>\n<p class=\"MsoNormal\">In the New-ModulesDrive.ps1 script, another function is created. This function displays global <b>filesystem<\/b> Windows PowerShell drives. When the script is run, the <b>New-ModuleDrives<\/b> function is called. It is followed by calling the <b>Get-FileSystemDrives<\/b> function. The complete New-ModulesDrive.ps1 script is shown here. <\/p>\n<p class=\"MsoNormal\"><b>New-ModulesDrive.ps1<\/p>\n<p><\/b><\/p>\n<p class=\"CodeBlockScreened\"><font><font face=\"Lucida Sans Typewriter\">Function New-ModuleDrives<br \/>{<br \/>&lt;#<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>.SYNOPSIS<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>Creates two PSDrives: myMods and sysMods<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>.EXAMPLE<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>New-ModuleDrives<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>Creates two PSDrives: myMods and sysMods. These correspond <br \/><span>&nbsp;&nbsp;&nbsp; <\/span>to the users&#8217; modules folder and the system modules folder respectively. <br \/>#&gt;<br \/><span>&nbsp;<\/span>$driveNames = &#8220;myMods&#8221;,&#8221;sysMods&#8221;<\/p>\n<p><span>&nbsp;<\/span>For($i = 0 ; $i -le 1 ; $i++)<br \/><span>&nbsp;<\/span>{<br \/><span>&nbsp; <\/span>New-PsDrive -name $driveNames[$i] -PSProvider filesystem `<br \/><span>&nbsp; <\/span>-Root ($env:PSModulePath.split(&#8220;;&#8221;)[$i]) -scope Global |<br \/><span>&nbsp; <\/span>Out-Null<br \/><span>&nbsp;<\/span>} #end For<br \/>} #end New-ModuleDrives<\/p>\n<p>Function Get-FileSystemDrives<br \/>{<br \/>&lt;#<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>.SYNOPSIS<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>Displays global PS Drives that use the Filesystem provider<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>.EXAMPLE<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>Get-FileSystemDrives<br \/><span>&nbsp;&nbsp;&nbsp; <\/span>Displays global PS Drives that use the Filesystem provider<br \/>#&gt;<br \/><span>&nbsp;<\/span>Get-PSDrive -PSProvider FileSystem -scope Global<br \/>} #end Get-FileSystemDrives<\/p>\n<p># *** EntryPoint to Script ***<br \/>New-ModuleDrives<br \/>Get-FileSystemDrives<\/p>\n<p><\/font><\/font><\/p>\n<p class=\"MsoNormal\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"MsoNormal\">KG, that is all there is to using Windows PowerShell modules. Windows PowerShell Module Week will continue tomorrow. <\/p>\n<p class=\"MsoNormal\">If you want to know exactly what we will be looking at tomorrow, follow us on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> or <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\"><font face=\"Segoe\">Facebook<\/font><\/a>. If you have any questions, send e-mail to us at <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\" target=\"_blank\"><font face=\"Segoe\">scripter@microsoft.com<\/font><\/a> or post them on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\"><font face=\"Segoe\">Official Scripting Guys Forum<\/font><\/a>. See you tomorrow. Until then, peace.<\/p>\n<p class=\"MsoNormal\">\n<p>&nbsp;<\/p>\n<\/p>\n<p><b><span>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/p>\n<p><\/span><\/b><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Hey, Scripting Guy! I have been reading your articles about Windows PowerShell modules this week, but I am still a bit confused about where they go, how to get them there, and the best practice for dealing with them. Do you have any insight about how to actually work with Windows PowerShell module paths? [&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":[51,52,3,4,45],"class_list":["post-51523","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-getting-started","tag-modules","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; Hey, Scripting Guy! I have been reading your articles about Windows PowerShell modules this week, but I am still a bit confused about where they go, how to get them there, and the best practice for dealing with them. Do you have any insight about how to actually work with Windows PowerShell module paths? [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/51523","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=51523"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/51523\/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=51523"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=51523"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=51523"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}