PI Services

Le blog des collaborateurs de PI Services

SCCM - SQL Query - Inventaire Software, Executables et AddRemove Programs

La requête ci-dessous fait un 'UNION' entre trois requêtes sur les vues [v_GS_INSTALLED_SOFTWARE_CATEGORIZED], [v_GS_INSTALLED_EXECUTABLE] et [v_ADD_REMOVE_PROGRAMS] pour obtenir un inventaire logiciel un peu plus "avancé".

N.B: Modifiez la variable @CollectionID si besoin pour réduire le scope des machines concernées, et éviter un nombre conséquent de ligne renvoyées.

 

/* --- SOFTWARES, EXECUTABLES, AND ADD-REMOVE PROGRAMS ENTRIES INVENTORY ---  
 NB: UNION ENTRE LES VUES:
	 [v_GS_INSTALLED_SOFTWARE_CATEGORIZED] 
	 [v_GS_INSTALLED_EXECUTABLE]
	 [v_ADD_REMOVE_PROGRAMS]
	 
	       
 NB: DES COLONNES SONT CREES ET POSITIONNEE A NULL POUR POUVOIR EFFECTUER LE UNION. (Meme nombre de colonnes) 

v_GS_INSTALLED_SOFTWARE_CATEGORIZED
Répertorie des informations sur les applications logicielles installées sur Configuration Manager clients trouvés via Asset Intelligence. 
Cette vue contient les informations contenues dans le v_GS_INSTALLED_SOFTWARE afficher et joint plusieurs autres tables pour fournir des détails supplémentaires sur les logiciels installés.

v_GS_INSTALLED_EXECUTABLE
Répertorie des informations sur les fichiers exécutables de l’application logicielle installée sur Configuration Manager clients trouvés via Asset Intelligence.

[v_ADD_REMOVE_PROGRAMS]
Combination of 32 and 64 bit programs data in 'Add Remove Programs'
*/



DECLARE @CollectionID as Varchar(8)
SET @CollectionID = 'SMS00001' --Specify the collection ID


SELECT  DISTINCT 

TAB.ResourceID
,TAB.ProductCode
,TAB.[Machine Name]
,TAB.OS_Name
,TAB.Publisher0
,TAB.NormalizedPublisher
,TAB.ExecutableName
,TAB.ProductName
,TAB.AddRemove_Name
,TAB.NormalizedName
,TAB.FamilyName
,TAB.CategoryName
,TAB.InstallDate
,TAB.Soft_Autostart
,TAB.EXE_FilePath
,TAB.EXE_Description
,TAB.ProductVersion
,TAB.EXE_FileVersion



 FROM (


SELECT 
SYST.ResourceID,
UPPER(SOFT.ProductCode0) as ProductCode,
SYST.Name0 as 'Machine Name',

-- OS Info --
OS.Caption0 as OS_Name,

-- SOFT INFO --
SOFT.Publisher0,
SOFT.NormalizedPublisher,
NULL as ExecutableName,
SOFT.ProductName0 as ProductName,
NULL as AddRemove_Name,
SOFT.NormalizedName,
SOFT.FamilyName,
SOFT.CategoryName,
SOFT.ProductVersion0 as ProductVersion,


SOFT.InstallDate0 as InstallDate,


CASE 
	WHEN AUTOSTART_SOFT.Product0 IS NULL THEN 'NO'
	ELSE 'YES'
	END as Soft_Autostart,

NULL as EXE_FilePath,
NULL as EXE_Description,
NULL as EXE_FileVersion


FROM [dbo].[v_GS_INSTALLED_SOFTWARE_CATEGORIZED] SOFT
FULL JOIN v_R_System SYST on SYST.ResourceID = SOFT.ResourceID
FULL JOIN [dbo].[v_GS_OPERATING_SYSTEM] OS on OS.ResourceID = SYST.ResourceID
FULL JOIN [dbo].[v_GS_AUTOSTART_SOFTWARE] AUTOSTART_SOFT on AUTOSTART_SOFT.Product0 = SOFT.ProductName0   -- TO MAKE RELATION WITH AUTO-START SOFTWARE
FULL JOIN v_FullCollectionMembership on (v_FullCollectionMembership.ResourceID = SYST.ResourceID)

WHERE v_FullCollectionMembership.CollectionID = @CollectionID


  
UNION 
 

SELECT 
  

SYST.ResourceID,
UPPER(EXE.ProductCode0) as ProductCode,
SYST.Name0 as 'Machine Name'

-- OS Info --
,OS.Caption0 as OS_Name

,EXE.Publisher0
,NULL as NormalizedPublisher
,EXE.ExecutableName0 as ExecutableName
,EXE.Product0 as ProductName
,NULL as AddRemove_Name
,NULL as NormalizedName
,NULL as FamilyName
,NULL as CategoryName 
,EXE.ProductVersion0 AS ProductVersion
,NULL as InstallDate
,NULL as Soft_Autostart

,EXE.InstalledFilePath0 as EXE_FilePath
,EXE.Description0 as EXE_Description
,EXE.FileVersion0 AS EXE_FileVersion


FROM [dbo].[v_GS_INSTALLED_EXECUTABLE] EXE
  
  FULL JOIN v_R_System SYST on SYST.ResourceID = EXE.ResourceID
  FULL JOIN [dbo].[v_GS_OPERATING_SYSTEM] OS on OS.ResourceID = SYST.ResourceID
  FULL JOIN v_FullCollectionMembership on (v_FullCollectionMembership.ResourceID = SYST.ResourceID)
 
 WHERE v_FullCollectionMembership.CollectionID = @CollectionID
 
  
  
UNION


SELECT
ARP.ResourceID
,UPPER(ARP.ProdID0) as ProductCode
,SYST.Name0 as 'Machine Name'
-- OS Info --
,OS.Caption0 as OS_Name
,ARP.Publisher0
,NULL as NormalizedPublisher
,NULL as ProductName
,NULL as ExecutableName
,ARP.DisplayName0 as AddRemove_Name
,NULL as NormalizedName
,NULL as FamilyName
,NULL as CategoryName 
,ARP.Version0 AS ProductVersion 

,CASE
WHEN ISDATE(ARP.InstallDate0) <> 0 THEN CONVERT(date,ARP.InstallDate0)
WHEN ISDATE(ARP.InstallDate0) = 0 THEN NULL
END AS InstallDate

,NULL as Soft_Autostart
,NULL as EXE_FilePath
,NULL as EXE_Description
,NULL as EXE_FileVersion

FROM [dbo].[v_ADD_REMOVE_PROGRAMS] ARP
FULL JOIN v_R_System SYST on SYST.ResourceID = ARP.ResourceID  
FULL JOIN v_FullCollectionMembership on (v_FullCollectionMembership.ResourceID = SYST.ResourceID)
INNER JOIN [dbo].[v_GS_OPERATING_SYSTEM] OS on OS.ResourceID = SYST.ResourceID  

WHERE v_FullCollectionMembership.CollectionID = @CollectionID 
  
  ) AS TAB

 

 

 

 

 

SCCM - SQL Query - Inventaire avancé de l'état des mise a jours.

 

