Prevent Renaming Outlook Folder

I have a custom application that creates a folder in Outlook. I need to lock down users from being able to rename, delete or move/copy that folder. I have read about creating an Outlook Add-In. I just want to know if this would be the best option and how exactly to begin execution of that.
Jordan HowardNetwork AdministratorAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

paarunCommented:
Is the custom app going to create folders on a regular basis? The easiest way to go about should be setting folder permissions.
Jordan HowardNetwork AdministratorAuthor Commented:
Yes. It creates a root folder once that needs to not be modified. Then it creates subfolders from then on that can be deleted but need not be moved or renamed.
paarunCommented:
Not really sure, but if the custom add-in can set folder permissions, then you could just provide Read access to all users.
IT Pros Agree: AI and Machine Learning Key

We’d all like to think our company’s data is well protected, but when you ask IT professionals they admit the data probably is not as safe as it could be.

Jordan HowardNetwork AdministratorAuthor Commented:
paarun, I'm not sure what you're saying.... This program creates a folder in a user's mailbox (that only they can see not shared). We need not that this folder be moved, deleted, or renamed.

I have went from modifying Mailbox Permissions, Mailbox Folder Permissions, VBA Scripting in Outlook (which works in regards to moving and deleting, but can't find out how to deploy it to all users Outlook in a network environment), and trying to research Visual Studio Add-In for Office (can't find any good reference material).

Can't figure this one out! If anyone has an idea, please let me know. Greatly appreciated
Will SzymkowskiSenior Solution ArchitectCommented:
paarun, I'm not sure what you're saying.... This program creates a folder in a user's mailbox (that only they can see not shared). We need not that this folder be moved, deleted, or renamed.

Unfortunately, based on the comment above,

You will not be able to accomplish this. You cannot restrict a user from modifying a folder in their own mailbox.

You can do this with a public folder or from a shared mailbox but not from a user's default mailbox.

Will.
Jordan HowardNetwork AdministratorAuthor Commented:
I was able to remove NT AUTHORITY\SELF from the main mailbox (which denied them access in opening Outlook), is there no "self" permission on the folder level?
Jordan HowardNetwork AdministratorAuthor Commented:
There's a 'default' and 'anonymous' user on each folder with no??? permissions. What are those accounts for?
Chris Raisin(Retired Analyst/Programmer)Commented:
Hi there! :-)

What is the purpose of your action?
Are you trying to ensure the mailbox and/or emails cannot be deleted or moved, or is it more that you want to KNOW when a user deletes emails/mailboxes (or moves them) from a security point of view?

Interesting (and perhaps helpful) articles can be found at the following links:

http://www.msexchange.org/articles-tutorials/exchange-server-2010/compliance-policies-archiving/auditing-mailbox-access.html

http://superuser.com/questions/720486/how-to-prevent-users-from-deleting-a-folder-while-still-giving-them-modify-perm

If it is more a case that you want to ensure that an email item or an email mailbox cannot be moved/deleted by a user in their own mailbox (ever) then it is a much more complicated restriction, which I will have to investigate further. There are certainly ways to stop such action in shared mailboxes, but users usually have unrestricted powers in their own personal mailboxes (and one would think maybe that is their right). You may have to consider restricting actions to shared mailboxes only so any action in a mailbox or messages to individuals where you do not want the mailbox/mail deleted must be made through a shared mailbox.

Please advise.

Cheers
Chris (Australia)
Jordan HowardNetwork AdministratorAuthor Commented:
Chris,

I have a custom application that creates a folder in Outlook. I need to lock down users from being able to rename, delete or move/copy that folder. I need to prevent them from deleting the folder itself. They can do whatever with what's inside of it.
Chris Raisin(Retired Analyst/Programmer)Commented:
Is the following of any help?

It is taken from Outlook 2010 help system.
The links will not work, because this is just an image, but if you go into "Outlook Help" and search for "Retention Policy" you  will find this article and can proceed from the links therein.

