We’ve worked very hard to automate our environment where I work. As a part of that I’ve wrote a lot of PowerShell functions to perform various actions. I even went so far as to put together a module.
Well, I needed to rewrite this module and improve it, but I’ve had a hard time getting motivated, so I was thinking I would force myself into that by blogging about it. I plan on adding a function at least once a week and building this module up. If you like it, please share with your friends and let me know what you think. Now, to start the module, I’ve rewrote two functions I have put on this blog before, but made a couple of changes.
New-CMNLogEntry – I’ve changed this so that you pass a new parameter, logEntries. If you do not pass this, it will just write-verbose whatever the message is. I did this because I do like to log a lot of things, especially when I’m troubleshooting. So, I figured I would have the function check to see if the entry needed to be written or just written verbose.
Get-CMNSccmConnectionInfo – I’ve made it take advantage of the logEntries feature now in New-CMNLogEntry.
So, without further delay, here is the start of the module. As always, I will have this in my bitbucket repository for your enjoyment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
Function Get-CMNSCCMConnectionInfo { <# .SYNOPSIS Returns a hashtable to containing the SCCMDBServer (Site Database Server), SCCMDB (Site Database), ComputerName (Site Server), SiteCode (Site Code), NameSpace (WMI NameSpace), and WMI Query Paramter hash Table (WMIQueryParameters) .DESCRIPTION This function creates a hashtable with the necessary information used by a variety of my functions. Whenever a function has to talk to an SCCM site, it expects to be passed this hastable so it knows the connection information .PARAMETER SiteServer This is the siteserver for the site you want to connect to. .PARAMETER logFile File for writing logs to. .PARAMETER logEntries Switch to say if we write to the log file. Otherwise, it will just be write-verbose .PARAMETER maxLogSize Specifies, in bytes, how large the file should be before rolling log over. .EXAMPLE Get-CMNSccmConnctionInfo -SiteServer Server01 .LINK http://configman-notes.com .NOTES Author: James Parris Contact: jim@ConfigMan-Notes.com Created: 2016-11-07 Updated: 2018-10-27 Added Comments and adjusted for new logentry function Version: 1.0.0 #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] PARAM( [Parameter(Mandatory = $true, HelpMessage = "Site server where the SMS Provider is installed.", Position = 1)] [ValidateNotNullOrEmpty()] [ValidateScript( {Test-Connection -ComputerName $_ -Count 1 -Quiet})] [string]$siteServer, [Parameter(Mandatory = $false, HelpMessage = 'LogFile Name')] [String]$logFile = 'C:\Temp\Error.log', [Parameter(Mandatory = $false, HelpMessage = 'Log entries')] [Switch]$logEntries, [Parameter(Mandatory = $false, HelpMessage = 'Max Log size')] [Int32]$MaxLogSize = 5242880 ) begin { # Assign a value to logEntries if ($PSBoundParameters['logEntries']) {$logEntries = $true} else {$logEntries = $false} #Build splat for log entries $NewLogEntry = @{ logFile = $logFile; component = 'Get-CMNSCCMConnectionInfo'; logEntries = $logEntries; maxLogSize = $MaxLogSize; } #Write to the log if we're supposed to! New-CMNLogEntry -entry 'Starting Function' -type 1 @NewLogEntry } process { #Get the site code from the site server $siteCode = $(Get-WmiObject -ComputerName $siteServer -Namespace 'root/SMS' -Class SMS_ProviderLocation -ErrorAction SilentlyContinue).SiteCode #if we don't get a result, we have a problem. if (-not($SiteCode)) { New-CMNLogEntry -entry "Unable to connect to Site Server $SiteServer" -type 3 @NewLogEntry throw "Unable to connect to Site Server $siteServer" break } #Now, to determine the SQL Server and database being used for the site. $DataSourceWMI = $(Get-WmiObject -Class SMS_SiteSystemSummarizer -Namespace root/sms/site_$siteCode -ComputerName $siteServer -Filter "Role = 'SMS SQL SERVER' and SiteCode = '$siteCode' and ObjectType = 1").SiteObject $SCCMDBServer = $DataSourceWMI -replace '.*\\\\([A-Z0-9_.]+)\\.*', '$+' $SCCMDB = $DataSourceWMI -replace ".*\\([A-Z_0-9]*?)\\$", '$+' #Now, we've got our data, time to return some results! $ReturnHashTable = @{ SCCMDBServer = $SCCMDBServer; SCCMDB = $SCCMDB; SiteCode = $SiteCode; ComputerName = $SiteServer; NameSpace = "Root/SMS/Site_$siteCode"; WMIQueryParameters = @{ Namespace = "Root/SMS/Site_$siteCode"; ComputerName = $SiteServer; } } #Let's put our TypeName on the results $obj = New-Object -TypeName PSObject -Property $ReturnHashTable $obj.PSObject.TypeNames.Insert(0, 'CMN.SCCMConnectionInfo') #Log if if we're supposed to! New-CMNLogEntry -entry "SCCMDBServer = $SCCMDBServer" -type 1 @NewLogEntry New-CMNLogEntry -entry "SCCMDB = $SCCMDB" -type 1 @NewLogEntry New-CMNLogEntry -entry "SiteCode = $siteCode" -type 1 @NewLogEntry New-CMNLogEntry -entry "ComputerName = $siteServer" -type 1 @NewLogEntry New-CMNLogEntry -entry "NameSpace = Root/SMS/Site_$siteCode" -type 1 @NewLogEntry } end { #Done! Log it! New-CMNLogEntry -entry 'Completing Function' -Type 1 @NewLogEntry Return $obj } } #End Get-CMNSCCMConnectionInfo Function New-CMNLogEntry { <# .SYNOPSIS Writes log entry that can be read by CMTrace.exe .DESCRIPTION If you specify 'logEntries' writes log entries to a file. If the file is larger then MaxFileSize, it will rename it to *yyyymmdd-HHmmss.log and start a new file. You can specify if it's an (1) informational, (2) warning, or (3) error message as well. It will also add time zone information, so if you have machines in multiple time zones, you can convert to UTC and make sure you know exactly when things happened. Will always write the entry verbose for troubleshooting .PARAMETER entry This is the text that is the log entry. .PARAMETER type Defines the type of message, 1 = Informational (default), 2 = Warning, and 3 = Error. .PARAMETER component Specifies the Component information. This could be the name of the function, or thread, or whatever you like, to further help identify what is being logged. .PARAMETER logFile File for writing logs to. .PARAMETER logEntries Switch to say if we write to the log file. Otherwise, it will just be write-verbose .PARAMETER maxLogSize Specifies, in bytes, how large the file should be before rolling log over. .PARAMETER maxLogHistory Specifies the number of history log files to keep, default is 5 .EXAMPLE New-CMNLogEntry -entry "Machine $computerName needs a restart." -type 2 -component 'Installer' -logFile $logFile -logEntries -MaxLogSize 10485760 This will add a warning entry, after expanding $computerName from the compontent Installer to the logfile and roll it over if it exceeds 10MB .LINK http://configman-notes.com .NOTES FileName: Copy-CMNApplicationDeployment.ps1 Author: James Parris Contact: jim@ConfigMan-Notes.com Created: 2016-03-22 Updated: 2017-03-01 - Added log rollover 2018-10-23 - Added Write-Verbose Added adjustment in TimeZond for Daylight Savings Time Corrected time format for renaming logs because I'm an idiot and put 3 digits in the minute field. Version: 2.0 #> [CmdletBinding(ConfirmImpact = 'Low')] Param ( [Parameter(Mandatory = $false, HelpMessage = 'Entry for the log')] [String]$entry = '', [Parameter(Mandatory = $true, HelpMessage = 'Type of message, 1 = Informational, 2 = Warning, 3 = Error')] [ValidateSet(1, 2, 3)] [INT32]$type, [Parameter(Mandatory = $true, HelpMessage = 'Component')] [String]$component, [Parameter(Mandatory = $true, HelpMessage = 'Log File')] [String]$logFile = 'C:\Temp\Error.log', [Parameter(Mandatory = $false, HelpMessage = 'Log entries')] [Switch]$logEntries, [Parameter(Mandatory = $false, HelpMessage = 'Max Log size')] [Int32]$maxLogSize = 5242880, [Parameter(Mandatory = $false, HelpMessage = 'Max number of history logs')] [Int32]$maxLogHistory = 5, [Parameter(Mandatory = $false, HelpMessage = 'Clear existing log?')] [Switch]$clearLog ) #Get Timezone info $now = Get-Date $tzInfo = [System.TimeZoneInfo]::Local #Get Timezone Offset $tzOffset = $tzInfo.BaseUTcOffset.Negate().TotalMinutes #If it's daylight savings time, we need to adjust if ($tzInfo.IsDaylightSavingTime($now)) { $tzAdjust = ((($tzInfo.GetAdjustmentRules()).DaylightDelta).TotalMinutes)[0] $tzOffset -= $tzAdjust } #Now, to figure out the format. if the timezone adjustment is posative, we need to represent it as +### if ($tzOffset -ge 0) {$tzOffset = "$(Get-Date -Format "HH:mm:ss.fff")+$($tzOffset)"} #otherwise, we need to represent it as -### else {$tzOffset = "$(Get-Date -Format "HH:mm:ss.fff")$tzOffset"} #Create entry line, properly formatted $cmEntry = "<![LOG[{0}]LOG]!><time=""{2}"" date=""{1}"" component=""{5}"" context="""" type=""{4}"" thread=""{3}"">" -f $entry, (Get-Date -Format "MM-dd-yyyy"), $tzOffset, $pid, $type, $component if ($PSBoundParameters['logEntries']) { #Now, see if we need to roll the log if (Test-Path $logFile) { #File exists, now to check the size if ((Get-Item -Path $logFile).Length -gt $MaxLogSize) { #Rename file $backupLog = ($logFile -replace '\.log$', '') + "-$(Get-Date -Format "yyyymmdd-HHmmss").log" Rename-Item -Path $logFile -NewName $backupLog -Force #Get filter information #First, we do a regex search, and just get the text before the .log and after the \ $logFile -match '(\w*).log' | Out-Null #Now, we add a trailing * for the filter $logFileName = "$($Matches[1])*" #Get the path for the log so we know where to search $logPath = Split-Path -Path $logFile #And we remove any extra rollover logs. Get-ChildItem -Path $logPath -filter $logFileName | Where-Object {$_.Name -notin (Get-ChildItem -Path $logPath -Filter $logFileName | Sort-Object -Property LastWriteTime -Descending | Select-Object -First $maxLogHistory).name} | Remove-Item } } #Finally, we write the entry $cmEntry | Out-File $logFile -Append -Encoding ascii } #Also, we write verbose, just incase that's turned on. Write-Verbose $entry }#End New-CMNLogEntry Export-ModuleMember -Function Get-CMNSCCMConnectionInfo Export-ModuleMember -Function New-CMNLogEntry |
Hello Jim! Nice script, beautiful formatting.
Thank you! I don’t think I’m very good at keeping up with my blog though! I need to improve!
Nice job!
Thank you sir!