Get Drive letter from Volume ID - powershell

I want to use drive letter instead of Volume ID like below. How can I do that ?
Thanks,
My output :
VolumeName OriginatingMachine InstallDate
\\?\Volume{3c0a6eed-1b4c-4e90-a25b-8af1af46e368}\ app01.contoso.com 4/13/2021 6:03:34 PM
\\?\Volume{de5c18ac-56e1-4efa-afb4-abaf476a99a9}\ app01.contoso.com 4/13/2021 6:03:34 PM
My desired output :
VolumeName OriginatingMachine InstallDate
E: app01.contoso.com 4/13/2021 6:03:34 PM
X: app01.contoso.com 4/13/2021 6:03:34 PM
Command:
Get-CimInstance Win32_ShadowCopy | Where InstallDate -lt ([datetime]::Now.AddDays(-5)) | Select-Object VolumeName,OriginatingMachine,InstallDate
Get-CimInstance Win32_ShadowCopy output :
Caption :
Description :
InstallDate : 9/17/2021 9:22:06 PM
Name :
Status :
ClientAccessible : False
Count : 11
DeviceObject : \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1234
Differential : True
ExposedLocally : False
ExposedName :
ExposedPath :
ExposedRemotely : False
HardwareAssisted : False
ID : {3C8DAB36-F083-4C68-84BA-E339B8A18AF3}
Imported : False
NoAutoRelease : True
NotSurfaced : False
NoWriters : False
OriginatingMachine : app01.contoso.com
Persistent : True
Plex : False
ProviderID : {B5946137-7B9F-4925-AF80-51ABD60B20D5}
ServiceMachine : app01.contoso.com
SetID : {D3D15CE2-9FFC-4A22-B03C-77D7FCB7D40E}
State : 12
Transportable : False
VolumeName : \\?\Volume{85e62cfa-2e9c-4a46-af5a-f0748acd60b6}\
PSComputerName :

The Win32_ShadowCopy command returns Win32_ShadowCopy objects, which have a number of fields all described here.
Some of the fields provided in ShadowCopy happen to match other WMI Classes which have info about Drive Letters, namely the VolumeName field. This field happens to also be present on both the ShadowCopy and Win32_Volume class, the latter of which has the drive letter property we need!
All we have to do is lookup all of the shadow copies, then lookup all of the volumes on the machine, then we can loop through the copies to find the matching volumes. If you have some really complex mounting logic, you'll need to add some extra logic though in the foreach section.
So we would make a quick little function to do this lookup for us, which would look like this:
function Get-Win32ShadowVolumeDiskInfo{
$shadowCopies = Get-CimInstance Win32_ShadowCopy
$volumes = Get-CimInstance Win32_Volume
$returnObject = #()
foreach ($copy in $shadowCopies){
$matchingVolume = $volumes | Where DeviceID -eq $copy.VolumeName
$returnObject += [PSCustomObject]#{
VolumeName=$matchingVolume.Name;
OriginatingMachine = $copy.OriginatingMachine;
InstallDate = $copy.InstallDate}
}
$returnObject
}

Related

How Get All Camera Devices ID From PowerShell

I am trying to get all camera devices ID and respective names using PowerShell command line. I tried several commands, but nothing has done what I am aiming. Below my "best" approach:
Get-CimInstance Win32_PnPEntity | where caption -match 'camera'
output
Caption : Remote Desktop Camera Bus
Description : UMBus Enumerator
InstallDate :
Name : Remote Desktop Camera Bus
Status : OK
Availability :
ConfigManagerErrorCode : 0
ConfigManagerUserConfig : False
CreationClassName : Win32_PnPEntity
DeviceID : UMB\UMB\1&841921D&0&RDCAMERA_BUS
ErrorCleared :
ErrorDescription :
LastErrorCode :
PNPDeviceID : UMB\UMB\1&841921D&0&RDCAMERA_BUS
PowerManagementCapabilities :
PowerManagementSupported :
StatusInfo :
SystemCreationClassName : Win32_ComputerSystem
SystemName : DESKTOP
ClassGuid : {4d36e97d-e325-11ce-bfc1-08002be10318}
CompatibleID :
HardwareID : {UMB\UMBUS}
Manufacturer : Microsoft
PNPClass : System
Present : True
Service : umbus
PSComputerName :
I know, for example, that generally the integrated camera has a name "integrated camera" with a ID "0". But this is not what is being shown.
Get-CimInstance Win32_PnPEntity | ? { $_.service -eq "usbvideo" } | Select-Object -Property PNPDeviceID, Name

