Introduction
This is a "workaround" solution to enable programmatic changes to the Windows Parental Controls of a user whether or not they are logged on, and even if the machine is a standalone with no domain.
The Story...
I was trying to have one of my VB.NET programs change the Parental Control settings for a named user on a local standalone system with no domain. Every piece of code I could find worked for the current logged-on user, but, no matter how I tried, I could not get it to work for any user who was not logged on at the time. The problem is that, whilst there are several ways we can address the settings, to do so we need either a logon token (only available for logged on users), a UPN (only available from an active domain), or to know the SID for each username whose WPC settings we need to access. Turning the username into a SID gives much the same problems. So...
I'd found a code-snippet that worked nicely for any user I knew the SID for (Not very well formatted - Sorry!):
Dim searcher As New ManagementObjectSearcher("root\CIMV2\Applications\WindowsParentalControls", "SELECT * FROM WpcUserSettings")
If queryObj("SID") = "S-1-5-21-666666666-444444444-7777777777-1001" Then
queryObj("AppRestrictions") = True
queryObj("HourlyRestrictions") = True
queryObj("LoggingRequired") = False
queryObj("LogonHours") = False
queryObj("OverrideRequests") = False
queryObj("WpcEnabled") = True
queryObj.Put()
End If
I then tried all ways and for hours to get the machine to give me the SID of the account from the username, but all attempts failed, for similar reasons to why the other ways of querying the WPC settings failed.
Finally, I realised that I already had a piece of code that worked the other way around: i.e. it gives the username for any given SID. Hence, all I had to do was to generate a list of ALL the SID's for a machine , and then run a simple If/Then loop to find the right one. It turns out that getting all the SID's from a machine is quite easy.
Here's what we end up with. Quick note here: If you're copying and pasting this code, remember the "Imports" lines, and to set the references to them in your project. ("Coding 101 - Egg Sucking for grandmothers", I know, but we all forget sometimes!)
Imports System
Imports System.Collections.Generic
Imports System.Management
Imports System.Text
Module Module1
Sub Main()
Console.WriteLine("Starting Module")
Dim SidString As String = ""
Dim AccountName As String = ""
Dim FullName As String = Environment.MachineName & "\YOUR ACCOUNT NAME"
Try
Dim searcher As New ManagementObjectSearcher("root\CIMV2\Applications\WindowsParentalControls",
"SELECT * FROM WpcUserSettings")
Console.WriteLine("Path to the Parental Control settings - " & searcher.ToString)
For Each queryObj As ManagementObject In searcher.[Get]()
SidString = queryObj("SID")
Console.WriteLine("SID - " & SidString)
AccountName = New SecurityIdentifier(SidString).Translate(GetType(NTAccount)).ToString
Console.WriteLine(AccountName & " is " & FullName)
If AccountName = FullName Then
Console.WriteLine(queryObj("SID"))
queryObj("AppRestrictions") = True
queryObj("HourlyRestrictions") = True
queryObj("LoggingRequired") = False
queryObj("LogonHours") = False
queryObj("OverrideRequests") = False
queryObj("WpcEnabled") = True
queryObj.Put()
Else
Console.WriteLine(AccountName & " is not " & FullName)
End If
Next
Catch e As ManagementException
Console.WriteLine("An error occurred setting the WMI data: " + e.Message)
End Try
Console.ReadKey()
End Sub
End Module
So, there you have it. A way to change Parental Control permissions for any account from any account... well, almost... You need Administrator rights to run it... Sorry kids!