If the "Retention Policy" is not showing in the "Tags" Group of the Home Tab, you need to go into "Customize Ribbon" and search "All Commands" to find "Retention Policy" then assign it to the "Tags" Group of the "Home" Tab.

If this can be actioned manually to set up the restriction (administrators only), then I cannot see why we cannot come up with some code (VBA) that will go into a users mailbox and automatically apply the "No delete" and "no move" policy to a folder. There is a "sunset" time though (end date) for any restrictions, so if you want it permanent, you would have to set a date like "31/12/9999" (if possible). Remember though that any administrator could change that in the future.

Retention Policies that can be applied to email or folders
Jordan HowardNetwork AdministratorAuthor Commented:
Chris,

The retention policy options in exchange allows a user to still delete but just gives you the ability to recovery something if needed. I don't want it deleted to begin with. CodeTwo has created an Add-In that throws a prompt when something is about to be moved or deleted. I'd love to know how this was done in order to produce my own prompts.
Howard BashSenior Software EngineerCommented:
If you're wiling to write an outlook add-in.  You could trap the event and not allow it.
Jordan HowardNetwork AdministratorAuthor Commented:
This is what I was asking. Anyone experienced in writing Office Add-Ins?
Chris Raisin(Retired Analyst/Programmer)Commented:
I will have a go at writing one now (my first one!).

Stand by....

Cheers
Chris
Jordan HowardNetwork AdministratorAuthor Commented:
(smile) Thanks Chris....I'm still learning on my end too.
Howard BashSenior Software EngineerCommented:
Try searching for Visual Studio Tools for Office Outlook Object Model.  You add the event handlers to your custom code (an add-in) and don't allow the action that you want to disable.
Chris Raisin(Retired Analyst/Programmer)Commented:
What language do you prefer for your add-in (seeing how you are learning as well). Do you want C# or Visual Basic?

Cheers
Chris (Australia)
Jordan HowardNetwork AdministratorAuthor Commented:
Visual Basic
Chris Raisin(Retired Analyst/Programmer)Commented:
OK....working on it

I am in different time zone, so you will have to bear with me.

Cheers
Chris
Jordan HowardNetwork AdministratorAuthor Commented:
Thanks Chris. I have some VBA code but not VB.NET for an Add In...let me know what you come up with.
Chris Raisin(Retired Analyst/Programmer)Commented:
If the VBA code is designed to prevent the renaming etc. via the Outlook "ThisSession" Object model, it will be of help to see it.
Could you please post the code here and I will adapt it into VB.Net and write the add-in.

Cheers
Chris
Jordan HowardNetwork AdministratorAuthor Commented:
Dim WithEvents objCritFolder As Outlook.Folder
Dim ObjNS As Outlook.NameSpace
Dim objApp As Outlook.Application
 
'Dim WithEvents myFolders As Outlook.Folders
 
Private Sub Application_Startup()
    Set objApp = Application
    Set ObjNS = objApp.GetNamespace("MAPI")
    Dim myFolder As Outlook.Folder
    'the following line should probably be changed in production to: Set myFolder = ObjNS.GetDefaultFolder(olFolderManagedEmail)
    Set myFolder = ObjNS.GetDefaultFolder(olFolderInbox)
    Set objCritFolder = myFolder.Folders("Test")
    Set objInbox = Nothing
    Set objRootFolder = Nothing
 
'    Set myFolders = ObjNS.GetDefaultFolder(olFolderInbox).Folders
End Sub
       
Private Sub objCritFolder_BeforeFolderMove(ByVal MoveTo As MAPIFolder, Cancel As Boolean)
    Dim strMsg As String
    Cancel = True
    strMsg = "You can't delete the Test folder."
    MsgBox strMsg, vbCriticial, "Folder Move Not Allowed"
End Sub
'Private Sub myFolders_FolderChange(ByVal Folder As Outlook.Folder)
'    If Folder.Items.Count = 0 Then
'       MyPrompt = Folder.Name & " is empty. Do you want to delete it?"
'       If MsgBox(MyPrompt, vbYesNo + vbQuestion) = vbYes Then
'           Folder.Delete
'        End If
'    End If
'End Sub
 
