Tuesday, April 25, 2023

Microsoft Family Safety

What is the Microsoft Family Safety?

It is a free service offered by Microsoft that allows you to manage your family's devices and share information.  Much like the google family link service, but is for use with all of Microsoft's services such as office, xbox game services, screen time tracking, and reporting.

What do you need to use this?  All you need is an email address, it can be from any service.  My wife and I both have Microsoft accounts we are using with the service and the kids have an associated Gmail account (because Chromebooks).

You will send an invite to an already active email; or you will have to create an account.

When you set them up, they will have the option of being setup as a managed user or as a family organizer.  The organizer is an "administrator" and settings for restrictions are not applied to them.  If there is more then one family organizer the only options another organizer has is to remove them from the family group.

Adding a family member as a standard account you have many more features that you can control.


The overview for the accounts is where you modify a number of the account settings, which is specific to each managed family member.  You can also modify setting though the manage consent settings.

Connecting A Device

The PC Account needs to be a standard user.  XBox, Android and iOS devices are also supported.  If want to setup limits you have to do so for each child there isn't a global setting you can apply to the family users.  Settings have to be applied individually.

You can specify scheduled times, to limit screen time and what games are playable on the devices.

Content Filters

Content filters come in two sections Web and Search then Apps and Games.  You can specifiy specific website to be allowed only or block specific websites.  You can set age limits for games and any apps you don't want your kids to have access to.

The real power in Family Safety is the calendar and one note features for family.  Being able to automatically add everyone to add items for Grocery lists; or having the shared calendars for family to automatically show up for everyone is fantastic.

If you haven't set it up I highly recommend setting this up for your family; keep in mind that all family members will get a basic Microsoft account; which gives them 5GB of one drive space and access to the online versions of Word, PowerPoint and Excel.  The free service is quite comprehensive, and helps me keep an eye on my family.


Monday, April 24, 2023

Using PowerShell to send scheduled emails based on a php generated xml file

Laptop Lending Locker
Laptop Lending Locker
D-Tech International has some vey nice equipment, and it works pretty well.  When these were purchased they were to send out the following email notices.

  1. When a laptop is borrowed with the date and time that it is due back
  2. an email notice 15 minutes before it is due
  3. an email notice if it is overdue
  4. an email notice when it is returned
Unfortunately not all the emails worked.  The 15 minute notice and the overdue notice were not working properly.  Email notices were sent when the laptop was taken out and when it was returned but not at the 15 minutes before it is due or when it is overdue.  Since the system is using a SirsiDynix ILS system it has a server called Horizon Web Services; which is more/less an API connector for the ILS Database.  

A php script generates a XML file which we will use to generate scheduled tasks for each laptop that is borrowed.  Those tasks will run at specific times to send notices out to the user that borrowed it.  The notice times obviously need to be flexible and only generate and send a notice for the laptop that is due within the operating hours of the location.

To do all this we are going to use powershell.  Below is how the XML file is generated and structured.

XML File

<laptopName>Laptop 2</laptopName>


The Process:

The emails for the borrowing and the returning of the laptops work great.  However because this is something I can code and control the following notices will be generated.
  • 15 minute pre-due notice
  • Notice that the laptop is due
  • 15 minute overdue notice
  • 15 minute pre-closing notice
  • Laptop not returned the next day notice

There will be 11 different files.  A powershell script with a bat file for executing the powershell script as to not change the default powershell security model on the system.  Below is a sample of the scripts for generating the task scheduler and email notices.

The Scripts:

Obviously because of the locked down security model we are going to use task scheduler to run bat files to execute our powershell scripts.  Our bat file must contain the $Path that goes to our powershell file.  Below is a sample file.

The Bat Files:

Powershell.exe -executionpolicy remotesigned -File  $PATH\LaptopsDue.ps1

Powershell Files:

Generate Notices (Sample) - This is the biggest and most complex file; as this is the one that makes and removes our scheduled tasks.  Below is a sample of the script which will be provided at the end of the post.

#update the generated xml file from the php script (status.xml)
$WebResponse = Invoke-WebRequest "$URL/generate.php" -UseBasicParsing

#URL to get the laptops data
$url = "$URL/status.xml"

#store the laptop xml file
$filename = "$PATH\status.xml"

