Private/Functions.ps1
<#
.SYNOPSIS Another stupid custom log writing function #> Function Write-Log { param ( [String] $Message, [int] $Severity = 1, [string] $LogFile = '', [bool] $ShowMsg = $true ) $TimeZoneBias = Get-WmiObject -Query "Select Bias from Win32_TimeZone" $Date = Get-Date -Format "HH:mm:ss.fff" $Date2 = Get-Date -Format "MM-dd-yyyy" if (($logfile -ne $null) -and ($logfile -ne '')) { "<![LOG[$Message]LOG]!><time=`"$date+$($TimeZoneBias.Bias)`" date=`"$date2`" component=`"$component`" context=`"`" type=`"$severity`" thread=`"`" file=`"`">" | Out-File -FilePath $logfile -Append -NoClobber -Encoding Default } if ($showmsg -eq $true) { switch ($severity) { 3 { Write-Host $Message -ForegroundColor Red } 2 { Write-Host $Message -ForegroundColor Yellow } 1 { Write-Host $Message } } } } function Test-Powershell64bit { Write-Output ([IntPtr]::size -eq 8) } Function Test-Folder { param ( [String] $Path, [bool] $Create = $true ) if (Test-Path -Path $Path) { return $true } elseif ($Create -eq $true) { try { New-Item ($Path) -Type Directory -Force | Out-Null Write-Output $true } catch { Write-Output $false } } else { Write-Output $false } } Function Test-RegistryExist { param ( $ComputerName, $LogFile = '' , $KeyName, $AccessType = 'LocalMachine' ) Write-Verbose "Testing registry key from $($ComputerName), $($AccessType), $($KeyName)" try { $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($AccessType, $ComputerName) $RegKey = $Reg.OpenSubKey($KeyName) $return = ($RegKey -ne $null) } catch { $return = "ERROR: Unknown" $Error.Clear() } Write-Output $return } function Test-Admin { $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() $principal = New-Object System.Security.Principal.WindowsPrincipal($identity) $admin = [System.Security.Principal.WindowsBuiltInRole]::Administrator $principal.IsInRole($admin) } function Get-XmlUrlContent { param ( [parameter(Mandatory=$True, HelpMessage="Target URL")] [ValidateNotNullOrEmpty()] [string] $Url ) Write-Verbose "reading data from remote file: $Url" $content = "" try { $content = Invoke-WebRequest -Uri $Url -ErrorAction Stop } catch {} if ($content -ne "") { $lines = $content -split "`n" $result = "" for ($i = 1; $i -lt $lines.count; $i++) { $result += $lines[$i] + "`n" } } Write-Output $result } function Set-ReplaceString { param ( [string] $Value, [string] $SiteCode, [int] $NumberOfDays = "", [string] $ServerName = "", [bool] $Space = $true ) $return = $value $date = Get-Date if ($space) { $return = $return -replace "\r\n", " " $return = $return -replace "\r", " " $return = $return -replace "\n", " " $return = $return -replace "\s", " " $return = $return -replace "\s{2}\b"," " } $return = $return -replace "@@SITECODE@@",$SiteCode $return = $return -replace "@@STARTMONTH@@",$date.ToString("01/MM/yyyy") $return = $return -replace "@@TODAYMORNING@@",$date.ToString("yyyy/MM/dd") $return = $return -replace "@@NUMBEROFDAYS@@",$NumberOfDays $return = $return -replace "@@SERVERNAME@@",$ServerName if ($space) { while (($return.IndexOf(" ") -ge 0)) { $return = $return -replace " ", " " } } Write-Output $return } Function Get-RegistryValue { param ( [String] $ComputerName, [string] $LogFile = '' , [string] $KeyName, [string] $KeyValue, [string] $AccessType = 'LocalMachine' ) Write-Verbose "Getting registry value from $($ComputerName), $($AccessType), $($keyname), $($keyvalue)" try { $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($AccessType, $ComputerName) $RegKey= $Reg.OpenSubKey($keyname) if ($RegKey -ne $null) { try { $return = $RegKey.GetValue($keyvalue) } catch { $return = $null } } else { $return = $null } Write-Verbose "Value returned $return" } catch { $return = "ERROR: Unknown" $Error.Clear() } Write-Output $return } Function ReportSection { param ( $HealthCheckXML, $Section, $SqlConn, [string] $SiteCode, $NumberOfDays, [string] $LogFile, [string] $ServerName, $ReportTable, [switch] $Detailed ) Write-Verbose "[function: ReportSection]" if ($Detailed) { Write-Verbose "[detailed = True]" Write-Verbose "-----------------------------------------------------------" Write-Verbose "**** Starting Section $Section with [Detailed] = $($detailed.ToString())" Write-Verbose "-----------------------------------------------------------" } foreach ($healthCheck in $HealthCheckXML.dtsHealthCheck.HealthCheck) { if ($healthCheck.IsTextOnly.ToLower() -eq 'true') { continue } if ($healthCheck.IsActive.ToLower() -ne 'true') { continue } if ($healthCheck.Section.ToLower() -ne $Section) { continue } $sqlquery = $healthCheck.SqlQuery $tablename = (Set-ReplaceString -Value $healthCheck.XMLFile -SiteCode $SiteCode -NumberOfDays $NumberOfDays -ServerName $servername) $xmlTableName = $healthCheck.XMLFile if ($Section -eq 5) { if (!($Detailed)) { $tablename += "summary" $xmlTableName += "summary" $gbfiels = "" foreach ($field in $healthCheck.Fields.Field) { if ($field.groupby -in ("2")) { if ($gbfiels.Length -gt 0) { $gbfiels += "," } $gbfiels += $field.FieldName } } $sqlquery = "select $($gbfiels), count(1) as Total from ($($sqlquery)) tbl group by $($gbfiels)" } else { $tablename += "detail" $xmlTableName += "detail" $sqlquery = $sqlquery -replace "select distinct", "select" $sqlquery = $sqlquery -replace "select", "select distinct" } } $filename = $reportFolder + $tablename + '.xml' $row = $ReportTable.NewRow() $row.TableName = $xmlTableName $row.XMLFile = $tablename + ".xml" $ReportTable.Rows.Add($row) Write-Verbose ("XMLfile... $filename") Write-Verbose ("Section... $Section") Write-Verbose ("Table..... $TableName - Information...Starting") Write-Verbose ("Type...... $($healthCheck.querytype)") try { switch ($healthCheck.querytype.ToLower()) { 'mpconnectivity' { Write-MPConnectivity -FileName $filename -TableName $tablename -sitecode $SiteCode -SiteCodeQuery $SiteCodeQuery -NumberOfDays $NumberOfDays -logfile $logfile -type 'mplist' | Out-Null} 'mpcertconnectivity' { Write-MPConnectivity -FileName $filename -TableName $tablename -sitecode $SiteCode -SiteCodeQuery $SiteCodeQuery -NumberOfDays $NumberOfDays -logfile $logfile -type 'mpcert' | Out-Null} 'sql' { Get-SQLData -sqlConn $sqlConn -SQLQuery $sqlquery -FileName $fileName -TableName $tablename -siteCode $siteCode -NumberOfDays $NumberOfDays -servername $servername -healthcheck $healthCheck -logfile $logfile -section $section -detailed $detailed | Out-Null} 'baseosinfo' { Write-BaseOSInfo -FileName $filename -TableName $tablename -sitecode $SiteCode -NumberOfDays $NumberOfDays -servername $servername -logfile $logfile -continueonerror $true | Out-Null} 'diskinfo' { Write-DiskInfo -FileName $filename -TableName $tablename -sitecode $SiteCode -NumberOfDays $NumberOfDays -servername $servername -logfile $logfile -continueonerror $true | Out-Null} 'networkinfo' { Write-NetworkInfo -FileName $filename -TableName $tablename -sitecode $SiteCode -NumberOfDays $NumberOfDays -servername $servername -logfile $logfile -continueonerror $true | Out-Null} 'rolesinstalled' { Write-RolesInstalled -FileName $filename -TableName $tablename -sitecode $SiteCode -NumberOfDays $NumberOfDays -servername $servername -logfile $logfile | Out-Null} 'servicestatus' { Write-ServiceStatus -FileName $filename -TableName $tablename -sitecode $SiteCode -NumberOfDays $NumberOfDays -servername $servername -logfile $logfile -continueonerror $true | Out-Null} 'hotfixstatus' { if (-not $NoHotfix) { Write-HotfixStatus -FileName $filename -TableName $tablename -sitecode $SiteCode -NumberOfDays $NumberOfDays -servername $servername -logfile $logfile -continueonerror $true | Out-Null } } default {} } } catch { $errorMessage = $Error[0].Exception.Message $errorCode = "0x{0:X}" -f $Error[0].Exception.ErrorCode Write-Verbose "ERROR/EXCEPTION: The following error occurred..." Write-Verbose "Error $errorCode : $errorMessage connecting to $servername" $Error.Clear() } Write-Verbose ("$tablename Information...Done") } Write-Verbose "End Section $section" } Function Set-FormatedValue { param ( $Value, [string] $Format, [string] $SiteCode ) Write-Verbose "[function: Set-FormatedValue]" Write-Verbose " [format = $Format]" Write-Verbose " [sitecode = $SiteCode]" if ($Value -eq $null) { Write-Verbose " [value = NULL]" } else { Write-Verbose " [value = $Value]" } switch ($format.ToLower()) { 'schedule' { $schedule_Class = [wmiclass]"" $schedule_class.psbase.path = "\\$($smsprovider)\root\sms\site_$($SiteCodeNamespace):SMS_ScheduleMethods" $schedule = ($schedule_class.ReadFromString($value)).TokenData if ($schedule.DaySpan -ne 0) { $return = ($schedule.DaySpan * 24 * 60) } elseif ($schedule.HourSpan -ne 0) { $return = ($schedule.HourSpan * 60) } elseif ($schedule.MinuteSpan -ne 0) { $return = ($schedule.MinuteSpan) } return $return break } 'alertsname' { if ($value -eq $null) { $return = '' } else { switch ($value.ToString().ToLower()) { '$databasefreespacewarning' { $return = 'Low free space alert for database on site' break } '$sumcompliance2updategroupdeploymentname' { $return = 'Low deployment success rate alert of update group' break } default { $return = $value break } } } return $return break } 'alertsseverity' { if ($value -eq $null) { $return = '' } else { switch ($value.ToString().ToLower()) { '1' { $return = 'Error' break } '2' { $return = 'Warning' break } '3' { $return = 'Informational' break } default { $return = 'Unknown' break } } } return $return break } 'alertstypeid' { switch ($value.ToString().ToLower()) { '12' { $return = 'Update group deployment success' break } '25' { $return = 'Database free space warning' break } '31' { $return = 'Malware detection' break } default { $return = $value break } } Write-Output $return break } 'messagesolution' { Write-Verbose "[messagesolution] convert to string" if ($value -ne $null) { $return = $value.ToString() } Write-Output $return break } default { Write-Output $value break } } } Function Get-SQLData { param ( [parameter(Mandatory=$True)] $sqlConn, [parameter(Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] $SQLQuery, [parameter(Mandatory=$False)] [string] $FileName, [parameter(Mandatory=$False)] [string] $TableName, [parameter(Mandatory=$False)] [string] $SiteCode, [parameter(Mandatory=$False)] $NumberOfDays, [parameter(Mandatory=$False)] $LogFile, [parameter(Mandatory=$False)] [string] $ServerName, [parameter(Mandatory=$False)] [bool] $ContinueOnError = $true, [parameter(Mandatory=$False)] $HealthCheck, [parameter(Mandatory=$False)] $Section, [parameter(Mandatory=$False)] [switch] $Detailed ) Write-Verbose "[function: Get-SQLData]" if ($Detailed) { Write-Verbose " [detailed = True]" } try { $SqlCommand = $sqlConn.CreateCommand() $logQuery = Set-ReplaceString -value $SQLQuery -SiteCode $SiteCode -NumberOfDays $NumberOfDays -ServerName $ServerName $executionquery = Set-ReplaceString -value $SQLQuery -SiteCode $SiteCode -NumberOfDays $NumberOfDays -ServerName $ServerName -space $false Write-Verbose "SQL Query...`n$executionquery" Write-Verbose "Log Query...`n$logQuery" $SqlCommand.CommandTimeOut = 0 $SqlCommand.CommandText = $executionquery $DataAdapter = New-Object System.Data.SqlClient.SqlDataAdapter $SqlCommand $dataset = New-Object System.Data.Dataset $DataAdapter.Fill($dataset) if (($dataset.Tables.Count -eq 0) -or ($dataset.Tables[0].Rows.Count -eq 0)) { Write-Verbose "SQL Query returned 0 records" Write-Verbose "Table $tablename is empty. No file output to $filename ..." } else { Write-Verbose "SQL Query returned $($dataset.Tables[0].Rows.Count) records" foreach ($field in $healthCheck.Fields.Field) { Write-Verbose (" field = $($Field.FieldName) description = $($Field.Description)") if ($section -eq 5) { if (($detailed) -and ($field.groupby -notin ('1','2'))) { continue } elseif (($detailed -eq $false) -and ($field.groupby -notin ('2','3'))) { continue } } if ($field.format -ne "") { Write-Verbose " custom format specified for this attribute: $($Field.Format)" foreach ($row in $dataset.Tables[0].Rows) { #$fn = $field.FieldName $tempx = Set-FormatedValue -Value $row.$($field.FieldName) -Format $field.format -SiteCode $SiteCode try { $row.$($field.FieldName) = $tempx } catch { $row break } } } } Write-Verbose "Export: Exporting xml data to $filename" , $dataset.Tables[0] | Export-CliXml -Path $filename } } catch { $errorMessage = $Error[0].Exception.Message $errorCode = "0x{0:X}" -f $Error[0].Exception.ErrorCode if ($continueonerror -eq $false) { Write-Verbose "ERROR/EXCEPTION: The following error occurred (stop)." } else { Write-Verbose "ERROR/EXCEPTION: The following error occurred (continue)." } Write-Verbose "Error $errorCode : $errorMessage connecting to $ServerName" $Error.Clear() Write-Verbose "Unable to update file: $filename" if ($continueonerror -eq $false) { Throw "Error $errorCode : $errorMessage connecting to $ServerName" } } } function New-CmDataTable { param ( [string] $TableName, [String[]] $Fields ) Write-Verbose "[function: New-CmDataTable]" $DataTable = New-Object System.Data.DataTable "$tableName" foreach ($field in $fields) { $col = New-Object System.Data.DataColumn "$field",([string]) $DataTable.Columns.Add($col) } ,$DataTable } Function Write-BaseOSInfo { param ( [string] $FileName, [string] $TableName, [string] $SiteCode, [int] $NumberOfDays, [string] $LogFile, [string] $ServerName, [bool] $ContinueOnError = $true ) Write-Verbose "[function: write-baseosinfo]" $WMIOS = Get-CmWmiObject -Class "win32_operatingsystem" -ComputerName $servername -LogFile $logfile -ContinueOnError $continueonerror if ($WMIOS -eq $null) { return } $WMICS = Get-CmWmiObject -Class "win32_computersystem" -ComputerName $servername -LogFile $logfile -ContinueOnError $continueonerror $WMIProcessor = Get-CmWmiObject -Class "Win32_processor" -ComputerName $servername -LogFile $logfile -ContinueOnError $continueonerror $WMITimeZone = Get-CmWmiObject -Class "Win32_TimeZone" -ComputerName $servername -LogFile $logfile -ContinueOnError $continueonerror ##AV Information $avInformation = $null $AVArray = @("McAfee Security@McShield", "Symantec Endpoint Protection@symantec antivirus", "Sophos Antivirus@savservice", "Avast!@aveservice", "Avast!@avast! antivirus", "Immunet Protect@immunetprotect", "F-Secure@fsma", "AntiVir@antivirservice", "Avira@avguard", "F-Protect@fpavserver", "Panda Security@pshost", "Panda AntiVirus@pavsrv", "BitDefender@bdss", "ArcaBit/ArcaVir@abmainsv", "IKARUS@ikarus-guardx", "ESET Smart Security@ekrn", "G Data Antivirus@avkproxy", "Kaspersky Lab Antivirus@klblmain", "Symantec VirusBlast@vbservprof", "ClamAV@clamav", "Vipre / GFI managed AV@SBAMSvc", "Norton@navapsvc", "Kaspersky@AVP", "Windows Defender@windefend", "Windows Defender/@MsMpSvc", "Microsoft Security Essentials@msmpeng") foreach ($av in $AVArray) { $info = $av.Split("@") if ((Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $info[1]).ToString().Tolower().Indexof("error") -lt 0) { $avInformation = $info[0] break } } $OSProcessorArch = $WMIOS.OSArchitecture if ($OSProcessorArch -ne $null) { switch ($OSProcessorArch.ToUpper() ) { "AMD64" {$ProcessorArchDisplay = "64-bit"} "i386" {$ProcessorArchDisplay = "32-bit"} "IA64" {$ProcessorArchDisplay = "64-bit - Itanium"} default {$ProcessorArchDisplay = $OSProcessorArch } } } else { $ProcessorArchDisplay = "" } $LastBootUpTime = $WMIOS.ConvertToDateTime($WMIOS.LastBootUpTime) $LocalDateTime = $WMIOS.ConvertToDateTime($WMIOS.LocalDateTime) $numProcs = 0 $ProcessorType = "" $ProcessorName = "" $ProcessorDisplayName= "" foreach ($WMIProc in $WMIProcessor) { $ProcessorType = $WMIProc.Manufacturer switch ($WMIProc.NumberOfCores) { 1 {$numberOfCores = "single core"} 2 {$numberOfCores = "dual core"} 4 {$numberOfCores = "quad core"} $null {$numberOfCores = "single core"} default { $numberOfCores = $WMIProc.NumberOfCores.ToString() + " core" } } switch ($WMIProc.Architecture) { 0 {$CpuArchitecture = "x86"} 1 {$CpuArchitecture = "MIPS"} 2 {$CpuArchitecture = "Alpha"} 3 {$CpuArchitecture = "PowerPC"} 6 {$CpuArchitecture = "Itanium"} 9 {$CpuArchitecture = "x64"} } if ($ProcessorDisplayName.Length -eq 0) { $ProcessorDisplayName = " " + $numberOfCores + " $CpuArchitecture processor " + $WMIProc.Name } else { if ($ProcessorName -ne $WMIProc.Name) { $ProcessorDisplayName += "/ " + " " + $numberOfCores + " $CpuArchitecture processor " + $WMIProc.Name } } $numProcs += 1 $ProcessorName = $WMIProc.name } $ProcessorDisplayName = "$numProcs" + $ProcessorDisplayName if ($WMICS.DomainRole -ne $null) { switch ($WMICS.DomainRole) { 0 {$RoleDisplay = "Workstation"} 1 {$RoleDisplay = "Member Workstation"} 2 {$RoleDisplay = "Standalone Server"} 3 {$RoleDisplay = "Member Server"} 4 {$RoleDisplay = "Backup Domain Controller"} 5 {$RoleDisplay = "Primary Domain controller"} default: {$RoleDisplay = "unknown, $($WMICS.DomainRole)"} } } $Fields = @("ComputerName","OperatingSystem","ServicePack","Version","Architecture","LastBootTime","CurrentTime","TotalPhysicalMemory","FreePhysicalMemory","TimeZone","DaylightInEffect","Domain","Role","Model","NumberOfProcessors","NumberOfLogicalProcessors","Processors","AntiMalware") $BaseOSInfoTable = New-CmDataTable -TableName $tableName -Fields $Fields $row = $BaseOSInfoTable.NewRow() $row.ComputerName = $ServerName $row.OperatingSystem = $WMIOS.Caption $row.ServicePack = $WMIOS.CSDVersion $row.Version = $WMIOS.Version $row.Architecture = $ProcessorArchDisplay $row.LastBootTime = $LastBootUpTime.ToString() $row.CurrentTime = $LocalDateTime.ToString() $row.TotalPhysicalMemory = ([string]([math]::Round($($WMIOS.TotalVisibleMemorySize/1MB), 2)) + " GB") $row.FreePhysicalMemory = ([string]([math]::Round($($WMIOS.FreePhysicalMemory/1MB), 2)) + " GB") $row.TimeZone = $WMITimeZone.Description $row.DaylightInEffect = $WMICS.DaylightInEffect $row.Domain = $WMICS.Domain $row.Role = $RoleDisplay $row.Model = $WMICS.Model $row.NumberOfProcessors = $WMICS.NumberOfProcessors $row.NumberOfLogicalProcessors = $WMICS.NumberOfLogicalProcessors $row.Processors = $ProcessorDisplayName if ($avInformation -ne $null) { $row.AntiMalware = $avInformation } else { $row.AntiMalware = "Antimalware software not detected" } $BaseOSInfoTable.Rows.Add($row) , $BaseOSInfoTable | Export-CliXml -Path ($filename) } Function Write-DiskInfo { param ( [string] $FileName, [string] $TableName, [string] $SiteCode, [int] $NumberOfDays, [string] $LogFile, [string] $ServerName, [bool] $ContinueOnError = $true ) Write-Verbose "[function: write-diskinfo]" $DiskList = Get-CmWmiObject -Class "Win32_LogicalDisk" -Filter "DriveType = 3" -ComputerName $servername -LogFile $logfile -ContinueOnError $continueonerror if ($DiskList -eq $null) { return } $Fields=@("DeviceID","Size","FreeSpace","FileSystem") $DiskDetails = New-CmDataTable -TableName $tableName -Fields $Fields foreach ($Disk in $DiskList) { $row = $DiskDetails.NewRow() $row.DeviceID = $Disk.DeviceID $row.Size = ([int](($Disk.Size) / 1024 / 1024 / 1024)).ToString() $row.FreeSpace = ([int](($Disk.FreeSpace) / 1024 / 1024 / 1024)).ToString() $row.FileSystem = $Disk.FileSystem $DiskDetails.Rows.Add($row) } , $DiskDetails | Export-CliXml -Path ($filename) } function Write-NetworkInfo { param ( [string] $FileName, [string] $TableName, [string] $SiteCode, [int] $NumberOfDays, [string] $LogFile, [string] $ServerName, [bool] $ContinueOnError = $true ) Write-Verbose "[function: write-networkinfo]" $IPDetails = Get-CmWmiObject -Class "Win32_NetworkAdapterConfiguration" -Filter "IPEnabled = true" -ComputerName $servername -logfile $logfile -continueonerror $continueonerror if ($IPDetails -eq $null) { return } $Fields = @("IPAddress","DefaultIPGateway","IPSubnet","MACAddress","DHCPEnabled") $NetworkInfoTable = New-CmDataTable -TableName $tableName -Fields $Fields foreach ($IPAddress in $IPDetails) { $row = $NetworkInfoTable.NewRow() $row.IPAddress = ($IPAddress.IPAddress -join ", ") $row.DefaultIPGateway = ($IPAddress.DefaultIPGateway -join ", ") $row.IPSubnet = ($IPAddress.IPSubnet -join ", ") $row.MACAddress = $IPAddress.MACAddress if ($IPAddress.DHCPEnable -eq $true) { $row.DHCPEnabled = "TRUE" } else { $row.DHCPEnabled = "FALSE" } $NetworkInfoTable.Rows.Add($row) } , $NetworkInfoTable | Export-CliXml -Path ($filename) } function Write-RolesInstalled { param ( [string] $FileName, [string] $TableName, [string] $SiteCode, [int] $NumberOfDays, [string] $LogfFle, [string] $ServerName, [bool] $ContinueOnError = $true ) Write-Verbose "[function: write-rolesinstalled]" $WMISMSListRoles = Get-CmWmiObject -Query "select distinct RoleName from SMS_SCI_SysResUse where NetworkOSPath = '\\\\$Servername'" -computerName $smsprovider -namespace "root\sms\site_$SiteCodeNamespace" -logfile $logfile $SMSListRoles = @() foreach ($WMIServer in $WMISMSListRoles) { $SMSListRoles += $WMIServer.RoleName } $DPProperties = Get-CmWmiObject -Query "select * from SMS_SCI_SysResUse where RoleName = 'SMS Distribution Point' and NetworkOSPath = '\\\\$Servername' and SiteCode = '$SiteCode'" -computerName $smsprovider -namespace "root\sms\site_$SiteCodeNamespace" -logfile $logfile $Fields = @("SiteServer", "IIS", "SQLServer", "DP", "PXE", "MultiCast", "PreStaged", "MP", "FSP", "SSRS", "EP", "SUP", "AI", "AWS", "PWS", "SMP", "Console", "Client", "CPC", "DWP", "DMP") $RolesInstalledTable = New-CmDataTable -TableName $tableName -Fields $Fields $row = $RolesInstalledTable.NewRow() $row.SiteServer = ($SMSListRoles -contains 'SMS Site Server').ToString() $row.SQLServer = ($SMSListRoles -contains 'SMS SQL Server').ToString() $row.DP = ($SMSListRoles -contains 'SMS Distribution Point').ToString() if ($DPProperties -eq $null) { $row.PXE = "False" $row.MultiCast = "False" $row.PreStaged = "False" } else { $row.PXE = (($DPProperties.Props | Where-Object {$_.PropertyName -eq "IsPXE"}).Value -eq 1).ToString() $row.MultiCast = (($DPProperties.Props | Where-Object {$_.PropertyName -eq "IsMulticast"}).Value -eq 1).ToString() $row.PreStaged = (($DPProperties.Props | Where-Object {$_.PropertyName -eq "PreStagingAllowed"}).Value -eq 1).ToString() } $row.MP = ($SMSListRoles -contains 'SMS Management Point').ToString() $row.FSP = ($SMSListRoles -contains 'SMS Fallback Status Point').ToString() $row.SSRS = ($SMSListRoles -contains 'SMS SRS Reporting Point').ToString() $row.EP = ($SMSListRoles -contains 'SMS Endpoint Protection Point').ToString() $row.SUP = ($SMSListRoles -contains 'SMS Software Update Point').ToString() $row.AI = ($SMSListRoles -contains 'AI Update Service Point').ToString() $row.AWS = ($SMSListRoles -contains 'SMS Application Web Service').ToString() $row.PWS = ($SMSListRoles -contains 'SMS Portal Web Site').ToString() $row.SMP = ($SMSListRoles -contains 'SMS State Migration Point').ToString() # added in 0.64 $row.CPC = ($SMSListRoles -contains 'SMS Cloud Proxy Connector').ToString() $row.DWP = ($SMSListRoles -contains 'Data Warehouse Service Point').ToString() $row.DMP = ($SMSListRoles -contains 'SMS Dmp Connector').ToString() # other roles as of build 1702 <# SMS Device Management Point SMS System Health Validator SMS Multicast Service Point SMS AMT Service Point SMS Enrollment Server SMS Enrollment Web Site SMS Notification Server SMS Certificate Registration Point SMS DM Enrollment Service #> $row.Console = (Test-RegistryExist -ComputerName $servername -Logfile $logfile -KeyName 'SOFTWARE\\Wow6432Node\\Microsoft\\ConfigMgr10\\AdminUI').ToString() $row.Client = (Test-RegistryExist -ComputerName $servername -Logfile $logfile -KeyName 'SOFTWARE\\Microsoft\\CCM\\CCMExec').ToString() $row.IIS = ((Get-RegistryValue -ComputerName $server -Logfile $logfile -KeyName 'SOFTWARE\\Microsoft\\InetStp' -KeyValue 'InstallPath') -ne $null).ToString() $RolesInstalledTable.Rows.Add($row) , $RolesInstalledTable | Export-Clixml -Path ($filename) } Function Get-ServiceStatus { param ( $LogFile, [string] $ServerName, [string] $ServiceName ) Write-Verbose "[function: get-servicestatus]" Write-Verbose " servername = $servername / servicename = $servicename" try { $service = Get-Service -ComputerName $servername | Where-Object {$_.Name -eq $servicename} if ($service -ne $null) { $return = $service.Status } else { $return = "ERROR: Not Found" } Write-Verbose "Service status $return" } catch { $return = "ERROR: Unknown" $Error.Clear() } Write-Output $return } function Write-MPConnectivity { param ( [string] $FileName, [string] $TableName, [string] $SiteCode, [int] $NumberOfDays, $LogFile, [string] $Type = 'mplist' ) Write-Verbose "[function: write-mpconnectivity]" $Fields = @("ServerName", "HTTPReturn") $MPConnectivityTable = New-CmDataTable -TableName $tableName -Fields $Fields $MPList = Get-CmWmiObject -query "select * from SMS_SCI_SysResUse where SiteCode = '$SiteCode' and RoleName = 'SMS Management Point'" -computerName $smsprovider -namespace "root\sms\site_$SiteCodeNamespace" -logfile $logfile foreach ($MPInformation in $MPList) { $SSLState = ($MPInformation.Props | Where-Object {$_.PropertyName -eq "SslState"}).Value $mpname = $MPInformation.NetworkOSPath -replace '\\', '' if ($SSLState -eq 0) { $protocol = 'http' $port = $HTTPport } else { $protocol = 'https' $port = $HTTPSport } $web = New-Object -ComObject msxml2.xmlhttp $url = $protocol + '://' + $mpname + ':' + $port + '/sms_mp/.sms_aut?' + $type if ($healthcheckdebug) { Write-Verbose ("URL Connection: $url") } $row = $MPConnectivityTable.NewRow() $row.ServerName = $mpname try { $web.open('GET', $url, $false) $web.send() $row.HTTPReturn = $web.status } catch { $row.HTTPReturn = "313 - Unable to connect to host" $Error.Clear() } Write-Verbose " Status: $($web.status)" $MPConnectivityTable.Rows.Add($row) } , $MPConnectivityTable | Export-CliXml -Path ($filename) } Function Write-HotfixStatus { param ( [string] $FileName, [string] $TableName, [string] $SiteCode, [int] $NumberOfDays, $LogFile, [string] $ServerName, $ContinueOnError = $true ) Write-Verbose "[function: write-hotfixstatus]" try { $Session = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.Session", $ServerName)) $Searcher = $Session.CreateUpdateSearcher() $historyCount = $Searcher.GetTotalHistoryCount() $return = $Searcher.QueryHistory(0, $historyCount) Write-Verbose " Hotfix count: $HistoryCount" } catch { $errorMessage = $Error[0].Exception.Message $errorCode = "0x{0:X}" -f $Error[0].Exception.ErrorCode Write-Verbose " The following error happen" Write-Verbose " Error $errorCode : $errorMessage connecting to $ServerName" $Error.Clear() return } $Fields = @("Title", "Date") $HotfixTable = New-CmDataTable -tablename $tableName -fields $Fields foreach ($hotfix in $return) { $row = $HotfixTable.NewRow() $row.Title = $hotfix.Title $row.Date = $hotfix.Date $HotfixTable.Rows.Add($row) } , $HotfixTable | Export-CliXml -Path ($filename) } function Write-ServiceStatus { param ( [string] $FileName, [string] $TableName, [string] $SiteCode, [int] $NumberOfDays, $LogFile, [string] $ServerName, $ContinueOnError = $true ) Write-Verbose "[function: write-servicestatus]" $SiteInformation = Get-CmWmiObject -query "select Type from SMS_Site where ServerName = '$Server'" -namespace "Root\SMS\Site_$SiteCodeNamespace" -computerName $smsprovider -logfile $logfile if ($SiteInformation -ne $null) { $SiteType = $SiteInformation.Type } $WMISMSListRoles = Get-CmWmiObject -query "select distinct RoleName from SMS_SCI_SysResUse where NetworkOSPath = '\\\\$Server'" -computerName $smsprovider -namespace "root\sms\site_$SiteCodeNamespace" -logfile $logfile $SMSListRoles = @() foreach ($WMIServer in $WMISMSListRoles) { $SMSListRoles += $WMIServer.RoleName } Write-Verbose "Roles discovered: " + $SMSListRoles -join(", ") $Fields = @("ServiceName", "Status") $ServicesTable = New-CmDataTable -TableName $tableName -Fields $Fields if ($SMSListRoles -contains 'AI Update Service Point') { $row = $ServicesTable.NewRow() $row.ServiceName = "AI_UPDATE_SERVICE_POINT" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) } if (($SMSListRoles -contains 'SMS Application Web Service') -or ($SMSListRoles -contains 'SMS Distribution Point') -or ($SMSListRoles -contains 'SMS Fallback Status Point') -or ($SMSListRoles -contains 'SMS Management Point') -or ($SMSListRoles -contains 'SMS Portal Web Site') ) { $row = $ServicesTable.NewRow() $row.ServiceName = "IISADMIN" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) $row = $ServicesTable.NewRow() $row.ServiceName = "W3SVC" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) } if ($SMSListRoles -contains 'SMS Component Server') { $row = $ServicesTable.NewRow() $row.ServiceName = "SMS_Executive" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) } if ($SMSListRoles -contains 'SMS Site Server') { $row = $ServicesTable.NewRow() $row.ServiceName = "SMS_NOTIFICATION_SERVER" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) $row = $ServicesTable.NewRow() $row.ServiceName = "SMS_SITE_COMPONENT_MANAGER" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) if ($SiteType -ne 1) { $row = $ServicesTable.NewRow() $row.ServiceName = "SMS_SITE_VSS_WRITER" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) } } if ($SMSListRoles -contains 'SMS Software Update Point') { $row = $ServicesTable.NewRow() $row.ServiceName = "WsusService" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) } if ($SMSListRoles -contains 'SMS SQL Server') { $row = $ServicesTable.NewRow() if ($SiteType -ne 1) { $row.ServiceName = "$SQLServiceName" } else { $row.ServiceName = 'MSSQL$CONFIGMGRSEC' } $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) $row = $ServicesTable.NewRow() $row.ServiceName = "SQLWriter" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) } if ($SMSListRoles -contains 'SMS SRS Reporting Point') { $row = $ServicesTable.NewRow() $row.ServiceName = "ReportServer" $row.Status = (Get-ServiceStatus -LogFile $logfile -ServerName $servername -ServiceName $row.ServiceName) $ServicesTable.Rows.Add($row) } , $ServicesTable | Export-CliXml -Path ($filename) } function Get-CmCredentials { try { $cred = Get-Credentials Write-Verbose " Trying username: $($cred.Username)" Write-Output $cred } catch { Write-Output $null } } function Get-CmWmiObject { param ( $Class, $Filter = '', $Query = '', $ComputerName, $Namespace = "root\cimv2", $LogFile, [bool] $ContinueOnError = $false ) if ($query -ne '') { $class = $query } Write-Verbose " WMI Query: \\$ComputerName\$Namespace, $class, filter: $filter" if ($query -ne '') { $WMIObject = Get-WmiObject -Query $query -Namespace $Namespace -ComputerName $ComputerName -ErrorAction SilentlyContinue } elseif ($filter -ne '') { $WMIObject = Get-WmiObject -Class $class -Filter $filter -Namespace $Namespace -ComputerName $ComputerName -ErrorAction SilentlyContinue } else { $WMIObject = Get-WmiObject -Class $class -NameSpace $Namespace -ComputerName $ComputerName -ErrorAction SilentlyContinue } if ($WMIObject -eq $null) { Write-Verbose " WMI Query returned 0) records" } else { $i = 1 foreach ($obj in $wmiobj) { i++ } Write-Verbose " WMI Query returned $($i) records" } if ($Error.Count -ne 0) { $errorMessage = $Error[0].Exception.Message $errorCode = "0x{0:X}" -f $Error[0].Exception.ErrorCode if ($ContinueOnError -eq $false) { Write-Error " The following error occurred, no futher action taken" } else { Write-Error "The following error occurred" } Write-Verbose " Error $errorCode : $errorMessage connecting to $ComputerName" $Error.Clear() if ($ContinueOnError -eq $false) { Throw "Error $errorCode : $errorMessage connecting to $ComputerName" } } Write-Output $WMIObject } Function Get-SQLServerConnection { param ( [parameter(Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] $SQLServer, [parameter(Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] $DBName ) Try { $conn = New-Object System.Data.SqlClient.SqlConnection $conn.ConnectionString = "Data Source=$SQLServer;Initial Catalog=$DBName;Integrated Security=SSPI;" return $conn } Catch { $errorMessage = $_.Exception.Message $errorCode = "0x{0:X}" -f $_.Exception.ErrorCode Write-Verbose "The following error happen, no futher action taken" Write-Verbose "Error $errorCode : $errorMessage connecting to $SQLServer" $Error.Clear() Throw "Error $errorCode : $errorMessage connecting to $SQLServer" } } #---------------------------------- function Get-MessageInformation { param ( $MessageID ) $msg = $MessagesXML.dtsHealthCheck.Message | Where-Object {$_.MessageId -eq $MessageID} if ($msg -eq $null) { Write-Output "Unknown Message ID $MessageID" } else { Write-Output $msg.Description } } function Get-MessageSolution { param ( $MessageID ) $msg = $MessagesXML.dtsHealthCheck.MessageSolution | Where-Object {$_.MessageId -eq $MessageID} if ($msg -eq $null) { Write-Output "There is no known possible solution for Message ID $MessageID" } else { Write-Output $msg.Description } } function Write-WordText { param ( $WordSelection, [string] $Text = "", [string] $Style = "No Spacing", $Bold = $false, $NewLine = $false, $NewPage = $false ) $texttowrite = "" $wordselection.Style = $Style if ($bold) { $wordselection.Font.Bold = 1 } else { $wordselection.Font.Bold = 0 } $texttowrite += $text $wordselection.TypeText($text) If ($newline) { $wordselection.TypeParagraph() } If ($newpage) { $wordselection.InsertNewPage() } } Function Set-WordDocumentProperty { param ( $Document, $Name, $Value ) Write-Verbose "info: document property [$Name] set to [$Value]" $document.BuiltInDocumentProperties($Name) = $Value } Function Write-WordReportSection { param ( $HealthCheckXML, $Section, $Detailed = $false, $Doc, $Selection, $LogFile ) Write-Log -Message "Starting Section $section with detailed as $($detailed.ToString())" -LogFile $logfile foreach ($healthCheck in $HealthCheckXML.dtsHealthCheck.HealthCheck) { if ($healthCheck.Section.tolower() -ne $Section) { continue } $Description = $healthCheck.Description -replace("@@NumberOfDays@@", $NumberOfDays) if ($healthCheck.IsActive.tolower() -ne 'true') { continue } if ($healthCheck.IsTextOnly.tolower() -eq 'true') { if ($Section -eq 5) { if ($detailed -eq $false) { $Description += " - Overview" } else { $Description += " - Detailed" } } Write-WordText -WordSelection $selection -Text $Description -Style $healthCheck.WordStyle -NewLine $true Continue; } Write-WordText -WordSelection $selection -Text $Description -Style $healthCheck.WordStyle -NewLine $true $bFound = $false $tableName = $healthCheck.XMLFile if ($Section -eq 5) { if (!($detailed)) { $tablename += "summary" } else { $tablename += "detail" } } foreach ($rp in $ReportTable) { if ($rp.TableName -eq $tableName) { $bFound = $true Write-Log -Message (" - Exporting $($rp.XMLFile) ...") -LogFile $logfile $filename = $rp.XMLFile if ($filename.IndexOf("_") -gt 0) { $xmltitle = $filename.Substring(0,$filename.IndexOf("_")) $xmltile = ($rp.TableName.Substring(0,$rp.TableName.IndexOf("_")).Replace("@","")).Tolower() switch ($xmltile) { "sitecode" { $xmltile = "Site Code: "; break; } "servername" { $xmltile = "Server Name: "; break; } } switch ($healthCheck.WordStyle) { "Heading 1" { $newstyle = "Heading 2"; break; } "Heading 2" { $newstyle = "Heading 3"; break; } "Heading 3" { $newstyle = "Heading 4"; break; } default { $newstyle = $healthCheck.WordStyle; break } } $xmltile += $filename.Substring(0,$filename.IndexOf("_")) Write-WordText -WordSelection $selection -Text $xmltile -Style $newstyle -NewLine $true } if (!(Test-Path ($reportFolder + $rp.XMLFile))) { Write-WordText -WordSelection $selection -Text $healthCheck.EmptyText -NewLine $true Write-Log -Message ("Table does not exist") -LogFile $logfile -Severity 2 $selection.TypeParagraph() } else { Write-Verbose "importing XML file: $filename" $datatable = Import-CliXml -Path ($reportFolder + $filename) $count = 0 $datatable | Where-Object { $count++ } if ($count -eq 0) { Write-WordText -WordSelection $selection -Text $healthCheck.EmptyText -NewLine $true Write-Log -Message ("Table: 0 rows") -LogFile $logfile -Severity 2 $selection.TypeParagraph() continue } switch ($healthCheck.PrintType.ToLower()) { "table" { Write-Verbose "writing table type: table" $Table = $Null $TableRange = $Null $TableRange = $doc.Application.Selection.Range $Columns = 0 foreach ($field in $HealthCheck.Fields.Field) { if ($section -eq 5) { if (($detailed) -and ($field.groupby -notin ('1','2'))) { continue } elseif ((!($detailed)) -and ($field.groupby -notin ('2','3'))) { continue } } $Columns++ } $Table = $doc.Tables.Add($TableRange, $count+1, $Columns) $table.Style = $TableStyle $i = 1; Write-Log -Message ("Table: $count rows and $Columns columns") -LogFile $logfile foreach ($field in $HealthCheck.Fields.Field) { if ($section -eq 5) { if (($detailed) -and ($field.groupby -notin ('1','2'))) { continue } elseif ((!($detailed)) -and ($field.groupby -notin ('2','3'))) { continue } } $Table.Cell(1, $i).Range.Font.Bold = $True $Table.Cell(1, $i).Range.Text = $field.Description $i++ } $xRow = 2 $records = 1 $y=0 foreach ($row in $datatable) { if ($records -ge 500) { Write-Log -Message ("Exported $(500*($y+1)) records") -LogFile $logfile $records = 1 $y++ } $i = 1; foreach ($field in $HealthCheck.Fields.Field) { if ($section -eq 5) { if (($detailed) -and ($field.groupby -notin ('1','2'))) { continue } elseif ((!($detailed)) -and ($field.groupby -notin ('2','3'))) { continue } } $Table.Cell($xRow, $i).Range.Font.Bold = $false $TextToWord = ""; switch ($field.Format.ToLower()) { "message" { $TextToWord = Get-MessageInformation -MessageID ($row.$($field.FieldName)) break ; } "messagesolution" { $TextToWord = Get-MessageSolution -MessageID ($row.$($field.FieldName)) break ; } default { $TextToWord = $row.$($field.FieldName); break; } } if ([string]::IsNullOrEmpty($TextToWord)) { $TextToWord = " " } $Table.Cell($xRow, $i).Range.Text = $TextToWord.ToString() $i++ } $xRow++ $records++ } $selection.EndOf(15) | Out-Null $selection.MoveDown() | Out-Null $doc.ActiveWindow.ActivePane.view.SeekView = 0 $selection.EndKey(6, 0) | Out-Null $selection.TypeParagraph() break } "simpletable" { Write-Verbose "writing table type: simpletable" $Table = $Null $TableRange = $Null $TableRange = $doc.Application.Selection.Range $Columns = 0 foreach ($field in $HealthCheck.Fields.Field) { if ($section -eq 5) { if (($detailed) -and ($field.groupby -notin ('1','2'))) { continue } elseif ((!($detailed)) -and ($field.groupby -notin ('2','3'))) { continue } } $Columns++ } $Table = $doc.Tables.Add($TableRange, $Columns, 2) $table.Style = $TableSimpleStyle $i = 1; Write-Log -Message ("Table: $Columns rows and 2 columns") -LogFile $logfile $records = 1 $y=0 foreach ($field in $HealthCheck.Fields.Field) { if ($section -eq 5) { if (($detailed) -and ($field.groupby -notin ('1','2'))) { continue } elseif ((!($detailed)) -and ($field.groupby -notin ('2','3'))) { continue } } if ($records -ge 500) { Write-Log -Message ("Exported $(500*($y+1)) records") -LogFile $logfile $records = 1 $y++ } $Table.Cell($i, 1).Range.Font.Bold = $true $Table.Cell($i, 1).Range.Text = $field.Description $Table.Cell($i, 2).Range.Font.Bold = $false if ($poshversion -ne 3) { $TextToWord = ""; switch ($field.Format.ToLower()) { "message" { $TextToWord = Get-MessageInformation -MessageID ($datatable.Rows[0].$($field.FieldName)) break ; } "messagesolution" { $TextToWord = Get-MessageSolution -MessageID ($datatable.Rows[0].$($field.FieldName)) break ; } default { $TextToWord = $datatable.Rows[0].$($field.FieldName) break; } } if ([string]::IsNullOrEmpty($TextToWord)) { $TextToWord = " " } $Table.Cell($i, 2).Range.Text = $TextToWord.ToString() } else { $TextToWord = ""; switch ($field.Format.ToLower()) { "message" { $TextToWord = Get-MessageInformation -MessageID ($datatable.$($field.FieldName)) break ; } "messagesolution" { $TextToWord = Get-MessageSolution -MessageID ($datatable.$($field.FieldName)) break ; } default { $TextToWord = $datatable.$($field.FieldName) break; } } if ([string]::IsNullOrEmpty($TextToWord)) { $TextToWord = " " } $Table.Cell($i, 2).Range.Text = $TextToWord.ToString() } $i++ $records++ } $selection.EndOf(15) | Out-Null $selection.MoveDown() | Out-Null $doc.ActiveWindow.ActivePane.View.SeekView = 0 $selection.EndKey(6, 0) | Out-Null $selection.TypeParagraph() break break } default { Write-Verbose "writing table type: default" $records = 1 $y=0 foreach ($row in $datatable) { if ($records -ge 500) { Write-Log -Message ("Exported $(500*($y+1)) records") -LogFile $logfile $records = 1 $y++ } foreach ($field in $HealthCheck.Fields.Field) { $TextToWord = ""; switch ($field.Format.ToLower()) { "message" { $TextToWord = ($field.Description + " : " + (Get-MessageInformation -MessageID ($row.$($field.FieldName)))) break ; } "messagesolution" { $TextToWord = ($field.Description + " : " + (Get-MessageSolution -MessageID ($row.$($field.FieldName)))) break ; } default { $TextToWord = ($field.Description + " : " + $row.$($field.FieldName)) break; } } if ([string]::IsNullOrEmpty($TextToWord)) { $TextToWord = " " } Write-WordText -WordSelection $selection -Text ($TextToWord.ToString()) -NewLine $true } $selection.TypeParagraph() $records++ } } } } } } if ($bFound -eq $false) { Write-WordText -WordSelection $selection -Text $healthCheck.EmptyText -NewLine $true Write-Log -Message ("Table does not exist") -LogFile $logfile -Severity 2 $selection.TypeParagraph() } } } <# function Write-RevisionTable (){ Write-Verbose "inserting revision history table" $Table = $Null $TableRange = $Null $TableRange = $selection.Range $Table = $doc.Tables.Add($TableRange, 4, 4) $Table.Style = $TableStyle for ($i -eq 1; $i -le 4; $i++) { $Table.Cell($i, 1).Range.Font.Bold = $True $Table.Cell($i, 2).Range.Font.Bold = $False } $Table.Cell(1, 1).Range.Text = "Version" $Table.Cell(1, 2).Range.Text = "Date" $Table.Cell(1, 3).Range.Text = "Description" $Table.Cell(1, 4).Range.Text = "Author" $Table.Cell(2, 1).Range.Text = "1.0" $Table.Cell(2, 2).Range.Text = $(Get-Date).ToShortDateString() $Table.Cell(2, 3).Range.Text = "Initial release" $Table.Cell(2, 4).Range.Text = $($AuthorName -split " " | ForEach-Object {$_.Substring(0,1)}) -join "" $selection.EndOf(15) | Out-Null $selection.MoveDown() | Out-Null $doc.ActiveWindow.ActivePane.view.SeekView = 0 $selection.EndKey(6, 0) | Out-Null $selection.TypeParagraph() } #> function Write-WordTableGrid { param ( [parameter(Mandatory=$True)] [string] $Caption, [parameter(Mandatory=$True)] [int] $Rows, [parameter(Mandatory=$True)] [string[]] $ColumnHeadings ) Write-Verbose "inserting custom table: $Caption" $Selection.TypeText($Caption) $Selection.Style = "Heading 1" $Selection.TypeParagraph() $Cols = $ColumnHeadings.Length $Table = $doc.Tables.Add($Selection.Range, $rows, $cols) $Table.Style = "Grid Table 4 - Accent 1" for ($col = 1; $col -le $cols; $col++) { $Table.Cell(1, $col).Range.Text = $ColumnHeadings[$col-1] } for ($row = 1; $row -lt $rows; $row++) { $Table.Cell($row+1, 1).Range.Text = $row.ToString() } # set table width to 100% $Table.PreferredWidthType = 2 $Table.PreferredWidth = 100 # set column widths if ($cols -gt 2) { $Table.Columns(2).PreferredWidthType = 2 $Table.Columns(2).PreferredWIdth = 7 } else { $Table.Columns.First.PreferredWidthType = 2 $Table.Columns.First.PreferredWidth = 7 } $Selection.EndOf(15) | Out-Null $Selection.MoveDown() | Out-Null $doc.ActiveWindow.ActivePane.view.SeekView = 0 $Selection.EndKey(6, 0) | Out-Null $Selection.TypeParagraph() } <# .SYNOPSIS Get-CmSiteInstallPath returns [string] path to the base installation of System Center Configuration Manager on the site server. .DESCRIPTION Returns the full SCCM installation path using a registry query. #> function Get-CmSiteInstallPath { try { $x = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\SMS\setup" Write-Output $x.'Installation Directory' } catch {} } |