poniedziałek, 5 marca 2018

How to check which binaries can be removed from SCCM server

    Recently I received an interesting question - can particular folders from the SCCM source share be removed or are they still in use by any application? It can be actually verified with a below SQL query, which helps to identify all folders set as a source for any application or package and matching a certain wildcard chosen by an administrator.


Exemplary output of the folder presence SQL query

Usage:
    Replace the _ServerFQDN_ string with the name of the source server, XXX$ with a name of the share and YYY with a regular expression matching a path to the folders you want to verify. 
    Obviously the query should be run via SQL Management Studio or any other similar tool letting you execute T-SQL queries.

Code:
SELECT Name,PkgSourcePath,ContentSource FROM v_Content
JOIN v_Package ON v_Package.PackageID = v_Content.PkgID
WHERE ContentSource LIKE '\\_ServerFQDN_\XXX$\YYY\%'
OR PkgSourcePath LIKE '\\_ServerFQDN_\XXX$\YYY\%'

poniedziałek, 19 lutego 2018

Checking the Full Folder Path of Collection Objects in SCCM

    Following up the recent post about identifying full folder path in SCCM for certain drivers, that can be found over here:

    I decided to post another, modified SQL query which hopefully will help you in this situation:

 Delete Collection Error - References to Other Collections Block the Delete Collection Action

    We know, that the references to the collection we want to remove in other collections are blocking the possibility to remove our collection. A task to find those collections might not be trivial if you don't know where in SCCM folder structure do they reside. Query below will recursively find the full folder path to those collections based on the regular expressions.

Usage:
    Replace the _CollectionRegexp_ string with the regular expression matching your needs depending on the collections you are looking for.
    Obviously the query should be run via SQL Management Studio or any other similar tool letting you execute T-SQL queries.

Code:
SELECT ROW_NUMBER() OVER (ORDER BY v_Collection.Name,vSMS_Folders.ContainerNodeID) AS [Row], v_Collection.Name, vSMS_Folders.ContainerNodeID,v_Collection.Name AS Folder  INTO #Temp
FROM v_Collection
JOIN vFolderMembers on v_Collection.CollectionID = vFolderMembers.InstanceKey
JOIN vSMS_Folders ON vFolderMembers.ContainerNodeID = vSMS_Folders.ContainerNodeID
WHERE v_Collection.Name LIKE '_CollectionRegexp_'
AND vFolderMembers.ObjectTypeName = 'SMS_Collection_Device'
ORDER BY v_Collection.Name

DECLARE @It INT=1

