CPolydorou.IIS.psm1
#region Functions #region Get-WebConnections function Get-WebConnections { Param ( [Parameter(Mandatory = $false, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $false, Position = 0)] [string]$WebSite, [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [string[]]$ComputerName = $env:COMPUTERNAME ) Begin{} Process { foreach($c in $ComputerName) { $results = @() $perfmon = new-object System.Diagnostics.PerformanceCounter $perfmon.CategoryName = "Web Service" $perfmon.CounterName = "Current Connections" $perfmon.MachineName = $c $cat = new-object System.Diagnostics.PerformanceCounterCategory("Web Service") $instances = $cat.GetInstanceNames() foreach ($instance in $instances) { if(-not ([String]::IsNullOrEmpty($WebSite))) { if($WebSite -ne $instance) { continue } } $perfmon.InstanceName = $instance $obj = New-Object psobject $obj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $c $obj | Add-Member -MemberType NoteProperty -Name WebSite -Value $instance $connections = -1 try { $connections = $perfmon.NextValue() } catch { } $obj | Add-Member -MemberType NoteProperty -Name Connections -Value $connections $results += $obj } write-output $results } } End{} } #endregion #region Restart-IISApplicationPool Function Restart-IISApplicationPool { [cmdletBinding()] Param ( [Parameter(Mandatory = $false, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias("Name")] [string[]]$ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory = $true, Position = 1)] [string[]]$AppPool ) Begin {} Process { foreach($s in $ComputerName) { Write-Verbose ("Processing server: " + $s) Invoke-Command -ComputerName $s ` -ScriptBlock { [cmdletBinding()] Param ( [string[]]$ApplicationPoolNames ) # Import the web administration module Import-Module WebAdministration # Restart the application pool $VerbosePreference = $using:VerbosePreference foreach($ap in $ApplicationPoolNames) { Write-Verbose ("`tRestarting application pool: " + $ap) Restart-WebAppPool -Name $ap } } -ArgumentList (,$AppPool) -Verbose } } End {} } #endregion #region Get-IISApplicationPool function Get-IISApplicationPool { [cmdletBinding()] Param ( [Parameter(Mandatory = $false, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias("Name")] [string[]]$ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory = $false, Position = 1)] [string[]]$AppPool ) Begin {} Process { foreach($s in $ComputerName) { Write-Verbose ("Processing server: " + $s) $pools = Invoke-Command -ComputerName $s ` -ScriptBlock { [cmdletBinding()] Param ( [string[]]$ApplicationPoolNames ) # Import the web administration module Import-Module WebAdministration # Restart the application pool $VerbosePreference = $using:VerbosePreference Get-ChildItem -Path IIS:\AppPools } -Verbose | Select-Object -Property @{Name="Name"; Expression={$_.Name}}, ` @{Name="State"; Expression={$_.State}}, ` @{Name="ComputerName"; Expression = {$_.PSComputerName}}, ` @{Name="WorkerProcesses"; Expression={$_.WorkerProcesses.Collection.ProcessID -join ","}} if($AppPool) { foreach($ap in $AppPool) { $pools | Where-Object {$_.Name -like $ap} } } else { $pools } } } End {} } #endregion #region Get-IISApplicationPoolWorkerProcesses function Get-IISApplicationPoolWorkerProcesses { [cmdletBinding()] Param ( [Parameter(Mandatory = $false, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias("Name")] [string[]]$ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory = $false, Position = 1)] [string[]]$AppPool ) Begin {} Process { foreach($s in $ComputerName) { Write-Verbose ("Processing server: " + $s) $workerProcesses = Invoke-Command -ComputerName $s ` -ScriptBlock { [cmdletBinding()] Param ( [string[]]$ApplicationPoolNames ) # Import the web administration module Import-Module WebAdministration # Restart the application pool $VerbosePreference = $using:VerbosePreference Get-ChildItem -Path IIS:\AppPools | %{ $appPool = $_.Name Get-ChildItem -Path ("IIS:\AppPools\" + $_.Name + "\WorkerProcesses") | Select-Object -Property @{Name="AppPool"; Expression={$appPool}},ProcessID,State,Handles,StartTime } } -Verbose | Select-Object -Property @{Name="AppPool"; Expression={$_.AppPool}}, ` @{Name="ComputerName"; Expression = {$_.PSComputerName}}, ` @{Name="ProcessID"; Expression={$_.processid}}, ` @{Name="State"; Expression={$_.state}}, ` @{Name="Handles"; Expression={$_.handles}}, ` @{Name="StartTime"; Expression={$_.starttime}} if($AppPool) { foreach($ap in $AppPool) { $workerProcesses | Where-Object {$_.AppPool -like $ap} } } else { $workerProcesses } } } End {} } #endregion #region Search-IISSiteLog workflow Search-IISSiteLog { <# .Synopsis Parse log files. .DESCRIPTION Parse log files in folder or using the web site name. .EXAMPLE Search the log files for site "Default Web Site" of local server for pattern "401" Search-IISSiteLog -WebSite "Default Web Site" -Pattern "401" .EXAMPLE Search the files under the "c:\inetpub\logs\LogFiles\W3SVC1" of the local server for lines that match the pattern "404" Search-IISSiteLog -Path "c:\inetpub\logs\LogFiles\W3SVC1" -Pattern "404" .EXAMPLE Search the files in directory "c:\inetpub\logs\LogFiles\W3SVC1" that are last changed between 12/31/2017 and 7/1/2018 on webservers "webserver1" and "webserver2" for the regex pattern "40" Search-IISSiteLog -ComputerName webserver1,webserver2 -Path "c:\inetpub\logs\LogFiles\W3SVC1" -Pattern "40" -End "12/31/2017" -Start "7/1/2017" .NOTES This workflow requires remote PowerShell access to the servers and in case the website name is used, the WebAdministration module has to be available on the servers. .FUNCTIONALITY Log file parser. #> #region Parameters [CmdletBinding(DefaultParameterSetName='Parameter Set Website', ConfirmImpact='Low')] Param ( # The web server [Parameter(Mandatory=$false, Position=0, ParameterSetName='Parameter Set Website')] [Parameter(Mandatory=$false, Position=0, ParameterSetName='Parameter Set Folder')] [Alias("Server")] [string[]] $ComputerName, # The web site [Parameter(Mandatory=$false, Position=1, ParameterSetName='Parameter Set Website')] [string[]] $WebSite, # The folder [Parameter(Mandatory=$false, Position=1, ParameterSetName='Parameter Set Folder')] [string] $Path, # The expression to match against [Parameter(Mandatory=$false, Position=2, ParameterSetName='Parameter Set Website')] [Parameter(Mandatory=$false, Position=2, ParameterSetName='Parameter Set Folder')] [string] $Pattern, # The start time [Parameter(Mandatory=$false, Position=3, ParameterSetName='Parameter Set Website')] [Parameter(Mandatory=$false, Position=3, ParameterSetName='Parameter Set Folder')] [DateTime] $Start, # The end time [Parameter(Mandatory=$false, Position=4, ParameterSetName='Parameter Set Website')] [Parameter(Mandatory=$false, Position=4, ParameterSetName='Parameter Set Folder')] [DateTime] $End ) #endregion #region configuration # Set the default value for the computername if(-not $ComputerName) { $ComputerName = $env:COMPUTERNAME } #endregion #region Permission Level # Check if the workflow was executed under administrator level permissions if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` [Security.Principal.WindowsBuiltInRole] "Administrator")) { Write-Error "This cmdlet has to be executed with administrator rights." return } #endregion #region Set the mode of operation if($Path) { $mode = "Path" $location = $Path } else { $mode = "Site" $location = $WebSite } #endregion #region Create the configuration # A hashtable is created in order to be passed as a variable to the scriptblock $configuration = @{ Mode = $mode Location = $location Match = $Pattern Start = $Start End = $End } #endregion #region Process servers foreach -parallel ($c in $ComputerName) { Write-Verbose "Processing logs on server $c" inlineScript { Invoke-Command -ComputerName $using:c ` -ScriptBlock { # The scriptblock paramters Param($config) # Create a variable to hold the files to be processed $files = New-Object -TypeName System.Collections.ArrayList #region Get the files to process # Deferentiate uppon mode if($config.Mode -eq "Path") { # Get the files in the directory and add them to the collection Get-ChildItem -Path $config.Location -Force -File | %{ $files.Add($_) | Out-Null } } if($config.Mode -eq "Site") { # Load the IIS module Import-Module webadministration # Get the website Write-Warning "afsdf" $site = Get-Website | Where-Object {$_.Name -eq $config.Location} # Get the path to the log files if($site) { # Get the path $logPath = [System.Environment]::ExpandEnvironmentVariables($site.logFile.directory) + "\w3svc" + $site.id # Get the files Get-ChildItem -Path $logPath -Force -File | %{ $files.Add($_) | Out-Null } } else { continue } } #endregion # Create the RegEx object $regex = New-Object -TypeName system.text.regularexpressions.regex $config.Match #region Process the files foreach($f in $files) { # Exclude files older than start time if($config.Start -ne [DateTime]::MinValue) { if($f.LastWriteTime -le $config.Start) { continue } } # Exclude files newer than end date if($config.End -ne [DateTime]::MinValue) { if($f.LastWriteTime -ge [DateTime]$config.End) { continue } } # Get the content of each file $content = Get-Content -Path $f.Fullname foreach($line in $content) { #region Pattern # Check if pattern is specified if($Config.Match -ne $null) { # Move to the next line if not matched if( -not $regex.IsMatch($line)) { continue } } #endregion # Create the custom object $props = [ordered]@{ ComputerName = $env:COMPUTERNAME File = $f Entry = $line } New-Object -TypeName PSObject -Property $props } } #endregion } ` -ArgumentList $using:configuration } } #endregion } #endregion #endregion |