Search and delete registry values containing string using Powershell

I'm trying to find all the values recursively that contains this sub-string in it name : "~fr-FR~".
$registry = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackageDetect\" -Recurse
Foreach($a in $registry) {
($a | Get-ItemProperty).Psobject.Properties |
Where-Object { $_.Name -like '*~fr-FR~*' }
}
At this point I can retrieve all the values filtered recursively. Pasted below is example of one of the results:
MemberType : NoteProperty
IsSettable : True
IsGettable : True
Value : 3
TypeNameOfValue : System.Int32
Name : Microsoft-Windows-GroupPolicy-ClientTools-Package~31bf3856ad364e35~amd64~fr-FR~10.0.17134.1
IsInstance : True
How do I remove the sub-string?

Compare-Object returning unexpected output

I have created a small function that captures Get-Volume into a local file. The next time the function runs, it compares the output of a fresh Get-Volume with the one previously saved to the file system.
This function works perfectly for services but is strangely returning a volume as 'different' even though we can see from the output it is not.
function Compare-Volumes{
$Path = "$Env:PROGRAMDATA\VACS\states\"
$File = "volumes.csv"
$Volumes = Get-Volume | Select-Object OperationalStatus, HealthStatus, DriveType, FileSystemType, DedupMode, UniqueId, AllocationUnitSize, DriveLetter, FileSystem, FileSystemLabel, Size
if (![System.IO.File]::Exists($Path+$File)){
$Volumes | Export-CSV -Path $Path$File -Force
}else{
# Load file to object, get differences, submit to API, replace previous snapshot in file with new one
$Snapshot = Import-CSV -Path "$Path$File"
$StatusChanges = Compare-Object -ReferenceObject ($Snapshot) -DifferenceObject ($Volumes) -Property OperationalStatus, HealthStatus, DriveType, FileSystemType, DedupMode, UniqueId, AllocationUnitSize, DriveLetter, FileSystem, FileSystemLabel, Size -IncludeEqual
$StatusChanges
$Volumes | Export-CSV -Path $Path$File -Force
}
}
My expected results are that everything returns as equal/unchanged (==) as none of the properties change, as is clear in the output below. Yet for some reason, the SideIndicator property added by Compare-Object is indicating value differences for the volume labelled Recovery.
OperationalStatus : Unknown
HealthStatus : Healthy
DriveType : CD-ROM
FileSystemType : Unknown
DedupMode : Disabled
UniqueId : \\?\Volume{2b4803c9-1ebe-11e6-9bed-005056c00008}\
AllocationUnitSize : 0
DriveLetter : E
FileSystem :
FileSystemLabel :
Size : 0
SideIndicator : ==
OperationalStatus : OK
HealthStatus : Healthy
DriveType : Fixed
FileSystemType : NTFS
DedupMode : NotAvailable
UniqueId : \\?\Volume{f688d14f-0ee7-11e5-b210-806e6f6e6963}\
AllocationUnitSize : 4096
DriveLetter : C
FileSystem : NTFS
FileSystemLabel : Windows
Size : 953903214592
SideIndicator : ==
OperationalStatus : Unknown
HealthStatus : Healthy
DriveType : CD-ROM
FileSystemType : Unknown
DedupMode : Disabled
UniqueId : \\?\Volume{f688d152-0ee7-11e5-b210-806e6f6e6963}\
AllocationUnitSize : 0
DriveLetter : D
FileSystem :
FileSystemLabel :
Size : 0
SideIndicator : ==
OperationalStatus : OK
HealthStatus : Healthy
DriveType : Fixed
FileSystemType : NTFS
DedupMode : NotAvailable
UniqueId : \\?\Volume{f688d14e-0ee7-11e5-b210-806e6f6e6963}\
AllocationUnitSize : 4096
DriveLetter :
FileSystem : NTFS
FileSystemLabel : Recovery
Size : 6291451904
SideIndicator : =>
OperationalStatus : OK
HealthStatus : Healthy
DriveType : Fixed
FileSystemType : NTFS
DedupMode : NotAvailable
UniqueId : \\?\Volume{f688d14e-0ee7-11e5-b210-806e6f6e6963}\
AllocationUnitSize : 4096
DriveLetter :
FileSystem : NTFS
FileSystemLabel : Recovery
Size : 6291451904
SideIndicator : <=
Strangely it is the DriveLetter property which compares falsely
with volumes which doesn't have one (like the recovery partition).
Presumably you'll have to include a Select-Object with a calculated property
which also checks the DriveLetter [string]::IsNullOrEmpty()
to avoid comparing $Null with the stringified output "" of Export-Csv
Your script, a bit streamlined:
## Q:\Test\2018\12\31\SO_53990220.ps1
function Compare-Volumes{
$FilePath = Join-Path "$Env:PROGRAMDATA\VACS\states\" "volumes.csv"
$Volumes = Get-Volume | Select-Object OperationalStatus,HealthStatus,DriveType,
FileSystemType, DedupMode,UniqueId,AllocationUnitSize,FileSystemLabel,FileSystem,Size,
#{n='DriveLetter';e={if([string]::IsNullOrEmpty($_.DriveLetter)){""}else{$_.DriveLetter}}}
if (Test-Path $FilePath){
# Load file to object, get differences, submit to API, replace previous snapshot in file with new one
$Snapshot = Import-CSV -Path $FilePath
$StatusChanges = Compare-Object -ReferenceObject ($Snapshot) -DifferenceObject ($Volumes) `
-IncludeEqual -Property OperationalStatus,HealthStatus,DriveType,FileSystemType,
DedupMode,UniqueId,AllocationUnitSize,FileSystemLabel,FileSystem,Size,
DriveLetter
$StatusChanges
}
$Volumes | Export-CSV -Path $FilePath -Force -NoTypeInformation
}
Compare-Volumes

Receiving invalid data via WMI

I've had a script running for the better half of a year now that checks for disk space, should it be low it sends out an email been working just fine.
Today I received an alert saying that that Disk space was at 0gb.. I logged into the server and had about 30gbs available.
Part of code that checks the space.
[decimal]$thresholdspace = 5
$tableFragment= Get-WMIObject -ComputerName $computer Win32_LogicalDisk `
| select __SERVER, DriveType, VolumeName, Name, #{n='Size (Gb)' ;e={"{0:n2}" -f ($_.size/1gb)}},#{n='FreeSpace (Gb)';e={"{0:n2}" -f ($_.freespace/1gb)}}, #{n='PercentFree';e={"{0:n2}" -f ($_.freespace/$_.size*100)}} `
| Where-Object {$_.DriveType -eq 3 -and [decimal]$_.PercentFree -lt [decimal]$thresholdspace}
So I opened up an ISE session and did the following.
$computer = 'Server_01'
Get-WMIObject -ComputerName $computer Win32_LogicalDisk | select __SERVER, DriveType, VolumeName, Name,FreeSpace
and it responded with:
__SERVER : Server_01
DriveType : 2
VolumeName :
Name : A:
FreeSpace :
__SERVER : Server_01
DriveType : 3
VolumeName :
Name : C:
FreeSpace : 31372767232
__SERVER : Server_01
DriveType : 5
VolumeName :
Name : E:
FreeSpace :
So I then ran the part of my code that is getting space and it returned with the following:
__SERVER : Server_01
DriveType : 3
VolumeName :
Name : C:
Size (Gb) : 0.00
FreeSpace (Gb) : 0.00
PercentFree :
So I ran the simple WMI query and it responded with no data..
__SERVER : Server_01
DriveType : 2
VolumeName :
Name : A:
FreeSpace :
__SERVER : Server_01
DriveType : 3
VolumeName :
Name : C:
FreeSpace :
__SERVER : Server_01
DriveType : 5
VolumeName :
Name : E:
FreeSpace :
Any idea as to why I'm getting invalid or what appears to be incomplete data? I've never seen anything like this, and have not ran into this issue at all before. Nothing has changed on either server it is running from.

Powershell, get ip4v address of VM

I'm new to powershell and I"m trying to get just the IPv4 address of a vm and save it as a string.
I can get all network attributes like so:
PS C:\Windows\system32> get-vm | select -ExpandProperty networkadapters | select vmname, macaddress, switchname, ipaddres
sses
VMName MacAddress SwitchName IPAddresses
------ ---------- ---------- -----------
foobar vSwitch {192.0.2.1, fe80::84a...
I can get both the v4 and the v6 ip address
PS C:\Windows\system32> $IP = ( GEt-VM -ComputerName $HVCOMPUTERNAME -VMName $HVNAME | Get-VMNetworkAdapter).IpAddresses
PS C:\Windows\system32> $IP
192.0.2.1
fe80::d47e:
----------
How can I get just the v4 address as a string?
Update
It looks like there is no object property that just includes the v4 address
PS C:\Windows\system32> GEt-VM -ComputerName $HVCOMPUTERNAME -VMName $HVNAME | Get-VMNetworkAdapter | Format-List -Property *
IovWeight : 0
IovQueuePairsRequested : 1
IovQueuePairsAssigned : 0
IovInterruptModeration : Default
IovUsage : 0
ClusterMonitored : True
VirtualFunction :
IsLegacy : False
IsManagementOs : False
IsExternalAdapter : False
Id : Microsoft:xxxxxxxxxxx
AdapterId : xxxxxxxxxxx
DynamicMacAddressEnabled : True
MacAddress : 00155D5B9B14
MacAddressSpoofing : Off
SwitchId : xxxxxxxxxxx
Connected : True
PoolName :
SwitchName : vSwitch
AclList : {}
ExtendedAclList : {}
IsolationSetting : Microsoft.HyperV.PowerShell.VMNetworkAdapterIsolationSetting
CurrentIsolationMode : Vlan
RoutingDomainList : {}
DhcpGuard : Off
RouterGuard : Off
PortMirroringMode : None
IeeePriorityTag : Off
VirtualSubnetId : 0
DynamicIPAddressLimit : 0
StormLimit : 0
AllowTeaming : Off
VMQWeight : 100
IPsecOffloadMaxSA : 512
VmqUsage : 0
IPsecOffloadSAUsage : 0
VFDataPathActive : False
VMQueue :
MandatoryFeatureId : {}
MandatoryFeatureName : {}
VlanSetting : Microsoft.HyperV.PowerShell.VMNetworkAdapterVlanSetting
BandwidthSetting :
BandwidthPercentage : 0
TestReplicaPoolName :
TestReplicaSwitchName :
StatusDescription : {OK}
Status : {Ok}
IPAddresses : {192.0.2.1, fe80::xxxxxxxxxxx}
ComputerName : xxxxxxxxxxx
Name : Network Adapter
IsDeleted : False
VMId : xxxxxxxxxxx
VMName : foobar
VMSnapshotId : 00000000-0000-0000-0000-000000000000
VMSnapshotName :
Key :
You can just filter out any IP that has ":" in it, as such:
$IP | ?{$_ -notmatch ':'}
Assuming there is only 1 V4 address, and that the v4 address is the first output, do:
$IP = ( GEt-VM -ComputerName $HVCOMPUTERNAME -VMName $HVNAME | Get-VMNetworkAdapter).IpAddresses | Select-String -List 1
IPAddresses looks like an array or list and you only want the first one so try:
$IP = ( GEt-VM -ComputerName $HVCOMPUTERNAME -VMName $HVNAME | Get-VMNetworkAdapter).IpAddresses[0]