Categories
Uncategorized

Maths Challenge

#ref: https://ironscripter.us/another-powershell-math-challenge/
<#
Intermediate Level
Given a value like this:

$i = 2568
What is the total sum of all the individual integers? That is to say

2+5+6+8
Write a function that will accept a value and return the sum.

Bonus Elements
Limit the length of the number to 10 digits
Include Verbose output to show the operation
Write a variation on the function that writes an object to the pipeline that shows the original number, the number of individual elements and the sum.
#>
Function Calculation2 {
    param (
       $InPutNumber

    )
    if($InPutNumber.GetType().Name -like '*Int*' ){

#Turn on Verbose    
$VerbosePreference = "continue"
$DigitLenghtLimit = 11
$MaxNumber = $DigitLenghtLimit - 1
$TotalNumbers = ($InputNumber.ToString() | Measure-Object -Character).Characters
If($TotalNumbers -lt $DigitLenghtLimit){
    
    $Calculation = $null
    $i = 0
    while($i -lt $TotalNumbers){
        $PreviousCalc = $Calculation
        $Calculation = $Calculation + [int](($InputNumber.ToString())[$i]).ToString()

     if($i -eq 0){

     }#If $i is zero do nada
     else{
    $PreviousNumber = [int](($InputNumber.ToString())[($i -1)]).ToString()
    $Number = [int](($InputNumber.ToString())[$i]).ToString()
    Write-Verbose "$PreviousCalc + $Number = $Calculation"
     }#else continue



        $i ++
    }
    $Calculation
    ############Variation #################
###### to write an object to the pipeline which shows the original number, the number of individual elements and the sum
foreach($char in ($InputNumber.ToString()).ToCharArray()){
    $FormatChar = $char + "+"
        $Sum += $FormatChar
    
    }#FE Character create Sum output
    $Sum = $Sum.TrimEnd("+")
    
    
    New-Object psobject -Property @{
        "Original Number"     = $InPutNumber
        "Number of Elements"  = $TotalNumbers
        "Sum"         = $Sum
            
    }#New PSOBJECT
    ############Variation #################
}

else{
   Write-Output "$InputNumber has $TotalNumbers Digits. Max is $MaxNumber " 
}
    }#Is int32 so continue
    else{
        Write-Output "Please Enter an Integer with maximum 10 digits"
         }#Else Nada

}#Function Calculation2



Categories
Uncategorized

PowerShell Puzzles and Challenges

Here are my solutions to the posted challenges:

  1. How many stopped services are on your computer?
(Get-Service | where status -eq 'Stopped').count

2. list services set to autostart but are NOT running?

$AutoStrtType = (Get-Service | where{$_.StartType -eq "Automatic"})
foreach($srv in $autoStrtType){if($srv.status -ne 'Running'){$srv.DisplayName}}

3. List ONLY the property names of the Win32_BIOS WMI class.

Get-CimInstance "Win32_BIOS" -KeyOnly

4. List all loaded functions displaying the name, number of parameter sets, and total number of lines in the function.

$LoadedFunctions = gcm (Get-ChildItem function:\ -Name)
foreach($Function in $LoadedFunctions){
$numberOfPSets =($Function.ParameterSets).count
$FunctionName = $Function.Name
$NumberOfLines = (((Get-Command $FunctionName).ScriptBlock) | Measure-Object -Line).Lines
Write-Output "Function: $FunctionName has $numberOfPSets Parameter Sets and $NumberOfLines number of lines in the function"
}#FE Function

5. Create a formatted report of Processes grouped by UserName. Skip processes with no user name.

$output = Get-Process -IncludeUserName  | Group-Object UserName
foreach($out in $output){
if(($out.Name | Measure-Object -Character).Characters -eq 0){
}#If Name is empty then skip
else{
$out
}#Else output groups
}#FE output

6. Using your previous code, display the username, the number of processes, the total workingset size. Set no username to NONE.

function CalculateProcess {
    param (
        [string]$userNameChange
    )
    $WorkingSetsize = $out.group.WS
    foreach($Wset in $WorkingSetsize){
        $TotalWorkingSetSize += $Wset
    }#FE
    
    $NumberOfProcesses = $Out.group.count
    if($userNameChange){
        $UserName = $userNameChange
    }#If UserName Change is True
    else{
    $UserName = $out.Name 
    }#Else
    Write-Output "UserName: $UserName has $NumberOfProcesses processes using total workingSet size: $TotalWorkingSetSize"
}#Function CalculateProcess
$output = Get-Process -IncludeUserName  | Group-Object UserName
foreach($out in $output){
    $TotalWorkingSetSize = $null
if(($out.Name | Measure-Object -Character).Characters -eq 0){
    CalculateProcess -userNameChange "None"
}#If Name is empty then skip
else{
CalculateProcess
}#Else output groups
}#FE output

7. Create a report that shows files in %TEMP% by extension. Include Count,total size, % of total directory size.

$FolderToCheck = $env:temp
$Groups = get-childitem $FolderToCheck -recurse -file | Group-Object Extension ###Gets files by extension and count
$FolderSize = (get-childItem $FolderToCheck -recurse -file -force | Measure-Object -Property length -sum).sum 
$Groups.name
$FolderREport = foreach($grp in $Groups){
    $TypeTotal   = $null
    $GroupList   = $null
    $PercentUsed = $null
$GroupList = $grp.group.FullName | Out-String
foreach ($file in (get-childitem -path $grp.group.FullName)){
    $TypeTotal += $file.length

    }#FE File in list
$PercentUsed = ($TypeTotal/$FolderSize).ToString("P")

New-Object psobject -Property @{
    "Extension Type"            = $grp.name
    "Count"                     = $grp.count
    "Total Size in MB"          = $TypeTotal/1MB
    "Group"                     = $GroupList
    "% of Total Directory size" = $PercentUsed
}#New PSOBJECT
}#FE Group
$FolderREport

#####Extra - export to Excel
try{Install-Module PSExcel -ErrorAction stop
}#Try to install PSExcel module
catch{}#Catch
Import-Module PSExcel
$Filename = "TempFolder_Report" + ".xlsx"
$FolderREport | Export-XLSX -Path ".\$Filename" -Table -Autofit

