{"id":2312,"date":"2014-01-01T00:01:00","date_gmt":"2014-01-01T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2014\/01\/01\/create-a-proxy-function-to-display-registry-key-time-stamps\/"},"modified":"2014-01-01T00:01:00","modified_gmt":"2014-01-01T00:01:00","slug":"create-a-proxy-function-to-display-registry-key-time-stamps","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/create-a-proxy-function-to-display-registry-key-time-stamps\/","title":{"rendered":"Create a Proxy Function to Display Registry Key Time Stamps"},"content":{"rendered":"<p><b>Summary<\/b>: Guest blogger, Rohn Edwards, discusses creating a Windows PowerShell proxy function to display registry key time stamps.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Happy New Year to you all. Guest blogger, Rohn Edwards, is back with us today to continue his series about retrieving registry key last-modified time stamps. Be sure to read the following blog posts before you start reading the post today, if you have not already done so.<\/p>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-access-registry-last-modified-time-stamp\/\" target=\"_blank\">Use PowerShell to Access Registry Last-Modified Time Stamp<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/reusing-powershell-registry-time-stamp-code\/\" target=\"_blank\">Reusing PowerShell Registry Time Stamp Code<\/a>&nbsp;&nbsp;&nbsp;<\/li>\n<\/ul>\n<p>Yesterday, we built a Windows PowerShell advanced function that gets information from registry keys that isn&rsquo;t normally exposed to Windows PowerShell. Our function gets a key&rsquo;s last-modified time class name. Today, we&rsquo;re going to create a proxy function for <b>Get-ChildItem<\/b> that will let us get this information without calling the tool we built yesterday (it will still use it internally, though).<\/p>\n<p>Before we get started, let me mention two ways that we can make the function behave:<\/p>\n<p style=\"margin-left:30px\">1. We can make it automatically get the information any time you call <b>Get-ChildItem<\/b>.<\/p>\n<p style=\"margin-left:30px\">2. We can make it get the information when you provide a switch parameter to the function. If that parameter isn&rsquo;t provided, <b>Get-ChildItem<\/b> behaves normally.<\/p>\n<p>We&rsquo;re going to go with option #1 today, so any time you use the proxied <b>Get-ChildItem<\/b> on a registry path, you&rsquo;ll get the <b>LastWriteTime<\/b> and the <b>ClassName<\/b>. If you want the behavior from option #2, feel free to modify the final script.<\/p>\n<p style=\"margin-left:30px\"><b>Note<\/b>&nbsp;&nbsp;If you&rsquo;re not familiar with proxy functions, I suggest you read this awesome Hey, Scripting Guy! Blog post by Shay Levy: <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/proxy-functions-spice-up-your-powershell-core-cmdlets\/\" target=\"_blank\">Proxy Functions: Spice Up Your PowerShell Core Cmdlets<\/a>.<\/p>\n<p>The first thing we need to do is let Windows PowerShell generate a function that will call the cmdlet, and we do that with the following two lines:<\/p>\n<p style=\"margin-left:30px\">$MetaData = New-Object System.Management.Automation.CommandMetadata (Get-Command Get-ChildItem)<\/p>\n<p style=\"margin-left:30px\">[System.Management.Automation.ProxyCommand]::Create($MetaData) | clip.exe<\/p>\n<p>By piping it to <b>clip.exe<\/b>, we&rsquo;ve put the generated script in our clipboard. All you have to do is create a function declaration and paste the script inside of it:<\/p>\n<p style=\"margin-left:30px\">function Get-ChildItem {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Paste script here]<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>By running those two lines of Windows PowerShell script and creating the function declaration, you get just over 70 lines of code. It looks intimidating, but it&rsquo;s really not that bad. If you were to run your script now, it should declare the proxy function. If you were to call <b>Get-Command<\/b> with the <b>-All<\/b> parameter, you would see that there is a function and a cmdlet named <b>Get-ChildItem<\/b>:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-1-1-14-1.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/p>\n<p>If you type <b>Get-ChildItem<\/b> at the prompt, it will call the function instead of the cmdlet. Because we haven&rsquo;t modified the script that was generated, the function will pretty much behave exactly like the cmdlet. The parameters that were passed to the function will be forwarded to the original <b>Get-ChildItem<\/b>.<\/p>\n<p>There is some functionality that is missing, though. Our proxy function doesn&rsquo;t have any dynamic parameters. (For more information, see <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-use-powershell-to-find-dynamic-parameters\/\" target=\"_blank\">Use PowerShell to Find Dynamic Parameters<\/a>.) The <b>Get-ChildItem<\/b> cmdlet has some incredibly useful ones, so we&rsquo;re going to have to fix that.<\/p>\n<p>To add the original dynamic parameters back into our proxy function, we&rsquo;re going to need to add the <b>dynamicparam<\/b> keyword. This is a script block that is defined at the same level as the <b>begin<\/b>, <b>process<\/b>, and <b>end<\/b> blocks inside of a function. For more information, see the <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/hh847743.aspx\" target=\"_blank\">about_Functions_Advanced_Parameters<\/a> Help topic.<\/p>\n<p>Here&rsquo;s what our <b>dynamicparam<\/b> block is going to look like:<\/p>\n<p style=\"margin-left:30px\">dynamicparam {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # We need to find the path to use (if no path is specified, use the current path<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # in the current provider:<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($PSBoundParameters.Path) { $GciPath = $PSBoundParameters.Path }<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif ($PSBoundParameters.LiteralPath) { $GciPath = $PSBoundParameters.LiteralPath }<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else { $GciPath = &quot;.&quot; }<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Create the dictionary that this scriptblock will return:<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $DynParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Get dynamic params that real Cmdlet would have:<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Parameters = Get-Command -CommandType Cmdlet -Name Get-ChildItem -ArgumentList $GciPath |<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Select-Object -ExpandProperty Parameters<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach ($Parameter in ($Parameters.GetEnumerator() | Where-Object { $_.Value.IsDynamic })) {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $DynamicParameter = New-Object System.Management.Automation.RuntimeDefinedParameter (<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $Parameter.Key,<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $Parameter.Value.ParameterType,<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $Parameter.Value.Attributes<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $DynParamDictionary.Add($Parameter.Key, $DynamicParameter)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Return the dynamic parameters<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $DynParamDictionary<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>All that&rsquo;s going on here is that we make a call to <b>Get-Command<\/b> for the <b>Get-ChildItem<\/b> cmdlet, and we pass <b>Get-Command<\/b> the path we would pass to <b>Get-ChildItem<\/b>. <b>Get-Command<\/b> gives us back the command info, and we save the parameters collection from that output.<\/p>\n<p>Next, we loop through each parameter that has the <b>IsDynamic<\/b> property set to True, create a new <b>RuntimeDefinedParameter<\/b> each time that has the same name, type, and attributes as the parameter info we got from <b>Get-Command<\/b>, and add that <b>RuntimeDefinedParameter<\/b> object to the parameter dictionary. Finally, we return the parameter dictionary after all of the dynamic parameters have been processed.<\/p>\n<p>If you add the <b>DynamicParam<\/b> block to the function defintion, our proxy function should perfectly mimic the original <b>Get-ChildItem<\/b> cmdlet. Now it&rsquo;s time to add the new functionality! Let&rsquo;s take a look at the original begin block:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-1-1-14-2.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-1-1-14-2.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Take a look at the line where the <b>$scriptCmd<\/b> variable is defined. If you think about it, all we really need to do is add a call to our <b>Add-RegKeyMember<\/b> function from yesterday&rsquo;s post when a registry path has been provided to <b>Get-ChildItem<\/b>. Before we can do that, though, we need to know when the function was called on a registry path. For that, we can turn to the <b>Resolve-Path<\/b> cmdlet:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-1-1-14-3.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-1-1-14-3.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>So, it looks like we can use <b>Resolve-Path<\/b> to see the provider that a path uses. If the <b>Registry<\/b> provider is being used, we can change the <b>$scriptCmd<\/b> variable. Here&rsquo;s the new <b>begin<\/b> block with the modifications:<\/p>\n<p style=\"margin-left:30px\">begin<\/p>\n<p style=\"margin-left:30px\">{<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $outBuffer = $null<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($PSBoundParameters.TryGetValue(&#039;OutBuffer&#039;, [ref]$outBuffer))<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $PSBoundParameters[&#039;OutBuffer&#039;] = 1<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"margin-left:30px\">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand(&#039;Get-ChildItem&#039;, [System.Management.Automation.CommandTypes]::Cmdlet)<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # We need to find the path to use (if no path is specified, use the current path<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # in the current provider:<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($PSBoundParameters.Path) { $GciPath = $PSBoundParameters.Path }<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif ($PSBoundParameters.LiteralPath) { $GciPath = $PSBoundParameters.LiteralPath }<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else { $GciPath = &quot;.&quot; }<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((Resolve-Path $GciPath).Provider.Name -eq &quot;Registry&quot;) {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Registry provider, so call function to get extra key info:<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $scriptCmd = {&amp; $wrappedCmd @PSBoundParameters | Add-RegKeyMember }<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; # Don&#039;t do anything special; just call gci cmdlet:<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $scriptCmd = {&amp; $wrappedCmd @PSBoundParameters }<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $steppablePipeline.Begin($PSCmdlet)<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>And that&rsquo;s it! To use it, save the two functions (<b>Add-RegKeyMember<\/b> and <b>Get-ChildItem<\/b>) to a .ps1 file and dot-source them. (For more information, see <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/how-to-reuse-windows-powershell-functions-in-scripts\/\" target=\"_blank\">How to Reuse Windows PowerShell Functions in Scripts<\/a>.)<\/p>\n<p>If you want the function to always be available, you can dot-source the script in your profile. (For more information, see <a href=\"https:\/\/devblogs.microsoft.com\/scripting\/understanding-and-using-powershell-profiles\/\" target=\"_blank\">Understanding and Using PowerShell Profiles<\/a>.) Or you can add the functions directly to your profile script and not worry about dot-sourcing. &nbsp;<\/p>\n<p>Try out some of these examples:<\/p>\n<p style=\"margin-left:30px\"># Show the last modified time of the keys under HKLM:\\SOFTWARE:<\/p>\n<p style=\"margin-left:30px\">dir HKLM:\\SOFTWARE | Select Name, LastWriteTime<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\"># Show keys under Lsa that have a class name:<\/p>\n<p style=\"margin-left:30px\">dir HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Lsa | where classname | select name, classname<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\"># Get registry keys under HKLM:\\Software that have been modified in the last day:<\/p>\n<p style=\"margin-left:30px\">dir HKLM:\\SOFTWARE -Recurse | ? lastwritetime -gt (Get-Date).AddDays(-1)<\/p>\n<p>~Rohn<\/p>\n<p>Thanks, Rohn, for sharing your time and knowledge. Join us tomorrow as Rohn brings us one more day of awesomeness.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Guest blogger, Rohn Edwards, discusses creating a Windows PowerShell proxy function to display registry key time stamps. Microsoft Scripting Guy, Ed Wilson, is here. Happy New Year to you all. Guest blogger, Rohn Edwards, is back with us today to continue his series about retrieving registry key last-modified time stamps. Be sure to read [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[13,56,31,26,342,3,4,45],"class_list":["post-2312","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-dates-and-times","tag-guest-blogger","tag-operating-system","tag-registry","tag-rohn-edwards","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Guest blogger, Rohn Edwards, discusses creating a Windows PowerShell proxy function to display registry key time stamps. Microsoft Scripting Guy, Ed Wilson, is here. Happy New Year to you all. Guest blogger, Rohn Edwards, is back with us today to continue his series about retrieving registry key last-modified time stamps. Be sure to read [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/2312","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\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=2312"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/2312\/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=2312"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=2312"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=2312"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}