Powershell – SCCM Software Center server update

In our organization, we have SCCM for manual update deployment. I have a lot of servers I need to patch, on some regular basis.

Most of my servers reside on VmWare infrastructure, and before every update I need to create a snapshot of each and every one.
With the help of Powershell scripts and VmWare PowerCli I managed to create snapshot for my list of servers, patch servers with Function Install-SCCMPatchesAvailable, restart if necessary, and then check services with Automatic startup but not Started status. I separated Creation and Deletion of snaphots, patching and service checking, because It was easier for now. Script will be upgraded, maybe transfered to MS System Center Orchestrator or some other automatization software, but for now her it is.

# PARAMETERS
$Enviroment = "TEST"
$SnapCD = "D" # "C" "D" (Create or delete snapshots)
$patching = "NO" # "NO" "YES"
$serviceChecking = "YES" #"YES" "NO"
$pViServer = "vcenter.company.com"
$email = "someone@company.com"

Set-Location -Path "$PSScriptRoot"
#GetCurrent Directory of a script - $PSScriptRoot
switch ($Enviroment) {
  "TEST" {
        $ppath = "$PSScriptRoot\VM_Servers_TEST.txt"
  }
  "PROD" {
		$ppath = "$PSScriptRoot\VM_Servers_Prod.txt"
  }
}
$cred = Get-Credential

$ServerList = Get-Content -path $ppath
$Date = Get-Date -Format "yyyyMMdd"
$Description = "Powershell created Snapshot"
$excludeServices = @("BITS", "CDPSvc", "DoSvc", "gupdate", "MapsBroker", "RemoteRegistry", "RtkAudioService", "sppsvc", "WbioSrvc", "UALSVC") #some services don't need to be checked
$from = "Patching@company.com"
$mailsrv = "mail.company.com"
$mailencoding = ([System.Text.Encoding]::UTF8)