'Private Sub objCritFolder_FolderChange(ByVal Folder As Outlook.Folder)
'    If Folder.Name = "Test" Then
'        Dim strMsg As String
'        Cancel = True
'        strMsg = "You can't rename the MatterSphere folder."
'        Folder.Name = "Test"
'    End If
'End Sub
 
Dim WithEvents objCritFolder As Outlook.Folder
Private Sub application_startup()
    Dim objRootFolder As Outlook.Folder
    Set objRootFolder = _
    Application.Session.DefaultStore.GetRootFolder
    Set objCritFolder = objRootFolder.Folders("Critical")
    Set objInbox = Nothing
    Set objRootFolder = Nothing
End Sub
Private Sub objCritFolder_BeforeFolderMove(ByVal MoveTo As MAPIFolder, cancel As Boolean)
    Dim strMsg As String
    cancel = True
    strMsg = "You can't delete the Critical folder."
    MsgBox strMsg, vbCritical, "Folder Move Not Allowed"
End Sub
Chris Raisin(Retired Analyst/Programmer)Commented:
Thanks for that, am working on changing to VB.Net and compiling as an add-in.

Do you have Visual Studio  Community 2013 or later? (It is now free)

While we are mentioning add-ins, Microsoft has now stopped supporting add-ins, and from VS 2013 they are now produced as
"VSPackages" . A VSPackage replaces add-ins, and there are ways to convert add-ins to VSPackages. We could create an add-in using earlier version of Visual Studio, but since all versions are now free
we may as well learn how to produce a VSPackage to do what we want.
Is that OK with you?
 
Cheers
Chris
Jordan HowardNetwork AdministratorAuthor Commented:
Yeah. I didn't know they stopped supporting add-ins???? That's probably why it's so hard to find a good book about them.
Chris Raisin(Retired Analyst/Programmer)Commented:
I may have been wrong about VSPackages...still coming to grips with the 2013 UI.....One source says add-ins are now replaced by VSPackages, whereas another source says VSPackages are used to actually change the UI of the VS Editor!.    Stand by.

Cheers
Chris
Chris Raisin(Retired Analyst/Programmer)Commented:
I have found it difficult to build an a"add-in" (or whatever they are called now) under VS 2013 Community, so I went back to Visual Studio 2010 Professional and it is easy to write it front that interface.
Once I have written it I will supply the code, and also a video on how to create an Add-in using Visual Studio 2010 Professional.

If you do not have VS 2010 Professional then any version earlier than 2013 should be OK (and should now be free anyway).....
How does that sound?

Cheers
Chris
Jordan HowardNetwork AdministratorAuthor Commented:
Awesome!!!! I'd love a video!
Chris Raisin(Retired Analyst/Programmer)Commented:
This is what I have so far (see code below). The module created is a COM Class object.

When built within Visual Studio 2010 it automatically adds itself as an Add-In to the Outlook environment.
After it is all working properly we will think about the logistics of deployment.

I still have to fully test for deletion and try a rename yet.

I tried deletion on an empty (not restricted) folder and it came up with the question "do you want to delete?"
(which is part of this code) simply because it ran the "FolderChange" event. I am not sure this is what we really want, since "Deletion" would happen BEFORE the Change event happens (i.e. it is already deleted). The code as you supplied it was supposed (I think)  to alert a user to an empty folder which has just come into existence because its only mail item has just been deleted. At the moment though it appears when you actually delete the folder as well (the default) even if the folder is "restricted". I will look further into that.

So I still need to fully to test the empty "Test" and "Test2" folders to make sure they cannot be moved or deleted.

You will notice I have made provision for more than one restricted folder by storing the names of the "restricted" folders into an array. If the folder which the user is attempting to move (or delete) has the same name as that held in the array somewhere, the "Not allowed" message should show.

I will have to also consider what happens when there are two folders in the Incox which have the same name (one folder is a sub folder of another). If we just test on "name" we may end up with folders being restricted when they should not be. I guess we will have to test on something more detailed than just "Name" (perhaps Parent Folder + Name)

