PowerShell Code Snippets

Any solutions you find on these pages are provided “AS-IS” with no warranties. 

Find Applications with a specific dependency (Java, .Net, c++ runtime, ….)

Let’s assume you want to update your Java Application and you have to find all the Applications in SCCM where Java is set as dependency. The script below will give you the list.

#Enter the Application that is set as dependency
$Dependency = ‘%Java%’

# Fill in your database name and database server below
$SCCMDBName = ‘CM_P01’
$SCCMDBServerName = ‘SVRCMP01’

$objConnection = New-Object -comobject ADODB.Connection
$objRecordset = New-Object -comobject ADODB.Recordset
$con = “Provider=SQLOLEDB.1;Integrated Security=SSPI;Initial Catalog=$SCCMDBName;Data Source=$SCCMDBServerName”
$strSQL = @”
select rel.FromApplicationCIID from v_CIAppDependenceRelations as rel
inner join fn_ListLatestApplicationCIs(1033) AS app on app.CI_ID = rel.ToApplicationCIID
where app.DisplayName like ‘$Dependency’
“@

$objConnection.Open($con)
$objConnection.CommandTimeout = 0
# *********** Check If connection is open *******************
If($objConnection.state -eq 0)
{
Write-Host “Error: Connection to database failed. ”
Exit 1
}
else
{
$CIID_Array = @()
$objRecordset.Open($strSQL,$objConnection)
$objRecordset.MoveFirst()
$rows=$objRecordset.RecordCount
do
{
$objRecordset.MoveNext()
$CIID = $objRecordset.Fields.Item(0).Value
$CIID_Array += $CIID
}
until ($objRecordset.EOF -eq $TRUE)
$objRecordset.Close()

foreach ($ID in $CIID_Array)
{
$strSQL2 = @”
select DisplayName from fn_ListLatestApplicationCIs(1033) where CI_ID like ‘$ID’
“@
$objRecordset.Open($strSQL2,$objConnection)
If($objConnection.state -eq 0)
{
Write-Host “Error: Connection to database failed. ”
Exit 1
}
else
{
$value = $objRecordset.Fields.Item(0).Value
if($value)
{
Write-Host $value
}
$objRecordset.Close()
}
}
}

Modify the maximum runtime of software updates in SCCM

A frequent complaint is that the maximum runtime of software updates is too short. Or too long in case that small maintenance windows are being used. In most cases, the maxruntime is 10, 60, or sometimes 120 min. The script below allows you to modify the value (the feature to adjust the value was added in 1706).

function LoadCMModule
{
Import-module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + ‘\ConfigurationManager.psd1’)

$SiteCode = Get-PSDrive -PSProvider CMSITE
Set-location $SiteCode”:”
}

$updates = Get-CMSoftwareUpdate -Name “*2020-04*” -Fast #Better set a filter, this takes quite long
$count = 0

foreach ($update in $updates )
{
Write-Host $update.LocalizedDisplayName $update.MaxExecutionTime

switch($update.MaxExecutionTime){
600 {Set-CMSoftwareUpdate -CI_ID $update.CI_ID -MaximumExecutionMins 15; $count++; Write-Host “Changing ” $update.LocalizedDisplayName ” Current MaximumExecutionMins: ” $update.MaxExecutionTime -ForegroundColor Yellow; break;}
3600 {Set-CMSoftwareUpdate -CI_ID $update.CI_ID -MaximumExecutionMins 90; $count++; Write-Host “Changing ” $update.LocalizedDisplayName ” Current MaximumExecutionMins: ” $update.MaxExecutionTime -ForegroundColor Yellow; break;}
7600 {Set-CMSoftwareUpdate -CI_ID $update.CI_ID -MaximumExecutionMins 180; $count++; Write-Host “Changing ” $update.LocalizedDisplayName ” Current MaximumExecutionMins: ” $update.MaxExecutionTime -ForegroundColor Yellow; break;}
}
}
Write-Host $count ” changes made” -ForegroundColor Green