$HTML = @" 
<style> 
BODY{background-color :#FFFFF} 
TABLE{Border-width:thin;border-style: solid;border-color:Black;border-collapse: collapse;} 
TH{border-width: 1px;padding: 1px;border-style: solid;border-color: black;background-color: ThreeDShadow} 
TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color: Transparent} 
H2{color: #457dcf;font-family: Arial, Helvetica, sans-serif;font-size: medium; margin-left: 40px; 
</style> 
"@ 
#This is Create Snapshot part
IF ($SnapCD -eq "C") {
  #CONNECT TO Vmware
  try {
    Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false | Out-Null
    Connect-ViServer -server $pViServer -credential $cred -Verbose:$false | Out-Null
    Write-Output "Succesfully connected to $pViServer"
  }
  catch {
    Write-Output "error connecting to Vcenter  - Force Disconnect"
    Disconnect-VIServer -server $pViServer -Force -Confirm:$false
  }

  $Failed = @()
   
  foreach ($server in $ServerList) {
    $SnapshotName = "$server-$Date-$shortcode"
    Try {
      Write-Output "Snapshot create for server $server"
      #CREATE VM Snapshot#                       
      New-Snapshot -VM $server -Name $SnapshotName -Description $Description -memory:$false -Quiesce:$false -ErrorAction Stop | Out-Null
      Write-Output "Snapshot created - $server"     
    }
    Catch {
      #Failed Snapshots
      $ErrorMessage = $_.Exception.Message
      Write-Output "Sumting wong with creating snapshot $server; $ErrorMessage `r`n"
      $failed += "$server ;$ErrorMessage"
      
    }         
  }
                    
  if ($Failed) {
    $MailBody = ($Failed | Out-String)
    send-mailmessage -to $email -from $from -Subject "Failed Snapshot CREATE" -body $MailBody  -smtpserver $mailsrv  -Encoding $mailencoding
  }    
        
  #DISCONNECT FROM VmWARE
  Disconnect-VIServer -server $pViServer -Force -Confirm:$false   
  Write-Output "Disconnected from $pViServer"
}
#Start patching segment
IF ($patching -eq "YES") {
  #CONNECT TO Vmware
  try {
    Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false | Out-Null
    Connect-ViServer -server $pViServer -credential $cred -Verbose:$false | Out-Null
    Write-Output "Succesfully connected to $pViServer"
  }
  catch {
    Write-Output "Greška kod spajanja na Vcenter  - Force Disconnect"
    Disconnect-VIServer -server $pViServer -Force -Confirm:$false
  }
  $Failed = @()
  foreach ($server in $ServerList) {
    $VM = Get-Vm $server | Get-View
    $toolsstatus = $VM.guest.ToolsStatus #if toolsOk then restart server - else just patch  !!!Automatic tool install automatically restarts VM!!! this is the step
    #Write-Output "$toolsstatus - $server"
    #Write-Output "Patching started $server"                
    #IF server available - connect and run patching
    if (Test-Connection -ComputerName $server ) {
      try {
        #Na serveru pusti patchiranje
        Invoke-Command -ComputerName $server -Credential $cred -ScriptBlock {
          Function Install-SCCMPatchesAvailable {
			  
            [CmdletBinding()]
            param(
              [Parameter(
                Position = 0,
                Mandatory = $false,
                ValueFromPipelineByPropertyName = $true,
                HelpMessage = "Do not reboot server after patches install")]
              [ValidateNotNullOrEmpty()]
              [switch]
              $DoNotReboot
            )

            begin {
              Write-Verbose "Install-SCCMPatchesAvailable: Started"
            }

            process {
              try {
                ([wmiclass]'ROOT\ccm\ClientSDK:CCM_SoftwareUpdatesManager').InstallUpdates([System.Management.ManagementObject[]] `
                  (Get-WmiObject -Query 'SELECT * FROM CCM_SoftwareUpdate' -namespace 'ROOT\ccm\ClientSDK'))

                while (-not((Get-WmiObject -Namespace 'ROOT\ccm\ClientSDK' -Class 'CCM_ClientUtilities' -list).DetermineIfRebootPending().RebootPending)) {
                  $Time = (get-date).ToShortTimeString()
                  Write-Output "Still Patching @ $Time"
                  Start-Sleep -s 20
                }
                if (-not $PSBoundParameters.ContainsKey('DoNotReboot')) {
                  if ((Get-WmiObject -Namespace 'ROOT\ccm\ClientSDK' -Class 'CCM_ClientUtilities' -list).DetermineIfRebootPending().RebootPending) {
                    (Get-WmiObject -Namespace 'ROOT\ccm\ClientSDK' -Class 'CCM_ClientUtilities' -list).RestartComputer()
                  }
                }
              }
              catch {
                Write-Error -Message "Something went wrong with Install-SCCMPatchesAvailable.`n`nError.Exception.Message : $($_.Exception.Message)`nError.Exception.FullName: $($_.Exception.GetType().FullName)"
              }
            }

            end {
              Write-Verbose "Install-SCCMPatchesAvailable: Completed"
            }
          } #End 
                               
          #IF NO PATCHES
          IF (-NOT(Get-WmiObject -Query 'SELECT * FROM CCM_SoftwareUpdate' -namespace 'ROOT\ccm\ClientSDK')) {
            Write-Output "No patches for server $using:server `r`n"
          }
          else {
        
            IF ($using:toolsstatus.value -eq "toolsOk") {
              Write-Output "Install patches on $using:server and restart `r`n"
              Install-SCCMPatchesAvailable
            }
            else {
              Write-Output "Install patches on $using:server and DONT restart `r`n"
              Install-SCCMPatchesAvailable DoNotReboot
            }
            
          }#else

        } -ErrorAction Stop #scriptblock 
      }
      catch {
        $ErrorMessage = $_.Exception.Message
        Write-Output "Sumting wong with patching $server; $ErrorMessage `r`n"
        $failed += "$server ;$ErrorMessage"
      }

    }#if
  }#foreach
  if ($Failed) {
    $MailBody = ($Failed | Out-String)
    send-mailmessage -to $email -from $from -Subject "Failed Patch Installing" -body $MailBody  -smtpserver $mailsrv  -Encoding $mailencoding
  } 
}#IF
#Service checking segment
IF ($serviceChecking -eq "YES") {

  $Failed = @()
  foreach ($server in $ServerList) {
    #IF server connection OK connect and run command
    if (Test-Connection -ComputerName $server -Quiet) {
      try {
        Invoke-Command -ComputerName $server -Credential $cred -ScriptBlock {

          If ($patching -eq "YES" -and $serviceChecking -eq "YES") {
            #if service checking is after patching, then wait 3 minutes to check services
            Start-Sleep -s 180 #wait 3 minutes
          }
          $services = Get-service | Where-Object { $_.Status -ne "Running" -and $_.StartType -eq "Automatic" -and $_.Name -notin $using:excludeServices } | Select-Object Name, Status, StartType, DisplayName
          IF ($services) {
            $MailBody = $services | ConvertTo-Html -Property "Name", "Status", "StartType", DisplayName -head $HTML -body  "<H2> Services Not running $env:computername</H2>" | Out-String
            #$enc = ([System.Text.Encoding]::UTF8)
            send-mailmessage -to $using:email -from $using:from -Subject "$using:server - Services not started" -body $MailBody  -smtpserver $using:mailsrv -BodyAsHtml  
          }#IF
          else {
            $MailBody = "<H2> Services OK - Patching Successfull $env:computername</H2>"
            send-mailmessage -to $using:email -from $using:from -Subject "$using:server - Services not started" -body $MailBody  -smtpserver $using:mailsrv -BodyAsHtml
          }#else
        } -ErrorAction Stop #Scriptblock
      }
      catch {
        $ErrorMessage = $_.Exception.Message
        Write-Output "Sumting wong with checking services $server; $ErrorMessage `r`n"
        $failed += "$server ;$ErrorMessage"
        
      }
    }#test
  }#foreach
  if ($Failed) {
    $MailBody = ($Failed | Out-String)
    send-mailmessage -to $email -from $from -Subject "Failed Services Check" -body $MailBody  -smtpserver $mailsrv  -Encoding $mailencoding
  } 
} #IF
#Snapshot delete segment
#Delete only snapshot that has specific description (from parameters)
if ($SnapCD -eq "D") {
  try {
    #CONNECT TO Vmware
    Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false | Out-Null
    Connect-ViServer -server $pViServer -credential $cred | Out-Null
    Write-Output "Succesfully connected to $pViServer"
  }
  catch {
    Write-Output "error connecting to Vcenter  - Force Disconnect"
    Disconnect-VIServer -server $pViServer -Force -Confirm:$false
  }

  $Failed = @()
  $failed
  foreach ($server in $ServerList) {
    Try {
      #FINALY DELETE VmWareSnapshot
      Write-Output "Snapshot deletetion for server $server"
      Get-Snapshot -VM $server -ErrorAction Stop | where-object { $_.Description -match $Description } | Remove-Snapshot -Confirm:$false -ErrorAction Stop | Out-Null 
      Write-Output "Snapshot deleted - $server"
    }
    Catch {
      #Failed Snapshots
      $failed += $server
    }
  }
  if ($Failed) {
    #IF failed snapshots send mail
    $MailBody = ($Failed | Out-String)
    send-mailmessage -to $email -from $from -Subject "Failed Snapshot DELETE" -body $MailBody  -smtpserver $mailsrv  -Encoding $mailencoding
  }   
            
  #DISCONNECT FROM VmWARE
  Disconnect-VIServer -server $pViServer -Force -Confirm:$false
}

So this is semi-automatic patch deployment, but for now is quicker than all manual work. Hope this helps somebody.

Good Luck

Windows 10 start menu search problem

Hi,

when Windows 10 came out, I bravely installed it on my business notebook. It works great, except Start menu search. Everything I searched returned blank. So I got couple of days to check what was going on.
I tried repairing Windows with SFC, I tried turning off Cortana, tamper with registry.. but nothing worked.
Then I suspected the GPO. So, I tested one by one, and finally I got to one where we had all our Internet Explorer settings.
After couple hours of trial and error, I got to conclusion that this two settings enabled Windows 10 start menu search:

Allow Website caches and database must be turned on, and I set it up to 50MB (default is 10)

image

And if pop-up blocker is turned on, change it’s setting to Low: allow pop-ups from secure sites.

image

So this helped for me.

Good Luck

Windows Server NIC address error

We virtualized one of our servers with VMM2012 P2V. Conversion went like a charm, but there was some IP problems.
So, the VMM2012 converted NIC adapters, but he transferred addresses to Hyper-V Virtual Network adapter, because his physical adapters are no longer present.
The server was up and running in virtual environment, but I hade to make some modifications to NIC.
then I received an error:

“The IP address X.X.X.X you have entered for this network adapter is already assigned to another adapter……”

So that means that no longer present adapter has the same address as the new virtual one.
Now, first of all we must go to device manager, but we must be able to see also nonpresnet adapters.
Open CMD as admin on that machine:
set devmgr_show_nonpresnet_devices=1
start devmgmt.msc

On View menu select Show hidden devices.
image

Expand Network adapters, and uninstall old/no presented adapters.

I suggest restart the machine

Good Luck

Uninistall of SC agents from Core OS

I deinstalled VMM 2012 from one server. But its agents remained on my Hyper-V core installation servers. How to uninstall them if no Add/Remove programs exist, or you dont have original agent.msi package?

On Core OS (2008 or 2012) run regedit
Go to HKLM\Software\Microsoft\Windows\Current Version\Uninstall
Expand Uninstall, then search in subfolders for string in DisplayName =”System Center Virtual Machine Manager Agent (x64)”, then you know this is a folder for VMM agent.
Now from that same folder copy entire string (example: MsiExec.exe /I{5142AB0B-73E3-4AD3-9D0F-65B3D9026769}) from UninstallString to CMD window in CoreOS and press Enter.

Good Luck

Windows: RPC server unavailable

Today I had some problem of connecting to some of Windows 7 machines. The error I recieved was: The RPC server is unavailable.
After searching some articles on the net, I found out that I need to enable RemoteAdmin firewall rule, and add DCOM TCP port 135 to Inbound rules.

call netsh firewall set service RemoteAdmin enable
call netsh firewall add portopening protocol=tcp port=135 name=DCOM_TCP135

For port 135 there is a firewall rule Windows Management Instrumentation (DCOM-In) which needs to be enabled.

Good Luck

SRSS – Get list of Reports and Its Data sources and Datasets

I needed to get the list of my reports and what data source and dataset they use.

use ReportServer;
WITH XMLNAMESPACES ( DEFAULT ‘http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition’, ‘http://schemas.microsoft.com/SQLServer/reporting/reportdesigner’ AS rd )
SELECT distinct ReportName = name
,DataSetName = x.value(‘(@Name)[1]’, ‘VARCHAR(250)’)
,DataSourceName = x.value(‘(Query/DataSourceName)[1]’,’VARCHAR(250)’)
,CommandText = x.value(‘(Query/CommandText)[1]’,’VARCHAR(250)’)

FROM ( SELECT C.Name,CONVERT(XML,CONVERT(VARBINARY(MAX),C.Content)) AS reportXML
FROM ReportServer.dbo.Catalog C
WHERE C.Content is not null
AND C.Type = 2
) a
CROSS APPLY reportXML.nodes(‘/Report/DataSets/DataSet’) r ( x )
CROSS APPLY x.nodes(‘Fields/Field’) f(df)
ORDER BY name

image.png

 

 

Good Luck

Enable / Re-enable mount of ISO image in Windows 8

Yesterday I installed CD Burner XP. After that I couldn’t mount ISO images anymore.

image

 

The solution to this problem is in file association.

Right click on ISO file, select properties;

image

 

Choose button change on Opens with:

image

 

From the list, choose Windows Explorer

image

Close properties window, and then try the right click menu on ISO file

image

 

Good Luck

SQL – Linked Server xp_prop_oledb_provider error

 

When you create a Linked Server on SQL Server, some users may get this error:
EXECUTE denied on object ‘xp_prop_oledb_provider’, database ‘mssqlsystemresource’, schema ‘sys’.

image

 

So, the only thing you need (if you have set up your permissions correctly on Linked Server) is to run the following code:

GRANT EXECUTE ON SYS.XP_PROP_OLEDB_PROVIDER TO LOGIN;

If you use domain user, change login to [DOMAIN\username]

 

And this should solve your problem.

 

Good Luck