La requête SQL ci-dessous propose un inventaire avancé des patchs de mise a jour installés ou requis sur les machines cibles.

Les variables @StartDate et @EndDate sont utilisées pour limiter la date de création du patch.

 

	/* PATCH REQUIRED OR INSTALLED STATUS FOR ALL SERVERS WITH SOFTWARE UPDATE GROUP INFO */
	DECLARE @Collection varchar(8)
	DECLARE @StartDate DATETIME, @EndDate DATETIME
	SET @Collection = 'SMS00001' -- Collection ID for All Systems
	-- Since 1 months
	SET @StartDate = DATEADD(mm, -1,GETDATE())
	SET @EndDate = GETDATE() 
	
	SELECT DISTINCT  VRS.Name0 as 'MachineName',
	Os.Caption0 as 'OperatingSystem',
	CASE
		WHEN summ.ClientActiveStatus = 0 THEN 'Inactive' 
		WHEN summ.ClientActiveStatus = 1 THEN 'Active' 
		end as 'ClientActiveStatus',
	CASE 
		WHEN LastHealthEvaluationResult = 1 THEN 'Not Yet Evaluated' 
		WHEN LastHealthEvaluationResult = 2 THEN 'Not Applicable'
		WHEN LastHealthEvaluationResult = 3 THEN 'Evaluation Failed' 
		WHEN LastHealthEvaluationResult = 4 THEN 'Evaluated Remediated Failed' 
		WHEN LastHealthEvaluationResult = 5 THEN 'Not Evaluated Dependency Failed' 
		WHEN LastHealthEvaluationResult = 6 THEN 'Evaluated Remediated Succeeded'
		WHEN LastHealthEvaluationResult = 7 THEN 'Evaluation Succeeded'
		end as 'Last Health Evaluation Result',
	CASE 
		WHEN LastEvaluationHealthy = 1 THEN 'Pass'
		WHEN LastEvaluationHealthy = 2 THEN 'Fail'
		WHEN LastEvaluationHealthy = 3 THEN 'Unknown'
		end as 'Last Evaluation Healthy',
	CASE 
		WHEN summ.ClientRemediationSuccess = 1 THEN 'Pass' 
		WHEN summ.ClientRemediationSuccess = 2 THEN 'Fail' ELSE '' 
		end as 'ClientRemediationSuccess',
	
	
	UI.Title as 'Title',
	UI.ArticleID as 'ArticleID',
	UI.BulletinID as 'BulletinID',
	UI.DatePosted,
	UI.DateCreated,
	UI.DateLastModified,
	
	CASE UI.Severity
		WHEN 0 THEN 'None'
		WHEN 2 THEN 'Low'
		WHEN 6 THEN 'Moderate'
		WHEN 8 THEN 'Important'
		WHEN 10 THEN 'Critical'
		end as Patch_Severity,

        CASE UI.IsExpired 
		WHEN 0 THEN 'NOT EXPIRED' 
		WHEN 1 THEN 'EXPIRED' 
		END AS [EXPIRY],
	
	CASE UI.IsSuperseded 
		WHEN 0 THEN 'NOT Superseded' 
		WHEN 1 THEN 'Superseded' 
		END AS [SUPERSEDENCE],


	CASE 
		WHEN UCS.Status = 2 THEN 'Required'
		WHEN UCS.Status = 3 THEN 'Installed'
		ELSE 'Unknown' END AS 'KBStatus',
	UI.InfoURL as 'InformationURL', 
	KB_AND_SUG.Title as SoftwareUpdateGroup,

	
	CASE 
		WHEN USS.LastScanState = 0 THEN 'unknown'
		WHEN USS.LastScanState = 1 THEN 'waiting for catalog location'
		WHEN USS.LastScanState = 2 THEN 'running'
		WHEN USS.LastScanState = 3 THEN 'completed'
		WHEN USS.LastScanState = 4 THEN 'pending retry'
		WHEN USS.LastScanState = 5 THEN 'failed'
		WHEN USS.LastScanState = 6 THEN 'completed with errors'
		END as LastScanState,

	USS.ScanTime,
	USS.LastScanTime,
	USS.LastErrorCode,
	USS.LastStatusMessageID
	
	FROM v_R_System VRS
	INNER JOIN v_UpdateComplianceStatus UCS ON UCS.ResourceID = VRS.ResourceID
	INNER JOIN v_UpdateInfo UI ON UCS.CI_ID = UI.CI_ID
	INNER JOIN v_UpdateScanStatus USS on VRS.ResourceID = USS.ResourceID
	INNER JOIN v_CICategories_All CIC ON UI.CI_ID = CIC.CI_ID
	
	
	INNER JOIN v_CH_ClientSummary summ on Vrs.ResourceID = summ.ResourceID
	INNER JOIN v_GS_OPERATING_SYSTEM Os on UCS.ResourceID = Os.ResourceID
	INNER JOIN Computer_System_DATA St on UCS.ResourceID = st.MachineID
	INNER JOIN v_FullCollectionMembership Col on UCS.ResourceID = Col.ResourceID
	
/* JOINTURE POUR OBTENIR L'INFO DU SOFTWARE UPDATE GROUP AUQUEL APPARTIENS LE PATCH */
INNER JOIN (SELECT DISTINCT
		upd.ArticleID,
		AL.Title
		FROM vSMS_CIRelation as cr
		INNER JOIN fn_ListUpdateCIs(1033) upd ON  upd.CI_ID = cr.ToCIID AND cr.RelationType = 1
		INNER JOIN v_CIToContent CC ON cc.CI_ID=upd.CI_ID
		INNER JOIN v_AuthListInfo AL ON al.CI_ID =cr.FromCIID
		) KB_AND_SUG on UI.ArticleID = KB_AND_SUG.ArticleID
		
	--WHERE VRS.Operating_System_Name_and0 like '%Server%'
	AND Col.CollectionID = @Collection
	AND DateCreated BETWEEN @StartDate AND @EndDate
	--AND CategoryInstanceName = 'Security Updates' -- Only Security Updates
	
	ORDER BY DateCreated DESC
	

 

Script - API Vmware VCenter - Get VM infos

Le script ci-dessous est un exemple simple de l'utilisation de l'API Rest de Vcenter pour recuperer toute sorte d'information, nottament sur les machines virtuelles.

A noter que la limitation du nombre d'objet retournés oblige simplement a recuperer dans un premier temps la liste des hosts, puis par host la liste des VMs.

 

### QUERY VCENTER REST API TO GET VM LIST ###


$user = ‘myaccount’
$pswd = Read-Host -Prompt "Enter Password"
$vCenterName = ‘MyVcenter’
$encoded = [System.Text.Encoding]::UTF8.GetBytes(($user, $pswd -Join ‘:’))
$encodedPassword = [System.Convert]::ToBase64String($Encoded)
$authHeader = @{
Authorization = "Basic $($EncodedPassword)"
}
$sRest = @{
Method = ‘Post’
Uri = "https://$($vCenterName)/rest/com/vmware/cis/session"
Headers = $authHeader
}
$result = Invoke-RestMethod @sRest