Parsing Kerberos events

Parsing EventLog events is a bit tricky. The code snippets below shall help to parse events 4768 and 4769 with PowerShell on Domain Controllers (mind that only the first 100 events are requested)

Get 4768 events (authentication ticket (TGT) was requested):

Get-WinEvent -FilterHashtable @{LogName = 'Security';ID='4768'} | select -First 100 -Property * | ForEach-Object -Process {New-Object -TypeName PSObject -Property @{'TimeCreated'=$_.TimeCreated; 'Account Name'=$_.properties[0].Value; 
'Supplied Realm Name'=$_.properties[1].Value;

'User ID'=$_.properties[2].Value;
'Service Name'=$_.properties[3].Value;
'Service ID'=$_.properties[4].Value;
'Ticket Options'=$_.properties[5].Value;
'Result Code'='{0:x8}' -f $_.properties[5].Value;
'EncryptionType'='{0:x2}' -f $_.properties[7].Value}}

Link: 4768(S, F): A Kerberos authentication ticket (TGT) was requested
https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4768

Get 4769 events (A Kerberos service ticket was requested):

Get-WinEvent -FilterHashtable @{LogName = 'Security';ID='4769'} | select -First 100 -Property * | ForEach-Object -Process {New-Object -TypeName PSObject -Property @{'TimeCreated'=$_.TimeCreated;
'TargetUserName'=$_.properties[0].Value;
'TargetDomainName'=$_.properties[1].Value;
'ServiceName'=$_.properties[2].Value;
'ServiceSID'=$_.properties[3].Value;
'TicketOptions'='{0:x8}' -f $_.properties[4].Value;
'TicketEncryptionType'='{0:x2}' -f $_.properties[5].Value;
'IPAdress'=$_.properties[6].Value
'IPPort'=$_.properties[7].Value
'Status'=$_.properties[8].Value;
'Logon GUID'=$_.properties[9].Value;
'TransmittedServices'=$_.properties[10].Value}}


Link: 4769(S, F): A Kerberos service ticket was requested. https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4769

Little helpers:
Get SID of an account:

$AdObj = New-Object System.Security.Principal.NTAccount(‘s-sql3@happyadmin.inc’)
$SID = $AdObj.Translate([System.Security.Principal.SecurityIdentifier])
$SID.Value

Get account from SID:

$sid = ‘S-1-5-21-291460342-2294237019-3453978477-502’
$objSID = New-Object System.Security.Principal.SecurityIdentifier($sid)
$objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
$objUser.Value

Monitor inboxes

$filewatcher = New-Object System.IO.FileSystemWatcher
#Mention the folder to monitor
$filewatcher.Path = “E:\Program Files\Microsoft Configuration Manager\inboxes” #Correct this!!
$filewatcher.Filter = “*.*”
#include subdirectories $true/$false
$filewatcher.IncludeSubdirectories = $true
$filewatcher.EnableRaisingEvents = $true

### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$writeaction = { $path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
$logline = “$(Get-Date), $changeType, $path”
Add-content “$PSScriptRoot\InboxWatch1.log” -value $logline
WriteLog -Path “$PSScriptRoot\InboxWatch.log” -Message ($logline | Out-String) -Component ‘InboxWatch’ -Type Info
}
### DECIDE WHICH EVENTS SHOULD BE WATCHED

#The Register-ObjectEvent cmdlet subscribes to events that are generated by .NET objects on the local computer or on a remote computer.
#When the subscribed event is raised, it is added to the event queue in your session. To get events in the event queue, use the Get-Event cmdlet.
Register-ObjectEvent $filewatcher “Created” -Action $writeaction
Register-ObjectEvent $filewatcher “Changed” -Action $writeaction
Register-ObjectEvent $filewatcher “Deleted” -Action $writeaction
Register-ObjectEvent $filewatcher “Renamed” -Action $writeaction
while ($true) {sleep 5}