Public/Invoke-SPORequest.ps1

<#
.Synopsis
This script is used to check .
 
.Description
This script will query all key points for drive V Bitlocker encryption and check Hyper-V
service status.
 
It's better to save result into variable. Because this script will run a bit longer.
 
Note: The parameter Credential is different with common. This credential just used to query
DSE's PMs. It will not take effect, if the input PM array not contains DSE's PM.
 
Script can accept pipe input by zone or PM name. Please refer in exmaples.
It's querying in batch mode by PowerShell job. It will return PS object array as result.
The returned object include below customed properties:
 
.Parameter ComputerName
PMachine name array. It's accept pipeline input.
Alias are "Cn" and "MachineName".
 
.Parameter ZoneId
Zone Id. It's accept pipeline input by property name.
 
.Parameter CheckType
Accept array input including "TestDriveV", "CheckKeyProtector", "CheckCert", "CheckUnlockService" and "CheckHyperVService".
Alias is "Type".
 
 
.Parameter Credential
Your ada account credential. It's just for DSE's PM querying.
It will not take effect if the PM list not contains DSE's PM.
 
.Example
$result = 6,7 | CheckBitLocker.ps1 -Credential $ada_cred
This example is querying all checking types for all PMs in zone 6 and 7 both.
 
.Example
$result = $PMName | CheckBitLocker.ps1 -Credential $ada_cred -Type "TestDriveV", "CheckKeyProtector"
This example is querying checking types "TestDriveV", "CheckKeyProtector" for PMs stored in variable PMName.
 
.Outputs
PSObject[]
 
 
==========================================
changelogs:
 
12/4: Add Test-Ping function to export BadPMs as txt file
 
#>