WHILE (@It <= (SELECT COUNT(*) FROM #Temp))
BEGIN
      DECLARE @ContainerID INT=(SELECT ContainerNodeID FROM #Temp WHERE Row=@It)
      DECLARE @ContainerIDBeg INT=(SELECT ContainerNodeID FROM #Temp WHERE Row=@It)
      DECLARE @ContainerFullName VARCHAR(MAX)
      DECLARE @ContainerName VARCHAR(MAX)
      WHILE (SELECT ParentContainerNodeID FROM vSMS_Folders WHERE ContainerNodeID=@ContainerID) != 0
      BEGIN
            SET @ContainerName = (SELECT Name FROM vSMS_Folders WHERE ContainerNodeID=@ContainerID)
            IF (@ContainerID=(SELECT TOP 1 ContainerNodeID FROM #Temp))
                  SET @ContainerFullName = @ContainerName
            ELSE
                  SET @ContainerFullName = @ContainerName + '\' + @ContainerFullName
            SET @ContainerID = (SELECT ParentContainerNodeID FROM vSMS_Folders WHERE ContainerNodeID=@ContainerID)
      END
SET @ContainerFullName = (SELECT Name FROM vSMS_Folders WHERE ContainerNodeID=@ContainerID) + '\' + @ContainerFullName
UPDATE #Temp
SET Folder = @ContainerFullName
WHERE Row = @It
SET @It += 1
SET @ContainerFullName = ''
END

SELECT Name,Folder FROM #Temp
DROP TABLE #Temp

środa, 14 lutego 2018

SCOM Monitor Checking Updates Availability in Software Center

    Recently I came across an interesting request, that I considered having a huge added value to the infrastructure thanks to SCCM-SCOM synergy. Namely the task was to configure a way to receive SCOM alerts whenever there are updates available on the servers in Software Center. After some research over few possible ways of implementing this via Script Rule I finally decided to complete the task with the usage of WMI Performance Counter monitor. Here is how to configure the whole solution

Configuration:
1. Go to the Authoring pane in SCOM console, right-click on monitors and select Create a Monitor -> Unit Monitor... option
     
Starting Monitor Creation Wizard Window

2. In the Monitor Type tab of the wizard go to WMI Performance Counters -> Static Thresholds -> Single Threshold -> Simple Threshold and select a Management Pack of your choice to store the monitor. Keep in mind, that if you plan to later on enable a monitor only for certain group of computers, this group will have to be kept in the same Management Pack in order for the override to be created
Monitor Type Settings Tab of the Wizard

3. In the General tab of the wizard provide the name of the monitor and select a parent monitor for it. I choose a Configuration one, which I think fits best the nature of the monitor, but it's an open choice. For the name you can copy the following one:

Manual Intervention Required for Software Updates Installation on the System

    I recommend, as a best practice, to always create a monitor as disabled and only enable it for a specific group of computers in order to avoid serious problems in case of a mistake during configuration process.

 General Settings Tab of the Wizard

4. In the WMI Configuration tab of the wizard put the following settings in the WMI Namespace and Query windows:

root\ccm\ClientSDK
SELECT * FROM CCM_SoftwareUpdate WHERE ComplianceState='0'

    I chose to configure the interval to 21600 seconds, as I believe one check every 6 hours is enough. Here you can see the configuration used for initial testing purposes

 WMI Configuration Settings Tab of the Wizard

5. In the Performance Mapper tab of the wizard put the following settings in the Object, Counter, Instance and Value fields:

Pending Updates
Pending Updates
$Data/Property[@Name='Name']$
$Data/Property[@Name='PercentComplete']$

 Performance Mapper Settings Tab of the Wizard

6. In the Threshold Value tab of the wizard set the threshold to 1.00
Threshold Value Settings Tab of the Wizard

7. In the Configure Health tab of the wizard set the Over Threshold condition to Healthy and Under Threshold one to Warning

Configure Health Settings Tab of the Wizard

8. In the Configure Alerts tab of the wizard tick both boxes - to generate and automatically resolve alerts. Set the monitor to generate an alert when the monitor is in a warning health state and put the following text in Alert Name and Alert Description fields:

Manual Intervention Required for Software Updates Installation on the System

The server has updates pending manual intervention. Please review the Software Center in order to verify whether there are no available updates or updates pending restart, and take necessary actions to resolve the SCOM alert
    Further troubleshooting:
1. Open wbemtest program on the problematic server
2. Connect to the root\ccm\ClientSDK namespace
3. Run the following query:
    SELECT * FROM CCM_SoftwareUpdate WHERE ComplianceState='0'
4. Verify whether there are any objects returned that would have an EvaluationState property set to either '0' (update available) or '8' (restart pending)


   Priority and Severity of the alerts is a personal choice, but I set it to Medium and Warning.

Configure Alerts Settings Tab of the Wizard


Additional Notes:
    1. Do not use the WMI Events branch in the wizard. The reason for this is, that we are using "normal" WMI query here rather than WMI Event query, which cannot be parsed by WMI Event Monitor/Rule. It will produce an alert in SCOM and a windows event 10357 from Health Service Modules source with the following error:

Module was unable to execute the notification query
Error: 0x80041059
Details: Class is not an event class

    2. Unfortunately WQL does not provide COUNT method similar to SQL. Therefore it is not possible to write a WQL query which would return the number of pending software updates and return an alert when it's greater than '0'. The workaround solution applied in this case is to catch the value of PercentComplete property of the collected WMI objects and throw an alert when it's lower than 1% (if the update is pending restart or available this value will be always set to 0%). If there is no value returned at all (meaning there are no pending update -related actions) there will be no instance found and the monitor will remain Healthy.

    3. After some testing it turned out, that despite all settings properly set in SCOM the alerts do not auto-close because the monitor do not change the status back to Healthy. They have to be manually reset after applying the updates to the servers. I believe a reason for this is, that the WMI objects queried simply disappear after the installation of patches and SCOM has no possibility to check for the values of the properties of those objects anymore. The developed solution is a simple PowerShell script, which can be run after the updates have been applied in order to reset the status of this monitor for a particular group of computers:

$monitor = Get-SCOMMonitor | ?{$_.DisplayName -like "*Manual Intervention*"}
$(Get-SCOMGroup | ?{$_.DisplayName -like "*Computer_Group_
Name*"}) | Get-SCOMClassInstance | ?{$_.HealthState -ne "Success"} | foreach {Write-Host -Foreground Green Resetting Manual Updates Intervention Monitor for server $_.Name;$_.ResetMonitoringState($monitor)}


    The script has to be saved as a .ps1 file and run from either Operations Manager Shell or normal PowerShell window after importing Operations Manager module. You have to replace the Computer_Group_Name string with the name of your computer group.


    4. Below is a quick command to double check the existence of patches from the command line (which I find more trustful than the Software Center itself):

wmic /namespace:\\root\ccm\ClientSDK path CCM_SoftwareUpdate WHERE ComplianceState=0 GET ArticleID,EvaluationState /format:list

środa, 13 grudnia 2017

Update - Log Files Sanitizier v2

    Following up the recent post about removing confidential data from the log files,
that can be found over here:

    I decided to post a new version of the script with several improvements comparing to the first version. In the initial release of the script was able to remove the confidential data from all the files in the same folder. Recently I was put against a bigger challenge though - I had to provide and sanitize the logs contained in multiple sub-folders in a complex folder structure. It would be a daunting challenge to copy and run the sanitizer script to every single location. Therefore I created a second version of the script with the following improvements:

1. The script digs now recursively through the whole sub-folders in a folder structure and removes confidential information from every single file
2. Previous version was creating a copy of the file where the confidential information has been found with a ".parsed" suffix next to the original file. In a multiple folder tree scenario fishing for those parsed files and manually removing the non-parsed files would be another time consuming task which I wanted to avoid. The new version of the script is creating a "_Senstive" folder at the top of the tree where it moves all the files with the confidential information. The sanitized version are replacing the original files in their respective locations
3. Minor bug fix - tests proved, that the previous version was not dealing well with the files containing other dots in the name, that the ones separating the file name and the file extension. In an extreme situation, when the files had similar names it would lead to overwriting ".parsed" versions of the files. Current version deals in a different way with renaming the files and this problem is resolved

Usage:
    Save the code of the log parser as a .sp1 file in the root of a directory containing all the files, that you want to sanitize. Run the log parser from Administrator PowerShell and it will create new files for any log files, that had the IP addresses detected

 Log Sanitizer output

Additional Notes:
    Be careful with *.evtx files, as they store IP addresses in a way, that there are spaces stored between each character (i.e. 1 0 . 1 . 1 2 2 . 1 3). This would not be detected by the log parser, so if you are exporting Windows Event Viewer logs for parsing ensure they are exported in the .csv format
Code:
New-Item .\_Sensitive -Type Directory
$logfiles = Get-ChildItem .\. -Recurse | ?{!$_.PSIsContainer}
Write-Host

forEach ($log in $logfiles){
                Write-Host -f green "Parsing $log"
        $IPsMatched = 0
        Get-Content $log.VersionInfo.FileName | ?{$_ -match '(?<IP>(10|172|255|192|45|48|49)\.\d{1,3}\.\d{1,3}\.\d{1,3})'} | ForEach-Object {$IPsMatched++}
        if ($IPsMatched -gt 0){
                Write-Host "Found $IPsMatched IP addresses"
                $parsedLogName = $log.Name.SubString(0, $log.Name.lastIndexOf('.')) + "_parsed." + $log.Name.Split('.')[-1]
                                $parsedLogFullName = $log.FullName | Split-Path
                                $parsedLogFullName += "\"
                                $parsedLogFullName += $parsedLogName
                (Get-Content $log.VersionInfo.FileName) -replace '(10|172|255|192|45|48|49)\.\d{1,3}\.\d{1,3}\.\d{1,3}','X.X.X.X' | Set-Content $parsedLogFullName
                Write-Host "Sanitized log file written into " -nonewline; Write-Host -f yellow $parsedLogFullName
                                Write-Host $log.VersionInfo.FileName -nonewline; Write-Host -f yellow " moved to .\_Sensitive folder"
                                Move-Item $log.VersionInfo.FileName .\_Sensitive
        }
        else {
                Write-Host "No IP addresses found"
        }
        Write-Host
}

piątek, 17 listopada 2017

Checking the Full Folder Path of Driver Objects in SCCM

    Following up the recent life hacks series post about finding certain drivers in SCCM, that can be found over here:

    I decided to post about the follow up question that I received afterwards. As we already identified, that certain drivers exist in the infrastructure, the next question is - where are they? The answer to this is not too obvious, as finding the full folder path in SCCM requires looping through the database with a SQL query, that will iterate towards the parent folder until such exists. With the below query you can identify this rather than checking folder by folder in the SCCM Console. Below you can find the exemplary output of the query:

 Exemplary Output of the Path of Driver Objects SQL query

Usage:
    Replace the _DriverModelRegexp_ string with the regular expression matching your needs depending on the model of the drivers you are looking for.
    Obviously the query should be run via SQL Management Studio or any other similar tool letting you execute T-SQL queries.

Additional Notes:
    Interesting fact about this query - it does find the drivers not only if they are present as an object with an exact same name as the queried one. It also finds the drivers that are compatible with the queried ones even with the other name. Apparently this is the way that the information is stored in SCCM database. You can see the example below, as in the query above I was looking for Allied Telesis AT-2911xx Gigabit Fiber Ethernet. The results of the query pointed me to the following folder with the following 4 objects inside:

Returned Folder Does Not Contain Allied Telesis AT-2911 Drivers

    However when you looks closer and check the Applicability tab in the dirver's properties you see, that they are actually compatible with AT-2911xx Gigabit Fiber Ethernet. Very convenient!

 Returned Drivers are compatible with Allied Telesis AT-2911 Ones

Code:
SELECT ROW_NUMBER() OVER (ORDER BY ModelName,vSMS_Folders.ContainerNodeID) AS Row,ModelName,vSMS_Folders.ContainerNodeID,ModelName AS Folder INTO #Temp
FROM v_CI_DriverModels
JOIN vFolderMembers ON v_CI_DriverModels.CI_UniqueID = vFolderMembers.InstanceKey
JOIN vSMS_Folders ON vFolderMembers.ContainerNodeID = vSMS_Folders.ContainerNodeID
WHERE ModelName LIKE '_DriverModelRegexp_'
ORDER BY ModelName
DECLARE @It INT=1
WHILE (@It <= (SELECT COUNT(*) FROM #Temp))
BEGIN
      DECLARE @ContainerID INT=(SELECT ContainerNodeID FROM #Temp WHERE Row=@It)
      DECLARE @ContainerIDBeg INT=(SELECT ContainerNodeID FROM #Temp WHERE Row=@It)
      DECLARE @ContainerFullName VARCHAR(MAX)
      DECLARE @ContainerName VARCHAR(MAX)
      WHILE (SELECT ParentContainerNodeID FROM vSMS_Folders WHERE ContainerNodeID=@ContainerID) != 0
      BEGIN
            SET @ContainerName = (SELECT Name FROM vSMS_Folders WHERE ContainerNodeID=@ContainerID)
            IF (@ContainerID=(SELECT TOP 1 ContainerNodeID FROM #Temp))
                  SET @ContainerFullName = @ContainerName
            ELSE
                  SET @ContainerFullName = @ContainerName + '\' + @ContainerFullName
            SET @ContainerID = (SELECT ParentContainerNodeID FROM vSMS_Folders WHERE ContainerNodeID=@ContainerID)
      END
SET @ContainerFullName = (SELECT Name FROM vSMS_Folders WHERE ContainerNodeID=@ContainerID) + '\' + @ContainerFullName
UPDATE #Temp
SET Folder = @ContainerFullName
WHERE Row = @It
SET @It += 1
SET @ContainerFullName = ''
END

SELECT ModelName,Folder FROM #Temp
DROP TABLE #Temp

piątek, 3 listopada 2017

Life Hacks - Checking the Presence of Certain Drivers in SCCM


    What will you say if someone asks you - do we have this particular driver already imported anywhere in SCCM? Here is the answer - a short but useful T-SQL query which will help you to find this out

Usage:
    Replace the _DriverModelRegexp_ string with the regular expression matching your needs depending on the model of the drivers you are looking for.
    Obviously the query should be run via SQL Management Studio or any other similar tool letting you execute T-SQL queries

Code: 
SELECT ModelName

FROM v_CI_DriverModels

WHERE ManufacturerName LIKE '_DriverModelRegexp_'

GROUP BY ModelName

ORDER BY ModelName