# Get TokenID
$authHeader = @{
‘vmware-api-session-id’ = $result.value
}


# Get All Hosts
$gethosts = "https://$($vCenterName)/rest/vcenter/host"
$resultgethost = Invoke-RestMethod -Uri $gethosts -Headers $authHeader
$hostidlist = $resultgethost.value.host


# For each host, get all VMs

foreach ($hostid in $hostidlist)
{
$get_vm = "https://$($vCenterName)/rest/vcenter/vm?filter.hosts=$hostid"
$resultvm = Invoke-RestMethod -Uri $get_vm -Headers $authHeader
[array]$FinalTableau += $resultvm
}

# Display Result
$FinalTableau.value | select name,power_state


# Output to CSV
$CsvTab = $FinalTableau.value | select name,power_state | ConvertTo-Csv -Delimiter ';' -NoTypeInformation
$CsvTab | Out-File .\VMList.csv

 

 

 

 

SCCM - SQL Queries - Deployments,Assignments,Updates

Ci-dessous, une série de requêtes SQL sur les déploiements, les assignations et les mise a jours.

/**** QUERIES: DEPLOYMENTS,ASSIGNMENTS,UPDATES ****/


--- LIST OF DEPLOYMENTS NAME
SELECT 
--DeploymentID = cia.Assignment_UniqueID,
DeploymentName = isnull(grp.Title+' - ', '') + cia.AssignmentName
FROM [dbo].[vCI_CIAssignments]  CIA
LEFT JOIN [dbo].[vCI_AssignmentTargetedGroups]  ATG on CIA.AssignmentType=5 and ATG.AssignmentID=CIA.AssignmentID
LEFT JOIN [dbo].[v_AuthListInfo] GRP on CIA.AssignmentType=5 and GRP.CI_ID=ATG.AssignedUpdateGroup
WHERE CIA.AssignmentType in (1,5)




--- LIST OF ASSIGNMENTS NAME WITH RELATED DEPLOYMENTS NAME
SELECT 
--AssignmentID,
CIA.AssignmentName,
--,DEPLOY.DeploymentID,
DEPLOY.DeploymentName 

FROM v_CIAssignment CIA
INNER JOIN (
			SELECT DeploymentID = cia.Assignment_UniqueID
			, DeploymentName = isnull(grp.Title+' - ', '') + cia.AssignmentName
			FROM [dbo].[vCI_CIAssignments]  CIA
			LEFT JOIN[dbo].[vCI_AssignmentTargetedGroups]  ATG on CIA.AssignmentType=5 and ATG.AssignmentID=CIA.AssignmentID
			LEFT JOIN [dbo].[v_AuthListInfo] GRP on CIA.AssignmentType=5 and GRP.CI_ID=ATG.AssignedUpdateGroup
			WHERE CIA.AssignmentType in (1,5)

			) DEPLOY on DEPLOY.DeploymentID = CIA.Assignment_UniqueID



---- LIST OF UPDATES 

		SELECT DISTINCT 
		--CI_UniqueID,
		DisplayTitle = ui.Title+isnull(' ('+nullif(ui.ArticleID, '')+')', '') + isnull(' ('+nullif(ui.BulletinID, '') +')', '')
		,DateCreated
		, (CASE ui.Severity 
		WHEN 0 THEN 'NONE' 
		WHEN 2 THEN 'LOW' 
		WHEN 6 THEN 'MODERATE' 
		WHEN 8 THEN 'IMPORTANT' 
		WHEN 10 THEN 'CRITICAL' END) AS SEVERITY
		FROM v_UpdateInfo UI
		
		ORDER BY DateCreated DESC

        

---- LIST OF UPDATES AND RELATED ASSIGNMENTS NAME

		SELECT DISTINCT 
		--CI_UniqueID,
		DisplayTitle = ui.Title+isnull(' ('+nullif(ui.ArticleID, '')+')', '') + isnull(' ('+nullif(ui.BulletinID, '') +')', '')
		,DateCreated
		,(CASE ui.Severity 
			WHEN 0 THEN 'NONE' 
			WHEN 2 THEN 'LOW' 
			WHEN 6 THEN 'MODERATE' 
			WHEN 8 THEN 'IMPORTANT' 
			WHEN 10 THEN 'CRITICAL' END) AS SEVERITY
		,CIA.AssignmentName
		FROM v_CIAssignment CIA
		INNER JOIN v_CIAssignmentToCI  ATC on ATC.AssignmentID=CIA.AssignmentID
		INNER JOIN v_UpdateInfo UI on UI.CI_ID=ATC.CI_ID

		ORDER BY DateCreated DESC
		
		



---- LIST OF UPDATES AND RELATED DEPLOYMENTS NAME

		SELECT 
		--CI_UniqueID,
		DisplayTitle = ui.Title+isnull(' ('+nullif(ui.ArticleID, '')+')', '') + isnull(' ('+nullif(ui.BulletinID, '') +')', '')
		,UI.DateCreated
		,(CASE ui.Severity 
			WHEN 0 THEN 'NONE' 
			WHEN 2 THEN 'LOW' 
			WHEN 6 THEN 'MODERATE' 
			WHEN 8 THEN 'IMPORTANT' 
			WHEN 10 THEN 'CRITICAL' END) AS SEVERITY
		,DEPLOY.DeploymentName
		FROM v_CIAssignment CIA
		INNER JOIN v_CIAssignmentToCI  ATC on ATC.AssignmentID=CIA.AssignmentID
		INNER JOIN v_UpdateInfo UI on UI.CI_ID=ATC.CI_ID
		INNER JOIN (
					SELECT DeploymentID = cia.Assignment_UniqueID
					, DeploymentName = isnull(grp.Title+' - ', '') + cia.AssignmentName
					FROM [dbo].[vCI_CIAssignments]  CIA
					LEFT JOIN [dbo].[vCI_AssignmentTargetedGroups]  ATG on CIA.AssignmentType=5 and ATG.AssignmentID=CIA.AssignmentID
					LEFT JOIN [dbo].[v_AuthListInfo] GRP on CIA.AssignmentType=5 and GRP.CI_ID=ATG.AssignedUpdateGroup
					WHERE CIA.AssignmentType in (1,5)

					) DEPLOY on DEPLOY.DeploymentID = CIA.Assignment_UniqueID
			
		ORDER BY DateCreated DESC

	

 

 

Script - Invoquer un update d'un agent Trend OSC a distance

Le script ci-dessous propose d'utiliser a distance la commande "PccNTMon.exe -u" sur un agent Trend OSC pour invoquer une mise a jour, en direction de son serveur OSC de rattachement.

 

#### RemoteInvokeTrendOSCAgentUpdate.ps1: REMOTELY INITIATE AN UPDATE OF A TREND OSC AGENT ####

## COMMENT: The script execute command through PSSession and open a RDP window to allow interactive use of "OSCAgentExe -u" ###

param(
# Target Computer
$Computer = "MyTarget",
# Cred
$Cred = $(Get-Credential -Credential "MyAccount"),
# OSC Agent Folder
$OSCAgentFolder = "C:\Program Files (x86)\Trend Micro\OfficeScan Client\",
# OSC Client Process
$OSCClientProc = "PccNTMon"
)


