Jun 15, 2017

EventLog Forwarding and Disk Space Monitoring

Hey all! You all know how to do EventLog forwarding to a centralized server and you're doing it, right? Some GPO's, centralized server somewhere with a lots of disk to store old EventLog files (*.evtx) but how to make sure that your disk space wont run out?

Ok, lets say that you calculated enough disk space for x months of *.evtx's to store, doesn't need to be just so exact 90 or 180 days but it's enough for you to store some 100GB of logs. And you want the logs to roll so oldest one will be deleted if free disk space is less than 5 percentage. It's accurate enough for now.

You can do this in a single-liner but readability and maintenance is always a nice feature in PS scripts too so here's my quick'n dirty solution I run as scheduled task.

Cheers, Ari


$freePercentageLimit = 95
$diskStat = Get-WmiObject –Class Win32_Volume -Filter "DriveLetter='D:'" | select Capacity,FreeSpace,@{Label='FreePercentage';Expression={($_.FreeSpace/$_.Capacity)*100}}
if ($diskStat.FreePercentage -le $freePercentageLimit) {
Get-ChildItem -Path 'D:\Event Log Forwarding' -Filter '*.evtx' | Sort LastWriteTime | select -First 1 | Remove-Item -Force

Kickin' those SUGs

You find out that some Software Update Groups (SUG) are low on compliant percentage, what to do? You can run the reports from SCCM console to see which clients are not fully compliant against specific SUG. Then you do some magic on the client and get the updates rolling again, right?

Well, sounds like too much work for me. Lets see what we can do with PowerShell...

Did some researching and found Eswar Koneti's @eskonr post about how to get Update Compliance status with SQL query. Nice! Now I took that SQL script, simplified it some and I was able to retrieve computers that need special care with updates.

Here's the script, ping me in Twitter @arisaastamoinen if you find it useful (or bugs...)

Cheers, Ari


 Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" 
 Set-Location "ABC:" # Set the current location to be the site code.
 # Which SUG we are checking?  
 $sug = 'Windows Updates Automatic Deployment 2017-06'  
 # Against which devices?  
 $devColl = Get-CMDeviceCollection -Name 'All Desktop and Server Clients'  
 <# Update statuses  
   Unknown = 0  
   Not Applicable = 1  
   Required = 2  
   Installed = 3  
 #>  
 $UpdateStatus = "2"  
 # Create a new collection where non-compliant clients will be added   
 $coll = New-CMDeviceCollection -Name 'Computers with Updates that need attention' -LimitingCollectionName 'All Systems' -Comment '2017-06-15 - Computers with Updates that need special attention' # -WhatIf  
 # or you can Get- the collection  
 $coll = Get-CMDeviceCollection -Name 'Computers with Updates that need attention'  
 # SQL specs  
 $SQLInstance = "mysqlserver\systemcenter"  
 $CMDatabase = "CM_X01"  
 # SQL Query returns computernames from a Collection whose Software Update Group status is x   
 $query = @"  
 Declare @Status nvarchar(255)  
 Declare @SUG nvarchar(255)  
 declare @devColl nvarchar(10)  
 set @Status='$UpdateStatus'  
 set @SUG = '$sug'  
 set @devColl = '$($devColl.CollectionID)'  
  select   
     RSys.name0 [Computername]  
  From v_Update_ComplianceStatusAll UCS  
      left join v_r_system RSys on UCS.resourceid=RSys.resourceid  
      left join v_FullCollectionMembership FCM on RSys.resourceid=FCM.resourceid  
      left join v_collection coll on coll.collectionid=FCM.collectionid  
      left join v_AuthListInfo LI on UCS.ci_id=li.ci_id  
  where li.title = @SUG and coll.collectionID = @devColl and UCS.status=@Status  
 "@  
 # Check results  
 # $query  
 # Invoke-Sqlcmd -ServerInstance $SQLInstance -Database $CMDatabase -Query $query  
 $computer = Invoke-Sqlcmd -ServerInstance $SQLInstance -Database $CMDatabase -Query $query | select -ExpandProperty Computername  
 $computer | foreach {  
   $dev = Get-CMDevice -Fast -Name $_  
   Add-CMDeviceCollectionDirectMembershipRule -CollectionId $coll.CollectionID -ResourceId $dev.ResourceID # -WhatIf  
 }  
 # for fun, call Machine Policy refresh on the group  
 Invoke-CMClientNotification -DeviceCollectionId $coll.CollectionID -NotificationType RequestMachinePolicyNow  
 # now you can initiate client notifications from GUI but lets do it with PS/WMI  
 #Software Updates Deployment Evaluation Cycle  
 $strAction = "{00000000-0000-0000-0000-000000000108}"  
 $computer | foreach {  
   Invoke-Command -ComputerName $_ -ScriptBlock {  
     Invoke-WmiMethod -Namespace root\ccm -Class SMS_Client -Name TriggerSchedule -ArgumentList $Using:strAction   
   } -AsJob -Verbose  
 }  
 # Software Updates Scan Cycle  
 $strAction = "{00000000-0000-0000-0000-000000000113}"  
 $computer | foreach {  
   Invoke-Command -ComputerName $_ -ScriptBlock {  
     Invoke-WmiMethod -Namespace root\ccm -Class SMS_Client -Name TriggerSchedule -ArgumentList $Using:strAction   
   } -AsJob -Verbose  
 }  

Jun 8, 2017

How to rollup ConfigMgr Software Updates for reporting

So you got an Automatic Deployment Rule (ADR) in place and Software Updates being automatically deployed once a week. We're half way this year and you've got something like 20-30 Software Update Groups (SUG) being deployed, do'h! SUG's are named perhaps something like 'Windows Updates Automatic Deployment 2017-05-09 10:05:22' - depending the naming convention you have in you ARD

How to rollup those updates to just one group per month or per year? With PowerShell, of cource!

First you need a SUG for all updates, lets call it "All Updates". Yes, I know, how clever! Then you need SUG for each month. Let's just cheat a little, go ahead and rename one of your monthly SUG's to '....2017-05' leaving out the day and time part of the name. This group will be the monhly group of May.

And the the magic! Just connect to your SCCM via PowerShell and run this script, modifying it by changing your own CM sitecode and the names of source and rollup groups:

Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1"
Set-Location "L01:"

$SourceGroup = 'Windows updates automatic deployment 2017-05-*'
$RollupGroup = 'Windows updates automatic deployment 2017-05'
$AllUpdatesGroup = 'All Updates'

$ListOfUpdates = (Get-CMSoftwareUpdateGroup | where {$_.LocalizedDisplayname -like $SourceGroup}).Updates

Write-Verbose "Adding to rollup group"
Add-CMSoftwareUpdateToGroup -SoftwareUpdateId $ListOfUpdates -SoftwareUpdateGroupName $RollupGroup -Verbose

Write-Verbose "Adding to All Updates group"
Add-CMSoftwareUpdateToGroup -SoftwareUpdateId $ListOfUpdates -SoftwareUpdateGroupName $AllUpdatesGroup -Verbose

 This script will just pick all the updates from the source groups and throw them to the rollup groups. Later you can then just delete the source groups, leaving one group per month and big 'All Updates' group for reporting etc.

And as always, if you have any comments please send me a tweet @arisaastamoinen

Cheers, Ari