All posts by James

NetScaler PowerShell function to get nsmode “mediaclassification”

In version 11. build 64.34 there is a bug with NetScaler mode “MediaClassification” that can potentially crash a NetScaler appliance if AppFlow is enabled. Additionally, there is a separate bug that enables the “mediaclassification” mode on the NetScaler. This can occur when Insight Center (or a specific Nitro API call) communicates with the NetScaler appliance to add AppFlow policies. This means that if running this particular build, and someone uses Insight Center to create a new policy, it can potentially enable the “mediaclassification” mode, thus potentially causing the NetScaler appliance to encounter the bug with said mode, and ultimately crash the appliance. I have seen this real world, and it can put an HA pair into an infinite boot loop. Be warned, HA will not save the day with this particular issue. The bug specifically crashes a NetScaler when “mediaclassification” is enabled, and the NetScaler receives a http request that does not contain a host header (HTTP 1.0 anyone?). The workaround for this is to disable the mode. However, as previously mentioned, a seperate bug can and will re-enable this mode. So here is a PowerShell Script to check the mode on NetScaler(s) and send an SMTP message if the mode is discovered to be enabled. This could be modified to suit other alert\notification needs as well.

 

 


Function Get-NSmode
{
Param
(
[array]$nsip

)

# Choose protocol for contacting the NetScaler, http:// or https://
$nsprotocol = "http://"
# NetScaler account authorized to a least show ns mode. Recommend full read only account for ease of use.
$nsuser = "ns_read_only_account"
# Password for account defined in $nsuser
$nspass = "SomeCrazyPasswordForReadOnlyServiceAccount" | ConvertTo-SecureString -asPlainText -Force
# SMTP server address
$psemailserver = "mymail.local.com"
# Mail to address
$mailto = "NetScalerGuy@local.com"
# Mail from address
$mailfrom = "NetScalerMaintenanceScript@local.com"
# Do not modify unless you know what you are doing
$cred = New-Object System.Management.Automation.PSCredential($nsuser,$nspass)

### MAIN ###

if (Invoke-RestMethod -Method GET -Credential $cred -Uri ($nsprotocol + $nsip + "/nitro/v1/config/nsmode") | ?{$_.nsmode -lik e "*MediaClassification=False*"}) {$mediaclassification = $false}
else {
$report = Invoke-RestMethod -Method GET -Credential $cred -Uri ($nsprotocol + $nsip + "/nitro/v1/config/nsmode") | select -Exp andProperty nsmode | select mediaclassification
$body = ("MediaClassification Mode is enabled on $nsip. This mode can cause the NetScaler to crash. Investigate if this was
intentional.
$report
"
)
Send-MailMessage -smtpserver $psemailserver -to "$mailto" -from $mailfrom -Subject "*** NetScaler $nsip MediaClassification Mode Enabled ***" -body $body }

}

Get-NSmode NetScaler1.local.com
Get-NSmode NetScaler2.local.com
Get-NSmode NetScaler3.local.com
Get-NSmode NetScaler4.local.com

###  END   ###

This script is best run as a scheduled task. Leave your comments below.

Thanks

Get-ApplockerReport (Function)

Here is another time saver I use almost daily. You can enter a servername here, and answer the how many days question to get a nice list of applocker logs. This is very useful to quickly see if something is being blocked.

Function Get-AppLockerReport
{
        param
                (
        [array]$ServerNames
                )
        $TimeInput = Read-Host "Enter number of days to query logs"
        $AppLockerServers = $ServerNames
        $StartTime = (Get-Date).AddDays(-$TimeInput)

        Foreach ($AppLockerServer in $AppLockerServers)
                {
                $AppLockerServer
                Get-WinEvent -filterhashtable @{LogName="Microsoft-Windows-AppLocker/EXE and DLL";
                StartTime=$StartTime} -Computername $AppLockerServer | Where-Object {$_.LevelDisplayName -eq "Error"} | group-object message -noelement | Format-List
                }
}

Set-ScomMaint

Here is a little function I put together to QUICKLY be able to place servers in SCOM maintenance. For anyone who uses the GUI to do this, you know it can get a little clunky. This saves me loads of time. I sourced some of the parts of this script from various sites that I no longer remember. Please forgive not giving credit to those particular sections.

You must change the following variables to entries from your environment.
$ManServer = “Man.Server.FQDN”
$domain = “domain.FQDN.com”


<#
    .SYNOPSIS
        The Set-SCOMMaint function places a server or servers in
                maintenance mode programatically.
    .DESCRIPTION
        This function will place a server or servers in maintenance
                mode programitically with little to no error checking.
                The management server is hard coded into this version of the
                function.
    .PARAMETER  computers
        computers is used to define which servers to enter into maintenance.
                a single machine name can be entered, or a comma seperated value of
                machine names can be entered.
    .PARAMETER  minutes
        minutes is used to define the amount of time in minutes to set maintenance mode for.
    .EXAMPLE
        Set-SCOMMaint -computername bobsPC -minutes 10
    .EXAMPLE
        Set-SCOMMaint -computername bobsPC,BillsPC,BensPC -minutes 240
    .version beta
                First release.  Feature add to come.  Stay tuned.
#>



Function Get-LocalTime($UTCTime)
{
$strCurrentTimeZone = (Get-WmiObject win32_timezone).StandardName
$TZ = [System.TimeZoneInfo]::FindSystemTimeZoneById($strCurrentTimeZone)
$LocalTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($UTCTime, $TZ)
Return $LocalTime
}