function Invoke-SPORequest2 {
    param (
    
        [Parameter(Mandatory = $true, ParameterSetName = "cn",
            ValueFromPipeline = $true)]
        [Alias("Cn", "MachineName")]
        [String[]]$ComputerName,
        [Parameter(Mandatory = $true, ParameterSetName = "dc",
            #ValueFromPipelineByPropertyName=$true,
            ValueFromPipeline = $true)]
        [string[]]$DCName,
        [ValidateSet("TestDriveV", "CheckKeyProtector", "CheckCert", "CheckUnlockService", "CheckHyperVService", "CheckPM","CheckVM")]
        [Alias("Type")]
        [String[]]$CheckType = @("TestDriveV", "CheckKeyProtector", "CheckCert", "CheckUnlockService", "CheckHyperVService", "CheckPM","CheckVM"),
        [PSCredential]$Credential
    )


    begin {

        $PMachines = @()
        $CheckResult = @()
        $Properties = @()

        #region scriptblock

        $TestDriveV = {
            $hasV = Test-Path V:\
            return New-Object -TypeName PSObject -Property @{hasDriveV = $hasV; ComputerName = $env:COMPUTERNAME }
        }


        $CheckServerHealth = {


            $ret = (Get-Date) - (gcim Win32_OperatingSystem).LastBootUpTime
                    
            if ($ret) {
                # save status
                $day = $ret.Days
                $uptimeStatus = "$day Days"
                $ping = $true;

                return [PSCustomObject]@{
                    ComputerName = $env:COMPUTERNAME
                    Status       = $uptimeStatus
                         
                }
            }
            else {
                return [PSCustomObject]@{
                    ComputerName = $env:COMPUTERNAME
                    Status       = "Offline"
                         
                }
                
            }
        }


        $CheckKeyProtector = {
            $v = Get-BitLockerVolume V -ErrorAction Ignore
            if ($v) {
                return New-Object -TypeName PSObject -Property @{
                    Exist            = $true
                    LockStatus       = $v.LockStatus.ToString(); 
                    ProtectionStatus = $v.ProtectionStatus.ToString(); 
                    KeyProtector     = $v.KeyProtector;
                    ComputerName     = $env:COMPUTERNAME
                }
            }
            else {
                return New-Object -TypeName PSObject -Property @{
                    Exist            = $false
                    LockStatus       = $null 
                    ProtectionStatus = $null
                    KeyProtector     = $null
                    ComputerName     = $env:COMPUTERNAME
                }
           
            }
        }

        $CheckCert = {
            $Cert = Get-Item Cert:\LocalMachine\My\BD8F9B5FDD339C0383B35CE89F0745720533DC74 -ErrorAction Ignore
            if ($Cert) {

                #Add check cert key value from registry.
                $key_path = 'HKLM:\SOFTWARE\Policies\Microsoft\FVE'
                $ip = (Get-ItemProperty -Path $key_path -ErrorAction Ignore)

                if ($ip) {
                    $KeyName = @($ip | Get-Member | Where-Object Name -match '^v2' | Select-Object -ExpandProperty Name)
                }
                return New-Object -TypeName PSObject -Property @{Exist = $true; Cert = $Cert; KeyName = $KeyName; ComputerName = $env:COMPUTERNAME }
            }
            else { return New-Object -TypeName PSObject -Property @{Exist = $false; Cert = $null; KeyName = $null; ComputerName = $env:COMPUTERNAME } }
        }

        $CheckUnlockService = {
    
            $Version = 2
            $Service = Get-WmiObject -Query "select * from Win32_service where Name='BitLockerUnlockService'"

            if (!$Service) {
                $Service = Get-WmiObject -Query "select * from Win32_service where Name='BitLockerUnlockingService'"
                $Version = 1
            }

            if ($Service) {
                $PathName = $Service.PathName
                $FileExisted = Test-Path $PathName
                return New-Object -TypeName PSObject -Property @{
                    Exist        = $true
                    Version      = $Version
                    Name         = $Service.Name
                    State        = $Service.State.ToString()
                    FilePath     = $PathName
                    FileExisted  = $FileExisted
                    ComputerName = $env:COMPUTERNAME
                }
            }
            else {
                return New-Object -TypeName PSObject -Property @{
                    Exist        = $false
                    Version      = $null
                    Name         = $null
                    State        = $null
                    FilePath     = $null
                    FileExisted  = $null
                    ComputerName = $env:COMPUTERNAME
                }
            }
        }

        $CheckHyperVService = {
            $Service = Get-Service vmms -ErrorAction Ignore

            if ($Service) {
                $KeyProperty = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\VMMS"
                return New-Object -TypeName PSObject -Property @{
                    Exist           = $true
                    Name            = $Service.Name
                    State           = $Service.Status.ToString()
                    DependOnService = $KeyProperty.DependOnService
                    ComputerName    = $env:COMPUTERNAME
                }
            }
            else {
                return New-Object -TypeName PSObject -Property @{
                    Exist           = $false
                    Name            = $null
                    State           = $null
                    DependOnService = $null
                    ComputerName    = $env:COMPUTERNAME
                }
            }
        }

        $CheckNetFrameworkV4 = {
            $V4 = Get-ItemProperty -Path 'HKLM:SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' -ErrorAction Ignore
            if ($V4 -and $V4.Release -ge 461808) {
                return New-Object -TypeName PSObject -Property @{
                    Exist         = $true
                    ReleaseVerion = $V4.Release
                    ComputerName  = $env:COMPUTERNAME
                }
            }
            else {
                return New-Object -TypeName PSObject -Property @{
                    Exist         = $false
                    ReleaseVerion = $null
                    ComputerName  = $env:COMPUTERNAME
                }
            }
        }

        $CheckNetFrameworkV35 = {

            $V35 = Get-ItemProperty -Path 'HKLM:SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5' -ErrorAction Ignore

            if ($V35) {
                return New-Object -TypeName PSObject -Property @{
                    Exist        = $V35.Installed
                    ComputerName = $env:COMPUTERNAME
                }
            }
            else {
                return New-Object -TypeName PSObject -Property @{
                    Exist         = $false
                    ReleaseVerion = $null
                    ComputerName  = $env:COMPUTERNAME
                }
            }
    
        }


        $CheckVMHealth = {
            $Service = Get-Service vmms -ErrorAction Ignore

            if ($Service) 
            {

                $allVMs = Get-VM
                if($allVMs)
                {
                    $vms = @()
                    $offVm = Get-VM | where-object State -eq off
                    if($offVm)
                    {
                        $offVM | % { $vms +=$_.name+","}
                        $vms = $vms.substring(0,$vms.length-1)
                        $vmstate = 'offline'
                    }#end offVv

                    $onlineVm = Get-VM | ? State -eq running
                    if($onlineVm)
                    {
                        $onlineVM | % { $vms +=$_.name+","}
                        $vms = $vms.substring(0,$vms.length-1)
                        $vmstate = 'running'
                    }#end onlineVM

                    return New-Object -TypeName PSObject -Property @{
                        VMList            = $vms
                        State           = $vmstate
                        ComputerName    = $env:COMPUTERNAME
                    }
                }
                else{

                    return New-Object -TypeName PSObject -Property @{
                        VMList            = 'No VMs'
                        State           = 'NotDeploy'
                        ComputerName    = $env:COMPUTERNAME
                    }
                }
            }
            else {
                return New-Object -TypeName PSObject -Property @{
                    VMList            = 'No VMs'
                    State           = 'NoService'
                    ComputerName    = $env:COMPUTERNAME
                }
            }
        }


        #endregion




        #region Nested function

        function ExecuteTesting {

            param (
                [String[]]$PMachines,
                [PSCredential]$Credential
            )
        
            Write-Host ("`nPM count: {0}" -f $PMachines.Count) -ForegroundColor Green
            
        
            # Test the PMs are pingable.
            <#
            $BadPMs = @(Test-MachineConnectivity -ComputerName $PMachines -ReturnBad)
         
            if ($BadPMs.Count -gt 0) {
                Write-Host ("PMs: {0} cannot be reachable.`n" -f (Convert-ArrayAsString $BadPMs)) -ForegroundColor Red
                
            }
         
            
         
            $PMachines = @($PMachines | Where-Object { $BadPMs -notcontains $_ })
            #>

            # Starting to check
            if ($PMachines.Count -gt 0) {
            
                $Properties = @()
                foreach ($pm in $PMachines) {
                    $Properties += @{ComputerName=$pm}
                }
        
              
        
                  #region step 1: Check PM.
            
                if ($CheckType -contains "CheckPM") {
        
                    Write-Host "Starting to CheckingPM... " -NoNewline
        
                    if (!$Credential) {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckServerHealth -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Checking PM ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckServerHealth -ComputerName $PMachines
                        }
                    }
                    else {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckServerHealth -ComputerName $PMachines -AsJob -Credential $Credential | Watch-Jobs -Activity "Checking PM ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckServerHealth -ComputerName $PMachines -Credential $Credential
                        }
                    }
        
                    foreach ($r in $Result) {
                        
                        $Properties | Where-Object {$_.ComputerName -eq $r.ComputerName} | foreach-object {
                            
                            $_.Add("Status", $r.Status)
                            
                            
                        }
        
                    }
                    
                    
        
                    Write-Host "Done" -ForegroundColor Green
        
                }
            
                #endregion
        
        
                #region step 1: Test drive V.
            
                if ($CheckType -contains "TestDriveV") {
        
                    Write-Host "Starting to test drive V ... " -NoNewline
        
                    if (!$Credential) {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $TestDriveV -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Testing drive V ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $TestDriveV -ComputerName $PMachines
                        }
                    }
                    else {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $TestDriveV -ComputerName $PMachines -AsJob -Credential $Credential | Watch-Jobs -Activity "Testing drive V ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $TestDriveV -ComputerName $PMachines -Credential $Credential
                        }
                    }
        
                    foreach ($r in $Result) {
                        
                        $Properties | Where-Object {$_.ComputerName -eq $r.ComputerName} | foreach-object {
                            $_.Add("hasDriveV", $r.hasDriveV)
                            
                        }
        
                    }
        
                    Write-Host "Done" -ForegroundColor Green
        
                }
            
                #endregion
        
        
                #region step 2: Check lock state.
        
                if ($CheckType -contains "CheckKeyProtector") {
        
                    Write-Host "Starting to check key protector ... " -NoNewline
        
                    if (!$Credential) {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckKeyProtector -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Checking Key Protector ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckKeyProtector -ComputerName $PMachines
                        }
                    }
                    else {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckKeyProtector -ComputerName $PMachines -Credential $Credential -AsJob | Watch-Jobs -Activity "Checking Key Protector ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckKeyProtector -ComputerName $PMachines -Credential $Credential
                        }
                    }
        
                    foreach ($r in $Result) {
        
                        $Properties | Where-Object {$_.ComputerName -eq $r.ComputerName} | foreach-object {
                            $_.Add("BitlockerExist", $r.Exist)
                            $_.Add("LockStatus", $r.LockStatus)
                            $_.Add("ProtectionStatus", $r.ProtectionStatus)
                            $_.Add("KeyProtector", $r.KeyProtector)
                        }
                        
                    }
        
                    Write-Host "Done" -ForegroundColor Green
        
                }
             
        
                #endregion
        
        
                #region step 3: Check cert.
        
                if ($CheckType -contains "CheckCert") {
        
                    Write-Host "Starting to check certificate ... " -NoNewline
        
                    if (!$Credential) {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckCert -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Checking certificate ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckCert -ComputerName $PMachines
                        }
                    }
                    else {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckCert -ComputerName $PMachines -Credential $Credential -AsJob | Watch-Jobs -Activity "Checking certificate ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckCert -ComputerName $PMachines -Credential $Credential
                        }
                    }
        
                    foreach ($r in $Result) {
        
                        $Properties | Where-Object {$_.ComputerName -eq $r.ComputerName} | foreach-object {
                            $_.Add("CertExist", $r.Exist)
                            $_.Add("Cert", $r.Cert)
                            $_.Add("KeyName", $r.KeyName)
                        }
                    }
        
                    Write-Host "Done" -ForegroundColor Green
        
                }
        
                #endregion
        
        
                #region step 4: Cert key value in registry.
        
                # Merged into "check cert".
        
        
                #endregion
        
        
                #region Step 5: Check bitlocker unlocking service
        
                # Including framework 3.5 & 4 checking.
        
                if ($CheckType -contains "CheckUnlockService") {
        
                    Write-Host "Starting to check unlock service ... " -NoNewline
        
                    if (!$Credential) {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckUnlockService -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Checking Unlock Service ..."
                            $V35Result = Invoke-Command -ScriptBlock $CheckNetFrameworkV35 -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Checking Net framework V3.5 ..."
                            $V4Result = Invoke-Command -ScriptBlock $CheckNetFrameworkV4 -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Checking Net framework V4 ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckUnlockService -ComputerName $PMachines
                            $V35Result = Invoke-Command -ScriptBlock $CheckNetFrameworkV35 -ComputerName $PMachines
                            $V4Result = Invoke-Command -ScriptBlock $CheckNetFrameworkV4 -ComputerName $PMachines
                        }
                    }
                    else {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckUnlockService -ComputerName $PMachines -Credential $Credential -AsJob | Watch-Jobs -Activity "Checking Unlock Service ..."
                            $V35Result = Invoke-Command -ScriptBlock $CheckNetFrameworkV35 -ComputerName $PMachines -Credential $Credential -AsJob | Watch-Jobs -Activity "Checking Net framework V3.5 ..."
                            $V4Result = Invoke-Command -ScriptBlock $CheckNetFrameworkV4 -ComputerName $PMachines -Credential $Credential -AsJob | Watch-Jobs -Activity "Checking Net framework V4 ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckUnlockService -ComputerName $PMachines -Credential $Credential
                            $V35Result = Invoke-Command -ScriptBlock $CheckNetFrameworkV35 -ComputerName $PMachines -Credential $Credential
                            $V4Result = Invoke-Command -ScriptBlock $CheckNetFrameworkV4 -ComputerName $PMachines -Credential $Credential
                        }
                    }
        
                    foreach ($r in $Result) {
        
                        $Properties | Where-Object {$_.ComputerName -eq $r.ComputerName} | foreach-object {
                            $_.Add("UnlockServiceExist", $r.Exist)
                            $_.Add("UnlockServiceVersion", $r.Version)
                            $_.Add("UnlockServiceState", $r.State)
                            $_.Add("UnlockServiceFileExist", $r.FileExisted)
                            if ($r.Version -eq 1) { 
                                $V35Exist = $V35Result | Where-Object ComputerName -eq $r.ComputerName | Select-Object -ExpandProperty Exist
                                $_.Add("V35Exist", $V35Exist) 
                            }
                            elseif ($r.Version -eq 2) { 
                                $V4Exist = $V4Result | Where-Object ComputerName -eq $r.ComputerName | Select-Object -ExpandProperty Exist
                                $_.Add("V4Exist", $V4Exist) 
                            }
                        }
                    }
        
                    
        
                    Write-Host "Done" -ForegroundColor Green
        
                }
        
                #endregion
        
        
                #region step 6: check service 'vmms'
        
                if ($CheckType -contains "CheckHyperVService") {
        
                    Write-Host "Starting to check Hyper-V service ... " -NoNewline
        
                    if (!$Credential) {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckHyperVService -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Checking Hyper-V Service ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckHyperVService -ComputerName $PMachines
                        }
                    }
                    else {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckHyperVService -ComputerName $PMachines -Credential $Credential -AsJob | Watch-Jobs -Activity "Checking Hyper-V Service ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckHyperVService -ComputerName $PMachines -Credential $Credential
                        }
                    }
        
                    foreach ($r in $Result) {
        
                        $Properties | Where-Object {$_.ComputerName -eq $r.ComputerName} | foreach-object {
                            $_.Add("HyperVServiceExist", $r.Exist)
                            $_.Add("HyperVServiceState", $r.State)
                            $_.Add("HyperVServiceDependOn", $r.DependOnService)
                        }
                    }
        
                    Write-Host "Done" -ForegroundColor Green
        
                }
        
                #endregion


                #region : check VMs
        
                if ($CheckType -contains "CheckVM") {
        
                    Write-Host "Starting to CheckVM ... " -NoNewline
        
                    if (!$Credential) {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckVMHealth -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Checking CheckVM Service ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckVMHealth -ComputerName $PMachines
                        }
                    }
                    else {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $CheckVMHealth -ComputerName $PMachines -Credential $Credential -AsJob | Watch-Jobs -Activity "Checking CheckVM Service ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $CheckVMHealth -ComputerName $PMachines -Credential $Credential
                        }
                    }
        
                    foreach ($r in $Result) {
                        $Properties | Where-Object {$_.ComputerName -eq $r.ComputerName} | foreach-object {
                            $_.Add("VMList", $r.VMList)
                            $_.Add("State", $r.State)
                        }
                    }
        
                    Write-Host "Done" -ForegroundColor Green
        
                }
        
                #endregion
        
            }
            else {
                Write-Host "No any PM is reachable." -ForegroundColor Red
            }
        
            return $Properties
        
        }


        #endregion

    } # end begin

    process {

        if ($PSCmdlet.ParameterSetName -eq "dc") {
      

        
            $PMachines = @()

            foreach ($item in $DCName) {
                $PMachines += Get-Servers $item

            }



        
            Write-Host "`n`nStarting to check PMs for zone [$DCName]." -ForegroundColor Green
            Write-Host ("Check Type: [{0}]" -f (Convert-ArrayAsString $CheckType)) -ForegroundColor Green
       
    
            # to pull BadPMs from $PMachines and output as file
            <#$BadPMs = Test-Pingable -PMachines $PMachines # -Credential $Credential
        $BadPMs | Out-File $file -Append
        #>


       
            #$PMachines = @($PMachines | Where-Object { $BadPMs -notcontains $_ })
        

            # To find out DSE's PM and ask credential if input is not provide.
            $DSEPMs = FindOutDSEPM -PMachines $PMachines
            if ($DSEPMs.Count -gt 0) {
            
                if (!$Credential) {
                    Write-Verbose "PM list include DSE's PM. Please provide ada account credential!" -ForegroundColor Yellow
                    $Credential = Get-Credential -Message "Your ada account:"
                }

            
                $Properties += ExecuteTesting -PMachines $DSEPMs -Credential $Credential

            

                $PMachines = $PMachines | Where-Object { $DSEPMs -notcontains $_ }
            
            }

        
            $Properties += ExecuteTesting -PMachines $PMachines

                

        }

        if ($PSCmdlet.ParameterSetName -eq "cn") {
            $PMachines += $ComputerName
        

            # to pull BadPMs from $PMachines and output as file
            # $BadPMs = Test-Pingable -PMachines $PMachines -Credential $Credential
            # $BadPMs | Out-File $file -Append
       
           # $PMachines = @($PMachines | Where-Object { $BadPMs -notcontains $_ })
        

            # To find out DSE's PM and ask credential if input is not provide.
            $DSEPMs = FindOutDSEPM -PMachines $PMachines
            if ($DSEPMs.Count -gt 0) {
            
                if (!$Credential) {
                    Write-Host "PM list include DSE's PM. Please provide ada account credential!" -ForegroundColor Yellow
                    $Credential = Get-Credential -Message "Your ada account:"
                }

            
                $Properties += ExecuteTesting -PMachines $DSEPMs -Credential $Credential

                #get only non-DSE PMs
                $PMachines = $PMachines | Where-Object { $DSEPMs -notcontains $_ }

            
            }

        
            $Properties += ExecuteTesting -PMachines $PMachines
        }

    } # end process

    end {
  

        if ($PSCmdlet.ParameterSetName -eq "cn") {
            Write-Host "`n`nStarting to check PM." -ForegroundColor Green
            # Write-Host ("Check Type: [{0}]" -f (Convert-ArrayAsString $CheckType)) -ForegroundColor Green

            #$PMachines

            # to pull BadPMs from $PMachines and output as file
            $BadPMs = Test-Pingable -PMachines $PMachines -Credential $Credential 
        
            $BadPMs | Out-File $file -Force
       
            $PMachines = @($PMachines | Where-Object { $BadPMs -notcontains $_ })
        
               
            # To find out DSE's PM and ask credential if input is not provide.
            $DSEPMs = FindOutDSEPM -PMachines $PMachines
            if ($DSEPMs.Count -gt 0) {
            
                if (!$Credential) {
                    Write-Host "PM list include DSE's PM. Please provide ada account credential!" -ForegroundColor Yellow
                    $Credential = Get-Credential -Message "Your ada account:"
                }

                Write-Host "DSE's PM checking:" -ForegroundColor Green 
                $Properties += ExecuteTesting -PMachines $DSEPMs -Credential $Credential

                $PMachines = $PMachines | Where-Object { $DSEPMs -notcontains $_ }
            }

            Write-Host "PMs checking:" -ForegroundColor Green 
            $Properties += ExecuteTesting -PMachines $PMachines
        }

        # Make objects for return
        if ($Properties.Count -gt 0) {
            foreach ($Property in $Properties) {
                $CheckResult += New-Object -TypeName PSObject -Property $Property
            }
        }
    
        return $CheckResult
   
    } # end end


}