Remember that a file or folder deletion is in fact a "move" to "Deleted Items", so we only need to check for "moves" not deletions. The important thing to pick up is the deletion of a restriucted folder (the unrestricted folders should process as per normal).

The code is not fully commented yet. It is now 4.22am and I have been working on this for several hours now (and am a bit tired). I will supply fully commented code (which will probably change a little as I find problems) at a later time.

I will not prepare the video until everything works as it should......stand by.

Cheers
Chris (Australia)

Option Explicit On
Imports Extensibility
Imports System.Runtime.InteropServices
Imports Microsoft.Office.Interop.Outlook

#Region " Read me for Add-in installation and setup information. "
' When run, the Add-in wizard prepared the registry for the Add-in.
' At a later time, if the Add-in becomes unavailable for reasons such as:
'   1) You moved this project to a computer other than which is was originally created on.
'   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
'   3) Registry corruption.
' you will need to re-register the Add-in by building the FolderMgrSetup project, 
' right click the project in the Solution Explorer, then choose install.
#End Region

<GuidAttribute("DE25940C-C1E1-43FB-A2DA-E359F495CEE0"), ProgIdAttribute("FolderMgr.Connect")> _
Public Class Connect
    Implements Extensibility.IDTExtensibility2
    Dim applicationObject As Object
    Dim addInInstance As Object
    Dim ObjNS As [NameSpace]
    Dim objApp As Application
    Dim WithEvents myMAPIFolder As MAPIFolder
    Dim WithEvents myFolder As Folder
    Dim WithEvents objCriticalFolder As Folder
    Dim objCritFolders(1) As Folder
    Public Sub OnBeginShutdown(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnBeginShutdown
        On Error Resume Next
        'I'm not sure whether the garbage collector takes care of this, but just to be sure we
        'had better clean up
        applicationObject = Nothing
        addInInstance = Nothing
        ObjNS = Nothing
        objApp = Nothing
        myMAPIFolder = Nothing
        myFolder = Nothing
        objCriticalFolder = Nothing
        objCritFolders = Nothing
    End Sub

    Public Sub OnAddInsUpdate(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnAddInsUpdate
    End Sub

    Public Sub OnStartupComplete(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnStartupComplete
        ObjNS = objApp.GetNamespace("MAPI")
        'the following line should probably be changed in production to: myFolder = ObjNS.GetDefaultFolder(olFolderManagedEmail)
        myMAPIFolder = ObjNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox)
        myFolder = CType(myMAPIFolder, Folder)
        objCritFolders(0) = CType(myFolder.Folders("test"), Folder)
        objCritFolders(1) = CType(myFolder.Folders("Test2"), Folder)
    End Sub

    Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnDisconnection
        On Error Resume Next
        If RemoveMode <> Extensibility.ext_DisconnectMode.ext_dm_HostShutdown Then
            Call OnBeginShutdown(custom)
        End If
    End Sub

    Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection
        applicationObject = application
        addInInstance = addInInst

        ' If you aren't in startup, manually call OnStartupComplete.
        If (connectMode <> Extensibility.ext_ConnectMode.ext_cm_Startup) Then
            Call OnStartupComplete(custom)
        End If
    End Sub

    Private Sub FolderBeforeMove(ByVal MoveTo As MAPIFolder, ByRef Cancel As Boolean) Handles myFolder.BeforeFolderMove
        Dim strMsg As String = ""
        Dim nFolder As Integer = 0
        For Folder = 0 To objCritFolders.GetUpperBound(0)
            If objCritFolders(nFolder).Name = objCriticalFolder.Name Then
                Cancel = True
                strMsg = "You must not move or delete this folder"
                MsgBox(strMsg, MsgBoxStyle.Critical, objCriticalFolder.Name)
                Exit For
            End If
        Next
    End Sub
    Private Sub myFolder_FolderChange(ByVal Folder As Folder)
        Dim myPrompt As String = ""
        If Folder.Items.Count = 0 Then
            myPrompt = Folder.Name & " is empty. Do you want to delete it?"
            If MsgBox(myPrompt, MsgBoxStyle.YesNo Or MsgBoxStyle.Question, Folder.Name) = MsgBoxResult.Yes Then
                Folder.Delete()
            End If
        End If
    End Sub
End Class

Open in new window

Chris Raisin(Retired Analyst/Programmer)Commented:
Well, it builds fine and even Outlook senses the add-in is there, but it strangely points to the incorrect DLL.
and so does not work yet. (See image below). It should point to

I believe that there is probably a problem with the registration of the DLL in the registry and I am investigating further (others have had the same problem).

Points to wrong DLL
At least I know the code compiles correctly and without errors
although its structure may not be quite right.

Stand by...this may take a while.....
Chris Raisin(Retired Analyst/Programmer)Commented:
It appears that the code I have supplied is in the style suitable for Visual Studio 2013 (and later) but I cannot quite get it to produce the required module (yet) since it is handled quite differently in compilation and deployment than Add-Ins in earlier versions of VS.

That being said, I am now trying to produce the required Add-In using Visual Studio 2010 and the code should be a lot simpler.

One question - it is possible to have folders within folders. The following code is really only looking at parent folders in the Inbox, so will your restriction ever apply to "sub folders" (folders within folders")?

Cheers
Chris
Jordan HowardNetwork AdministratorAuthor Commented:
No. Just the root parent folder. Any sub folders under it don't need to be locked down.
Chris Raisin(Retired Analyst/Programmer)Commented:
OK.. I have it all working now (it was messy, because there are known bugs in the Outlook "BeforeFolderMove"
event when there are a lot of folders in the Root Folder (usually the "InBox") so you have to work with just a single folder when testing for the move and not test for moved on a collection of folders.(This will actually make the code much more efficient anyway!)  :-)

The code follows.

I will try to get the video done in the next day or two.

Cheers
Chris (Australia)


Option Explicit On
' We need "Forms" since we are going to use the Outlook explorer to
' ascertain which folder is being moved/deleted/renamed
Imports System.Windows.Forms
'Importing this saves us having to type "Microsoft.office.interop.outlook.folder" all the time when defining a folder
Imports Microsoft.Office.Interop.Outlook

Public Class ThisAddIn
    Dim lstCriticalFolders As New List(Of String)
    Dim myRootFolder As MAPIFolder = Nothing
    Dim WithEvents myFolders As Folders = Nothing 'withevents is required because we are referring to the default event handler "FolderChange"
    Dim WithEvents myFolder As Folder = Nothing 'withevents is required because we are referring to the default event handler "BeforeFolderMove"
    Dim strCurrentFolderName As String = ""  'this is a repository to store the name of the current folder before any action is taken on it
    Dim WithEvents oEx As explorer = Nothing 'we need the Outlook Explorer to store values into strCurrentFolderName
    Private Sub ThisAddIn_Startup() Handles Me.Startup
        'Comment: MAYBE the following line should probably be changed in production to: 
        '        myFolder = cType(Application.session.GetDefaultFolder(olDefaultFolder.olFolderManagedEmail),folder)
        '(I left the above comment in from the old code example supplied to me)
        myRootFolder = Application.Session.GetDefaultFolder(OlDefaultFolders.olFolderInbox)
        myFolders = myRootFolder.Folders
        oEx = Application.ActiveExplorer
        'Store the name of the folders you want protected in the list of critial folders
        'Note: the Case of the folder names is unimportant (upper/lower/mixed)
        lstCriticalFolders.Add("Test")
        lstCriticalFolders.Add("Test2")
    End Sub
    Private Sub BeforeFolderMove(oMoveTo As MAPIFolder, ByRef Cancel As Boolean) Handles myFolder.BeforeFolderMove
        'this routine will also come into effect on folder deletions, since deletions are simply moves to the deleteds folder
        Dim strMsg As String = ""
        Dim nFolder As Integer = 0
        For nFolder = 0 To lstCriticalFolders.Count - 1
            If lstCriticalFolders(nFolder).Trim.ToLower = myFolder.Name.Trim.ToLower Then
                strMsg = "You must not move/delete this folder"
                Cancel = True
                MessageBox.Show(strMsg, myFolder.Name, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                Exit For
            End If
        Next
    End Sub
    Private Sub FolderSelect() Handles oEx.SelectionChange
        strCurrentFolderName = oEx.CurrentFolder.Name 'stores the currently selected folder name for use in case of an attempted rename
        myFolder = oEx.CurrentFolder
    End Sub
    Private Sub FolderChange(oFolder As Folder) Handles myFolders.FolderChange
        'used to pick up an attempted rename of a folder
        Dim strMsg As String = ""
        Dim nFolder As Integer = 0
        For nFolder = 0 To lstCriticalFolders.Count - 1
            If lstCriticalFolders(nFolder).Trim.ToLower = strCurrentFolderName.Trim.ToLower Then
                If oFolder.Name.Trim.ToLower <> strCurrentFolderName.Trim.ToLower Then
                    'just in case this is the restoration of the original'foldername  
                    strMsg = "You must not rename this folder"
                    MessageBox.Show(strMsg, strCurrentFolderName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                    oFolder.Name = lstCriticalFolders(nFolder)
                    Exit For
                End If
            End If
        Next
        strCurrentFolderName = oFolder.Name 'since we already have the folder selected we must change this manually
    End Sub

    Private Sub ThisAddIn_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown
        'Not sure if we need to do this (leave to garbage collector?) - but just to be sure (to be sure)...as the Irish would say.
        lstCriticalFolders = Nothing
        myRootFolder = Nothing
        myFolders = Nothing
        myFolder = Nothing
    End Sub
End Class

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Jordan HowardNetwork AdministratorAuthor Commented:
Awesome dude! Thanks!
Jordan HowardNetwork AdministratorAuthor Commented:
Chris, any update on the video?
Chris Raisin(Retired Analyst/Programmer)Commented:
Yes...sorry about the delay...my main PC is havong those "not responding" problems and I am a bit ;loathe to make the video while that is happening. I might try to do it on my laptop instead since it is running fast. I will have to completely rebuild my main PC since I think it has become unstable due to a mishap some time ago when I deleted a lot of my "User" files in error (AAAhhh!) (Those are the files on the C: drive you are not supposed to touch). I tried restoring from backup, but the restore failed and ever since then things have been messy.

If the Video does not work out,I will put together complete step by step tutorial.....please be patient, it may be 4-5 days yet.

Is that OK?
Jordan HowardNetwork AdministratorAuthor Commented:
Of course, I appreciate what you've done thus far. No worries
Jordan HowardNetwork AdministratorAuthor Commented:
Hey Chris,

The code is great!!! The only problem we're having is that we're trying to apply this to a folder that would be on the root of the mailbox (not in the Inbox). This seems to be impossible to make work....please tell me we haven't done all of this for a no go???!??? Any suggestions? We've referenced the folder as Outlook.olDefaultFolder.olFolderManagedEmail but the code throws errors???
Chris Raisin(Retired Analyst/Programmer)Commented:
Glad you got it to work.

First thoughts are hat you could change the line:

"myRootFolder = Application.Session.GetDefaultFolder(OlDefaultFolders.olFolderInbox)"
to
"myRootFolder = Application.Session.GetDefaultFolder(olFolderManagedEmail)"   OR
"myRootFolder = Application.Session.GetDefaultFolder(olPublicFoldersAllPublicFolders)".

but you MUST be using Exchange accounts for these to work.

What error message are you getting when using identifier constant
olFolderManagedEmail?

If you are not using Exchange then I will have to try out things at my end (since I am not using Exchange). Perhaps :
"myRootFolder = Application.Session.Folders(0)" might work (??)
I will investigate it when I get back from Bridge this afternoon.

Do you still want me to create the video? I would be interested in knowing you method of deployment.

Chris
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Applications

From novice to tech pro — start learning today.