Thursday, April 3, 2025

Install Powershell 7 and VSCode

 

Download and Install VSCode from

https://code.visualstudio.com/download

Use this command to check which versions are available

winget search Microsoft.PowerShell

Use this command on Windows 10 or 11 to install the latest Powershell

winget install --id Microsoft.Powershell --source winget

To install a specific version download from here



Launch VSCode and Install the Powershell extension from Microsoft





Tuesday, December 10, 2024

SCCM Configuration Manager powershell

 

Open the SCCM console and open Powershell ISE from the top left.  Powershell ISE will open with a script containing the SCCM connection values.

Run the script to make a powershell drive connection to SCCM. 

Test the connection using an SCCM cmdlet


Tuesday, February 20, 2024

Modules management

 

Once you start working with Powershell soon or later you will have to get a grip of module version management.  Basic Microsoft.Powershell.Core module cmdlets to manage modules are

Get-Module - List the modules imported in the current session or use -ListAvailable to show ones that can be imported from the PSModulePath.

Import-Module - Adds modules to the current session.
Remove-Module - Removes modules from the current session.

The full list of Microsoft.Powershell.Core modules are listed here

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/?view=powershell-7.4

You can get a feel for what these module commands do by following this exercise.  The below screen shot was taken on on a vanilla Windows Server 2019.

Start a fresh Powershell ISE window
Get-Module to display the current modules loaded in the session.
Get-Adapter to display the network adapter info.
Get-Module to display the current modules loaded in the session.  Notice that now NetAdapter and NetAdapter.Format.Helper appear in the list.
Remove-Module -Name NetAdapter

Get-Module this now displays the list of loaded modules but NetAdapter has been removed.





The next module we're interested in here is PowerShellGet

Let see what PowerShellGet version we have with our freshly installed Windows Server 2019:







Windows PowerShell 5.1 comes with PowerShellGet version 1.0.0.1, which doesn't include the NuGet provider. This provider is required by PowerShellGet when working with the PowerShell Gallery.  As it is, PowerShellGet version 1.0.0.1 can't really do much.  It can't even update itself with help from something else.  That something else is the NuGet provider.

This subject is also covered in 

https://learn.microsoft.com/en-us/powershell/gallery/powershellget/update-powershell-51?view=powershellget-3.x

Install-PackageProvider -Name NuGet -Force

Now that's installed upgrade the PowerShellGet

Install-Module PowerShellGet -AllowClobber -Force

Close and reopen the powershell interface.

It is recommended to set the Powershell Gallery as a trusted repository using

Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

To List available module versions in the PSGallery

Find-Module -name <ModuleName> 

Tuesday, August 8, 2023

Get User Groups Recursive

 param (

    [Parameter (ValueFromPipeline=$true, Mandatory=$true)]

    [string]$username = $null

       )


$dn = (Get-ADUser $username).DistinguishedName

#Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn) | where {$_.name -like "*oracle*" -or $_.name -like "*FDM*"} | select -expand Name | sort name

Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn) -Properties description | select Name,description | sort name

#Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn) | where {$_.name -like "PERM-D-*"} | select -expand Name | sort name

#Get-ADGroup -LDAPFilter ("(member:1.2.840.113556.1.4.1941:={0})" -f $dn) | select -expand Name | sort name

Tuesday, June 21, 2022

Remotely updating machine account group membership

 In this script, an operating system tool called klist is being called to update the machine account group memberships.  It then triggers a GPO update.  This would be useful where GPO security filtering has been limited to a group and new members have been added to the group for the GPO to apply to.

Consider adjusting the gpupdate call to restrict it machine or user as necessary.


param (
    [Parameter (ValueFromPipeline=$true, Mandatory=$true)]
    [string]$Groupname = $null
            )

$TargetMachineList=get-adgroupmember $groupname | select -expand name | sort name

foreach ($compname in $TargetMachineList)

    {
    $online = test-connection -computername $compname -Beffersize 16 -count 1 -quiet

    if ($online -like "true")
        {
        invoke-command -cn $compname -command {c:\windows\system32\klist -lh 0 -li 0x3e7 purge}
        invoke-command -cn $compname -command {c:\windows\system32\gpupdate /force}
        }

    }

Tuesday, March 8, 2022

Edit XML

 

This code locates a XML code section and modifies it.  It is based on a couple of articles:

https://gist.github.com/aadennis/1efa5015fca7b0ec23ee341d0665a067

https://superuser.com/questions/560329/how-to-modify-create-values-in-xml-files-using-powershell


The powershell is here followed by the structure of the target XML

#Checks the user config file

#Checks the AllowBatchPrinting setting is set to false and changes it to false if not.

 #Target Config File Name

$ConfigFileName = $env:LOCALAPPDATA+"\Microsoft\AppV\Client\VFS\5BC6440A-16C1-4529-B9B9-1A55D86892F5\ProgramFilesX86\Mitratech Holdings Inc\DataStoreDSX\Searching Client\HitecLabs.DataStore.SearchingClient.exe.config"

#Create XML object from file

$xml = [xml] (get-content -Raw $ConfigFileName)

#Check the item number of the target item

$names=$xml.configuration.applicationSettings.'HitecLabs.DataStore.Client.Applications.VisualDataStoreHelperLibrary.Properties.Settings'.Setting.name
$count=0
foreach ($name in $names)
    {

    if ($name -like "AllowBatchPrinting")

        {$item=$count}

    else

        {$count=$count+1}

    }

