Param ( [Parameter(Mandatory=$False,Position=0)][string]$Version = "2.1", #Script version [switch]$GUI, #Are we invoking this from the GUI [Parameter(Mandatory=$True,Position=0)][string]$MG #Script version ) ############################################################################################################################# #region - Setup custom functions #**************************************************************************************************************************# #**************************************************************************************************************************# #endregion ############################################################################################################################# #Setting up environment #Setting TLS version [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 #Getting start time $Stopwatch = [system.diagnostics.stopwatch]::startNew() #Getting the current directory and importing the CTKCore module $Dir=(Get-Item -Path . -Verbose).FullName if ($GUI) { $CTKModule = $Dir+"\Modules\CTKCore\CTKCore.psm1" $ExcelModule = $Dir+"\Modules\ExcelHandlers\ExcelHandlers.psm1" } else { $CTKModule = [string]((get-item $Dir).parent.fullname)+"\Modules\CTKCore\CTKCore.psm1" $ExcelModule = [string]((get-item $Dir).parent.fullname)+"\Modules\ExcelHandlers\ExcelHandlers.psm1" } Import-Module $CTKModule -force -DisableNameChecking Import-Module $ExcelModule -force -DisableNameChecking #Testing Core token and obtaining one if we don't have one try {$Testing = Get-CoreDevice -Device 879665} catch {Get-CoreToken} #endregion ############################################################################################################################# #region - Import Session Functions #Import functions from the current session into the RunspacePool session state #Create runspace session state $InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault() # Import all session functions into the runspace session state from the current one Get-ChildItem Function:\ | Where-Object {$_.name -notlike "*:*"} | select name -ExpandProperty name | ForEach-Object { # Get the function code $Definition = Get-Content "function:\$_" -ErrorAction Stop # Create a sessionstate function with the same name and code $SessionStateFunction = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList "$_", $Definition # Add the function to the session state $InitialSessionState.Commands.Add($SessionStateFunction) } #endregion ############################################################################################################################# #region - Creating move groups, file locations and querying $NSIURI = "https://dbapi.nsi.rackspace.com/migration/dfw1/Find" #URI for the NSI API $Destination_File = $Dir+"\$MG-DeviceStatusCheck.xlsx" #Result Excel file $Limit = 10 #Max runspace threads $Jobs = New-Object System.Collections.ArrayList #Creating an array for our jobs $TempDir = $Dir+"\Temp\" #Where we're storing the temporary files $CurrentDevice = 0 #Variable to track the current number of jobs created $Row = 1 #Excel row variable $Column = 1 #Excel column variable $Destination_File = $Dir+"\$MG-DeviceStatusCheck.xlsx" #Excel file we're generating #Checking if our temporary directory exists and creating it if it doesn't if (!(Test-Path $TempDir)) { New-Item -Path $TempDir -ItemType directory |Out-Null #Creating a temporary directory for our working files } #NSI JSON $JSON = @" { "query": { "move_group":"$MG" } } "@ #Polling NSI for the API $Results = Invoke-RestMethod -Uri $NSIURI -Body "$JSON" -ContentType "application/json" -Method "POST" -Headers @{"X-Auth"=$Global:Token} -TimeoutSec 120 #endregion ############################################################################################################################# #region - Runspace Pool Setup # Create a Runspace Pool that uses the defined session state $RunspacePool = [RunspaceFactory]::CreateRunspacePool($InitialSessionState) $RunspacePool.SetMinRunspaces(1) | Out-Null $RunspacePool.SetMaxRunspaces($Limit) | Out-Null $PowerShell = [powershell]::Create() $PowerShell.RunspacePool = $RunspacePool $RunspacePool.Open() #endregion ############################################################################################################################# #region - build jobs for runspace to run in the background Write-Progress -Activity "Building jobs - $($Results.result.count) remaining." -PercentComplete 0 -Status "Percent complete - 0%" Write-Progress -Activity "Processing jobs - 0 of $Limit threads running. 0 jobs remaining." -PercentComplete 0 -Status "Percent complete - 0%" -id 1 Write-Progress -Activity "Processing temporary files and building Excel file." -PercentComplete 0 -Status "Percent complete - 0%" -id 2 #Processing devices from NSI poll ForEach ($Device in $Results.Result) { $CurrentDevice++ #Keeping track of numbers of devices #Calculating and writing progress $JobPercentComplete = ($CurrentDevice/$Results.result.count)*100 $JobPercentComplete = "{0:N0}" -f $JobPercentComplete Write-Progress -Activity "Building jobs - $($Results.result.count - $CurrentDevice) remaining." -PercentComplete $JobPercentComplete -Status "Percent complete - $JobPercentComplete%" #If device is actually in NSI we'll go through and build a job to poll Core for device statuses if ($Device.deleted -ne "true") { #Creating the space for the job $PowerShell = [powershell]::Create() #Assigning the runspace to the job space $PowerShell.RunspacePool = $RunspacePool #Generating parameter list for the job $ParamList = @{ OS = $Device.device.os DeviceNumber = $Device._id Directory = $TempDir } #Define the script to be run $MyScript = { Param ( $OS, #The OS of the polled device $DeviceNumber, #The device number of the polled device $Directory #The directory we're pushing files to ) #Polling Core for device status $COREInfo = get-coredevice $DeviceNumber #If there's no status we need to set the status as CNLA. Otherwise we'll use what we get back from Core. if ($COREInfo.Status -eq $Null) { $Status = "Computer no longer active" } else { $Status = $COREInfo.Status } #Building the individual CSV file for each device $OutFile = $Directory+$DeviceNumber+".csv" $OutLine = "DN,Status,OS" Set-Content $OutFile $Outline $OutLine = [string]$DeviceNumber+","+$Status+","+$OS Add-Content $OutFile $Outline } # Set parameters and values to import into the runspace that will be used in the script [void]$PowerShell.AddScript($MyScript) [void]$PowerShell.AddParameters($ParamList) #Building and generating the job $Handle = $PowerShell.BeginInvoke() $temp = '' | Select PowerShell,Handle $temp.PowerShell = $PowerShell $temp.handle = $Handle [void]$jobs.Add($Temp) } } #endregion ############################################################################################################################# #region - checking job status and writing progress #Starting with all the jobs we generated $Remaining = $Jobs.Count #We'll go through until all the jobs have been addressed while ($Remaining -gt 1) { #Checking the status of each job ForEach ($Job in $Jobs) { if ($Job.handle.iscompleted -eq "Completed") { #If the job is completed shut it down and dispose of it $return = $Job.powershell.EndInvoke($Job.handle) $Job.PowerShell.Dispose() } } #Calculating the progress and writing it appropriately $Remaining = $($($Jobs | Where-Object {$_.Handle.IsCompleted -eq $False}).count) $RunningPercentComplete = (($Jobs.count - $Remaining) / $Jobs.Count * 100) $RunningPercentComplete = "{0:N0}" -f $RunningPercentComplete Write-Progress -Activity "Processing jobs - $($Limit - $($RunspacePool.GetAvailableRunspaces())) of $Limit threads running. $Remaining jobs remaining." -PercentComplete $RunningPercentComplete -Status "Percent complete - $RunningPercentComplete%" -id 1 } #endregion ############################################################################################################################# #region - Creating the Excel object $Excel = New-Object -ComObject excel.application $Excel.visible = $False #$Excel.visible = $True $Excel.displayalerts = $False $OutExcel = $Excel.Workbooks.Add() $OutSheet = $OutExcel.Worksheets.Item(1) $OutSheet.Name = "Device Classification" #endregion ############################################################################################################################# #region - processing our temporary files $AllTempFiles = Get-ChildItem -Path $TempDir -Filter *.csv #Setting the variable for the current file count $CurrentFile = 0 #Writing the headings on the Excel file $OutSheet.cells.Item($Row,$Column) = "Device Number" $Column++ $OutSheet.cells.Item($Row,$Column) = "Status" $Column++ $OutSheet.cells.Item($Row,$Column) = "Type" #Processing all the temporary files ForEach ($File in $AllTempFiles) { $CurrentFile++ #Importing the CSV for the individual device $Device = Import-CSV $File.FullName #Setting the Excel positions $Row++ $Column = 1 #Writing the data in Excel $OutSheet.cells.Item($Row,$Column) = $Device.DN $Column++ $OutSheet.cells.Item($Row,$Column) = $Device.Status $Column++ $OutSheet.cells.Item($Row,$Column) = $Device.OS #Calculating the progress and writing it appropriately $ExcelPercentComplete = ($CurrentFile/$Jobs.Count * 100) $ExcelPercentComplete = "{0:N0}" -f $ExcelPercentComplete Write-Progress -Activity "Processing temporary files and building Excel file." -PercentComplete $ExcelPercentComplete -Status "Percent complete - $ExcelPercentComplete%" -id 2 } #Making the Excel table and moving to cell A1 MakeTable "$MG" "A" 1 "C" $Row $OutSheet $Excel GoHome $OutSheet #endregion ############################################################################################################################# #region - Closing down Excel $OutExcel.Saveas($Destination_File) $OutExcel.Close($True) $Excel.Quit() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel) | Out-Null Remove-Variable Excel #endregion ############################################################################################################################# #region - Cleaning up temporary files ForEach ($File in $AllTempFiles) { Remove-Item $File.FullName } Remove-Item $TempDir #endregion ############################################################################################################################# #Timing functions $Stopwatch.stop() write-host write-host "Complete." -foregroundcolor "green" write-host write-host "Execution time: $($Stopwatch.Elapsed.Minutes) minutes $($Stopwatch.Elapsed.Seconds) seconds." -foregroundcolor "green" write-host