Param ( [string]$ScriptVersion = "6.6" #Reporting script version ) ############################################################################################################################# Function ParseLine ($Line, $StartPosition, $PrimaryBreakCharacter, $AlternateBreakCharacter) { #*********************************************************************************************************** #This function is passed a string, a position in the string to start and two characters on which if #encountered the processing of the string will stop. This is used to extract information from a messy #and/or inconsistent string. #Essentially you pass it a string and tell it where you want it to stop and on what character (up to two) #you want it to stop. It will return all the characters between where you told it to start and the stop #character, not including the stop character. It also returns the position in the string where it #encountered the stop character. #*********************************************************************************************************** $ResultArray=@("string",2) #Array for the parse results $PrimaryValue=@() #Array to hold individual characters until we join it as a string $CurrentPosition = 0 #Placeholder for the position in the line being processed $LineLength = $Line.Length - 1 #Array designated length of the line being processed #Processing the line character by character for ($ParseLoop = $StartPosition; $ParseLoop -le $LineLength; $ParseLoop++) { #If the character we're looking at matches either break character we're done If ($Line[$ParseLoop] -eq $PrimaryBreakCharacter -or $Line[$ParseLoop] -eq $AlternateBreakCharacter) { $CurrentPosition = $ParseLoop $ParseLoop = $LineLength } Else { #Otherwise add to the string array $PrimaryValue += $Line[$ParseLoop] } } #Push the character array into a string #$PrimaryValue = -join $PrimaryValue #Can't use -join because PS1 doesn't have it foreach ($Character in $PrimaryValue) {$EndString+=$Character} #Set the values for the returned array #$ResultArray[0] = $PrimaryValue $ResultArray[0] = $EndString $ResultArray[1] = $CurrentLine Return $ResultArray } ########################################################################################################### Function ParseUntilChar ($Line, $StartPosition) { #*********************************************************************************************************** #This function is passed a string, a position in the string to start and two characters on which if #encountered the processing of the string will stop. This is used to extract information from a messy #and/or inconsistent string. #Essentially you pass it a string and tell it where you want it to stop and on what character (up to two) #you want it to stop. It will return all the characters between where you told it to start and the stop #character, not including the stop character. It also returns the position in the string where it #encountered the stop character. #*********************************************************************************************************** $ResultArray=@("string",2) #Array for the parse results $PrimaryValue=@() #Array to hold individual characters until we join it as a string $CurrentPosition = 0 #Placeholder for the position in the line being processed $LineLength = $Line.Length - 1 #Array designated length of the line being processed $SpaceCount = 0 #Processing the line character by character for ($ParseLoop = $StartPosition; $ParseLoop -le $LineLength; $ParseLoop++) { if ($Line[$ParseLoop] -eq " ") { $SpaceCount++ } else { if ($SpaceCount -gt 2) { while ($Line[$ParseLoop] -eq " ") { $CurrentPosition = $ParseLoop $ParseLoop++ } } else { $SpaceCount = 0 $CurrentPosition = $ParseLoop $PrimaryValue += $Line[$ParseLoop] } } } $ParseLoop-=2 #Push the character array into a string #$PrimaryValue = -join $PrimaryValue #Rewritten for PS1 foreach ($Character in $PrimaryValue) {$EndString+=$Character} #Set the values for the returned array #$ResultArray[0] = $PrimaryValue $ResultArray[0] = $EndString $ResultArray[1] = $CurrentLine Return $ResultArray } ########################################################################################################### function Get-NetshInformation { #*********************************************************************************************************** #This function gathers netsh IP information for a server and returns an array with the IP address and whether skipassource is enabled. #*********************************************************************************************************** $Netsh = Netsh int ipv4 show ipaddresses level=verbose Set-Content 'c:\rs-pkgs\HR-Netsh-Premigration.txt' $Netsh return $Netsh } ########################################################################################################### function Get-ServiceConfiguration { #*********************************************************************************************************** #This function gathers the service configuration for a server and returns saves it locally for later #consumption. #*********************************************************************************************************** $Services = Get-Service $MRServiceData = 'c:\rs-pkgs\MR-Services-Premigration.csv' #file location for the pre-migration machine friendly format $HRServiceData = 'c:\rs-pkgs\HR-Services-Premigration.txt' #file location for the pre-migration human friendly format #Writing headers $Outline = "DisplayName,ServiceName,Status" set-content $MRServiceData $Outline $Outline = "DisplayName`tServiceName`tStatus" set-content $HRServiceData $Outline #Iterating through services and recording the current state foreach ($Service in $Services) { $Outline = $Service.DisplayName+","+$Service.ServiceName+","+$Service.Status add-content $MRServiceData $Outline $Outline = $Service.DisplayName+"`t"+$Service.ServiceName+"`t"+$Service.Status add-content $HRServiceData $Outline } #There should always be more than zero services. If there are zero then we need to flag a problem. if ($Services.count -gt 0) { return $True } else { return $False } } ########################################################################################################### function IsServer2003 { #*********************************************************************************************************** #This function determines if the subject server is running Server 2003 or not. #*********************************************************************************************************** $OSTest = wmic os list status if ($OSTest -like "*2003*") { return $True } else { Return $False } } ########################################################################################################### function IsServer2008R1 { #*********************************************************************************************************** #This function determines if the subject server is running Server 2008 R1 or not. #*********************************************************************************************************** $OSTest = wmic os list status $ReturnValue = $False if ($OSTest -like "*2008*") { if (!($OSTest -like "*R2*")) { $ReturnValue = $True } } Return $ReturnValue } ########################################################################################################### function IsThisHyper-V { #*********************************************************************************************************** #This function determines if the subject server is running Hyper-V #*********************************************************************************************************** $Services = $Null $Services = get-service $IsHyperV = $False foreach ($Service in $Services) { if ($Service.name -eq "vmms" -and $Service.status -eq "Running") { $IsHyperV = $True } } Return $IsHyperV } ########################################################################################################### function Get-HyperVVMStatuses { #*********************************************************************************************************** #This function examines Hyper-V VMs and builds a human readable and machine readable file with useful information. #*********************************************************************************************************** $HyperVFileMR = 'c:\rs-pkgs\MR-Hyper-VVMs-Premigration.csv' #file location for the pre-migration less-friendly, parsed VM information $HyperVFileHR = 'c:\rs-pkgs\HR-Hyper-VVMs-Premigration.txt' #file location for the pre-migration human-friendly, parsed VM information $Running = 0 #Number of running VMs #Gathering data for all VMs $AllVMs = Get-VM #Setting up headings for MR and HR files $Outline = "Name,State,Status,Automatic Start Action" set-content $HyperVFileMR $Outline $Outline = "Name`t`tState`t`tStatus`t`t`tAutomatic Start Action" set-content $HyperVFileHR $Outline #Iterating through VMs foreach ($VM in $AllVMs) { #Recording MR data in CSV $Outline = $VM.Name+","+$VM.State+","+$VM.Status+","+$VM.AutomaticStartAction add-content $HyperVFileMR $Outline #Recording HR data in text format and determining how many tabs are required between if ($VM.Name.length -lt 8) { $Outline = $VM.Name+"`t`t"+$VM.State+"`t`t"+$VM.Status+"`t"+$VM.AutomaticStartAction } else { $Outline = $VM.Name+"`t"+$VM.State+"`t`t"+$VM.Status+"`t"+$VM.AutomaticStartAction } add-content $HyperVFileHR $Outline #Tallying the number of running VMs if ($VM.State -eq "Running") {$Running++} } #Adding a couple of blank lines to HR files $Outline = "" add-content $HyperVFileHR $Outline add-content $HyperVFileHR $Outline #Writing total and number of running VMs $Outline = "VM Count:`t"+$AllVMs.count add-content $HyperVFileHR $Outline $Outline = "Running VMs:`t"+$Running add-content $HyperVFileHR $Outline return $AllVMs.count } ########################################################################################################### function Get-UAC { #*********************************************************************************************************** #This function determines whether UAC is enabled returns true or false. #*********************************************************************************************************** $UACStatus = (Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System).EnableLUA if ($UACStatus -eq 1) {Return $True} else {Return $False} } ########################################################################################################### function Get-IPConfiguration ($NetshArray) { #*********************************************************************************************************** #This function gathers the IP information for a server and saves it at C:\rs-pkgs. #*********************************************************************************************************** #Gathering all ipconfig data and dropping it in human-readable format first just in case $IPConfig = ipconfig /all Set-Content 'c:\rs-pkgs\HR-IPConfigAll-Premigration.txt' $IPConfig $NICData = 'c:\rs-pkgs\MR-NICData-Premigration.csv' #file location for the pre-migration less-friendly, parsed ipconfig /all output $TotalLines = $IPConfig.length #Total length of the ipconfig /all information $CurrentLine = 0 #The current line number being processed in the ipconfig information $LineInProcess = $IPConfig[$CurrentLine] #The actual line being processed $NICName = "" #Friendly NIC name $Position = 0 #Largely a placeholder variable for the parseline function, which returns two variables $NICCount = 0 #The current count of NICs $DefaultGateway = "" #Default gateway $DNSServer = "" #A single DNS server $DNSServers = "None" #The string that contains a space-delimited list of DNS servers for a NIC $DNSServerCount = 0 #The current count of DNS servers on the current NIC $MACAddress = "" #The MAC address of the current NIC $IPAddress = "" #A single IP address for the current NIC $IPAddresses = @() #The string that contains a space-delimited list of IP addresses for a NIC $SubnetMask = "" #The subnet mask for the current NIC $SkipasSourceFlag = "" #Whether skipassource is enabled $SkipasSourceFlags = @() #All skipassource flags for all IPs #Parsing the ipconfig information and building a simple file for post migration comparison $Outline = "NICName,Description,MAC,Gateway,IPAddress,SkipasSource,DNSServers" Set-content $NICData $Outline while ($CurrentLine -lt $TotalLines) { #Advancing a line in the ipconfig data and setting the line variable $CurrentLine++ $LineInProcess = $IPConfig[$CurrentLine] #Filtering out lines of no length, which will error if ($LineInProcess -ne $Null) { if ($LineInProcess[0] -eq "E") { #Ethernet Adapter #Resetting the variables between NICs $NICName = "" $DefaultGateway = "" $DNSServer = "" $DNSServers = $Null $MACAddress = "" $IPAddress = "" $IPAddresses = @() $SubnetMask = "" $SkipasSourceFlag = "" $SkipasSourceFlags = @() $NICCount++ $NICName,$Position = (Parseline $LineInProcess 17 "*" ":")[0] } else { Switch -casesensitive ($LineInProcess[3]) { "D" #Various fields can be designated by the D here. We'll try and iron out what specifically this is. { Switch -casesensitive ($LineInProcess[6]) { #*D*es*c*ripton "c" { $NICDescription,$Position = (Parseline $LineInProcess 39 "*" ":")[0] } #*D*ef*a*ult Gateway "a" { $DefaultGateway,$Position = (Parseline $LineInProcess 39 "*" ":")[0] } #*D*NS* *Servers " " { $DNSLine = $True $DNSServer, $Position = (Parseline $LineInProcess 39 "*" "%")[0] if (!($DNSServer -like "*:*")) { #Filtering out IPv6 DNS servers. Some ServiceNet adapters have them. $DNSServers=$DNSServer } $CurrentLine++ $LineInProcess = $IPConfig[$CurrentLine] #There are likely multiple DNS servers so we'll gather each While ($DNSLine) { if ($LineInProcess[3] -eq " ") { $DNSServer, $Position = (Parseline $LineInProcess 39 "*" "%")[0] if (!($DNSServer -like "*:*")) { $DNSServers=$DNSServers+" "+$DNSServer } $CurrentLine++ $LineInProcess = $IPConfig[$CurrentLine] } Else { #As we iterate we'll go too far so we have to step back after that $CurrentLine-- $LineInProcess = $IPConfig[$CurrentLine] $DNSLine = $False } } } } } "P" #MAC Address { $MACAddress = (Parseline $LineInProcess 39 "*" ":")[0] } "I" #IP Address/es { #Making sure this is an IPv4 address if ($LineInProcess[6] -eq "4") { $IPAddress = (Parseline $LineInProcess 39 "*" "(")[0] #We'll iterate through the array that was passed by the netsh function and include the skipassource flag for this particular IP foreach ($IP in $NetshArray) { if ($IP.address -eq $IPAddress) { $SkipasSourceFlag = $IP.SkipasSource } } $IPAddresses+=$IPAddress $SkipasSourceFlags+=[string]$SkipasSourceFlag } } "S" #Subnet Mask { $SubnetMask,$Position = (Parseline $LineInProcess 39 "*" "(")[0] } "N" #NetBIOS - we don't care about this but it's the end of a particular NIC's data. It should always be there if it's an Ethernet NIC and TCP-enabled { if ($LineInProcess[6] -eq "B") { for ($i=0; $i -lt $IPAddresses.count; $i++) { $Outline = $NICName+","+$NICDescription+","+$MACAddress+","+$DefaultGateway+","+$IPAddresses[$i]+","+$SkipasSourceFlags[$i]+","+$DNSServers Add-Content $NICData $Outline } } } } } } } } ########################################################################################################### function Get-RouteInformation { #*********************************************************************************************************** #This function gathers the routing table and stores it to c:\rs-pkgs as-is. #*********************************************************************************************************** $Routes = route print Add-Content 'c:\rs-pkgs\Route-Print-Premigration.txt' $Routes } ########################################################################################################### function Get-DiskInformation { #*********************************************************************************************************** #This function gathers information for disks presented to the OS. #*********************************************************************************************************** $Disks = Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.DriveType -ne 5} | Sort-Object -Property Name $MRDiskFile = "C:\rs-pkgs\MR-Disks-Premigration.csv" $Outline = "Drive,Size,Free,Access,DriveType,FileSystem,MediaType,Dirty,VolumeName,Serial" Set-Content $MRDiskFile $Outline if ($Disks.Count -eq $Null) { #If there is a null count that means there is only one disk and we need to process the variable differently $Size = $Disks.Size/1GB $Size = [math]::Round($Size) $Free = $Disks.FreeSpace/1GB $Free = [math]::Round($Free) $Outline = $Disks.Name+","+$Size+","+$Free+","+$Disks.Access+","+$Disks.DriveType+","+$Disks.FileSystem+","+$Disks.MediaType+","+$Disks.VolumeDirty+","+$Disks.VolumeName+","+$Disks.VolumeSerialNumber Add-Content $MRDiskFile $Outline $Count++ } else { #Otherwise we have multiple disks and need to iterate foreach ($Disk in $Disks) { $Size = $Disk.Size/1GB $Size = [math]::Round($Size) $Free = $Disk.FreeSpace/1GB $Free = [math]::Round($Free) $Outline = $Disk.Name+","+$Size+","+$Free+","+$Disk.Access+","+$Disk.DriveType+","+$Disk.FileSystem+","+$Disk.MediaType+","+$Disk.VolumeDirty+","+$Disk.VolumeName+","+$Disk.VolumeSerialNumber Add-Content $MRDiskFile $Outline $Count++ } } if ($Count -gt 0) { return $True } else { return $False } } ########################################################################################################### function Check-rspkgs { #*********************************************************************************************************** #This function determines whether the C:\rs-pkgs file exists and is writable. #*********************************************************************************************************** $ReturnValue = $False #Simple test to see if the directory exists if (!(test-path 'C:\rs-pkgs')) { #Create it if it doesn't new-item 'C:\rs-pkgs' -type directory |out-null } #Test write into the rs-pkgs directory new-item 'C:\rs-pkgs\MigTest.txt' -type file |out-null #If the file exists then the directory is good to proceed if (test-path 'C:\rs-pkgs\MigTest.txt') { #Setting the value we're going to pass and removing the test file $ReturnValue = $True remove-item 'C:\rs-pkgs\MigTest.txt' } #If the error logging directory doesn't exist, create it if (!(test-path "C:\rs-pkgs\Errors")) { new-item 'C:\rs-pkgs\Errors' -type directory |out-null } return $ReturnValue } ########################################################################################################### function IsThisACluster ($Server2003,$Server2008R1) { #*********************************************************************************************************** #This function determines whether or not this node is part of a cluster. If it is we'll recod some data #about the cluster node members #*********************************************************************************************************** Import-Module failoverclusters $Services = get-service #Gathering the services on the local device $ClusterMemberFile = "C:\rs-pkgs\MR-ClusterMembers-Premigration.csv" $Outline = "Name,Id,State" #Setting the header of the cluster node file $IsCluster = $False #Variable for determining if there's a cluster or not. Starting it as false first and we'll change it if we find a valid cluster service #Iterating through the services and if we find a running cluster service then this is a cluster foreach ($Service in $Services) { if ($Service.name -eq "ClusSvc" -and $Service.status -eq "Running") { $IsCluster = $True } } #If this is a cluster we'll gather the state of each node and record it for post-migration remediation if ($IsCluster) { #Writing the header for the CSV Set-Content $ClusterMemberFile $Outline #If the node is 2003 or 2008R1 there are different techniques for gathering the node disposition If ($Server2003 -or $Server2008R1) { $Nodes = cluster node #Iterating through the cluster node report. Starting at line 8 because there's no need to parse through that aspect. for ($i=8; $i -lt $Nodes.length-1;$i+=2) { #Parsing through each line and gathering the appropriate information $NodeName,$Position = Parseline $Nodes[$i] 0 "*" " " if ($Nodes[$i][20] -eq " ") { $NodeID = $Nodes[$i][21] } else { $NodeID = $Nodes[$i][20]+$Nodes[$i][21] } $NodeState,$Position = Parseline $Nodes[$i] 23 "*" " " $Outline = $NodeName+","+$NodeId+","+$NodeState add-Content $ClusterMemberFile $Outline } } else { #Doing the easier post 2008 R2 node gathering. $Nodes = get-clusternode|sort-object -property Name foreach ($Node in $Nodes) { $Outline = $Node.Name+","+$Node.Id+","+$Node.State add-Content $ClusterMemberFile $Outline } } } return $IsCluster } ########################################################################################################### function Get-ClusterStatus { #*********************************************************************************************************** #This function gathers the list of cluster resources and their current owning nodes. The resulting files are stored it to c:\rs-pkgs. #*********************************************************************************************************** #The human-readable file $ClusterGroupsHRFile = 'c:\rs-pkgs\HR-ClusterGroups-Premigration.txt' #CSV for easy manipulation in the future $ClusterGroupsCSVFile = 'c:\rs-pkgs\MR-ClusterGroups-Premigration.csv' #The human-readable file $ClusterResourceHRFile = 'c:\rs-pkgs\HR-ClusterResources-Premigration.txt' #CSV for easy manipulation in the future $ClusterResourceCSVFile = 'c:\rs-pkgs\MR-ClusterResources-Premigration.csv' #Getting the list of groups and their owners $ClusterNodeDisposition = Get-ClusterNode #Getting the list of groups and their owners $ClusterGroupDisposition = $ClusterNodeDisposition | Get-ClusterGroup #Getting the list of groups and their owners $ClusterResourceDisposition = $ClusterGroupDisposition | Get-ClusterResource #Iterating through the resource lists if ($ClusterGroupDisposition.Count -eq 0) { #This means either there are no cluster resource groups or there was a failure. As such we'll flag this and send back to main. return $false } else { #Building headers for the respective group files Set-Content $ClusterGroupsHRFile "Name`t`t`t`tOwnerNode`tState" Set-Content $ClusterGroupsCSVFile "Name,OwnerNode,State" foreach ($Group in $ClusterGroupDisposition) { #In order to make this easier to read we'll adjust the amount of tabs in the output based on the length of the resource name if ($Group.Name.length -lt 16) { $Outline = $Group.Name+"`t`t`t"+$Group.OwnerNode+"`t"+$Group.State } elseif ($Group.Name.length -lt 21) { $Outline = $Group.Name+"`t`t"+$Group.OwnerNode+"`t"+$Group.State } else { $Outline = $Group.Name+"`t"+$Group.OwnerNode+"`t"+$Group.State } #Writing the data to files Add-Content $ClusterGroupsHRFile $Outline $Outline = $Group.Name+","+$Group.OwnerNode+","+$Group.State Add-Content $ClusterGroupsCSVFile $Outline } #Building headers for the respective group files Set-Content $ClusterResourceHRFile "Name`t`t`t`tOwnerNode`tState" Set-Content $ClusterResourceCSVFile "Name,Group,OwnerNode,State" foreach ($Resource in $ClusterResourceDisposition) { #In order to make this easier to read we'll adjust the amount of tabs in the output based on the length of the resource name if ($Resource.Name.length -lt 15) { $Outline = $Resource.Name+"`t`t`t"+$Resource.OwnerGroup.Name+"`t"+$Resource.OwnerNode.Name+"`t"+$Resource.State } elseif ($Resource.Name.length -lt 20) { $Outline = $Resource.Name+"`t`t"+$Resource.OwnerGroup.Name+"`t"+$Resource.OwnerNode.Name+"`t"+$Resource.State } else { $Outline = $Resource.Name+"`t"+$Resource.OwnerGroup.Name+"`t"+$Resource.OwnerNode.Name+"`t"+$Resource.State } #Writing the data to files Add-Content $ClusterResourceHRFile $Outline $Outline = $Resource.Name+","+$Resource.OwnerNode+","+$Resource.State Add-Content $ClusterResourceCSVFile $Outline } return $True } } ########################################################################################################### function Get-ClusterStatus2003 { #*********************************************************************************************************** #This function gathers the list of cluster resources and their current owning nodes. The resulting files are stored it to c:\rs-pkgs. #This is specific to 2003/2008 R1 OS devices that don't have the same PowerShell commands for cluster management #*********************************************************************************************************** #The human-readable file $ClusterGroupsHRFile = 'c:\rs-pkgs\HR-ClusterGroups-Premigration.txt' #CSV for easy manipulation in the future $ClusterGroupsCSVFile = 'c:\rs-pkgs\MR-ClusterGroups-Premigration.csv' $ClusterGroupDisposition = cluster group $TotalLines = $ClusterGroupDisposition.length #Total length of the ipconfig /all information $CurrentLine = 8 #The current line number being processed in the ipconfig information $LineInProcess = "" #The actual line being processed $ResourceName = "" #Cluster resource name $ResourceOwnerNode = "" #Cluster resource owner $ResourceOwnerState = "" #Cluster resource state #Building headers for the respective files Set-Content $ClusterGroupsHRFile "Name`t`t`t`tOwnerNode`tState" Set-Content $ClusterGroupsCSVFile "Name,OwnerNode,State" #Iterating through the resource lists #Getting the list of resources and their owners while ($CurrentLine -lt $TotalLines) { #Resetting variables $ResourceName = "" $ResourceOwnerNode = "" $ResourceState = "" $LineInProcess = $ClusterGroupDisposition[$CurrentLine] #Filtering out lines of no length, which will error if ($LineInProcess -ne $Null) { #Gathering resource name for ($i = 0; $i -le 20; $i++) { $ResourceName+= $LineInProcess[$i] } $ResourceName = [string]$ResourceName.trim() #Gathering resource owner for ($i = 21; $i -le 36; $i++) { $ResourceOwnerNode+= $LineInProcess[$i] } $ResourceOwnerNode = [string]$ResourceOwnerNode.trim() #Gathering resource state for ($i = 37; $i -le ($LineInProcess.length-1); $i++) { $ResourceState+= $LineInProcess[$i] } $ResourceState = [string]$ResourceState.trim() #Creating output lines based on length if ($ResourceName.length -lt 15) { $Outline = $ResourceName+"`t`t`t"+$ResourceOwnerNode+"`t"+$ResourceState } elseif ($Resource.Name.length -lt 20) { $Outline = $ResourceName+"`t`t"+$ResourceOwnerNode+"`t"+$ResourceState } else { $Outline = $ResourceName+"`t"+$ResourceOwnerNode+"`t"+$ResourceState } #Writing the data to files Add-Content $ClusterGroupsHRFile $Outline $Outline = $ResourceName+","+$ResourceOwnerNode+","+$ResourceState Add-Content $ClusterGroupsCSVFile $Outline } #There's a blank line between entries so we might as well skip it $CurrentLine+=2 } return $True } ########################################################################################################### function Get-ClusterIPs { #*********************************************************************************************************** #This function gathers all cluster IPs and writes them to a file for post-migration comparison. #*********************************************************************************************************** #This command gets all cluster resources and digs deeper into the specific IP addresses. $HRClusterIPFile = 'c:\rs-pkgs\HR-ClusterIPs-Premigration.txt' $MRClusterIPFile = 'c:\rs-pkgs\MR-ClusterIPs-Premigration.txt' $ClusterIPResources = Get-ClusterResource |where-object {$_.ResourceType -like "*IP Address*"}|Get-ClusterParameter |where-object {$_.name -eq "Address"} |Sort-Object Value #Creating the new file $Outline = "Object`t`t`tValue" set-content $HRClusterIPFile $Outline $Outline = "Object,Value" set-content $MRClusterIPFile $Outline #Dropping values in the file if ($ClusterIPResources.Count -eq 0) { return $False } else { foreach ($IP in $ClusterIPResources) { $Outline = [string]$IP.ClusterObject+","+[string]$IP.Value Add-Content $MRClusterIPFile $Outline $Outline = [string]$IP.ClusterObject+"`t`t"+[string]$IP.Value Add-Content $HRClusterIPFile $Outline } return $True } } ########################################################################################################### function Get-ClusterIPs2003 { #*********************************************************************************************************** #This function gathers all cluster IPs and writes them to a file for post-migration comparison. #*********************************************************************************************************** #This command gets all cluster resources and digs deeper into the specific IP addresses. $HRClusterIPFile = 'c:\rs-pkgs\HR-ClusterIPs-Premigration.txt' $ClusterResources = cluster resource /priv $TotalLines = $ClusterResources.length #Total length of the ipconfig /all information $CurrentLine = 8 #The current line number being processed in the ipconfig information $Count = 0 #Count of IP lines #Creating the new file set-content $HRClusterIPFile $ClusterResources[4] #Dropping values in the file while ($CurrentLine -lt $TotalLines) { $LineInProcess = $ClusterResources[$CurrentLine] if ($LineInProcess -like "* Address*") { if (!($LineInProcess -like "*Lease*" -or $LineInProcess -like "*Dhcp*" -or $LineInProcess -like "*NetBIOS*" -or $LineInProcess -like "*OverrideAddressMatch*")) { add-content $HRClusterIPFile $LineInProcess $Count++ } } $CurrentLine++ } If ($Count -gt 0) { return $True } else { return $False } } ########################################################################################################### function Log-Local ($LogFile,$Message) { #*********************************************************************************************************** #This function takes an array and logs locally to file. #*********************************************************************************************************** $OutFile = "C:\rs-pkgs\"+$LogFile add-content $OutFile $Message } #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- #BEGIN SCRIPT ########################################################################################################### #Variable Initialization $Cluster = $Null #Is this device a cluster? $Hostname = hostname #Device's hostname $UAC = $Null #This is set to null and we should have a true/false value if the check is successful. This will flag an automation failure if it's still null on evaluation $NetshArray = @() #Array for the IP information that comes from netsh and the skipassource checks $ResponseArray = @() #Collection of items that failed during the $ClusterGather = $False #Array to gather cluster resource groups and owners $ClusterIPGather = $False #Tracks if the various cluster gathering scripts have succeeded or failed $Hard = 0 #Number of hard errors $Soft = 0 #Number of soft errors $Success = 0 #Number of successes $ServerIs2003 = IsServer2003 #Is the server 2003 $ServerIs2008R1 = IsServer2008R1 #Is the server 2008 R1 $ServiceGather = $False #Were we successful in gathering service information? $HyperV = $Null #Hyper-V check variable $VMCount = 0 #Hyper-V VM count used for determining if we've captured Hyper-V VM statues appropriately $DiskCheck = $Null #Disk check variable #******************************************************************************* #Testing for the existence of rs-pkgs and creating it if it's not there. If this fails we'll log to the failure array $RspkgsExists = Check-rspkgs if (!($RspkgsExists)) { $RspkgsSeverity = "hard" $RspkgsVisibility = "public" $RspkgsContext = "auditing" $RspkgsMessage = "Unable to verify C rs-pkgs. Directory still does not exist." $Hard++ } else { $RspkgsSeverity = "success" $RspkgsVisibility = "public" $RspkgsContext = "auditing" $RspkgsMessage = "C rs-pkgs exists and is writable." $Success++ } Log-local "ScriptLog - 2-Hour.txt" "Script Version:`t$ScriptVersion" #******************************************************************************* #Gathering UAC status $UAC = Get-UAC #If UAC is enabled then send to the PSOGenerator function to be collected if ($UAC) { $UACSeverity = "hard" $UACVisibility = "public" $UACContext = "qc" $UACMessage = "Device has User Access Control enabled. This prevents our automated shutdown script from running and will require the device to be manually shut down ahead of the scheduled shut down for automation." $Hard++ } else { $UACSeverity = "success" $UACVisibility = "public" $UACContext = "qc" $UACMessage = "UAC is deactivated." $Success++ } #Flag automation as failed if there is no value and send to our PSOGenerator if ($UAC -eq $Null) { $UACSeverity = "hard" $UACVisibility = "public" $UACContext = "qc" $UACMessage = "UAC status check failed." $Hard++ } #******************************************************************************* #Checking cluster status and running cluster-specific items if this device is in a cluster. If this fails we'll log to the failure array $Cluster = IsThisACluster $ServerIs2003 $ServerIs2008R1 #$Cluster will be null if the check fails if ($Cluster -eq $Null) { $ClusterCheckSeverity = "hard" $ClusterCheckVisibility = "public" $ClusterCheckContext = "qc" $ClusterCheckMessage = "Unable to determine if this is a cluster." $Hard++ } else { #Log success if cluster check is successful $ClusterCheckSeverity = "success" $ClusterCheckVisibility = "public" $ClusterCheckContext = "qc" $ClusterCheckMessage = "Cluster check successful. $Cluster" $Success++ } #******************************************************************************* #Cluster-specific commands if ($Cluster) { Import-Module failoverclusters if (!($ServerIs2003 -or $ServerIs2008R1)) { #******************************************************************************* #Getting resource groups and owners. If this fails we'll log to the failure array $ClusterGather = Get-ClusterStatus if (!($ClusterGather)) { $ClusterResourceSeverity = "hard" $ClusterResourceVisibility = "public" $ClusterResourceContext = "auditing" $ClusterResourceMessage = "Unable to verify cluster resource status. Cluster resource detection failed." $Hard++ } else { $ClusterResourceSeverity = "success" $ClusterResourceVisibility = "public" $ClusterResourceContext = "auditing" $ClusterResourceMessage = "Cluster resource status recorded." $Success++ } #******************************************************************************* #Getting IPs associated with the cluster nodes. If this fails we'll log to the failure array $ClusterIPGather = Get-ClusterIPs if (!($ClusterIPGather)) { $ClusterIPSeverity = "hard" $ClusterIPVisibility = "public" $ClusterIPContext = "auditing" $ClusterIPMessage = "Unable to verify cluster IPs. Cluster IP detection failed." $Hard++ } else { $ClusterIPSeverity = "success" $ClusterIPVisibility = "public" $ClusterIPContext = "auditing" $ClusterIPMessage = "Cluster IPs identified and recorded." $Success++ } } else { #2003/2008 R1 specific cluster checks #******************************************************************************* #Getting resource groups and owners. If this fails we'll log the failure $ClusterGather = Get-ClusterStatus2003 if (!($ClusterGather)) { $ClusterGather = Get-ClusterStatus2003 if (!($ClusterGather)) { $ClusterResourceSeverity = "hard" $ClusterResourceVisibility = "public" $ClusterResourceContext = "auditing" $ClusterResourceMessage = "Unable to verify cluster resource status. Cluster resource detection failed." $Hard++ } else { $ClusterResourceSeverity = "success" $ClusterResourceVisibility = "public" $ClusterResourceContext = "auditing" $ClusterResourceMessage = "Cluster resource status recorded." $Success++ } } else { $ClusterResourceSeverity = "success" $ClusterResourceVisibility = "public" $ClusterResourceContext = "auditing" $ClusterResourceMessage = "Cluster resource status recorded." $Success++ } $ClusterIPGather = Get-ClusterIPs2003 if (!($ClusterIPGather)) { $ClusterIPGather = Get-ClusterIPs2003 if (!($ClusterIPGather)) { $ClusterIPSeverity = "hard" $ClusterIPVisibility = "public" $ClusterIPContext = "auditing" $ClusterIPMessage = "Unable to verify cluster IPs. Cluster IP detection failed." $Hard++ } else { $ClusterIPSeverity = "success" $ClusterIPVisibility = "public" $ClusterIPContext = "auditing" $ClusterIPMessage = "Cluster IPs identified and recorded." $Success++ } } else { $ClusterIPSeverity = "success" $ClusterIPVisibility = "public" $ClusterIPContext = "auditing" $ClusterIPMessage = "Cluster IPs identified and recorded." $Success++ } } } #******************************************************************************* #Server 2003-specific commands if ($ServerIs2003) { $NetshSeverity = "success" $NetshVisibility = "public" $NetshContext = "auditing" $NetshMessage = "Server is 2003. Netsh and skipassource data not required." $Success++ } else { #******************************************************************************* #Auditing the skipassource settings. If this fails (i.e. the first entry in the array is null we'll log to the failure array $NetshArray = Get-NetshInformation if ($NetshArray[0] -eq $Null) { $NetshSeverity = "hard" $NetshVisibility = "public" $NetshContext = "auditing" $NetshMessage = "Netsh gather failure. Netsh data null" $Hard++ } else { $NetshSeverity = "success" $NetshVisibility = "public" $NetshContext = "auditing" $NetshMessage = "IP settings gathered successfully and recorded." $Success++ } } #******************************************************************************* #Gathering the IP information and storing the data locally Get-IPConfiguration $NetshArray #******************************************************************************* #Gathering the Service information and storing the data locally $ServiceGather = Get-ServiceConfiguration if (!($ServiceGather)) { $ServiceGather = Get-ServiceConfiguration if (!($ServiceGather)) { $ServiceConfigSeverity = "hard" $ServiceConfigVisibility = "public" $ServiceConfigContext = "auditing" $ServiceConfigMessage = "Failure to gather service information." $Hard++ } else { $ServiceConfigSeverity = "success" $ServiceConfigVisibility = "public" $ServiceConfigContext = "auditing" $ServiceConfigMessage = "Gathered service information successfully." $Success++ } } else { $ServiceConfigSeverity = "success" $ServiceConfigVisibility = "public" $ServiceConfigContext = "auditing" $ServiceConfigMessage = "Gathered service information successfully." $Success++ } #******************************************************************************* #Hyper-V-specific commands $HyperV = IsThisHyper-V #$HyperV will be null if the check fails if ($HyperV -eq $Null) { $HyperV = IsThisHyper-V if ($HyperV -eq $Null) { $HyperVCheckSeverity = "hard" $HyperVCheckVisibility = "public" $HyperVCheckContext = "qc" $HyperVCheckMessage = "Unable to determine if this is a HyperV." $Hard++ } else { #Log success if HyperV check is successful $HyperVCheckSeverity = "success" $HyperVCheckVisibility = "public" $HyperVCheckContext = "qc" $HyperVCheckMessage = "HyperV check successful. $HyperV" $Success++ } } else { #Log success if HyperV check is successful $HyperVCheckSeverity = "success" $HyperVCheckVisibility = "public" $HyperVCheckContext = "qc" $HyperVCheckMessage = "HyperV check successful. $HyperV" $Success++ } #Checking status of Hyper-V VMs if ($HyperV) { $VMCount = Get-HyperVVMStatuses if ($VMCount -lt 1) { $VMCount = Get-HyperVVMStatuses if ($VMCount -lt 1) { $HyperVVMCheckSeverity = "hard" $HyperVVMCheckVisibility = "public" $HyperVVMCheckContext = "qc" $HyperVVMCheckMessage = "Unable to verify VM statuses. $VMCount" $Hard++ } else { $HyperVVMCheckSeverity = "success" $HyperVVMCheckVisibility = "public" $HyperVVMCheckContext = "qc" $HyperVVMCheckMessage = "VM statuses verified. $VMCount" $Success++ } } else { $HyperVVMCheckSeverity = "success" $HyperVVMCheckVisibility = "public" $HyperVVMCheckContext = "qc" $HyperVVMCheckMessage = "VM statuses verified. $VMCount" $Success++ } } #******************************************************************************* #Gathering disk information $DiskCheck = Get-DiskInformation if (!($DiskCheck) -or $DiskCheck -eq $Null) { $DiskCheck = Get-DiskInformation if (!($DiskCheck) -or $DiskCheck -eq $Null) { $DiskCheckSeverity = "hard" $DiskCheckVisibility = "public" $DiskCheckContext = "auditing" $DiskCheckMessage = "Failure to gather disk information." $Hard++ } else { $DiskCheckSeverity = "success" $DiskCheckVisibility = "public" $DiskCheckContext = "auditing" $DiskCheckMessage = "Gathered disk information successfully." $Success++ } } else { $DiskCheckSeverity = "success" $DiskCheckVisibility = "public" $DiskCheckContext = "auditing" $DiskCheckMessage = "Gathered disk information successfully." $Success++ } #******************************************************************************* #Writing RBA output write-output "RBA START STATUS:" write-output "{" write-output "`"success`": $Success, " write-output "`"soft`": $Soft, " write-output "`"hard`": $Hard , " write-output "`"scriptversion`": $ScriptVersion " write-output "}" write-output "RBA END STATUS:" write-output "RBA START DATA:" write-output "[" write-output "`t{" write-output "`t`t`"scriptversion`": `"$ScriptVersion`" " write-output "`t}," #rs-pkgs output write-output "`t{" write-output "`t`t`"testname`": `"rspkgs`"," write-output "`t`t`"severity`": `"$RspkgsSeverity`"," write-output "`t`t`"visibility`": `"$RspkgsVisibility`"," write-output "`t`t`"context`": `"$RspkgsContext`"," write-output "`t`t`"message`": `"$RspkgsMessage`"" write-output "`t}," #UAC Output write-output "`t{" write-output "`t`t`"testname`": `"UAC`"," write-output "`t`t`"severity`": `"$UACSeverity`"," write-output "`t`t`"visibility`": `"$UACVisibility`"," write-output "`t`t`"context`": `"$UACContext`"," write-output "`t`t`"message`": `"$UACMessage`"" write-output "`t}," #Cluster check output write-output "`t{" write-output "`t`t`"testname`": `"Cluster`"," write-output "`t`t`"severity`": `"$ClusterCheckSeverity`"," write-output "`t`t`"visibility`": `"$ClusterCheckVisibility`"," write-output "`t`t`"context`": `"$ClusterCheckContext`"," write-output "`t`t`"message`": `"$ClusterCheckMessage`"" write-output "`t}," if ($Cluster) { #Cluster resource gather change output write-output "`t{" write-output "`t`t`"testname`": `"ClusterResource`"," write-output "`t`t`"severity`": `"$ClusterResourceSeverity`"," write-output "`t`t`"visibility`": `"$ClusterResourceVisibility`"," write-output "`t`t`"context`": `"$ClusterResourceContext`"," write-output "`t`t`"message`": `"$ClusterResourceMessage`"" write-output "`t}," #Cluster IP gather output write-output "`t{" write-output "`t`t`"testname`": `"ClusterIP`"," write-output "`t`t`"severity`": `"$ClusterIPSeverity`"," write-output "`t`t`"visibility`": `"$ClusterIPVisibility`"," write-output "`t`t`"context`": `"$ClusterIPContext`"," write-output "`t`t`"message`": `"$ClusterIPMessage`"" write-output "`t}," } #Netsh check output write-output "`t{" write-output "`t`t`"testname`": `"Netsh`"," write-output "`t`t`"severity`": `"$NetshSeverity`"," write-output "`t`t`"visibility`": `"$NetshVisibility`"," write-output "`t`t`"context`": `"$NetshContext`"," write-output "`t`t`"message`": `"$NetshMessage`"" write-output "`t}," #ServiceConfig gather output write-output "`t{" write-output "`t`t`"testname`": `"Services`"," write-output "`t`t`"severity`": `"$ServiceConfigSeverity`"," write-output "`t`t`"visibility`": `"$ServiceConfigVisibility`"," write-output "`t`t`"context`": `"$ServiceConfigContext`"," write-output "`t`t`"message`": `"$ServiceConfigMessage`"" write-output "`t}," #Hyper-V check output write-output "`t{" write-output "`t`t`"testname`": `"HyperV`"," write-output "`t`t`"severity`": `"$HyperVCheckSeverity`"," write-output "`t`t`"visibility`": `"$HyperVCheckVisibility`"," write-output "`t`t`"context`": `"$HyperVCheckContext`"," write-output "`t`t`"message`": `"$HyperVCheckMessage`"" write-output "`t}," if ($HyperV) { #Cluster resource gather change output write-output "`t{" write-output "`t`t`"testname`": `"HyperVVms`"," write-output "`t`t`"severity`": `"$HyperVVMCheckSeverity`"," write-output "`t`t`"visibility`": `"$HyperVVMCheckVisibility`"," write-output "`t`t`"context`": `"$HyperVVMCheckContext`"," write-output "`t`t`"message`": `"$HyperVVMCheckMessage`"" write-output "`t}," } write-output "`t{" write-output "`t`t`"testname`": `"Disks`"," write-output "`t`t`"severity`": `"$DiskCheckSeverity`"," write-output "`t`t`"visibility`": `"$DiskCheckVisibility`"," write-output "`t`t`"context`": `"$DiskCheckContext`"," write-output "`t`t`"message`": `"$DiskCheckMessage`"" write-output "`t}" #Writing footer write-output "]" write-output "RBA END DATA:"