#Read current value of target value
$TargetSettingValue=$xml.configuration.applicationSettings.'HitecLabs.DataStore.Client.Applications.VisualDataStoreHelperLibrary.Properties.Settings'.Setting.item($item).value

 

#Change value if necessary.
if ($TargetSettingValue="True"){$xml.configuration.applicationSettings.'HitecLabs.DataStore.Client.Applications.VisualDataStoreHelperLibrary.Properties.Settings'.Setting.item($item).value = "False"
$xml.Save($ConfigFileName)
}

Target XML structure partial file section:

<?xml version="1.0" encoding="utf-8"?>

<!--

Configuration settings for DataStore Searching Client Application

-->

<configuration>

  <configSections>

    These sections removed

    </sectionGroup>

  </configSections>

  <applicationSettings>

    <HitecLabs.DataStore.Help.Properties.Settings>

      <setting name="DSSearchingClientHelpURL" serializeAs="String">

        <value>http://servername/DSXHelp/SearchingClient/SearchingClient.htm</value>

      </setting>

    </HitecLabs.DataStore.Help.Properties.Settings>

    <!-- Document Comparer setting for document revisions dialog -->

    <HitecLabs.DataStore.Client.Applications.VisualDataStoreHelperLibrary.Properties.Settings>

      <setting name="DocumentComparisonMethod" serializeAs="String">

        <!--

            0=Microsoft Word

            1=Aspose.Words

         -->

        <value>0</value>

      </setting>

      <setting name="MaxLogFileSizeToZipForEmailInMBs" serializeAs="String">

        <value>200</value>

      </setting>

      <setting name="AllowBatchPrinting" serializeAs="String">

        <value>False</value>

      </setting>

      <setting name="PrintBatchSize" serializeAs="String">

        <value>100</value>

      </setting>

    </HitecLabs.DataStore.Client.Applications.VisualDataStoreHelperLibrary.Properties.Settings>


Tuesday, March 9, 2021

Automatically Logoff Idle Users

Google around and you'll find various ways of automatically logging off idle users.  None of them suited my requirements so I created a task scheduler coupled to a powershell script to manage it.  The advantages of this approach are

  • Can't be intercepted by users
  • Only uses existing OS tools and scripting
  • Manages user logons individually
  • Works if Switch User is used to logon other accounts
  • Simple, quick, effective with no significant processing requirement
  • Any background management tasks such as OS updates are not affected.
The exact requirements were to logoff "idle" user logon sessions from Windows 10 computers.  The computers were open access type computers.  None of the work in the sessions would have any state to save and no background processing tasks in the session would exist.  Forcing a logoff for unused logons would not result in any lost work.  In reality this does not check for "Idle" sessions or an idle computer state.  It assumes sessions are unused and not needed and forces them to logoff.

This method also requires security event auditing to be turned on so that the events are stored in the security log.

The scheduled task is set to run as SYSTEM.  Check the tick box Run with highest privileges

The scheduled task is triggered by a custom event filter. The XML of which is thus:

<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[(EventID=4800 or EventID=4802)]]</Select>
  </Query>
</QueryList>

The program called is the powershell.exe with the argument -file <PathToScript>

There are no conditions.

Settings - Select "Run a new instance in parallel"  This setting enables multiple user sessions to be tracked if neccessary.

The PowerShell script is as follows:

#This script has just been triggered by a user 4800(lock) or 4802(screensaver) security log event
#get user id and event time
$trigger = get-eventlog -logname security | where {$_.InstanceId -like "4800" -or $_.InstanceId -like "4802"} | select -first 1

#Get event log time
#We'll look forward from this point later.
$trigtime = get-date -date $trigger.TimeGenerated

#Get trigger SessionId
$trigMsg = $trigger.Message
$trigIDtemp = $trigMsg.split("Session ID: ") | select -last 1
$trigID = $trigIDtemp.trim()

# Every 15 minutes check to see if the user has returned
# Do this in total 11 times (during 3 hours) if the user is still not back
# log them out.

#first wait 15 mins  wait period 1
start-sleep -s 900
#wait test
#start-sleep -s 120

#count from 0 while less that 10 causes 10 checks
$count = 0
While ($count -le 10)
    {
    #Current Time
    if ($count -eq 0)
        {$TimeSpec = $trigtime}
    else
        {$TimeSpec = $CheckTime}
           
    #Has user returned in the last 15 mins?
    $CheckEvLog = $null
    $CheckEvLog = get-eventlog -logname security -After $TimeSpec | where {$_.InstanceID -eq 4801 -or $_.InstanceId -eq 4803}
    
    #Check any return events 4801(unlock) or 4803(screensaver dismissed) for user id
    if ($CheckEvLog -notlike $null) 
        {
        #were any of the events related to the trigger sessionid ?
        foreach ($logitem in $CheckEvLog)
            {
            $logitemMsg = $logitem.Message
            $entryIDtemp = $logitemMsg.split("Session ID: ") | select -last 1
            $entryID = $entryIDtemp.trim()
        
            #if sessionIDs match then user has returned so exit
            if ($entryID -eq $trigID){exit}
            }
        }
    
    #there are no return events or they are not for current session id.
    $CheckTime = Get-Date
    
    #wait 15 mins
    start-sleep -s 900
    #wait test
    #start-sleep -s 15
       
    $Count; $Count +=1
    }

#if you're here, that user/sessionID ain't back. Time periods configured above have expired.
#Time to log them off
& logoff $trigID