How to automatically hide the Widgets and Teams chat button in Windows 11

As many of you know Windows 11 was released yesterday. Right now I’m I’m currently testing the official release and running Procmon to figure out some of the new registry keys that were introduced with Windows 11. Here are the registry keys and values that will automatically hide the Widgets and Teams chat button from the taskbar in Windows 11:

How to hide the widgets button:

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
“TaskbarDa”=dword:00000000

How to hide the Teams chat button:

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
“TaskbarMn”=dword:00000000

How to create Outlook holidays with Powershell

The following script is a proof of concept to demonstrate that you can create Outlook holidays automatically with Powershell. The POC script will automatically create a “Test Holiday” on the date that you ran the script. I also added an IF statement to check if the holiday already exists. That way users wouldn’t see the holiday added multiple times. The script can easily be setup to run in a ForEach loop to add multiple holidays in one script. You would just need to update the $Date and $Subject variables for each holiday.

$Date = (Get-Date).ToShortDateString()
$Subject = "Test Holiday"
$Outlook = New-Object -ComObject Outlook.Application
$NameSpace = $Outlook.GetNameSpace("MAPI")

If($NameSpace.GetDefaultFolder(9).Items.Restrict("[Start] = '$Date 12:00 AM' AND [Subject] = '$Subject'").count -eq 0) {

    $tzs = $Outlook.TimeZones
    $NewEvent = $Outlook.CreateItem(1)
    $NewEvent.Subject = $Subject
    $NewEvent.Start = $Date
    $NewEvent.End = $Date
    $NewEvent.StartTimeZone =$tzs["Central Standard Time"]
    $NewEvent.EndTimeZone = $tzs["Central Standard Time"]
    $NewEvent.Location = "United States"
    $NewEvent.Categories = "Holiday"
    $NewEvent.AllDayEvent = "True"
    $NewEvent.Save()

}

How to bring back the Windows 10 start menu on Windows 11

Update (10/6/2021) – I just tested the official Windows 11 release today and it appears you cannot bring back the Windows 10 start menu anymore. However the following registry key still works to move the start menu to the left side of the screen.

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
“TaskbarAl”=dword:00000000

As many of you know, Windows 11 will be introducing a new start menu layout. If you want to keep things consistent for your users you can add the following registry keys to your GPO when your company decides to roll out Windows 11.

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]
“TaskbarAl”=dword:00000000
“Start_ShowClassicMode”=dword:00000001

The Start_ShowClassicMode registry key will bring back the Windows 10 start layout and the TaskbarAl registry key will move everything to the left like it used to be.

Get-LogonServer Function

I have noticed in my testing that the %LOGONSERVER% environmental variable can sometimes be unreliable. After searching some time on Google, I found that using the nltest /dsgetdc: command was the most reliable method of returning the logon server. This unfortunately provides some complications since the results of the command also gives additional information that is not needed if you just need the current logon server. This is why I created the following Get-LogonServer function so you could easily return the logon server and use it in a Powershell script.

Function Get-LogonServer {

    Try {

        (nltest /dsgetdc: | findstr 'DC: ').split(" ") | %{
 
	        If($_ -like '\\*'){

			    $DC= $_.replace('\\','')

	        }

        }

    }
    Catch {
        
	    $DC = $False

    }
 
 
    If ($DC){

        $DC

    }
    Else {

        Return $False

    }
  
}

New-ChromeWebApp Function

Use the New-ChromeWebApp Powershell function to automatically create Google Chrome web application shortcuts.

Example: Create a web application shortcut for JoseEspitia.com in the Start Menu

New-ChromeWebApp -Location "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Jose Espitia.lnk" -URL https://www.JoseEspitia.com -Icon https://www.JoseEspitia.com/favicon.ico

Function:

