This is the second part of our two-part series on using VBA with JSON in OneNote. Today, we’ll learn how to delete pages, update them, copy to a section, and create sections and section groups.
Using VBA with JSON: OneNote, Part 1 on GitHub
Using VBA with JSON: OneNote, Part 1
Today’s Lesson on GitHub
Link to get token
OneNote API documentation
database sample
Final Code
Or skip down to explanations of how to do various things in OneNote:
- Delete Pages From OneNote Notebook
- Update Pages From OneNote Notebook
- Copy Pages to Section of OneNote Notebook
- Create Section in OneNote Notebook
Some of this content will be repeated from the previous post on how to interact with JSON. If you know how JSON works with VBA and you want to skip directly to the OneNote part, click here to go to “Explanation of Code“.
JSON
JSON stands for JavaScript Object Notation. It is a text string loaded with information that lots of places use to communicate over the internet. The important part is, it’s structured in a way that you can extract pieces of information out of it to use in coding. Many companies have an API that uses JSON that you probably work with every day such as Clio, CourtListener, PayPal, Wunderlist, OneNote, and many others. You can use it to communicate with these companies over the internet and automate the things you do in their software. We will be going over some in the coming weeks. For a more in-depth explanation, I recommend this site. I receive no remuneration for linking that (or anything here); I just like the explanation and think it is sufficient for this exercise.
References
We’ll be working in an empty database. I have provided an almost empty database for this article, which you can find here. It contains three modules and one empty table. Save the database so that you can hit Ctrl + S frequently and save all the time. Get into the habit of it if you can. If you use this database, you may skip down to the section “Security“. If you do not wish to download the sample, continue and we’ll go through setting up our database manually.
Open a new empty database in Access. Just open up Access and select “blank database”. Save it as any name. It’s just a sandbox or testing area, so don’t worry about what it’s called. Once you’ve saved your new empty database, go to Database Tools on the top row above the ribbon and hit ‘Visual Basic’. Now, you should see the following screen:
A module is the white screen you’re looking at in the VBA window. You can name your modules. You may have multiple modules within one file. This is where all your macros and code are stored. But yours will all be empty and we do not want that, so import the two modules from the following two links, VBA Dictionary & JSON Converter. Right click on the “Modules” folder, then import JSON Converter . Right click on “Class Modules”, then import VBA Dictionary. Next, you’ll want to create a third regular module, the one you’ll be editing code in. Mine is named ‘Wunderlist‘. Save again.
You will need to add the following references. References are like libraries that let you use the code we’re learning. These references are what allow ‘early binding’ to occur like we discuss in a little bit. But the more references you add, the bigger your application is and the longer it takes to load, so you only want to turn on the ones you are actually using. Here are the ones we will be using throughout the course of your journey here. The starred ones are the only ones we are actually using today and they are the only ones turned on in the sample database. So if you want to just turn those on, that’s sufficient for this post. But these unstarred ones, you’ll need in later weeks as we progress in the blog.
- Visual Basic for Applications *
- Microsoft Office 16.0 Access database engine Object Library *
- OLE Automation *
- Microsoft OneNote 15.0 Object Library *
- Microsoft Access 16.0 Object Library
- Microsoft XML, v6.0 *
- Microsoft Office 16.0 Object Library *
- Microsoft Scripting Runtime
- Microsoft Word 16.0 Object Library
- Microsoft Internet Controls
- Microsoft Excel 16.0 Object Library
- Microsoft Outlook 16.0 Object Library
- Microsoft Publisher 16.0 Object Library
- Microsoft Shell Controls and Automation
- Microsoft HTML Object Library
- Microsoft WinHTTP Services, version 5.1
- Microsoft OneNote 15.0 Object Library
If you have Adobe Acrobat, you want to make sure these are checked on as well. We are not using any of these for this exercise, so you may leave them unchecked.
- AFormAut 1.0 Type Library
- Adobe Acrobat 9.0 Type Library
- Acrobat Distiller
Security
You should never hard-code a token, password, username, client secret, secret I.D., or anything else you wish to keep safe right into your software or database, meaning you do NOT EVER write in your code something like this:
sToken = "2389407sejklfasdjl23908"
If you do this and someone breaks into your database, they will also have your various secret codes/passwords/etc. At the very least, you should store the various secret phrases, tokens, etc we’ll be discussing in a local text file on a local hard drive, NOT shared, and only give access to it from the current user. Then in theory, after you’ve done that, you could call on it as a variable when you need it and clear it out of memory as soon as you don’t.
Restrict the text file’s access to only your current user allowed or at the very least do not ‘share’ it or put it on a network drive, OneDrive, or a public repository on GitHub (yes, that really happens) or any place like that.
Always use HTTPS for URLs. Do NOT send data over http unless you do not care if the entire world sees it, actors good AND bad, so to speak.
Early Versus Late Binding
Early binding is where you declare a “reference”. As we talked about earlier, you can look at these references by going to Tools –> References in the menu up at the top. With early binding, because the function knows what each object will be doing at start, Intellisense can help you pick out the correct piece of code. It makes auto-fill suggestions for your code.
In late binding, you just declare an object and tell it at the last minute what it should do. But because the object doesn’t know what to do until after the function’s started, Intellisense doesn’t work, among other things. As opposed to the picture below, simply nothing would pop up as you type.
Most of the time, we will be using early binding with references because it is easier to do as a new person, but this exercise will be one example of late binding. Importantly, you do not need to turn on references with late binding. For our purposes, early binding is usually preferred to late.
This exercise has an extra step or two, but it largely similar to the previous exercises we’ve gone through. The main extra step is an authentication step. You need a Microsoft account. Go here to create one if you don’t have one already.
Sign in with your Microsoft account to the Microsoft Dev Center.
Enter in a name, any name, for your app. Mine is named something like ‘accessdb’.
The Microsoft website will ask you or maybe has already if you want to view the app in Azure. Say yes and it will open a new window. For now, go back to the old window you were just at.
On the next page, in “Microsoft Graph Permissions”, click the box “Add” next to “Application Permissions”. Ensure the following four options are checked:
- User.Export.All (Admin Only)
- User.Invite.All (Admin Only)
- User.Read.All (Admin Only)
- User.ReadWrite.All (Admin Only)
Under “Application Secrets”, select “Generate New Password”, and copy+paste the key into its own text file with nothing else in the text file. Save the text file on your local hard drive. What you just saved is called your ‘secret’ in the Microsoft API.
Next, you should see on the same window where you got your ‘secret’ something towards the top called ‘Application ID’ under the ‘Properties’ heading. Copy and paste that into its own text file as well on your local hard drive.
Now, go to the Azure window you opened earlier from the prompt asking you to view the app on the Azure platform. You should see your app there with three pieces of information; the ‘object ID’, ‘application (client) ID’, and the ‘directory (tenant) ID’. You already have saved one of these. Save the remaining two in their own text files to your local drive (two numbers, two text files).
In the same Azure window, you should see the phrase “Managed application in local directory” with your app name. Click on the app name. Click on your ‘total users’, which should be ‘1’. Click on the user there, which should be you, and you will see a heading labeled ‘Identity’. See the ‘object ID’ there? Copy and paste that into its own text file on your local hard drive as well.
The last thing you will need to do is select a phrase which is called a ‘state’. It is simply a text value which can be anything you want and is used to “encode info about the user’s state in the app before the authentication request occurred, such as the page or view they were on”. If you want more info, go here.
For this exercise, I have selected “aqc” as my ‘state’, although that is not my real one. You may save this in a text file, too, if you wish, similar to the other text strings you’ve saved.
Next, you must request permissions by going to a URL constructed from the information we just got:
https://login.microsoftonline.com/{tenant}/adminconsent?client_id={app_id}&state={state}&redirect_uri=http://localhost/myapp/permissions
A dialog to accept/approve will come up and you should accept/approve.
Delete Pages From OneNote Notebook
Now we’re ready to go over the actual VBA code for this exercise. First exercise we’re going to go through is how to delete a page from one of your notebooks.
Here’s the info box at the beginning of the function, variable declarations:
Function fONDeletePage() '==================================================== ' Name : fONDeletePage ' Author : Erica L Ingram ' Copyright : 2019, A Quo Co. ' Call command: Call fONDeletePage() ' Description : delete ON page by page ID '==================================================== Dim sURL As String, sToken As String, sLine4 As String Dim Parsed As Dictionary Dim sFile1 As String, sFile2 As String, sFile3 As String Dim sFile4 As String Dim sLine1 As String, sLine2 As String, sLine3 As String Dim apiWaxLRS As String, sGroupID As String Dim sCBID As String, sPageID As String, sSiteID As String
Next, we’ll get our token as we’ve done before:
'preparing to get token sFile1 = "C:\other\6.txt" 'object id / user ID sFile2 = "C:\other\7.txt" 'directory tenant id sFile3 = "C:\other\8.txt" 'application client id sFile4 = "C:\other\9.txt" 'secret 'before auth if you make privilege changes you must visit 'this website and accept permissions. 'sState = "" '"https://login.microsoftonline.com/" & sLine2 & '"adminconsent?client_id=" & sLine3 & "&state=" & 'sState & '"&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient" Open sFile1 For Input As #1 Line Input #1, sLine1 Close #1 Open sFile2 For Input As #2 Line Input #2, sLine2 Close #2 Open sFile3 For Input As #3 Line Input #3, sLine3 Close #3 Open sFile4 For Input As #4 Line Input #4, sLine4 Close #4 sURL = "https://login.microsoftonline.com/" & sLine2 & "/oauth2/v2.0/token" 'getting token With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Content-Type", "application/x-www-form-urlencoded" .setRequestHeader "Host", "login.microsoftonline.com" .send ("client_id=" & sLine3 & "&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=" & sLine4 & "&grant_type=client_credentials") .waitForResponse apiWaxLRS = .responseText Debug.Print "--------------------------------------------" .abort End With Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sToken = Parsed("access_token")
Now we’re to the new part. You should have gotten a page ID from a function covered in the previous blog post, and it goes in the variable in this chunk of code:
Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sToken = Parsed("access_token") 'fill this in with your page ID sPageID = ""
Next, we construct the URL that we’ll call on to delete the page. The URL can be constructed in a couple different ways and i’ve suggested some here, but there is one uncommented by default.
'several URL options to choose from for deleting pages: 'personal account: 'DELETE https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/onenote/pages/{id} sURL = "https://graph.microsoft.com/v1.0/users/" & sLine1 & "/onenote/pages/" & sPageID 'DELETE https://graph.microsoft.com/v1.0/groups/{id}/onenote/pages/{id} 'sURL = "https://graph.microsoft.com/v1.0/groups/" & sGroupID & "/onenote/pages/" & sPageID 'DELETE https://graph.microsoft.com/v1.0/sites/{id}/onenote/pages/{id} 'sURL = "https://graph.microsoft.com/v1.0/sites/" & sSiteID & "/onenote/pages/" & sPageID
Now, we’re calling on the URL to tell them to delete the page, assigning the response to a variable, and then clearing out information from the sensitive variables since we don’t need it anymore.
With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "DELETE", sURL, False .setRequestHeader "Authorization", "Bearer " & sToken .setRequestHeader "Content-Type", "text/html" .send apiWaxLRS = .responseText If apiWaxLRS = "" Then apiWaxLRS = .status End If sToken = "" sFile2 = "" sFile3 = "" sFile4 = "" sURL = "" sLine1 = "" sLine2 = "" sLine3 = "" sLine4 = "" 'Debug.Print apiWaxLRS 'Debug.Print "--------------------------------------------" .abort End With
Lastly, we’ll print some info to the debug window (Ctrl+G) so we know it deleted successfully. If it isn’t successful, you’ll see the response so you can troubleshoot it.
Debug.Print "Page Deleted, ID No.: " & sPageID Debug.Print "Status: " & apiWaxLRS & " | (204 means deleted successfully)" Debug.Print "--------------------------------------------"
Update Pages From OneNote Notebook
Now, we want to update a page already in the OneNote notebook.
Here’s the info box at the beginning of the function, variable declarations:
Function fONUpdatePage() '============================================================================ ' Name : fONUpdatePage ' Author : Erica L Ingram ' Copyright : 2019, A Quo Co. ' Call command: Call fONUpdatePage() ' Description : update ON page by page ID '============================================================================ Dim sURL As String, sToken As String, sLine4 As String Dim Parsed As Dictionary Dim sFile1 As String, sFile2 As String, sFile3 As String, sFile4 As String Dim sLine1 As String, sLine2 As String, sLine3 As String Dim apiWaxLRS As String, sGroupID As String Dim sCBID As String, sPageID As String, sSiteID As String
Next, we’ll get our token as we’ve done before:
'preparing to get token sFile1 = "C:\other\6.txt" 'object id / user ID sFile2 = "C:\other\7.txt" 'directory tenant id sFile3 = "C:\other\8.txt" 'application client id sFile4 = "C:\other\9.txt" 'secret 'before auth if you make privilege changes you must visit this website and accept permissions. 'sState = "" '"https://login.microsoftonline.com/" & sLine2 & "adminconsent?client_id=" & sLine3 & "&state=" & sState & "&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient" Open sFile1 For Input As #1 Line Input #1, sLine1 Close #1 Open sFile2 For Input As #2 Line Input #2, sLine2 Close #2 Open sFile3 For Input As #3 Line Input #3, sLine3 Close #3 Open sFile4 For Input As #4 Line Input #4, sLine4 Close #4 sURL = "https://login.microsoftonline.com/" & sLine2 & "/oauth2/v2.0/token" 'getting token With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Content-Type", "application/x-www-form-urlencoded" .setRequestHeader "Host", "login.microsoftonline.com" .send ("client_id=" & sLine3 & "&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=" & sLine4 & "&grant_type=client_credentials") .waitForResponse apiWaxLRS = .responseText Debug.Print "--------------------------------------------" .abort End With Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sToken = Parsed("access_token")
Now, we put our page ID that we want to update into a variable and construct the URL we’ll be calling on to update the page. There is one default uncommented, but i have constructed and commented out a couple other versions if you have a need for them.
'fill this in with your page ID sPageID = "" 'several URL options to choose from for updating pages: 'personal account: 'PATCH https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/onenote/pages/{id}/content sURL = "https://graph.microsoft.com/v1.0/users/" & sLine1 & "/onenote/pages/" & sPageID & "/content" 'PATCH https://graph.microsoft.com/v1.0/groups/{id}/onenote/pages/{id}/content 'sURL = "https://graph.microsoft.com/v1.0/groups/" & sGroupID & "/onenote/pages/" & sPageID & "/content" 'PATCH https://graph.microsoft.com/v1.0/sites/{id}/onenote/pages/{id}/content 'sURL = "https://graph.microsoft.com/v1.0/sites/" & sSiteID & "/onenote/pages/" & sPageID & "/content"
Next, we’ll need to construct the JSON string we’ll be sending to tell Microsoft what updates you are making. I have provided an example modified from an example on Microsoft’s site, but you may edit this as necessary.
'update request follows json format: sUpdateJSON = "[{" & _ "'target':'#para-id'," & _ "'action':'insert'," & _ "'position':'before'," & _ "'content':'<img src=" & Chr(34) & "image-url-or-part-name" & Chr(34) & "alt=" & Chr(34) & "image-alt-text" & Chr(34) & " />'" & _ "},{" & _ "'target':'#list-id'," & _ "'action':'append'," & _ "'content':'<li>new-page-content</li>'" & _ "}]"
Next, we’ll call on the URL, send the JSON string we constructed with the required request headers, wait for a response, and clear out the sensitive information from their variables.
'call on URL to delete page With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "PATCH", sURL, False .setRequestHeader "Authorization", "Bearer " & sToken .setRequestHeader "Content-Type", "application/json" .send sUpdateJSON apiWaxLRS = .responseText If apiWaxLRS = "" Then apiWaxLRS = .status End If sToken = "" sFile2 = "" sFile3 = "" sFile4 = "" sURL = "" sLine1 = "" sLine2 = "" sLine3 = "" sLine4 = "" 'Debug.Print apiWaxLRS 'Debug.Print "--------------------------------------------" .abort End With
Lastly, we’ll print some info to the debug window (Ctrl+G) so we know it updated successfully. If it isn’t successful, you’ll see the response so you can troubleshoot it.
'print status on successful update Debug.Print "Page Updated, ID No.: " & sPageID Debug.Print "Status: " & apiWaxLRS & " | (204 means updated successfully)" Debug.Print "--------------------------------------------" End Function
Copy Pages to Section of OneNote Notebook
Now, we want to copy a page already in the OneNote notebook to a certain section.
Here’s the info box at the beginning of the function, variable declarations:
Function fONCopyPageToSection() '============================================================================ ' Name : fONCopyPageToSection ' Author : Erica L Ingram ' Copyright : 2019, A Quo Co. ' Call command: Call fONCopyPageToSection() ' Description : copy ON page by page ID to section '============================================================================ Dim sURL As String, sToken As String, sLine4 As String Dim Parsed As Dictionary Dim sFile1 As String, sFile2 As String, sFile3 As String, sFile4 As String Dim sLine1 As String, sLine2 As String, sLine3 As String Dim apiWaxLRS As String, sGroupID As String Dim sCBID As String, sPageID As String, sSiteID As String
Next, we’ll get our token as we’ve done before:
'preparing to get token sFile1 = "C:\other\6.txt" 'object id / user ID sFile2 = "C:\other\7.txt" 'directory tenant id sFile3 = "C:\other\8.txt" 'application client id sFile4 = "C:\other\9.txt" 'secret 'before auth if you make privilege changes you must visit this website and accept permissions. 'sState = "" '"https://login.microsoftonline.com/" & sLine2 & "adminconsent?client_id=" & sLine3 & "&state=" & sState & "&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient" Open sFile1 For Input As #1 Line Input #1, sLine1 Close #1 Open sFile2 For Input As #2 Line Input #2, sLine2 Close #2 Open sFile3 For Input As #3 Line Input #3, sLine3 Close #3 Open sFile4 For Input As #4 Line Input #4, sLine4 Close #4 sURL = "https://login.microsoftonline.com/" & sLine2 & "/oauth2/v2.0/token" 'getting token With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Content-Type", "application/x-www-form-urlencoded" .setRequestHeader "Host", "login.microsoftonline.com" .send ("client_id=" & sLine3 & "&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=" & sLine4 & "&grant_type=client_credentials") .waitForResponse apiWaxLRS = .responseText Debug.Print "--------------------------------------------" .abort End With Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sToken = Parsed("access_token")
Next, we’ll fill in our page ID/section IDs and construct our URL:
'fill this in with your page ID & desired section ID to copy to sPageID = "" sSectionID = "" 'several URL options to choose from for copying pages: 'personal account: 'POST https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/onenote/pages/{id}/copyToSection sURL = "https://graph.microsoft.com/v1.0/users/" & sLine1 & "/onenote/pages/" & sPageID & "/copyToSection" 'POST https://graph.microsoft.com/v1.0/groups/{id}/onenote/pages/{id}/copyToSection 'sURL = "https://graph.microsoft.com/v1.0/groups/" & sGroupID & "/onenote/pages/" & sPageID & "/copyToSection" 'POST https://graph.microsoft.com/v1.0/me/onenote/pages/{id}/copyToSection 'sURL = "https://graph.microsoft.com/v1.0/me/onenote/pages/" & sPageID & "/copyToSection"
Next we’ll construct a JSON request string to send to Microsoft:
'Here, we're constructing the JSON string we need to send so Microsoft knows which page to copy and to which section to copy. sCopyJSON = "{" & _ Chr(34) & "id" & Chr(34) & ": " & Chr(34) & sPageID & Chr(34) & "," & _ Chr(34) & "groupId" & Chr(34) & ": " & Chr(34) & sSectionID & Chr(34) & _ "}"
So now we’re calling on the URL with some required headers and sending the JSON string we just made. Then we put the response in a variable and clear out the sensitive information from their respective variables.
'call on URL to copy page to desired section With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Authorization", "Bearer " & sToken .setRequestHeader "Content-Type", "application/json" .setRequestHeader "Content-Length", "52" .send sCopyJSON apiWaxLRS = .responseText If apiWaxLRS = "" Then apiWaxLRS = .status End If sToken = "" sFile2 = "" sFile3 = "" sFile4 = "" sURL = "" sLine1 = "" sLine2 = "" sLine3 = "" sLine4 = "" 'Debug.Print apiWaxLRS 'Debug.Print "--------------------------------------------" .abort End With
Lastly, we’ll print some info to the debug window so we know it was successful or, if unsuccessful, an error message that will help you troubleshoot.
'print status on successful update Debug.Print "Page ID No.: " & sPageID & " | Section ID No.: " & sSectionID Debug.Print "Status: " & apiWaxLRS & " | (202 means updated successfully)" Debug.Print "--------------------------------------------" End Function
Create Section in OneNote Notebook
Last function we’ll go over is how to create a section in OneNote.
This part is probably familiar to you; we have our info box and variable declaration, followed by getting some sensitive necessary info into variables and getting our token. So i won’t go over this since this part is the same in every function we’ve gone over in OneNote.
Function fONCreateSection() '============================================================================ ' Name : fONCreateSection ' Author : Erica L Ingram ' Copyright : 2019, A Quo Co. ' Call command: Call fONCreateSection() ' Description : create ON section '============================================================================ Dim sURL As String, sToken As String, sLine4 As String Dim Parsed As Dictionary Dim sFile1 As String, sFile2 As String, sFile3 As String, sFile4 As String Dim sLine1 As String, sLine2 As String, sLine3 As String Dim sResponseText As String, apiWaxLRS As String Dim sONID As String, sSelfLink As String, sCreatedDateTime As String Dim sDisplayName As String, sLastModifiedDateTime As String, isDefault As String Dim sUserRole As String, sIsShared As String, sSectionsUrl As String, sSectionGroupsUrl As String Dim sCBDisplayName As String, sCBLastModifiedName As String Dim sCBLWebURL As String, sIsDefault As String Dim sCBID As String Dim rep Dim sCBLastModifiedID As String, sCBLClientURL As String Dim sJSONRequest As String, sNotebookID As String sFile1 = "C:\other\6.txt" 'object id / user ID sFile2 = "C:\other\7.txt" 'directory tenant id sFile3 = "C:\other\8.txt" 'application client id sFile4 = "C:\other\9.txt" 'secret 'before auth if you make privilege changes you must visit this website and accept permissions. 'sState = "" '"https://login.microsoftonline.com/" & sLine2 & "adminconsent?client_id=" & sLine3 & "&state=" & sState & "&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient" Open sFile1 For Input As #1 Line Input #1, sLine1 Close #1 Open sFile2 For Input As #2 Line Input #2, sLine2 Close #2 Open sFile3 For Input As #3 Line Input #3, sLine3 Close #3 Open sFile4 For Input As #4 Line Input #4, sLine4 Close #4 sURL = "https://login.microsoftonline.com/" & sLine2 & "/oauth2/v2.0/token" With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Content-Type", "application/x-www-form-urlencoded" .setRequestHeader "Host", "login.microsoftonline.com" .send ("client_id=" & sLine3 & "&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=" & sLine4 & "&grant_type=client_credentials") .waitForResponse apiWaxLRS = .responseText Debug.Print "--------------------------------------------" .abort End With Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sToken = Parsed("access_token")
Next, we’ll put the notebook ID where we want the new section in a variable and name our new section.
'notebook id where you want your new section to go sNotebookID = "" 'set new section name here sSectionName = "Testing VBA New Section 1" 'sGroupID = ""
Now we need a URL to call on. I have commented several examples, but the default one is first and uncommented.
'POST https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/onenote/notebooks/{id}/sections sURL = "https://graph.microsoft.com/v1.0/users/" & sLine1 & "/onenote/notebooks/" & sNotebookID & "/sections" 'POST https://graph.microsoft.com/v1.0/groups/{id}/onenote/notebooks/{id}/sections 'sURL = "https://graph.microsoft.com/v1.0/groups/" & sGroupID & "/onenote/notebooks/" & sNotebookID & "/sections" 'POST https://graph.microsoft.com/v1.0/sites/{id}/onenote/notebooks/{id}/sections 'sURL = "https://graph.microsoft.com/v1.0/sites/" & sGroupID & "/onenote/notebooks/" & sNotebookID & "/sections" 'POST https://graph.microsoft.com/v1.0/me/onenote/notebooks/{id}/sections 'sURL = "https://graph.microsoft.com/v1.0/me/onenote/notebooks/" & sNotebookID & "/sections"
Now, we have a very small JSON string we need to construct to send with our request when we call on the URL. Notice your section name goes in here.
sJSONRequest = "{" & Chr(34) & "displayName" & Chr(34) & ": " & Chr(34) & sSectionName & Chr(34) & "}"
Now, we’ll call on the URL and send with it the JSON string we just constructed, put the response into a variable, and clear out the sensitive information.
With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Authorization", "Bearer " & sToken .setRequestHeader "Content-type", "application/json" .setRequestHeader "Content-length", "27" .send sJSONRequest apiWaxLRS = .responseText sToken = "" sFile2 = "" sFile3 = "" sFile4 = "" sURL = "" sLine1 = "" sLine2 = "" sLine3 = "" sLine4 = "" Debug.Print apiWaxLRS Debug.Print "--------------------------------------------" .abort End With
Now, similar to our other functions, we’re going to parse the response into variables and print it out in the debug window.
Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sIsShared = Parsed("@odata.context") sONID = Parsed("id") sSelfLink = Parsed("self") sCreatedDateTime = Parsed("createdDateTime") sTitle = Parsed("displayName") scontentUrl = Parsed("pagesUrl") sLastModifiedDateTime = Parsed("lastModifiedDateTime") Set rep1 = Parsed("links") Set rep2 = rep1("oneNoteClientUrl") sCBLClientURL = rep2("href") Set rep3 = rep1("oneNoteWebUrl") sCBLWebURL = rep3("href") Debug.Print "sIsShared = " & sIsShared Debug.Print "sONID = " & sONID Debug.Print "sTitle = " & sTitle Debug.Print "scontentUrl = " & scontentUrl Debug.Print "sSelfLink = " & sSelfLink Debug.Print "sCreatedDateTime = " & sCreatedDateTime Debug.Print "sLastModifiedDateTime = " & sLastModifiedDateTime Debug.Print "sCBLClientURL = " & sCBLClientURL Debug.Print "sCBLWebURL = " & sCBLWebURL Debug.Print "--------------------------------------------" 'print status on successful section create Debug.Print "Section ID No.: " & sONID & " | Section Name: " & sSectionName Debug.Print "Status: " & apiWaxLRS Debug.Print "201 updated successfully" Debug.Print "--------------------------------------------" End Function
Final Code
- Delete Pages From OneNote Notebook
- Update Pages From OneNote Notebook
- Copy Pages to Section of OneNote Notebook
- Create Section in OneNote Notebook
- Create Section Group in OneNote Notebook
Update Pages From OneNote Notebook
Function fONUpdatePage() '============================================================================ ' Name : fONUpdatePage ' Author : Erica L Ingram ' Copyright : 2019, A Quo Co. ' Call command: Call fONUpdatePage() ' Description : update ON page by page ID '============================================================================ Dim sURL As String, sToken As String, sLine4 As String Dim Parsed As Dictionary Dim sFile1 As String, sFile2 As String, sFile3 As String, sFile4 As String Dim sLine1 As String, sLine2 As String, sLine3 As String Dim apiWaxLRS As String, sGroupID As String Dim sCBID As String, sPageID As String, sSiteID As String Dim sUpdateJSON As String 'preparing to get token sFile1 = "C:\other\6.txt" 'object id / user ID sFile2 = "C:\other\7.txt" 'directory tenant id sFile3 = "C:\other\8.txt" 'application client id sFile4 = "C:\other\9.txt" 'secret 'before auth if you make privilege changes you must visit this website and accept permissions. 'sState = "" '"https://login.microsoftonline.com/" & sLine2 & "adminconsent?client_id=" & sLine3 & "&state=" & sState & "&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient" Open sFile1 For Input As #1 Line Input #1, sLine1 Close #1 Open sFile2 For Input As #2 Line Input #2, sLine2 Close #2 Open sFile3 For Input As #3 Line Input #3, sLine3 Close #3 Open sFile4 For Input As #4 Line Input #4, sLine4 Close #4 sURL = "https://login.microsoftonline.com/" & sLine2 & "/oauth2/v2.0/token" 'getting token With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Content-Type", "application/x-www-form-urlencoded" .setRequestHeader "Host", "login.microsoftonline.com" .send ("client_id=" & sLine3 & "&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=" & sLine4 & "&grant_type=client_credentials") .waitForResponse apiWaxLRS = .responseText Debug.Print "--------------------------------------------" .abort End With Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sToken = Parsed("access_token") 'fill this in with your page ID sPageID = "" 'several URL options to choose from for updating pages: 'personal account: 'PATCH https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/onenote/pages/{id}/content sURL = "https://graph.microsoft.com/v1.0/users/" & sLine1 & "/onenote/pages/" & sPageID & "/content" 'PATCH https://graph.microsoft.com/v1.0/groups/{id}/onenote/pages/{id}/content 'sURL = "https://graph.microsoft.com/v1.0/groups/" & sGroupID & "/onenote/pages/" & sPageID & "/content" 'PATCH https://graph.microsoft.com/v1.0/sites/{id}/onenote/pages/{id}/content 'sURL = "https://graph.microsoft.com/v1.0/sites/" & sSiteID & "/onenote/pages/" & sPageID & "/content" 'update request follows json format: sUpdateJSON = "[{" & _ "'target':'#para-id'," & _ "'action':'insert'," & _ "'position':'before'," & _ "'content':'<img src=" & Chr(34) & "image-url-or-part-name" & Chr(34) & "alt=" & Chr(34) & "image-alt-text" & Chr(34) & " />'" & _ "},{" & _ "'target':'#list-id'," & _ "'action':'append'," & _ "'content':'<li>new-page-content</li>'" & _ "}]" 'call on URL to delete page With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "PATCH", sURL, False .setRequestHeader "Authorization", "Bearer " & sToken .setRequestHeader "Content-Type", "application/json" .send sUpdateJSON apiWaxLRS = .responseText If apiWaxLRS = "" Then apiWaxLRS = .status End If sToken = "" sFile2 = "" sFile3 = "" sFile4 = "" sURL = "" sLine1 = "" sLine2 = "" sLine3 = "" sLine4 = "" 'Debug.Print apiWaxLRS 'Debug.Print "--------------------------------------------" .abort End With 'print status on successful update Debug.Print "Page Updated, ID No.: " & sPageID Debug.Print "Status: " & apiWaxLRS & " | (204 means updated successfully)" Debug.Print "--------------------------------------------" End Function
Delete Pages From OneNote Notebook
Function fONDeletePage() '============================================================================ ' Name : fONDeletePage ' Author : Erica L Ingram ' Copyright : 2019, A Quo Co. ' Call command: Call fONDeletePage() ' Description : delete ON page by page ID '============================================================================ Dim sURL As String, sToken As String, sLine4 As String Dim Parsed As Dictionary Dim sFile1 As String, sFile2 As String, sFile3 As String, sFile4 As String Dim sLine1 As String, sLine2 As String, sLine3 As String Dim apiWaxLRS As String, sGroupID As String Dim sCBID As String, sPageID As String, sSiteID As String 'preparing to get token sFile1 = "C:\other\6.txt" 'object id / user ID sFile2 = "C:\other\7.txt" 'directory tenant id sFile3 = "C:\other\8.txt" 'application client id sFile4 = "C:\other\9.txt" 'secret 'before auth if you make privilege changes you must visit this website and accept permissions. 'sState = "" '"https://login.microsoftonline.com/" & sLine2 & "adminconsent?client_id=" & sLine3 & "&state=" & sState & "&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient" Open sFile1 For Input As #1 Line Input #1, sLine1 Close #1 Open sFile2 For Input As #2 Line Input #2, sLine2 Close #2 Open sFile3 For Input As #3 Line Input #3, sLine3 Close #3 Open sFile4 For Input As #4 Line Input #4, sLine4 Close #4 sURL = "https://login.microsoftonline.com/" & sLine2 & "/oauth2/v2.0/token" 'getting token With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Content-Type", "application/x-www-form-urlencoded" .setRequestHeader "Host", "login.microsoftonline.com" .send ("client_id=" & sLine3 & "&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=" & sLine4 & "&grant_type=client_credentials") .waitForResponse apiWaxLRS = .responseText Debug.Print "--------------------------------------------" .abort End With Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sToken = Parsed("access_token") 'fill this in with your page ID sPageID = "" 'sGroupID = "" 'sSiteID = "" 'several URL options to choose from for deleting pages: 'personal account: 'DELETE https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/onenote/pages/{id} sURL = "https://graph.microsoft.com/v1.0/users/" & sLine1 & "/onenote/pages/" & sPageID 'DELETE https://graph.microsoft.com/v1.0/groups/{id}/onenote/pages/{id} 'sURL = "https://graph.microsoft.com/v1.0/groups/" & sGroupID & "/onenote/pages/" & sPageID 'DELETE https://graph.microsoft.com/v1.0/sites/{id}/onenote/pages/{id} 'sURL = "https://graph.microsoft.com/v1.0/sites/" & sSiteID & "/onenote/pages/" & sPageID 'call on URL to delete page With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "DELETE", sURL, False .setRequestHeader "Authorization", "Bearer " & sToken .setRequestHeader "Content-Type", "text/html" .send apiWaxLRS = .responseText If apiWaxLRS = "" Then apiWaxLRS = .status End If sToken = "" sFile2 = "" sFile3 = "" sFile4 = "" sURL = "" sLine1 = "" sLine2 = "" sLine3 = "" sLine4 = "" 'Debug.Print apiWaxLRS 'Debug.Print "--------------------------------------------" .abort End With 'print status on successful delete Debug.Print "Page Deleted, ID No.: " & sPageID Debug.Print "Status: " & apiWaxLRS & " | (204 means deleted successfully)" Debug.Print "--------------------------------------------" End Function
Copy Pages to Section of OneNote Notebook
Function fONCopyPageToSection() '============================================================================ ' Name : fONCopyPageToSection ' Author : Erica L Ingram ' Copyright : 2019, A Quo Co. ' Call command: Call fONCopyPageToSection() ' Description : copy ON page by page ID to section '============================================================================ Dim sURL As String, sToken As String, sLine4 As String Dim Parsed As Dictionary Dim sFile1 As String, sFile2 As String, sFile3 As String, sFile4 As String Dim sLine1 As String, sLine2 As String, sLine3 As String Dim apiWaxLRS As String, sGroupID As String Dim sCBID As String, sPageID As String, sSiteID As String Dim sCopyJSON As String, sSectionID As String 'preparing to get token sFile1 = "C:\other\6.txt" 'object id / user ID sFile2 = "C:\other\7.txt" 'directory tenant id sFile3 = "C:\other\8.txt" 'application client id sFile4 = "C:\other\9.txt" 'secret 'before auth if you make privilege changes you must visit this website and accept permissions. 'sState = "" '"https://login.microsoftonline.com/" & sLine2 & "adminconsent?client_id=" & sLine3 & "&state=" & sState & "&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient" Open sFile1 For Input As #1 Line Input #1, sLine1 Close #1 Open sFile2 For Input As #2 Line Input #2, sLine2 Close #2 Open sFile3 For Input As #3 Line Input #3, sLine3 Close #3 Open sFile4 For Input As #4 Line Input #4, sLine4 Close #4 sURL = "https://login.microsoftonline.com/" & sLine2 & "/oauth2/v2.0/token" 'getting token With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Content-Type", "application/x-www-form-urlencoded" .setRequestHeader "Host", "login.microsoftonline.com" .send ("client_id=" & sLine3 & "&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=" & sLine4 & "&grant_type=client_credentials") .waitForResponse apiWaxLRS = .responseText Debug.Print "--------------------------------------------" .abort End With Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sToken = Parsed("access_token") 'fill this in with your page ID & desired section ID to copy to sPageID = "" sSectionID = "" 'several URL options to choose from for copying pages: 'personal account: 'POST https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/onenote/pages/{id}/copyToSection sURL = "https://graph.microsoft.com/v1.0/users/" & sLine1 & "/onenote/pages/" & sPageID & "/copyToSection" 'POST https://graph.microsoft.com/v1.0/groups/{id}/onenote/pages/{id}/copyToSection 'sURL = "https://graph.microsoft.com/v1.0/groups/" & sGroupID & "/onenote/pages/" & sPageID & "/copyToSection" 'POST https://graph.microsoft.com/v1.0/me/onenote/pages/{id}/copyToSection 'sURL = "https://graph.microsoft.com/v1.0/me/onenote/pages/" & sPageID & "/copyToSection" 'Here, we're constructing the JSON string we need to send so Microsoft knows which page to copy and to which section to copy. sCopyJSON = "{" & _ Chr(34) & "id" & Chr(34) & ": " & Chr(34) & sPageID & Chr(34) & "," & _ Chr(34) & "groupId" & Chr(34) & ": " & Chr(34) & sSectionID & Chr(34) & _ "}" 'call on URL to copy page to desired section With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Authorization", "Bearer " & sToken .setRequestHeader "Content-Type", "application/json" .setRequestHeader "Content-Length", "52" .send sCopyJSON apiWaxLRS = .responseText If apiWaxLRS = "" Then apiWaxLRS = .status End If sToken = "" sFile2 = "" sFile3 = "" sFile4 = "" sURL = "" sLine1 = "" sLine2 = "" sLine3 = "" sLine4 = "" 'Debug.Print apiWaxLRS 'Debug.Print "--------------------------------------------" .abort End With 'print status on successful update Debug.Print "Page ID No.: " & sPageID & " | Section ID No.: " & sSectionID Debug.Print "Status: " & apiWaxLRS & " | (202 means updated successfully)" Debug.Print "--------------------------------------------" End Function
Create Section in OneNote Notebook
Function fONCreateSection() '============================================================================ ' Name : fONCreateSection ' Author : Erica L Ingram ' Copyright : 2019, A Quo Co. ' Call command: Call fONCreateSection() ' Description : create ON section '============================================================================ Dim sURL As String, sToken As String, sLine4 As String Dim Parsed As Dictionary Dim sFile1 As String, sFile2 As String, sFile3 As String, sFile4 As String Dim sLine1 As String, sLine2 As String, sLine3 As String Dim sResponseText As String, apiWaxLRS As String Dim sONID As String, sSelfLink As String, sCreatedDateTime As String Dim sDisplayName As String, sLastModifiedDateTime As String, isDefault As String Dim sUserRole As String, sIsShared As String, sSectionsUrl As String, sSectionGroupsUrl As String Dim sCBDisplayName As String, sCBLastModifiedName As String Dim sCBLWebURL As String, sIsDefault As String Dim sCBID As String Dim rep Dim sCBLastModifiedID As String, sCBLClientURL As String Dim sJSONRequest As String, sNotebookID As String sFile1 = "C:\other\6.txt" 'object id / user ID sFile2 = "C:\other\7.txt" 'directory tenant id sFile3 = "C:\other\8.txt" 'application client id sFile4 = "C:\other\9.txt" 'secret 'before auth if you make privilege changes you must visit this website and accept permissions. 'sState = "" '"https://login.microsoftonline.com/" & sLine2 & "adminconsent?client_id=" & sLine3 & "&state=" & sState & "&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient" Open sFile1 For Input As #1 Line Input #1, sLine1 Close #1 Open sFile2 For Input As #2 Line Input #2, sLine2 Close #2 Open sFile3 For Input As #3 Line Input #3, sLine3 Close #3 Open sFile4 For Input As #4 Line Input #4, sLine4 Close #4 sURL = "https://login.microsoftonline.com/" & sLine2 & "/oauth2/v2.0/token" With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Content-Type", "application/x-www-form-urlencoded" .setRequestHeader "Host", "login.microsoftonline.com" .send ("client_id=" & sLine3 & "&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret=" & sLine4 & "&grant_type=client_credentials") .waitForResponse apiWaxLRS = .responseText Debug.Print "--------------------------------------------" .abort End With Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sToken = Parsed("access_token") 'notebook id where you want your new section to go sNotebookID = "" 'set new section name here sSectionName = "Testing VBA New Section 1" 'sGroupID = "" 'POST https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/onenote/notebooks/{id}/sections sURL = "https://graph.microsoft.com/v1.0/users/" & sLine1 & "/onenote/notebooks/" & sNotebookID & "/sections" 'POST https://graph.microsoft.com/v1.0/groups/{id}/onenote/notebooks/{id}/sections 'sURL = "https://graph.microsoft.com/v1.0/groups/" & sGroupID & "/onenote/notebooks/" & sNotebookID & "/sections" 'POST https://graph.microsoft.com/v1.0/sites/{id}/onenote/notebooks/{id}/sections 'sURL = "https://graph.microsoft.com/v1.0/sites/" & sGroupID & "/onenote/notebooks/" & sNotebookID & "/sections" 'POST https://graph.microsoft.com/v1.0/me/onenote/notebooks/{id}/sections 'sURL = "https://graph.microsoft.com/v1.0/me/onenote/notebooks/" & sNotebookID & "/sections" sJSONRequest = "{" & Chr(34) & "displayName" & Chr(34) & ": " & Chr(34) & sSectionName & Chr(34) & "}" With CreateObject("WinHttp.WinHttpRequest.5.1") .Open "POST", sURL, False .setRequestHeader "Authorization", "Bearer " & sToken .setRequestHeader "Content-type", "application/json" .setRequestHeader "Content-length", "27" .send sJSONRequest apiWaxLRS = .responseText sToken = "" sFile2 = "" sFile3 = "" sFile4 = "" sURL = "" sLine1 = "" sLine2 = "" sLine3 = "" sLine4 = "" Debug.Print apiWaxLRS Debug.Print "--------------------------------------------" .abort End With Set Parsed = JsonConverter.ParseJson(apiWaxLRS) sIsShared = Parsed("@odata.context") sONID = Parsed("id") sCreatedDateTime = Parsed("createdDateTime") sTitle = Parsed("displayName") scontentUrl = Parsed("pagesUrl") sLastModifiedDateTime = Parsed("lastModifiedDateTime") Set rep1 = Parsed("links") Set rep2 = rep1("oneNoteClientUrl") sCBLClientURL = rep2("href") Set rep3 = rep1("oneNoteWebUrl") sCBLWebURL = rep3("href") Debug.Print "sIsShared = " & sIsShared Debug.Print "sONID = " & sONID Debug.Print "sTitle = " & sTitle Debug.Print "scontentUrl = " & scontentUrl Debug.Print "sCreatedDateTime = " & sCreatedDateTime Debug.Print "sLastModifiedDateTime = " & sLastModifiedDateTime Debug.Print "sCBLClientURL = " & sCBLClientURL Debug.Print "sCBLWebURL = " & sCBLWebURL Debug.Print "--------------------------------------------" 'print status on successful section create Debug.Print "Section ID No.: " & sONID & " | Section Name: " & sSectionName Debug.Print "Status: " & apiWaxLRS Debug.Print "201 updated successfully" Debug.Print "--------------------------------------------" End Function