$webClient = new-object System.Net.WebClient
$webClient.DownloadFile( $url, $filename )

#load the xml file we downloaded
[xml]$xml = get-content "$PATH\status.xml"

#check and see if there are any checked out laptops
#if there are laptops checked out laptops
if ($xml.notices.laptopCirc -ne $null){
    Write-Output "there are checked out laptops"
#if there are no checked out laptops
    Write-Output "There are NO check out laptops"
#Write-Output $xml.notices.laptopCirc

#here is where we sort the xml file
$xml.notices.laptopCirc | ForEach-Object {
#Conversions for date and time for creating tasks
$DueTime = [datetime]::ParseExact($_.timeDue.substring(0, 19), 'yyyy-MM-ddTHH:mm:ss', $null)
$PreTime = [datetime]::ParseExact($_.timeDue.substring(0, 19), 'yyyy-MM-ddTHH:mm:ss', $null)
$OverTime = [datetime]::ParseExact($_.timeDue.substring(0, 19), 'yyyy-MM-ddTHH:mm:ss', $null)

#Create Timestamps
$PreTS = $PreTime.AddSeconds(-900).ToString('MM/dd/yyyy HH:mm:ss')
$OverTS = $OverTime.AddSeconds(+900).ToString('MM/dd/yyyy HH:mm:ss')
$DueTS = $DueTime.AddSeconds(+0).ToString('MM/dd/yyyy HH:mm:ss')

#get current Date & Time
$nowTime = (Get-Date).ToString('MM/dd/yyyy HH:mm:ss').substring(11,5)
$nowDate = (Get-Date).ToString('MM/dd/yyyy HH:mm:ss').substring(0,8)
$nowTS = Get-Date -Format yyyy-MM-ddTHH:mm:ss

$whatDay = (get-date).DayOfWeek
if ($whatDay -match 'Monday|Tuesday|Wednesday|Thursday' -and $nowTime -gt "10:00" -and $nowTime -lt "20:45"){
 Write-Output "Today is "+ $DayOfTheWeek
###Notices for Monday - Thursday
#Pre-Over Due Notice
$taskName = $_.laptopName+"_PreOverDue"
if(Get-ScheduledTask $taskName -ErrorAction Ignore) { 
Write-Output "Task Found" 
} else { 
$actions = (New-ScheduledTaskAction -Execute '$Path\LaptopPreDue.bat' -WorkingDirectory '$PATH')
$trigger = New-ScheduledTaskTrigger -Once -At $PreTime.substring(11, 5)
$principal = New-ScheduledTaskPrincipal -UserId '$user' -RunLevel Highest 
$settings = New-ScheduledTaskSettingsSet -RunOnlyIfNetworkAvailable -WakeToRun
$task = New-ScheduledTask -Action $actions -Principal $principal -Trigger $trigger -Settings $settings
$taskName = $_.laptopName+"_PreOverDue"
Register-ScheduledTask $taskName -InputObject $task

    'displayName'   = $_.displayName
    'barcode'       = $_.barcode
    'emailAddress'  = $_.emailAddress
    'checkOutTime'  = $_.checkOutTime
    'timeDue'       = $_.timeDue
    'laptopName'    = $_.laptopName


#        'id'        = $_.id
#        'name'      = $_.name
#        'status'    = $_.status
#        'checkout'  = $_.checkout
#        'due'       = $_.due
#        'email'     = $_.email



Item Due Email Notice (SAMPLE)

#URL to get the laptops data
$url = "$URL/status.xml"

#store the laptop xml file
$filename = "$PATH\status.xml"

$webClient = new-object System.Net.WebClient
$webClient.DownloadFile( $url, $filename )

#load the xml file we downloaded
[xml]$xml = get-content "status.xml"

#here is where we sort the xml file
$xml.notices.laptopCirc | ForEach-Object {

#Conversions for date and time for creating tasks
$TimeDueTS = [datetime]::ParseExact($_.timeDue.substring(0, 19), 'yyyy-MM-ddTHH:mm:ss', $null)

#add time to time due if required
$DueTime = $Due_Conversion.AddSeconds(+0).ToString('MM/dd/yyyy HH:mm:ss')

#get current time
$CurrentTime = (Get-Date).ToString('MM/dd/yyyy HH:mm:ss')
$CurrentTimeStamp = Get-Date -Format yyyy-MM-ddTHH:mm:ss

$removeTask = $_.laptopName+"_Due"
$isDue = $DueTime.substring(11, 5)

#Send an email if the laptop is due
if ($CurrentTime -match $DueTime){
#send an email if the current time matches the time due.  Remove the task once the email is sent
#Write-output $_.laptopName $_.emailAddress
$emailBody = "Hello "+$_.displayName+",
Your laptop is now overdue and needs to be returned to the locker. If you need help with saving your document or the return process, please ask Staff. 

Laptops are loaned for a maximum of 4 hours"
$emailSubject = "Please return "+$_.laptopName+" to the locker"
Send-MailMessage -Encoding UTF8 -From '$FROM ADDRESS' -To $_.emailAddress -Subject $emailSubject -Body $emailBody -smtpserver '$SMTPSERVER'
Unregister-ScheduledTask -TaskName $removeTask -Confirm:$false

    'displayName'   = $_.displayName
    'barcode'       = $_.barcode
    'emailAddress'  = $_.emailAddress
    'checkOutTime'  = $_.checkOutTime
    'timeDue'       = $_.timeDue
    'laptopName'    = $_.laptopName


I have a scheduled task that runs every 5 minutes checking to see if a laptop is checked out; if it is it creates the notices; if not then it exits the script.  If there is a notice already made it skips creating it again.  It works really well.

Sunday, March 19, 2023

Intel Mac - Install the latest version of Windows using Bootcamp

I have a project I am working on where a computer is needed to be available for any body to use but it has to have Multi-Media software installed and it needs to be useable.  There is no budget for new hardware but there are two outdated iMacs available.  These iMacs were purchased in 2015 and were not being used.  Originally the idea was to have these macs put out with MacOS X because of the reputation apple did have as being used for creative professionals, that was a different era though and those times are gone.  Also with the costs to upgrade the software, staff training, etc.  Since the software we were planning to use was also available on Windows it was decided to go with the latest version of Windows 10 22H2, because of the software that we are currently using for managing our systems.

3.2GHz Quad-core Intel Core i5, Turbo Boost up to 3.6GHz
16GB 1600MHz DDR3 SDRAM - 2x8GB
256GB Flash Storage

You MUST run thought the boot camp wizard.  If you try to make a bootcamp boot disk with a newer version of windows such as 22H2 IT WILL FAIL.  To successfully run though the bootcamp assistant; I had to use a windows 7 iso to create a bootcamp disk and have the Boot Camp Assistant successfully partition the disk.

While the Bootcamp assistant was working I used Rufus to make a second windows boot disk using GPT and UEFI for booting.  Once the Mac OS as finished with the boot camp assistant, it will reboot and if you do nothing it will try to boot off the Windows 7 boot disk that was created.  I put the Rufus boot disk into an open USB port after the boot camp partitioning completed successfully.  Now if you reboot and hold down the "OptionKey" you can select which disk you can boot off of.

The Rufus boot disk shows up as a EFI boot disk and the bootcamp disk shows up as a Windows Disk.  will booted into boot camp and started to run the windows 7 installer I cancelled the install and booted up holding the "Option" or "Alt" key then selected the UEFI boot device (which is our windows 10 usb installer)

After a few minutes it booted into the windows 10 installer

Bootcamp formats the drive for NTFS, you can either keep your mac files or erase the whole thing install windows on the whole system disk.  I deleted all partitions and installed windows on the full disk.  I chose the latter because I need a full fledged windows Machine and don't need Mac OS.  This will NOT affect the system's bootup.  If you need to install Mac OS you will have to make a USB drive or use the cloud recovery mode.

Windows will go though it's full installer; once it gets into windows the bootcamp installer we made should auto launch and install any required drivers.  Once the installation is complete the system will reboot and will work like any other windows system.  Some caveats about using a mac like this.

  1. Wake on Lan doesn't work.  We are using WOL to schedule turning on the systems and shutting them down at night.  While the shutdown is still possible to do; turning the system on is a big time saver for the staff so the shutdown for the system will be disabled.

  2. Cloud Recovery.  Since it is not possible to lockout cloud recovery it is possible for someone to erase the system and reset it to MacOS

  3. Ports are on the back.  The ports are on the back of the imac and are accessible and can be damaged.

Wednesday, February 01, 2023

Setting up a "Guest" or "Visitor" user account on a domain on Windows 10

The requirements

To have a "guest" account on a specific system; but staff on the active directory have to be able to login and access the data they need such as mounted drives and network shares while the "guest" has access to save files to the computer and has no access to any network resources except internet.  The Guest user must be setup as the default user and auto login.  For making this setup I am using an administrator account, specifically a local admin account, and the computer is already attached to the domain.  This computer is also going to be hooked up to a large sound system and will need to be muted on reboot as well at the end of the day if the sound had been left enabled if someone had been using it.  Finally we will have to ensure that no files had been left behind; so we will need a way to delete them.

The User Account

The user account is a domain user; and therefore has to be placed in the local machine guest group for proper privileges to apply.  On the active directory controller I setup a OU called Guest, I will add a GP to this later, but here we want to block inheritance, to stop any global GP from being applied which is what the ! means.  The user and the computer will be placed in the Guest OU.

Auto Login

I don't want to enable a global "guest" or "visitor" account to the entire org which is why I don't have the AD Guest account enabled.  So I created a user in AD called lets call them "org guest"; and on a specific computer that the org guest will be able to login to I also want it to auto login to that account for ease of use.  I also need to ensure that the user is in the proper local group so they get the proper restrictions which is really quite restrictive; I don't want them to be able to access any of the organizations network resources such as any network drives.  All I want them to have is the internet and the ability to copy from a USB drive to the local computer.

So to do this we are going to use regedit to make the following changes to the following registry location.

Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon

Find the following entries we will need to edit them




if you don't have them we will need to make these entries and set the following values, these are all string entries and will need the following values

AutoAdminLogon and set the Value data to 1

DefaultUserName and set the Value data to $domainuser

DefaultPassword and set the Value data to $userpassword

Add the user in this case "guest" to our guest group on the local machine.

Local Users and Groups

Group Policy

Once complete login to your AD controller and setup the following File Explorer settings under computer management.  Computer Management -> Administrative Templates -> Windows Components -> File Explorer

Essentially the only settings we are changing is the hibernate power options menu and the sleep power options menu.  We are going to set them to disabled.

Now the user Profile in AD requires a bit more configuration.

User Configuration -> Administrative Templates -> Windows Components -> File Explorer

We aren't going to be modifying anything in the following

  • Common Open File Dialog
  • Explorer Frame Pane
  • Previous Versions
We have altered the settings for the file explorer in AD with the following settings as shown below.

With our group policy configured we still have two requirements we have to work though; the audio muting and deleting left over files.  We are going to deal with the left over files first.

I created a folder called "orgtools" working out of the C: drive; I have the folder hidden by default and inside it I have a folder called powershell where I have a bat file setup so the powershell script can run, called deletefiles.bat

The bat file is configured to specifically only allow the single script to run.

Powershell.exe -executionpolicy remotesigned -File ./delete.ps1

The powershell file I have configured to delete files and folders in the user (orgguest) directory.  The file is call "delete.sp1"

Get-ChildItem -Path C:\Users\orgguest\ -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Desktop -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Downloads -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Documents -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path "C:\Users\orgguest\3D Objects" -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Contacts -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Favorites -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Links -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Music -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Videos -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Pictures -Include *.* -File -Recurse | foreach { $_.Delete()}

Get-ChildItem -Path C:\Users\orgguest\Searches -Include *.* -File -Recurse | foreach { $_.Delete()}

rm C:\Users\orgguest\Desktop -r -force

rm C:\Users\orgguest\Downlaods -r -force

rm C:\Users\orgguest\Documents -r -force

rm C:\Users\orgguest\Music -r -force

rm C:\Users\orgguest\Videos -r -force

rm C:\Users\orgguest\Pictures -r -force

rm "C:\Users\orgguest\3D Objects" -r -force

rm C:\Users\orgguest\Contacts -r -force

rm C:\Users\orgguest\Favorites -r -force

rm C:\Users\orgguest\Links -r -force

rm C:\Users\orgguest\Searches -r -force

#Delete Browser History, Cache and Cookies

rm C:\Users\orgguest\AppData\local\Google\Chrome\User Data\Default -r -force

rm C:\Users\orgguest\AppData\local\Google\Microsoft\Edge\User Data\Default -r -force

rm C:\Users\orgguest\AppData\local\Mozilla\Firefox\Profiles -r -force

To run the powershell file I have it setup to run on login; but could be setup to run on logoff, restart, shutdown etc.  I have it setup to use task scheduler to run on login of the domain\orgguest user.

And our final requirement is the Auto Mute, we will require some additional software like with my post about creating an Audio PA System; we are going to use NirSoft Sound CommandLine tool.  For this I am putting it in the powershell directory just for convivence sake.

Here is a picture of the directory

So the powershell command is fairly simple.  I called the file mute.ps1

.\svcl.exe /Mute "Speakers"

and again I have a bat file setup to run the powershell script like our delete files

Powershell.exe -executionpolicy remotesigned -File ./mute.ps1

I have setup a task scheduler to run on login and at 11:30 pm; incase the speakers are left on after an event which would typically be in the evening near close.  If there is something during the day it would be up to staff to either reboot the system or mute the speakers after using the system.

So what we have is a system that autoboots and logs in as a specific user who has very restricted access.  Below are some screen shots of the logged in user.  You can connect a flash drive mount it and copy files off

After the reboot; the copied file is gone

If you were to try copy to a folder you don't have access to you would get the following Error.

Friday, January 06, 2023

How to fix Lenovo Laptop Dock Monitor Blinking/Flickering

The organization I work for uses Lenovo Thinkpads and we purchased Lenovo USB C docks for those laptops and on the two of the new Gen 11 Intel laptops and on the Gen 8 Intel laptop using three separate Lenovo ThinkPad USB C Docks specifically the Type 40A9 and Type 40AY.  The laptops when docked and started from a cold boot or a reboot have an issue showing the screen on the monitors connected with DisplayPort.  I don't have HDMI monitors so I can't use HDMI.  

This seems to be a well known issue with Lenovo laptops and Lenovo USB C Docks you can reference the sources below.  This issue has been going on for about 6 months and I have tried all the fixes listed below during the 6 months applying the fixes as soon as they were available. 






The screens are either not showing (just black after about 1 to 3 minutes) or the screen is distorted with running horizontal lines showing only on one screen with screen jitter.

In fact the issue has persisted; with some staff using the devices becoming upset that this issue has not been fixed.  I can't say I blame them, we have been using Lenovo laptops and docks for 8 years and just within the last 6 months this has become an issue that hasn't been resolved.  At least until today with a work around using powershell.  Troubleshooting this issue nothing really came up in the event viewer; I caught an issue with the UCM-USCI ACPI Device not responding and given a error 43 but the dock had not stopped working with the exception of the displays.  At least according to the computer management console.  

View in device manager

Code 43 given randomly

I had noticed Network, sound, keyboard, webcams, mouse all continued to work when the monitors did the "blinking" issue.

Lenovo L15 Gen2 blinking issue on Type: 40AY Dock

For what ever reason when the monitor "Blinks" stops working and stay black until you either unplug the dock and plug it back in or you disable and re-enable the Intel display driver.

So my solution (after making sure everything was as up-to-date as possible with the latest Lenovo fixes) was the following.

Two Scripts.  A bat file and a powershell file.

The bat file allows the running of the powershell script.

---------BAT FILE----------

Powershell.exe -executionpolicy remotesigned -File  ./dock-disable-enable.ps1


-------Powershell File-------

Get-PnpDevice -FriendlyName 'Intel(R) Iris(R) Xe Graphics' | Disable-PnpDevice -Confirm:$false
Start-Sleep -Seconds 10
Get-PnpDevice -FriendlyName 'Intel(R) Iris(R) Xe Graphics' | Enable-PnpDevice -Confirm:$false


Using Task Scheduler, On a user login; I have a script that runs after a 30 second wait to run; However once it runs the script disables the Intel Driver and re-enables it after 10 seconds.  

This has stopped staff from having to unplug and re-plug in their laptops into the docking stations; and are much more happy with going to get a coffee when they login then come back then having to unplug and re-plug in their laptop dock.

Microsoft Family Safety

What is the Microsoft Family Safety? It is a free service offered by Microsoft that allows you to manage your family's devices and share...