8. Find the total % of WS memory a process is using. Show top 10 processes,count,total workingset and PctUsedMemory.

$WS = (Get-Counter "\Process(*)\Working Set").CounterSamples
foreach($value in $WS){
    $TotalWSValue =+ $value.CookedValue
   }#FE Counter
$TotalWSValue #/1MB
$Top10Unique = (Get-Process | Sort-Object -Property ws -Descending | Select-Object -first 10 Name -Unique).name
foreach($Proc in $Top10Unique){
    $WSTotal = $null
    $ProcTotal = $null
    $TotalArrayValue = $Null

     $WSTotal = (Get-Process -Name $Proc).WorkingSet
     if($WSTotal.GetType().BaseType.Name -eq 'Array'){
        foreach($arr in $WSTotal){
            $TotalArrayValue += $arr
        }#FE Array Element
        $WSTotal = $TotalArrayValue
     }#If array
     else{
     }#Else out Int
     $WSTotalMB = $WSTotal /1MB
    $ProcTotal = (Get-Process -Name $Proc).count
    $PercentUsed = ($WSTotal/$TotalWSValue).ToString("P")
    Write-Output "Process name: $Proc total Working set in use is: $WSTotalMB MB's with count of $ProcTotal procesess. Percent of WS used is $PercentUsed"
}#FE top 10MB

Bonus #1

Write PowerShell code to achieve the following goals:

  1. Create a directory called C:\DataFiles
  2. Create 25 files of varying sizes between 1KB and 1MB with your own naming convention.
    But don’t use something as simple as Test-1. Files should have a .dat extension.
  3. Modify the creation and last write times to “age” the files between 10 and 100 days.
$Path = 'C:\DataFiles'
$NumberOfFilesToCreate = 25
New-Item -Path $Path  -ItemType Directory -ErrorAction Ignore
#Get list of 25 Random unique strings to use for file names
$ListOfRandomNames = (Get-command | Get-Member).Name | Select-Object -unique

$Number = 0
while($Number -lt $NumberOfFilesToCreate){
    $RandomNumber = Get-Random -Maximum 1000
    $RandomName = $ListOfRandomNames[$Number]
    fsutil file createNew $Path\$RandomName.dat $RandomNumber

$Number ++
}#While Number is less than $NumberOfFilesToCreate

###age last write and creation time by random 10 - 100 days 
$ListOfFiles = (Get-ChildItem -Path $Path).FullName
foreach($File in $ListOfFiles){

$CreationTime = (Get-Item $File).CreationTime
$LastWriteTime = (Get-Item $File).LastWriteTime
(Get-Item $File).LastWriteTime = (Get-date).AddDays((Get-Random -Minimum 10 -Maximum 101))
(Get-Item $File).CreationTime = (Get-date).AddDays((Get-Random -Minimum 10 -Maximum 101))
$CreationTimeNew = (Get-Item $File).CreationTime
$LastWriteTimeNew = (Get-Item $File).LastWriteTime
Write-Output "$File original creationTime: $CreationTime changed to $CreationTimeNew"
Write-Output "$File original LastWriteTime: $LastWriteTIme changed to $LastWriteTimeNew"
}#FE file change last write and creation time

Bonus #2

Create a formatted HTML report that shows each module location from %PSModulePath%, the number of modules in each location and their total size, and then a listing of each module which shows the most recent version and the total size of all module files.

Extra bonus points if you can make it pretty with CSS formatting.


