Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #requires -Version 4.0 -Modules PoshRSJob
- Using Namespace System.Collections.Generic
- Using Namespace System.Text.RegularExpressions
- Set-StrictMode -Version Latest
- function Search-KBPhysicalDriveSerialNumber {
- <#
- .SYNOPSIS
- Searches for physical drives matching one or more specified serial numbers.
- .DESCRIPTION
- The Search-KBPhysicalDriveSerialNumber cmdlet searches for physical drives on remote computers that match specified one or more serial number regular expressions.
- .PARAMETER ComputerName
- Specifies single or multiple computers.
- .PARAMETER SerialNumber
- Specifies one or more serial number regular expressions that will be used to match serial numbers of physical drives against.
- .PARAMETER Timeout
- Determines how long the client computer waits for the session connection to be established.
- .EXAMPLE
- Search-KBPhysicalDriveSerialNumber -Computer 'WORKSTATION' -SerialNumber '15351740', '11GDT5UWT'
- This cmdlet searches computer with name 'WORKSTATION' for physical drives that match serial number regular expressions of '15351740' and '11GDT5UWT'.
- #>
- [CmdletBinding()]
- [OutputType('KBPhysicalDriveSerialNumber')]
- param(
- [Parameter(Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
- [Alias('CN', '__SERVER')]
- [ValidateNotNullOrEmpty()]
- [String[]]$ComputerName = $env:COMPUTERNAME,
- [ValidateNotNullOrEmpty()]
- [String[]]$SerialNumber = '.*',
- [ValidateRange(0, 300)]
- [Int]$Timeout = 0
- )
- begin {
- $computers = [List[String]]::new()
- try {
- $driveSerialNumberRegex = [Regex]::new(($SerialNumber -join '|'), [RegexOptions]::IgnoreCase)
- } catch [System.Management.Automation.MethodInvocationException] {
- Write-Error -Message ("Invalid SerialNumber RegEx pattern: {0}" -f $_.Exception.InnerException.Message) -ErrorAction Stop
- }
- }
- process {
- $computers.AddRange($ComputerName)
- }
- end {
- try {
- $jobBatch = ([Guid]::NewGuid()).Guid
- $cpuCount = [Int]($env:NUMBER_OF_PROCESSORS) * 4
- [Void]$PSBoundParameters.Remove('SerialNumber')
- [Void]$PSBoundParameters.Remove('ComputerName')
- [Void]$PSBoundParameters.Remove('Timeout')
- $jobsPool = $computers | Start-RSJob -Name {$_} -Batch $jobBatch -Throttle $cpuCount -VariablesToImport @('Timeout') -ScriptBlock {
- #Code inside ScriptBlock has to be compatible with PS 2.0 in order to support Windows 2003 and XP
- $diskDriveProperty = @{Property = 'DeviceID', 'Caption', 'Size'; Filter = "Size > 0"}
- $diskDriveSelect = @{Property = 'DeviceID', 'Caption', 'Size'}
- $diskDriveSort = @{Property = 'DeviceID'}
- $physicalMediaProperty = @{Property = 'Tag', 'SerialNumber'; Filter = "Tag LIKE '%PHYSICALDRIVE%' AND SerialNumber LIKE '%[a-z0-9]%'"}
- $physicalMediaSelect = @{Property = 'Tag', 'SerialNumber'}
- Invoke-Command -ComputerName $_ -HideComputerName -SessionOption (New-PSSessionOption -OpenTimeout $Timeout) -ScriptBlock {
- $physicalDriveCollection = New-Object -TypeName 'PSObject' -Property @{
- PhysicalDrive = New-Object -TypeName 'System.Collections.Generic.List[PSObject]'
- Status = 'Success'
- }
- try {
- if (Get-Command -Name Get-CimInstance -CommandType Cmdlet -ErrorAction SilentlyContinue) {
- $diskDrive = Get-CimInstance -ClassName 'Win32_DiskDrive' @using:diskDriveProperty -ErrorAction Stop | Select-Object @using:diskDriveSelect | Sort-Object @using:diskDriveSort
- $physicalMedia = Get-CimInstance -ClassName 'Win32_PhysicalMedia' @using:physicalMediaProperty -ErrorAction Stop | Select-Object @using:physicalMediaSelect
- } else {
- $diskDrive = Get-WmiObject -Class 'Win32_DiskDrive' @using:diskDriveProperty -ErrorAction Stop | Select-Object @using:diskDriveSelect | Sort-Object @using:diskDriveSort
- $physicalMedia = Get-WmiObject -Class 'Win32_PhysicalMedia' @using:physicalMediaProperty -ErrorAction Stop | Select-Object @using:physicalMediaSelect
- }
- foreach ($disk in $diskDrive) {
- foreach ($media in $physicalMedia) {
- if ($disk.DeviceID -eq $media.Tag) {
- $physicalDriveCollection.PhysicalDrive.Add((New-Object -TypeName 'PSObject' -Property @{
- ComputerName = $env:COMPUTERNAME
- DeviceID = $disk.DeviceID -replace '\\\\\.\\'
- Caption = $disk.Caption
- Size = $disk.Size
- SerialNumber = $media.SerialNumber.Trim()
- }))
- }
- }
- }
- } catch {
- $physicalDriveCollection.Status = ('Error: {0}' -f $_.Exception.Message.Trim())
- }
- #Output data
- $physicalDriveCollection
- } -ErrorAction SilentlyContinue | Select-Object -Property * -ExcludeProperty RunspaceID
- }
- $driveCollection, $errorCollection = @(Wait-RSJob -Batch $jobBatch -ShowProgress | Receive-RSJob).Where({$_.Status -eq 'Success'}, 'Split')
- $failedJobs = @(@($jobsPool).Where({$_.HasErrors}) | Select-Object -ExpandProperty Name)
- if (($PSBoundParameters.ContainsKey('Verbose')) -and ($failedJobsCount = $failedJobs.Count) -gt 0) {
- Write-Verbose ("RSJob execution errors [{0}/{1}]:" -f $failedJobsCount, @($jobsPool).Count)
- $failedJobs.ForEach({Write-Verbose $_})
- }
- Show-KBErrorCollection -ErrorCollection $errorCollection @PSBoundParameters
- Remove-RSJob -Batch $jobBatch -Force
- $foundDrives = [List[PSObject]]::new()
- foreach ($driveSet in $driveCollection) {
- foreach ($drive in $driveSet.PhysicalDrive) {
- if ($driveSerialNumberRegex.IsMatch($drive.SerialNumber)) {
- $drive.PSObject.TypeNames.Insert(0, 'KBPhysicalDriveSerialNumber')
- $foundDrives.Add($drive)
- }
- }
- }
- $foundDrives
- } catch {
- Write-Error -ErrorRecord $_ -ErrorAction $ErrorActionPreference
- }
- }
- }
Add Comment
Please, Sign In to add comment