Function New-ChromeWebApp {

    <#  
 
    .SYNOPSIS Create Chrome Web Applications
 
    .PARAMETER Location - Specify location for the shortcut

    .PARAMETER URL - Specify the web apps URL

    .PARAMETER Icon - Specify location for shortcut icon

    .EXAMPLE - Create JoseEspitia.com web app in All Users start menu
    New-ChromeWebApp -Location "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Jose Espitia.lnk" -URL https://www.JoseEspitia.com -Icon https://www.JoseEspitia.com/favicon.ico
 
    #>

    param (
        [parameter(Mandatory=$True)]
        [string]$Location,
        [parameter(Mandatory=$True)]
        [string]$URL,
        [parameter(Mandatory=$True)]
        [string]$Icon

    )
    # Get Chrome.exe path
    $ChromeOpenCommand = (Get-ItemProperty Registry::HKCR\ChromeHTML\shell\open\command)."(Default)"
    $ChromeDefaultPath = $ChromeOpenCommand.Substring(0, $ChromeOpenCommand.IndexOf(' --'))

    # Create web app shortcut
    $Shortcut = (New-Object -ComObject WScript.Shell).CreateShortcut("$Location") 
    $Shortcut.TargetPath = "$ChromeDefaultPath"
    $Shortcut.Arguments = "--app=$URL"
    $Shortcut.WorkingDirectory = "C:\Program Files\Google\Chrome\Application"
    $Shortcut.IconLocation = "$Icon"
    $Shortcut.Save()

}

Create custom environment variables for ConfigMgr

Have you ever wanted a quick shortcut on your clients that would allow you to access the Software Center, ConfigMgr Control Panel Applet and the CCM logs folder by just running a simple variable? Well the script below will automate the entire process for you. The following variables will be configured in the script:

  • CM
    • Launches the Configuration Manager Control Panel Applet
  • CMSC
    • Launches the Software Center
  • CMLogs
    • Opens %SystemRoot%\CCM\Logs

This makes accessing these commonly used resources as easy as hitting Windows + R and typing CM, CMSC, or CMLogs on the client machine.

Powershell Script:

$QuickcutDir = "C:\IT\Quickcuts"

If(!(Test-Path $QuickcutDir)) {

    New-Item $QuickcutDir -ItemType Directory -Force

}

$Shortcut = (New-Object -ComObject WScript.Shell).CreateShortcut("$QuickcutDir\CM.lnk") 
$Shortcut.TargetPath = "$($env:SystemRoot)\CCM\SMSCFGRC.cpl" 
$Shortcut.WorkingDirectory = "$($env:SystemRoot)\CCM" 
$Shortcut.IconLocation = "$($env:SystemRoot)\CCM\SMSCFGRC.cpl,0" 
$Shortcut.Save()

$Shortcut = (New-Object -ComObject WScript.Shell).CreateShortcut("$QuickcutDir\CMLogs.lnk") 
$Shortcut.TargetPath = "$($env:SystemRoot)\CCM\Logs"
$Shortcut.WorkingDirectory = "$($env:SystemRoot)\CCM" 
$Shortcut.IconLocation = "$($env:SystemRoot)\system32\imageres.dll,3" 
$Shortcut.Save()


$Shortcut = (New-Object -ComObject WScript.Shell).CreateShortcut("$QuickcutDir\CMSC.lnk") 
$Shortcut.TargetPath = "softwarecenter:"
$Shortcut.IconLocation = "$($env:SystemRoot)\CCM\scclient.exe,0" 
$Shortcut.Save()

$Path = (Get-ItemProperty -Path "HKLM:\SYSTEM\ControlSet001\Control\Session Manager\Environment").Path
$NewPath = "$QuickcutDir;" + $Path

If($Path -notlike "*$QuickcutDir*") {

    Set-ItemProperty -Path "HKLM:\SYSTEM\ControlSet001\Control\Session Manager\Environment" -Name Path -Type String -Value "$NewPath"

}

Get-Process Explorer | Stop-Process

Automatically remove inactive devices that do not exist in AD

The following script will query Configmgr for inactive devices and automatically remove them if they are no longer in Active Directory. Personally I prefer this simple script over the built in Configmgr maintenance task (Delete Inactive Client Discovery Data) because the task does not check Active Directory and it will remove any inactive device with the criteria that you have configured. By default, this maintenance task will remove any device that has been inactive for 90 days. At least in my environment, if a computer does not exist in Active Directory it should not be in MEMCM so I have the script run on a daily basis as a scheduled task to remove the devices that are not in AD.

