Friday 4 April 2014

PowerShell - Get list of assemblies across servers, based on filters

This script can interrogate a list of servers for assemblies installed in the GAC, based on a filter or array of filters (using wildcards, if necessary). Returns as an array of objects, so output can be piped to csv using the | export-csv commandlet

NOTE: The script assumes that windows is installed in C:\Windows on each server - you may need to change this in the script i.e.
 
dir "\\$server\c$\windows\assembly\gac_msil"
 
replace with 

dir "\\$server\?$\windowsfolder?\assembly\gac_msil"


Script: check-assemblies.ps1



# Script to get assemblies from servers, and can be filtered for custom assemblies
# Params
# -ServerListFile : File containing a list of server names to check. One line per server. If not specified, local server will be checked
# -filters : filter or array of filters, to filter on dlls to be return. For example, I could use the filters "*chris*.dll","*Lawes*.dll"

param ($ServerListFile, $filters)

# Get server list, depending on params - if not used, just check the local server

if ($ServerListFile){
    $Servers = Get-Content $ServerListFile
}
else{

    $servers = $env:computername
}


foreach($server in $servers)
{
    foreach ($filter in $filters) { 
        dir "\\$server\c$\windows\assembly\gac_msil" -Recurse | where-object {$_.name -ilike $filter} | select @{n="Server";e={$server}}, Name, Length, LastwriteTime , @{n="Environment";e={$Environ}}
    }
} 

SharePoint - Get Office and SP Patches for multiple servers

This script can interrogate a list of servers for Office and SP updates and Patches. Either a comparison can be made from a patch list file, or all patches are returned. They are returns as an array of objects, so output can be piped to csv using the | export-csv commandlet



Script: check-spupdates.ps1


# Script to check registry on multiple servers for Office patches and security updates)
# Params
# -filter : fileter on the registry lookup - normally can be ignored
# -ServerListFile : File containing a list of server names to check. One line per server
# -PatchListFile : List of KB patches - i.e. KB2553345 - one per line. Will return if the patch has been applied or not. If this param is not specified, all SP patches installed on the 
# Server will be returned. This could be used to create a ServerListFile (using just the server name field) if comparison is required for other servers.
# -regpath : The root of the registry where update information is stored - can normally be ignored, as default is set for the param to the correct location
# -Servers : Can be used if a ServerListFile is not used, so we can specifity the servers in the comamnd line. If neither servers or ServerListFile specified, just check local server
# -all : retruns all patches within the S-1-5-18 registry, even if they may not be Office related.


Param($Filter = ".*",$ServerListFile, $PatchListFile, $regpath ="SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products", $servers, [switch]$all)

function Check-RegKeys {
    Param($regkey,$Server)
    $ServerKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine", $Server)
    $SubKey = $ServerKey.OpenSubKey($regkey,$false)
    If(!($SubKey)){Return}
    if ($regkey -ilike "*Patch*"){
        $SubKeyValues = $SubKey.GetValueNames()
        if($SubKeyValues)
        {
            foreach($SubKeyValue in $SubKeyValues)
            {
                $Key = @{n="Key";e={$SubKey.Name -replace
                "HKEY_LOCAL_MACHINE\\",""}}
                $ValueName = @{n="ValueName";e={$SubKeyValue}}
                $Value = @{n="Value";e={$_}}
                $SubKey.GetValue($SubKeyValue) | ?{$_ -match $filter} | Select-Object $ValueName,$Value, @{n="path";e={$subkey.name}}
            }
        }
    }
    $SubKeyName = $SubKey.GetSubKeyNames()
    foreach($subkey in $SubKeyName)
    {
        $SubKeyName = "$regkey\$subkey"
        Check-RegKeys $SubKeyName $server
    }
}

# Get server list, depending on params - if not used, just check the local server
if (!$servers){
    if ($ServerListFile){
        $Servers = Get-Content $ServerListFile
    }
    else{
   
        $servers = $env:computername
    }
}

# Get Patches
if ($PatchListFile){
    try{$Patches = Get-Content $PatchListFile}catch {write-host " - Could not load Patch List File - will return all installed patches instead.."}
    $patches = $null
}

# Cycle through all servers
foreach ($server in $Servers){
    # Create array for results
    $allresults = @()
    write-host "Processing Server: $($server)"
    write-host "   - Getting Registry"
    # Get the registry entries for the patches
    $ServerPatches = Check-RegKeys $regPath $Server
    write-host "   - Obtained Registry"
    # Format the patches so we can get the relevent information    
    $patchraw = $ServerPatches | Where-Object {$_.ValueName -ne "AllPatches"} | group Path
    foreach ($group in $patchraw){
        # Cycle through each patch
        # Create object for results
        $results = "" | Select Server, DisplayName, KB, InstallDate, MoreInfoURL
        # Set data in object from the registry group
        $results.Server = $Server  
        $results.DisplayName = $($group.group | Where-Object{$_.ValueName -eq "DisplayName"}).Value
        $results.InstallDate = ([datetime]::ParseExact($($group.group | Where-Object{$_.ValueName -eq "Installed"}).Value,”yyyyMMdd”,$null)).ToShortDateString()
        $results.MoreInfoURL = $($group.group | Where-Object{$_.ValueName -eq "MoreInfoURL"}).Value
        if ($results.DisplayName -ilike "*kb*"){
            $results.KB =  "KB" + ([regex]::split(($results.DisplayName).ToUpper(), 'KB'))[1].split(")")[0]
        }
        elseif($results.MoreInfoURL -ilike "*/kb/*"){
               $results.KB = "KB" + (($results.MoreInfoURL).split("/"))[-1]
        }

        if ($all){
            $allresults += $results 
        }
        elseif (($results.MoreInfoURL).StartsWith("http://support.microsoft.com") ){
            # Filter out so only relevent patches are returned
            $allresults += $results  
        }
    } 
    #Remove deplicates and sort in KB order
    $allresults = $allresults | Sort-Object -Unique * | Sort-Object KB           
    # Patches specified, so we will test for these in the registry results
    if ($patches){
        foreach ($patch in $Patches){
            write-host "   - testing patch: $patch"
            $patchlookup = $allresults -match $patch
            if (!$Patchlookup){
                $patch | select @{Expression={$server};Name="Server"}, @{Expression={$patch};Name="KB"}, @{Expression={"False"};Name="Applied"}
                
            }
            else{
                $patchlookup | select *,@{Expression={"True"};Name="Applied"}
            }
        }
    }
    else{
        # No patches to test specified so retun all results
        $allresults
    }
}