Tag Archives: Invoke-RESTMethod

Changes to Invoke-RestMethod in PowerShell 7

The Invoke-RestMethod cmdlet has been with us since PowerShell 3.0. For those of us paying attention to PowerShell during the 2.0 to 3.0 transition, it was a huge release and the inclusion of this new command was only one of the reasons why. From that point forward, we had a built-in, PowerShell way to interact with RESTful Web Services. REST (Representational State Transfer) web services accept HTTP(S) requests, and respond with structured data, often in the form of JSON. This structured data is converted by the Invoke-RestMethod cmdlet into PowerShell objects. The command was greatly improved in PowerShell 6, but today we’re going to focus on the newest changes in PowerShell 7.

If you spent any time in the help file/online docs for Invoke-RestMethod (5.1 and 7.0), then you’ve likely seen the below example. It shows the basic ability of the cmdlet, and returns some worth wild results, too. The below results are created for us after issuing a specific, Invoke-RestMethod command. You can see it below. We first assigned the $Uri variable an exact, URI (Uniform Resource Identifier) value. This complete URI is the combination of the base URI, “https://blogs.msdn.microsoft.com,” and the endpoint, “/powershell/feed.” We then used the variable in the Invoke-RestMethod command, which makes an HTTPS request for the data, receives a response, and finally, converts it into PowerShell objects, where it’s then filtered by our Select-Object command.

$Uri = 'https://blogs.msdn.microsoft.com/powershell/feed/'
Invoke-RestMethod -Uri $Uri | Select-Object -Property Title,pubDate
 
title                                                     pubDate
-----                                                     -------
Secrets Management Module Vault Extensions                Thu, 06 Feb 2020 22:59:33 +0000
Public Preview of PowerShell Support in Jupyter Notebooks Thu, 06 Feb 2020 21:46:52 +0000
Secrets Management Development Release                    Thu, 06 Feb 2020 20:40:50 +0000
Announcing the PowerShell 7.0 Release Candidate           Tue, 17 Dec 2019 00:42:17 +0000
Improvements in Windows PowerShell Container Images       Tue, 10 Dec 2019 00:32:57 +0000
PowerShell 7 Preview 6                                    Fri, 22 Nov 2019 01:20:37 +0000
PowerShell Extension Roadmap                              Mon, 04 Nov 2019 13:19:35 +0000
DSC Resource Kit Release October 2019                     Wed, 30 Oct 2019 20:52:48 +0000
PowerShell 7 Preview 5                                    Wed, 23 Oct 2019 19:11:44 +0000
DSC Resource Kit Release September 2019                   Thu, 19 Sep 2019 18:07:12 +0000

As we continue, do keep in mind that Invoke-RestMethod can do much more than what we’ve seen so far, and what we’ll cover. It can do POST requests, handle pagination, handle multipart/form-data, and it can pass in multiple headers if required. Don’t forget about authentication and credentials; it can handle those, as well.

In PowerShell 7, there are a couple of newer features we’ll cover today. Before we do that, if you didn’t use this cmdlet in PowerShell 6, then do know that there were many changes in that version. You can actually find the PowerShell 6 features in the Invoke-RestMethod PowerShell 7 documentation.

Before we get into the new features, here’s another example of using Invoke-RestMethod. This article has coincided well with some of my AWS research and testing with Lambda and API Gateway. The below image shows some testing against a random number generator that has a REST API in front of it. That’s why there are various numbers in the results.

There are two new parameters for Invoke-RestMethod in PowerShell 7: StatusCodeVariable and SkipHttpErrorCheck.

The StatusCodeVariable parameter allows you to assign the status code, returned by the request to the RESTful web service, to a variable. As the below example was successful, it assigned 200, or an OK successful status response code, to the scv variable.

As mentioned, the other new parameter addition to this cmdlet is SkipHttpErrorCheck. This parameter causes Invoke-RestMethod to ignore an error status. It treats them as though they were successful requests. Without it, however, we received the error, as can be seen in the first Invoke-RestMethod invocation below. It’s not clear by the image, but the value in $Uri has been changed between our successful examples and this one.