Keep in mind to not run this script if you have workgroup computers because they will be deleted since they are not in AD.

Powershell Scripts:

Single Domain Environment:

$InactiveClients = Get-CMDevice | Where-Object { $_.ClientActiveStatus -eq 0 -or $_.ClientActiveStatus -eq $null -and $_.Name -notlike "*Unknown Computer*"}

ForEach($InactiveClient in $InactiveClients) {
    
    Try {

        If(-not(Get-ADComputer -Identity $($InactiveClient.Name))) { }

    }
    Catch {
    
        Write-Host "Removing: $($InactiveClient.Name)"
        Remove-CMDevice -Name $($InactiveClient.Name) -Force
    
    }

}

Multi Domain Environment:

$InactiveClients = Get-CMDevice | Where-Object { $_.ClientActiveStatus -eq 0 -or $_.ClientActiveStatus -eq $null -and $_.Name -notlike "*Unknown Computer*"}

$Domains = (Get-ADForest).Domains

[System.Collections.ArrayList]$Computers = @()


ForEach($InactiveClient in $InactiveClients) {

    ForEach($Domain in $Domains) {

        Try {

             If(-not(Get-ADComputer -Identity $($InactiveClient.Name) -Server $Domain)) { }

 
        }
        Catch {
     
            $Computers += $InactiveClient.Name
     
        }
        

    }
 
}

$ComputersNotInAD = ($Computers | Group-Object | Where-Object { $_.Count -eq $Domains.Count }).Values

Foreach($Computer in $ComputersNotInAD) {

    Write-Host "Removing: $Computer"
    Remove-CMDevice -Name $Computer -Force

}

Automatically update or remove an application in all of your ConfigMgr task sequences

There have been many times where I have needed to retire an old application but I can’t because the application in question is referenced in a few task sequences. Luckily this has become a little easier since ConfigMgr 1906 was released because Microsoft has added the task sequences tab in the application node. Unfortunately you can’t delete the application from the task sequence tab so it is still a tedious task that requires you to open each task sequence and remove or replace the application from each TS. This is why I wrote the following script to automate updating or removing an application from all of the task sequences that references the application.’

Eventually I will create a custom function for this that will make it easier to run but I figured if you are reading this, you are at least somewhat knowledgeable with Powershell 🙂

How to remove an application:

  1. Add the old application name to the $OldApplicationName variable
  2. Make the $Remove variable equal to $True

How to update an application

  1. Add the old application name to the $OldApplicationName variable
  2. Add the new application name to the $NewApplicationName variable
  3. Make the $Remove variable equal to $False

Code:

# Enter the name of the old application that you want to remove or replace
$OldApplicationName = ""

# Enter the new application name that that you want to use to replace the old application
$NewApplicationName = ""

# Make the remove variable value $true if you would like to remove an application from all task sequences
$Remove = ""

cls

$OldApplication = Get-CMApplication "$OldApplicationName"
$NewApplication = Get-CMApplication "$NewApplicationName"

$Application = Get-CMApplication -Name "$OldApplicationName"

# Get all task sequences that have the old application as a reference
$TaskSequences = Get-CMTaskSequence | Where-Object { $_.References.Package -eq $OldApplication.ModelName }

If($TaskSequences) {

    ForEach ($TaskSequence in $TaskSequences) {

        Write-Host "Updating $($TaskSequence.Name)"

        # Get all install application steps
        $InstallApplicationSteps = (Get-CMTSStepInstallApplication -InputObject (Get-CMTaskSequence -Name $TaskSequence.Name)).Name

        ForEach($InstallApplicationStep in $InstallApplicationSteps) {
            
            # Get a list of applications that are in the install application step
            $ApplicationList = (Get-CMTSStepInstallApplication -InputObject $TaskSequence -StepName "$InstallApplicationStep").ApplicationName.Split(",")

            # Get application steps that reference the old application
            If($OldApplication.ModelName -in $ApplicationList) {

                # Try to replace the old application with the new application
                Try {

                    If($Remove -eq $False) {

                        $ModelNames = $ApplicationList.Replace($OldApplication.ModelName,$NewApplication.ModelName)

                    }
                    Else {

                        $ModelNames = $ApplicationList | Where-Object { $_ -ne $OldApplication.ModelName }

                    }

                }
                Catch {

                    Write-Host "Failed to replace or remove old app"
                    Break

                }

                # Add the new application to the application step
                Write-Host "- Updating Step $InstallApplicationStep"
                Set-CMTSStepInstallApplication -InputObject $TaskSequence -StepName "$InstallApplicationStep" -Application ($ModelNames | ForEach { Get-CMApplication -ModelName $_ })

            }

        }

    }

}
Else {

    Write-Host "Could not locate the application in any task sequence!"

}