function Invoke-SPORequest {
    param (
    
        [Parameter(Mandatory = $true, ParameterSetName = "cn",
            ValueFromPipeline = $true)]
        [Alias("Cn", "MachineName")]
        [String[]]$ComputerName,
        [Parameter(Mandatory = $true, ParameterSetName = "dc",
            #ValueFromPipelineByPropertyName=$true,
            ValueFromPipeline = $true)]
        [string[]]$DCName,
        [scriptblock]$ScriptBlock,
        [PSCredential]$Credential
    )


    begin {

        $PMachines = @()
        $Properties = @()

        #region Nested function

        function ExecuteTesting {

            param (
                [String[]]$PMachines,
                [PSCredential]$Credential
            )
        
            Write-Verbose ("`nPM count: {0}" -f $PMachines.Count)
            
            # Starting to check
            if ($PMachines.Count -gt 0) {
            
                $Result = @()
                
                    Write-Verbose "Starting to CheckingPM... "
        
                    if (!$Credential) {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $ScriptBlock -ComputerName $PMachines -AsJob | Watch-Jobs -Activity "Checking PM ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $ScriptBlock -ComputerName $PMachines
                        }
                    }
                    else {
                        if ($PMachines.Count -gt 1) {
                            $Result = Invoke-Command -ScriptBlock $ScriptBlock -ComputerName $PMachines -AsJob -Credential $Credential | Watch-Jobs -Activity "Checking PM ..."
                        }
                        else {
                            $Result = Invoke-Command -ScriptBlock $ScriptBlock -ComputerName $PMachines -Credential $Credential
                        }
                    }
      
                    Write-Verbose "Done"
        
                
            }
            else {
                Write-Verbose "No any PM is reachable."
            }
        
            return $Result
        
        }


        #endregion

    } # end begin

    process {

        if ($PSCmdlet.ParameterSetName -eq "dc") {
      

        
            $PMachines = @()

            foreach ($item in $DCName) {
                $PMachines += Get-Servers $item

            }

        
            Write-Verbose "`n`nStarting to check PMs for zone [$DCName]."
        

         $BadPMs = Test-Pingable -PMachines $PMachines # -Credential $Credential

            
            $BadPMs | % { $Properties += $_}

       
            $PMachines = @($PMachines | Where-Object { $BadPMs -notcontains $_ })


            # To find out DSE's PM and ask credential if input is not provide.
            $DSEPMs = FindOutDSEPM -PMachines $PMachines
            if ($DSEPMs.Count -gt 0) {
            
                if (!$Credential) {
                    Write-Warning "PM list include DSE's PM. Please provide ada account credential!"
                    $Credential = Get-Credential -Message "Your ada account:"
                }

            
                $Properties += ExecuteTesting -PMachines $DSEPMs -Credential $Credential

            

                $PMachines = $PMachines | Where-Object { $DSEPMs -notcontains $_ }
            
            }

        
            $Properties += ExecuteTesting -PMachines $PMachines

                

        }

        if ($PSCmdlet.ParameterSetName -eq "cn") {
            $PMachines += $ComputerName
        

            $BadPMs = Test-Pingable -PMachines $PMachines # -Credential $Credential

            
            $BadPMs | % { $Properties += $_}

       
            $PMachines = @($PMachines | Where-Object { $BadPMs -notcontains $_ })
            
            $DSEPMs = FindOutDSEPM -PMachines $PMachines
            if ($DSEPMs.Count -gt 0) {
            
                if (!$Credential) {
                    Write-Warning "PM list include DSE's PM. Please provide ada account credential!"
                    $Credential = Get-Credential -Message "Your ada account:"
                }

            
                $Properties += ExecuteTesting -PMachines $DSEPMs -Credential $Credential

                #get only non-DSE PMs
                $PMachines = $PMachines | Where-Object { $DSEPMs -notcontains $_ }

            
            }

        
            $Properties += ExecuteTesting -PMachines $PMachines
        }

    } # end process

    end {
        

   
        return $Properties
   
    } # end end


}