The second invocation in the below image appeared that it was (somewhat) successful, but that was thanks to SkipHttpErrorCheck. It wasn’t, and you can gather that from the message that was returned, even though we’ve skipped the error.

The question is, “how might you know for sure if there was an error and you skipped it?” Yep. The StatusCodeVariable parameter and the variable to which you’ve assigned the status code. These two new parameters can be used in conjunction. The final command in the below example, uses both of the new PowerShell 7 Invoke-RestMethod parameters, as part of a single command.

Invoke-RestMethod is a complex command that consists of many ways in which it can be used. A full discussion on everything you can do with Invoke-RestMethod could fill up an entire PSBlogWeek (or two), all by itself. Even so, with the release of PowerShell 7, it made sense that as a group, we helped highlight this command and its two new parameters. It’s just a small offering of all the new additions in the newest version of PowerShell.

Welcome to PowerShell 7.0.

Use PowerShell to Edit a CSV


Notice: There is now a revisited, or second, Edit a CSV post. This time, however, we are obtaining and writing portions of a REST API response to our CSV.


I recently completed a scripting assignment for work. Yeah… it’s a part of what I do. During the process I learned something new, that I hadn’t known before. And like it normally does, this leaves me in a position to share it with the Internet, as well as help solidify it in my own mind. And that’s, why I’m writing today.

I thought my recent assignment had a need to edit an existing CSV file on the fly. It turns out it wasn’t necessary for the project, but just maybe it will be for another one, or maybe even one that’s sitting in front of you right now. So, how do you do that? How do you edit an existing CSV file?

Let’s begin with a simple, yet worthy CSV file as an example. In the below CSV data, we have four columns, fields, or properties — whatever you want to call them at this point. They are Name, Status, BatchName, and SentNotification. The idea here — or what I thought it was in my recent assignment, at first — was to notify by email the users that were in a Synced state (Status column) and then modify the SentNotification field so that it said True, instead of False. Take a look at our example data.

Name,Status,BatchName,SentNotification
landrews,Other,MigrationService:FirstBatch-to-O365,FALSE
lpope,Synced,MigrationService:FirstBatch-to-O365,FALSE
ljohnson,Other,MigrationService:FirstBatch-to-O365,FALSE
mlindsay,Other,MigrationService:FirstBatch-to-O365,FALSE
rperkins,Synced,MigrationService:FirstBatch-to-O365,FALSE
dstevenson,Other,MigrationService:FirstBatch-to-O365,FALSE
jbradford,Other,MigrationService:FirstBatch-to-O365,FALSE
jsmith,Other,MigrationService:FirstBatch-to-O365,FALSE
mdavidson,Synced,MigrationService:FirstBatch-to-O365,FALSE
bclark,Synced,MigrationService:FirstBatch-to-O365,FALSE

Let’s first begin by using Import-Csv and Format-Table to view our data.

Import-Csv -Path '.\Desktop\UCSVTestFile.csv' | Format-Table -AutoSize

Name       Status BatchName                           SentNotification
----       ------ ---------                           ----------------
landrews   Other  MigrationService:FirstBatch-to-O365 FALSE           
lpope      Synced MigrationService:FirstBatch-to-O365 FALSE           
ljohnson   Other  MigrationService:FirstBatch-to-O365 FALSE           
mlindsay   Other  MigrationService:FirstBatch-to-O365 FALSE           
rperkins   Synced MigrationService:FirstBatch-to-O365 FALSE           
dstevenson Other  MigrationService:FirstBatch-to-O365 FALSE           
jbradford  Other  MigrationService:FirstBatch-to-O365 FALSE           
jsmith     Other  MigrationService:FirstBatch-to-O365 FALSE           
mdavidson  Synced MigrationService:FirstBatch-to-O365 FALSE           
bclark     Synced MigrationService:FirstBatch-to-O365 FALSE

Now what we need to do, is modify the content, as it’s being imported. Let’s start first, however, by piping our Import-Csv cmdlet to ForEach-Object and returning each object (line).

Import-Csv -Path '.\Desktop\UCSVTestFile.csv' | ForEach-Object {
    $_
}