#Create a formatted HTML report that shows each module location from %PSModulePath%, the number of modules
#in each location and their total size, and then a listing of each module which shows the most recent version
# and the total size of all module files.
$ModuleReport = $Null
$ModulePaths = $env:PSModulePath
$ModuleReport = foreach($ModulePath in ($ModulePaths.Split(';'))){
    $ModuleCount = $Null
    $ListingOfModules = $Null
          try{ $ModuleFolders = (get-childitem -Path $ModulePath -Directory -ErrorAction stop).FullName
     

   
       foreach ($Module in $ModuleFolders){
    
 
              if((Get-ChildItem -Path $Module\*.psm1 -Recurse).name){
                   $ModuleCount ++
                #try with uppercase M  
                $ModuleShortName = $Module.Split("Modules\")[1]
               if($ModuleShortName.count -eq 0){
                  #Try with lowercase m
                   $ModuleShortName = $Module.Split("modules\")[1]

                    }#If count is 0 then Try lowercase modules
              #   Write-Host "$ModuleShortName" -ForegroundColor blue
                   
                   $IndividualModuleSize = ((get-childItem $Module -recurse -force | Measure-Object -Property length -sum).sum) 
                   $ModulesTotalSize =+ $IndividualModuleSize
                   #Try to get Module Version
                   try{
                   $ModVer =  (Get-InstalledModule $ModuleShortName -ErrorAction stop)[0].Version
                   
                   }#try to get module version
                   catch{
                    $ModVer = ((Get-Module $ModuleShortName -ListAvailable).Version)[0].ToString()
                   }
                  # Write-Host "$ModuleShortName version is $Modver" -ForegroundColor Yellow -BackgroundColor Red
                   $ListingOfModules  += " "
                   $NameAndVer = $ModuleShortName + " " +"v" + $ModVer + " Module Size:" + $IndividualModuleSize/1MB + " MB"
                   $ListingOfModules += $NameAndVer
                   $ListingOfModules  += " "


                }#If there are .psm1 files then proceed and create new PS objects

}#FE Module Folder

New-Object psobject -Property @{
    "M Location"     = $ModulePath
    "M  Number"        = $ModuleCount
    "M Size"         = $ModulesTotalSize/1MB
    "List"    = $ListingOfModules
    
}#New PSOBJECT
     }#try and get folder contents for folder from module path list

catch{
  }#catch folders that do not exist
}#FE Module PAth
$ModuleReport


##Export to HTML using module from: https://github.com/EvotecIT/PSWriteHTML
Import-Module PSWriteHTML -Force
New-HTML -TitleText 'Bonus 2 HTML' -UseCssLinks:$true -UseJavaScriptLinks:$true -FilePath $PSScriptRoot\Example01.html -ShowHTML {
  New-HTMLPanel {
      New-HTMLTable -DataTable $ModuleReport -HideFooter -ScrollCollapse {
      New-HTMLTableHeader -BackGroundColor Green -Color White -Title 'Bonus 2 Powershell Puzzles output'
      }
  }
}

Categories
Uncategorized

Screen Saver per AD department

Requirement to set different screen saver for customer depending on AD department.
Create Central accessible folder locations, example netlogon folder.
Create Powershell script to determine department from ADSI for logged in user.
Create User GPO to copy script to folder on Machine and set a scheduled task to run the script at any user logon (Delayed if required).
Then Set Security Group filtering and link GPO to users OU and enable GPO
Then just update the central department folders with new images when required
 <# 
 .SYNOPSIS 
   Automate Set Screen Saver as Department
  
 .DESCRIPTION 
   Gets logged on user with CIMInstance
   Gets SID for user to locate reg Hive and sets the ScreenShow speed
   Checks AD for Logged in User using ADSI and gets department name
   Each Department has folder in central location which contains screen saver images
   If there is a new update to folder then apply
   If department changes then apply new department screen savers
  
 .PARAMETER  
     None
  
 .INPUTS 
   None
  
 .OUTPUTS 
   None
  
 .NOTES 
   Version:        1.0 
   Author:         Peter Charleston
   Creation Date:  20/12/2019
   Purpose/Change: Task to automate dynamic screen saver per AD department 
    
 .EXAMPLE 
   None
 #> 

################ Edit Added on 14/01/2020 to test update process ####################

$CurrentImageFolderAll = "C:\Admin\Screen\*"
$CurrentImageFolder = "C:\Admin\Screen"
$NetworkSaverLocation = "\\Domain\NETLOGON\ScreenSavers"
$date = (Get-Date).ToString("yyyy-MM-dd_HHmmss")
$userExplore = Get-CimInstance Win32_Process -Filter "Name='explorer.exe'" | Invoke-CimMethod -MethodName GetOwner
$user = $userExplore[0]
$fltr = "Name='{0}' AND Domain='{1}'" -f $user.User, $user.Domain
$sid = (Get-CimInstance Win32_UserAccount -Filter $fltr).SID
$SlideShowSpeed = "Registry::HKEY_USERS\$sid\Software\Microsoft\Windows Photo Viewer\Slideshow\Screensaver"
#Test to see if Reg folder exists and if not create
if(Test-Path -Path $SlideShowSpeed){
Set-ItemProperty -Path $SlideShowSpeed -Name Speed -Value 0


}#If Folder already exists then create new key and value
else{
New-Item -Path "Registry::HKEY_USERS\$sid\Software\Microsoft" -name "Windows Photo Viewer"
New-Item -Path "Registry::HKEY_USERS\$sid\Software\Microsoft" -name "Windows Photo Viewer\Slideshow"
New-Item -Path "Registry::HKEY_USERS\$sid\Software\Microsoft" -name "Windows Photo Viewer\Slideshow\Screensaver"
New-ItemProperty -Path "Registry::HKEY_USERS\$sid\Software\Microsoft\Windows Photo Viewer\Slideshow\Screensaver" -Name "Speed" -Value 0


}#Else create new Reg items

$UserAccount = $User.User
#$UserAccount = (Get-CimInstance win32_LoggedOnUser).Antecedent.Name
$Department = $null
$DepartmentPathName = $null
#Get SID Poweshell 7 
#([System.Security.Principal.NTAccount]('{0}\{1}' -f $user.Domain, $user.User)).Translate([System.Security.Principal.SecurityIdentifier]) 

##########Function##########
function ScreenFileCheck {
    param(
    #[string]$DepartmentName,
    [string]$DepartmentPath

    )

 
    Remove-Item -Path $CurrentImageFolderAll -Force -ErrorAction SilentlyContinue

    Copy-Item -Path $DepartmentPath  -Destination $CurrentImageFolder
}#ScreenFileCheck Function



############Get Department######################
$Department = ([ADSISearcher]"(sAMAccountName=$UserAccount)").FindOne().Properties['department']
#$Department = "People Department"




function UpdateScreenSaver {
param (

    [String]$Department

)
    $location = $Department
    $DepartmentPathName = "$NetworkSaverLocation\$Location\*"
    $DepartmentPathNameGetItems = "$NetworkSaverLocation\$Location"
    #Add Condition to determine if there are new files loaded
    $GetNetworkFolderlastWrite = Get-Item $DepartmentPathNameGetItems | select LastWriteTime
    $GetLocalFolderLastWrite = Get-Item $CurrentImageFolder | select LastWriteTime
    if ($GetNetworkFolderlastWrite.LastWriteTime -gt $GetLocalFolderLastWrite.LastWriteTime) {
        Write-Output "New Files found @ $DepartmentPathName. Copying over new files"
        ScreenFileCheck -DepartmentName $Department -DepartmentPath $DepartmentPathName
    }#If There are new files on Network location then move to local
    else {

        write-host "There are no new files on $DepartmentPathName" -ForegroundColor Red
        write-host "Checking to see if files in $CurrentImageFolder contain the $Location Savers" -ForegroundColor Yellow
        
        #Get count of number of files @ network location and write-host
        #$NetworkfileCount = (Get-item $DepartmentPathName).count
        #write-host "Current number of files at $DepartmentPathNameGetItems is $NetworkfileCount"
        $ListOfFileSavers = (Get-ChildItem -Path $CurrentImageFolder).Name
        #Get count of number of files @ local locatoin and write-host
        #$LocalFileCount = (Get-Item $CurrentImageFolderAll).count
        #write-host "Current number of files at $CurrentImageFolder is $LocalFileCount"

        #Compare folders for file names
        try{
        $FileNameCheck = Compare-Object -ReferenceObject ((Get-Childitem $CurrentImageFolderAll).Name) -DifferenceObject ((Get-Childitem $DepartmentPathName).Name) -ErrorAction Stop

            If($FileNameCheck){
        $DifferrenceInFile = $True

        }#If there is a differrence in FileNames check
        else{
         $DifferrenceInFile = $False

        }#If thre is no differrence in FileNames check

        }#Try to compare objects
        #catch [System.Management.Automation.ParameterBindingValidationException] {
       catch{
       if(($PSItem.Exception -like '*ReferenceObject*') -or ($PSItem.Exception -like '*DifferenceObject*')){
       If($PSItem.Exception -like '*ReferenceObject*'){

        write-host "$CurrentImageFolder is empty" -ForegroundColor Red
        }#if Ref Object
        If($PSItem.Exception -like '*DifferenceObject*'){

        write-host "$DepartmentPathName is empty" -ForegroundColor Red
        }#if Ref Object


        $DifferrenceInFile = $True

        }#If 
        }#catch exception

    

        #if (($ListOfFileSavers -like "$Department*") -and ($ListOfFileSavers.Count -eq $NetworkFileCount))  {


        ############Add just check if DifferrenceInFile######## this will tell us if there are any differrences in FileNames and determine if files are correct - Dont need to check fileName -like
      #   if (($ListOfFileSavers -like "$Department*") -and !($DifferrenceInFile))  {
      if(!($DifferrenceInFile)){

            Write-host "Correct files in $currentImageFolder" -ForegroundColor Green
        }#If There is no differrence in Files

        #}#If List of files contatin Place
        else {

            write-host "Incorrect files located in $CurrentImageFolder... Moving files from $DepartmentPathName to $CurrentImageFolder" -ForegroundColor Green
            ScreenFileCheck -DepartmentPath $DepartmentPathName

        }#Else incorrect files 
        
    }#Else there are no new files on Network folder

    }#Function UpdateScreenSaver

UpdateScreenSaver -Department $Department





Categories
Uncategorized

Unmanage Azure VM ORION NODES

Reducing noise is important.
Lots of Azure vm’s turning on and off when not required.
Lots of Alerts from ORION when this happens producing a lot of noise.
Wanted to create a dynamic solution to take into account any new vm’s added or tag properties modified.
Created a Runbook in Azure which runs on a Hybrid worker group.
This connects to Azure and pulls all vms from all Resource groups in each specified subscription.
If login to azure account fails then send alert and restart Runbook
Then it checks to see if the vm is on a schedule or not by checking the vm tags.
Report status is created for all vm’s.
The ones which are on a schedule to turn on and off are determined if AlwaysOff and AlwaysOn are both false and then the tags are checked.
There is a function to check for the next day a vm will be back on.
Then for each of these sheduled vms, it connects to the ORION API and checks if its a managed node.
If it is, then try to unmanage node from time vm is off till next time vm is on.
If this fails then try to mute node for same period.
If this fails then sent alert and continue
An email report will be sent when completed.

<#
 .Synopsis
  Azure runbook to Unmanage Azure VM nodes in ORION during times they are de-allocated to reduce Alert Noise

 .Description
  Executed daily from Azure Runbook on Hybrid Worker Group

 .Example

 .NOTES 
   Version:        1.0
   Author:         Peter Charleston 
   Creation Date:  05/06/2019
   Purpose/Change: AutoMate ORION Unmanage Azure Nodes
#>


#Get Azure Automation Creds
$automationAccountName = "AzureCredsWithAccessToSubscriptions"
$ORIONCreds = "LocalSolarWindsAccount"

$AzureCredentials = Get-AutomationPSCredential -Name $automationAccountName
$OrionCredsToPass = Get-AutomationPSCredential -Name $ORIONCreds
$ORIONServerName = "SolarWindsServerName"


$Sub1 = "SubscriptionName1"
$Sub2 = "SubscriptionName2"
$Date = get-date
$DayToday = (get-date).DayOfWeek
$DayTomorrow = ((get-date).addDays(1)).DayOfWeek
$DayTomorrow1 = ((get-date).addDays(2)).DayOfWeek
$DayTomorrow2 = ((get-date).addDays(3)).DayOfWeek
$DayTomorrow3 = ((get-date).addDays(4)).DayOfWeek
$DayTomorrow4 = ((get-date).addDays(5)).DayOfWeek
$DayTomorrow5 = ((get-date).addDays(6)).DayOfWeek
$DayTomorrow6 = ((get-date).addDays(7)).DayOfWeek
$ScriptStartTime = (Get-Date).DateTime
$ScriptStartTime
$folderPath = "C:\ORIONALERTMUTING"
$VMNotTagged =  $folderPath +"\" + "VMNotTagged_" + (Get-Date).ToString("yyyy-MM-dd_HHmmss") +".txt"
$IssueWithTags = $folderPath + "\" + "IssueWithTags_" + (Get-Date).ToString("yyyy-MM-dd_HHmmss") +".txt"
$VMAlwaysOn = $folderPath + "\" +"VMAlwaysOn_" + (Get-Date).ToString("yyyy-MM-dd_HHmmss") +".txt"
$VMAlwaysOff = $folderPath + "\" +"VMAlwaysOff_" + (Get-Date).ToString("yyyy-MM-dd_HHmmss") +".txt"
$VMAlwaysOffAndOn = $folderPath + "\" +"VMAlwaysOffAndOn_" + (Get-Date).ToString("yyyy-MM-dd_HHmmss") +".txt"
#Check if Path Exists if not create it
if(Test-Path -Path $folderPath){

}#If Folder exists do nothing
else{
#Create folder
New-Item -Path $folderPath -ItemType "directory"
}#Else Create New Folder

function CheckNextTagSchedule {

$MaxDayInMonth = ((get-date $Date -Day 1 -hour 0 -Minute 0 -Second 0).AddMonths(1).AddSeconds(-1)).Day

$ScheduleTomorrow = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow"}).Value

if(($ScheduleTomorrow -eq '-') -or ($ScheduleTomorrow.Length -lt 1)){
write-host "There is no Tag Schedule for $DayTomorrow" -ForegroundColor Yellow
write-host "Checking Tag Schedule for $DayTomorrow1" -ForegroundColor Green

$ScheduleTomorrow1 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow1"}).Value
#CHECK NEXT DAY
if(($ScheduleTomorrow1 -eq '-') -or ($ScheduleTomorrow1.Length -lt 1)){
write-host "There is no Tag Schedule for $DayTomorrow1" -ForegroundColor Yellow
write-host "Checking Tag Schedule for $DayTomorrow2" -ForegroundColor Green
$ScheduleTomorrow2 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow2"}).Value
####CHECK NEXT DAY
if(($ScheduleTomorrow2 -eq '-') -or ($ScheduleTomorrow2.Length -lt 1)){
write-host "There is no Tag Schedule for $DayTomorrow2" -ForegroundColor Yellow
write-host "Checking Tag Schedule for $DayTomorrow3" -ForegroundColor Green
$ScheduleTomorrow3 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow3"}).Value
if(($ScheduleTomorrow3 -eq '-') -or ($ScheduleTomorrow3.Length -lt 1)){
write-host "There is no Tag Schedule for $DayTomorrow3" -ForegroundColor Yellow
write-host "Checking Tag Schedule for $DayTomorrow4" -ForegroundColor Green
#Checking Schedule for $dayTomorrow4

$ScheduleTomorrow4 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow4"}).Value
if(($ScheduleTomorrow4 -eq '-') -or ($ScheduleTomorrow4.Length -lt 1)){
write-host "There is no Tag Schedule for $DayTomorrow4" -ForegroundColor Yellow
write-host "Checking Tag Schedule for $DayTomorrow5" -ForegroundColor Green
#Checking Schedule for $dayTomorrow5

$ScheduleTomorrow5 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow5"}).Value
if(($ScheduleTomorrow5 -eq '-') -or ($ScheduleTomorrow5.Length -lt 1)){
write-host "There is no Tag Schedule for $DayTomorrow5" -ForegroundColor Yellow
write-host "Checking Tag Schedule for $DayTomorrow6" -ForegroundColor Green
#Checking Schedule for $dayTomorrow6

$ScheduleTomorrow6 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow6"}).Value
if(($ScheduleTomorrow6 -eq '-') -or ($ScheduleTomorrow6.Length -lt 1)){
write-host "There is no Tag Schedule for $DayTomorrow6" -ForegroundColor Yellow
#write-host "Checking Tag Schedule for $DayTomorrow6" -ForegroundColor Green
#Checking Schedule for $dayTomorrow4

}#If checking ScheduleTomorrow3
else{
Write-Output "$DayTomorrow6"
$ScheduleTomorrow6
if((($Date).Day + 7) -le $MaxDayInMonth){
$Day =($Date).Day + 7
$Month = ((Get-Date).Month)
}#If Day is less than or equal to Max day in Month
else{
$Day = (($Date).Day + 7) - $MaxDayInMonth
if(((Get-Date).Month) -eq 12){
$month = 1
}#If Month is 12
else{
$month = ((Get-Date).Month) + 1
}
}

$Day
$Month


}##Else after checking SheduleTomorrow5

}#If checking ScheduleTomorrow3
else{
Write-Output "$DayTomorrow5"
$ScheduleTomorrow5
if((($Date).Day + 6) -le $MaxDayInMonth){
$Day =($Date).Day + 6
$Month = ((Get-Date).Month)
}#If Day is less than or equal to Max day in Month
else{
$Day = (($Date).Day + 6) - $MaxDayInMonth
if(((Get-Date).Month) -eq 12){
$month = 1
}#If Month is 12
else{
$month = ((Get-Date).Month) + 1
}
}

$Day
$Month

}##Else after checking SheduleTomorrow5

}#If checking ScheduleTomorrow3
else{
Write-Output "$DayTomorrow4"
#$ScheduleTomorrow4 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow4"}).Value
$ScheduleTomorrow4
if((($Date).Day + 5) -le $MaxDayInMonth){
$Day =($Date).Day + 5
$Month = ((Get-Date).Month)
}#If Day is less than or equal to Max day in Month
else{
$Day = (($Date).Day + 5) - $MaxDayInMonth
if(((Get-Date).Month) -eq 12){
$month = 1
}#If Month is 12
else{
$month = ((Get-Date).Month) + 1
}
}

$Day
$Month

}##Else after checking SheduleTomorrow4

}#If checking ScheduleTomorrow3
else{
Write-Output "$DayTomorrow3"
#$ScheduleTomorrow3 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow3"}).Value
$ScheduleTomorrow3
if((($Date).Day + 4) -le $MaxDayInMonth){
$Day =($Date).Day + 4
$Month = ((Get-Date).Month)
}#If Day is less than or equal to Max day in Month
else{
$Day = (($Date).Day + 4) - $MaxDayInMonth
if(((Get-Date).Month) -eq 12){
$month = 1
}#If Month is 12
else{
$month = ((Get-Date).Month) + 1
}
}

$Day
$Month

}##Else after checking SheduleTomorrow3


}#Is Shedule empty Normaly Tuesday
else{
Write-Output "$DayTomorrow2"
#$ScheduleTomorrow2 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow2"}).Value
$ScheduleTomorrow2
if((($Date).Day + 3) -le $MaxDayInMonth){
$Day =($Date).Day + 3
$Month = ((Get-Date).Month)
}#If Day is less than or equal to Max day in Month
else{
$Day = (($Date).Day + 3) - $MaxDayInMonth
if(((Get-Date).Month) -eq 12){
$month = 1
}#If Month is 12
else{
$month = ((Get-Date).Month) + 1
}
}

$Day
$Month
#$Day= (Get-date).AddDays(4).Day
}#If Scheule found after 3rd day
}#If Schedule is empty - Normaly Monday so should not be
else{
Write-output "$DayTomorrow1"
#$ScheduleTomorrow1 = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow1"}).Value
$ScheduleTomorrow1
if((($Date).Day + 2) -le $MaxDayInMonth){
$Day =($Date).Day + 2
$Month = ((Get-Date).Month)
}#If Day is less than or equal to Max day in Month
else{
$Day = (($Date).Day + 2) - $MaxDayInMonth
if(((Get-Date).Month) -eq 12){
$month = 1
}#If Month is 12
else{
$month = ((Get-Date).Month) + 1
}
}

$Day
$Month

#$Day= (Get-date).AddDays(2).Day

}
}#If no schedule
else{
Write-Output "$DayTomorrow"
#$ScheduleTomorrow = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayTomorrow"}).Value
$ScheduleTomorrow

if((($Date).Day + 1) -le $MaxDayInMonth){
$Day =($Date).Day + 1
$Month = ((Get-Date).Month)
}#If Day is less than or equal to Max day in Month
else{
$Day = (($Date).Day + 1) - $MaxDayInMonth
if(((Get-Date).Month) -eq 12){
$month = 1
}#If Month is 12
else{
$month = ((Get-Date).Month) + 1
}
}

$Day
$Month

#$Day= (Get-date).AddDays(1).Day
}#TagScheduleFound


}#Function CheckNextTagSchedule


#UseFull outPut to tell which Hybrid Worker job is running on
write-output "Running on $Env:COMPUTERNAME"
$result = Login-AzureRmAccount -Credential $AzureCredentials

If($result){





#Select required subscriptions
$Subscriptions = Get-AzureRmSubscription | Where-Object { $_.Name -in ("$Sub2","$Sub1") }


#$Report =
 ForEach ($Subscription in $Subscriptions) {
    $SubscriptionName = $Subscription.Name
    #$SubscriptionName = "Live"
    Set-AzureRmContext -SubscriptionName "$SubscriptionName" | Out-Null
    #Get All ResourceGroups in Subscription
    $RGs = Get-AzureRMResourceGroup 
    #$RGs = Get-AzureRmResourceGroup -Name 'LBE-RG-DHY-001'

  foreach ($RG in $RGs) {
  #Get All VMS in ResourceGroup
        $VMs = Get-AzureRmVM -ResourceGroupName $RG.ResourceGroupName
        
        foreach ($VM in $VMs) {

        #$VM = Get-AzureRmVM -ResourceGroupName $RG.ResourceGroupName -Name $VM.Name
         #   $Vm.tags
    $VMNAME = $VM.name
    $NotTagged = $null
    $Schedule = $null
    $ManagedInORION = $false
    $tags = $null
	$tags = $vm.Tags 
    $VMTaggedStatus = $Null
    $nodes = $Null
    $MuteFrom = $null
    $UnMuteFrom = $null

#If schedule exists get start and end time for each day
    if (!($tags.Keys -like '*Schedule*')) #($tags.Values.count -lt 1)
    {
            # No direct or inherited tag. Skip this VM.
           # Write-Output "[$($vm.Name)]: Not tagged for shutdown directly or via membership in a tagged resource group. Skipping this VM."
            "$VMNAME Not Tagged for Schedule" | Out-File -FilePath "$VMNotTagged" -Append
            Write-Output "$VMNAME not tagged for Schedule" #-ForegroundColor Magenta
            $VMTaggedStatus = $false
            #continue
    } #If there is no Schedule Tagged
    else{
    if($tags.GetEnumerator()){}else{"Issue with Tags on $VMNAME $tags" | Out-File -FilePath "$IssueWithTags" -Append}

	$ifAlwaysOn = $false
	$ifAlwaysOff = $false
    $VMTaggedStatus = $True

    #Check if AlwaysON is equal to $True
   	if ((($tags.GetEnumerator() | Where-Object {$_.Key -like "AlwaysON"}).Value).tolower() -like "*true")
	{
		$ifAlwaysOn = $true
        "$VMNAME is alwaysOn" | Out-File -FilePath "$VMAlwaysOn" -Append
        Write-Output "$VMNAME is set to AlwaysOn" #-ForegroundColor Yellow
		
	}#If Tag equals AlwaysOn


#Check if AlwaysOFF is equal to $True
	if ((($tags.GetEnumerator() | Where-Object {$_.Key -like "AlwaysOFF"}).Value).tolower() -like "*true")
	{
		$ifAlwaysOff = $true
        "$VMNAME is alwaysOFF" | Out-File -FilePath "$VMAlwaysOff"-Append
         Write-Output "$VMNAME is set to AlwaysOff" #-ForegroundColor Blue
		
	}# If Tag equals AlwaysOff
			
	If (($ifAlwaysOn)  -and ($ifAlwaysOff))
	{
	#Write-Output "[$($vm.Name)]: Has AlwaysOn and AlwaysOff both set to TRUE. This doesn't make sence. Skipping...."
    "$VMNAME is alwaysOn and AlwaysOff" | Out-File -FilePath "$VMAlwaysOffAndOn" -Append
            Write-Output "$VMNAME is set to AlwaysOn and AlwaysOff - Investigate" #-ForegroundColor Yellow

		continue
	}#If Tags set to AlwayOn and AlwaysOff



    #Check if AlwaysOn and AlwaysOff equals False
	If ((-not $ifAlwaysOn)  -and (-not $ifAlwaysOff))
	{
 Write-Output "$VMNAME has Tag AlwaysOff: False and tag AlwaysOn: False"
		
            #get Schedule for Today
			$Schedule = ($tags.GetEnumerator() | Where-Object {$_.Key -like "Schedule_$DayToday"}).Value

		

           if($Schedule -eq $Null){
            $Schedule = "No Schedule tagged"
             

        }#If Schedule is equal to Null
        ####Added test to see if split from Schedule is empty####
		if ($Schedule.Split("->")[2] -eq $null)
		{
				
                Write-Output "$VMNAME  Not tagged for the $DayToday."
              	continue
		}#If Schedule split is equal to Null
else{
Write-Output "$VMNAME has an Azure Tag schedule for $DayToday... Checking ORION"
######################## MUTE ORION ALERTS   ######################################


                                        ##### Start Check Azure Tag Shedule for Tomorrow#####

#write-output "Calling Function CheckNextTagSchedule"
$GetNextDayTag = CheckNextTagSchedule

$GetNextDayTag

$NextDaySchedule = $GetNextDayTag[0] #Next Day with Tag Schedule
$hourToUnMute = (($GetNextDayTag[1].Split("->")[0]).Split(":")[0]) #Time to UnMute
$DayToUnMute = $GetNextDayTag[2] #Day to UnMute
$month = $GetNextDayTag[3]#Month to Unmute

#Create Date/Time Object to Mute Alert
$MuteFrom =     ([dateTime]$Schedule.Split("->")[2])#Mute From
if(([dateTime]$Schedule.Split("->")[2]).IsDaylightSavingTime()){
#$true
$MuteFromUTC =     ([dateTime]$Schedule.Split("->")[2]).ToUniversalTime()#Mute From UniversalTime

}#If UniversalTime
else{
$MuteFromUTC = ([dateTime]$Schedule.Split("->")[2])
}#Else not UniversalTime

                                        ##### END Check Azure Tag Shedule for Tomorrow#####

                                        ######### Start Check if VM is in ORION #########


 #SeverName
$ServerNodeName =  $VMNAME
#Make Connection to NPM Server
$swisconnection = Connect-Swis -hostname $ORIONServerName -Credential $OrionCredsToPass
#Set SWIS QUERY
    $swisQuery = @"
SELECT top 1 NodeID as [ID], 
Caption as [Name], 
EntityType as [Type], 
Uri as [Uri],
'N' as [Prefix],
UnManaged as [UnManaged],
UnManageFrom as [UnManageFrom],
UnManageUntil as [UnManageuntil],
StatusDescription as [StatusDescription],
Status as [Status],
BlockUntil as [BlockUntil]
FROM Orion.Nodes 
where (Caption = \@p or DNS = \@p or IPAddress=\@p)
"@

    try {
        $nodes = Get-SwisData $swisconnection $swisQuery @{p=$ServerNodeName} -ErrorAction Stop
    }#Try to Get Node details from ORION API 
    catch {
              if($PSItem.Exception.InnerException -like '*An error occurred when verifying security for the message*'){
                    $IPSTRIngToSearch = (test-connection -ComputerName $ORIONServerName -count 1).ipv4Address.IPAddressToString
                    $PortToSearch = "17777"

                    write-output "Security error connecting to ORION API"
                    write-output "Capturing current TCP connection to ORION Server on port 17777"
                    $TCPCapture = Get-NetTCPConnection | ? {($_.RemotePort -like "*$PortToSearch*") -and ($_.RemoteAddress -like "*$IPStringToSearch*")}
                    $TCPState =$TCPCapture.state
                    $TCPCapture = $TCPCapture.LocalAddress
                    $TCPCapture
                    $TCPState
                    #Send Mail to alert on Failure
                    $ScriptEndTime = (Get-Date).DateTime
                    $ScriptEndTime
                    $subject = "ORION Mute Alert Failed Trying to make connection to ORION Server"
                    $Body = "StartTime: $ScriptStartTime and EndTime: $ScriptEndTime Result from Get-NetTCPConnection is $TCPCapture and $TCPState "
                    $MailServer = "smtprelayServer"
                    $To = "AutoMationSupport@company.com"
                    $From = "OrionAzureVMMute@company.com"
                    $BCC = "additionalalert@otheraddress.com"
                    #Test for $FileName existence
                    if(Test-path $Filename){
                        write-output "Sending Mute Alert Failed report with $Filename"
                              Send-MailMessage -Body $Body -From $From -To $To -cc $BCC -SmtpServer $MailServer -Subject $Subject -attachment $Filename
                    }#Send Mail with report
                    else{
                        write-output "Sending Mute Alert with no report attached"
                              Send-MailMessage -Body $Body -From $From -To $To -cc $BCC -SmtpServer $MailServer -Subject $Subject #-attachment $Filename


                    }#Else send mail without report
                }#if InnerException caught

       
        exit 1
    }
if($nodes -eq $Null){
$ManagedInORION = $false
$MuteFrom = $null 
}#Node not found in ORION
else{
if(!$nodes.UnManaged){
$NodeName = $nodes.Name
$NodeID = $nodes.ID
Write-Output "Node Is Managed in ORION Name: $NodeName Node ID: $NodeID"

    $Year = (Get-Date).Year
    #Add + 40 minutes to allow Automation to start VM
    $Minute = 40
    $Second = 00

#Create Date/Time Object to Unmute alert
$UnMuteFrom =  (Get-Date -Year $Year -Month $month -Day $DayToUnMute -Hour $hourToUnMute -Minute $Minute -Second $Second)
if((Get-Date -Year $Year -Month $month -Day $DayToUnMute -Hour $hourToUnMute -Minute $Minute -Second $Second).IsDaylightSavingTime()){
$UnMuteFromUTC =  (Get-Date -Year $Year -Month $month -Day $DayToUnMute -Hour $hourToUnMute -Minute $Minute -Second $Second).ToUniversalTime()

}#if Daylight saving time
else{
$UnMuteFromUTC = (Get-Date -Year $Year -Month $month -Day $DayToUnMute -Hour $hourToUnMute -Minute $Minute -Second $Second)
}#else not Daylight saving

Write-Output "UnManaging $VMNAME from $MuteFrom till $UnMuteFrom"

$prefixedID=$Nodes.Prefix+":"+$Nodes.ID

###################################UnManageNode###################################
try{
$SendUnManageCommand =Invoke-SwisVerb $swisconnection $Nodes.Type Unmanage @( $prefixedID, $MuteFromUTC, $UnMuteFromUTC, "false" ) -ErrorAction stop
}#Try Unmanage


catch{
 $Excep1 = $PSItem.Exception
 $PSItem.Exception
Write-Output "Unable to UnManage $VMNAME so will try to Mute Alert instead from $MuteFrom till $UnMuteFrom"
try{
################# TRY TO MUTE INSTEAD ###############
write-output "Trying to Mute alert instead for $VMName from $MuteFrom till $UnMuteFrom"
$SendMuteAlertCommand = Invoke-SwisVerb $swisconnection "Orion.AlertSuppression" SuppressAlerts @( @($nodes.Uri), $MuteFromUTC, $UnMuteFromUTC) -ErrorAction stop
}#try to Mute alert
catch{
$Excep2 = $PSItem.Exception
$PSItem.Exception
write-output "Attempt to Mute alert Failed for $VMName"
###############Send Mail Report for nodes which failed to unmanage or mute###################################
$MailServer = "smtprelay.company.com"
            $To = "Adminalert@domain.com"
            $From = "OrionAzureVMAlert@domain.com"
            $BCC = "Adminalert2@domain.com"
            $Subject = "Node $VMNAME failed to unmanage or Mute"
            $Body = "Unmanage Exception is: $Excep1 Mute alert Exception is $Excep2"
            Send-MailMessage -Body $Body -From $From -To $To -cc $CC -bcc $BCC -SmtpServer $MailServer -Subject $Subject -attachment $filepath


}#Catch attempt to Mute alert


}#Catch Unmanage attempt


###################################UnManageNode###################################

#$nodes.ID
#$nodes.Prefix
$ManagedInORION = $True
}#if Node found in ORION
else{
Write-Output "Node is not Managed in ORION Name: $VMNAME" #-ForegroundColor Red
$ManagedInORION = $false
$MuteFrom = $null

}#Node not Managed in ORION
}#Node found in ORION 

                        ######### End Check if VM is in ORION #########

           # VM Status (running/deallocated/stopped)
            $VMDetail = Get-AzureRmVM -ResourceGroupName $RG.ResourceGroupName -Name $VM.Name -Status
            $VMStatusDetail = $VMDetail.Statuses.DisplayStatus -match "^VM .*$"
     $Report = New-Object psobject -Property @{
                "VMName"           = $VM.Name
                "OSType"           = $VM.StorageProfile.OSDisk.OSType
                "ResourceGroup"    = $RG.ResourceGroupName
                "VMStatus"         = "$VMStatusDetail"
                "SubscriptionName" = $SubscriptionName
                "Day Today"        = $DayToday
                "Schedule"         = $Schedule
                "Managed in ORION" = $ManagedInORION
                "UnManage Node From" = $MuteFrom
                "Unmanage Node Till" = $UnMuteFrom
            }
            $Report | Export-Csv -Path $Filename -NoTypeInformation -Append

            }#Else there is a schedule so collect data
            }#If Both set to False
              } #Else if VM has Tags 
        }#ForEach VM in list of VMS
    }#ForEach RG in list of RG's
}#ForEach Sub

#Create Array with log Paths
$filepath = @()
#Add VMNotTagged log if exists
if(Test-path -Path $VMNotTagged){
$filepath += $VMNotTagged
}#if there is a VMNotTagged File
#Add $Filename log if exists
if(Test-path -Path $Filename){
$filepath += $Filename
}#if there is a $Filename
#Add $IssueWithTags log if exists
if(Test-path -Path $IssueWithTags){
$filepath += $IssueWithTags
}#if there is a $IssueWithTags
#Add $VMAlwaysOn log if exists
if(Test-path -Path $VMAlwaysOn){
$filepath += $VMAlwaysOn
}#if there is a $VMAlwaysOn
#Add $VMAlwaysOff log if exists
if(Test-path -Path $VMAlwaysOff){
$filepath += $VMAlwaysOff
}#if there is a $VMAlwaysOff
#Add $VMAlwaysOffAndOn log if exists
if(Test-path -Path $VMAlwaysOffAndOn){
$filepath += $VMAlwaysOffAndOn
}#if there is a $VMAlwaysOffAndOn


$ScriptEndTime = (Get-Date).DateTime
$ScriptEndTime
$subject = "ORION UnManage Node Daily WorkFlow Completed"
$Body = "StartTime: $ScriptStartTime and EndTime: $ScriptEndTime"
$MailServer = "smtprelay.company"
            $To = "AutoMationSupport@company.com"
            $From = "OrionAzureVMAlert@company.com"
            $BCC = "otherAddress@comany.com"
            $CC = "security@company.com"
            Send-MailMessage -Body $Body -From $From -To $To -cc $CC -bcc $BCC -SmtpServer $MailServer -Subject $Subject -attachment $filepath
            #Send-MailMessage -Body $Body -From $From -To $To -bcc $BCC -SmtpServer $MailServer -Subject $Subject -attachment $filepath

            Write-Output "ORION Daily UnManage Node WorkFlow Completed"

            }#If LogIn is True then Run Script


            else{

                write-output "Login to Azure Failed. Script has not Completed"
                #####Adding Error Handling

                $ScriptEndTime = (Get-Date).DateTime
$ScriptEndTime
$subject = "ORION UnManage Node Daily WorkFlow Failed to complete as connection to Azure failed. Restarting Runbook now."
$Body = "StartTime: $ScriptStartTime and EndTime: $ScriptEndTime"
$MailServer = "smtprelay.company.com"
            $To = "AutoMationSupport@company.com"
            $From = "OrionAzureVMAlert@company.com"
            $BCC = "otherAddress@comany.com"
            #$Subject = "Test message from automation"
            #$Body = "SMTP Test from Azure"
            Start-AzureRmAutomationRunbook -AutomationAccountName "AutomationAccountName" -Name "RunbookName" -ResourceGroupName "RG" -runon "HybridWorkerGroup"
            Send-MailMessage -Body $Body -From $From -To $To -cc $CC -bcc $BCC -SmtpServer $MailServer -Subject $Subject -attachment $filepath
            #Send-MailMessage -Body $Body -From $From -To $To -bcc $BCC -SmtpServer $MailServer -Subject $Subject -attachment $filepath

            }#Else Logon to Azure Failed. Send alert and restart Runbook

Categories
Uncategorized

Introduction

Hi, My name is Peter!

I work in infrastructure and my main focus is Automation.

I love to Automate whatever I can.

I believe automation is essential.