Function Set-SCOMMaint
{
        Param
        (
        [array]$computers,
        [string]$minutes
        )

# Defining global variables
$ManServer = "server.fqdn.jameier.com"
$domain = "jameier.com"
$class = "Microsoft.Windows.Computer"
$comment = 'Scheduled Maintenance'

# Adding temporary Environment variable
$p = [Environment]::GetEnvironmentVariable(“PSModulePath”)
$p += “;C:\Program Files\System Center 2012\Operations Manager\Powershell\”
[Environment]::SetEnvironmentVariable(“PSModulePath”,$p)

# Importing necessary modules
Import-Module OperationsManager

# Connect to management server, and get\set times
New-SCOMManagementGroupConnection $ManServer
$class = Get-SCOMClass -Name $class
$startTime = [System.DateTime]::Now.ToUniversalTime()
$endTime = [System.DateTime]::Now.AddMinutes($minutes).ToUniversalTime()

# Begin loop
foreach ($computer in $Computers) {
 $instance = Get-SCOMClassInstance -Class $class | ? { $_.Name -eq ($computer + "." + $domain) }
 Write-Host -foregroundcolor yellow Attempting to place $computer into maintenance mode for $minutes minutes
 $instance.ScheduleMaintenanceMode($startTime, $endTime, "PlannedApplicationMaintenance", $comment , "Recursive")
 $InMaint = Get-SCOMMaintenanceMode -Instance $Instance
 $InMaintLocalTime = Get-LocalTime($InMaint.ScheduledEndTime)
 Write-Host -foregroundcolor Green $computer entered into maintenance mode until $InMaintLocalTime
 Start-Sleep -s 1
}
}

Get-DuplicateItems (by MD5 Checksum)

Here is a very useful script I use to remove duplicate items.

Sourced from http://blogs.msdn.com/powershell/archive/2006/04/25/583225.aspx

#requires -version 3
[CmdletBinding()]
param (
[string]
$Path
)

function Get-MD5 {
param (
[Parameter(Mandatory)]
[string]
$Path
)
# This Get-MD5 function sourced from:
# http://blogs.msdn.com/powershell/archive/2006/04/25/583225.aspx
$HashAlgorithm = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$Stream = [System.IO.File]::OpenRead($Path)
try {
$HashByteArray = $HashAlgorithm.ComputeHash($Stream)
} finally {
$Stream.Dispose()
}

return [System.BitConverter]::ToString($HashByteArray).ToLowerInvariant() -replace '-',''
}

if (-not $Path) {
if ((Get-Location).Provider.Name -ne 'FileSystem') {
Write-Error 'Specify a file system path explicitly, or change the current location to a file system path.'
return
}
$Path = (Get-Location).ProviderPath
}

Get-ChildItem -Path $Path -Recurse -File |
Where-Object { $_.Length -gt 0 } |
Group-Object -Property Length |
Where-Object { $_.Count -gt 1 } |
ForEach-Object {
$_.Group |
ForEach-Object {
$_ |
Add-Member -MemberType NoteProperty -Name ContentHash -Value (Get-MD5 -Path $_.FullName)
}

$_.Group |
Group-Object -Property ContentHash |
Where-Object { $_.Count -gt 1 }
}

Once you have the output of the script you could use it to delete the unnecessary files: $dupes = .\Get-DuplicateItems.ps1 $dupes | % { ($null, $rest) = $_.Group; $rest } | Remove-Item -WhatIf

Create RDS directories (Scheduled Task)

This script is intended to query AD for a list of users (samaccountname). The returned list will be matched against a path to check\create user profile directories for 2008 and up domains. This script only checks for the existence of the directory, and creates it if it does not exist.


$List = Get-ADUser -Filter * -SearchBase "ou=something,dc=jameier,dc=com" | select samaccountname

$Users = $List.samaccountname

#$Users = "username"

foreach ($user in $users) {

$exist = test-path ("\\some\path\to\RDS\" + $user + ".V2")
if ($exist -match $true) {
write-host -foregroundcolor Green ("$user already has a V2 profile directory")
}

else {
new-item -itemtype directory -path ("\\some\path\to\RDS\" + $user + ".V2") # Set path of roaming.V2 profile

$objUser = New-Object System.Security.Principal.NTAccount("corp\$user")
$objACE = New-Object System.Security.AccessControl.FileSystemAccessRule($objUser,"FullControl","3","None","Allow")

$objACL = Get-ACL ("\\some\path\to\RDS\" + $user + ".V2") # Set path for ACL
$objACL.AddAccessRule($objACE)

Set-ACL ("\\some\path\to\RDS" + $user + ".V2") $objACL # Set path to modify ACL
}
}

Powershell Get Custom Event Logs Function

Did you ever wish there was a fast and efficient way to retrieve event logs from a remote machine?  Enter Get-CustomEventLogs function.  Below is a simple function that allows you to quickly query a remote machine by name, logname, and timeframe (0-744 hours which is 31 days).  The results will be returned to the console.  This function can be piped to other outputs as well.  Try Get-CustomEventsLogs | Out-GridView for a quick way to scroll through events.

Function Get-CustomEventsLogs
{
Param
(
[string]$server
,
[string]$logname
,
[ValidateRange(0,744)]
$StartTime
)
$logtime = (Get-Date) - (New-TimeSpan -Hours $StartTime)
Get-WinEvent -filterhashtable @{LogName=$logname; StartTime=$logtime} -Computername $Server | where {$_.TimeCreated -ge $logtime} | select message,id,recordid,providername,logname,machinename,userid,timecreated,containerlog,leveldisplayname
}