# OSC Agent Exe
$OSCAgentExe = "$OSCAgentFolder$OSCClientProc`.exe"


# FUNCTIONS
function Set-WindowState {
	
	[CmdletBinding(DefaultParameterSetName = 'InputObject')]
	param(
		[Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
		[Object[]] $InputObject,

		[Parameter(Position = 1)]
		[ValidateSet('FORCEMINIMIZE', 'HIDE', 'MAXIMIZE', 'MINIMIZE', 'RESTORE',
					 'SHOW', 'SHOWDEFAULT', 'SHOWMAXIMIZED', 'SHOWMINIMIZED',
					 'SHOWMINNOACTIVE', 'SHOWNA', 'SHOWNOACTIVATE', 'SHOWNORMAL')]
		[string] $State = 'SHOW'
	)

	Begin {
		$WindowStates = @{
			'FORCEMINIMIZE'		= 11
			'HIDE'				= 0
			'MAXIMIZE'			= 3
			'MINIMIZE'			= 6
			'RESTORE'			= 9
			'SHOW'				= 5
			'SHOWDEFAULT'		= 10
			'SHOWMAXIMIZED'		= 3
			'SHOWMINIMIZED'		= 2
			'SHOWMINNOACTIVE'	= 7
			'SHOWNA'			= 8
			'SHOWNOACTIVATE'	= 4
			'SHOWNORMAL'		= 1
		}

		$Win32ShowWindowAsync = Add-Type -MemberDefinition @'
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
'@ -Name "Win32ShowWindowAsync" -Namespace Win32Functions -PassThru

		if (!$global:MainWindowHandles) {
			$global:MainWindowHandles = @{ }
		}
	}

	Process {
		foreach ($process in $InputObject) {
			if ($process.MainWindowHandle -eq 0) {
				if ($global:MainWindowHandles.ContainsKey($process.Id)) {
					$handle = $global:MainWindowHandles[$process.Id]
				} else {
					Write-Error "Main Window handle is '0'"
					continue
				}
			} else {
				$global:handle = $process.MainWindowHandle
			}

			$Win32ShowWindowAsync::ShowWindowAsync($handle, $WindowStates[$State]) | Out-Null
			Write-Verbose ("Set Window State '{1} on '{0}'" -f $handle, $State)
		}
	}
}




# FOR EACH COMPUTER
foreach ($Comp in $Computer) {


# Create PSSession
try
{
New-PSSession -ComputerName $Comp -Credential $Cred -Name "PSSession_$Comp" -ErrorAction Stop
}
catch
{
write-host -F Red "Error during New-PSSession `n $($Error[0].Exception)"
exit 1 
}


# Get PSsession
$RemoteSession = Get-PSSession -Name "PSSession_$Comp"


# Open RDP Session (needed because the invoke update is interactive)
cmdkey /generic:TERMSRV/$Comp /user:($Cred.UserName) /pass:($Cred.GetNetworkCredential().Password)

mstsc /v:$Comp /w:50 /h:50

Write-Host "Wait for 10 sec..."
Start-Sleep -Seconds 10


# Get the RDP process Id to kill it at the end
$ProcId = (Get-Process mstsc | Where-Object {$_.MainWindowTitle -like "*$Comp*"}).Id


# Minimize RDP Window
(Get-Process mstsc | Where-Object {$_.MainWindowTitle -like "*$Comp*"}) | foreach {Set-WindowState $_ HIDE}


Write-Host "Wait for 10 sec..."
Start-Sleep -Seconds 10



# Invoke Update
write-host "Invoking update..."
Invoke-Command -Session $RemoteSession -ScriptBlock {Start-Process -FilePath $Using:OSCAgentExe -ArgumentList "-u"} 


        # Wait while update (see for update of ofcscan.ini file)
        do {
            Write-Host "Wait while update..."
           }

        until

           (
            (Invoke-Command -Session $RemoteSession -ScriptBlock {Get-ChildItem -Path "$Using:OSCAgentFolder`ofcscan.ini" | Where-Object {$_.LastWriteTime -gt $(get-date).AddMinutes(-15)}})
           )


Write-Host "Wait for 10 sec..."
Start-Sleep -Seconds 10



# Close RDP Session
write-host "Logoff RDP Session on $Comp..."
Invoke-Command -Session $RemoteSession -ScriptBlock {`
    $CredUser = $($Using:Cred.UserName)
    $sessions = quser | Where-Object {$_ -match $CredUser} ; 
    $sessionIds = ($sessions -split ' +')[2] ; 
    Write-Host "Found $(@($sessionIds).Count) user login(s) on computer.";
    $sessionIds | ForEach-Object {Write-Host "Logging off session id [$($_)]..." ; logoff $_}
     
     }


# Close RDP Session Disconnect Window by killing process
Get-Process -Id $ProcId | stop-process


}

# Remove Pssession
Get-PSSession | Remove-PSSession

 

Script - SCCM - Endpoint Protection Info

Le script SQL ci-dessous propose de lister les détails de l'état et la configuration des antivirus Defender pour des machines gérés par SCCM.

 

/****** ALL WORKSTATIONS ENDPOINT PROTECTION DETAILS  ******/

	SELECT DISTINCT (S.ResourceID)
	,S.Name0 AS 'Machine Name'
	,AD_Site_Name0 AS 'AD Site'
	,S.Operating_System_Name_and0 AS 'Operating System'
	,CASE [EpProtected]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Protected'
	,CASE [EpAtRisk]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Computer at Risk'
	,CASE [EpNotYetInstalled]
		WHEN 1 THEN 'NOT INSTALLED'
		WHEN 0 THEN 'INSTALLED'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Installed'
	,CASE [EpUnsupported]
		WHEN 1 THEN 'UNSUPPORTED'
		WHEN 0 THEN 'SUPPORTED'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Support'
	,CASE[Inactive]
		WHEN 1 THEN 'INACTIVE'
		WHEN 0 THEN 'ACTIVE'
		ELSE 'UNKNOWN' 
		END AS 'SCCM Client Activity'
	,CASE[NotClient]
		WHEN 1 THEN 'NO'
		WHEN 0 THEN 'YES'
		ELSE 'UNKNOWN' 
		END AS 'SCCM Client'
	,CASE [AmRemediationFailed]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Failed Remediation'
	,CASE [AmFullscanRequired]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Full Scan Required'
	,CASE [AmRestartRequired]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Restart Required'
	,CASE [AmOfflineScanRequired]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Offline Scan Required'
	,CASE [AmManualStepsRequired]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Manual Scan Required'
	,CASE [AmRecentlyCleaned]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Recently Cleaned'
	,CASE [AmThreatActivity]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Threat Activity'
	,CASE [EpInstallFailed]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Failed Install'
	,CASE [EpEnforcementSucceeded]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Enforce Succeed'
	,CASE [EpEnforcementFailed]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Enforce Failed'
	,CASE [EpPendingReboot]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Pending Reboot'
	,CASE [Unhealthy]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Unhealthy'
	,CASE [SignatureUpTo1DayOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Signature Age 1 day old'
	,CASE [SignatureUpTo3DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Signature Age 3 day old'
	,CASE [SignatureUpTo7DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Signature Age 7 day old'
	,CASE [SignatureOlderThan7Days]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Signature Age over 7 day old'
	,CASE [NoSignature]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'No Signature'
	,CASE [AmPending]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Pending'
	,CASE [LastScanUpTo2DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Last Scan 2 days old'
	,CASE [LastScanUpTo8DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Last Scan 8 days old'
	,CASE [LastScanUpTo31DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Last Scan 31 days old'
	,CASE [LastScanOver31DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Last Scan Over 31 days old'
	,CASE [Healthy]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Healthy'
	,CASE [Active]
		WHEN 1 THEN 'ACTIVE'
		WHEN 0 THEN 'INACTIVE'
		ELSE 'UNKNOWN' 
		END AS 'Client Activity'
	,CASE [EpUnmanaged]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Not Managed'
	,CASE [EpToBeInstalled]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint To be installed'
	,CASE [EpManaged]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Managed'
	,CASE [EpInstalled]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Managed'
	,CASE [EpEnforced]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Enforced'
	,CASE [EpEnabled]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Enabled'
	
	,CASE AMSH.Enabled 
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware_Enabled'
	,AMSH.Version as AntiMalware_Version
	--,AMSH.ProductStatus
	,CASE AMSH.RtpEnabled
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'RealTime_Ptct_Enabled'
	,CASE AMSH.OnAccessProtectionEnabled -- Specifies whether the computer is monitoring file and program activity on your computer
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'OnAccess_Ptct_Enabled'
	,CASE AMSH.IoavProtectionEnabled -- Scan all downloaded files and attachments
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Downloaded_Ptct_Enabled'
	,CASE AMSH.BehaviorMonitorEnabled
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Behavior_Monitor_Enabled'
	,CASE AMSH.AntivirusEnabled
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Antivirus_Enabled'
	,CASE AMSH.AntispywareEnabled
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Antispyware_Enabled'
	,AMSH.EngineVersion
	,AMSH.LastQuickScanDateTimeStart as 'Last QuickScan DateTime Start'
	,AMSH.LastQuickScanDateTimeEnd as 'Last QuickScan DateTime End'
	,AMSH.LastFullScanDateTimeStart as 'Last FullScan DateTime Start'
	,AMSH.LastFullScanDateTimeEnd as 'Last FullScan DateTime End'
	,AMSH.LastFullScanAge as 'Last FullScan Age'
	,AMSH.LastQuickScanAge as 'Last Quick Scan Age'
	,AMSH.AntivirusSignatureUpdateDateTime as 'Antivirus Signature Update DateTime'
	,AMSH.AntiSpywareSignatureUpdateDateTime as 'AntiSpyware Signature Update DateTime'
	,AMSH.AntivirusSignatureAge as 'Antivirus Signature Age'
	,AMSH.AntispywareSignatureAge as 'Antispyware Signature Age'
	,AMSH.AntivirusSignatureVersion as 'Antivirus Signature Version'
	,AMSH.AntispywareSignatureVersion as 'Anti spyware Signature Version'
	
	FROM [CM_BIM].[dbo].[v_EndpointProtectionStatus] EPPS /*(v_EndpointProtectionStatus: Fournit un résumé de l'état des clients Endpoint Protection global pour chaque ordinateur)*/
	INNER JOIN v_R_System S on S.ResourceID = EPPS.ResourceID
	INNER JOIN v_GS_AntimalwareHealthStatus AMSH on AMSH.ResourceID = EPPS.ResourceID /*(v_GS_AntimalwareHealthStatus:  Most recent snapshot of the AntimalwareHealthStatus WMI class for each client where EndPoint Protection is installed)*/
	



Script – Attribution de droits utilisateur dans la Local Policy

Le script ci-dessous prend en paramètre un compte et un nom de Privilège pour l’attribution des ‘User Rights Assignment’ au niveau de la 'Local Policy' d’une machine.

LocPolicyAddUserRight.ps1 (5,75 kb)

 

#### SCRIPT: ADD NEW ACCOUNT IN USER RIGHT ASSIGNMENT OF LOCAL SECURITY POLICY

# SCRIPTNAME : LocPolicyAddUserRight.ps1

# PARAMETERS:
# User: Account to grant
# PrivilegeName : See $AccesList to select right name
# ConfFilesPath : Path to export/import Conf File

# EXAMPLE: LocPolicyAddUserRight.ps1 -User MyDomain\MyAccount -PrivilegeName SeTimeZonePrivilege -ConfFilesPath C:\



Param
(
$User,
$PrivilegeName,
$ConfFilesPath
)



#USER RIGHT ASSIGNMENT LIST

[array]$AccessList = $(
"Access Credential Manager as a trusted caller = SeTrustedCredManAccessPrivilege"
"Access this computer from the network = SeNetworkLogonRight"
"Act as part of the operating system;SeTcbPrivilege"
"Add workstations to domain = SeMachineAccountPrivilege"
"Adjust memory quotas for a process = SeIncreaseQuotaPrivilege"
"Allow log on locally = SeInteractiveLogonRight"
"Allow log on through Remote Desktop Services = SeRemoteInteractiveLogonRight"
"Back up files and directories = SeBackupPrivilege"
"Bypass traverse checking = SeChangeNotifyPrivilege"
"Change the system time = SeSystemtimePrivilege"
"Change the time zone = SeTimeZonePrivilege"
"Create a pagefile = SeCreatePagefilePrivilege"
"Create a token object = SeCreateTokenPrivilege"
"Create global objects = SeCreateGlobalPrivilege"
"Create permanent shared objects = SeCreatePermanentPrivilege"
"Create symbolic links = SeCreateSymbolicLinkPrivilege"
"Debug programs = SeDebugPrivilege"
"Deny access to this computer from the network = SeDenyNetworkLogonRight"
"Deny log on as a batch job = SeDenyBatchLogonRight"
"Deny log on as a service = SeDenyServiceLogonRight"
"Deny log on locally = SeDenyInteractiveLogonRight"
"Deny log on through Remote Desktop Services = SeDenyRemoteInteractiveLogonRight"
"Enable computer and user accounts to be trusted for delegation = SeEnableDelegationPrivilege"
"Force shutdown from a remote system = SeRemoteShutdownPrivilege"
"Generate security audits = SeAuditPrivilege"
"Impersonate a client after authentication = SeImpersonatePrivilege"
"Increase a process working set = SeIncreaseWorkingSetPrivilege"
"Increase scheduling priority = SeIncreaseBasePriorityPrivilege"
"Load and unload device drivers = SeLoadDriverPrivilege"
"Lock pages in memory = SeLockMemoryPrivilege"
"Log on as a batch job = SeBatchLogonRight"
"Log on as a service = SeServiceLogonRight"
"Manage auditing and security log = SeSecurityPrivilege"
"Modify an object label = SeRelabelPrivilege"
"Modify firmware environment values = SeSystemEnvironmentPrivilege"
"Perform volume maintenance tasks = SeManageVolumePrivilege"
"Profile single process = SeProfileSingleProcessPrivilege"
"Profile system performance = SeSystemProfilePrivilege"
"Remove computer from docking station = SeUndockPrivilege"
"Replace a process level token = SeAssignPrimaryTokenPrivilege"
"Restore files and directories = SeRestorePrivilege"
"Shut down the system = SeShutdownPrivilege"
"Synchronize directory service data = SeSyncAgentPrivilege"
"Take ownership of files or other objects = SeTakeOwnershipPrivilege"

)



Function GetUserSID($UserName)
{
(New-Object System.Security.Principal.NTAccount($UserName)).Translate([System.Security.Principal.SecurityIdentifier]).value
}




Function Parse-SecPol($CfgFile){ 
    secedit /export /cfg "$CfgFile" | out-null
    $obj = New-Object psobject
    $index = 0
    $contents = Get-Content $CfgFile -raw
    [regex]::Matches($contents,"(?<=\[)(.*)(?=\])") | %{
        $title = $_
        [regex]::Matches($contents,"(?<=\]).*?((?=\[)|(\Z))", [System.Text.RegularExpressions.RegexOptions]::Singleline)[$index] | %{
            $section = new-object psobject
            $_.value -split "\r\n" | ?{$_.length -gt 0} | %{
                $value = [regex]::Match($_,"(?<=\=).*").value
                $name = [regex]::Match($_,".*(?=\=)").value
                $section | add-member -MemberType NoteProperty -Name $name.tostring().trim() -Value $value.tostring().trim() -ErrorAction SilentlyContinue | out-null
            }
            $obj | Add-Member -MemberType NoteProperty -Name $title -Value $section
        }
        $index += 1
    }
    return $obj
}




Function Set-SecPol($Object, $CfgFile){
   $OldSecPool.psobject.Properties.GetEnumerator() | %{
        "[$($_.Name)]"
        $_.Value | %{
            $_.psobject.Properties.GetEnumerator() | %{
                "$($_.Name)=$($_.Value)"
            }
        }
    } | out-file $CfgFile -ErrorAction Stop
    secedit /configure /db c:\windows\security\local.sdb /cfg "$CfgFile" #| out-null
}



# Export Original Conf
$OldSecPool = Parse-SecPol -CfgFile "$ConfFilesPath`Old.inf"

# Get user SID
try
    {
    $newsid = GetUserSID -UserName $User
    }
catch
    {
    $Message = "'$User' user SID has not been found"
    Write-Host -F Red $Message.ToUpper()
    exit 1 
    }


# 
if ($OldSecPool.'Privilege Rights'.$PrivilegeName -eq $null)
    {
    $Message = "'$PrivilegeName' privilege has not been found. Check Name. `n "
    Write-Host -F Red $Message.ToUpper()
    Write-Host "--- ACCESS RIGHTS NAMES ---:`n"
    $AccessList
    exit 1
    }
Else
    {
    # get original value
    $OldValue = $OldSecPool.'Privilege Rights'.$PrivilegeName
    # Add new SID to the string with required additional characters
    $NewValue = $OldValue+",*$newsid"
    # Set New Value
    $OldSecPool.'Privilege Rights'.$PrivilegeName = $NewValue
    }


$result = Set-SecPol -Object $OldValue -CfgFile "$ConfFilesPath`New.inf" 

if ($result[-2] -like "*successfully*")
    {
    $Message = "OK - '$User' has been granted '$PrivilegeName' `n $($result[-2]) `n $($result[-1])"
    write-host -F Green $Message.ToUpper()
    exit 0
    }

Else
    {
    $Message = "Error during grant of rights"
    write-host -F Red $Message.ToUpper()
    $result
    exit 1
    }

 

 

 

Script - Modification du fichier host et test de la resolution a distance

Le script ci-dessous propose de remplacer a distance le contenu du fichier de resolution c:\windows\system32\etc\hosts et d'effectuer un test de resolution des nouveaux noms.

Remote_ModifyHostFiles_And_Test.ps1 (3,61 kb)

# SCRIPT TO MODIFY HOSTS FILE ON TARGET SERVER AND REMOTELY TEST RESOLUTION

Param(
$SrvList = ("Srv1","Srv2"),
$HostFilePath = "C:\Windows\System32\drivers\etc\hosts",
$cred = $(Get-Credential -Credential MyDomain\Me),
$Host1 = "Host1",
$IP1 = "0.0.0.1",
$Host2 = "Host2",
$IP2 = "0.0.0.2"
)


$cred = $(Get-Credential -Credential MyDomain\Me)




# host file
$hostcontent = 
"# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#	127.0.0.1       localhost
#	::1             localhost


# MY SERVERS
$Host1     $IP1
$Host2     $IP2
"


# FUNCTIONS
function Spec-Ping
{
Param($HostToPing)
Try {
            Test-Connection -ComputerName $HostToPing -Count 1 -ErrorAction Stop
            } 
            Catch [System.Net.NetworkInformation.PingException]
            {
            $pingresult = "PING ERROR TO $HostToPing - CHECK NAME RESOLVING"
            }

}


# OPENING WINRM SESSIONS ON MGS SERVERS
$SrvList | foreach {


            try
            {
            New-PSSession -Name $($_.Substring(0,13)) -ComputerName $_ -Credential $cred
            }
            catch
            {
            write-host -F red "Erreur lors de la creation de la session Winrm vers $_"
            }

}





$sessions = Get-PSSession

Foreach ($sess in $sessions)
    {
        
        Invoke-Command -Session $sess -ScriptBlock {Param($hostcontent,$HostFilePath) Set-Content -Path $HostFilePath -value $hostcontent} -ArgumentList $hostcontent,$HostFilePath
    
}



Write-Host "`n--- PING RESULT:"

Foreach ($sess in $sessions) 
    {
        
        # First Host Test
        $pingresult = Invoke-Command -Session $sess -ScriptBlock ${Function:Spec-Ping} -ArgumentList $Host1
            
            
            
             switch -Wildcard ($pingresult.value)
             {
             "PING ERROR*" {write-host -ForegroundColor red $pingresult.value}
             }
             

             Switch ($pingresult.IPV4Address.IPAddressToString)
                {
                $IP1 {Write-Host "OK -- $Host1 is resolved by "$sess.ComputerName" to $IP1"}
                default {Write-Host "KO - Unable to get resolution of $Host1 on"$sess.ComputerName""}
                }
    



        
         # Second Host Test
         $pingresult = Invoke-Command -Session $sess -ScriptBlock ${Function:Spec-Ping} -ArgumentList $Host2
         switch -Wildcard ($pingresult.value)
             {
             "PING ERROR*" {write-host -ForegroundColor red $pingresult.value}
             }
             

             Switch ($pingresult.IPV4Address.IPAddressToString)
                {
                $IP2 {Write-Host "OK -- $Host2 is resolved by "$sess.ComputerName" to $IP2"}
                default {Write-Host "KO - Unable to get resolution of $Host2 on"$sess.ComputerName""}
                }

    }     




#Remove Pssessions
Remove-PSSession *

 

 

SCOM - Script - Exemple d'inventaire avec les classes "Principales".

L'idée du script ci-dessous est de proposer une forme d'inventaire des applications couvertes par une infra SCOM, en utilisant une liste, a maintenir, des principales classes d'objets tel que  'Active Directory Domain Controller Computer Role'  ou encore 'IIS Server Role'.

Il est donc necessaire de maintenir un minimum dans le temps, le contenu de $ClassList, et la correspondance faites entre les pattern de nom de classes et les application correspondantes.

SCOM_Inventory_with_Main_Classes.ps1 (12,71 kb)

 

### SCOM INVENTORY USING APPLICATION MAIN CLASS ###


#Parameters
Param(
$MS= "MyMS.MyDomain",
$cred = $(Get-Credential "MyDomain\")
)


# List of all 'Top' Classes for which we need to get instances
$ClassList=(
# ACTIVE DIRECTORY
'Active Directory Domain Controller Computer Role',` # ACTIVE DIRECTORY
'Certificate Service',  # ACTIVE DIRECTORY CERTIFICATE SERVICES
'Federation Server',    # ACTIVE DIRECTORY FEDERATION SERVICES 

# CITRIX
'Managed Citrix Presentation Server',  # CITRIX


# EXCHANGE
'Microsoft Exchange 2010 Server', # EXCHANGE
'Exchange 2007 Server Role', # EXCHANGE
'Exchange 2013 Server', # EXCHANGE

# LYNC/SKYPE
'LS Server Role', # LYNC/SKYPE

# SHAREPOINT
'SharePoint Server', # SHAREPOINT

# SQL
'SQL Server 2008 DB Engine', # SQL (SQL 2008)
'SQL Server 2012 DB Engine', # SQL (SQL 2012)
'SQL Server 2014 DB Engine', # SQL (SQL 2014)
'SQL Server 2016 DB Engine', # SQL (SQL 2016)
'MSSQL on Windows: DB Engine', # SQL (SQL 2017+)

# SQL SSIS
'SQL Server 2014 Integration Services', # SQL SSIS (SQL 2014)
'SQL Server 2016 Integration Services', # SQL SSIS (SQL 2016)
'MSSQL on Windows Integration Services: Local Instance', # SQL SSIS (SQL 2017+)

# SQL SSAS
'SSAS 2008 Instance', # SQL SSAS (SQL 2008)
'SSAS 2012 Instance', # SQL SSAS (SQL 2012)
'SSAS 2014 Instance', # SQL SSAS (SQL 2014)
'SSAS 2016 Instance', # SQL SSAS (SQL 2016)
'MSSQL Analysis Services: Generic Instance', # SQL SSAS (SQL 2017+)

# SQL SSRS
'Microsoft SQL Server 2008 Reporting Services (Native Mode)', # SQL SSRS (SQL 2008)
'Microsoft SQL Server 2012 Reporting Services (Native Mode)', # SQL SSRS (SQL 2012)
'Microsoft SQL Server 2014 Reporting Services (Native Mode)', # SQL SSRS (SQL 2014)
'Microsoft SQL Server 2016 Reporting Services (Native Mode)', # SQL SSRS (SQL 2016)
'MSSQL Reporting Services: Instance (Native Mode)' , # SQL SSRS (SQL 2017)

# WINDOWS CLUSTER NODES
'Cluster Node', # WINDOWS CLUSTER

# IIS
'IIS Server Role', # IIS

# WINDOWS PRINT SERVER
'Print Services Role', # WINDOWS PRINT SERVER

# WINDOWS DNS
'Windows DNS Server', # WINDOWS DNS

# WSUS
'WSUS 3.0 Server', # WSUS
'Microsoft Windows Server Update Services 2012 R2', # WSUS
'Microsoft Windows Server Update Services 2016' # WSUS


  
)


#Import of SCOM module
try
{
Import-Module -Name OperationsManager -ErrorAction stop
}
catch
{
write-host -ForegroundColor red "Error during import of SCOM Module"
}

#Connection to $MS management server
New-SCOMManagementGroupConnection -ComputerName $MS -Credential $cred



# Create an empty tableau
$Finaltableau = @()


# Get All Instances for each class
foreach ($classname in $ClassList)
{

    
    $class = Get-SCOMClass -DisplayName $classname

    # If class is found we can go on  
    If($class)
    {
    


                $instances += Get-SCOMClassInstance -Class $class -ErrorAction SilentlyContinue



                foreach ($inst in $instances)
                {

                $obj = New-Object psobject


                    switch -Regex ($classname)
                    {
                    # ACTIVE DIRECTORY
                    "Active Directory Domain Controller Computer Role"  
                                            {

                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.path
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "ACTIVE DIRECTORY"
                                            }
    
    
                    # ACTIVE DIRECTORY CERTIFICATE SERVICES
                    "Certificate Service"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.displayname
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "ACTIVE DIRECTORY CERTIFICATE SERVICES"
                                            }


                    # ACTIVE DIRECTORY FEDERATION SERVICES
                    "Federation Server"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.displayname
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "ACTIVE DIRECTORY FEDERATION SERVICES"
                                            }


                    # CITRIX
                    ".*Citrix.*"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.displayname
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "CITRIX"
                                            }

                    
                    
                    # EXCHANGE
                    ".*Exchange.*"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.displayname
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "EXCHANGE"
                                            }          
                    
                    
                    # LYNC/SKYPE
                    ".*LS Server.*"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.Path
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "LYNC/SKYPE"
                                            }          



                    # SHAREPOINT
                    ".*sharepoint.*"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.Path
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "SHAREPOINT"
                                            }          




                    # SQL DB ENGINE
                    "SQL Server.*DB Engine"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.Path
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "SQL"
                                            }          



                    
                    "MSSQL on Windows: DB Engine"
   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.'[Microsoft.SQLServer.Windows.DBEngine].PrincipalName'.value
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "SQL"
                                            }          





                    # SQL BI
                    ".*(SQL Server.*Integration Services|Analysis Services|Reporting Services|SSAS).*"
                       
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.Path
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "SQL BI"
                                            }          


                    
                    "MSSQL on Windows Integration Services: Local Instance"
                                            
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.'[Microsoft.SQLServer.IS.Windows.LocalInstance].PrincipalName'.value
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "SQL BI"
                                            }      






                    # WINDOWS CLUSTER
                    ".*Cluster Node.*"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.DisplayName
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "WINDOWS CLUSTER"
                                            }          




                    # IIS
                    ".*IIS Server Role.*"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.Path
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "IIS"
                                            }          




                    # WINDOWS PRINT SERVER
                    ".*Print Services Role.*"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.Path
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "WINDOWS PRINT SERVER"
                                            }          




                    # WINDOWS DNS
                    ".*Windows DNS Server.*"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.Path
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "WINDOWS DNS"
                                            }          




                    # WSUS
                    ".*(Windows Server Update|WSUS).*"   
                                            {
                                            $obj | Add-Member -Name "COMPUTER" -membertype Noteproperty -Value $inst.Path
                                            $obj | Add-Member -Name "CLASS" -membertype Noteproperty -Value $classname
                                            $obj | Add-Member -Name "MAIN ROLE" -membertype Noteproperty -Value "WSUS"
                                            }          



                    }



                $Finaltableau += $obj

                }

    }


    Else
    {
    $ClassError = "'$classname' class was not found`n"
     
    }



# Clear of $instances variable for each $classname loop
Clear-Variable instances

}



# Display Final Result
$Finaltableau



# Display If some class was not found
If ($ClassError)
{
Write-Host -F Red "SOME CLASSES WAS NOT FOUND:`n$ClassError"
}

 

 

SCOM - Script de mode maintenance depuis une liste

Le script ci-dessous est une version un peu avancée avec des fonctions de log et de vérification.

SetInstanceFromFileInMM.txt (5,99 kb)

 

# SET MULTIPLE CLASS INSTANCE FROM LIST, IN MAINTENANCE MODE.

#Parametres
Param(
$ClassName="Microsoft.Windows.Computer", # Name of Class (Not DisplayName to avoid system language differences) 
$MS= "MyMS.Mydomain.com", # Target Management Server
$cred = $(Get-Credential),
$HostFilePath="C:\HostMM.txt", # List of Host to put in Maintenance Mode
$Duration="10", # Duration in minutes (min: 5 minutes)
$LogPath = "C:\MMlog.txt" # Path of Log file
)



function Write-Log 
{ 
    [CmdletBinding()] 
    Param 
    ( 
        [Parameter(Mandatory=$true, 
                   ValueFromPipelineByPropertyName=$true)] 
        [ValidateNotNullOrEmpty()] 
        [Alias("LogContent")] 
        [string]$Message, 
 
        [Parameter(Mandatory=$false)] 
        [Alias('LogPath')] 
        [string]$Path=$LogPath, 
         
        [Parameter(Mandatory=$false)] 
        [ValidateSet("Error","Warn","Info")] 
        [string]$Level="Info", 
         
        [Parameter(Mandatory=$false)] 
        [switch]$NoClobber 
    ) 
 
    Begin 
    { 
        # Set VerbosePreference to Continue so that verbose messages are displayed. 
        $VerbosePreference = 'Continue' 
    } 
    Process 
    { 
         
        # If the file already exists and NoClobber was specified, do not write to the log. 
        if ((Test-Path $Path) -AND $NoClobber) { 
            Write-Error "Log file $Path already exists, and you specified NoClobber. Either delete the file or specify a different name." 
            Return 
            } 
 
        # If attempting to write to a log file in a folder/path that doesn't exist create the file including the path. 
        elseif (!(Test-Path $Path)) { 
            Write-Verbose "Creating $Path." 
            $NewLogFile = New-Item $Path -Force -ItemType File 
            } 
 
        else { 
            # Nothing to see here yet. 
            } 
 
        # Format Date for our Log File 
        $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" 
 
        # Write message to error, warning, or verbose pipeline and specify $LevelText 
        switch ($Level) { 
            'Error' { 
                Write-Error $Message 
                $LevelText = 'ERROR:' 
                } 
            'Warn' { 
                Write-Warning $Message 
                $LevelText = 'WARNING:' 
                } 
            'Info' { 
                Write-Verbose $Message 
                $LevelText = 'INFO:' 
                } 
            } 
         
        # Write log entry to $Path 
        "$FormattedDate $LevelText $Message" | Out-File -FilePath $Path -Append 
    } 
    End 
    { 
    } 
}


# Initiate Log File
$message = "------ START OF MAINTENANCE MODE LOG ------`n`n"
Write-Log -Message $message -Path $LogPath -Level Info -ErrorAction SilentlyContinue


#Check that Host list file exist
if (!(Test-Path -Path $HostFilePath))
    {
    $message = "Unable to find Host list file`n"
    write-host -ForegroundColor red $message
    Write-Log -Message $message -Path $LogPath -Level Error -ErrorAction SilentlyContinue
    exit 1
    }


# Store content of file
$HostList = Get-Content -Path $HostFilePath


#Import of SCOM module
try
{
Import-Module -Name OperationsManager -ErrorAction stop
}
catch
{
$message = "Error during import of SCOM PS module`n"
write-host -ForegroundColor red $message
Write-Log -Message $message -Path $LogPath -Level Error -ErrorAction SilentlyContinue
exit 1
}


#Connection to management server $MS
try
{
New-SCOMManagementGroupConnection -ComputerName $MS -Credential $cred
}
catch
{
$message = "Error during connection to $MS`n"
write-host -ForegroundColor red $message
Write-Log -Message $message -Path $LogPath -Level Error -ErrorAction SilentlyContinue
exit 1
}
 

# Set Start/End Time upon Duration 
$startTime = [DateTime]::Now
$endTime = $startTime.AddMinutes($Duration)


# Get the class
$Class = Get-SCOMClass | where-object {$_.Name -eq $ClassName} -ErrorAction Stop

If ($Class -eq $null)
    {
    $message = "Unable to find `"$ClassName`" Class`n"
    write-host -ForegroundColor red $message
    Write-Log -Message $message -Path $LogPath -Level Error -ErrorAction SilentlyContinue
    exit 1
    }



# Get the instances where displayname match content of $HostList
$Instances = Get-SCOMClassInstance -Class $Class | Where-Object {`
$_.Displayname -in $HostList 
} -ErrorAction Stop

If ($Instances -eq $null)
    {
    $message = "Unable to find instances of `"$ClassName`" Class`n"
    write-host -ForegroundColor red $message
    Write-Log -Message $message -Path $LogPath -Level Error -ErrorAction SilentlyContinue
    exit 1
    }



# Put in Maintenance Mode
$message = "Putting following instances in Maintenance Mode for $Duration minutes...:`n $($Instances | foreach {"$_;`n"})"
write-host $message
Write-Log -Message $message -Path $LogPath -Level Info -ErrorAction SilentlyContinue

    
$Instances | foreach {`
    try
    {
    $message = "`nSetting Maintenance Mode on `"$_`"..."
    write-host $message
    Write-Log -Message $message -Path $LogPath -Level Info -ErrorAction SilentlyContinue
    Start-SCOMMaintenanceMode -Instance $_ -Reason "PlannedOther" -EndTime $endTime -Comment "MM of $_" -ErrorAction Stop
    }
    catch
    {
    $message = "Error setting Maintenance Mode on `"$_`""
    write-host -ForegroundColor red $message
    Write-Log -Message $message -Path $LogPath -Level Error -ErrorAction SilentlyContinue
    }
}
    

# Check and log Maintenance Mode
$message = "Checking Maintenance Mode..."
Write-Log -Message $message -Path $LogPath -Level Info -ErrorAction SilentlyContinue

$Instances | foreach {`
$message = Get-SCOMMaintenanceMode -Instance $_ | foreach {"COMMENT: $($_.Comments) -- START:$($_.StartTime) -- END:$($_.ScheduledEndTime) -- REASON:$($_.Reason) -- USER:$($_.User)`n" } 
Write-Log -Message $message -Path $LogPath -Level Info -ErrorAction SilentlyContinue

}