Automatically create Microsoft Edge profile shortcuts

Recently Adam Gross from A Square Dozen wrote a blog post on how to pin Microsoft Edge profile shortcuts to the taskbar and that got me thinking into how I could do this automatically. Unfortunately I couldn’t find a way to pin to the taskbar without a third party tool so I came up with the following solution that will create shortcuts for each of your profiles automatically on the desktop instead. The script will scan through %LOCALAPPDATA%\Microsoft\Edge\UserData and locate any custom profiles that you may have created (Example: %LOCALAPPDATA%\Microsoft\Edge\UserData\Profile 1). It will then query each profile’s preference file and locate the name of the profile so it can be used for the shortcut name (Example: Edge – Jose). At the end of the script, it will also create a shortcut for your default profile.

Keep in mind this script will only work with the regular Edge channel and not the DEV,Beta or Canary channel since the “C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe” is hard coded in the script. Hopefully this will help someone and if there is a way to pin to the taskbar by just using Powershell, please let me know!

$EdgeProfiles = Get-ChildItem "$env:LOCALAPPDATA\Microsoft\Edge\User Data" | Where-Object { $_.Name -like "Profile *"}

ForEach($EdgeProfile in $EdgeProfiles.Name) {

    # Get Profile Name
    $Preferences = "$env:LOCALAPPDATA\Microsoft\Edge\User Data\$EdgeProfile\Preferences"
    $Data = (ConvertFrom-Json (Get-content $Preferences -Raw))
    $ProfileName = $Data.Profile.Name

    # Create Shortcut on Desktop
    $TargetPath =  "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
    $ShortcutFile = "$env:USERPROFILE\Desktop\Edge - $ProfileName.lnk"
    $WScriptShell = New-Object -ComObject WScript.Shell
    $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
    $Shortcut.IconLocation = "$env:LOCALAPPDATA\Microsoft\Edge\User Data\$EdgeProfile\Edge Profile.ico, 0"
    $Shortcut.Arguments =  "--profile-directory=""$EdgeProfile"""
    $Shortcut.TargetPath = $TargetPath
    $Shortcut.Save()

}

# Get Profile Name
$Preferences = "$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Preferences"
$Data = (ConvertFrom-Json (Get-content $Preferences -Raw))
$ProfileName = $Data.Profile.Name

If($ProfileName -eq "Person 1") {

    $ProfileName = "Default"

}

# Create Shortcut on Desktop
$TargetPath =  "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
$ShortcutFile = "$env:USERPROFILE\Desktop\Edge - $ProfileName.lnk"
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
$Shortcut.IconLocation = "$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Edge Profile.ico, 0"
$Shortcut.Arguments =  "--profile-directory=""Default"""
$Shortcut.TargetPath = $TargetPath
$Shortcut.Save()

Get-CMGStatus Function

This small Powershell function can be used to determine if an SCCM client is connected to the Internet or Intranet. It is useful when you have a job that requires some type of network resource and it cannot run while your client is connected to a cloud management gateway. Using this example, you can easily determine the connection with the function and then decide to exit the script and run it at a later time.

Function Get-CMGStatus {

    <#
  
    .SYNOPSIS
    Queries SCCM connection type to determine if the PC is connected to a CMG
  
    #>

    $ClientInfo = Get-WmiObject -namespace root\ccm -Class ClientInfo

    If($ClientInfo.InInternet) {

        Return $True

    }
    Else {
        
        Return $False

    }

}
Older Posts »
Page 1 of 10