Name       Status BatchName                           SentNotification
----       ------ ---------                           ----------------
landrews   Other  MigrationService:FirstBatch-to-O365 FALSE           
lpope      Synced MigrationService:FirstBatch-to-O365 FALSE           
ljohnson   Other  MigrationService:FirstBatch-to-O365 FALSE           
mlindsay   Other  MigrationService:FirstBatch-to-O365 FALSE           
rperkins   Synced MigrationService:FirstBatch-to-O365 FALSE           
dstevenson Other  MigrationService:FirstBatch-to-O365 FALSE           
jbradford  Other  MigrationService:FirstBatch-to-O365 FALSE           
jsmith     Other  MigrationService:FirstBatch-to-O365 FALSE           
mdavidson  Synced MigrationService:FirstBatch-to-O365 FALSE           
bclark     Synced MigrationService:FirstBatch-to-O365 FALSE

Hey, look at that. It’s the same thing. The $_ variable represents the current object, or the current row, — if it helps to think about it that way — in the pipeline. Let’s add an If statement inside our ForEach-Object loop, and get the results we’re after. Remember, if a user has a Synced status, we want to change their SentNotification property to $true, and perhaps notify them, had this been more than just an example.

Import-Csv -Path '.\Desktop\UCSVTestFile.csv' | ForEach-Object {
    If ($_.Status -eq 'Synced' -and $_.SentNotification -eq $false) {
        $_.SentNotification = $true
    }
    $_
} | Format-Table -AutoSize

Name       Status BatchName                           SentNotification
----       ------ ---------                           ----------------
landrews   Other  MigrationService:FirstBatch-to-O365 FALSE           
lpope      Synced MigrationService:FirstBatch-to-O365 True            
ljohnson   Other  MigrationService:FirstBatch-to-O365 FALSE           
mlindsay   Other  MigrationService:FirstBatch-to-O365 FALSE           
rperkins   Synced MigrationService:FirstBatch-to-O365 True            
dstevenson Other  MigrationService:FirstBatch-to-O365 FALSE           
jbradford  Other  MigrationService:FirstBatch-to-O365 FALSE           
jsmith     Other  MigrationService:FirstBatch-to-O365 FALSE           
mdavidson  Synced MigrationService:FirstBatch-to-O365 True            
bclark     Synced MigrationService:FirstBatch-to-O365 True

In the above example, we use an If statement to check the values of two properties. If Status is Synced and SentNotification is $false, we’ll change SentNotification to $true. You can see that this worked. But what now? You see, the file from which we did our import is still the same. In order to update that file, we have a bit more work to do.

I wish I could say pipe directly back to the file; however, that doesn’t work. The file ends up being blank. It makes sense it doesn’t work though, as we’re literally reading each object — each row — and then trying to write back to the file in the same pipeline. Something is bound to go wrong, and it does. So, don’t do what’s in the below example, unless your goal is to fail at this assignment and wipe out your data. If that’s what you’re after, then by all means, have at it.

Import-Csv -Path '.\Desktop\UCSVTestFile.csv' | ForEach-Object {
    If ($_.Status -eq 'Synced' -and $_.SentNotification -eq $false) {
        $_.SentNotification = $true
    }
    $_
} | Export-Csv -Path '.\Desktop\UCSVTestFile.csv' -NoTypeInformation

What we need to do instead, is Export to a file with a different name, so that when we’re done, both files exist at the same time. Then, we remove the original file and rename the new one with the old one’s name. Here’s the entire example; take a look. And then after that, enjoy the weekend. Oh wait, tomorrow is only Friday. I keep thinking it’s the weekend, because I’m home tomorrow to deal with 1,000 square feet of sod. If only PowerShell could lay the sod for me.

Import-Csv -Path '.\Desktop\UCSVTestFile.csv' | ForEach-Object {
    If ($_.Status -eq 'Synced' -and $_.SentNotification -eq $false) {
        $_.SentNotification = $true
    }
    $_
} | Export-Csv -Path '.\Desktop\UCSVTestFile-temp.csv' -NoTypeInformation
Remove-Item -Path '.\Desktop\UCSVTestFile.csv'
Rename-Item -Path '.\Desktop\UCSVTestFile-temp.csv' -NewName 'UCSVTestFile.csv'